Documentation ¶
Overview ¶
Package golembic is intended to provide tooling for managing SQL migrations in Go.
The underlying principles of golembic are as follows:
- Migrations should follow a straight line (from some root); this line should be verified to avoid merge conflicts causing "branching"
- The "current" state of the world will be tracked in a `migrations` table containing all migrations that have been applied.
- A series of migrations should be easy to use both in a script or as part of a larger piece of Go code
- Avoid all import time side effects caused either by importing a package that uses `init()` or by requiring migrations files to use `init()`
- Down migrations are not supported. The idea being that the risk of data loss from a down migration is not worth it and that writing down migrations can be more challenging than writing up migrations.
The design allows for running "arbitrary" code inside migrations so that even non-SQL tasks can be tracked as a "run-once" migration.
The name is a portmanteau of Go (the programming language) and `alembic`, the Python migrations package. The name `alembic` itself is motivated by the foundational ORM SQLAlchemy (an alembic is a distilling apparatus used by alchemists).
Index ¶
- Constants
- Variables
- func CreateMigrationsTable(ctx context.Context, manager *Manager) (err error)
- func QuoteIdentifier(name string) string
- func QuoteLiteral(literal string) string
- func ToRoundDuration(d, base time.Duration) (int64, error)
- type ApplyConfig
- type ApplyOption
- type Column
- type CreateTableOption
- func OptCreateTableConstraints(constraints string) CreateTableOption
- func OptCreateTableCreatedAt(createdAt string) CreateTableOption
- func OptCreateTablePrevious(previous string) CreateTableOption
- func OptCreateTableRevision(revision string) CreateTableOption
- func OptCreateTableSerialID(serialID string) CreateTableOption
- func OptCreateTableSkip(skip bool) CreateTableOption
- type CreateTableParameters
- type EngineProvider
- type Manager
- func (m *Manager) ApplyMigration(ctx context.Context, migration Migration) (err error)
- func (m *Manager) CloseConnectionPool() error
- func (m *Manager) Describe(_ context.Context) error
- func (m *Manager) EnsureConnectionPool(ctx context.Context) (*sql.DB, error)
- func (m *Manager) EnsureMigrationsTable(ctx context.Context) error
- func (m *Manager) GetVersion(ctx context.Context, opts ...ApplyOption) (*Migration, error)
- func (m *Manager) InsertMigration(ctx context.Context, tx *sql.Tx, migration Migration) error
- func (m *Manager) IsApplied(ctx context.Context, tx *sql.Tx, migration Migration) (bool, error)
- func (m *Manager) Latest(ctx context.Context) (revision string, createdAt time.Time, err error)
- func (m *Manager) NewConnectionPool(ctx context.Context) (*sql.DB, error)
- func (m *Manager) NewTx(ctx context.Context) (*sql.Tx, error)
- func (m *Manager) Up(ctx context.Context, opts ...ApplyOption) error
- func (m *Manager) UpOne(ctx context.Context, opts ...ApplyOption) error
- func (m *Manager) UpTo(ctx context.Context, opts ...ApplyOption) error
- func (m *Manager) Verify(ctx context.Context) (err error)
- func (m *Manager) Version(ctx context.Context, opts ...ApplyOption) error
- type ManagerOption
- func OptDevelopmentMode(mode bool) ManagerOption
- func OptManagerConnectionPool(pool *sql.DB) ManagerOption
- func OptManagerLog(log PrintfReceiver) ManagerOption
- func OptManagerMetadataTable(table string) ManagerOption
- func OptManagerProvider(provider EngineProvider) ManagerOption
- func OptManagerSequence(migrations *Migrations) ManagerOption
- type Migration
- type MigrationOption
- func OptAlwaysError(err error) MigrationOption
- func OptDescription(description string) MigrationOption
- func OptMilestone(milestone bool) MigrationOption
- func OptPrevious(previous string) MigrationOption
- func OptRevision(revision string) MigrationOption
- func OptUp(up UpMigration) MigrationOption
- func OptUpConn(up UpMigrationConn) MigrationOption
- func OptUpConnFromFile(filename string) MigrationOption
- func OptUpConnFromSQL(statement string) MigrationOption
- func OptUpFromFile(filename string) MigrationOption
- func OptUpFromSQL(statement string) MigrationOption
- type Migrations
- func (m *Migrations) All() []Migration
- func (m *Migrations) Between(since, until string) (int, []Migration, error)
- func (m *Migrations) Describe(log PrintfReceiver)
- func (m *Migrations) Get(revision string) *Migration
- func (m *Migrations) Register(migration Migration) error
- func (m *Migrations) RegisterMany(ms ...Migration) error
- func (m *Migrations) RegisterManyOpt(manyOpts ...[]MigrationOption) error
- func (m *Migrations) Revisions() []string
- func (m *Migrations) Root() Migration
- func (m *Migrations) Since(revision string) (int, []Migration, error)
- func (m *Migrations) Until(revision string) (int, []Migration, error)
- type PrintfReceiver
- type TimeColumnPointer
- type TimestampColumn
- type UpMigration
- type UpMigrationConn
Constants ¶
const ( // DefaultMetadataTable is the default name for the table used to store // metadata about migrations. DefaultMetadataTable = "golembic_migrations" )
Variables ¶
var ( // ErrDurationConversion is the error returned when a duration cannot be // converted to multiple of some base (e.g. milliseconds or seconds) // without round off. ErrDurationConversion = errors.New("Cannot convert duration") // ErrNotRoot is the error returned when attempting to start a sequence of // migration with a non-root migration. ErrNotRoot = errors.New("Root migration cannot have a previous migration set") // ErrMissingRevision is the error returned when attempting to register a migration // with no revision. ErrMissingRevision = errors.New("A migration must have a revision") // ErrNoPrevious is the error returned when attempting to register a migration // with no previous. ErrNoPrevious = errors.New("Cannot register a migration with no previous migration") // ErrPreviousNotRegistered is the error returned when attempting to register // a migration with a previous that is not yet registered. ErrPreviousNotRegistered = errors.New("Cannot register a migration until previous migration is registered") // ErrAlreadyRegistered is the error returned when a migration has already been // registered. ErrAlreadyRegistered = errors.New("Migration has already been registered") // ErrNilInterface is the error returned when a value satisfying an interface // is nil in a context where it is not allowed. ErrNilInterface = errors.New("Value satisfying interface was nil") // ErrMigrationNotRegistered is the error returned when no migration has been // registered for a given revision. ErrMigrationNotRegistered = errors.New("No migration registered for revision") // ErrMigrationMismatch is the error returned when the migration stored in // SQL does not match the registered migration. ErrMigrationMismatch = errors.New("Migration stored in SQL doesn't match sequence") // ErrCannotInvokeUp is the error returned when a migration cannot invoke the // up function (e.g. if it is `nil`). ErrCannotInvokeUp = errors.New("Cannot invoke up function for a migration") // ErrCannotPassMilestone is the error returned when a migration sequence // contains a milestone migration that is **NOT** the last step. ErrCannotPassMilestone = errors.New("If a migration sequence contains a milestone, it must be the last migration") )
Functions ¶
func CreateMigrationsTable ¶
CreateMigrationsTable invokes SQL statements required to create the metadata table used to track migrations. If the table already exists (as detected by `provider.TableExistsSQL()`), this function will not attempt to create a table or any constraints.
func QuoteIdentifier ¶
QuoteIdentifier quotes an identifier, such as a table name, for usage in a query.
This implementation is vendored in here to avoid the side effects of importing `github.com/lib/pq`.
See: - https://github.com/lib/pq/blob/v1.8.0/conn.go#L1564-L1581 - https://www.sqlite.org/lang_keywords.html - https://github.com/ronsavage/SQL/blob/a67e7eaefae89ed761fa4dcbc5431ec9a235a6c8/sql-99.bnf#L412
func QuoteLiteral ¶
QuoteLiteral quotes a literal, such as `2023-01-05 15:00:00Z`, for usage in a query.
This implementation is vendored in here to avoid the side effects of importing `github.com/lib/pq`.
See: - https://github.com/lib/pq/blob/v1.8.0/conn.go#L1583-L1614 - https://www.sqlite.org/lang_keywords.html - https://github.com/ronsavage/SQL/blob/a67e7eaefae89ed761fa4dcbc5431ec9a235a6c8/sql-99.bnf#L758-L761 - https://github.com/ronsavage/SQL/blob/a67e7eaefae89ed761fa4dcbc5431ec9a235a6c8/sql-99.bnf#L290
Types ¶
type ApplyConfig ¶
ApplyConfig provides configurable fields for "up" commands that will apply migrations.
func NewApplyConfig ¶
func NewApplyConfig(opts ...ApplyOption) (*ApplyConfig, error)
NewApplyConfig creates a new `ApplyConfig` and applies options.
type ApplyOption ¶
type ApplyOption = func(*ApplyConfig) error
ApplyOption describes options used to create an apply configuration.
func OptApplyRevision ¶
func OptApplyRevision(revision string) ApplyOption
OptApplyRevision sets `Revision` on an `ApplyConfig`.
func OptApplyVerifyHistory ¶
func OptApplyVerifyHistory(verify bool) ApplyOption
OptApplyVerifyHistory sets `VerifyHistory` on an `ApplyConfig`.
type Column ¶
Column represents an abstract SQL column value; it requires a `Scan()` interface for reading and a `Value()` interface for writing.
type CreateTableOption ¶
type CreateTableOption = func(*CreateTableParameters)
CreateTableOption describes options used for create table parameters.
func OptCreateTableConstraints ¶
func OptCreateTableConstraints(constraints string) CreateTableOption
OptCreateTableConstraints sets the `Constraints` field in create table options.
func OptCreateTableCreatedAt ¶
func OptCreateTableCreatedAt(createdAt string) CreateTableOption
OptCreateTableCreatedAt sets the `CreatedAt` field in create table options.
func OptCreateTablePrevious ¶
func OptCreateTablePrevious(previous string) CreateTableOption
OptCreateTablePrevious sets the `Previous` field in create table options.
func OptCreateTableRevision ¶
func OptCreateTableRevision(revision string) CreateTableOption
OptCreateTableRevision sets the `Revision` field in create table options.
func OptCreateTableSerialID ¶
func OptCreateTableSerialID(serialID string) CreateTableOption
OptCreateTableSerialID sets the `SerialID` field in create table options.
func OptCreateTableSkip ¶
func OptCreateTableSkip(skip bool) CreateTableOption
OptCreateTableSkip sets the `SkipConstraintStatements` field in create table options.
type CreateTableParameters ¶
type CreateTableParameters struct { SerialID string Revision string Previous string CreatedAt string Constraints string SkipConstraintStatements bool }
CreateTableParameters specifies a set of parameters that are intended to be used in a `CREATE TABLE` statement. This allows providers to specify custom column types or add custom checks / constraints that are engine specific.
func NewCreateTableParameters ¶
func NewCreateTableParameters(opts ...CreateTableOption) CreateTableParameters
NewCreateTableParameters populates a `CreateTableParameters` with a basic set of defaults and allows optional overrides for all fields.
type EngineProvider ¶
type EngineProvider interface { // QueryParameter produces a placeholder like `$1` or `?` for a numbered // parameter in a SQL query. QueryParameter(index int) string // NewCreateTableParameters produces column types and constraints for the // `CREATE TABLE` statement used to create the migrations table. NewCreateTableParameters() CreateTableParameters // TimestampColumn produces a value that can be used for reading / writing // the `created_at` column. TimestampColumn() TimestampColumn // QuoteIdentifier quotes an identifier, such as a table name, for usage // in a query. QuoteIdentifier(name string) string // QuoteLiteral quotes a literal, such as `2023-01-05 15:00:00Z`, for usage // in a query. QuoteLiteral(literal string) string // Open creates a database connection for the engine provider. Open() (*sql.DB, error) // TableExistsSQL returns a SQL query that can be used to determine if a // table exists. It is expected to use a clause such as `WHERE tablename = $1` // or `WHERE tablename = ?` to filter results. TableExistsSQL() string }
EngineProvider describes the interface required for a database engine.
type Manager ¶
type Manager struct { // MetadataTable is the name of the table that stores migration metadata. // The expected default value (`DefaultMetadataTable`) is // "golembic_migrations". MetadataTable string // ConnectionPool is a cache-able pool of connections to the database. ConnectionPool *sql.DB // Provider delegates all actions to an abstract SQL database engine, with // the expectation that the provider also encodes connection information. Provider EngineProvider // Sequence is the collection of registered migrations to be applied, // verified, described, etc. by this manager. Sequence *Migrations // DevelopmentMode is a flag indicating that this manager is currently // being run in development mode, so things like extra validation should // intentionally be disabled. This is intended for use in testing and // development, where an entire database is spun up locally (e.g. in Docker) // and migrations will be applied from scratch (including milestones that // may not come at the end). DevelopmentMode bool // Log is used for printing output Log PrintfReceiver }
Manager orchestrates database operations done via `Up` / `UpConn` as well as supporting operations such as creating a table for migration metadata and writing rows into that metadata table during a migration.
func NewManager ¶
func NewManager(opts ...ManagerOption) (*Manager, error)
NewManager creates a new manager for orchestrating migrations.
func (*Manager) ApplyMigration ¶
ApplyMigration creates a transaction that runs the "Up" migration.
func (*Manager) CloseConnectionPool ¶
CloseConnectionPool closes the connection pool and removes it, if one is set / cached on the current manager.
func (*Manager) EnsureConnectionPool ¶
EnsureConnectionPool returns a cached database connection pool (if already set) or invokes `NewConnection()` to create a new one.
func (*Manager) EnsureMigrationsTable ¶
EnsureMigrationsTable checks that the migrations metadata table exists and creates it if not.
func (*Manager) GetVersion ¶
GetVersion returns the migration that corresponds to the version that was most recently applied.
func (*Manager) InsertMigration ¶
InsertMigration inserts a migration into the migrations metadata table.
func (*Manager) IsApplied ¶
IsApplied checks if a migration has already been applied.
NOTE: This assumes, but does not check, that the migrations metadata table exists.
func (*Manager) Latest ¶
Latest determines the revision and timestamp of the most recently applied migration.
NOTE: This assumes, but does not check, that the migrations metadata table exists.
func (*Manager) NewConnectionPool ¶
NewConnectionPool creates a new database connection pool and validates that it can ping the DB.
func (*Manager) NewTx ¶
NewTx creates a new transaction after ensuring there is an existing connection.
func (*Manager) Up ¶
func (m *Manager) Up(ctx context.Context, opts ...ApplyOption) error
Up applies all migrations that have not yet been applied.
func (*Manager) UpOne ¶
func (m *Manager) UpOne(ctx context.Context, opts ...ApplyOption) error
UpOne applies the **next** migration that has yet been applied, if any.
func (*Manager) UpTo ¶
func (m *Manager) UpTo(ctx context.Context, opts ...ApplyOption) error
UpTo applies all migrations that have yet to be applied up to (and including) a revision, if any. This expects the `ApplyConfig` revision to be set in `opts`.
type ManagerOption ¶
ManagerOption describes options used to create a new manager.
func OptDevelopmentMode ¶
func OptDevelopmentMode(mode bool) ManagerOption
OptDevelopmentMode sets the development mode flag on a manager.
func OptManagerConnectionPool ¶
func OptManagerConnectionPool(pool *sql.DB) ManagerOption
OptManagerConnectionPool sets the connection pool on a manager.
func OptManagerLog ¶
func OptManagerLog(log PrintfReceiver) ManagerOption
OptManagerLog sets the logger interface on a manager. If `log` is `nil` the option will return an error.
func OptManagerMetadataTable ¶
func OptManagerMetadataTable(table string) ManagerOption
OptManagerMetadataTable sets the metadata table name on a manager.
func OptManagerProvider ¶
func OptManagerProvider(provider EngineProvider) ManagerOption
OptManagerProvider sets the provider on a manager.
func OptManagerSequence ¶
func OptManagerSequence(migrations *Migrations) ManagerOption
OptManagerSequence sets the migrations sequence on a manager.
type Migration ¶
type Migration struct { // Previous is the revision identifier for the migration immediately // preceding this one. If absent, this indicates that this migration is // the "base" or "root" migration. Previous string // Revision is an opaque name that uniquely identifies a migration. It // is required for a migration to be valid. Revision string // Description is a long form description of why the migration is being // performed. It is intended to be used in "describe" scenarios where // a long form "history" of changes is presented. Description string // Milestone is a flag indicating if the current migration is a milestone. // A milestone is a special migration that **must** be the last migration // in a sequence whenever applied. This is intended to be used in situations // where a change must be "staged" in two (or more parts) and one part // must run and "stabilize" before the next migration runs. For example, in // a rolling update deploy strategy some changes may not be compatible with // "old" and "new" versions of the code that may run simultaneously, so a // milestone marks the last point where old / new versions of application // code should be expected to be able to interact with the current schema. Milestone bool // Up is the function to be executed when a migration is being applied. Either // this field or `UpConn` are required (not both) and this field should be // the default choice in most cases. This function will be run in a transaction // that also writes a row to the migrations metadata table to signify that // this migration was applied. Up UpMigration // UpConn is the non-transactional form of `Up`. This should be used in // rare situations where a migration cannot run inside a transaction, e.g. // a `CREATE UNIQUE INDEX CONCURRENTLY` statement. UpConn UpMigrationConn // contains filtered or unexported fields }
Migration represents an individual migration to be applied; typically as a set of SQL statements.
func NewMigration ¶
func NewMigration(opts ...MigrationOption) (*Migration, error)
NewMigration creates a new migration from a variadic slice of options.
func (Migration) ExtendedDescription ¶
ExtendedDescription is an extended form of `m.Description` that also incorporates other information like whether `m` is a milestone.
func (Migration) InvokeUp ¶
InvokeUp dispatches to `Up` or `UpConn`, depending on which is set. If both or neither is set, that is considered an error. If `UpConn` needs to be invoked, this lazily creates a new connection from a pool. It's crucial that the pool sets the relevant timeouts when creating a new connection to make sure migrations don't cause disruptions in application performance due to accidentally holding locks for an extended period.
type MigrationOption ¶
MigrationOption describes options used to create a new migration.
func OptAlwaysError ¶
func OptAlwaysError(err error) MigrationOption
OptAlwaysError returns an option that always returns an error.
func OptDescription ¶
func OptDescription(description string) MigrationOption
OptDescription sets the description on a migration.
func OptMilestone ¶
func OptMilestone(milestone bool) MigrationOption
OptMilestone sets the milestone flag on a migration.
func OptPrevious ¶
func OptPrevious(previous string) MigrationOption
OptPrevious sets the previous on a migration.
func OptRevision ¶
func OptRevision(revision string) MigrationOption
OptRevision sets the revision on a migration.
func OptUp ¶
func OptUp(up UpMigration) MigrationOption
OptUp sets the `up` function on a migration.
func OptUpConn ¶
func OptUpConn(up UpMigrationConn) MigrationOption
OptUpConn sets the non-transactional `up` function on a migration.
func OptUpConnFromFile ¶
func OptUpConnFromFile(filename string) MigrationOption
OptUpConnFromFile returns an option that sets the non-transctional `up` function to execute a SQL statement that is stored in a file.
func OptUpConnFromSQL ¶
func OptUpConnFromSQL(statement string) MigrationOption
OptUpConnFromSQL returns an option that sets the non-transctional `up` function to execute a SQL statement.
func OptUpFromFile ¶
func OptUpFromFile(filename string) MigrationOption
OptUpFromFile returns an option that sets the `up` function to execute a SQL statement that is stored in a file.
func OptUpFromSQL ¶
func OptUpFromSQL(statement string) MigrationOption
OptUpFromSQL returns an option that sets the `up` function to execute a SQL statement.
type Migrations ¶
type Migrations struct {
// contains filtered or unexported fields
}
Migrations represents a sequence of migrations to be applied.
func NewSequence ¶
func NewSequence(root Migration) (*Migrations, error)
NewSequence creates a new sequence of migrations rooted in a single base / root migration.
func (*Migrations) All ¶
func (m *Migrations) All() []Migration
All produces the migrations in the sequence, in order.
NOTE: This does not verify or enforce the invariant that there must be exactly one migration without a previous migration. This invariant is enforced by the exported methods such as `Register()` and `RegisterMany()` and the constructor `NewSequence()`.
func (*Migrations) Between ¶
func (m *Migrations) Between(since, until string) (int, []Migration, error)
Between returns the migrations that occur between two revisions.
This can be seen as a combination of `Since()` and `Until()`.
func (*Migrations) Describe ¶
func (m *Migrations) Describe(log PrintfReceiver)
Describe displays all of the registered migrations (with descriptions).
func (*Migrations) Get ¶
func (m *Migrations) Get(revision string) *Migration
Get retrieves a revision from the sequence, if present. If not, returns `nil`.
func (*Migrations) Register ¶
func (m *Migrations) Register(migration Migration) error
Register adds a new migration to an existing sequence of migrations, if possible. The new migration must have a previous migration and have a valid revision that is not already registered.
func (*Migrations) RegisterMany ¶
func (m *Migrations) RegisterMany(ms ...Migration) error
RegisterMany attempts to register multiple migrations (in order) with an existing sequence.
func (*Migrations) RegisterManyOpt ¶
func (m *Migrations) RegisterManyOpt(manyOpts ...[]MigrationOption) error
RegisterManyOpt attempts to register multiple migrations (in order) with an existing sequence. It differs from `RegisterMany()` in that the construction of `Migration` objects is handled directly here by taking a slice of option slices.
func (*Migrations) Revisions ¶
func (m *Migrations) Revisions() []string
Revisions produces the revisions in the sequence, in order.
This utilizes `All()` and just extracts the revisions.
func (*Migrations) Root ¶
func (m *Migrations) Root() Migration
Root does a linear scan of every migration in the sequence and returns the root migration. In the "general" case such a scan would be expensive, but the number of migrations should always be a small number.
NOTE: This does not verify or enforce the invariant that there must be exactly one migration without a previous migration. This invariant is enforced by the exported methods such as `Register()` and `RegisterMany()` and the constructor `NewSequence()`.
func (*Migrations) Since ¶
func (m *Migrations) Since(revision string) (int, []Migration, error)
Since returns the migrations that occur **after** `revision`.
This utilizes `All()` and returns all migrations after the one that matches `revision`. If none match, an error will be returned. If `revision` is the **last** migration, the migrations returned will be an empty slice.
func (*Migrations) Until ¶
func (m *Migrations) Until(revision string) (int, []Migration, error)
Until returns the migrations that occur **before** `revision`.
This utilizes `All()` and returns all migrations up to and including the one that matches `revision`. If none match, an error will be returned.
type PrintfReceiver ¶
PrintfReceiver is a generic interface for logging and printing. In cases where a trailing newline is desired (e.g. STDOUT), the type implemented `PrintfReceiver` must add the newline explicitly.
type TimeColumnPointer ¶
TimeColumnPointer provides the default implementation of `TimestampColumn`.
func (*TimeColumnPointer) Pointer ¶
func (tcp *TimeColumnPointer) Pointer() interface{}
Pointer returns a pointer to the stored timestamp value.
func (TimeColumnPointer) Timestamp ¶
func (tcp TimeColumnPointer) Timestamp() time.Time
Timestamp returns the stored timestamp value.
type TimestampColumn ¶
TimestampColumn represents an abstract SQL column that stores a timestamp.
type UpMigration ¶
UpMigration defines a function interface to be used for up / forward migrations. The SQL transaction will be started **before** `UpMigration` is invoked and will be committed **after** the `UpMigration` exits without error. In addition to the contents of `UpMigration`, a row will be written to the migrations metadata table as part of the transaction.
The expectation is that the migration runs SQL statements within the transaction. If a migration cannot run inside a transaction, e.g. a `CREATE UNIQUE INDEX CONCURRENTLY` statement, then the `UpMigration` interface should be used.
Source Files ¶
Directories ¶
Path | Synopsis |
---|---|
Package command provides helpers to create a binary / command from a migration sequence.
|
Package command provides helpers to create a binary / command from a migration sequence. |
Package mysql provides MySQL helpers for golembic.
|
Package mysql provides MySQL helpers for golembic. |
Package postgres provides PostgreSQL helpers for golembic.
|
Package postgres provides PostgreSQL helpers for golembic. |
Package sqlite3 provides SQLite helpers for golembic.
|
Package sqlite3 provides SQLite helpers for golembic. |