kit

package
v0.0.0-...-b1a5df8 Latest Latest
Warning

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

Go to latest
Published: Mar 20, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package kit provides Grizzle's migration tooling: schema snapshots, diffing, SQL generation, and schema push. It is the Go equivalent of Drizzle Kit.

Typical usage (library mode — user writes their own migrate entrypoint):

snap := kit.FromDefs(schema.Users, schema.Realms)
sql  := kit.GenerateCreateSQL(schema.Users, schema.Realms)

// Push to DB (introspects current state, diffs, applies changes):
err := kit.Push(ctx, pool, schema.Users, schema.Realms)

Index

Constants

View Source
const MigrationsTable = "_grizzle_migrations"

MigrationsTable is the name of the history table Grizzle creates to track applied migrations.

Variables

This section is empty.

Functions

func AllChangeSQL

func AllChangeSQL(snap Snapshot, changes []Change) []string

AllChangeSQL returns all SQL statements for all changes in order.

func AllChangeSQLMySQL

func AllChangeSQLMySQL(snap Snapshot, changes []Change) []string

AllChangeSQLMySQL returns all MySQL SQL statements for all changes in order.

func AllChangeSQLSQLite

func AllChangeSQLSQLite(snap Snapshot, changes []Change) []string

AllChangeSQLSQLite returns all SQLite SQL statements for all changes in order. Includes SQL comment stubs for changes that SQLite cannot apply directly (ALTER COLUMN type/nullability/untranslatable-default changes).

func ChecksumSQL

func ChecksumSQL(stmts []string) string

ChecksumSQL returns the SHA-256 hex digest of the concatenated SQL statements. The checksum is order-sensitive and is stored in the migrations history table.

func DescribeChanges

func DescribeChanges(changes []Change) string

DescribeChanges produces a short human-readable summary of the change list, e.g. "create_table: users; add_column: posts.title; drop_column: posts.body"

func GenerateChangeSQL

func GenerateChangeSQL(snap Snapshot, c Change) []string

GenerateChangeSQL translates a single Change into one or more SQL statements. The caller is responsible for ordering (Diff() already returns changes in a safe application order for common cases).

func GenerateChangeSQLMySQL

func GenerateChangeSQLMySQL(snap Snapshot, c Change) []string

GenerateChangeSQLMySQL translates a single Change into MySQL SQL statements.

func GenerateChangeSQLSQLite

func GenerateChangeSQLSQLite(snap Snapshot, c Change) []string

GenerateChangeSQLSQLite translates a single Change into SQLite SQL statements.

func GenerateCreateSQL

func GenerateCreateSQL(tables ...pg.TableDefiner) string

GenerateCreateSQL returns the full SQL to create all given tables from scratch, including separate CREATE INDEX statements. Statements are separated by ";\n". It accepts tables from any dialect via the TableDefiner interface.

func GenerateCreateSQLMySQL

func GenerateCreateSQLMySQL(tables ...pg.TableDefiner) string

GenerateCreateSQLMySQL returns CREATE TABLE statements using MySQL syntax. It accepts tables from any dialect via the TableDefiner interface; the DDL is always rendered in MySQL syntax regardless of origin dialect.

func GenerateCreateSQLSQLite

func GenerateCreateSQLSQLite(tables ...pg.TableDefiner) string

GenerateCreateSQLSQLite returns CREATE TABLE + CREATE INDEX statements for SQLite. Unlike the PostgreSQL version, schemas are ignored (SQLite has no schema namespace; ATTACH DATABASE is the SQLite equivalent). It accepts tables from any dialect via the TableDefiner interface.

func SaveJSON

func SaveJSON(snap Snapshot, path string) error

SaveJSON writes a snapshot to a JSON file.

Types

type Change

type Change struct {
	Kind      ChangeKind
	TableName string // qualified name

	// Set for column-level changes.
	OldCol *pg.ColumnDef
	NewCol *pg.ColumnDef

	// Set for constraint-level changes.
	Constraint *pg.Constraint
}

Change represents a single schema mutation — the unit that SQL generation works from.

func Diff

func Diff(old, new Snapshot) []Change

Diff computes the ordered list of Changes needed to transition from the old snapshot to the new snapshot. Pass EmptySnapshot() as old when targeting a fresh database.

Ordering is deterministic:

  1. Create new tables (so FK references resolve).
  2. Alter existing tables (columns first, then constraints).
  3. Drop removed constraints.
  4. Drop removed tables.

Output is sorted for determinism: within each phase, changes are sorted by table name. Within a single table, changes are emitted in slice order (added/modified columns first, then dropped columns, then added/dropped constraints). No secondary sort by change kind or column name is applied.

func SQLiteApplyableChanges

func SQLiteApplyableChanges(changes []Change) []Change

SQLiteApplyableChanges filters a change list to only those that SQLite can actually execute. Changes that require a full table rebuild (ALTER COLUMN type or nullability) and default changes where the translated expression is empty (e.g. gen_random_uuid()) are removed.

Use this when deciding whether a migration has real work to do, so that untranslatable schema differences do not cause infinite spurious migrations.

type ChangeKind

type ChangeKind string

ChangeKind identifies the type of schema change.

const (
	ChangeCreateTable        ChangeKind = "create_table"
	ChangeDropTable          ChangeKind = "drop_table"
	ChangeAddColumn          ChangeKind = "add_column"
	ChangeDropColumn         ChangeKind = "drop_column"
	ChangeAlterColumnType    ChangeKind = "alter_column_type"
	ChangeAlterColumnNull    ChangeKind = "alter_column_nullable"
	ChangeAlterColumnDefault ChangeKind = "alter_column_default"
	ChangeRenameColumn       ChangeKind = "rename_column"
	ChangeAddConstraint      ChangeKind = "add_constraint"
	ChangeDropConstraint     ChangeKind = "drop_constraint"
)

type MigrateResult

type MigrateResult struct {
	AlreadyCurrent bool // true when no changes were needed
	Changes        []Change
	SQL            []string
	Checksum       string
}

MigrateResult contains the outcome of a Migrate call.

func Migrate

func Migrate(ctx context.Context, pool *pgxpool.Pool, tables ...pg.TableDefiner) (MigrateResult, error)

Migrate is like Push but records the applied SQL in the _grizzle_migrations history table. Calling Migrate twice with an unchanged schema is a no-op. It accepts tables from any dialect via the TableDefiner interface.

result, err := kit.Migrate(ctx, pool, schema.Users, schema.Realms)

func MigrateMySQL

func MigrateMySQL(ctx context.Context, db *sql.DB, tables ...pg.TableDefiner) (MigrateResult, error)

MigrateMySQL is like PushMySQL but records the applied SQL in the _grizzle_migrations history table. Calling MigrateMySQL twice with an unchanged schema is a no-op. It accepts tables from any dialect via the TableDefiner interface.

func MigrateSQLite

func MigrateSQLite(ctx context.Context, db *sql.DB, tables ...pg.TableDefiner) (MigrateResult, error)

MigrateSQLite is like PushSQLite but records the applied SQL in the _grizzle_migrations history table. It accepts tables from any dialect via the TableDefiner interface.

type MigrationRecord

type MigrationRecord struct {
	ID          int64     `db:"id"`
	AppliedAt   time.Time `db:"applied_at"`
	Checksum    string    `db:"checksum"`    // SHA-256 hex of the SQL batch
	SQLBatch    string    `db:"sql_batch"`   // full SQL that was applied
	Description string    `db:"description"` // human-readable summary of changes
}

MigrationRecord is a row in the history table.

func LoadHistory

func LoadHistory(ctx context.Context, pool *pgxpool.Pool) ([]MigrationRecord, error)

LoadHistory returns all rows from _grizzle_migrations in chronological order. Returns an empty slice (not an error) if the table does not exist yet.

type PushResult

type PushResult struct {
	Changes []Change
	SQL     []string
}

PushResult contains the outcome of a Push operation.

func DryRun

func DryRun(ctx context.Context, pool *pgxpool.Pool, tables ...pg.TableDefiner) (PushResult, error)

DryRun is like Push but does not apply changes — it only computes and returns what would be run. It accepts tables from any dialect via the TableDefiner interface.

func DryRunMySQL

func DryRunMySQL(ctx context.Context, db *sql.DB, tables ...pg.TableDefiner) (PushResult, error)

DryRunMySQL is like PushMySQL but does not apply changes — it only computes and returns what would be run. It accepts tables from any dialect via the TableDefiner interface.

func DryRunSQLite

func DryRunSQLite(ctx context.Context, db *sql.DB, tables ...pg.TableDefiner) (PushResult, error)

DryRunSQLite is like PushSQLite but does not apply changes. It accepts tables from any dialect via the TableDefiner interface.

func Push

func Push(ctx context.Context, pool *pgxpool.Pool, tables ...pg.TableDefiner) (PushResult, error)

Push inspects the live database, diffs it against the provided table definitions, and applies all necessary DDL changes in a single transaction. It accepts tables from any dialect via the TableDefiner interface.

Example:

result, err := kit.Push(ctx, pool, schema.Users, schema.Realms)
for _, stmt := range result.SQL {
    fmt.Println(stmt)
}

func PushMySQL

func PushMySQL(ctx context.Context, db *sql.DB, tables ...pg.TableDefiner) (PushResult, error)

PushMySQL inspects the live MySQL database, diffs it against the provided table definitions, and applies all necessary DDL changes in a transaction. It accepts tables from any dialect via the TableDefiner interface.

func PushSQLite

func PushSQLite(ctx context.Context, db *sql.DB, tables ...pg.TableDefiner) (PushResult, error)

PushSQLite inspects the live SQLite database, diffs it against the provided table definitions, and applies all necessary DDL changes. It accepts tables from any dialect via the TableDefiner interface.

Note: SQLite does not support ALTER COLUMN (type, nullability, or default changes). Such changes will produce SQL comment stubs; apply them by rebuilding the affected table manually.

type Snapshot

type Snapshot struct {
	Version   string                `json:"version"`
	CreatedAt time.Time             `json:"created_at"`
	Tables    map[string]*TableSnap `json:"tables"` // keyed by qualified table name
}

Snapshot is a serializable, point-in-time representation of a database schema. It is saved to disk as JSON and used to compute incremental diffs.

func EmptySnapshot

func EmptySnapshot() Snapshot

EmptySnapshot returns an empty snapshot representing a blank database.

func FromDefs

func FromDefs(tables ...pg.TableDefiner) Snapshot

FromDefs builds a Snapshot from a set of dialect-agnostic TableDefiner values. This is the normal way to capture your schema definition. It accepts tables from any dialect (pg, mysql, sqlite).

func LoadJSON

func LoadJSON(path string) (Snapshot, error)

LoadJSON reads a snapshot from a JSON file.

type StatusResult

type StatusResult struct {
	Applied []MigrationRecord // rows in _grizzle_migrations (oldest first)
	Pending []Change          // changes not yet applied
	SQL     []string          // SQL that would apply the pending changes
}

StatusResult is returned by Status — it shows what is recorded vs. what the live schema looks like.

func Status

func Status(ctx context.Context, pool *pgxpool.Pool, tables ...pg.TableDefiner) (StatusResult, error)

Status reports the applied migration history and any pending changes without modifying the database. It accepts tables from any dialect via the TableDefiner interface.

status, err := kit.Status(ctx, pool, schema.Users, schema.Realms)
for _, r := range status.Applied {
    fmt.Printf("[%s] %s\n", r.AppliedAt.Format(time.RFC3339), r.Description)
}
if len(status.Pending) > 0 {
    fmt.Println("Pending changes:", len(status.Pending))
}

func StatusMySQL

func StatusMySQL(ctx context.Context, db *sql.DB, tables ...pg.TableDefiner) (StatusResult, error)

StatusMySQL reports the applied migration history and any pending changes for a MySQL database without modifying it. It accepts tables from any dialect via the TableDefiner interface.

func StatusSQLite

func StatusSQLite(ctx context.Context, db *sql.DB, tables ...pg.TableDefiner) (StatusResult, error)

StatusSQLite reports the applied migration history and any pending changes for a SQLite database without modifying it. It accepts tables from any dialect via the TableDefiner interface.

type TableSnap

type TableSnap struct {
	Name        string          `json:"name"`
	Schema      string          `json:"schema,omitempty"`
	Columns     []pg.ColumnDef  `json:"columns"`
	Constraints []pg.Constraint `json:"constraints,omitempty"`
}

TableSnap is the snapshot of a single table.

func (*TableSnap) QualifiedName

func (t *TableSnap) QualifiedName() string

QualifiedName returns the schema-qualified name used as the map key.

Directories

Path Synopsis
Package introspect reads a live PostgreSQL database and returns a kit.Snapshot representing its current schema.
Package introspect reads a live PostgreSQL database and returns a kit.Snapshot representing its current schema.

Jump to

Keyboard shortcuts

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