migrate

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 22, 2026 License: AGPL-3.0 Imports: 10 Imported by: 0

Documentation

Overview

Package migrate runs database schema migrations with goose over the pgx stdlib driver (a database/sql handle, distinct from an application's pgxpool). The migration set is supplied by the caller — an fs.FS and a directory within it, via New — rather than embedded in this package, so each application embeds and owns its own migrations and this package only supplies the up/down/status/reset/up-to/down-to plumbing plus the pooler-safe connection handling.

It is built on goose's Provider API (goose.NewProvider), not the legacy package-level dispatcher (goose.RunContext). The legacy API configures goose through process-global state — one base fs.FS and one dialect, both set once via init() — so a library built on it could only ever serve one migration set per process. Provider takes its filesystem per instance and holds no global state, so a Runner has none either: two Runners over different migration sets coexist safely in one process.

goose records applied migrations in its goose_db_version table (created automatically on first run); the up/down/status/reset/up-to/down-to operations consult it to compute the delta to apply or revert.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func WriteStatus

func WriteStatus(w io.Writer, statuses []MigrationStatus) error

WriteStatus renders statuses to w in the same table format the legacy goose dispatcher printed — through its own logger, which, despite this package's former doc comment claiming stdout, actually wrote to stderr. Callers now choose the destination explicitly; Nestova passes os.Stdout, which finally makes that documented behaviour true.

Types

type MigrationStatus

type MigrationStatus struct {
	Version   int64
	Source    string // filepath.Base of the migration file
	Applied   bool
	AppliedAt time.Time // zero value if not applied
}

MigrationStatus is one migration's applied/pending state, independent of goose's own type so goose stays out of this package's public API surface.

type Option

type Option func(*options)

Option customizes a migration run.

func PoolerSafe

func PoolerSafe() Option

PoolerSafe configures the migration connection to use the simple query protocol so goose's version-bookkeeping queries do not rely on named server-side prepared statements, which a transaction pooler (PgBouncer / Supabase Supavisor) cannot keep across multiplexed transactions. Prefer pointing the DSN at a direct/session connection over enabling this.

type Runner

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

Runner applies migrations from one caller-supplied filesystem. Construct one with New; it holds no process-global state, so multiple Runners over different migration sets are safe to use concurrently in one process.

func New

func New(fsys fs.FS, dir string) (*Runner, error)

New returns a Runner over the .sql migrations rooted at dir within fsys. dir may be "" or "." for a filesystem that is already rooted at its migrations (e.g. a //go:embed of just the migration files); any other value names a subdirectory of fsys.

New fails fast when dir holds no .sql migrations, rather than deferring that discovery to the first Up/Down/etc. call: goose's Provider globs the ROOT of the fs.FS it is given for "*.sql" — it does not walk into subdirectories — so this check mirrors exactly what every Runner method requires of the filesystem it was built from. fs.Sub does not itself fail on a missing directory, so without this check a bad dir would surface only much later, as an opaque "no migrations found" from inside goose.

func (*Runner) Down

func (r *Runner) Down(ctx context.Context, dsn string, opts ...Option) error

Down rolls back the most recently applied migration. If nothing is applied, it returns a wrapped goose.ErrNoNextVersion — unlike Reset and DownTo, Down does not treat an empty database as a no-op.

func (*Runner) DownTo

func (r *Runner) DownTo(ctx context.Context, dsn string, version int64, opts ...Option) error

DownTo rolls back migrations until only those up to and including the given goose version remain applied — the mirror of UpTo. DownTo(ctx, dsn, 24) leaves 00024 applied and rolls back everything above it.

This is the pinned-version-boundary pattern for migration tests: a test that means "roll back exactly migration N" must use DownTo(N-1), never Down. Down rolls back whatever is LATEST, so a test written against it silently starts exercising a different migration the moment another one lands on top. Pinning both boundaries keeps such a test meaningful at any future highest version.

func (*Runner) Reset

func (r *Runner) Reset(ctx context.Context, dsn string, opts ...Option) error

Reset rolls back every applied migration, via DownTo(0). Intended for tests and local resets.

Unlike the legacy dispatcher this package used to sit on, Reset needs no special case for a pristine database: goose's Provider ensures the version table (and its zero-version row) exists before reading applied versions, so DownTo(0) against an already-empty schema is a clean no-op rather than an error.

Reset is also STRICTER than the legacy behaviour about orphan versions: a database row recorded for a version with no corresponding migration file — for example, one migrated from a different branch — now fails loudly instead of being silently skipped. That is deliberate; do not read it as a bug.

func (*Runner) Status

func (r *Runner) Status(ctx context.Context, dsn string, opts ...Option) ([]MigrationStatus, error)

Status returns the applied/pending state of every migration in the Runner's filesystem, ordered by version ascending. It performs no output itself; pass the result to WriteStatus to render it.

func (*Runner) Up

func (r *Runner) Up(ctx context.Context, dsn string, opts ...Option) error

Up applies all pending migrations.

func (*Runner) UpTo

func (r *Runner) UpTo(ctx context.Context, dsn string, version int64, opts ...Option) error

UpTo applies migrations up to and including the given goose version — the migration file's numeric filename prefix, e.g. 24 for 00024_reward_catalog_admin.sql.

This exists for gated tests that need to seed data against an intermediate schema (i.e. stop applying migrations partway through) and then apply one specific migration on top of it, to prove that migration handles pre-existing rows correctly — coverage a plain Reset+Up cannot provide, since that always starts from an empty database where a backfill UPDATE trivially matches zero rows.

Jump to

Keyboard shortcuts

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