# Migrations All migrations go into a single file I'll creatively call `migrations`: -- 1 up CREATE TABLE IF NOT EXISTS pastes ( paste_id SERIAL PRIMARY KEY, paste_body TEXT ); -- 1 down DROP TABLE pastes; Connect to the database and then apply the migrations: my $dbh = DBIish.connect: 'Pg', :host, :database, :user, password => prompt 'enter DB password: '; my $m = DB::Migration::Simple.new: :$dbh, :migration-file; $m.migrate: :version<1>; Get prompted for password for now: $ ./bin/pastes-bin enter DB password: hogrider69 line: -- 1 up version: 1, direction: up line: CREATE TABLE IF NOT EXISTS pastes ( line: paste_id SERIAL PRIMARY KEY, line: paste_body TEXT line: ); line: -- 1 down version: 1, direction: down line: DROP TABLE pastes; initializing db-migrations-simple-meta set initial version to 0 {1 => {down => DROP TABLE pastes; , up => CREATE TABLE IF NOT EXISTS pastes ( paste_id SERIAL PRIMARY KEY, paste_body TEXT ); }} migrating from version '0' to version '1' True migrating 'up' from version '0' to version '1' doing 'up' migrations for 1 executing CREATE TABLE IF NOT EXISTS pastes ( paste_id SERIAL PRIMARY KEY, paste_body TEXT ) Humming-Bird listening on port http://localhost:3000 Let's check on DB: $ psql -h devbussy.swagg.net -U pastes_bin Password for user pastes_bin: psql (15.3 (Debian 15.3-0+deb12u1)) SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off) Type "help" for help. pastes_bin=> \d List of relations Schema | Name | Type | Owner --------+---------------------------+----------+------------ public | db-migrations-simple-meta | table | pastes_bin public | pastes | table | pastes_bin public | pastes_paste_id_seq | sequence | pastes_bin (3 rows) pastes_bin=> \d pastes; Table "public.pastes" Column | Type | Collation | Nullable | Default ------------+---------+-----------+----------+------------------------------------------ paste_id | integer | | not null | nextval('pastes_paste_id_seq'::regclass) paste_body | text | | | Indexes: "pastes_pkey" PRIMARY KEY, btree (paste_id) Some mock-up 'model' code: use Pastes-Bin::Model::Paste; # No routes yet just prompt to 'fake it' my $new-paste = prompt 'enter a new paste: '; Pastes-Bin::Model::Paste.create: $new-paste; Now test it: $ ./bin/pastes-bin enter DB password: C65VCQyp&zKsi#wKXzTLUM5V line: -- 1 up version: 1, direction: up line: CREATE TABLE IF NOT EXISTS pastes ( line: paste_id SERIAL PRIMARY KEY, line: paste_body TEXT line: ); line: -- 1 down version: 1, direction: down line: DROP TABLE pastes; current-version: allrows: [[1]] {1 => {down => DROP TABLE pastes; , up => CREATE TABLE IF NOT EXISTS pastes ( paste_id SERIAL PRIMARY KEY, paste_body TEXT ); }} migrating from version '1' to version '1' DB already at version 1 enter a new paste: testing 123... Humming-Bird listening on port http://localhost:3000 ^C Now check the DB for the paste: pastes_bin=> SELECT * FROM pastes; paste_id | paste_body ----------+------------ (0 rows) pastes_bin=> SELECT * FROM pastes; paste_id | paste_body ----------+---------------- 1 | testing 123... (1 row) End result: use Humming-Bird::Core; use Humming-Bird::Middleware; use Humming-Bird::Advice; use DB::Migration::Simple; use DBIish; # Local libs use Pastes-Bin::Model::Paste; # Logging middleware &middleware-logger; advice &advice-logger; # Database stuff my $*dbh = DBIish.connect: 'Pg', :host, :database, :user, password => prompt 'enter DB password: '; my $m = DB::Migration::Simple.new: :$*dbh, :migration-file, :verbose; $m.migrate: :version<1>; # No routes yet just prompt to 'fake it' my $new-paste = prompt 'enter a new paste: '; Pastes-Bin::Model::Paste.create: $new-paste;