Documentation
¶
Overview ¶
Package migrate applies schema migrations declared with Go builders and compiled into the binary. One declaration compiles to PostgreSQL, MySQL, SQLite, or single-server ClickHouse SQL, with rollbacks, dry-run plans, checksums, and repeatable migrations.
Entry points: Add and AddRepeatable register migrations in the default Collection (NewCollection and WithCollection keep an explicit one); New wraps a caller-owned *sql.DB with one of Postgres, MySQL, SQLite, or ClickHouse; Migrator.Up, Rollback, Status, and Plan drive it. Irreversible operations require WithDown. The package owns no connections or drivers.
Example (ClickHouse) ¶
ClickHouse tables require an explicit storage engine.
package main
import (
"context"
"database/sql"
"log"
"github.com/go-rio/migrate"
)
type role string
const (
roleAdmin role = "admin"
roleMember role = "member"
)
// Applications register migrations from init functions in a migrations
// package imported for effect.
func init() {
migrate.Add("20260708100000_create_users", func(s *migrate.Schema) {
s.Create("users", func(t *migrate.Table) {
t.ID()
t.String("email").Unique()
t.String("name", 100)
t.Enum("role", roleAdmin, roleMember).Default(roleMember)
t.Timestamps()
})
})
migrate.Add("20260708110000_create_posts", func(s *migrate.Schema) {
s.Create("posts", func(t *migrate.Table) {
t.ID()
t.ForeignID("user_id").Constrained().CascadeOnDelete()
t.String("title")
t.Text("body").Nullable()
t.JSON("meta").Nullable()
t.Index("user_id", "title")
})
})
}
func main() {
c := migrate.NewCollection()
c.Add("20260809100000_create_events", func(s *migrate.Schema) {
s.Create("events", func(t *migrate.Table) {
t.UUID("id")
t.String("tenant_id")
t.TimestampTz("occurred_at")
t.JSON("payload")
t.ClickHouseEngine(
"MergeTree() PARTITION BY toYYYYMM(occurred_at) " +
"ORDER BY (tenant_id, occurred_at)",
)
})
})
db, err := sql.Open("clickhouse", "clickhouse://localhost:9000/default")
if err != nil {
log.Fatal(err)
}
defer func() { _ = db.Close() }()
m, err := migrate.New(db, migrate.ClickHouse,
migrate.WithCollection(c),
migrate.WithoutLock(), // the deploy system must serialize this call
)
if err != nil {
log.Fatal(err)
}
if err := m.Up(context.Background()); err != nil {
log.Fatal(err)
}
}
Output:
Index ¶
- Variables
- func Add(name string, up func(*Schema), opts ...MigrationOption)
- func AddRepeatable(name string, run func(*Schema), opts ...MigrationOption)
- type Clock
- type Collection
- type Column
- func (c *Column) After(column string) *Column
- func (c *Column) AutoIncrement() *Column
- func (c *Column) Change() *Column
- func (c *Column) Collation(name string) *Column
- func (c *Column) Comment(comment string) *Column
- func (c *Column) CopyFrom(expr string) *Column
- func (c *Column) Default[V DefaultLiteral](value V) *Column
- func (c *Column) DefaultExpr(expr string) *Column
- func (c *Column) First() *Column
- func (c *Column) Index() *Column
- func (c *Column) Nullable() *Column
- func (c *Column) Primary() *Column
- func (c *Column) SkipCopy() *Column
- func (c *Column) StoredAs(expr string) *Column
- func (c *Column) Unique() *Column
- func (c *Column) Unsigned() *Column
- func (c *Column) UseCurrent() *Column
- func (c *Column) UseCurrentOnUpdate() *Column
- func (c *Column) Using(expr string) *Column
- func (c *Column) VirtualAs(expr string) *Column
- type DB
- type DefaultLiteral
- type Dialect
- type ForeignColumn
- func (fc *ForeignColumn) CascadeOnDelete() *ForeignColumn
- func (fc *ForeignColumn) Constrained(table ...string) *ForeignColumn
- func (fc *ForeignColumn) Deferrable() *ForeignColumn
- func (fc *ForeignColumn) Index() *ForeignColumn
- func (fc *ForeignColumn) NullOnDelete() *ForeignColumn
- func (fc *ForeignColumn) Nullable() *ForeignColumn
- func (fc *ForeignColumn) References(table string, columns ...string) *ForeignColumn
- func (fc *ForeignColumn) RestrictOnDelete() *ForeignColumn
- func (fc *ForeignColumn) Unique() *ForeignColumn
- type ForeignKey
- func (f *ForeignKey) CascadeOnDelete() *ForeignKey
- func (f *ForeignKey) CascadeOnUpdate() *ForeignKey
- func (f *ForeignKey) Deferrable() *ForeignKey
- func (f *ForeignKey) Name(name string) *ForeignKey
- func (f *ForeignKey) NoActionOnDelete() *ForeignKey
- func (f *ForeignKey) NullOnDelete() *ForeignKey
- func (f *ForeignKey) NullOnUpdate() *ForeignKey
- func (f *ForeignKey) References(table string, columns ...string) *ForeignKey
- func (f *ForeignKey) RestrictOnDelete() *ForeignKey
- func (f *ForeignKey) RestrictOnUpdate() *ForeignKey
- type Index
- func (i *Index) Concurrently() *Index
- func (i *Index) Desc(columns ...string) *Index
- func (i *Index) Include(columns ...string) *Index
- func (i *Index) Name(name string) *Index
- func (i *Index) NullsNotDistinct() *Index
- func (i *Index) Using(method string) *Index
- func (i *Index) Where(predicate string) *Index
- type Migration
- type MigrationOption
- type Migrator
- func (m *Migrator) Baseline(ctx context.Context, upTo ...string) error
- func (m *Migrator) Fresh(ctx context.Context) error
- func (m *Migrator) Plan(ctx context.Context) ([]Planned, error)
- func (m *Migrator) PlanRollback(ctx context.Context, steps int) ([]Planned, error)
- func (m *Migrator) PlanRollbackBatch(ctx context.Context) ([]Planned, error)
- func (m *Migrator) Repair(ctx context.Context) error
- func (m *Migrator) Reset(ctx context.Context) error
- func (m *Migrator) Rollback(ctx context.Context, steps int) error
- func (m *Migrator) RollbackBatch(ctx context.Context) error
- func (m *Migrator) Status(ctx context.Context) ([]Status, error)
- func (m *Migrator) Up(ctx context.Context) error
- type Option
- type Planned
- type SafetyLevel
- type Schema
- func (s *Schema) Create(table string, fn func(*Table))
- func (s *Schema) Drop(table string)
- func (s *Schema) DropIfExists(table string)
- func (s *Schema) Exec(query string, args ...any)
- func (s *Schema) Recreate(table string, fn func(*Table))
- func (s *Schema) Rename(from, to string)
- func (s *Schema) Run(fn func(ctx context.Context, db DB) error)
- func (s *Schema) Table(table string, fn func(*Table))
- type Status
- type Table
- func (t *Table) BigInteger(name string) *Column
- func (t *Table) Binary(name string) *Column
- func (t *Table) Boolean(name string) *Column
- func (t *Table) Char(name string, length ...int) *Column
- func (t *Table) Check(name, expr string)
- func (t *Table) ClickHouseEngine(clause string)
- func (t *Table) Column(name, sqlType string) *Column
- func (t *Table) Comment(comment string)
- func (t *Table) Date(name string) *Column
- func (t *Table) DateTime(name string) *Column
- func (t *Table) Decimal(name string, precision, scale int) *Column
- func (t *Table) Double(name string) *Column
- func (t *Table) DropCheck(name string)
- func (t *Table) DropColumn(names ...string)
- func (t *Table) DropConstraint(name string)
- func (t *Table) DropForeign(columns ...string)
- func (t *Table) DropForeignByName(name string)
- func (t *Table) DropFullText(columns ...string)
- func (t *Table) DropIndex(columns ...string)
- func (t *Table) DropIndexByName(name string)
- func (t *Table) DropPrimary()
- func (t *Table) DropSpatial(columns ...string)
- func (t *Table) DropUnique(columns ...string)
- func (t *Table) Enum[V ~string](name string, values ...V) *Column
- func (t *Table) Float(name string) *Column
- func (t *Table) Foreign(columns ...string) *ForeignKey
- func (t *Table) ForeignID(name string) *ForeignColumn
- func (t *Table) FullText(columns ...string) *Index
- func (t *Table) ID(name ...string) *Column
- func (t *Table) Index(columns ...string) *Index
- func (t *Table) IndexExpr(name string, exprs ...string) *Index
- func (t *Table) Integer(name string) *Column
- func (t *Table) JSON(name string) *Column
- func (t *Table) Primary(columns ...string)
- func (t *Table) RenameColumn(from, to string)
- func (t *Table) RenameIndex(from, to string)
- func (t *Table) SmallInteger(name string) *Column
- func (t *Table) SoftDeletes(name ...string) *Column
- func (t *Table) Spatial(columns ...string) *Index
- func (t *Table) String(name string, length ...int) *Column
- func (t *Table) Text(name string) *Column
- func (t *Table) Time(name string) *Column
- func (t *Table) Timestamp(name string) *Column
- func (t *Table) TimestampTz(name string) *Column
- func (t *Table) Timestamps()
- func (t *Table) TinyInteger(name string) *Column
- func (t *Table) UUID(name string) *Column
- func (t *Table) Unique(columns ...string) *Index
- func (t *Table) UniqueConstraint(name string, columns ...string)
- func (t *Table) UniqueExpr(name string, exprs ...string) *Index
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrIrreversible marks a migration with no automatic or explicit rollback. ErrIrreversible = errors.New("migrate: migration cannot be automatically reversed") // ErrLockTimeout marks a timed-out advisory lock acquisition. ErrLockTimeout = errors.New("migrate: timed out waiting for the migration lock") // ErrLockUnsupported indicates that the dialect has no built-in migration // lock. Callers may use WithoutLock only after serializing deployments // externally. ErrLockUnsupported = errors.New("migrate: migration lock unsupported") // ErrChecksumMismatch marks an edited applied migration. ErrChecksumMismatch = errors.New("migrate: checksum mismatch") )
var ErrUnsafe = errors.New("migrate: unsafe migration")
ErrUnsafe marks a migration rejected by SafetyStrict.
Functions ¶
func Add ¶
func Add(name string, up func(*Schema), opts ...MigrationOption)
Add registers a migration in the default collection.
Example ¶
Builders reverse themselves; raw SQL and Go functions discard information, so a migration using them declares its rollback with WithDown.
package main
import (
"context"
"github.com/go-rio/migrate"
)
func main() {
migrate.Add("20260709120000_backfill_names",
func(s *migrate.Schema) {
s.Table("users", func(t *migrate.Table) {
t.String("display_name").Nullable()
})
s.Run(func(ctx context.Context, db migrate.DB) error {
_, err := db.ExecContext(ctx, "UPDATE users SET display_name = name WHERE display_name IS NULL")
return err
})
},
migrate.WithDown(func(s *migrate.Schema) {
s.Table("users", func(t *migrate.Table) {
t.DropColumn("display_name")
})
}),
)
}
Output:
func AddRepeatable ¶
func AddRepeatable(name string, run func(*Schema), opts ...MigrationOption)
AddRepeatable registers a repeatable migration in the default collection.
Types ¶
type Clock ¶
Clock supplies applied_at timestamps for migration records; WithClock injects one, typically in tests.
type Collection ¶
type Collection struct {
// contains filtered or unexported fields
}
Collection is a named migration set. Package-level Add uses a default one.
func (*Collection) Add ¶
func (c *Collection) Add(name string, up func(*Schema), opts ...MigrationOption)
Add registers a lexically ordered migration. It panics on an empty, whitespace-padded, or over-191-character name, on a duplicate name, or on a nil declaration.
func (*Collection) AddRepeatable ¶
func (c *Collection) AddRepeatable(name string, run func(*Schema), opts ...MigrationOption)
AddRepeatable registers an idempotent declaration that reruns when its SQL checksum changes. Repeatables run after versioned migrations and have no rollback; Reset forgets their records.
func (*Collection) SQL ¶
func (c *Collection) SQL(dialect Dialect) ([]Planned, error)
SQL renders the entire collection offline: versioned migrations first, then repeatables.
Example ¶
Collection.SQL renders migrations without a database.
package main
import (
"fmt"
"log"
"github.com/go-rio/migrate"
)
func main() {
c := migrate.NewCollection()
c.Add("20260708100000_create_teams", func(s *migrate.Schema) {
s.Create("teams", func(t *migrate.Table) {
t.ID()
t.String("name").Unique()
})
})
plans, err := c.SQL(migrate.Postgres)
if err != nil {
log.Fatal(err)
}
for _, p := range plans {
fmt.Printf("-- %s\n", p.Name)
for _, stmt := range p.Statements {
fmt.Printf("%s;\n", stmt)
}
}
}
Output: -- 20260708100000_create_teams CREATE TABLE "teams" ( "id" BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, "name" VARCHAR(255) NOT NULL ); CREATE UNIQUE INDEX "teams_name_unique" ON "teams" ("name");
type Column ¶
type Column struct {
// contains filtered or unexported fields
}
Column configures a declared column.
func (*Column) AutoIncrement ¶
AutoIncrement makes an integer column a database-generated primary key. It cannot be nullable or have a default.
func (*Column) Change ¶ added in v0.7.0
Change restates a column's complete target definition inside Schema.Table. SQLite requires Schema.Recreate. The change is irreversible without WithDown; indexes and constraints must be changed separately.
func (*Column) Collation ¶ added in v0.14.0
Collation sets the column's collation by the dialect's own name: a PostgreSQL collation ("C", "und-x-icu"), a MySQL collation (utf8mb4_bin), or a SQLite one (NOCASE). ClickHouse rejects it.
func (*Column) CopyFrom ¶
CopyFrom sets the SELECT expression used to fill this column during Schema.Recreate. It has no effect elsewhere.
func (*Column) Default ¶
func (c *Column) Default[V DefaultLiteral](value V) *Column
Default sets a portable scalar default. Use DefaultExpr for SQL.
func (*Column) DefaultExpr ¶
DefaultExpr sets a verbatim SQL default expression.
func (*Column) StoredAs ¶
StoredAs makes this a stored generated column using a verbatim expression.
func (*Column) Unsigned ¶
Unsigned uses MySQL's or ClickHouse's unsigned integer type. Other dialects ignore it.
func (*Column) UseCurrent ¶
UseCurrent defaults the column to the current timestamp.
func (*Column) UseCurrentOnUpdate ¶
UseCurrentOnUpdate enables MySQL's automatic timestamp refresh. ClickHouse rejects it; other dialects ignore it.
type DB ¶
type DB interface {
ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
}
DB is the database/sql surface available to Run functions; *sql.DB, *sql.Conn, and *sql.Tx satisfy it.
type DefaultLiteral ¶ added in v0.8.0
type DefaultLiteral interface {
~bool | ~string |
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
~float32 | ~float64
}
DefaultLiteral contains the scalar types Default renders portably. SQL expressions belong in DefaultExpr.
type Dialect ¶
type Dialect interface {
// contains filtered or unexported methods
}
Dialect compiles and executes migrations for one database engine. Built-in values are Postgres, MySQL, SQLite, and ClickHouse; the methods are unexported, so no other implementation exists.
var ClickHouse Dialect = clickHouseDialect{}
ClickHouse is the single-server ClickHouse dialect. It never emits ON CLUSTER and does not provide an in-database migration lock.
var MySQL Dialect = mysqlDialect{}
MySQL targets MySQL 8.0+ or an equivalent MariaDB release. DDL commits implicitly, so failures report the statement and persisted prefix.
var Postgres Dialect = postgresDialect{}
Postgres is the PostgreSQL dialect. Migrations run inside a transaction, and a session-level advisory lock serializes concurrent migrators.
var SQLite Dialect = sqliteDialect{}
SQLite targets SQLite 3.35+. Constraint alterations require Schema.Recreate. Its single-writer transaction and record-first bookkeeping replace advisory locking.
type ForeignColumn ¶
type ForeignColumn struct {
*Column
// contains filtered or unexported fields
}
ForeignColumn configures a ForeignID column and its constraint.
func (*ForeignColumn) CascadeOnDelete ¶
func (fc *ForeignColumn) CascadeOnDelete() *ForeignColumn
CascadeOnDelete deletes child rows when the parent row is deleted.
func (*ForeignColumn) Constrained ¶
func (fc *ForeignColumn) Constrained(table ...string) *ForeignColumn
Constrained references id on the given table, or infers it from a *_id name.
func (*ForeignColumn) Deferrable ¶ added in v0.14.0
func (fc *ForeignColumn) Deferrable() *ForeignColumn
Deferrable checks the key at commit; see ForeignKey.Deferrable.
func (*ForeignColumn) Index ¶
func (fc *ForeignColumn) Index() *ForeignColumn
Index adds an index while preserving the ForeignColumn chain.
func (*ForeignColumn) NullOnDelete ¶
func (fc *ForeignColumn) NullOnDelete() *ForeignColumn
NullOnDelete sets the column to NULL when the parent row is deleted.
func (*ForeignColumn) Nullable ¶
func (fc *ForeignColumn) Nullable() *ForeignColumn
Nullable allows NULL while preserving the ForeignColumn chain.
func (*ForeignColumn) References ¶
func (fc *ForeignColumn) References(table string, columns ...string) *ForeignColumn
References adds a foreign key to the table; columns default to "id".
func (*ForeignColumn) RestrictOnDelete ¶
func (fc *ForeignColumn) RestrictOnDelete() *ForeignColumn
RestrictOnDelete rejects deleting a parent row that still has children.
func (*ForeignColumn) Unique ¶
func (fc *ForeignColumn) Unique() *ForeignColumn
Unique adds a unique index while preserving the ForeignColumn chain.
type ForeignKey ¶
type ForeignKey struct {
// contains filtered or unexported fields
}
ForeignKey configures a declared foreign key.
func (*ForeignKey) CascadeOnDelete ¶
func (f *ForeignKey) CascadeOnDelete() *ForeignKey
CascadeOnDelete deletes child rows when the parent row is deleted.
func (*ForeignKey) CascadeOnUpdate ¶
func (f *ForeignKey) CascadeOnUpdate() *ForeignKey
CascadeOnUpdate propagates key updates to child rows.
func (*ForeignKey) Deferrable ¶ added in v0.14.0
func (f *ForeignKey) Deferrable() *ForeignKey
Deferrable checks the key at commit (DEFERRABLE INITIALLY DEFERRED) on PostgreSQL and SQLite, so rows can reference each other within one transaction. MySQL rejects it.
func (*ForeignKey) Name ¶
func (f *ForeignKey) Name(name string) *ForeignKey
Name overrides the conventional foreign-key name.
func (*ForeignKey) NoActionOnDelete ¶
func (f *ForeignKey) NoActionOnDelete() *ForeignKey
NoActionOnDelete defers enforcement where the dialect supports it.
func (*ForeignKey) NullOnDelete ¶
func (f *ForeignKey) NullOnDelete() *ForeignKey
NullOnDelete sets the child columns to NULL when the parent row is deleted.
func (*ForeignKey) NullOnUpdate ¶
func (f *ForeignKey) NullOnUpdate() *ForeignKey
NullOnUpdate sets the child columns to NULL when the parent key changes.
func (*ForeignKey) References ¶
func (f *ForeignKey) References(table string, columns ...string) *ForeignKey
References sets the parent table and columns; columns default to "id".
func (*ForeignKey) RestrictOnDelete ¶
func (f *ForeignKey) RestrictOnDelete() *ForeignKey
RestrictOnDelete rejects deleting a parent row that still has children.
func (*ForeignKey) RestrictOnUpdate ¶
func (f *ForeignKey) RestrictOnUpdate() *ForeignKey
RestrictOnUpdate rejects updating a key that still has children.
type Index ¶
type Index struct {
// contains filtered or unexported fields
}
Index configures a declared index.
func (*Index) Concurrently ¶ added in v0.7.0
Concurrently builds and drops a PostgreSQL index without blocking writes. The migration must use WithoutTransaction. Other dialects ignore it.
func (*Index) Desc ¶ added in v0.13.0
Desc indexes the named columns descending, so the key matches a scan that mixes directions (ORDER BY created_at DESC, id). Every dialect honors it; MySQL before 8.0 parsed and ignored it. Expression indexes carry the direction inside the expression instead.
func (*Index) Include ¶ added in v0.7.0
Include adds PostgreSQL covering-index columns. Other dialects reject it.
func (*Index) NullsNotDistinct ¶ added in v0.7.0
NullsNotDistinct enables PostgreSQL 15+'s NULLS NOT DISTINCT.
type Migration ¶
type Migration struct {
// contains filtered or unexported fields
}
Migration is one registered declaration; Collection.Add creates it and Name identifies it in the records table.
type MigrationOption ¶
type MigrationOption func(*Migration)
MigrationOption configures a single migration at registration time.
func Assured ¶
func Assured() MigrationOption
Assured marks a migration as reviewed and skips safety analysis.
func WithDown ¶
func WithDown(down func(*Schema)) MigrationOption
WithDown defines rollback for otherwise irreversible operations.
func WithoutTransaction ¶
func WithoutTransaction() MigrationOption
WithoutTransaction permits statements such as PostgreSQL CREATE INDEX CONCURRENTLY. Earlier statements may remain applied after a failure.
type Migrator ¶
type Migrator struct {
// contains filtered or unexported fields
}
Migrator applies one Collection to a database. Advisory locks serialize concurrent processes unless WithoutLock is set.
func New ¶
New creates a Migrator without taking ownership of db. The dialect must match the database driver. New fails on a nil db or dialect and on invalid options; each Option documents its constraints.
Example ¶
New wraps a caller-owned *sql.DB; the dialect must match the driver, and options tune locking, checksums, safety, and logging.
package main
import (
"context"
"database/sql"
"fmt"
"log"
"log/slog"
"time"
"github.com/go-rio/migrate"
)
type role string
const (
roleAdmin role = "admin"
roleMember role = "member"
)
// Applications register migrations from init functions in a migrations
// package imported for effect.
func init() {
migrate.Add("20260708100000_create_users", func(s *migrate.Schema) {
s.Create("users", func(t *migrate.Table) {
t.ID()
t.String("email").Unique()
t.String("name", 100)
t.Enum("role", roleAdmin, roleMember).Default(roleMember)
t.Timestamps()
})
})
migrate.Add("20260708110000_create_posts", func(s *migrate.Schema) {
s.Create("posts", func(t *migrate.Table) {
t.ID()
t.ForeignID("user_id").Constrained().CascadeOnDelete()
t.String("title")
t.Text("body").Nullable()
t.JSON("meta").Nullable()
t.Index("user_id", "title")
})
})
}
func main() {
db, err := sql.Open("pgx", "postgres://localhost/app") // driver of your choice
if err != nil {
log.Fatal(err)
}
defer func() { _ = db.Close() }()
m, err := migrate.New(db, migrate.Postgres,
migrate.WithLogger(slog.Default()),
migrate.WithLockTimeout(2*time.Minute),
migrate.WithStrictChecksum(),
migrate.WithSafety(migrate.SafetyStrict),
)
if err != nil {
log.Fatal(err)
}
statuses, err := m.Status(context.Background())
if err != nil {
log.Fatal(err)
}
for _, st := range statuses {
fmt.Printf("%s applied=%t drifted=%t\n", st.Name, st.Applied, st.Drifted)
}
}
Output:
func (*Migrator) Baseline ¶
Baseline records existing schema without executing migrations. An optional name limits versioned migrations; repeatables are always included. Rollback skips baselined rows, while Reset includes them.
func (*Migrator) Fresh ¶
Fresh drops every table and reapplies all migrations. It is a destructive development operation and must not be used on production data.
func (*Migrator) Plan ¶
Plan renders pending SQL without executing it. Versioned migrations precede changed repeatables.
func (*Migrator) PlanRollback ¶
PlanRollback renders Rollback without executing it.
func (*Migrator) PlanRollbackBatch ¶
PlanRollbackBatch renders RollbackBatch without executing it.
func (*Migrator) Repair ¶
Repair accepts reviewed checksum drift for versioned migrations. Repeatables are unchanged because drift schedules their next run.
func (*Migrator) Rollback ¶
Rollback reverses the latest steps versioned migrations; steps must be positive. Irreversible operations fail with ErrIrreversible, and baselined rows are not touched.
func (*Migrator) RollbackBatch ¶
RollbackBatch reverses the latest batch without touching baselined rows.
func (*Migrator) Up ¶
Up applies pending versioned migrations as one batch, then runs changed repeatables. Each migration uses its own transaction when the dialect supports one and the migration has not opted out. Up fails before executing anything with ErrChecksumMismatch under WithStrictChecksum, ErrUnsafe under SafetyStrict, and ErrLockTimeout or ErrLockUnsupported from the lock.
Example ¶
Up applies pending migrations as one batch, then changed repeatables; Plan previews the SQL and safety findings first.
package main
import (
"context"
"database/sql"
"fmt"
"log"
"github.com/go-rio/migrate"
)
type role string
const (
roleAdmin role = "admin"
roleMember role = "member"
)
// Applications register migrations from init functions in a migrations
// package imported for effect.
func init() {
migrate.Add("20260708100000_create_users", func(s *migrate.Schema) {
s.Create("users", func(t *migrate.Table) {
t.ID()
t.String("email").Unique()
t.String("name", 100)
t.Enum("role", roleAdmin, roleMember).Default(roleMember)
t.Timestamps()
})
})
migrate.Add("20260708110000_create_posts", func(s *migrate.Schema) {
s.Create("posts", func(t *migrate.Table) {
t.ID()
t.ForeignID("user_id").Constrained().CascadeOnDelete()
t.String("title")
t.Text("body").Nullable()
t.JSON("meta").Nullable()
t.Index("user_id", "title")
})
})
}
func main() {
db, err := sql.Open("pgx", "postgres://localhost/app")
if err != nil {
log.Fatal(err)
}
defer func() { _ = db.Close() }()
m, err := migrate.New(db, migrate.Postgres)
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
plans, err := m.Plan(ctx)
if err != nil {
log.Fatal(err)
}
for _, p := range plans {
fmt.Printf("-- %s: %d statements, %d warnings\n", p.Name, len(p.Statements), len(p.Warnings))
}
if err := m.Up(ctx); err != nil {
log.Fatal(err)
}
}
Output:
type Option ¶
type Option func(*config)
Option configures a Migrator at construction time; pass options to New.
func WithCollection ¶
func WithCollection(c *Collection) Option
WithCollection replaces the package-level default collection.
func WithLockTimeout ¶
WithLockTimeout sets the advisory-lock wait; the default is one minute and New rejects non-positive durations.
func WithLogger ¶
WithLogger sets the progress logger; the default discards logs and New rejects nil.
func WithSafety ¶
func WithSafety(level SafetyLevel) Option
WithSafety sets the safety level. The default is SafetyWarn.
func WithStrictChecksum ¶
func WithStrictChecksum() Option
WithStrictChecksum makes Up fail with ErrChecksumMismatch instead of warning. Repair accepts reviewed drift.
func WithTable ¶
WithTable sets the records table name and advisory-lock namespace. The name may be schema-qualified; New rejects empty names, names over 128 bytes, and names containing quotes or NUL.
func WithoutLock ¶
func WithoutLock() Option
WithoutLock disables serialization. Use it only with an external single-run guarantee.
type Planned ¶
type Planned struct {
Name string
// Statements contains SQL in execution order; Run appears as a placeholder.
Statements []string
// Warnings contains safety findings.
Warnings []string
}
Planned is one migration in a dry-run plan.
type SafetyLevel ¶
type SafetyLevel int
SafetyLevel controls handling of potentially disruptive operations.
const ( // SafetyWarn logs findings and proceeds. SafetyWarn SafetyLevel = iota // SafetyStrict rejects all findings before execution. SafetyStrict // SafetyOff disables the analysis. SafetyOff )
type Schema ¶
type Schema struct {
// contains filtered or unexported fields
}
Schema records migration operations without touching the database. Declarations must be deterministic because they are re-run for planning, checksums, application, and rollback.
func (*Schema) DropIfExists ¶
DropIfExists removes a table if it exists. Like Drop, it is irreversible.
func (*Schema) Exec ¶
Exec records raw SQL in plans and checksums. It is irreversible without WithDown and uses native dialect placeholders.
func (*Schema) Recreate ¶
Recreate rebuilds a table while preserving rows and triggers. Columns copy by name unless CopyFrom or SkipCopy says otherwise. PostgreSQL and SQLite run the rebuild transactionally; MySQL and ClickHouse reject it.
Recreate is irreversible without WithDown. PostgreSQL also rejects rebuilds blocked by dependent foreign keys or views.
func (*Schema) Rename ¶
Rename renames a table and reverses automatically. PostgreSQL and SQLite reject cross-schema renames.
func (*Schema) Run ¶
Run records an opaque Go data migration. It runs in the migration transaction when the dialect provides one, or on the dedicated connection otherwise. It is excluded from checksums and is irreversible.
Keep DDL out of fn: rio cannot see inside it, so on MySQL DDL would commit implicitly without appearing in failure reports. Use the builders or Exec.
type Status ¶
type Status struct {
Name string
Applied bool // the database has a record
Batch int // batch it was applied in; 0 also marks baselined rows, -1 repeatable ones
AppliedAt time.Time // zero when not applied
Registered bool // the current collection contains the migration
Repeatable bool
Drifted bool // declaration checksum differs from the record
}
Status describes a registered or recorded migration.
type Table ¶
type Table struct {
// contains filtered or unexported fields
}
Table builds a new table or a set of alterations. Declaration errors are collected and returned when the migration compiles.
func (*Table) BigInteger ¶
BigInteger declares a 64-bit integer.
func (*Table) Check ¶
Check declares a named CHECK constraint with a verbatim SQL expression. SQLite alterations must use Schema.Recreate instead.
func (*Table) ClickHouseEngine ¶ added in v0.9.0
ClickHouseEngine sets the complete ClickHouse storage fragment rendered after ENGINE =. It may include engine parameters, PARTITION BY, ORDER BY, PRIMARY KEY, SAMPLE BY, TTL, and storage SETTINGS. It is only valid inside Schema.Create; omit ENGINE =, table COMMENT, and a trailing semicolon. Other dialects ignore it.
func (*Table) Comment ¶
Comment sets a table comment. SQLite ignores comments; altering one is irreversible.
func (*Table) Decimal ¶
Decimal declares an exact fixed-point column, e.g. Decimal("amount", 10, 2).
func (*Table) DropColumn ¶
DropColumn removes columns and is irreversible without WithDown.
func (*Table) DropConstraint ¶ added in v0.12.0
DropConstraint drops any named table constraint. Irreversible without WithDown; SQLite alters via Schema.Recreate.
func (*Table) DropForeign ¶
DropForeign removes the conventional foreign key for the columns.
func (*Table) DropForeignByName ¶
DropForeignByName removes a foreign key by its exact name.
func (*Table) DropFullText ¶ added in v0.7.0
DropFullText removes the conventional full-text index for the columns.
func (*Table) DropIndexByName ¶
DropIndexByName removes an index by its exact name.
func (*Table) DropPrimary ¶
func (t *Table) DropPrimary()
DropPrimary removes the table's primary key.
func (*Table) DropSpatial ¶ added in v0.7.0
DropSpatial removes the conventional spatial index for the columns.
func (*Table) DropUnique ¶
DropUnique removes the conventional unique index for the columns.
func (*Table) Enum ¶
Enum declares a native MySQL ENUM or an equivalent checked VARCHAR. Values may use any defined string type.
func (*Table) Foreign ¶
func (t *Table) Foreign(columns ...string) *ForeignKey
Foreign declares a foreign key on existing columns.
func (*Table) ForeignID ¶
func (t *Table) ForeignID(name string) *ForeignColumn
ForeignID declares an unsigned 64-bit foreign-key column.
func (*Table) FullText ¶ added in v0.7.0
FullText declares a MySQL FULLTEXT index. Other dialects reject it.
func (*Table) IndexExpr ¶ added in v0.7.0
IndexExpr declares a named index over SQL expressions written verbatim into the index key list; wrap an expression when the database demands it and append what belongs outside the parentheses, like an operator class in "lower(email) text_pattern_ops". Exception: MySQL requires every functional key part parenthesized, so each expression gains one pair there.
func (*Table) RenameColumn ¶
RenameColumn renames a column. It reverses to the opposite rename.
func (*Table) RenameIndex ¶
RenameIndex renames an index. It reverses to the opposite rename. SQLite cannot rename indexes; dropping and re-declaring is the portable route.
func (*Table) SmallInteger ¶
SmallInteger declares a 16-bit integer.
func (*Table) SoftDeletes ¶
SoftDeletes declares a nullable deleted_at TimestampTz column.
func (*Table) Spatial ¶ added in v0.7.0
Spatial declares a MySQL SPATIAL index. Other dialects reject it.
func (*Table) TimestampTz ¶
TimestampTz declares an instant, using the closest type each dialect offers.
func (*Table) Timestamps ¶
func (t *Table) Timestamps()
Timestamps declares nullable created_at and updated_at TimestampTz columns.
func (*Table) TinyInteger ¶
TinyInteger declares an 8-bit integer, or SMALLINT on PostgreSQL.
func (*Table) UniqueConstraint ¶ added in v0.12.0
UniqueConstraint declares a named table-level UNIQUE constraint — the form ON CONFLICT ON CONSTRAINT can reference, unlike Unique's index. SQLite supports it in Create only; alter via Schema.Recreate.