schema

package
v0.1.4 Latest Latest
Warning

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

Go to latest
Published: Apr 3, 2026 License: MIT Imports: 5 Imported by: 0

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

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func SchemaSnapshotString

func SchemaSnapshotString(d chuck.Dialect, tables ...*TableDef) string

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

func AutoIncrCol(name string) ColumnDef

AutoIncrCol creates an auto-incrementing primary key column (immutable).

func Col

func Col(name string, typeFn TypeFunc) ColumnDef

Col creates a new column definition. By default columns are nullable and mutable.

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

func StatusColumnDefs(defaultStatus string) []ColumnDef

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

func UUIDPKCol(name string) ColumnDef

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) Default

func (c ColumnDef) Default(expr string) ColumnDef

Default sets a literal DEFAULT expression (e.g. "'active'").

func (ColumnDef) DefaultFn

func (c ColumnDef) DefaultFn(fn func(chuck.Dialect) string) ColumnDef

DefaultFn sets a dialect-aware DEFAULT expression (e.g. d.Now()).

func (ColumnDef) Immutable

func (c ColumnDef) Immutable() ColumnDef

Immutable marks the column as immutable (excluded from UPDATE column lists).

func (ColumnDef) Mutable

func (c ColumnDef) Mutable() ColumnDef

Mutable marks the column as mutable (included in UPDATE column lists).

func (ColumnDef) Name

func (c ColumnDef) Name() string

Name returns the column name.

func (ColumnDef) NotNull

func (c ColumnDef) NotNull() ColumnDef

NotNull marks the column as NOT NULL.

func (ColumnDef) OnDelete

func (c ColumnDef) OnDelete(action string) ColumnDef

OnDelete sets the referential action for DELETE (e.g. "CASCADE", "SET NULL").

func (ColumnDef) OnUpdate

func (c ColumnDef) OnUpdate(action string) ColumnDef

OnUpdate sets the referential action for UPDATE (e.g. "CASCADE", "SET NULL").

func (ColumnDef) PrimaryKey

func (c ColumnDef) PrimaryKey() ColumnDef

PrimaryKey marks the column as a primary key.

func (ColumnDef) References

func (c ColumnDef) References(table, column string) ColumnDef

References adds a foreign key reference to another table's column.

func (ColumnDef) Unique

func (c ColumnDef) Unique() ColumnDef

Unique marks the column with a UNIQUE constraint.

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"`
}

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 Index

func Index(name, columns string) IndexDef

Index creates a new index definition.

type IndexSnapshot

type IndexSnapshot struct {
	Name    string `json:"name"`
	Columns string `json:"columns"`
}

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

type LiveIndexSnapshot struct {
	Name    string `json:"name"`
	Columns string `json:"columns"`
}

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

type SchemaError struct {
	Table   string
	Column  string
	Message string
}

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

func ValidateSchema(ctx context.Context, db *sql.DB, d chuck.Dialect, td *TableDef) []SchemaError

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 SeedRow

type SeedRow map[string]string

SeedRow represents a row of seed data as column name → value pairs.

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 NewConfigTable

func NewConfigTable(name, keyCol, valueCol string) *TableDef

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

func NewEventTable(name string, cols ...ColumnDef) *TableDef

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

func NewLookupJoinTable(name string) *TableDef

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

func NewLookupTable(name, groupCol, valueCol string) *TableDef

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

func NewMappingTable(name, leftCol, rightCol string) *TableDef

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

func NewQueueTable(name, payloadCol string) *TableDef

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

func NewTable(name string) *TableDef

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) Columns

func (t *TableDef) Columns(cols ...ColumnDef) *TableDef

Columns appends column definitions.

func (*TableDef) CreateIfNotExistsSQL

func (t *TableDef) CreateIfNotExistsSQL(d chuck.Dialect) []string

CreateIfNotExistsSQL returns CREATE TABLE IF NOT EXISTS followed by CREATE INDEX IF NOT EXISTS statements.

func (*TableDef) CreateSQL

func (t *TableDef) CreateSQL(d chuck.Dialect) []string

CreateSQL returns the CREATE TABLE statement followed by CREATE INDEX statements.

func (*TableDef) DropSQL

func (t *TableDef) DropSQL(d chuck.Dialect) string

DropSQL returns the DROP TABLE statement for the given dialect.

func (*TableDef) HasArchive

func (t *TableDef) HasArchive() bool

HasArchive reports whether the table uses archive.

func (*TableDef) HasExpiry

func (t *TableDef) HasExpiry() bool

HasExpiry reports whether the table uses expiry.

func (*TableDef) HasSeedData

func (t *TableDef) HasSeedData() bool

HasSeedData reports whether any seed rows have been declared.

func (*TableDef) HasSoftDelete

func (t *TableDef) HasSoftDelete() bool

HasSoftDelete reports whether the table uses soft-delete.

func (*TableDef) HasVersion

func (t *TableDef) HasVersion() bool

HasVersion reports whether the table uses optimistic concurrency control.

func (*TableDef) Indexes

func (t *TableDef) Indexes(indexes ...IndexDef) *TableDef

Indexes appends index definitions.

func (*TableDef) InsertColumns

func (t *TableDef) InsertColumns() []string

InsertColumns returns column names excluding auto-increment columns.

func (*TableDef) InsertColumnsFor

func (t *TableDef) InsertColumnsFor(d chuck.Dialect) []string

InsertColumnsFor returns column names excluding auto-increment columns, normalized for the given dialect.

func (*TableDef) SeedRows

func (t *TableDef) SeedRows() []SeedRow

SeedRows returns the declared seed data.

func (*TableDef) SeedSQL

func (t *TableDef) SeedSQL(d chuck.Dialect) []string

SeedSQL returns idempotent INSERT statements for all seed rows using the dialect's InsertOrIgnore method. Only columns present in the SeedRow are included — missing columns use their DB defaults.

func (*TableDef) SelectColumns

func (t *TableDef) SelectColumns() []string

SelectColumns returns all column names.

func (*TableDef) SelectColumnsFor

func (t *TableDef) SelectColumnsFor(d chuck.Dialect) []string

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

func (t *TableDef) SnapshotString(d chuck.Dialect) string

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

func (t *TableDef) TableNameFor(d chuck.Dialect) string

TableNameFor returns the table name normalized for the given dialect.

func (*TableDef) UniqueColumns

func (t *TableDef) UniqueColumns(columns ...string) *TableDef

UniqueColumns adds a composite UNIQUE constraint across the given columns.

func (*TableDef) UpdateColumns

func (t *TableDef) UpdateColumns() []string

UpdateColumns returns only mutable column names.

func (*TableDef) UpdateColumnsFor

func (t *TableDef) UpdateColumnsFor(d chuck.Dialect) []string

UpdateColumnsFor returns only mutable column names, normalized for the given dialect.

func (*TableDef) WithArchive

func (t *TableDef) WithArchive() *TableDef

WithArchive appends a nullable ArchivedAt timestamp column.

func (*TableDef) WithAuditTrail

func (t *TableDef) WithAuditTrail() *TableDef

WithAuditTrail appends CreatedBy, UpdatedBy, and DeletedBy columns.

func (*TableDef) WithExpiry

func (t *TableDef) WithExpiry() *TableDef

WithExpiry appends a nullable ExpiresAt timestamp column.

func (*TableDef) WithNotes

func (t *TableDef) WithNotes() *TableDef

WithNotes appends a nullable Notes text column.

func (*TableDef) WithParent

func (t *TableDef) WithParent() *TableDef

WithParent appends a nullable ParentID column for tree/hierarchy structures.

func (*TableDef) WithReplacement

func (t *TableDef) WithReplacement() *TableDef

WithReplacement appends a nullable ReplacedByID column for entity lineage tracking.

func (*TableDef) WithSeedRows

func (t *TableDef) WithSeedRows(rows ...SeedRow) *TableDef

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) WithSoftDelete

func (t *TableDef) WithSoftDelete() *TableDef

WithSoftDelete appends a DeletedAt column and marks the table for soft-delete.

func (*TableDef) WithSortOrder

func (t *TableDef) WithSortOrder() *TableDef

WithSortOrder appends a SortOrder column for manual ordering.

func (*TableDef) WithStatus

func (t *TableDef) WithStatus(defaultStatus string) *TableDef

WithStatus appends a Status column with the given default value.

func (*TableDef) WithTimestamps

func (t *TableDef) WithTimestamps() *TableDef

WithTimestamps appends CreatedAt and UpdatedAt columns.

func (*TableDef) WithUUID

func (t *TableDef) WithUUID() *TableDef

WithUUID appends a UUID column (NOT NULL, UNIQUE, immutable).

func (*TableDef) WithVersion

func (t *TableDef) WithVersion() *TableDef

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

type TypeFunc func(chuck.Dialect) string

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 TypeBool

func TypeBool() TypeFunc

TypeBool returns a TypeFunc for a boolean column.

func TypeDecimal

func TypeDecimal(precision, scale int) TypeFunc

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 TypeInt

func TypeInt() TypeFunc

TypeInt returns a TypeFunc for an integer column.

func TypeJSON

func TypeJSON() TypeFunc

TypeJSON returns a TypeFunc for a JSON column.

func TypeLiteral

func TypeLiteral(s string) TypeFunc

TypeLiteral returns a TypeFunc that always returns the given literal string.

func TypeString

func TypeString(n int) TypeFunc

TypeString returns a TypeFunc for a string column with the given max length.

func TypeText

func TypeText() TypeFunc

TypeText returns a TypeFunc for an unlimited text column.

func TypeTimestamp

func TypeTimestamp() TypeFunc

TypeTimestamp returns a TypeFunc for a timestamp column.

func TypeUUID

func TypeUUID() TypeFunc

TypeUUID returns a TypeFunc for a UUID 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

func TypeVarchar(n int) TypeFunc

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.

Jump to

Keyboard shortcuts

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