Documentation
¶
Overview ¶
Package schema provides a table definition DSL for declaring database schemas in Go. One table definition drives DDL generation, column lists, seed data, and schema snapshots across all supported dialects. Use Snapshot and LiveSnapshot to compare declared schemas against live databases for drift detection.
Index ¶
- Variables
- func SQLExpr(expr string) sqlExpr
- func SchemaSnapshotString(d chuck.Dialect, tables ...*TableDef) string
- type ColumnDef
- func ArchiveColumnDefs() []ColumnDef
- func AuditColumnDefs() []ColumnDef
- func AutoIncrCol(name string) ColumnDef
- func Col(name string, typeFn TypeFunc) ColumnDef
- func ExpiryColumnDefs() []ColumnDef
- func NotesColumnDefs() []ColumnDef
- func ParentColumnDefs() []ColumnDef
- func ReplacementColumnDefs() []ColumnDef
- func SoftDeleteColumnDefs() []ColumnDef
- func SortOrderColumnDefs() []ColumnDef
- func StatusColumnDefs(defaultStatus string) []ColumnDef
- func TimestampColumnDefs() []ColumnDef
- func UUIDColumnDefs() []ColumnDef
- func UUIDPKCol(name string) ColumnDef
- func VersionColumnDefs() []ColumnDef
- func (c ColumnDef) Check(expr string) ColumnDef
- func (c ColumnDef) Default(expr string) ColumnDef
- func (c ColumnDef) DefaultFn(fn func(chuck.Dialect) string) ColumnDef
- func (c ColumnDef) Immutable() ColumnDef
- func (c ColumnDef) Mutable() ColumnDef
- func (c ColumnDef) Name() string
- func (c ColumnDef) NotNull() ColumnDef
- func (c ColumnDef) OnDelete(action string) ColumnDef
- func (c ColumnDef) OnUpdate(action string) ColumnDef
- func (c ColumnDef) PrimaryKey() ColumnDef
- func (c ColumnDef) References(table, column string) ColumnDef
- func (c ColumnDef) Unique() ColumnDef
- type ColumnSnapshot
- type IndexDef
- type IndexSnapshot
- type LiveColumnSnapshot
- type LiveIndexSnapshot
- type LiveTableSnapshot
- type SchemaError
- type SeedRow
- type SeedValues
- type TableDef
- func CreationOrder(tables ...*TableDef) ([]*TableDef, error)
- func DropOrder(tables ...*TableDef) ([]*TableDef, error)
- func NewConfigTable(name, keyCol, valueCol string) *TableDef
- func NewEventTable(name string, cols ...ColumnDef) *TableDef
- func NewLookupJoinTable(name string) *TableDef
- func NewLookupTable(name, groupCol, valueCol string) *TableDef
- func NewMappingTable(name, leftCol, rightCol string) *TableDef
- func NewQueueTable(name, payloadCol string) *TableDef
- func NewTable(name string) *TableDef
- func (t *TableDef) Columns(cols ...ColumnDef) *TableDef
- func (t *TableDef) CreateIfNotExistsSQL(d chuck.Dialect) []string
- func (t *TableDef) CreateSQL(d chuck.Dialect) []string
- func (t *TableDef) DropSQL(d chuck.Dialect) string
- func (t *TableDef) HasArchive() bool
- func (t *TableDef) HasExpiry() bool
- func (t *TableDef) HasSeedData() bool
- func (t *TableDef) HasSoftDelete() bool
- func (t *TableDef) HasVersion() bool
- func (t *TableDef) Indexes(indexes ...IndexDef) *TableDef
- func (t *TableDef) InsertColumns() []string
- func (t *TableDef) InsertColumnsFor(d chuck.Dialect) []string
- func (t *TableDef) SeedRows() []SeedRow
- func (t *TableDef) SeedSQL(d chuck.Dialect) []string
- func (t *TableDef) SelectColumns() []string
- func (t *TableDef) SelectColumnsFor(d chuck.Dialect) []string
- func (t *TableDef) Snapshot(d chuck.Dialect) TableSnapshot
- func (t *TableDef) SnapshotString(d chuck.Dialect) string
- func (t *TableDef) TableNameFor(d chuck.Dialect) string
- func (t *TableDef) UniqueColumns(columns ...string) *TableDef
- func (t *TableDef) UpdateColumns() []string
- func (t *TableDef) UpdateColumnsFor(d chuck.Dialect) []string
- func (t *TableDef) WithArchive() *TableDef
- func (t *TableDef) WithAuditTrail() *TableDef
- func (t *TableDef) WithExpiry() *TableDef
- func (t *TableDef) WithNotes() *TableDef
- func (t *TableDef) WithParent() *TableDef
- func (t *TableDef) WithReplacement() *TableDef
- func (t *TableDef) WithSeedRows(rows ...SeedRow) *TableDef
- func (t *TableDef) WithSeedValues(rows ...SeedValues) *TableDef
- func (t *TableDef) WithSoftDelete() *TableDef
- func (t *TableDef) WithSortOrder() *TableDef
- func (t *TableDef) WithStatus(defaultStatus string) *TableDef
- func (t *TableDef) WithTimestamps() *TableDef
- func (t *TableDef) WithUUID() *TableDef
- func (t *TableDef) WithVersion() *TableDef
- type TableSnapshot
- type TypeFunc
- func TypeAutoIncrement() TypeFunc
- func TypeBigInt() TypeFunc
- func TypeBool() TypeFunc
- func TypeDecimal(precision, scale int) TypeFunc
- func TypeFloat() TypeFunc
- func TypeInt() TypeFunc
- func TypeJSON() TypeFunc
- func TypeLiteral(s string) TypeFunc
- func TypeString(n int) TypeFunc
- func TypeText() TypeFunc
- func TypeTimestamp() TypeFunc
- func TypeUUID() TypeFunc
- func TypeUUIDPK() TypeFunc
- func TypeVarchar(n int) TypeFunc
- type UniqueConstraint
Examples ¶
- NewConfigTable
- NewEventTable
- NewLookupJoinTable
- NewLookupTable
- NewMappingTable
- NewQueueTable
- NewTable
- NewTable (AllTraits)
- NewTable (ForeignKeys)
- NewTable (Traits)
- NewTable (UuidPrimaryKey)
- SchemaSnapshotString
- TableDef (ColumnLists)
- TableDef.Snapshot
- TableDef.WithSeedRows
- TableDef.WithSeedRows (Postgres)
Constants ¶
This section is empty.
Variables ¶
var ErrCyclicDependency = errors.New("cyclic foreign key dependency among tables")
ErrCyclicDependency is returned when tables have circular foreign key references.
Functions ¶
func SQLExpr ¶ added in v0.1.10
func SQLExpr(expr string) sqlExpr
SQLExpr wraps a raw SQL expression so it is emitted verbatim in seed data. Use this for database functions like CURRENT_TIMESTAMP or dialect-specific expressions.
func SchemaSnapshotString ¶
SchemaSnapshotString returns a human-readable snapshot of multiple tables.
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
d, _ := chuck.New(chuck.SQLite)
users := schema.NewTable("Users").
Columns(
schema.AutoIncrCol("ID"),
schema.Col("Email", schema.TypeString(255)).NotNull().Unique(),
)
tasks := schema.NewTable("Tasks").
Columns(
schema.AutoIncrCol("ID"),
schema.Col("Title", schema.TypeString(255)).NotNull(),
schema.Col("UserID", schema.TypeInt()).References("Users", "ID"),
)
fmt.Print(schema.SchemaSnapshotString(d, users, tasks))
}
Output: TABLE Users ID INTEGER PRIMARY KEY AUTOINCREMENT PRIMARY KEY AUTO INCREMENT NOT NULL [immutable] Email TEXT NOT NULL UNIQUE TABLE Tasks ID INTEGER PRIMARY KEY AUTOINCREMENT PRIMARY KEY AUTO INCREMENT NOT NULL [immutable] Title TEXT NOT NULL UserID INTEGER REFERENCES Users(ID)
Types ¶
type ColumnDef ¶
type ColumnDef struct {
// contains filtered or unexported fields
}
ColumnDef defines a single table column.
func ArchiveColumnDefs ¶
func ArchiveColumnDefs() []ColumnDef
ArchiveColumnDefs returns a nullable ArchivedAt timestamp column.
func AuditColumnDefs ¶
func AuditColumnDefs() []ColumnDef
AuditColumnDefs returns CreatedBy, UpdatedBy, and DeletedBy columns.
func AutoIncrCol ¶
AutoIncrCol creates an auto-incrementing primary key column (immutable).
func ExpiryColumnDefs ¶
func ExpiryColumnDefs() []ColumnDef
ExpiryColumnDefs returns a nullable ExpiresAt timestamp column.
func NotesColumnDefs ¶
func NotesColumnDefs() []ColumnDef
NotesColumnDefs returns a nullable Notes text column.
func ParentColumnDefs ¶
func ParentColumnDefs() []ColumnDef
ParentColumnDefs returns a nullable ParentID column for tree structures.
func ReplacementColumnDefs ¶
func ReplacementColumnDefs() []ColumnDef
ReplacementColumnDefs returns a nullable ReplacedByID column for entity lineage tracking.
func SoftDeleteColumnDefs ¶
func SoftDeleteColumnDefs() []ColumnDef
SoftDeleteColumnDefs returns a nullable DeletedAt timestamp column.
func SortOrderColumnDefs ¶
func SortOrderColumnDefs() []ColumnDef
SortOrderColumnDefs returns a SortOrder column for manual ordering.
func StatusColumnDefs ¶
StatusColumnDefs returns a Status column with a default value.
func TimestampColumnDefs ¶
func TimestampColumnDefs() []ColumnDef
TimestampColumnDefs returns CreatedAt and UpdatedAt column definitions.
func UUIDColumnDefs ¶
func UUIDColumnDefs() []ColumnDef
UUIDColumnDefs returns a UUID column (NOT NULL, UNIQUE).
func UUIDPKCol ¶
UUIDPKCol creates a UUID primary key column (immutable). On Postgres this generates: id UUID PRIMARY KEY DEFAULT gen_random_uuid() On other engines it uses the engine's UUID type with PRIMARY KEY.
func VersionColumnDefs ¶
func VersionColumnDefs() []ColumnDef
VersionColumnDefs returns a Version column for optimistic concurrency control.
func (ColumnDef) Check ¶ added in v0.1.10
Check adds a CHECK constraint with the given SQL expression (e.g. "age >= 0").
func (ColumnDef) Immutable ¶
Immutable marks the column as immutable (excluded from UPDATE column lists).
func (ColumnDef) OnDelete ¶
OnDelete sets the referential action for DELETE (e.g. "CASCADE", "SET NULL").
func (ColumnDef) OnUpdate ¶
OnUpdate sets the referential action for UPDATE (e.g. "CASCADE", "SET NULL").
func (ColumnDef) PrimaryKey ¶
PrimaryKey marks the column as a primary key.
func (ColumnDef) References ¶
References adds a foreign key reference to another table's column.
type ColumnSnapshot ¶
type ColumnSnapshot struct {
Name string `json:"name"`
Type string `json:"type"`
NotNull bool `json:"not_null,omitempty"`
Unique bool `json:"unique,omitempty"`
PrimaryKey bool `json:"primary_key,omitempty"`
AutoIncr bool `json:"auto_increment,omitempty"`
Mutable bool `json:"mutable"`
Default string `json:"default,omitempty"`
RefTable string `json:"references_table,omitempty"`
RefColumn string `json:"references_column,omitempty"`
OnDelete string `json:"on_delete,omitempty"`
OnUpdate string `json:"on_update,omitempty"`
Check string `json:"check,omitempty"`
}
ColumnSnapshot describes a single column's resolved schema for a given dialect.
type IndexDef ¶
type IndexDef struct {
// contains filtered or unexported fields
}
IndexDef defines a table index.
func PartialIndex ¶ added in v0.1.10
PartialIndex creates a partial (filtered) index definition with a WHERE clause.
func UniqueIndex ¶ added in v0.1.10
UniqueIndex creates a unique index definition.
func UniquePartialIndex ¶ added in v0.1.10
UniquePartialIndex creates a unique partial (filtered) index definition.
type IndexSnapshot ¶
type IndexSnapshot struct {
Name string `json:"name"`
Columns string `json:"columns"`
Unique bool `json:"unique,omitempty"`
Where string `json:"where,omitempty"`
}
IndexSnapshot describes a single index.
type LiveColumnSnapshot ¶
type LiveColumnSnapshot struct {
Name string `json:"name"`
Type string `json:"type"`
Nullable bool `json:"nullable"`
Default string `json:"default,omitempty"`
}
LiveColumnSnapshot describes a column as it exists in a live database.
type LiveIndexSnapshot ¶
LiveIndexSnapshot describes an index as it exists in a live database.
type LiveTableSnapshot ¶
type LiveTableSnapshot struct {
Name string `json:"name"`
Columns []LiveColumnSnapshot `json:"columns"`
Indexes []LiveIndexSnapshot `json:"indexes,omitempty"`
}
LiveTableSnapshot describes a table's actual schema as read from a live database. Compare against TableSnapshot (from Snapshot()) to detect schema drift.
func LiveSchemaSnapshot ¶
func LiveSchemaSnapshot(ctx context.Context, db *sql.DB, d chuck.Dialect, tableNames ...string) ([]LiveTableSnapshot, error)
LiveSchemaSnapshot queries the database for all listed tables and returns their live schemas.
func LiveSnapshot ¶
func LiveSnapshot(ctx context.Context, db *sql.DB, d chuck.Dialect, tableName string) (LiveTableSnapshot, error)
LiveSnapshot queries the database and returns the actual schema for a table. The result can be compared against a declared Snapshot() to detect drift.
func (LiveTableSnapshot) String ¶
func (s LiveTableSnapshot) String() string
LiveSnapshotString returns a human-readable representation of a live table schema, in the same format as SnapshotString for easy side-by-side comparison.
type SchemaError ¶
SchemaError describes a single schema validation mismatch.
func ValidateAll ¶
func ValidateAll(ctx context.Context, db *sql.DB, d chuck.Dialect, tables ...*TableDef) []SchemaError
ValidateAll validates multiple table definitions against the live database. Returns all mismatches across all tables, or nil if everything matches.
func ValidateSchema ¶
ValidateSchema compares a declared table definition against the live database and returns all mismatches found. Column names are normalized for the dialect before comparison — e.g. "CreatedAt" becomes "created_at" on Postgres.
Returns nil if the live schema matches the declaration.
func (SchemaError) Error ¶
func (e SchemaError) Error() string
type SeedValues ¶ added in v0.1.10
type SeedValues map[string]interface{}
SeedValues represents a row of seed data as column name to Go value pairs. Supported value types: string, int, int64, float64, bool, nil, and SQLExpr. Values are automatically converted to SQL literals per dialect.
type TableDef ¶
type TableDef struct {
Name string
// contains filtered or unexported fields
}
TableDef defines a table schema.
Example (ColumnLists) ¶
package main
import (
"fmt"
"strings"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
d, _ := chuck.New(chuck.Postgres)
tasks := schema.NewTable("Tasks").
Columns(
schema.AutoIncrCol("ID"),
schema.Col("Title", schema.TypeString(255)).NotNull(),
schema.Col("Done", schema.TypeBool()).NotNull().Default("false"),
).
WithTimestamps()
fmt.Println("Select:", strings.Join(tasks.SelectColumnsFor(d), ", "))
fmt.Println("Insert:", strings.Join(tasks.InsertColumnsFor(d), ", "))
fmt.Println("Update:", strings.Join(tasks.UpdateColumnsFor(d), ", "))
}
Output: Select: id, title, done, created_at, updated_at Insert: title, done, created_at, updated_at Update: title, done, updated_at
func CreationOrder ¶ added in v0.1.10
CreationOrder returns tables sorted so that foreign key dependencies are satisfied: parents appear before children. Self-referential foreign keys (a table referencing itself) are allowed and do not constitute a cycle. Tables with no FK dependencies may appear in any stable order.
func DropOrder ¶ added in v0.1.10
DropOrder returns tables sorted so that children appear before parents, which is the reverse of CreationOrder. This is the safe order for DROP TABLE.
func NewConfigTable ¶
NewConfigTable creates a key-value settings table with a UNIQUE key column and a TEXT value column. Caller provides the table name and column names for flexibility (e.g., "Key"/"Value" or "Name"/"Data").
Example ¶
package main
import (
"fmt"
"strings"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
d, _ := chuck.New(chuck.SQLite)
settings := schema.NewConfigTable("Settings", "Key", "Value")
fmt.Println("Columns:", strings.Join(settings.SelectColumns(), ", "))
fmt.Print(settings.SnapshotString(d))
}
Output: Columns: ID, Key, Value TABLE Settings ID INTEGER PRIMARY KEY AUTOINCREMENT PRIMARY KEY AUTO INCREMENT NOT NULL [immutable] Key TEXT NOT NULL UNIQUE Value TEXT INDEX idx_settings_key ON (Key)
func NewEventTable ¶
NewEventTable creates an append-only event/log table. All columns are immutable (no updates). Includes an auto-increment ID, a timestamp defaulting to NOW(), and caller-defined columns for the event data (e.g., event type, actor, payload).
Example ¶
package main
import (
"fmt"
"strings"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
d, _ := chuck.New(chuck.SQLite)
auditLog := schema.NewEventTable("AuditLog",
schema.Col("EventType", schema.TypeVarchar(50)).NotNull(),
schema.Col("ActorID", schema.TypeInt()).NotNull(),
schema.Col("Payload", schema.TypeJSON()),
)
fmt.Println("Columns:", strings.Join(auditLog.SelectColumns(), ", "))
// All columns are immutable in an event table
fmt.Println("Mutable count:", len(auditLog.UpdateColumns()))
fmt.Print(auditLog.SnapshotString(d))
}
Output: Columns: ID, EventType, ActorID, Payload, CreatedAt Mutable count: 0 TABLE AuditLog ID INTEGER PRIMARY KEY AUTOINCREMENT PRIMARY KEY AUTO INCREMENT NOT NULL [immutable] EventType TEXT NOT NULL [immutable] ActorID INTEGER NOT NULL [immutable] Payload TEXT [immutable] CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP [immutable] INDEX idx_auditlog_createdat ON (CreatedAt)
func NewLookupJoinTable ¶
NewLookupJoinTable creates a many-to-many join table linking an owner table to a lookup table.
Example ¶
package main
import (
"fmt"
"strings"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
d, _ := chuck.New(chuck.SQLite)
taskOptions := schema.NewLookupJoinTable("TaskOptions")
fmt.Println("Columns:", strings.Join(taskOptions.SelectColumns(), ", "))
fmt.Print(taskOptions.SnapshotString(d))
}
Output: Columns: OwnerID, LookupID TABLE TaskOptions OwnerID INTEGER NOT NULL [immutable] LookupID INTEGER NOT NULL [immutable] INDEX idx_taskoptions_ownerid ON (OwnerID) INDEX idx_taskoptions_lookupid ON (LookupID)
func NewLookupTable ¶
NewLookupTable creates a lookup-style table with ID and two caller-named columns. The groupCol categorizes entries (e.g., "Type", "Category") and the valueCol holds the display value (e.g., "Label", "Name"). Indexes are created on groupCol and (groupCol, valueCol).
Example ¶
package main
import (
"fmt"
"strings"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
d, _ := chuck.New(chuck.SQLite)
options := schema.NewLookupTable("Options", "Category", "Label")
fmt.Println("Columns:", strings.Join(options.SelectColumns(), ", "))
fmt.Print(options.SnapshotString(d))
}
Output: Columns: ID, Category, Label TABLE Options ID INTEGER PRIMARY KEY AUTOINCREMENT PRIMARY KEY AUTO INCREMENT NOT NULL [immutable] Category TEXT NOT NULL Label TEXT NOT NULL INDEX idx_options_category ON (Category) INDEX idx_options_category_label ON (Category, Label)
func NewMappingTable ¶
NewMappingTable creates a generic many-to-many join table with caller-defined column names. Both columns are NOT NULL, immutable, and indexed. A composite unique constraint is added to prevent duplicate associations.
Example ¶
package main
import (
"fmt"
"strings"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
d, _ := chuck.New(chuck.SQLite)
userRoles := schema.NewMappingTable("UserRoles", "UserID", "RoleID")
fmt.Println("Columns:", strings.Join(userRoles.SelectColumns(), ", "))
fmt.Println("Insert:", strings.Join(userRoles.InsertColumns(), ", "))
fmt.Print(userRoles.SnapshotString(d))
}
Output: Columns: UserID, RoleID Insert: UserID, RoleID TABLE UserRoles UserID INTEGER NOT NULL [immutable] RoleID INTEGER NOT NULL [immutable] INDEX idx_userroles_userid ON (UserID) INDEX idx_userroles_roleid ON (RoleID) UNIQUE (UserID, RoleID)
func NewQueueTable ¶
NewQueueTable creates a job/outbox queue table with status tracking and retry support. Includes ID, a caller-defined payload column name, Status (default "pending"), RetryCount, ScheduledAt, ProcessedAt, and CreatedAt. Indexes on Status and ScheduledAt for efficient polling.
Example ¶
package main
import (
"fmt"
"strings"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
d, _ := chuck.New(chuck.SQLite)
jobs := schema.NewQueueTable("Jobs", "Payload")
fmt.Println("Columns:", strings.Join(jobs.SelectColumns(), ", "))
fmt.Print(jobs.SnapshotString(d))
}
Output: Columns: ID, Payload, Status, RetryCount, ScheduledAt, ProcessedAt, CreatedAt TABLE Jobs ID INTEGER PRIMARY KEY AUTOINCREMENT PRIMARY KEY AUTO INCREMENT NOT NULL [immutable] Payload TEXT NOT NULL Status TEXT NOT NULL DEFAULT 'pending' RetryCount INTEGER NOT NULL DEFAULT 0 ScheduledAt TIMESTAMP ProcessedAt TIMESTAMP CreatedAt TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP [immutable] INDEX idx_jobs_status ON (Status) INDEX idx_jobs_scheduledat ON (ScheduledAt) INDEX idx_jobs_status_scheduledat ON (Status, ScheduledAt)
func NewTable ¶
NewTable creates a new table definition.
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
tasks := schema.NewTable("Tasks").
Columns(
schema.AutoIncrCol("ID"),
schema.Col("Title", schema.TypeString(255)).NotNull(),
schema.Col("Description", schema.TypeText()),
schema.Col("AssigneeID", schema.TypeInt()).References("Users", "ID").OnDelete("SET NULL"),
).
Indexes(
schema.Index("idx_tasks_title", "Title"),
)
// Snapshot shows the resolved schema for any dialect
d, _ := chuck.New(chuck.SQLite)
fmt.Print(tasks.SnapshotString(d))
}
Output: TABLE Tasks ID INTEGER PRIMARY KEY AUTOINCREMENT PRIMARY KEY AUTO INCREMENT NOT NULL [immutable] Title TEXT NOT NULL Description TEXT AssigneeID INTEGER REFERENCES Users(ID) ON DELETE SET NULL INDEX idx_tasks_title ON (Title)
Example (AllTraits) ¶
package main
import (
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
// Compose every trait on a single table to show the full column set
d, _ := chuck.New(chuck.SQLite)
table := schema.NewTable("FullDemo").
Columns(
schema.AutoIncrCol("ID"),
schema.Col("Title", schema.TypeString(255)).NotNull(),
).
WithTimestamps().
WithSoftDelete().
WithAuditTrail().
WithVersion().
WithStatus("draft").
WithSortOrder().
WithNotes().
WithUUID().
WithParent().
WithReplacement().
WithArchive().
WithExpiry()
fmt.Print(d.Engine(), " columns:\n")
for _, col := range table.SelectColumns() {
fmt.Println(" ", col)
}
}
Output: sqlite3 columns: ID Title CreatedAt UpdatedAt DeletedAt CreatedBy UpdatedBy DeletedBy Version Status SortOrder Notes UUID ParentID ReplacedByID ArchivedAt ExpiresAt
Example (ForeignKeys) ¶
package main
import (
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
pg, _ := chuck.New(chuck.Postgres)
comments := schema.NewTable("Comments").
Columns(
schema.AutoIncrCol("ID"),
schema.Col("TaskID", schema.TypeInt()).NotNull().
References("Tasks", "ID").OnDelete("CASCADE"),
schema.Col("AuthorID", schema.TypeInt()).
References("Users", "ID").OnDelete("SET NULL").OnUpdate("CASCADE"),
schema.Col("Body", schema.TypeText()).NotNull(),
)
fmt.Print(comments.SnapshotString(pg))
}
Output: TABLE comments id SERIAL PRIMARY KEY PRIMARY KEY AUTO INCREMENT NOT NULL [immutable] task_id INTEGER NOT NULL REFERENCES tasks(id) ON DELETE CASCADE author_id INTEGER REFERENCES users(id) ON DELETE SET NULL ON UPDATE CASCADE body TEXT NOT NULL
Example (Traits) ¶
package main
import (
"fmt"
"strings"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
projects := schema.NewTable("Projects").
Columns(
schema.AutoIncrCol("ID"),
schema.Col("Name", schema.TypeString(255)).NotNull(),
).
WithStatus("draft").
WithVersion().
WithSoftDelete().
WithTimestamps().
WithAuditTrail()
// The table knows which columns are mutable vs immutable
fmt.Println("Select:", strings.Join(projects.SelectColumns(), ", "))
fmt.Println("Update:", strings.Join(projects.UpdateColumns(), ", "))
fmt.Println("HasSoftDelete:", projects.HasSoftDelete())
fmt.Println("HasVersion:", projects.HasVersion())
// Postgres normalizes column names to snake_case
pg, _ := chuck.New(chuck.Postgres)
fmt.Println("Postgres select:", strings.Join(projects.SelectColumnsFor(pg), ", "))
}
Output: Select: ID, Name, Status, Version, DeletedAt, CreatedAt, UpdatedAt, CreatedBy, UpdatedBy, DeletedBy Update: Name, Status, Version, DeletedAt, UpdatedAt, UpdatedBy, DeletedBy HasSoftDelete: true HasVersion: true Postgres select: id, name, status, version, deleted_at, created_at, updated_at, created_by, updated_by, deleted_by
Example (UuidPrimaryKey) ¶
package main
import (
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
pg, _ := chuck.New(chuck.Postgres)
tokens := schema.NewTable("Tokens").
Columns(
schema.UUIDPKCol("ID"),
schema.Col("Scope", schema.TypeVarchar(100)).NotNull(),
).
WithExpiry().
WithTimestamps()
snap := tokens.Snapshot(pg)
fmt.Println("Table:", snap.Name)
fmt.Println("PK type:", snap.Columns[0].Type)
fmt.Println("HasExpiry:", snap.HasExpiry)
}
Output: Table: tokens PK type: UUID PRIMARY KEY DEFAULT gen_random_uuid() HasExpiry: true
func (*TableDef) CreateIfNotExistsSQL ¶
CreateIfNotExistsSQL returns CREATE TABLE IF NOT EXISTS followed by CREATE INDEX IF NOT EXISTS statements.
func (*TableDef) CreateSQL ¶
CreateSQL returns the CREATE TABLE statement followed by CREATE INDEX statements.
func (*TableDef) HasArchive ¶
HasArchive reports whether the table uses archive.
func (*TableDef) HasSeedData ¶
HasSeedData reports whether any seed rows have been declared.
func (*TableDef) HasSoftDelete ¶
HasSoftDelete reports whether the table uses soft-delete.
func (*TableDef) HasVersion ¶
HasVersion reports whether the table uses optimistic concurrency control.
func (*TableDef) InsertColumns ¶
InsertColumns returns column names excluding auto-increment columns.
func (*TableDef) InsertColumnsFor ¶
InsertColumnsFor returns column names excluding auto-increment columns, normalized for the given dialect.
func (*TableDef) SeedSQL ¶
SeedSQL returns idempotent INSERT statements for all seed rows using the dialect's InsertOrIgnore method. It includes both raw SeedRow entries and typed SeedValues entries (SeedValues are converted to SQL literals per dialect). Only columns present in the seed row are included — missing columns use their DB defaults.
func (*TableDef) SelectColumns ¶
SelectColumns returns all column names.
func (*TableDef) SelectColumnsFor ¶
SelectColumnsFor returns all column names normalized for the given dialect.
func (*TableDef) Snapshot ¶
func (t *TableDef) Snapshot(d chuck.Dialect) TableSnapshot
Snapshot returns a structured, dialect-resolved representation of the table schema. The output is useful for diffing against a live database or serializing to JSON for CI validation.
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
d, _ := chuck.New(chuck.Postgres)
tasks := schema.NewTable("Tasks").
Columns(
schema.AutoIncrCol("ID"),
schema.Col("Title", schema.TypeString(255)).NotNull(),
).
WithSoftDelete().
WithTimestamps()
fmt.Print(tasks.SnapshotString(d))
}
Output: TABLE tasks id SERIAL PRIMARY KEY PRIMARY KEY AUTO INCREMENT NOT NULL [immutable] title TEXT NOT NULL deleted_at TIMESTAMPTZ created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() [immutable] updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
func (*TableDef) SnapshotString ¶
SnapshotString returns a human-readable, diff-friendly text representation of the table schema resolved for the given dialect. The format is designed for side-by-side comparison with a live database schema.
func (*TableDef) TableNameFor ¶
TableNameFor returns the table name normalized for the given dialect.
func (*TableDef) UniqueColumns ¶
UniqueColumns adds a composite UNIQUE constraint across the given columns.
func (*TableDef) UpdateColumns ¶
UpdateColumns returns only mutable column names.
func (*TableDef) UpdateColumnsFor ¶
UpdateColumnsFor returns only mutable column names, normalized for the given dialect.
func (*TableDef) WithArchive ¶
WithArchive appends a nullable ArchivedAt timestamp column.
func (*TableDef) WithAuditTrail ¶
WithAuditTrail appends CreatedBy, UpdatedBy, and DeletedBy columns.
func (*TableDef) WithExpiry ¶
WithExpiry appends a nullable ExpiresAt timestamp column.
func (*TableDef) WithParent ¶
WithParent appends a nullable ParentID column for tree/hierarchy structures.
func (*TableDef) WithReplacement ¶
WithReplacement appends a nullable ReplacedByID column for entity lineage tracking.
func (*TableDef) WithSeedRows ¶
WithSeedRows declares initial seed data for the table. Each SeedRow maps column names to literal SQL values (strings should be single-quoted).
Example ¶
package main
import (
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
d, _ := chuck.New(chuck.SQLite)
statuses := schema.NewTable("Statuses").
Columns(
schema.AutoIncrCol("ID"),
schema.Col("Name", schema.TypeVarchar(50)).NotNull().Unique(),
).
WithSeedRows(
schema.SeedRow{"Name": "'active'"},
schema.SeedRow{"Name": "'archived'"},
schema.SeedRow{"Name": "'deleted'"},
)
fmt.Println("HasSeedData:", statuses.HasSeedData())
fmt.Println("SeedRows:", len(statuses.SeedRows()))
for _, stmt := range statuses.SeedSQL(d) {
fmt.Println(stmt)
}
}
Output: HasSeedData: true SeedRows: 3 INSERT OR IGNORE INTO "Statuses" (Name) VALUES ('active') INSERT OR IGNORE INTO "Statuses" (Name) VALUES ('archived') INSERT OR IGNORE INTO "Statuses" (Name) VALUES ('deleted')
Example (Postgres) ¶
package main
import (
"fmt"
"github.com/catgoose/chuck"
"github.com/catgoose/chuck/schema"
)
func main() {
d, _ := chuck.New(chuck.Postgres)
roles := schema.NewTable("Roles").
Columns(
schema.AutoIncrCol("ID"),
schema.Col("Name", schema.TypeVarchar(50)).NotNull().Unique(),
schema.Col("Description", schema.TypeText()),
).
WithSeedRows(
schema.SeedRow{"Name": "'admin'", "Description": "'Full access'"},
schema.SeedRow{"Name": "'viewer'", "Description": "'Read-only access'"},
)
for _, stmt := range roles.SeedSQL(d) {
fmt.Println(stmt)
}
}
Output: INSERT INTO "roles" (name, description) VALUES ('admin', 'Full access') ON CONFLICT DO NOTHING INSERT INTO "roles" (name, description) VALUES ('viewer', 'Read-only access') ON CONFLICT DO NOTHING
func (*TableDef) WithSeedValues ¶ added in v0.1.10
func (t *TableDef) WithSeedValues(rows ...SeedValues) *TableDef
WithSeedValues declares initial seed data using Go values instead of SQL literals. Values are automatically quoted per dialect when SeedSQL is called.
func (*TableDef) WithSoftDelete ¶
WithSoftDelete appends a DeletedAt column and marks the table for soft-delete.
func (*TableDef) WithSortOrder ¶
WithSortOrder appends a SortOrder column for manual ordering.
func (*TableDef) WithStatus ¶
WithStatus appends a Status column with the given default value.
func (*TableDef) WithTimestamps ¶
WithTimestamps appends CreatedAt and UpdatedAt columns.
func (*TableDef) WithVersion ¶
WithVersion appends a Version column for optimistic concurrency control.
type TableSnapshot ¶
type TableSnapshot struct {
Name string `json:"name"`
Columns []ColumnSnapshot `json:"columns"`
Indexes []IndexSnapshot `json:"indexes,omitempty"`
UniqueConstraints [][]string `json:"unique_constraints,omitempty"`
HasSoftDelete bool `json:"has_soft_delete,omitempty"`
HasVersion bool `json:"has_version,omitempty"`
HasExpiry bool `json:"has_expiry,omitempty"`
HasArchive bool `json:"has_archive,omitempty"`
}
TableSnapshot describes a table's full resolved schema for a given dialect.
func SchemaSnapshot ¶
func SchemaSnapshot(d chuck.Dialect, tables ...*TableDef) []TableSnapshot
SchemaSnapshot returns snapshots for multiple tables, useful for dumping the entire declared schema for comparison or CI validation.
type TypeFunc ¶
TypeFunc resolves a column type for a given dialect.
func TypeAutoIncrement ¶
func TypeAutoIncrement() TypeFunc
TypeAutoIncrement returns a TypeFunc for an auto-incrementing primary key column.
func TypeBigInt ¶
func TypeBigInt() TypeFunc
TypeBigInt returns a TypeFunc for a 64-bit integer column.
func TypeDecimal ¶
TypeDecimal returns a TypeFunc for an exact numeric column with precision and scale.
func TypeFloat ¶
func TypeFloat() TypeFunc
TypeFloat returns a TypeFunc for a floating-point column.
func TypeLiteral ¶
TypeLiteral returns a TypeFunc that always returns the given literal string.
func TypeString ¶
TypeString returns a TypeFunc for a string column with the given max length.
func TypeTimestamp ¶
func TypeTimestamp() TypeFunc
TypeTimestamp returns a TypeFunc for a timestamp column.
func TypeUUIDPK ¶
func TypeUUIDPK() TypeFunc
TypeUUIDPK returns a TypeFunc for a UUID primary key column. This embeds PRIMARY KEY in the type definition, similar to TypeAutoIncrement.
func TypeVarchar ¶
TypeVarchar returns a TypeFunc for a varchar column with the given max length.
type UniqueConstraint ¶
type UniqueConstraint struct {
// contains filtered or unexported fields
}
UniqueConstraint defines a composite UNIQUE constraint across multiple columns.