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
- Variables
- func Executors() []string
- func IsLockError(err error) bool
- func MigrationLockTableSchema() string
- func MigrationTableSchema() string
- func RegisterExecutor(driverName string, factory ExecutorFactory)
- type AppliedMigration
- type Executor
- type ExecutorFactory
- type Group
- type GroupOption
- type GroupStatus
- type LockInfo
- type LockInspector
- type MigrateFunc
- type MigrateResult
- type Migration
- type MigrationRegistry
- type MigrationStatus
- type Orchestrator
Constants ¶
const ( MigrationTable = "grove_migrations" MigrationLockTable = "grove_migration_locks" )
Schema constants for the migration tracking tables.
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 ¶
var DefaultRegistry = NewMigrationRegistry()
DefaultRegistry is the global migration registry. Modules register their groups here via init() functions.
var ErrLockHeld = errors.New("migrate: lock is held by another process")
ErrLockHeld is returned when a migration lock is already held.
Functions ¶
func Executors ¶
func Executors() []string
Executors returns the names of all registered executor factories.
func IsLockError ¶
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))
})
Types ¶
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 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 ¶
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 ¶
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 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) DependsOnGroups ¶
DependsOnGroups returns the list of group names this group depends on.
func (*Group) Migrations ¶
Migrations returns a copy of the group's migrations sorted by version.
func (*Group) MustRegister ¶
MustRegister is like Register but panics on error.
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 LockInspector ¶
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
}
Migration represents a single versioned migration.
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 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:
- Ensure migration and lock tables exist
- Acquire distributed lock
- Load already-applied migrations
- Topologically sort groups by dependencies
- Execute pending migrations in order
- 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.