Documentation
¶
Overview ¶
Package sow is a small, general-purpose SQL migration runner: point it at a SQLite or Postgres database and a directory of `.sql` migration files, and it applies the pending ones in order, once, recording what it applied so re-running is a no-op. Rollbacks run each migration's `down` section. No ORM, no codegen, no framework — read migrations, apply them, sow it up.
The core owns NO SQLite driver: it runs over an injected Conn (see Conn/TxConn), so it compiles to wasm and can run as a Pulp cell that gets SQLite from the host capability, exactly like a native binary gets it from modernc. Use Open (native, CLI) to get a modernc-backed DB, or New(conn) to inject any Conn — e.g. a host-backed one in a cell.
A migration file is plain SQL with two sections:
-- +sow up CREATE TABLE widgets (id INTEGER PRIMARY KEY, name TEXT); -- +sow down DROP TABLE widgets;
The file name (without .sql) is its VERSION and sort key: 001_init.sql, 20260708_x.sql.
Index ¶
- type Conn
- type DB
- func (d *DB) AppliedVersions() ([]string, error)
- func (d *DB) Close() error
- func (d *DB) Dialect() Dialect
- func (d *DB) Down(ms []Migration, n int, opt Options) (Result, error)
- func (d *DB) MarkApplied(version, name string, at int64) error
- func (d *DB) Pending(ms []Migration) ([]Migration, error)
- func (d *DB) Status(ms []Migration) ([]StatusRow, error)
- func (d *DB) Up(ms []Migration, opt Options) (Result, error)
- type Dialect
- type Manifest
- type Migration
- type Options
- type Result
- type StatusRow
- type TxConn
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Conn ¶
type Conn interface {
Exec(query string, args ...any) error
Query(query string, args ...any) ([][]any, error)
}
Conn is the minimal SQLite capability sow runs over. Inject a native (modernc) conn via Open, or a Pulp host-backed conn in a cell — the core imports no driver, so it builds to wasm. Query returns rows as [][]any (one []any per row), matching the host wire shape.
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB is a migration target: any Conn with the sow ledger ensured, speaking one Dialect.
func New ¶
New wraps an injected Conn (native, host-backed, or a test fake) and ensures the ledger table exists, speaking SQLite. This is the driver-agnostic constructor; Open is the native convenience. Use NewWithDialect to inject a Conn that talks to something else.
func NewWithDialect ¶
NewWithDialect is New over a caller-chosen Dialect — the seam for an injected Conn that is not SQLite (a Pulp cell whose host capability is Postgres, say). The zero Dialect means SQLite, so NewWithDialect(conn, Dialect{}) is exactly New(conn).
func Open ¶
Open opens (or creates) a SQLite database at path (":memory:" allowed) and returns a DB with the ledger ensured, backed by modernc over database/sql.
func OpenPostgres ¶
OpenPostgres opens a Postgres database at dsn (a URL like "postgres://user:pass@host:5432/db?sslmode=require", or a libpq key/value string) and returns a DB with the ledger ensured, backed by pgx over database/sql. It is the Postgres sibling of Open; the DB it returns speaks Postgres SQL for its ledger.
Note that sql.Open does not dial — a bad host surfaces on the ledger's first statement, which is inside this call, so a returned DB has proven it can reach the database.
func (*DB) AppliedVersions ¶
AppliedVersions returns the applied versions in application order.
func (*DB) Close ¶
Close closes the underlying Conn if it is a Closer (the native adapter is); a host-backed Conn the caller owns is left untouched.
func (*DB) Down ¶
Down rolls back the last n applied migrations (n<=0 means 1), newest first. A migration with no Down section is an error (irreversible).
func (*DB) MarkApplied ¶
MarkApplied records a version as already applied WITHOUT running it — the hook a caller uses to adopt sow over a database migrated by an older mechanism (seed the ledger from a prior version counter so those steps don't re-run). Idempotent.
type Dialect ¶
type Dialect struct {
// contains filtered or unexported fields
}
Dialect is the SQL flavour sow speaks to a target database. sow ships two: SQLite (the default) and Postgres. The zero value is SQLite, so a DB built without naming a dialect behaves exactly as sow did before dialects existed.
Its fields are unexported on purpose: a Dialect is a value sow hands you (SQLite() or Postgres()), not a plugin point. That keeps the published surface two functions wide and leaves sow free to change what a dialect must know without breaking callers.
func Postgres ¶
func Postgres() Dialect
Postgres returns the Postgres dialect: `ON CONFLICT (version) DO NOTHING` and `$n` placeholders. Pair it with OpenPostgres, or with NewWithDialect over an injected Conn.
type Manifest ¶ added in v0.3.0
type Manifest struct {
Migrations []string `json:"migrations"`
}
Manifest is an explicit, shippable migration plan. Entries are paths relative to the manifest file and run in the authored order; the filename still supplies each migration's stable version and name.
type Migration ¶
type Migration struct {
Version string // sort key / unique id (the file name without .sql)
Name string // human label (the part after the leading version token)
Up string // SQL applied when migrating forward
Down string // SQL applied when rolling back ("" = irreversible)
Path string // source file, for error messages ("" for in-memory)
}
Migration is one versioned step: its Up SQL, optional Down SQL, and identity.
func LoadFS ¶
LoadFS reads every *.sql migration under dir in an fs.FS — an embed.FS in a wasm cell, os.DirFS on disk, or any other fs.FS — parses them, and returns them sorted by version. This is the driver-agnostic sibling of Load(dir): it uses only io/fs, so it works inside a Pulp cell where there is no os filesystem and migrations ship embedded in the binary.
func LoadManifestFS ¶ added in v0.3.0
LoadManifestFS loads migrations in the exact order declared by a JSON manifest. It works with embed.FS, os.DirFS, or any other fs.FS, so an application can ship its migration plan and SQL together without hard-coding schema steps in Go.
type Options ¶
type Options struct {
DryRun bool // plan only — writes nothing
Logf func(format string, a ...any) // progress sink (nil = silent)
Now func() int64 // applied_at clock (nil = 0); injectable for tests
}
Options tune an Up/Down run.
type Result ¶
type Result struct {
Applied []Migration // migrations whose Up ran
Rolled []Migration // migrations whose Down ran
}
Result summarizes what a run did.
type TxConn ¶
TxConn is a Conn that can run a unit of work atomically. Backends that support transactions (the native modernc adapter) implement it, so each migration is all-or-nothing; a backend that doesn't (a bare host capability) is driven best-effort — statements then ledger, no rollback — which is how a seam-only store already migrates.