Documentation
¶
Overview ¶
Package migrate runs database schema migrations written with callbacks that receive an Operator. A Migration's Up and Down functions call op.CreateTable / op.AddColumn / op.DropColumn / op.CreateIndex / op.CreateForeignKey / ... to perform the change; columns are declared with the decl DSL (portable types and options), and the migrate package never asks the author to touch the sql package directly. The Migrator applies pending migrations inside a transaction and records every apply and rollback in an append-only history table (schema_migrations by default).
Migrations form a DAG: each carries a Revision id and the DownRevision it builds on (empty for the first). The Migrator resolves the apply order from those links, not from declaration order. Keep each migration in its own file and register it with a Registry:
var _ = Registry.Add(migrate.Migration{
Revision: "8f3a1c", // unique id; migrate.NewRevision() generates one
DownRevision: "", // the revision this builds on ("" = first)
Name: "create_tags",
Up: func(op *migrate.Operator) {
op.CreateTable("tags",
decl.Column("id", decl.BigInt, decl.PrimaryKey(), decl.Default()),
decl.Column("name", decl.VarChar(64), decl.Unique()),
)
},
Down: func(op *migrate.Operator) { op.DropTable("tags") },
})
m := Registry.NewMigrator(db)
err := m.Up(ctx)
Transactions: each migration applies in one transaction so its operations and its history row commit together. PostgreSQL DDL is transactional, so a failed migration rolls back cleanly. MySQL commits DDL implicitly and cannot roll a partly-applied migration back; treat MySQL migrations as non-atomic. Set DisableTx for a migration that must not run in a transaction (e.g. PostgreSQL CREATE INDEX CONCURRENTLY).
Index ¶
- func Diff(old, next meta.Metadata, dialect sql.Dialect) ([]sql.Statement, error)
- func NewRevision() string
- type AlterColumnChange
- type CLI
- type Direction
- type Execer
- type ForeignKeyOption
- type Migration
- type MigrationEvent
- type MigrationStatus
- type Migrator
- func (m *Migrator) Current(ctx context.Context) ([]string, error)
- func (m *Migrator) Down(ctx context.Context) error
- func (m *Migrator) DownTo(ctx context.Context, revision string) error
- func (m *Migrator) Downgrade(ctx context.Context, target string) error
- func (m *Migrator) DowngradeSQL(from, to string) (string, error)
- func (m *Migrator) Heads() []string
- func (m *Migrator) History(ctx context.Context) ([]MigrationEvent, error)
- func (m *Migrator) Pending(ctx context.Context) ([]Migration, error)
- func (m *Migrator) Runner(ctx context.Context) *Runner
- func (m *Migrator) Stamp(ctx context.Context, revision string) error
- func (m *Migrator) Status(ctx context.Context) ([]MigrationStatus, error)
- func (m *Migrator) Up(ctx context.Context) error
- func (m *Migrator) UpTo(ctx context.Context, revision string) error
- func (m *Migrator) Upgrade(ctx context.Context, target string) error
- func (m *Migrator) UpgradeSQL(from, to string) (string, error)
- type Operator
- func (o *Operator) AddCheck(name, table, expr string)
- func (o *Operator) AddColumn(table string, column decl.TableElement)
- func (o *Operator) AddEnumValue(name, value string)
- func (o *Operator) AddPrimaryKey(table string, columns ...string)
- func (o *Operator) AlterColumn(table, column string, changes ...AlterColumnChange)
- func (o *Operator) CreateEnum(name string, values ...string)
- func (o *Operator) CreateExtension(name string, ...)
- func (o *Operator) CreateForeignKey(name, table string, columns []string, refTable string, refColumns []string, ...)
- func (o *Operator) CreateFunction(name string, ...)
- func (o *Operator) CreateIndex(name, table string, columns ...string)
- func (o *Operator) CreateMaterializedView(name string, query sql.Query, ...)
- func (o *Operator) CreateSchema(name string)
- func (o *Operator) CreateSequence(name string, ...)
- func (o *Operator) CreateTable(name string, elements ...decl.TableElement)
- func (o *Operator) CreateTemporaryTable(name string, elements ...decl.TableElement)
- func (o *Operator) CreateUniqueIndex(name, table string, columns ...string)
- func (o *Operator) CreateView(name string, query sql.Query, opts ...ViewOption)
- func (o *Operator) DropColumn(table, column string)
- func (o *Operator) DropConstraint(name, table string)
- func (o *Operator) DropEnum(name string)
- func (o *Operator) DropExtension(name string)
- func (o *Operator) DropForeignKey(name, table string)
- func (o *Operator) DropFunction(name string, ...)
- func (o *Operator) DropIndex(name, table string)
- func (o *Operator) DropMaterializedView(name string)
- func (o *Operator) DropPrimaryKey(table string)
- func (o *Operator) DropSchema(name string)
- func (o *Operator) DropSequence(name string)
- func (o *Operator) DropTable(name string)
- func (o *Operator) DropView(name string)
- func (o *Operator) Err() error
- func (o *Operator) Exec(query sql.Query)
- func (o *Operator) Execute(stmt sql.Statement)
- func (o *Operator) Grant(grant sql.Statement)
- func (o *Operator) ModifyColumn(table string, column decl.TableElement)
- func (o *Operator) RefreshMaterializedView(name string, ...)
- func (o *Operator) RenameColumn(table, from, to string)
- func (o *Operator) RenameEnumValue(name, oldValue, newValue string)
- func (o *Operator) RenameTable(from, to string)
- func (o *Operator) Revoke(revoke sql.Statement)
- type Option
- type Registry
- type Runner
- type ViewOption
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Diff ¶
Diff compares an old schema to a desired new schema and returns the ordered DDL statements that migrate old into new — the forward (Up) plan for a migration. It takes a dialect because column-type equality and rendering are dialect-resolved.
It detects added/dropped tables; added/dropped columns; column type, nullability, and default changes; primary-key membership changes; added/dropped/changed indexes, foreign keys (including ON DELETE/UPDATE actions), and CHECK constraints; table/column comment changes; and added/dropped/changed non-table objects — extensions, enum types, sequences, materialized views, and grants — ordered so each is created before the tables that depend on it and dropped after (a changed object is dropped and recreated). Column modifications render for both PostgreSQL (separate ALTER COLUMN actions) and MySQL (a single MODIFY COLUMN). Statements are ordered for safety: drop foreign keys, drop indexes, and drop tables first; then create tables, alter columns, create indexes, add foreign keys, and set comments last.
Out of scope: column and table renames are reported as drop+add (which loses data — author a hand-written migration, or use the autogenerator's rename hints). Diff produces only the forward plan; author the Down statements by hand (the autogenerator derives a best-effort Down from the reverse diff).
func NewRevision ¶
func NewRevision() string
NewRevision returns a new random revision id (12 hex chars), a convenient collision-resistant value for Migration.Revision.
Types ¶
type AlterColumnChange ¶
type AlterColumnChange func(stmt sql.AlterTableBuilder, column string) sql.AlterTableBuilder
AlterColumnChange is one change applied by AlterColumn (TypeTo, SetNullable, SetDefault, DropDefault).
func SetDefault ¶
func SetDefault(expr string) AlterColumnChange
SetDefault sets a column's default to the given boolean/expression text.
func SetNullable ¶
func SetNullable(nullable bool) AlterColumnChange
SetNullable makes a column nullable (true) or NOT NULL (false).
func TypeTo ¶
func TypeTo(typ decl.DataType) AlterColumnChange
TypeTo changes a column's type to the given portable type.
type CLI ¶
type CLI struct {
Up upCmd `cmd:"" help:"Apply migrations up to a target (default head)."`
Down downCmd `cmd:"" help:"Roll back migrations to a target (default the most recent)."`
Stamp stampCmd `cmd:"" help:"Mark a revision applied without running it."`
Status statusCmd `cmd:"" help:"Show each migration's applied state."`
Pending pendingCmd `cmd:"" help:"List the unapplied migrations."`
Current currentCmd `cmd:"" help:"Show the revision(s) the database is at."`
Heads headsCmd `cmd:"" help:"Show the head revision(s)."`
History historyCmd `cmd:"" help:"Show the apply/rollback timeline."`
SQL sqlCmd `cmd:"" name:"sql" help:"Render migration SQL without running it."`
New newCmd `cmd:"" help:"Scaffold a new migration file."`
}
CLI is the command grammar for running and scaffolding migrations. Its struct tags describe the commands to a CLI framework without this package depending on one: build it with NewCLI, hand it to kong (kong.New(migrate.NewCLI())), and run the parsed command against m.Runner(ctx). To ship a migration binary without pulling in kong, use CLI.Dispatch instead.
Commands: up, down, stamp, status, pending, current, heads, history, sql up|down, and new.
func NewCLI ¶
func NewCLI() *CLI
NewCLI returns a fresh command grammar to hand to a CLI parser. The caller owns the parser (and its dependency): e.g.
cli := migrate.NewCLI()
parser, _ := kong.New(cli, kong.Name("migrate"))
kctx, _ := parser.Parse(os.Args[1:])
err := kctx.Run(m.Runner(ctx))
func (*CLI) Dispatch ¶
Dispatch parses args and runs the matching command against r, without any third-party CLI dependency. It accepts the same command set as the kong grammar (up, down, stamp, status, pending, current, heads, history, sql up|down, new) and is what a shipped binary or the sqlkit migrate bridge calls so neither needs kong:
err := migrate.NewCLI().Dispatch(m.Runner(ctx), os.Args[1:])
type Direction ¶
type Direction string
Direction is whether a history event applied a migration or rolled it back.
type Execer ¶
Execer is the execution surface the Operator runs statements against. Both *sqlkit.Database (auto-commit) and *sqlkit.Session (a transaction) satisfy it.
type ForeignKeyOption ¶
type ForeignKeyOption func(*sql.ForeignKeyConstraint)
ForeignKeyOption configures a foreign key added with CreateForeignKey.
func OnDelete ¶
func OnDelete(action meta.ReferentialAction) ForeignKeyOption
OnDelete sets a foreign key's ON DELETE referential action.
func OnUpdate ¶
func OnUpdate(action meta.ReferentialAction) ForeignKeyOption
OnUpdate sets a foreign key's ON UPDATE referential action.
type Migration ¶
type Migration struct {
Revision string
DownRevision string
DownRevisions []string // multiple parents (merge); overrides DownRevision
Name string
Up func(*Operator)
Down func(*Operator)
// DisableTx runs the migration outside a transaction (auto-commit). Needed
// for statements a transaction rejects, e.g. CREATE INDEX CONCURRENTLY.
DisableTx bool
}
Migration is one schema change in the migration DAG. Revision is its unique id; DownRevision is the revision it builds on ("" for the first migration). A merge migration builds on several revisions at once: set DownRevisions to the heads it joins (it takes precedence over DownRevision). Up and Down receive an Operator and perform the change with its operations (op.CreateTable, etc.); data backfills use op.Exec / op.Execute. Down may be nil for a migration that cannot be rolled back.
type MigrationEvent ¶
MigrationEvent is one recorded apply or rollback from the history table.
type MigrationStatus ¶
type MigrationStatus struct {
Revision string
DownRevision string
Name string
Applied bool
AppliedAt time.Time // zero when not applied
}
MigrationStatus is the applied state of one migration, returned by Status.
type Migrator ¶
type Migrator struct {
// contains filtered or unexported fields
}
Migrator applies a set of migrations to a database and records their history. Migrations form a DAG linked by Revision/DownRevision(s); the Migrator resolves the apply order topologically. Create one with New.
func New ¶
New creates a Migrator for the database and migrations. The migrations' Revision/DownRevision links are resolved into a topological apply order, so the caller's slice order does not matter. Configuration problems (duplicate or dangling revisions, cycles) are reported by the first operation.
func (*Migrator) Current ¶
Current returns the applied revisions that no applied migration builds on — the revision(s) the database is currently at.
func (*Migrator) DownTo ¶
DownTo rolls back every applied migration that descends from revision (not revision itself). An empty revision rolls back everything.
func (*Migrator) Downgrade ¶
Downgrade rolls migrations back toward a target, which may be:
- "base" / "" — every applied migration;
- "-N" — the N most recently applied migrations;
- a revision id (or unique prefix) — every applied descendant of it (the database ends up at that revision).
Like Upgrade, it holds the migration lock for the run.
func (*Migrator) DowngradeSQL ¶
DowngradeSQL renders, without touching the database, the SQL that downgrading from revision to revision would run (offline mode). from defaults to "head", to defaults to "base" (""). Statements are emitted in reverse topological order.
func (*Migrator) Heads ¶
Heads returns the revisions no other migration builds on (the tips of the DAG).
func (*Migrator) History ¶
func (m *Migrator) History(ctx context.Context) ([]MigrationEvent, error)
History returns every recorded apply/rollback event, oldest first. It is the full migration timeline persisted in the database.
func (*Migrator) Pending ¶
Pending returns the migrations that have not been applied, in topological order.
func (*Migrator) Runner ¶
Runner returns the binding that CLI commands run against. Hand it to a parsed command, e.g. kong's kctx.Run(m.Runner(ctx)) or CLI.Dispatch(m.Runner(ctx), …).
func (*Migrator) Stamp ¶
Stamp records the database as being at revision without running any migration — for baselining an existing schema. It writes history rows so the applied set becomes exactly the inclusive ancestors of revision: "head" stamps everything, "base"/"" stamps nothing applied. Migrations newly considered applied get an "up" row; ones no longer in range get a "down" row. No DDL runs.
Like Upgrade, it holds the migration lock while it writes.
func (*Migrator) Status ¶
func (m *Migrator) Status(ctx context.Context) ([]MigrationStatus, error)
Status returns the applied state of every known migration, in topological order.
func (*Migrator) Upgrade ¶
Upgrade applies migrations toward a target, which may be:
- "head" / "heads" / "" — every pending migration;
- "+N" — the next N pending migrations in topological order;
- a revision id (or unique prefix) — that revision and its unapplied ancestors.
On PostgreSQL and MySQL it holds the migration lock for the run, so concurrent Migrators on the same tracking table apply each migration once.
func (*Migrator) UpgradeSQL ¶
UpgradeSQL renders, without touching the database, the SQL that upgrading from revision to revision would run (offline mode). from defaults to "base" (""), to defaults to "head". Each migration's operations and its history insert are included, in topological order.
type Operator ¶
type Operator struct {
// contains filtered or unexported fields
}
Operator performs the schema (and data) changes of one migration. A Migration's Up/Down callbacks receive it and call its operations — CreateTable, AddColumn, CreateForeignKey, and so on — which execute immediately against the migration's transaction. Columns are declared with the decl DSL, and tables are referenced by name; foreign keys reference their target table by name too. The first failing operation is recorded and the rest become no-ops, so callbacks need not check an error on every line; the Migrator inspects Err after running the callback.
Up: func(op *migrate.Operator) {
op.CreateTable("posts",
decl.Column("id", decl.BigInt, decl.PrimaryKey(), decl.Default()),
decl.Column("user_id", decl.BigInt),
decl.Column("title", decl.Text),
)
op.CreateForeignKey("fk_posts_user_id", "posts",
[]string{"user_id"}, "users", []string{"id"})
}
func (*Operator) AddCheck ¶
AddCheck adds a named CHECK constraint with the given boolean expression.
func (*Operator) AddColumn ¶
func (o *Operator) AddColumn(table string, column decl.TableElement)
AddColumn adds a column, declared with a single decl.Column element.
func (*Operator) AddEnumValue ¶
AddEnumValue adds a label to an existing enum type (ALTER TYPE ... ADD VALUE). PostgreSQL cannot run this inside a transaction block before the value is used; keep it in its own migration.
func (*Operator) AddPrimaryKey ¶
AddPrimaryKey adds a PRIMARY KEY constraint over the columns.
func (*Operator) AlterColumn ¶
func (o *Operator) AlterColumn(table, column string, changes ...AlterColumnChange)
AlterColumn changes a column's type, nullability, or default (PostgreSQL).
func (*Operator) CreateEnum ¶
CreateEnum creates an enum type (CREATE TYPE name AS ENUM (values...)) in the migration's schema.
func (*Operator) CreateExtension ¶
func (o *Operator) CreateExtension(name string, configure ...func(sql.CreateExtensionBuilder) sql.CreateExtensionBuilder)
CreateExtension installs an extension (CREATE EXTENSION IF NOT EXISTS), so the step is idempotent. The extension name is not schema-qualified; target a schema with the WITH SCHEMA option via a configure callback:
op.CreateExtension("pg_trgm", func(s sql.CreateExtensionStmt) sql.CreateExtensionStmt {
return s.Schema("public")
})
func (*Operator) CreateForeignKey ¶
func (o *Operator) CreateForeignKey(name, table string, columns []string, refTable string, refColumns []string, opts ...ForeignKeyOption)
CreateForeignKey adds a foreign-key constraint referencing refTable by name (assumed to be in the same schema). Pass OnDelete/OnUpdate options to set its referential actions.
func (*Operator) CreateFunction ¶
func (o *Operator) CreateFunction(name string, configure ...func(sql.CreateFunctionBuilder) sql.CreateFunctionBuilder)
CreateFunction creates a function in the migration's schema. The signature and body are set through configure callbacks on the sql builder:
op.CreateFunction("bump", func(s sql.CreateFunctionStmt) sql.CreateFunctionStmt {
return s.OrReplace().Returns("trigger").Language("plpgsql").Body("BEGIN ... END;")
})
func (*Operator) CreateIndex ¶
CreateIndex creates a (non-unique) index.
func (*Operator) CreateMaterializedView ¶
func (o *Operator) CreateMaterializedView(name string, query sql.Query, configure ...func(sql.CreateMaterializedViewBuilder) sql.CreateMaterializedViewBuilder)
CreateMaterializedView creates a materialized view named by name in the migration's schema, defined by query (a SELECT built with the sql package; it binds no values, so inline literals with sql.Raw). Pass configure callbacks for WithNoData, explicit Columns, or IfNotExists.
func (*Operator) CreateSchema ¶
CreateSchema creates a schema (CREATE SCHEMA IF NOT EXISTS), so the step is idempotent and leaves an existing schema and its contents untouched.
func (*Operator) CreateSequence ¶
func (o *Operator) CreateSequence(name string, configure ...func(sql.CreateSequenceBuilder) sql.CreateSequenceBuilder)
CreateSequence creates a sequence in the migration's schema. Configure it with the sql builder's methods through configure callbacks:
op.CreateSequence("order_no", func(s sql.CreateSequenceStmt) sql.CreateSequenceStmt {
return s.Start(1000).Increment(1)
})
func (*Operator) CreateTable ¶
func (o *Operator) CreateTable(name string, elements ...decl.TableElement)
CreateTable creates a table declared with decl elements (Column, Index, UniqueIndex, Check, PrimaryKey, TableComment). It also emits the table's indexes and comments. Foreign keys belong in CreateForeignKey (referenced by name), not inline.
func (*Operator) CreateTemporaryTable ¶
func (o *Operator) CreateTemporaryTable(name string, elements ...decl.TableElement)
CreateTemporaryTable creates a session-scoped TEMPORARY table, otherwise identical to CreateTable. The engine drops it at the end of the session.
func (*Operator) CreateUniqueIndex ¶
CreateUniqueIndex creates a unique index.
func (*Operator) CreateView ¶
func (o *Operator) CreateView(name string, query sql.Query, opts ...ViewOption)
CreateView creates a view named by name whose body is query (a SELECT built with the sql package). Pass OrReplace / ViewColumns options to redefine an existing view or name its columns explicitly. The body binds no values; inline any literals with sql.Raw.
func (*Operator) DropColumn ¶
DropColumn drops a column.
func (*Operator) DropConstraint ¶
DropConstraint drops a CHECK / UNIQUE / primary-key constraint by name. Use DropForeignKey for foreign keys, whose syntax differs by dialect.
func (*Operator) DropEnum ¶
DropEnum drops an enum type if it exists (DROP TYPE ... IF EXISTS CASCADE).
func (*Operator) DropExtension ¶
DropExtension drops an extension if it exists.
func (*Operator) DropForeignKey ¶
DropForeignKey drops a foreign-key constraint (dialect-aware).
func (*Operator) DropFunction ¶
func (o *Operator) DropFunction(name string, configure ...func(sql.DropFunctionBuilder) sql.DropFunctionBuilder)
DropFunction drops a function if it exists. For an overloaded function pass its argument types through a configure callback (s.ArgTypes("int", "text")).
func (*Operator) DropMaterializedView ¶
DropMaterializedView drops a materialized view if it exists.
func (*Operator) DropPrimaryKey ¶
DropPrimaryKey drops a table's primary key (MySQL DROP PRIMARY KEY; PostgreSQL drops the conventional "<table>_pkey" constraint).
func (*Operator) DropSchema ¶
DropSchema drops a schema if it exists. On PostgreSQL a non-empty schema needs its objects dropped first; drop them in earlier steps or use Execute with sql.DropSchema(name).Cascade().
func (*Operator) DropSequence ¶
DropSequence drops a sequence if it exists.
func (*Operator) Execute ¶
Execute runs a raw DDL statement built with the sql package — an escape hatch for steps the operations above do not cover, and for migrate.Diff output.
func (*Operator) Grant ¶
Grant runs a GRANT statement built with sql.Grant. It is the typed counterpart of Execute for privileges:
op.Grant(sql.Grant("SELECT").On("public.users").To("readonly"))
func (*Operator) ModifyColumn ¶
func (o *Operator) ModifyColumn(table string, column decl.TableElement)
ModifyColumn restates a column's full definition — type, nullability, and default — from a single decl.Column element, the dialect-agnostic way to change those properties at once. MySQL renders one MODIFY COLUMN; PostgreSQL renders the equivalent ALTER COLUMN TYPE / SET|DROP NOT NULL / SET|DROP DEFAULT actions. It is what the migration autogenerator emits for a column change.
func (*Operator) RefreshMaterializedView ¶
func (o *Operator) RefreshMaterializedView(name string, configure ...func(sql.RefreshMaterializedViewBuilder) sql.RefreshMaterializedViewBuilder)
RefreshMaterializedView refreshes a materialized view's contents. Pass a configure callback for Concurrently or WithNoData.
func (*Operator) RenameColumn ¶
RenameColumn renames a column.
func (*Operator) RenameEnumValue ¶
RenameEnumValue renames an enum label (ALTER TYPE ... RENAME VALUE).
func (*Operator) RenameTable ¶
RenameTable renames a table.
type Option ¶
type Option func(*Migrator)
Option configures a Migrator.
func WithOutput ¶
WithOutput sets where the CLI writes its output (default os.Stdout).
func WithSchema ¶
WithSchema sets the schema for both the tracking table and the tables a migration's operations create or alter.
func WithTableName ¶
WithTableName overrides the tracking table name (default "schema_migrations").
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry collects migrations declared across several files into one set, so a project can keep each migration in its own file and register it there rather than maintaining a single growing slice. Declare a package-level registry and have each file add to it with a package-level var (Add returns the registry, so the blank identifier discards it). Migrator order does not depend on registration order — it is resolved from each migration's Revision/ DownRevision DAG links:
// migrations/migrations.go
var Registry = migrate.NewRegistry()
// migrations/0001_create_users.go
var _ = Registry.Add(migrate.Migration{Revision: "0001", Name: "create_users", Up: ...})
// main.go
m := migrations.Registry.NewMigrator(db)
err := m.Up(ctx)
A Registry is safe for concurrent Add.
func (*Registry) Add ¶
Add appends migrations to the registry and returns it, so it can be used as a package-level initializer (var _ = Registry.Add(...)).
func (*Registry) Migrations ¶
Migrations returns a copy of the registered migrations.
type Runner ¶
type Runner struct {
// contains filtered or unexported fields
}
Runner carries the migrator and context to each subcommand's Run method. It is the binding a CLI driver hands to the parsed command — pass it to kong's kctx.Run, or to CLI.Dispatch.
type ViewOption ¶
type ViewOption func(sql.CreateViewBuilder) sql.CreateViewBuilder
ViewOption configures a view created with CreateView.
func OrReplace ¶
func OrReplace() ViewOption
OrReplace makes CreateView emit CREATE OR REPLACE VIEW (PostgreSQL/MySQL).
func ViewColumns ¶
func ViewColumns(columns ...string) ViewOption
ViewColumns sets explicit view column names.