Package migration

import "github.com/BurntSushi/migration"
Overview
Index

Overview ▾

Package migration automatically handles versioning of a database schema by applying a series of migrations supplied by the client. It uses features only from the database/sql package, so it tries to be driver independent. However, to track the version of the database, it is necessary to execute some SQL. I've made an effort to keep those queries simple, but if they don't work with your database, you may override them.

This package works by applying a series of migrations to a database. Once a migration is created, it should never be changed. Every time a database is opened with this package, all necessary migrations are executed in a single transaction. If any part of the process fails, an error is returned and the transaction is rolled back so that the database is left untouched. (Note that for this to be useful, you'll need to use a database that supports rolling back changes to your schema. Notably, MySQL does not support this, although SQLite and PostgreSQL do.)

The version of a database is defined as the number of migrations applied to it.

func Open

func Open(driver, dsn string, migrations []Migrator) (*sql.DB, error)

Open wraps the Open function from the database/sql package, but performs a series of migrations on a database if they haven't been performed already.

Migrations are tracked by a simple versioning scheme. The version of the database is the number of migrations that have been performed on it. Similarly, the version of your library is the number of migrations that are given to this function.

If Open returns successfully, then the database and your library will have the same versions. If there was a problem migrating---or if the database version is greater than your library version---then an error is returned. Since all migrations are performed in a single transaction, if an error occurs, no changes are made to the database. (Assuming you're using a relational database that allows modifications to a schema to be rolled back.)

Note that this versioning scheme includes no semantic analysis. It is up to client to ensure that once a migration is defined, it never changes.

The details of how the version is stored are opaque to the client, but in general, it will add a table to your database called "migration_version" with a single column containing a single row.

func OpenWith

func OpenWith(
    driver, dsn string,
    migrations []Migrator,
    vget GetVersion, vset SetVersion,
) (*sql.DB, error)

OpenWith is exactly like Open, except it allows the client to specify their own versioning scheme. Note that vget and vset must BOTH be nil or BOTH be non-nil. Otherwise, this function panics. This is because the implementation of one generally relies on the implementation of the other.

If vget and vset are both set to nil, then the behavior of this function is identical to the behavior of Open.

type GetVersion

type GetVersion func(LimitedTx) (int, error)

GetVersion is any function that can retrieve the migration version of a particular database. It is exposed in case a client wants to override the default behavior of this package. (For example, by using the `user_version` PRAGMA in SQLite.)

The DefaultGetVersion function provided with this package creates its own table with a single column and a single row.

The version returned should be equivalent to the number of migrations applied to this database. It should be 0 if no migrations have been applied yet.

If an error is returned, the migration automatically fails.

Note that a LimitedTx is used to emphasize that functions with this type MUST NOT call Commit or Rollback. The migration routine in this pacakge will do it for you.

var DefaultGetVersion GetVersion = defaultGetVersion

The default way to get the version from a database. If the database has had no migrations performed, then it creates a table with a single row and a single column storing the version as 0. It then returns 0.

If the table exists, then the version stored in the table is returned.

type LimitedTx

type LimitedTx interface {
    Exec(query string, args ...interface{}) (sql.Result, error)
    Prepare(query string) (*sql.Stmt, error)
    Query(query string, args ...interface{}) (*sql.Rows, error)
    QueryRow(query string, args ...interface{}) *sql.Row
    Stmt(stmt *sql.Stmt) *sql.Stmt
}

LimitedTx specifies the behavior of a transaction *without* commit and rollback functions. Values with this type are given to client functions. In particular, the migration routines in this package handle transaction commits and rollbacks. Therefore the functions provided by the client should not use them.

type Migrator

type Migrator func(LimitedTx) error

Migrator corresponds to a function that updates the database by one version. Note that a migration should NOT call Rollback or Commit. Instead, this package will call Rollback for you if your migration returns an error. If no error is returned, then the next migration is applied. When all migrations have been applied, the version is updated and the changes are committed to the database.

type SetVersion

type SetVersion func(LimitedTx, int) error

SetVersion is the dual of GetVersion. It allows the client to define a different mechanism for setting the database version than the one used by DefaultSetVersion in this package.

If an error is returned, the migration that tried to set the version automatically fails.

Note that a LimitedTx is used to emphasize that functions with this type MUST NOT call Commit or Rollback. The migration routine in this pacakge will do it for you.

var DefaultSetVersion SetVersion = defaultSetVersion

The default way to set the version of the database. If the database has had no migrations performed, then it creates a table with a single row and a single column and storing the version given there.

If the table exists, then the existing version is overwritten.