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 ¶
- func DropAll(ctx context.Context, db *database.DB) error
- func Record(d database.Dialect, up func(s *Schema) error) ([]string, error)
- type Column
- func (c *Column) CascadeOnDelete() *Column
- func (c *Column) Constrained(table ...string) *Column
- func (c *Column) Default(v any) *Column
- func (c *Column) Index() *Column
- func (c *Column) NullOnDelete() *Column
- func (c *Column) Nullable() *Column
- func (c *Column) Primary() *Column
- func (c *Column) RestrictOnDelete() *Column
- func (c *Column) StoredAs(expr string) *Column
- func (c *Column) Unique() *Column
- type Expr
- type Index
- type Migration
- type Migrator
- func (m *Migrator) Checksum(mig Migration) (string, error)
- func (m *Migrator) Fresh(ctx context.Context) ([]string, error)
- func (m *Migrator) Reset(ctx context.Context) ([]string, error)
- func (m *Migrator) Rollback(ctx context.Context, steps int) ([]string, error)
- func (m *Migrator) Status(ctx context.Context) ([]Status, error)
- func (m *Migrator) Up(ctx context.Context) ([]string, error)
- type Schema
- func (s *Schema) Create(table string, fn func(t *Table)) error
- func (s *Schema) Dialect() string
- func (s *Schema) Drop(table string) error
- func (s *Schema) DropIfExists(table string) error
- func (s *Schema) HasColumn(table, column string) (bool, error)
- func (s *Schema) HasTable(table string) (bool, error)
- func (s *Schema) Raw(sql string, args ...any) error
- func (s *Schema) Rename(from, to string) error
- func (s *Schema) SQLDialect() database.Dialect
- func (s *Schema) Table(table string, fn func(t *Table)) error
- type Status
- type Table
- func (t *Table) BigInteger(name string) *Column
- func (t *Table) Binary(name string) *Column
- func (t *Table) Boolean(name string) *Column
- func (t *Table) Check(name, expr string)
- func (t *Table) Date(name string) *Column
- func (t *Table) Decimal(name string, precision, scale int) *Column
- func (t *Table) DropCheck(name string)
- func (t *Table) DropColumn(names ...string)
- func (t *Table) DropIndex(name string)
- func (t *Table) Enum(name string, values ...string) *Column
- func (t *Table) Float(name string) *Column
- func (t *Table) ForeignID(name string) *Column
- func (t *Table) ID() *Column
- func (t *Table) Index(cols ...string) *Index
- func (t *Table) Integer(name string) *Column
- func (t *Table) JSON(name string) *Column
- func (t *Table) Primary(cols ...string)
- func (t *Table) RenameColumn(from, to string)
- func (t *Table) SmallInteger(name string) *Column
- func (t *Table) SoftDeletes() *Column
- func (t *Table) String(name string, length ...int) *Column
- func (t *Table) Text(name string) *Column
- func (t *Table) Timestamp(name string) *Column
- func (t *Table) Timestamps()
- func (t *Table) ULID(name string) *Column
- func (t *Table) UUID(name string) *Column
- func (t *Table) UniqueIndex(cols ...string) *Index
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Record ¶ added in v0.29.0
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 ¶
CascadeOnDelete deletes children when the parent row is deleted.
func (*Column) Constrained ¶
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) NullOnDelete ¶
NullOnDelete sets the column to NULL when the parent row is deleted.
func (*Column) Primary ¶ added in v0.33.0
Primary makes this column the table's primary key (see Table.Primary).
func (*Column) RestrictOnDelete ¶
RestrictOnDelete prevents deleting a referenced parent.
func (*Column) StoredAs ¶ added in v0.33.0
StoredAs makes the column a stored generated column computed from expr (GENERATED ALWAYS AS (expr) STORED), e.g. an average of score columns. expr is raw SQL written by the developer (never user input). The database rejects writes to it, so map it in the ORM with db:"-" or a read-only model. SQLite cannot add a stored generated column to an existing table, so that migration fails.
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 and Using to pick a PostgreSQL index method.
func (*Index) Using ¶ added in v0.34.0
Using picks the PostgreSQL index method: "gin" for a JSONB column queried with @> or ?, "gist", "brin", "hash", "spgist" or "btree" (the default). Other dialects have no equivalent, so the migration fails there instead of creating an index that cannot serve the queries it was meant for.
func (*Index) Where ¶ added in v0.25.0
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
// NoTransaction runs Up and Down outside a transaction, for statements
// a transaction refuses (PostgreSQL CREATE INDEX CONCURRENTLY, SQLite
// VACUUM). The migration is recorded after Up succeeds; a failure
// half-way leaves the statements that ran, so keep such migrations to
// one statement, written to be re-run (IF NOT EXISTS).
NoTransaction bool
}
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 ¶
NewMigrator validates migrations (unique, non-empty IDs, Up present) and sorts them by ID.
func (*Migrator) Checksum ¶
Checksum returns the SHA-256 of the SQL a migration's Up generates for the database's dialect.
func (*Migrator) Fresh ¶
Fresh drops every table and runs all migrations. It is destructive: the CLI requires --force in production.
func (*Migrator) Rollback ¶
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 ¶
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 ¶
Up runs every pending migration in one new batch, each in its own transaction (unless NoTransaction). It returns the IDs that ran.
Up, Rollback, Reset and Fresh hold a lock for the whole run, so two processes migrating at once (a rolling deploy) run one after the other and the second finds nothing pending: a PostgreSQL advisory lock or a MySQL GET_LOCK, keyed by the migrations table. They wait for it until ctx is done, and fail without migrating when it cannot be taken. SQLite takes no lock: run its migrations from one process.
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 (*Schema) DropIfExists ¶
DropIfExists drops table when it exists.
func (*Schema) HasColumn ¶ added in v0.26.0
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) Raw ¶
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) SQLDialect ¶ added in v0.29.0
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.
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 ¶
BigInteger adds a 64-bit integer column.
func (*Table) Check ¶ added in v0.24.0
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) DropCheck ¶ added in v0.24.0
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 ¶
DropColumn drops columns (alter only).
func (*Table) ForeignID ¶
ForeignID adds a big integer column meant to reference another table; chain Constrained() to add the foreign key.
func (*Table) Primary ¶ added in v0.33.0
Primary declares the table's primary key on cols, e.g. t.Primary("user_id", "item_id") for a composite key or a UUID key with t.UUID("id").Primary(). It is Create only and cannot be combined with ID(). The ORM side of a composite key is orm.CompositeKeyer.
func (*Table) RenameColumn ¶
RenameColumn renames a column (alter only).
func (*Table) SmallInteger ¶ added in v0.33.0
SmallInteger adds a SMALLINT column (2 bytes, -32768..32767), e.g. a 1..10 score.
func (*Table) SoftDeletes ¶
SoftDeletes adds a nullable deleted_at timestamp.
func (*Table) Timestamp ¶
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 ¶
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) UniqueIndex ¶
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. |