An embeddable library for applying changes to your Go application's
database/sql schema.
go:embedCreate a schema.Migrator in your bootstrap/config/database connection code,
then call its Apply() method with your database connection and a slice of
*schema.Migration structs.
The .Apply() function figures out which of the supplied Migrations have not
yet been executed in the database (based on the ID), and executes the Script
for each in alphabetical order by IDe.
The []*schema.Migration can be created manually, but the package
has some utility functions to make it easier to parse .sql files into structs
with the filename as the ID and the file contents as the Script.
Go's embed package lets you embed a directory of files into the binary as an
embedded filesystem (embed.FS).
Assuming you have a directory of SQL files called my-migrations/ next to your
main.go file, you'll run something like this:
//go:embed my-migrations
var MyMigrations embed.FS
func main() {
db, err := sql.Open(...) // Or however you get a *sql.DB
migrations, err := schema.FSMigrations(MyMigrations, "my-migrations/*.sql")
migrator := schema.NewMigrator(schema.WithDialect(schema.MySQL))
err = migrator.Apply(db, migrations)
}
The WithDialect() option accepts: schema.MySQL, schema.Postgres,
schema.SQLite or schema.MSSQL. These dialects all use only database/sql
calls, so you may have success with other databases which are SQL-compatible
with the above dialects.
You can also provide your own custom Dialect. See dialect.go for the
definition of the Dialect interface, and the optional Locker interface. Note
that Locker is critical for clustered operation to ensure that only one of
many processes is attempting to run migrations simultaneously.
If you prefer not to use embedded migration files, Migration{} structs can be
created manually:
db, err := sql.Open(...)
migrator := schema.NewMigrator() // Postgres is the default Dialect
migrator.Apply(db, []*schema.Migration{
&schema.Migration{
ID: "2019-09-24 Create Albums",
Script: `
CREATE TABLE albums (
id SERIAL PRIMARY KEY,
title CHARACTER VARYING (255) NOT NULL
)
`
},
})
The NewMigrator() function accepts option arguments to customize the dialect
and the name of the migration tracking table. By default, the tracking table
will be named schema_migrations. To change it
to my_migrations instead:
migrator := schema.NewMigrator(schema.WithTableName("my_migrations"))
It is theoretically possible to create multiple Migrators and to use mutliple migration tracking tables within the same application and database.
It is also OK for multiple processes to run Apply on identically configured
migrators simultaneously. The Migrator only creates the tracking table if it
does not exist, and then locks it to modifications while building and running
the migration plan. This means that the first-arriving process will win and
will perform its migrations on the database.
This package was extracted from a PostgreSQL project. Other databases have solid automated test coverage, but should be considered somewhat experimental in production use cases. Contributions are welcome for additional databases or feature enhancements / bug fixes.
jack/pgx)There are many other schema migration tools. This one exists because of a particular set of opinions:
schema package imports only
standard library packages
(NOTE *We do import ory/dockertest in our tests).ID (filename) or Script (file contents)
of a Migration which has already been executed on your database. If you've
made a mistake, you'll need to correct it in a subsequent migration.Use a consistent, but descriptive format for migration IDs/filenames.
Consider prefixing them with today's timestamp. Examples:
ID: "2019-01-01T13:45:00 Creates Users"
ID: "2001-12-18 001 Changes the Default Value of User Affiliate ID"
Do not use simple sequentialnumbers like ID: "1".
Migrations are not executed in the order they are specified in the slice. They will be re-sorted alphabetically by their IDs before executing them.
... are welcome. Please include tests with your contribution. We've integrated dockertest to automate the process of creating clean test databases.
Before contributing, please read the package opinions section. If your contribution is in disagreement with those opinions, then there's a good chance a different schema migration tool is more appropriate.
Validate() method to allow checking migration names for
consistency and to detect problematic changes in the migrations list.ory/dockertest/v4ory/dockertest/v4denisenkom/go-mssqldb to microsoft/go-mssqldbFSMigrations(filesystem fs.FS, glob string))go 1.17.Security patches in upstream dependencies.
Bugfix for error with advisory lock being held open. Improved test coverage for simultaneous execution.
Use a database-held lock for all migrations not just the initial table creation.
Add the ability to attach a logger.
Switch to filepath package for improved cross-platform filesystem support.
Began using pg_advisory_lock() to prevent race conditions when multiple processes/machines try to simultaneously create the migrations table.
First published version.
$ claude mcp add schema \
-- python -m otcore.mcp_server <graph>