dbmigrate

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Aug 3, 2026 License: MIT Imports: 10 Imported by: 0

README

go-dbmigrate

Laravel-style database migrations for Go: name-keyed tracking, batch rollback, and checksum guards. Supports PostgreSQL and SQLite; additional drivers can be added by implementing the Dialect interface.

Installation

go get github.com/gomakenow/go-dbmigrate

Install the CLI:

go install github.com/gomakenow/go-dbmigrate/cmd/dbmigrate@latest

Features

  • Files: {YYYY_MM_DD_HHMMSS}_{slug}.up.sql + matching .down.sql
  • Tracking table: dbmigrate_migrations (override with --table)
    • name (PK), checksum (sha256 of up SQL), batch, applied_at
  • Identity is the name, not a monotonic version pointer.
  • One up run = one batch. rollback undoes the last batch (LIFO).
  • Checksums: if an already-applied file’s .up.sql changes, up fails.
  • Driver-level locking so concurrent runners do not interleave.
  • Each migration runs in its own transaction (SQL + tracking row).

CLI

dbmigrate up --dsn postgres://user:pass@localhost/db --dir ./migrations
dbmigrate up --dsn file:./dev.db --driver sqlite --dir ./migrations
dbmigrate create add_users_table --dir ./migrations
dbmigrate rollback --step 2 --dsn postgres://...
dbmigrate fresh --dsn postgres://...
dbmigrate baseline --dsn postgres://...

--driver is auto-detected from --dsn when possible:

  • postgres:// / postgresql://postgres
  • file:, :memory:, .db, .sqlite, .sqlite3sqlite

Library usage

import (
    "github.com/gomakenow/go-dbmigrate"
    "github.com/gomakenow/go-dbmigrate/postgres"
)

migs, err := dbmigrate.LoadPath("db/migrations")

db, err := postgres.Open("postgres://...")
m := dbmigrate.New(db, postgres.Dialect(), "dbmigrate_migrations")

err = m.Up(ctx, migs)
err = m.Rollback(ctx, migs, 1)
err = m.Baseline(ctx, migs, "")

Adding a new driver

Implement dbmigrate.Dialect:

type Dialect interface {
    Name() string
    EnsureTableSQL(tableName string) string
    Lock(ctx context.Context, db *sql.DB) (release func() error, err error)
    ListTablesSQL() string
    DropTableSQL(schema, table string) string
    TimestampDefault() string
    QuoteIdentifier(s string) string
}

License

MIT

Documentation

Overview

Package dbmigrate is a minimal, name-based schema migration engine. It is driver-agnostic: provide an *sql.DB and a Dialect implementation.

  • Migrations are tracked by NAME, not by version/timestamp comparison. Two branches creating migrations with colliding or out-of-order timestamps is a non-issue: each file is checked for presence individually, never compared against a "last applied" pointer.
  • Migrations applied together (one `up` run) share a BATCH number, mirroring Laravel's model, which is what makes `rollback`/`refresh` sensible in a name-keyed (non-strictly-ordered) system.
  • Down migrations are optional per-file but required for `rollback` and `refresh`. `fresh` never needs them (it drops tables directly).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Quoted

func Quoted(d Dialect, s string) string

Quoted is a small helper for quoting identifiers in fmt-style strings.

Types

type Dialect

type Dialect interface {
	// Name returns the driver name for logging/errors.
	Name() string

	// EnsureTableSQL returns the CREATE TABLE statement for the tracking table.
	EnsureTableSQL(tableName string) string

	// Lock serializes concurrent migrators. It should return a release
	// function that is safe to call even if the context is cancelled.
	Lock(ctx context.Context, db *sql.DB) (release func() error, err error)

	// ListTablesSQL returns a query that yields one column of table names.
	// Used by Fresh. May return an empty string if Fresh is unsupported.
	ListTablesSQL() string

	// DropTableSQL returns the DDL to drop the named table. schema may be
	// empty for drivers that do not support schemas.
	DropTableSQL(schema, table string) string

	// TimestampDefault returns the default expression for applied_at,
	// e.g. "now()" or "CURRENT_TIMESTAMP".
	TimestampDefault() string

	// QuoteIdentifier quotes a table/schema/column identifier.
	QuoteIdentifier(s string) string
}

Dialect abstracts the database-specific bits of the migration engine. Adding a new driver means implementing this interface plus an Open() function that returns an *sql.DB.

type HistoryEntry

type HistoryEntry struct {
	Name      string
	Batch     int
	AppliedAt string
}

HistoryEntry is one applied migration record.

type Migration

type Migration struct {
	Name     string // base name, e.g. "2022_03_19_153546_add_users_table"
	UpSQL    string
	DownSQL  string // empty if no .down.sql file exists
	HasDown  bool
	Checksum string // sha256 of UpSQL only
}

Migration represents one migration unit: an up file and an optional paired down file, identified by a shared base name.

func Load

func Load(fsys fs.FS, dir string) ([]Migration, error)

Load reads paired {name}.up.sql / {name}.down.sql files from dir inside fsys, sorted by name ascending.

func LoadPath

func LoadPath(dir string) ([]Migration, error)

LoadPath loads migrations from a filesystem directory path.

func LoadPaths

func LoadPaths(dirs []string) ([]Migration, error)

LoadPaths loads migrations from multiple directories in the given order (each directory sorted by name internally; directories are not re-sorted globally). Migration base names must be unique across all directories.

type Migrator

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

Migrator applies migrations from an fs.FS (e.g. embed.FS or os.DirFS) against a database connection, tracking progress by migration name + batch.

func New

func New(db *sql.DB, dialect Dialect, tableName string) *Migrator

New creates a Migrator. tableName defaults to "dbmigrate_migrations".

func (*Migrator) Baseline

func (m *Migrator) Baseline(ctx context.Context, migrations []Migration, lastFileToApply string) error

Baseline records pending migrations as applied without executing their SQL. Use when adopting dbmigrate on a database whose schema already matches some or all migration files (for example after switching from golang-migrate).

If lastFileToApply is non-empty, only migrations up to and including that file (by load order) are baselined; later files stay pending for a normal Up. Accepts a migration base name, optional .up.sql/.down.sql suffix, or a path basename.

func (*Migrator) Fresh

func (m *Migrator) Fresh(ctx context.Context, migrations []Migration, schemaName string) error

Fresh drops every user table directly (no down.sql needed) and then re-runs every migration from scratch as batch 1. Equivalent to Laravel's migrate:fresh. schemaName is ignored for drivers that do not support schemas.

func (*Migrator) History

func (m *Migrator) History(ctx context.Context) ([]HistoryEntry, error)

History returns all applied migrations ordered by batch, then name.

func (*Migrator) Refresh

func (m *Migrator) Refresh(ctx context.Context, migrations []Migration) error

Refresh rolls back every applied batch (requires down.sql on all of them) and then re-runs Up. Equivalent to Laravel's migrate:refresh.

func (*Migrator) Reset

func (m *Migrator) Reset(ctx context.Context, migrations []Migration) error

Reset rolls back every applied batch (requires down.sql on all of them) and does NOT re-apply anything afterward. Equivalent to Laravel's migrate:reset.

func (*Migrator) Rollback

func (m *Migrator) Rollback(ctx context.Context, migrations []Migration, steps int) error

Rollback reverses the last `steps` batches (default 1), running each migration's down.sql in reverse name order within each batch. All targeted migrations must have a down.sql or Rollback fails before changing anything.

func (*Migrator) Status

func (m *Migrator) Status(ctx context.Context, migrations []Migration) ([]string, error)

Status returns pending (not-yet-applied) migration names, in order.

func (*Migrator) Up

func (m *Migrator) Up(ctx context.Context, migrations []Migration) error

Up applies all pending migrations (names not yet recorded) in the order provided, all tagged with the same new batch number (Laravel-style: one migrate run → one batch).

type OpenFunc

type OpenFunc func(dsn string) (*sql.DB, error)

OpenFunc opens a *sql.DB from a DSN. Driver packages provide this.

Directories

Path Synopsis
cmd
dbmigrate command
Command dbmigrate is a small CLI around the dbmigrate package.
Command dbmigrate is a small CLI around the dbmigrate package.
Package postgres provides the PostgreSQL dialect for dbmigrate.
Package postgres provides the PostgreSQL dialect for dbmigrate.
Package sqlite provides the SQLite dialect for dbmigrate.
Package sqlite provides the SQLite dialect for dbmigrate.

Jump to

Keyboard shortcuts

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