diff --git a/cmd/sql-migrate/README.md b/cmd/sql-migrate/README.md new file mode 100644 index 0000000..d25e143 --- /dev/null +++ b/cmd/sql-migrate/README.md @@ -0,0 +1,124 @@ +# [sql-migrate](https://github.com/therootcompany/golib/tree/main/cmd/sql-migrate) + +> A feature-branch-friendly SQL migrator + +```sh +sql-migrate [-d sqldir] [-f logfile] [args] +``` + +## Features + +- Locally-stored Migrations (not in DB) +- Migration log can be hand edited to easily roll forwards or backwards +- Migrations are simple shell scripts +- Works with any database (just change the command) + +## Overview + +- Migration Directory +- Migration Log +- Migrations Files (up, down) + +### Migration Directory + +Lexicographically-sortable files in the format `_..sql`: + +```text +migrations/ +├── 2021-02-03-001000_init.up.sql +├── 2021-02-03-001000_init.down.sql +├── 2021-02-03-002000_add-products.up.sql +├── 2021-02-03-002000_add-products.down.sql +├── 2021-02-03-003000_add-customers.up.sql +└── 2021-02-03-003000_add-customers.down.sql +``` + +### Migration Log + +A simple list of migration names. + +`./sql/migrations.log`: + +```text +# command: psql "$PG_URL" < %s +# batch: 1 +2021-02-03-001000_init +2021-02-03-002000_add-products + +# batch: 2 +2021-02-03-003000_add-customers +``` + +Change `command` to work with any database. + +### Migration Files + +Simply SQL. Comments are generated for easy finding with `grep`. + +`2021-02-03-002000_add-products.up.sql`: + +```sh +-- add-products (up) +CREATE TABLE "products" ( + slug VARCHAR(127) NOT NULL, + name VARCHAR(255) NOT NULL, + price INTEGER NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + revoked_at TIMESTAMP, + PRIMARY KEY ("slug") +); +``` + +`2021-02-03-002000_add-products.down.sql`: + +```sh +-- add-products (down) +DROP TABLE IF EXISTS "products"; +``` + +## Usage + +```sh +sql-migrate init -d ./sql/migrations/ -f ./sql/migrations.log +sql-migrate create +sql-migrate status +sql-migrate up +sql-migrate down +sql-migrate list +``` + +See `sql-migrate help` for details. + + + +```text +COMMANDS + init - inits sql dir and migration file, adding or updating the + default command + create - creates a new, canonically-named up/down file pair in the + migrations directory + status - shows the same output as if processing a forward-migration + for the most recent batch + up - processes the first 'up' migration file missing from the + migration state + down - rolls back the latest entry of the latest migration batch + (the whole batch if just one) + list - lists migrations + +OPTIONS + -d default: ./sql/migrations/ + -f default: ./sql/migrations.log + + The migration state file contains the client command template (defaults to + 'psql "$PG_URL" < %s'), followed by a list of batches identified by a batch + number comment and a list of migration file basenames and optional user + comments, such as: + # command: psql "$PG_URL" < %s + # batch: 1 + 2020-01-01-1000_init.up.sql # does a lot + 2020-01-01-1100_add-customer-tables.up.sql + # batch: 2 + # We did id! Finally! + 2020-01-01-2000_add-ALL-THE-TABLES.up.sql +``` diff --git a/cmd/sql-migrate/doc.go b/cmd/sql-migrate/doc.go new file mode 100644 index 0000000..0fac1f5 --- /dev/null +++ b/cmd/sql-migrate/doc.go @@ -0,0 +1,2 @@ +// a feature-branch-friendly SQL migrator +package main diff --git a/cmd/sql-migrate/go.mod b/cmd/sql-migrate/go.mod new file mode 100644 index 0000000..13c2b55 --- /dev/null +++ b/cmd/sql-migrate/go.mod @@ -0,0 +1,3 @@ +module github.com/therootcompany/golib/cmd/sql-migrate + +go 1.25.3 diff --git a/cmd/sql-migrate/main.go b/cmd/sql-migrate/main.go index 1d2a694..b0f5eca 100644 --- a/cmd/sql-migrate/main.go +++ b/cmd/sql-migrate/main.go @@ -396,9 +396,13 @@ func main() { } command := os.Args[1] - if command == "help" || command == "--help" || command == "-h" || command == "version" || command == "--version" || command == "-V" { + switch command { + case "help", "--help", + "version", "--version", "-V": fmt.Printf("%s\n", helpText) os.Exit(0) + default: + // do nothing } fs := flag.NewFlagSet(command, flag.ExitOnError)