migrate

package
v1.10.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2026 License: MIT Imports: 16 Imported by: 62

Documentation

Overview

Package migrate provides a database-agnostic migration system with multi-module support, dependency ordering, and distributed locking.

Migrations are Go functions (not SQL files). Any Go module can register migrations into a shared, ordered, dependency-aware migration plan. Forge extensions ship their own migrations that compose with the host app.

Index

Constants

View Source
const (
	MigrationTable     = "grove_migrations"
	MigrationLockTable = "grove_migration_locks"
)

Schema constants for the migration tracking tables.

View Source
const DefaultLockTimeout = 5 * time.Minute

DefaultLockTimeout is the default maximum time Migrate/Rollback will wait to acquire the migration lock before giving up. Raised from the original 30s so that several extensions migrating the same database in one process serialize and wait instead of failing the boot.

Variables

View Source
var (
	Text      = ColumnType{Kind: KindText}
	SmallInt  = ColumnType{Kind: KindSmallInt}
	Integer   = ColumnType{Kind: KindInteger}
	BigInt    = ColumnType{Kind: KindBigInt}
	BigSerial = ColumnType{Kind: KindBigSerial}
	Boolean   = ColumnType{Kind: KindBoolean}
	Timestamp = ColumnType{Kind: KindTimestamp}
	Date      = ColumnType{Kind: KindDate}
	JSON      = ColumnType{Kind: KindJSON}
	UUID      = ColumnType{Kind: KindUUID}
	Bytes     = ColumnType{Kind: KindBytes}
	Float     = ColumnType{Kind: KindFloat}
)

The portable types.

View Source
var DefaultRegistry = NewMigrationRegistry()

DefaultRegistry is the global migration registry. Modules register their groups here via init() functions.

View Source
var ErrInvalidOperation = errors.New("migrate: invalid schema operation")

ErrInvalidOperation is wrapped by every error a schema builder reports for a misused chain or an operation that can't be rendered.

View Source
var ErrLockHeld = errors.New("migrate: lock is held by another process")

ErrLockHeld is returned when a migration lock is already held.

View Source
var ErrSchemaUnsupported = errors.New("migrate: schema operation not supported")

ErrSchemaUnsupported is wrapped by the error a driver returns when it can't carry out a schema operation, or has no schema renderer at all.

View Source
var ErrTxUnsupported = errors.New("migrate: executor cannot run this migration in a transaction")

ErrTxUnsupported is what TxExecutor.BeginTx returns when the executor can't run the migration in a transaction. It isn't a failure: the migration runs plain, as it would on an executor without TxExecutor.

View Source
var ErrUnknownDriver = errors.New("migrate: cannot tell which driver this executor runs on")

ErrUnknownDriver is wrapped by the error a builder returns when it can't tell which driver its executor runs on.

Functions

func DriverNameOf added in v1.10.0

func DriverNameOf(exec Executor) (string, bool)

DriverNameOf returns the driver name of exec, following Unwrapper through any wrappers until an executor implements DriverNamer. The bool is false when none does.

func ExecutorAs added in v1.10.0

func ExecutorAs[T any](exec Executor) (T, bool)

ExecutorAs finds the first executor in exec's wrapper chain that is a T, following Unwrapper. A driver's own helpers use it to reach their concrete executor even when a test wrapper sits in front.

func Executors

func Executors() []string

Executors returns the names of all registered executor factories.

func IsLockError

func IsLockError(err error) bool

IsLockError returns true if the error indicates a lock conflict.

func MigrationLockTableSchema

func MigrationLockTableSchema() string

MigrationLockTableSchema returns the CREATE TABLE SQL for the lock table.

func MigrationTableSchema

func MigrationTableSchema() string

MigrationTableSchema returns the CREATE TABLE SQL for the migration tracking table.

func RegisterExecutor

func RegisterExecutor(driverName string, factory ExecutorFactory)

RegisterExecutor registers a migration executor factory for a given driver name. It is typically called from a driver's migrate package init() function for auto-registration, or explicitly by user code during setup.

Subsequent calls with the same name overwrite the previous registration.

Auto-registration example (in pgmigrate package):

func init() {
    migrate.RegisterExecutor("pg", func(drv any) migrate.Executor {
        return New(drv.(driver.Driver))
    })
}

Explicit registration example:

migrate.RegisterExecutor("pg", func(drv any) migrate.Executor {
    return pgmigrate.New(drv.(driver.Driver))
})

func RegisterRenderer added in v1.10.0

func RegisterRenderer(driverName string, r Renderer)

RegisterRenderer registers the schema renderer for a driver name, the same name the driver's executor reports through DriverNamer. A driver's migrate package usually calls it from init, next to RegisterExecutor.

Subsequent calls with the same name overwrite the previous registration, and a nil renderer counts as none registered.

func Unsupported added in v1.10.0

func Unsupported(driverName, feature string) error

Unsupported reports that driverName can't do feature. The error wraps ErrSchemaUnsupported, so callers match it with errors.Is.

Types

type Action added in v1.10.0

type Action string

Action is a foreign key referential action.

const (
	NoAction   Action = "NO ACTION"
	Restrict   Action = "RESTRICT"
	Cascade    Action = "CASCADE"
	SetNull    Action = "SET NULL"
	SetDefault Action = "SET DEFAULT"
)

The referential actions a foreign key accepts.

type AlterAction added in v1.10.0

type AlterAction struct {
	Kind    AlterKind
	Column  Column
	Name    string
	NewName string
	Default *DefaultValue
	Type    ColumnType

	// Using is the expression that converts existing values for AlterSetType.
	Using      string
	Constraint Constraint

	IfExists    bool
	IfNotExists bool
	Cascade     bool
}

AlterAction is one change inside an AlterTable. Which fields matter depends on Kind:

  • AlterAddColumn uses Column, and IfNotExists.
  • AlterDropColumn uses Name, IfExists and Cascade.
  • AlterSetNotNull, AlterDropNotNull and AlterDropDefault use Name, the column.
  • AlterSetDefault uses Name and Default.
  • AlterSetType uses Name, Type and optionally Using.
  • AlterAddConstraint uses Constraint.
  • AlterDropConstraint uses Name, the constraint, with IfExists and Cascade.
  • AlterRenameColumn renames Name to NewName.
  • AlterRenameTo uses NewName, the table's new name.

type AlterKind added in v1.10.0

type AlterKind int

AlterKind says what one AlterAction does.

const (
	AlterAddColumn AlterKind = iota + 1
	AlterDropColumn
	AlterSetNotNull
	AlterDropNotNull
	AlterSetDefault
	AlterDropDefault
	AlterSetType
	AlterAddConstraint
	AlterDropConstraint
	AlterRenameColumn
	AlterRenameTo
)

The changes an ALTER TABLE can carry.

type AlterTable added in v1.10.0

type AlterTable struct {
	Table   string
	Actions []AlterAction
}

AlterTable changes an existing table. Actions run in the order written.

type AlterTableQuery added in v1.10.0

type AlterTableQuery struct {
	// contains filtered or unexported fields
}

AlterTableQuery builds an AlterTable. Each call adds one action, and the modifiers (IfExists, Using, Named and so on) apply to the action before them.

func (*AlterTableQuery) AddCheck added in v1.10.0

func (q *AlterTableQuery) AddCheck(sql string) *AlterTableQuery

AddCheck adds a CHECK constraint.

func (*AlterTableQuery) AddColumn added in v1.10.0

func (q *AlterTableQuery) AddColumn(name string, typ ColumnType, opts ...ColumnOption) *AlterTableQuery

AddColumn adds a column.

func (*AlterTableQuery) AddForeignKey added in v1.10.0

func (q *AlterTableQuery) AddForeignKey(cols ...string) *AlterTableQuery

AddForeignKey starts a foreign key over cols. Follow it with References, and optionally OnDelete.

func (*AlterTableQuery) AddPrimaryKey added in v1.10.0

func (q *AlterTableQuery) AddPrimaryKey(cols ...string) *AlterTableQuery

AddPrimaryKey adds a primary key over cols.

func (*AlterTableQuery) AddUnique added in v1.10.0

func (q *AlterTableQuery) AddUnique(cols ...string) *AlterTableQuery

AddUnique adds a UNIQUE constraint over cols.

func (*AlterTableQuery) Cascade added in v1.10.0

func (q *AlterTableQuery) Cascade() *AlterTableQuery

Cascade makes the DropColumn or DropConstraint before it drop whatever depends on the target too.

func (*AlterTableQuery) DropColumn added in v1.10.0

func (q *AlterTableQuery) DropColumn(name string) *AlterTableQuery

DropColumn drops a column.

func (*AlterTableQuery) DropConstraint added in v1.10.0

func (q *AlterTableQuery) DropConstraint(name string) *AlterTableQuery

DropConstraint drops the constraint called name.

func (*AlterTableQuery) DropDefault added in v1.10.0

func (q *AlterTableQuery) DropDefault(col string) *AlterTableQuery

DropDefault removes the default on col.

func (*AlterTableQuery) DropNotNull added in v1.10.0

func (q *AlterTableQuery) DropNotNull(col string) *AlterTableQuery

DropNotNull allows NULL in col again.

func (*AlterTableQuery) Exec added in v1.10.0

func (q *AlterTableQuery) Exec(ctx context.Context) error

Exec checks the chain, then has the renderer for the executor's driver apply it. A misused chain returns its error without touching the executor. An executor whose driver can't be told returns ErrUnknownDriver, and a driver with no renderer returns ErrSchemaUnsupported.

func (*AlterTableQuery) IfExists added in v1.10.0

func (q *AlterTableQuery) IfExists() *AlterTableQuery

IfExists makes the DropColumn or DropConstraint before it skip a missing target.

func (*AlterTableQuery) IfNotExists added in v1.10.0

func (q *AlterTableQuery) IfNotExists() *AlterTableQuery

IfNotExists makes the AddColumn before it skip a column that is already there.

func (*AlterTableQuery) Named added in v1.10.0

func (q *AlterTableQuery) Named(name string) *AlterTableQuery

Named names the constraint you just added. Left unnamed, the driver picks a name.

func (*AlterTableQuery) OnDelete added in v1.10.0

func (q *AlterTableQuery) OnDelete(a Action) *AlterTableQuery

OnDelete sets the referential action of the foreign key you just added. It has to follow References.

func (*AlterTableQuery) Operation added in v1.10.0

func (q *AlterTableQuery) Operation() (*AlterTable, error)

Operation returns what the chain describes. A misused chain returns its first mistake, wrapped in ErrInvalidOperation.

func (*AlterTableQuery) References added in v1.10.0

func (q *AlterTableQuery) References(table string, cols ...string) *AlterTableQuery

References sets the target of the foreign key you just added.

func (*AlterTableQuery) RenameColumn added in v1.10.0

func (q *AlterTableQuery) RenameColumn(from, to string) *AlterTableQuery

RenameColumn renames a column.

func (*AlterTableQuery) RenameTo added in v1.10.0

func (q *AlterTableQuery) RenameTo(name string) *AlterTableQuery

RenameTo renames the table.

func (*AlterTableQuery) SetDefault added in v1.10.0

func (q *AlterTableQuery) SetDefault(col string, value any) *AlterTableQuery

SetDefault sets a literal default on col. A nil value means DEFAULT NULL.

func (*AlterTableQuery) SetDefaultExpr added in v1.10.0

func (q *AlterTableQuery) SetDefaultExpr(col, sql string) *AlterTableQuery

SetDefaultExpr sets a default on col from a SQL expression.

func (*AlterTableQuery) SetNotNull added in v1.10.0

func (q *AlterTableQuery) SetNotNull(col string) *AlterTableQuery

SetNotNull forbids NULL in col.

func (*AlterTableQuery) SetType added in v1.10.0

func (q *AlterTableQuery) SetType(col string, typ ColumnType) *AlterTableQuery

SetType changes the type of col. Follow it with Using when existing values need converting.

func (*AlterTableQuery) Using added in v1.10.0

func (q *AlterTableQuery) Using(sql string) *AlterTableQuery

Using sets the expression that converts existing values for the SetType before it.

type AppliedMigration

type AppliedMigration struct {
	ID         int64
	Version    string
	Name       string
	Group      string
	MigratedAt string // ISO 8601 timestamp
}

AppliedMigration records that a migration has been applied.

type Column added in v1.10.0

type Column struct {
	Name       string
	Type       ColumnType
	NotNull    bool
	Default    *DefaultValue
	PrimaryKey bool
	Unique     bool

	// Check is a SQL expression for a column-level CHECK constraint.
	Check      string
	References *Reference

	// Identity makes the column GENERATED ALWAYS AS IDENTITY.
	Identity bool

	// Generated is a SQL expression for a stored generated column.
	Generated string
}

Column describes one column of a table.

type ColumnOption added in v1.10.0

type ColumnOption func(*Column) error

ColumnOption adjusts a column as a builder adds it. The builder wraps an error from an option in ErrInvalidOperation and the column's name, so an option returns a plain error.

func Check added in v1.10.0

func Check(sql string) ColumnOption

Check adds a column-level CHECK constraint.

func Default added in v1.10.0

func Default(value any) ColumnOption

Default sets a literal default. A nil value means DEFAULT NULL.

func DefaultExpr added in v1.10.0

func DefaultExpr(sql string) ColumnOption

DefaultExpr sets a default from a SQL expression such as now(), spliced in as written.

func GeneratedAs added in v1.10.0

func GeneratedAs(sql string) ColumnOption

GeneratedAs makes the column a stored generated column computed from sql.

func Identity added in v1.10.0

func Identity() ColumnOption

Identity makes the column GENERATED ALWAYS AS IDENTITY.

func NotNull added in v1.10.0

func NotNull() ColumnOption

NotNull forbids NULL in the column.

func OnDelete added in v1.10.0

func OnDelete(a Action) ColumnOption

OnDelete sets what happens to this row when the referenced row is deleted. It has to come after References.

func PrimaryKey added in v1.10.0

func PrimaryKey() ColumnOption

PrimaryKey makes the column the table's primary key. Use the table-level PrimaryKey for a composite one.

func References added in v1.10.0

func References(table string, columns ...string) ColumnOption

References makes the column a foreign key to table. A column-level reference names exactly one column. Use ForeignKey on the table for a composite key.

func Unique added in v1.10.0

func Unique() ColumnOption

Unique adds a UNIQUE constraint on this column alone.

type ColumnType added in v1.10.0

type ColumnType struct {
	Kind TypeKind

	// Raw is the type name passed straight to the driver when Kind is KindRaw.
	Raw string

	// Precision and Scale apply to KindNumeric. Both zero means no limits.
	Precision, Scale int

	// Elem is the element type when Kind is KindArray.
	Elem *ColumnType
}

ColumnType is a driver-agnostic column type. Use the package variables (Text, Integer and friends), Numeric, ArrayOf, or Type for anything a driver names but grove doesn't.

func ArrayOf added in v1.10.0

func ArrayOf(elem ColumnType) ColumnType

ArrayOf is an array of elem.

func Numeric added in v1.10.0

func Numeric(precision, scale int) ColumnType

Numeric is an exact decimal with the given precision and scale.

func Type added in v1.10.0

func Type(raw string) ColumnType

Type passes raw to the driver untouched, for types with no portable name such as Type("INET").

type Constraint added in v1.10.0

type Constraint struct {
	Kind       ConstraintKind
	Name       string
	Columns    []string
	Check      string
	References *Reference
}

Constraint is a table-level constraint. Name is empty when the driver should pick one.

type ConstraintKind added in v1.10.0

type ConstraintKind int

ConstraintKind says what a Constraint enforces.

const (
	PrimaryKeyConstraint ConstraintKind = iota + 1
	UniqueConstraint
	CheckConstraint
	ForeignKeyConstraint
)

The table constraints a builder can declare.

type CreateIndex added in v1.10.0

type CreateIndex struct {
	Name         string
	Table        string
	Columns      []IndexColumn
	Unique       bool
	IfNotExists  bool
	Concurrently bool

	// Using is the access method, such as gin, on drivers that have one.
	Using   string
	Include []string

	// Where is a SQL predicate for a partial index.
	Where string

	// Filter is the document form of Where, for drivers that take one.
	Filter any

	// Options carries driver-specific settings. A driver rejects any value it
	// doesn't recognise.
	Options []any
}

CreateIndex creates an index.

type CreateIndexQuery added in v1.10.0

type CreateIndexQuery struct {
	// contains filtered or unexported fields
}

CreateIndexQuery builds a CreateIndex.

func (*CreateIndexQuery) ColumnDesc added in v1.10.0

func (q *CreateIndexQuery) ColumnDesc(name string) *CreateIndexQuery

ColumnDesc adds a column sorted in descending order.

func (*CreateIndexQuery) ColumnExpr added in v1.10.0

func (q *CreateIndexQuery) ColumnExpr(sql string) *CreateIndexQuery

ColumnExpr adds a SQL expression such as lower(name) as an index key.

func (*CreateIndexQuery) Columns added in v1.10.0

func (q *CreateIndexQuery) Columns(names ...string) *CreateIndexQuery

Columns adds plain columns as index keys, in order.

func (*CreateIndexQuery) Concurrently added in v1.10.0

func (q *CreateIndexQuery) Concurrently() *CreateIndexQuery

Concurrently builds the index without blocking writes, on drivers that support it.

func (*CreateIndexQuery) Exec added in v1.10.0

func (q *CreateIndexQuery) Exec(ctx context.Context) error

Exec checks the chain, then has the renderer for the executor's driver apply it. A misused chain returns its error without touching the executor. An executor whose driver can't be told returns ErrUnknownDriver, and a driver with no renderer returns ErrSchemaUnsupported.

func (*CreateIndexQuery) Filter added in v1.10.0

func (q *CreateIndexQuery) Filter(doc any) *CreateIndexQuery

Filter is the document form of Where, for drivers that filter with a document, such as MongoDB's partialFilterExpression.

func (*CreateIndexQuery) IfNotExists added in v1.10.0

func (q *CreateIndexQuery) IfNotExists() *CreateIndexQuery

IfNotExists skips the statement when the index is already there.

func (*CreateIndexQuery) Include added in v1.10.0

func (q *CreateIndexQuery) Include(cols ...string) *CreateIndexQuery

Include adds non-key columns stored in the index.

func (*CreateIndexQuery) On added in v1.10.0

On sets the table the index covers.

func (*CreateIndexQuery) Operation added in v1.10.0

func (q *CreateIndexQuery) Operation() (*CreateIndex, error)

Operation returns what the chain describes. A misused chain returns its first mistake, wrapped in ErrInvalidOperation.

func (*CreateIndexQuery) Unique added in v1.10.0

func (q *CreateIndexQuery) Unique() *CreateIndexQuery

Unique makes the index enforce uniqueness.

func (*CreateIndexQuery) Using added in v1.10.0

func (q *CreateIndexQuery) Using(method string) *CreateIndexQuery

Using picks the index access method, such as gin.

func (*CreateIndexQuery) Where added in v1.10.0

func (q *CreateIndexQuery) Where(sql string) *CreateIndexQuery

Where makes the index partial, covering only rows that match the SQL predicate.

func (*CreateIndexQuery) With added in v1.10.0

func (q *CreateIndexQuery) With(opts ...any) *CreateIndexQuery

With passes driver-specific options. A driver returns an error for any option it doesn't recognise.

type CreateTable added in v1.10.0

type CreateTable struct {
	Table       string
	IfNotExists bool
	Columns     []Column
	Constraints []Constraint

	// Model is a grove model to take the columns from instead of Columns.
	Model any

	// Options carries driver-specific settings, such as a Mongo collection
	// option. A driver rejects any value it doesn't recognise.
	Options []any
}

CreateTable creates a table, or a collection on drivers without tables.

Columns render in the order written, then Constraints in the order written, because a driver that names unnamed constraints derives the name from that order. A builder enforces this by rejecting a column declared after a table constraint, so the order you write is the order a driver sees. A builder never sets Model together with Columns or Constraints.

type CreateTableQuery added in v1.10.0

type CreateTableQuery struct {
	// contains filtered or unexported fields
}

CreateTableQuery builds a CreateTable.

func (*CreateTableQuery) Check added in v1.10.0

func (q *CreateTableQuery) Check(expr string) *CreateTableQuery

Check adds a table-level CHECK constraint.

func (*CreateTableQuery) Column added in v1.10.0

func (q *CreateTableQuery) Column(name string, typ ColumnType, opts ...ColumnOption) *CreateTableQuery

Column adds a column. Columns render in the order you add them, and they all come before the table constraints. Declare every column first: a Column after PrimaryKey, Unique, Check or ForeignKey is a misuse, because the constraint modifiers (Named, References, OnDelete) bind to the last constraint and the written order would no longer be the rendered order.

func (*CreateTableQuery) Exec added in v1.10.0

func (q *CreateTableQuery) Exec(ctx context.Context) error

Exec checks the chain, then has the renderer for the executor's driver apply it. A misused chain returns its error without touching the executor. An executor whose driver can't be told returns ErrUnknownDriver, and a driver with no renderer returns ErrSchemaUnsupported.

func (*CreateTableQuery) ForeignKey added in v1.10.0

func (q *CreateTableQuery) ForeignKey(cols ...string) *CreateTableQuery

ForeignKey starts a foreign key over cols. Follow it with References, and optionally OnDelete.

func (*CreateTableQuery) IfNotExists added in v1.10.0

func (q *CreateTableQuery) IfNotExists() *CreateTableQuery

IfNotExists skips the statement when the table is already there.

func (*CreateTableQuery) Model added in v1.10.0

func (q *CreateTableQuery) Model(model any) *CreateTableQuery

Model takes the columns from a grove model instead of Column calls, for example Model((*User)(nil)). It can't be combined with columns or constraints.

func (*CreateTableQuery) Named added in v1.10.0

func (q *CreateTableQuery) Named(name string) *CreateTableQuery

Named names the constraint you just added. Left unnamed, the driver picks a name.

func (*CreateTableQuery) OnDelete added in v1.10.0

func (q *CreateTableQuery) OnDelete(a Action) *CreateTableQuery

OnDelete sets the referential action of the foreign key you just started. It has to follow References.

func (*CreateTableQuery) Operation added in v1.10.0

func (q *CreateTableQuery) Operation() (*CreateTable, error)

Operation returns what the chain describes. A misused chain returns its first mistake, wrapped in ErrInvalidOperation.

func (*CreateTableQuery) PrimaryKey added in v1.10.0

func (q *CreateTableQuery) PrimaryKey(cols ...string) *CreateTableQuery

PrimaryKey adds a table-level primary key over cols.

func (*CreateTableQuery) References added in v1.10.0

func (q *CreateTableQuery) References(table string, cols ...string) *CreateTableQuery

References sets the target of the foreign key you just started.

func (*CreateTableQuery) Unique added in v1.10.0

func (q *CreateTableQuery) Unique(cols ...string) *CreateTableQuery

Unique adds a table-level UNIQUE constraint over cols.

func (*CreateTableQuery) With added in v1.10.0

func (q *CreateTableQuery) With(opts ...any) *CreateTableQuery

With passes driver-specific options. A driver returns an error for any option it doesn't recognise.

type DB added in v1.10.0

type DB struct {
	// contains filtered or unexported fields
}

DB is the handle a migration builds its schema through. It wraps an Executor, and the builders it hands out end in Exec, which looks up the renderer registered for the executor's driver and has it apply the operation. The same handle runs raw statements through Exec and Query for anything the builders don't cover.

func NewDB added in v1.10.0

func NewDB(exec Executor) *DB

NewDB wraps exec. Tests pass nil when they only inspect what a builder produces with Operation. Running a builder against a nil executor returns ErrUnknownDriver.

func (*DB) Apply added in v1.10.0

func (db *DB) Apply(ctx context.Context, op Operation) error

Apply hands op to the renderer registered for the executor's driver. The builders call it from Exec after checking the chain, so it validates nothing itself. The renderer gets the executor as the handle holds it, not the executor inside a wrapper, so a wrapper keeps seeing every statement.

func (*DB) Dialect added in v1.10.0

func (db *DB) Dialect() string

Dialect returns the name of the driver behind the executor, such as "pg" or "mongo", or "" when the executor and anything it wraps never name one.

func (*DB) Exec added in v1.10.0

func (db *DB) Exec(ctx context.Context, query string, args ...any) (driver.Result, error)

Exec runs a statement that returns no rows, straight on the executor.

func (*DB) Executor added in v1.10.0

func (db *DB) Executor() Executor

Executor returns the executor the handle was built on.

func (*DB) NewAlterTable added in v1.10.0

func (db *DB) NewAlterTable(table string) *AlterTableQuery

NewAlterTable starts an ALTER TABLE for table. Chain several actions and they run in order.

func (*DB) NewCreateIndex added in v1.10.0

func (db *DB) NewCreateIndex(name string) *CreateIndexQuery

NewCreateIndex starts a CREATE INDEX called name. It needs On and at least one column before it can run.

func (*DB) NewCreateTable added in v1.10.0

func (db *DB) NewCreateTable(table string) *CreateTableQuery

NewCreateTable starts a CREATE TABLE for table.

func (*DB) NewDropIndex added in v1.10.0

func (db *DB) NewDropIndex(name string) *DropIndexQuery

NewDropIndex starts a DROP INDEX for name.

func (*DB) NewDropTable added in v1.10.0

func (db *DB) NewDropTable(table string) *DropTableQuery

NewDropTable starts a DROP TABLE for table.

func (*DB) Query added in v1.10.0

func (db *DB) Query(ctx context.Context, query string, args ...any) (driver.Rows, error)

Query runs a statement that returns rows, straight on the executor.

type DefaultValue added in v1.10.0

type DefaultValue struct {
	Value any
	Expr  string
}

DefaultValue is a column default. A non-empty Expr is a SQL expression the driver splices in as written. Otherwise Value is a literal, and nil means NULL.

type DriverNamer added in v1.10.0

type DriverNamer interface {
	DriverName() string
}

DriverNamer is implemented by an executor that knows which driver it runs on, such as "pg" or "mongo". It picks the renderer for that driver's schema operations.

type DropIndex added in v1.10.0

type DropIndex struct {
	Name         string
	Table        string
	IfExists     bool
	Concurrently bool
	Cascade      bool
}

DropIndex drops an index. Table is needed only on drivers that scope indexes to a table or collection.

type DropIndexQuery added in v1.10.0

type DropIndexQuery struct {
	// contains filtered or unexported fields
}

DropIndexQuery builds a DropIndex.

func (*DropIndexQuery) Cascade added in v1.10.0

func (q *DropIndexQuery) Cascade() *DropIndexQuery

Cascade drops whatever depends on the index too.

func (*DropIndexQuery) Concurrently added in v1.10.0

func (q *DropIndexQuery) Concurrently() *DropIndexQuery

Concurrently drops the index without blocking writes, on drivers that support it.

func (*DropIndexQuery) Exec added in v1.10.0

func (q *DropIndexQuery) Exec(ctx context.Context) error

Exec checks the chain, then has the renderer for the executor's driver apply it. A misused chain returns its error without touching the executor. An executor whose driver can't be told returns ErrUnknownDriver, and a driver with no renderer returns ErrSchemaUnsupported.

func (*DropIndexQuery) IfExists added in v1.10.0

func (q *DropIndexQuery) IfExists() *DropIndexQuery

IfExists skips the statement when the index is already gone.

func (*DropIndexQuery) On added in v1.10.0

func (q *DropIndexQuery) On(table string) *DropIndexQuery

On sets the table the index belongs to. Postgres doesn't need it, and MongoDB does.

func (*DropIndexQuery) Operation added in v1.10.0

func (q *DropIndexQuery) Operation() (*DropIndex, error)

Operation returns what the chain describes, or its first mistake wrapped in ErrInvalidOperation.

type DropTable added in v1.10.0

type DropTable struct {
	Table    string
	IfExists bool
	Cascade  bool
}

DropTable drops a table, or a collection.

type DropTableQuery added in v1.10.0

type DropTableQuery struct {
	// contains filtered or unexported fields
}

DropTableQuery builds a DropTable.

func (*DropTableQuery) Cascade added in v1.10.0

func (q *DropTableQuery) Cascade() *DropTableQuery

Cascade drops whatever depends on the table too.

func (*DropTableQuery) Exec added in v1.10.0

func (q *DropTableQuery) Exec(ctx context.Context) error

Exec checks the chain, then has the renderer for the executor's driver apply it. A misused chain returns its error without touching the executor. An executor whose driver can't be told returns ErrUnknownDriver, and a driver with no renderer returns ErrSchemaUnsupported.

func (*DropTableQuery) IfExists added in v1.10.0

func (q *DropTableQuery) IfExists() *DropTableQuery

IfExists skips the statement when the table is already gone.

func (*DropTableQuery) Operation added in v1.10.0

func (q *DropTableQuery) Operation() (*DropTable, error)

Operation returns what the chain describes, or its first mistake wrapped in ErrInvalidOperation.

type Executor

type Executor interface {
	// Exec executes a SQL statement that does not return rows.
	Exec(ctx context.Context, query string, args ...any) (driver.Result, error)

	// Query executes a SQL statement that returns rows.
	Query(ctx context.Context, query string, args ...any) (driver.Rows, error)

	// EnsureMigrationTable creates the migration tracking table if it doesn't exist.
	EnsureMigrationTable(ctx context.Context) error

	// EnsureLockTable creates the migration lock table if it doesn't exist.
	EnsureLockTable(ctx context.Context) error

	// AcquireLock attempts to acquire the distributed migration lock.
	// Returns an error if the lock is held by another process.
	AcquireLock(ctx context.Context, lockedBy string) error

	// ReleaseLock releases the distributed migration lock.
	ReleaseLock(ctx context.Context) error

	// ListApplied returns all migrations that have been applied.
	ListApplied(ctx context.Context) ([]*AppliedMigration, error)

	// RecordApplied records that a migration was successfully applied.
	RecordApplied(ctx context.Context, m *Migration) error

	// RemoveApplied removes the record of an applied migration (for rollback).
	RemoveApplied(ctx context.Context, m *Migration) error
}

Executor is the interface that driver-specific migration executors implement. It provides methods for running DDL/DML within migrations and managing the migration version table and lock.

func NewExecutorFor

func NewExecutorFor(drv any) (Executor, error)

NewExecutorFor creates a migration Executor for the given driver using the registered factory. The driver must implement a Name() string method (satisfied by both grove.GroveDriver and driver.Driver). Returns an error if no factory is registered for the driver's name.

type ExecutorFactory

type ExecutorFactory func(drv any) Executor

ExecutorFactory is a function that creates a migration Executor from a driver. The driver parameter is typed as any to support both SQL-based drivers (driver.Driver) and non-SQL drivers (e.g., *mongodriver.MongoDB). Each factory performs its own type assertion on the driver.

type Func added in v1.10.0

type Func func(ctx context.Context, db *DB) error

Func is the body of a migration written against a DB. Up and down functions use it so they can reach the schema builders without caring which executor runs them.

type Group

type Group struct {
	// contains filtered or unexported fields
}

Group represents a collection of migrations owned by a module or extension. Each group has a unique name (e.g., "core", "forge.billing") and can declare dependencies on other groups.

func NewGroup

func NewGroup(name string, opts ...GroupOption) *Group

NewGroup creates a new migration group with the given name and options.

var Migrations = migrate.NewGroup("core")
var Migrations = migrate.NewGroup("forge.billing", migrate.DependsOn("core"))

func (*Group) Add added in v1.10.0

func (g *Group) Add(up, down Func, opts ...Option)

Add registers a migration whose version and name come from the file that calls it, so the file name is the only place the version is written down. Call it from an init function in a file named <14 digit version>_<name>.go:

// 20240102030405_create_widgets.go
func init() {
	Migrations.Add(
		func(ctx context.Context, db *migrate.DB) error {
			return db.NewCreateTable("widgets").
				Column("id", migrate.Text, migrate.PrimaryKey()).
				Exec(ctx)
		},
		func(ctx context.Context, db *migrate.DB) error {
			return db.NewDropTable("widgets").Exec(ctx)
		},
	)
}

Add panics when the caller's file name doesn't fit that shape, or when the group already holds the version. An init that fails to register would otherwise leave a migration quietly missing from the plan.

func (*Group) DependsOnGroups

func (g *Group) DependsOnGroups() []string

DependsOnGroups returns the list of group names this group depends on.

func (*Group) Migrations

func (g *Group) Migrations() []*Migration

Migrations returns a copy of the group's migrations sorted by version.

func (*Group) MustRegister

func (g *Group) MustRegister(migrations ...*Migration)

MustRegister is like Register but panics on error.

func (*Group) Name

func (g *Group) Name() string

Name returns the group name.

func (*Group) Register

func (g *Group) Register(migrations ...*Migration) error

Register adds migrations to the group. The group name is automatically set on each migration. Returns an error if any migration has a duplicate version within this group.

type GroupOption

type GroupOption func(*Group)

GroupOption configures a migration group.

func DependsOn

func DependsOn(groups ...string) GroupOption

DependsOn declares that this group's migrations must run after the specified groups have completed.

type GroupStatus

type GroupStatus struct {
	Name    string
	Applied []*MigrationStatus
	Pending []*MigrationStatus
}

GroupStatus describes the state of all migrations in a group.

type IndexColumn added in v1.10.0

type IndexColumn struct {
	Name string
	Expr string
	Desc bool
}

IndexColumn is one key of an index: a column by Name, or an expression.

type LockInfo

type LockInfo struct {
	Held     bool
	LockedBy string
	LockedAt string
}

LockInfo describes the current migration lock state.

type LockInspector

type LockInspector interface {
	LockInfo(ctx context.Context) (*LockInfo, error)
}

LockInspector is an optional capability: executors that can report who holds the migration lock implement it, letting the orchestrator produce a diagnosable error when the wait budget is exhausted.

type MigrateFunc

type MigrateFunc func(ctx context.Context, exec Executor) error //nolint:revive // MigrateFunc is the established public API name

MigrateFunc is a function that performs a migration step. It receives a context and an Executor for running DDL/DML statements.

type MigrateResult

type MigrateResult struct {
	Applied  []*Migration // Migrations that were applied
	Rollback []*Migration // Migrations that were rolled back (for Rollback only)
}

MigrateResult holds the result of a Migrate or Rollback operation.

type Migration

type Migration struct {
	// Name is a human-readable identifier (e.g., "create_users").
	Name string

	// Version is a timestamp-based version string (e.g., "20240115120000").
	// Migrations run in version order within dependency constraints.
	Version string

	// Group identifies the module/extension that owns this migration.
	// Set automatically when registered with a Group.
	Group string

	// Up runs the forward migration.
	Up MigrateFunc

	// Down runs the rollback.
	Down MigrateFunc

	// Comment is an optional description.
	Comment string

	// Transactional makes the migrator run Up or Down and its applied record
	// in one transaction when the executor supports it. Add and Define set
	// it. Migrations registered as structs keep running without one.
	Transactional bool
}

Migration represents a single versioned migration.

func Define added in v1.10.0

func Define(version, name string, up, down Func, opts ...Option) *Migration

Define builds a migration from an up and a down function. It starts with Transactional on and then applies opts, so NoTransaction has the last word. Up and Down are left nil when the matching function is nil, which keeps the migrator's missing-Up check and the rollback-without-Down path working. Group.Register fills in Group.

type MigrationRegistry

type MigrationRegistry struct {
	// contains filtered or unexported fields
}

MigrationRegistry holds registered migration groups.

func NewMigrationRegistry

func NewMigrationRegistry() *MigrationRegistry

NewMigrationRegistry creates an empty MigrationRegistry.

func (*MigrationRegistry) Groups

func (r *MigrationRegistry) Groups() []*Group

Groups returns a copy of all registered migration groups.

func (*MigrationRegistry) Register

func (r *MigrationRegistry) Register(groups ...*Group)

Register adds one or more migration groups to the registry.

type MigrationStatus

type MigrationStatus struct {
	Migration *Migration
	Applied   bool
	AppliedAt string // empty if not applied
}

MigrationStatus describes the state of a single migration.

type Operation added in v1.10.0

type Operation interface {
	// contains filtered or unexported methods
}

Operation is a schema change a builder produced and a driver renders. The concrete types are the five exported structs below, so a renderer switches on them. Nobody outside this package implements it.

type Option added in v1.10.0

type Option func(*Migration)

Option adjusts a migration built by Define or registered by Group.Add.

func Comment added in v1.10.0

func Comment(text string) Option

Comment sets the migration's description.

func NoTransaction added in v1.10.0

func NoTransaction() Option

NoTransaction opts a migration out of the transaction Add and Define give it by default. Use it for statements a transaction can't hold, such as CREATE INDEX CONCURRENTLY on Postgres.

type Orchestrator

type Orchestrator struct {
	// contains filtered or unexported fields
}

Orchestrator manages migration execution across multiple groups.

func NewOrchestrator

func NewOrchestrator(executor Executor, groups ...*Group) *Orchestrator

NewOrchestrator creates a new migration orchestrator.

func (*Orchestrator) Migrate

func (o *Orchestrator) Migrate(ctx context.Context) (*MigrateResult, error)

Migrate runs all pending migrations in dependency-resolved order.

Steps:

  1. Ensure migration and lock tables exist
  2. Acquire distributed lock
  3. Load already-applied migrations
  4. Topologically sort groups by dependencies
  5. Execute pending migrations in order, each in a transaction with its applied record when the migration is Transactional and the executor is a TxExecutor
  6. Release lock

func (*Orchestrator) Rollback

func (o *Orchestrator) Rollback(ctx context.Context) (*MigrateResult, error)

Rollback rolls back the last batch of applied migrations (one per group, most recently applied first).

func (*Orchestrator) SetLockTimeout

func (o *Orchestrator) SetLockTimeout(d time.Duration) *Orchestrator

SetLockTimeout overrides the lock-wait budget. 0 = wait until ctx deadline.

func (*Orchestrator) Status

func (o *Orchestrator) Status(ctx context.Context) ([]*GroupStatus, error)

Status returns the status of all migrations across all groups.

type Reference added in v1.10.0

type Reference struct {
	Table   string
	Columns []string

	// OnDelete is empty when the driver's default applies.
	OnDelete Action
}

Reference is the target of a foreign key.

type Renderer added in v1.10.0

type Renderer interface {
	Apply(ctx context.Context, exec Executor, op Operation) error
}

Renderer turns schema operations into work on one driver. A driver's migrate package registers one with RegisterRenderer. Apply runs the work through exec, the executor the migration was handed, so a wrapper around it still sees every statement.

type TxExecutor added in v1.10.0

type TxExecutor interface {
	// BeginTx opens the transaction. It returns [ErrTxUnsupported] when this
	// executor can't hold one for the migration, and the orchestrator then runs
	// the migration without it.
	BeginTx(ctx context.Context) error

	// CommitTx commits the transaction.
	CommitTx(ctx context.Context) error

	// RollbackTx abandons the transaction. The orchestrator also calls it
	// after a failed CommitTx, so it has to tolerate a transaction that is
	// already finished.
	RollbackTx(ctx context.Context) error
}

TxExecutor is an optional interface an Executor implements so the orchestrator can run a migration and its applied record in one transaction. The orchestrator finds it with ExecutorAs, so a wrapper that has an Unwrap method keeps the transactions of the executor inside it, and executors that don't implement it keep working without one.

The orchestrator owns the transaction, and the executor holds its state on the connection that has the migration lock. BeginTx returns no handle: after it, every statement the migration runs through the executor, and the RecordApplied or RemoveApplied call that follows, must go through that transaction on that connection until CommitTx or RollbackTx.

type TypeKind added in v1.10.0

type TypeKind int

TypeKind says which portable type a ColumnType stands for.

const (
	KindText TypeKind = iota + 1
	KindSmallInt
	KindInteger
	KindBigInt
	KindBigSerial
	KindBoolean
	KindTimestamp
	KindDate
	KindJSON
	KindUUID
	KindBytes
	KindFloat
	KindNumeric
	KindArray
	KindRaw
)

The portable column types. Each driver maps them to its own type names.

type Unwrapper added in v1.10.0

type Unwrapper interface {
	Unwrap() Executor
}

Unwrapper is implemented by an executor that wraps another one, such as a test double that counts statements. It lets DriverNameOf and ExecutorAs see through the wrapper to the executor inside.

Directories

Path Synopsis
internal
addtest
Package addtest holds one migration registered with Group.Add from a file named for its version.
Package addtest holds one migration registered with Group.Add from a file named for its version.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL