Help us shape the future of Go! Take the 2026 Go Developer Survey

schema

package
v0.30.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package schema builds DDL with a fluent, dialect-aware API (SQLite, PostgreSQL and MySQL/MariaDB) and runs versioned migrations with batches and checksums.

s.Create("users", func(t *schema.Table) {
	t.ID()
	t.String("email").Unique()
	t.Timestamps()
})

A Schema builds and runs DDL on any database.Executor. A Migration pairs Up and Down functions under a sortable ID; a Migrator applies them (Up, Rollback, Reset, Fresh, Status) and is what vukem migrate runs. Apps pass their migrations with vukem.WithMigrations.

See https://github.com/AlexGalhardo/vukem/blob/main/docs/database.md#migrations.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func DropAll added in v0.4.0

func DropAll(ctx context.Context, db *database.DB) error

DropAll drops every table of the database (db:wipe, migrate:fresh).

func Record added in v0.29.0

func Record(d database.Dialect, up func(s *Schema) error) ([]string, error)

Record returns the statements up generates for dialect d without running them: the SQL Migrator.Checksum hashes, so a migration can be reviewed or diffed against DDL written elsewhere. Queries are not run while recording, so Schema.HasTable and Schema.HasColumn report false and up records the statements for an empty database.

Types

type Column

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

Column is a column definition; modifiers chain.

func (*Column) CascadeOnDelete

func (c *Column) CascadeOnDelete() *Column

CascadeOnDelete deletes children when the parent row is deleted.

func (*Column) Constrained

func (c *Column) Constrained(table ...string) *Column

Constrained adds a foreign key to table(id); the table defaults to the column name without "_id" pluralised with the ORM's table naming ("user_id" → "users", "category_id" → "categories").

func (*Column) Default

func (c *Column) Default(v any) *Column

Default sets the default (Go value or schema.Expr).

func (*Column) Index

func (c *Column) Index() *Column

Index adds a single-column index.

func (*Column) NullOnDelete

func (c *Column) NullOnDelete() *Column

NullOnDelete sets the column to NULL when the parent row is deleted.

func (*Column) Nullable

func (c *Column) Nullable() *Column

Nullable allows NULL.

func (*Column) RestrictOnDelete

func (c *Column) RestrictOnDelete() *Column

RestrictOnDelete prevents deleting a referenced parent.

func (*Column) Unique

func (c *Column) Unique() *Column

Unique adds a UNIQUE constraint.

type Expr

type Expr string

Expr is a raw SQL default such as schema.Expr("CURRENT_TIMESTAMP").

type Index added in v0.25.0

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

Index is an index added by Table.Index or Table.UniqueIndex; chain Where to make it partial.

func (*Index) Where added in v0.25.0

func (i *Index) Where(expr string) *Index

Where makes the index partial: only rows matching expr are indexed (and, for a unique index, must be unique), e.g. one live reservation per number with UniqueIndex("number_id").Where("status = 'live'"). expr is raw SQL written by the developer (never user input). PostgreSQL and SQLite support it; MySQL and MariaDB have no partial indexes, so the migration fails instead of creating a full index that would reject valid rows.

type Migration

type Migration struct {
	ID   string
	Up   func(s *Schema) error
	Down func(s *Schema) error
}

Migration is one versioned schema change. IDs sort chronologically: "20261016120000_create_users_table".

type Migrator

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

Migrator applies migrations to a database.

Example
package main

import (
	"context"
	"fmt"

	"github.com/AlexGalhardo/vukem/database"
	"github.com/AlexGalhardo/vukem/schema"
)

func main() {
	ctx := context.Background()

	db, _ := database.Open(ctx, ":memory:")
	defer db.Close()

	migrations := []schema.Migration{{
		ID: "20261016120000_create_users_table",
		Up: func(s *schema.Schema) error {
			return s.Create("users", func(t *schema.Table) {
				t.ID()
				t.String("email").Unique()
				t.Timestamps()
			})
		},
		Down: func(s *schema.Schema) error { return s.Drop("users") },
	}}

	m, err := schema.NewMigrator(db, migrations)
	if err != nil {
		fmt.Println(err)
		return
	}

	ran, _ := m.Up(ctx)
	fmt.Println("ran:", ran)

	has, _ := schema.New(ctx, db).HasTable("users")
	fmt.Println("users table:", has)

	rolled, _ := m.Rollback(ctx, 1)
	fmt.Println("rolled back:", rolled)
}
Output:
ran: [20261016120000_create_users_table]
users table: true
rolled back: [20261016120000_create_users_table]

func NewMigrator

func NewMigrator(db *database.DB, migrations []Migration) (*Migrator, error)

NewMigrator validates migrations (unique, non-empty IDs, Up present) and sorts them by ID.

func (*Migrator) Checksum

func (m *Migrator) Checksum(mig Migration) (string, error)

Checksum returns the SHA-256 of the SQL a migration's Up generates for the database's dialect.

func (*Migrator) Fresh

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

Fresh drops every table and runs all migrations. It is destructive: the CLI requires --force in production.

func (*Migrator) Reset

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

Reset reverts every applied migration.

func (*Migrator) Rollback

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

Rollback reverts the last batch, or the last steps migrations when steps > 0. It returns the IDs that were reverted, newest first.

func (*Migrator) Status

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

Status lists every migration with its state, including applied migrations whose generated SQL changed (edited after running) and recorded migrations missing from code.

func (*Migrator) Up

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

Up runs every pending migration in one new batch, each in its own transaction. It returns the IDs that ran.

type Schema

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

Schema runs DDL on an executor. In recording mode (used for checksums) statements are collected instead of executed.

func New

func New(ctx context.Context, ex database.Executor) *Schema

New returns a Schema bound to ctx and ex.

func (*Schema) Create

func (s *Schema) Create(table string, fn func(t *Table)) error

Create creates table with the columns and indexes defined by fn.

func (*Schema) Dialect

func (s *Schema) Dialect() string

Dialect returns the dialect name ("sqlite", "postgres", "mysql").

func (*Schema) Drop

func (s *Schema) Drop(table string) error

Drop drops table.

func (*Schema) DropIfExists

func (s *Schema) DropIfExists(table string) error

DropIfExists drops table when it exists.

func (*Schema) HasColumn added in v0.26.0

func (s *Schema) HasColumn(table, column string) (bool, error)

HasColumn reports whether table has column (false while recording, and for a missing table), so an upgrade migration can add a column only to tables created before it existed.

func (*Schema) HasTable

func (s *Schema) HasTable(table string) (bool, error)

HasTable reports whether table exists (false while recording).

func (*Schema) Raw

func (s *Schema) Raw(sql string, args ...any) error

Raw runs any SQL statement (data migrations, views, triggers). With args, "?" placeholders are rebound to the dialect (database.RebindChecked), so the same data migration runs on SQLite, MySQL and PostgreSQL; a query mixing "?" with "$n" or ending inside a literal is an error. Without args the statement runs as written, so PostgreSQL's jsonb "?" operators in DDL keep working. The migration checksum covers the query as written.

func (*Schema) Rename

func (s *Schema) Rename(from, to string) error

Rename renames a table.

func (*Schema) SQLDialect added in v0.29.0

func (s *Schema) SQLDialect() database.Dialect

SQLDialect returns the dialect the Schema builds DDL for, so a package can render one set of statements for both a migration and a non-migration path, such as a store's boot-time CREATE TABLE IF NOT EXISTS.

func (*Schema) Table

func (s *Schema) Table(table string, fn func(t *Table)) error

Table alters table: added columns, renames, drops and indexes.

type Status

type Status struct {
	ID      string    `json:"id"`
	Ran     bool      `json:"ran"`
	Batch   int       `json:"batch,omitempty"`
	RanAt   time.Time `json:"ran_at,omitzero"`
	Changed bool      `json:"changed,omitempty"` // applied migration whose SQL changed since
	Missing bool      `json:"missing,omitempty"` // recorded in the database but not in code
}

Status describes a migration's state.

type Table

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

Table collects column and index definitions for Create or Table.

func (*Table) BigInteger

func (t *Table) BigInteger(name string) *Column

BigInteger adds a 64-bit integer column.

func (*Table) Binary

func (t *Table) Binary(name string) *Column

Binary adds a binary column.

func (*Table) Boolean

func (t *Table) Boolean(name string) *Column

Boolean adds a boolean column.

func (*Table) Check added in v0.24.0

func (t *Table) Check(name, expr string)

Check adds a named CHECK constraint. expr is raw SQL written by the developer (never user input); it should only use syntax every target dialect understands. On Create it works on SQLite, PostgreSQL and MySQL. On Table (alter) SQLite cannot add constraints to an existing table, so the migration fails instead of silently skipping the rule. MySQL scopes constraint names per database, so prefix them with the table name.

func (*Table) Date

func (t *Table) Date(name string) *Column

Date adds a date column.

func (*Table) Decimal

func (t *Table) Decimal(name string, precision, scale int) *Column

Decimal adds a NUMERIC(precision, scale) column.

func (*Table) DropCheck added in v0.24.0

func (t *Table) DropCheck(name string)

DropCheck drops a named CHECK constraint (alter only; not supported on SQLite). It emits DROP CONSTRAINT, which needs MySQL 8.0.19+ or MariaDB 10.2+.

func (*Table) DropColumn

func (t *Table) DropColumn(names ...string)

DropColumn drops columns (alter only).

func (*Table) DropIndex

func (t *Table) DropIndex(name string)

DropIndex drops an index by name (alter only).

func (*Table) Enum

func (t *Table) Enum(name string, values ...string) *Column

Enum adds a text column restricted to values with a CHECK constraint.

func (*Table) Float

func (t *Table) Float(name string) *Column

Float adds a floating-point column.

func (*Table) ForeignID

func (t *Table) ForeignID(name string) *Column

ForeignID adds a big integer column meant to reference another table; chain Constrained() to add the foreign key.

func (*Table) ID

func (t *Table) ID() *Column

ID adds an auto-increment big integer primary key "id".

func (*Table) Index

func (t *Table) Index(cols ...string) *Index

Index adds an index over cols (name derived: table_col1_col2_index).

func (*Table) Integer

func (t *Table) Integer(name string) *Column

Integer adds an integer column.

func (*Table) JSON

func (t *Table) JSON(name string) *Column

JSON adds a JSON column (JSONB on PostgreSQL, TEXT on SQLite).

func (*Table) RenameColumn

func (t *Table) RenameColumn(from, to string)

RenameColumn renames a column (alter only).

func (*Table) SoftDeletes

func (t *Table) SoftDeletes() *Column

SoftDeletes adds a nullable deleted_at timestamp.

func (*Table) String

func (t *Table) String(name string, length ...int) *Column

String adds a VARCHAR column (default length 255).

func (*Table) Text

func (t *Table) Text(name string) *Column

Text adds an unbounded text column.

func (*Table) Timestamp

func (t *Table) Timestamp(name string) *Column

Timestamp adds a timestamp column (TIMESTAMPTZ on PostgreSQL, DATETIME(6) on MySQL).

func (*Table) Timestamps

func (t *Table) Timestamps()

Timestamps adds nullable created_at and updated_at.

func (*Table) ULID

func (t *Table) ULID(name string) *Column

ULID adds a CHAR(26) column, the width of the text form of a ULID. Package ulid generates the values; the Go field is a plain string.

func (*Table) UUID

func (t *Table) UUID(name string) *Column

UUID adds a UUID column.

func (*Table) UniqueIndex

func (t *Table) UniqueIndex(cols ...string) *Index

UniqueIndex adds a unique index over cols (name derived: table_col1_col2_unique).

Directories

Path Synopsis
Package stores ships the migrations for the tables vukem's own database-backed stores use: the queue's jobs and failed jobs tables, the sessions table, the cache table and the webhook delivery log.
Package stores ships the migrations for the tables vukem's own database-backed stores use: the queue's jobs and failed jobs tables, the sessions table, the cache table and the webhook delivery log.

Jump to

Keyboard shortcuts

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