pgmigrator is a very simple utility designed to roll up incremental (up only) migrations for PostgreSQL only.
Goal: to make an understandable tool for local development and stage environments.
- Database: PostgreSQL
- Migrations filename mask:
YYYYY-MM-DDD-<description>.sql
/YYYYY-MM-DD-<description>-NONTR.sql
- Migration types: UP only
- Algorithm: applies sorted migrations files that are in the folder and fit the file mask, except for what is already applied in the database
- The program works only with the configuration file located in the folder with migrations.
Q: Why only up migrations?
A: In development, we almost never write down migrations because it's useless in 99% of cases. If something goes wrong, we just don't roll up or decide manually what to do.
Q: Why only PostgreSQL?
A: There is a goal to create a highly specialized simple tool for migrations.
Q: Why such a specific file mask rather than the generally recognized one V<Version>_<description>.sql
?
A: This is historically the case. The date in the file gives more transparency than the version number. Less development conflicts in the branch.
It is possible to override this parameter through the configuration file.
Q: Why not as a library? Why migrations specifically as files on disk? A: The goal is a simple utility that works with files. Alternatives in the form of libraries have already been written here https://awesome-go.com/#database-schema-migration
Migration files are located in a folder. Subfolders are not counted. Files are sorted by name.
All recorded migrations are written to a table in database (by default public.pgMigrations
)
Default file mask: YYYYY-MM-DDD-<description>.sql
.
All migrations are started in a separate transaction with a specific StatementTimeout in the configuration file. If not specified, it is not used.
Non-transactional migrations have the following file mask: YYYYY-MM-DD-<description>-NONTR.sql
(e.g. for create index concurrently).
You can override the file mask through the configuration file. If not specified, the default one is used.
If there is MANUAL
at the end of the file name, this migration will be ignored.
2020 // folder, not counted
pgmigrator.toml // mandatory configuration file
2021-04-12-create-table-commentTranslations.sql // runs inside transaction
2021-06-02-make-person-alias-not-null-NONTR.sql // runs outside transaction
2021-06-03-make-person-alias-not-null-MANUAL.sql // ignored
[App]
Table = "public.pgMigrations"
StatementTimeout = "5s"
Filemask = "\d{4}-\d{2}-\d{2}-\S+.sql"
[Database]
Addr = "localhost:5432"
User = "postgres"
Password = "tesdb"
Database = "testdb"
PoolSize = 1
ApplicationName = "pgmigrator"
Command-line tool for PostgreSQL migrations
Usage:
pgmigrator [command]
Available Commands:
completion Generate the autocompletion script for the specified shell
dryrun Tries to apply migrations. Runs migrations inside single transaction and always rollbacks it
help Help about any command
init Initialize default configuration file in current directory
last Shows recent applied migrations from db
plan Shows migration files which can be applied
redo Rerun last applied migration from db
run Applies all new migrations
skip Marks migrations done without actually running them.
verify Checks and shows invalid migrations
Flags:
-c, --config string configuration file (default "pgmigrator.toml")
-h, --help help for pgmigrator
-v, --version version for pgmigrator
Use "pgmigrator [command] --help" for more information about a command.
Any command supports an argument in the form of a number. For last
it is the number of last migrations (default is 5). For all others - the number of the file from plan
to which to apply migrations. If no argument is passed, there are no restrictions (or default ones are used).
The base directory for migrations is the one where the configuration file is located.
That is, you can call pgmigrator --config docs/patches/pgmigrator.toml plan
and it will take all migrations from the docs/patches
folder.
Algorithm
- get a list of files sorted by name
- connect to the database
- check if there is a table
- get the list of migrations from the database
- display the list of files to be applied (TODO: highlight DROP?)
Output
Planning to apply Х migrations:
1 - 2022-07-18-movieComments.sql
2 - 2022-07-28-jwlinks.sql
3 - 2022-07-30-compilations-fix.sql
Algorithm
- create a table, if necessary
- make a plan
- for each file
- if the migration is regular
- begin
- perform migration
- add a record of the completed migration
- commit
- begin
- if migration is non-transactional
- add migration record
- perform migration
- update migration record
- if something goes wrong - rollback and exit (except for nontr, since it is not clear what exactly happened).
- if the migration is regular
- for each file
Output
Planning to apply Х migrations:
1 - 2022-07-18-movieComments.sql
2 - 2022-07-28-jwlinks.sql
3 - 2022-07-30-compilations-fix.sql
Applying:
1 - 2022-07-18-movieComments.sql ... done in 2s
2 - 2022-07-28-jwlinks.sql ... done in 3m
3 - 2022-07-30-compilations-fix.sql ...
ERROR: <error text>
- Like
Run
, but open one big transaction and use ROLLBACK. - If there is a NONTR - do not let dryrun run (only up to a certain filename)
StatementTimeout
setting is ignored
Like Run
, but without actually running sql migration, only adding migration success record
Shows the latest database migrations from a table.
Output
Showing last migrations in public.pgMigrations:
34 - 2022-08-30 22:25:03 (ERR) > 2022-07-30-compilations-NONTR.sql
33 - 2022-08-30 22:25:03 (3s) > 2022-07-30-compilations-fix.sql
32 - 2022-08-30 22:25:34 (1s) > 2022-07-28-jwlinks.sql
31 - 2022-08-30 22:23:12 (5m 4s) > 2022-07-18-movieComments.sql
Checks patch integrity in the database and locally by md5 hash.
Initializes a new configuration file with default settings.
Perform again the last migration that is recorded in the table.
Default: table pgMigrations
, scheme public
.
It is recommended to have a different migrations table for each schema.
create table if not exists "pgMigrations"
(
id serial not null,
filename text not null,
"startedAt" timestamptz default now() not null,
"finishedAt" timestamptz,
transactional bool default true not null,
md5sum varchar(32) not null,
primary key ("id"),
unique ("filename")
);
- id (pk) – serial
- filename - unique migration file name
- startedAt - timestamp of starting migration
- finishedAt - timestamp of finishing migration
- transactional - transactional flag (false для NONTR migrations)
- md5sum - md5 hash of migration file
- Docker Hub
- Packages Tab in this repo