sqlite

package
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Jul 14, 2026 License: MIT Imports: 13 Imported by: 0

Documentation

Overview

Package sqlite is the SQLite dialect for drops. It mirrors drops/pg's API surface — Table / Column / DB / DDL / query builders — over the same swappable drops.Driver connector, but emits SQLite-flavoured SQL: "?" placeholders, SQLite type affinities, and constraints declared inline in CREATE TABLE (SQLite has no ALTER TABLE ADD CONSTRAINT).

Because both pg and sqlite build on drops.Dialect, pointing the same schema at SQLite instead of PostgreSQL is a matter of swapping the package (and the underlying driver) — the builder chain is otherwise identical.

Index

Constants

View Source
const DefaultMigrationsTable = "_drops_sqlite_migrations"

DefaultMigrationsTable is the table used to track applied migrations when no override is set on the Migrator.

Variables

View Source
var (
	// ErrNoRows is returned by ScanOne when the result set is empty.
	ErrNoRows = errors.New("drops/sqlite: no rows in result set")

	// ErrNoRowsToInsert is returned when an INSERT has no rows to write.
	ErrNoRowsToInsert = errors.New("drops/sqlite: INSERT with no rows")

	// ErrInvalidIdentifier is returned (or panicked, at declaration
	// time) for an identifier that cannot be safely quoted.
	ErrInvalidIdentifier = errors.New("drops/sqlite: invalid identifier")
)

Sentinel errors for assertable failure modes. They mirror drops/pg's error surface so code that switches dialects keeps the same errors.Is checks.

View Source
var Dialect drops.Dialect = sqliteDialect{}

Dialect is the SQLite dialect value. Pass it to drops.WithDialect (or rely on the sqlite.DB, which installs it on every builder).

View Source
var ErrNoMigrationsApplied = errors.New("drops/sqlite: no migrations applied")

ErrNoMigrationsApplied is returned by Down when the history table is empty.

View Source
var Placeholder = drops.WithDialect(Dialect)

Placeholder is the SQLite placeholder BuilderOption, provided for symmetry with clickhouse.Placeholder. Prefer drops.WithDialect(Dialect).

Functions

func And

func And(preds ...drops.Expression) drops.Expression

And / Or combine predicates.

func CreateIndex

func CreateIndex(name string, t *Table, cols ...ColRef) drops.Expression

CreateIndex returns a CREATE INDEX statement over the given columns.

func CreateIndexIfNotExists

func CreateIndexIfNotExists(name string, t *Table, cols ...ColRef) drops.Expression

CreateIndexIfNotExists is the IF NOT EXISTS variant of CreateIndex.

func CreateTable

func CreateTable(t *Table) drops.Expression

CreateTable returns a CREATE TABLE statement for t.

Unlike PostgreSQL, SQLite cannot add constraints after the fact (there is no ALTER TABLE ADD CONSTRAINT), so EVERY constraint — composite primary key, UNIQUE, CHECK and single- or multi-column foreign key — is emitted inline inside the CREATE TABLE body. This is the deliberate dialect difference from drops/pg, whose migration generator emits those as separate ALTER statements.

func CreateTableIfNotExists

func CreateTableIfNotExists(t *Table) drops.Expression

CreateTableIfNotExists is the IF NOT EXISTS variant.

func CreateUniqueIndex

func CreateUniqueIndex(name string, t *Table, cols ...ColRef) drops.Expression

CreateUniqueIndex returns a CREATE UNIQUE INDEX statement.

func Diff

func Diff(prev, cur *Snapshot) []string

Diff returns the ordered list of SQL statements (and inline comments) that evolve a SQLite database from prev's schema to cur's. Output is deterministic for a given (prev, cur): every map is walked in sorted key order.

SQLite has no ALTER TABLE ADD CONSTRAINT and no ALTER COLUMN, so the rules differ sharply from drops/pg:

  • New table → a full CREATE TABLE with every constraint (composite PK, UNIQUE, CHECK, single- and multi-column FK) rendered INLINE.
  • Dropped table → DROP TABLE.
  • Added column that is nullable or has a default (and is not PRIMARY KEY / UNIQUE / a foreign key) → ALTER TABLE ADD COLUMN, which SQLite does support.
  • Dropped column, a column whose type / NOT NULL / default / PK / autoincrement changed, an added column that ALTER cannot add, or any table-level constraint change → the standard SQLite table-rebuild sequence: create "t_new" with the new shape, copy the shared columns across with INSERT … SELECT, DROP the old table and RENAME "t_new" into place. The sequence is prefixed by a `-- rebuild "t": <reason>` comment.

Operation order:

  1. DROP TABLE for tables removed entirely
  2. CREATE TABLE for new tables (all constraints inline)
  3. per surviving table: ADD COLUMN statements, or a rebuild sequence

func DiffDown

func DiffDown(prev, cur *Snapshot) []string

DiffDown returns the SQL that reverses the migration from cur back to prev — applying these statements after the corresponding Diff(prev, cur) restores the original schema. It is simply Diff(cur, prev).

func DropIndex

func DropIndex(name string) drops.Expression

DropIndex returns DROP INDEX name.

func DropIndexIfExists

func DropIndexIfExists(name string) drops.Expression

DropIndexIfExists is the IF EXISTS variant.

func DropTable

func DropTable(t *Table) drops.Expression

DropTable returns DROP TABLE t.

func DropTableIfExists

func DropTableIfExists(t *Table) drops.Expression

DropTableIfExists is the IF EXISTS variant.

func OnDelete

func OnDelete(action string) func(*FK)

OnDelete / OnUpdate configure the referential actions on a FK.

func OnUpdate

func OnUpdate(action string) func(*FK)

func Or

func Or(preds ...drops.Expression) drops.Expression

func ParseMigrationName

func ParseMigrationName(filename string) (version, name, kind string, ok bool)

ParseMigrationName recognises "<version>_<name>.{up,down}.sql" and returns the version, name and kind ("up" or "down"). It is exposed so callers can validate filenames before adding them.

func ToSQL

func ToSQL(e drops.Expression) (sql string, args []any)

ToSQL renders e with the SQLite dialect. Exposed for tests and logging (mirrors clickhouse.ToSQL).

Types

type CheckSnapshot

type CheckSnapshot struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

CheckSnapshot is one entry in TableSnapshot.CheckConstraints. Value is the SQL expression inside CHECK (...).

type Col

type Col[T any] struct{ *Column }

Col is the typed column handle whose Go value type is T.

func Add

func Add[T any](t *Table, c *Col[T]) *Col[T]

Add registers c on t and returns the same typed handle, so callers keep the *Col[T] for use in queries:

id := sqlite.Add(users, sqlite.Integer("id").PrimaryKey())

func BigInt

func BigInt(name string) *Col[int64]

func BigSerial

func BigSerial(name string) *Col[int64]

func Blob

func Blob(name string) *Col[[]byte]

Blob / Bytea are BLOB columns (Bytea is the PostgreSQL-parity alias).

func Boolean

func Boolean(name string) *Col[bool]

Boolean is stored as INTEGER 0/1; declared as BOOLEAN for readability.

func Bytea

func Bytea(name string) *Col[[]byte]

func Char

func Char(name string, _ int) *Col[string]

Char maps to TEXT (see Varchar).

func Custom

func Custom[T any](name, typeSQL string) *Col[T]

Custom declares a column with a caller-supplied declared type.

func Date

func Date(name string) *Col[time.Time]

Date / Time / Timestamp map to SQLite's date-time storage (TEXT affinity via the DATE/TIME/DATETIME declared types).

func DoublePrecision

func DoublePrecision(name string) *Col[float64]

func Integer

func Integer(name string) *Col[int32]

func JSON

func JSON(name string) *Col[json.RawMessage]

JSON / JSONB are stored as TEXT (SQLite's JSON1 functions operate on TEXT). JSONB is an alias for parity with PostgreSQL.

func JSONB

func JSONB(name string) *Col[json.RawMessage]

func Numeric

func Numeric(name string, _, _ int) *Col[string]

Numeric maps to NUMERIC affinity. Precision/scale are accepted for parity but SQLite does not enforce them.

func Real

func Real(name string) *Col[float32]

Real / DoublePrecision map to REAL affinity.

func Serial

func Serial(name string) *Col[int32]

Serial / BigSerial map to INTEGER. Auto-increment in SQLite is a property of an INTEGER PRIMARY KEY (add .PrimaryKey(), and optionally .AutoIncrement() for the strict monotonic ROWID), not a distinct column type as in PostgreSQL.

func SmallInt

func SmallInt(name string) *Col[int16]

Integer family — all map to INTEGER affinity.

func Text

func Text(name string) *Col[string]

Text is a TEXT column.

func Time

func Time(name string) *Col[time.Time]

func Timestamp

func Timestamp(name string, _ bool) *Col[time.Time]

Timestamp maps to DATETIME. withTimeZone is accepted for parity; SQLite has no zoned type — store UTC and convert in application code.

func UUID

func UUID(name string) *Col[string]

UUID is stored as TEXT.

func Varchar

func Varchar(name string, _ int) *Col[string]

Varchar maps to TEXT — SQLite does not enforce length, but the length is accepted for schema parity with PostgreSQL.

func (*Col[T]) AutoIncrement

func (c *Col[T]) AutoIncrement() *Col[T]

AutoIncrement marks an INTEGER PRIMARY KEY as AUTOINCREMENT. SQLite only permits AUTOINCREMENT on an INTEGER PRIMARY KEY.

func (*Col[T]) Default

func (c *Col[T]) Default(sqlExpr string) *Col[T]

Default sets a raw SQL default expression (e.g. "0", "CURRENT_TIMESTAMP").

func (*Col[T]) Eq

func (c *Col[T]) Eq(v T) drops.Expression

Comparison operators — the rendered SQL is dialect-agnostic (the placeholder and quoting come from the Builder's dialect).

func (*Col[T]) EqCol

func (c *Col[T]) EqCol(other ColRef) drops.Expression

EqCol compares two columns.

func (*Col[T]) Gt

func (c *Col[T]) Gt(v T) drops.Expression

func (*Col[T]) Gte

func (c *Col[T]) Gte(v T) drops.Expression

func (*Col[T]) In

func (c *Col[T]) In(values ...T) drops.Expression

In renders (col IN (?, ?, ...)). Empty renders "(0)" (never matches).

func (*Col[T]) IsNotNull

func (c *Col[T]) IsNotNull() drops.Expression

func (*Col[T]) IsNull

func (c *Col[T]) IsNull() drops.Expression

IsNull / IsNotNull.

func (*Col[T]) Lt

func (c *Col[T]) Lt(v T) drops.Expression

func (*Col[T]) Lte

func (c *Col[T]) Lte(v T) drops.Expression

func (*Col[T]) Ne

func (c *Col[T]) Ne(v T) drops.Expression

func (*Col[T]) NotNull

func (c *Col[T]) NotNull() *Col[T]

NotNull marks the column NOT NULL.

func (*Col[T]) PrimaryKey

func (c *Col[T]) PrimaryKey() *Col[T]

PrimaryKey marks the column as the (single-column) PRIMARY KEY.

func (*Col[T]) References

func (c *Col[T]) References(target *Col[T], opts ...func(*FK)) *Col[T]

References declares a single-column foreign key to target.

func (*Col[T]) Unique

func (c *Col[T]) Unique() *Col[T]

Unique marks the column UNIQUE.

func (*Col[T]) Val

func (c *Col[T]) Val(v T) ColumnValue

Val binds a typed value for INSERT/UPDATE.

type ColRef

type ColRef interface {
	drops.Expression
	// contains filtered or unexported methods
}

ColRef is implemented by *Column and *Col[T]: a type-erased column reference for APIs that don't depend on the Go value type.

type Column

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

Column is the type-erased column AST node. Most user code holds a *Col[T]; the untyped Column lets table column lists be heterogeneous.

func (*Column) DefaultSQL

func (c *Column) DefaultSQL() string

func (*Column) ForeignKey

func (c *Column) ForeignKey() *FK

func (*Column) HasDefault

func (c *Column) HasDefault() bool

func (*Column) IsAutoIncrement

func (c *Column) IsAutoIncrement() bool

func (*Column) IsNotNull

func (c *Column) IsNotNull() bool

func (*Column) IsPrimaryKey

func (c *Column) IsPrimaryKey() bool

func (*Column) IsUnique

func (c *Column) IsUnique() bool

func (*Column) Name

func (c *Column) Name() string

func (*Column) Table

func (c *Column) Table() *Table

func (*Column) Type

func (c *Column) Type() ColumnType

func (*Column) WriteSQL

func (c *Column) WriteSQL(b *drops.Builder)

WriteSQL writes a table-qualified column reference. The dialect on the Builder controls the quote character.

type ColumnSnapshot

type ColumnSnapshot struct {
	Name          string  `json:"name"`
	Type          string  `json:"type"`
	PrimaryKey    bool    `json:"primaryKey"`
	NotNull       bool    `json:"notNull"`
	Unique        bool    `json:"unique"`
	AutoIncrement bool    `json:"autoincrement"`
	Default       *string `json:"default,omitempty"`
}

ColumnSnapshot is one entry in TableSnapshot.Columns. Type is the SQLite affinity keyword. Unique / PrimaryKey record single-column constraints that render inline in CREATE TABLE; AutoIncrement is only meaningful on an INTEGER PRIMARY KEY.

type ColumnType

type ColumnType interface{ TypeSQL() string }

ColumnType describes the SQL type of a column as it appears in CREATE TABLE — e.g. "INTEGER", "TEXT", "REAL", "BLOB", "NUMERIC".

type ColumnValue

type ColumnValue interface {
	// contains filtered or unexported methods
}

ColumnValue is a column bound to a value for INSERT/UPDATE.

type CompositeFK

type CompositeFK struct {
	Name          string
	Columns       []*Column
	Target        *Table
	TargetColumns []*Column
	OnDelete      string
	OnUpdate      string
}

CompositeFK is a multi-column foreign key: FOREIGN KEY (Columns...) REFERENCES Target (TargetColumns...).

type CompositePKSnapshot

type CompositePKSnapshot struct {
	Name    string   `json:"name"`
	Columns []string `json:"columns"`
}

CompositePKSnapshot is one entry in TableSnapshot.CompositePrimaryKeys.

type DB

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

DB is the entry point for issuing SQLite queries through a drops.Driver. Any driver — database/sql with mattn/go-sqlite3 or modernc.org/sqlite, or a custom connection — can back it.

It offers the same Hook / Ping / Close / InTx / Select / Insert / Update / Delete contract as drops/pg's DB, so switching a codebase from PostgreSQL to SQLite is largely a matter of swapping the constructor. Every builder it returns renders SQLite syntax ("?" placeholders) via the shared drops.Dialect.

Safe for concurrent use by multiple goroutines provided the underlying Driver is; builders are not — create one per query.

func New

func New(drv drops.Driver) *DB

New wraps a drops.Driver as a SQLite DB.

func (*DB) Begin

func (db *DB) Begin(ctx context.Context) (*DB, drops.Tx, error)

Begin opens a transaction and returns a DB bound to it plus the raw Tx. Prefer InTx for automatic commit/rollback.

func (*DB) Close

func (db *DB) Close() error

Close releases the underlying driver if it implements io.Closer.

func (*DB) Delete

func (db *DB) Delete(t *Table) *DeleteBuilder

Delete begins a DELETE FROM <t>.

func (*DB) Driver

func (db *DB) Driver() drops.Driver

Driver returns the underlying driver.

func (*DB) Exec

func (db *DB) Exec(ctx context.Context, sql string, args ...any) (drops.Result, error)

Exec runs a raw SQL statement. Placeholders are SQLite "?" markers.

func (*DB) ExecExpr

func (db *DB) ExecExpr(ctx context.Context, e drops.Expression) (drops.Result, error)

ExecExpr renders e with the SQLite dialect and runs it. Convenience for DDL helpers like CreateTable.

func (*DB) Find

func (db *DB) Find(t *Table) *FindBuilder

Find begins a relational query against t. The result type passed to All/One determines which columns are scanned (via the same struct-field mapping rules as Select.All).

func (*DB) Hook

func (db *DB) Hook() drops.Hook

Hook returns the currently attached hook, or nil.

func (*DB) InTx

func (db *DB) InTx(ctx context.Context, fn func(*DB) error) (err error)

InTx runs fn inside a transaction, committing on nil and rolling back otherwise (including on panic, which is re-raised). Rollback uses a detached, short-timeout context so a cancelled caller-ctx can't block cleanup.

func (*DB) Insert

func (db *DB) Insert(t *Table) *InsertBuilder

Insert begins an INSERT INTO <t>.

func (*DB) Ping

func (db *DB) Ping(ctx context.Context) error

Ping verifies the connection with SELECT 1.

func (*DB) Query

func (db *DB) Query(ctx context.Context, sql string, args ...any) (drops.Rows, error)

Query runs a raw SQL query.

func (*DB) Select

func (db *DB) Select(cols ...drops.Expression) *SelectBuilder

Select begins a SELECT. With no columns the projection is "*".

func (*DB) Update

func (db *DB) Update(t *Table) *UpdateBuilder

Update begins an UPDATE <t>.

func (*DB) WithHook

func (db *DB) WithHook(hook drops.Hook) *DB

WithHook returns a shallow copy with hook installed; nil removes it.

type DeleteBuilder

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

DeleteBuilder builds a DELETE statement. Create one via DB.Delete.

func (*DeleteBuilder) Exec

func (d *DeleteBuilder) Exec(ctx context.Context) (drops.Result, error)

Exec runs the DELETE.

func (*DeleteBuilder) ToSQL

func (d *DeleteBuilder) ToSQL() (sql string, args []any)

ToSQL renders the statement with SQLite placeholders.

func (*DeleteBuilder) Where

func (d *DeleteBuilder) Where(preds ...drops.Expression) *DeleteBuilder

Where AND-s the given predicates onto the statement. A DELETE with no WHERE removes every row — that is intentional but rarely desired.

func (*DeleteBuilder) WriteSQL

func (d *DeleteBuilder) WriteSQL(b *drops.Builder)

WriteSQL implements drops.Expression.

type Entity

type Entity[T any] struct {
	// contains filtered or unexported fields
}

Entity is the typed CRUD layer over a Table, mirroring drops/pg's Entity[T]. It precomputes the column↔struct-field mapping for T and offers Get / Create / Update / Delete plus a fluent Query. T must be a struct with a field bound to each column (by `drop:"col"` tag, or by field name / camelCase), and the table must have a single-column primary key.

func NewEntity

func NewEntity[T any](t *Table) *Entity[T]

NewEntity builds the entity, panicking on misconfiguration (schemas are declared at startup, so bad config should fail loudly there).

func (*Entity[T]) Create

func (e *Entity[T]) Create(db *DB, ctx context.Context, r *T) error

Create inserts r.

func (*Entity[T]) Delete

func (e *Entity[T]) Delete(db *DB, ctx context.Context, id any) (drops.Result, error)

Delete removes the row whose primary key equals id.

func (*Entity[T]) Get

func (e *Entity[T]) Get(db *DB, ctx context.Context, id any) (T, error)

Get fetches the row whose primary key equals id, returning ErrNoRows if absent.

func (*Entity[T]) PK

func (e *Entity[T]) PK() *Column

PK returns the primary-key column.

func (*Entity[T]) Query

func (e *Entity[T]) Query(db *DB) *EntityQuery[T]

Query begins a fluent, entity-typed query.

func (*Entity[T]) Table

func (e *Entity[T]) Table() *Table

Table returns the entity's table.

func (*Entity[T]) Update

func (e *Entity[T]) Update(db *DB, ctx context.Context, r *T) error

Update writes every non-PK column of r, matched by primary key.

type EntityQuery

type EntityQuery[T any] struct {
	// contains filtered or unexported fields
}

EntityQuery is a typed wrapper over SelectBuilder that returns []T / T.

func (*EntityQuery[T]) All

func (q *EntityQuery[T]) All(ctx context.Context) ([]T, error)

All executes and returns every matching row.

func (*EntityQuery[T]) Limit

func (q *EntityQuery[T]) Limit(n int64) *EntityQuery[T]

Limit / Offset bound the result window.

func (*EntityQuery[T]) Offset

func (q *EntityQuery[T]) Offset(n int64) *EntityQuery[T]

func (*EntityQuery[T]) One

func (q *EntityQuery[T]) One(ctx context.Context) (T, error)

One executes and returns the first row, or ErrNoRows.

func (*EntityQuery[T]) OrderBy

func (q *EntityQuery[T]) OrderBy(exprs ...drops.Expression) *EntityQuery[T]

OrderBy sets ORDER BY expressions.

func (*EntityQuery[T]) Where

func (q *EntityQuery[T]) Where(preds ...drops.Expression) *EntityQuery[T]

Where AND-s predicates onto the query.

type FK

type FK struct {
	Target   *Column
	OnDelete string
	OnUpdate string
}

FK describes a single-column foreign-key reference.

type FindBuilder

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

FindBuilder composes a root SELECT and (optionally) eager-loads relations declared via NewRelations. It mirrors a subset of SelectBuilder's API — Where, OrderBy, Limit, Offset — and adds With for relations.

Each requested relation costs exactly one extra batched query (an IN (...) over the collected parent keys), so eager loading never degrades into N+1.

func (*FindBuilder) All

func (f *FindBuilder) All(ctx context.Context, dest any) error

All runs the find and populates dest, which must be *[]Struct or *[]*Struct. Each requested relation is loaded with a single follow-up query and stitched onto the matching dropRel-tagged field of every parent.

func (*FindBuilder) Limit

func (f *FindBuilder) Limit(n int64) *FindBuilder

Limit sets the LIMIT on the root query.

func (*FindBuilder) Offset

func (f *FindBuilder) Offset(n int64) *FindBuilder

Offset sets the OFFSET on the root query.

func (*FindBuilder) One

func (f *FindBuilder) One(ctx context.Context, dest any) error

One runs the find and populates dest, a pointer to a struct. Returns ErrNoRows when no row matches.

func (*FindBuilder) OrderBy

func (f *FindBuilder) OrderBy(exprs ...drops.Expression) *FindBuilder

OrderBy appends ORDER BY expressions to the root query.

func (*FindBuilder) Where

func (f *FindBuilder) Where(preds ...drops.Expression) *FindBuilder

Where appends predicates joined by AND to the root query.

func (*FindBuilder) With

func (f *FindBuilder) With(names ...string) *FindBuilder

With marks one or more relations to eager-load. Names must match relations declared on the table via NewRelations. Only single-level (non-nested) relations are supported.

type ForeignKeySnapshot

type ForeignKeySnapshot struct {
	Name        string   `json:"name"`
	TableFrom   string   `json:"tableFrom"`
	ColumnsFrom []string `json:"columnsFrom"`
	TableTo     string   `json:"tableTo"`
	ColumnsTo   []string `json:"columnsTo"`
	OnDelete    string   `json:"onDelete"`
	OnUpdate    string   `json:"onUpdate"`
}

ForeignKeySnapshot is one entry in TableSnapshot.ForeignKeys. A single-column FK (len(ColumnsFrom)==1) renders inline on its column; a composite FK renders as a table-level CONSTRAINT. OnDelete/OnUpdate hold the raw referential action ("CASCADE", "SET NULL", …) or "" for the SQLite default.

type InsertBuilder

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

InsertBuilder builds an INSERT statement. Create one via DB.Insert.

func (*InsertBuilder) Exec

func (i *InsertBuilder) Exec(ctx context.Context) (drops.Result, error)

Exec runs the INSERT.

func (*InsertBuilder) OrIgnore

func (i *InsertBuilder) OrIgnore() *InsertBuilder

OrIgnore emits INSERT OR IGNORE (SQLite's conflict-skip form).

func (*InsertBuilder) OrReplace

func (i *InsertBuilder) OrReplace() *InsertBuilder

OrReplace emits INSERT OR REPLACE (upsert-by-replace).

func (*InsertBuilder) Returning

func (i *InsertBuilder) Returning(cols ...ColRef) *InsertBuilder

Returning adds a RETURNING clause (SQLite >= 3.35).

func (*InsertBuilder) ToSQL

func (i *InsertBuilder) ToSQL() (sql string, args []any)

ToSQL renders the statement with SQLite placeholders.

func (*InsertBuilder) Values

func (i *InsertBuilder) Values(vals ...ColumnValue) *InsertBuilder

Values appends one row of column bindings. Every row must bind the same set of columns, in the same order.

func (*InsertBuilder) WriteSQL

func (i *InsertBuilder) WriteSQL(b *drops.Builder)

WriteSQL implements drops.Expression.

type Migration

type Migration struct {
	Version string // sortable string — zero-padded numeric is recommended ("0001")
	Name    string // human-readable label, used only for status output
	Up      func(ctx context.Context, db *DB) error
	Down    func(ctx context.Context, db *DB) error
}

Migration is one unit of schema change. Up and Down may be nil; a nil Down means the migration is irreversible (Down() will refuse to roll it back).

type MigrationDirection

type MigrationDirection int

MigrationDirection tells a MigrationHook whether the migrator is applying a migration (DirectionUp) or rolling one back (DirectionDown).

const (
	// DirectionUp is passed to hooks firing during Up.
	DirectionUp MigrationDirection = iota
	// DirectionDown is passed to hooks firing during Down.
	DirectionDown
)

func (MigrationDirection) String

func (d MigrationDirection) String() string

String renders the direction as "up" or "down".

type MigrationHook

type MigrationHook func(ctx context.Context, tx *DB, mig Migration, dir MigrationDirection) error

MigrationHook runs around a migration's Up/Down body, inside the same transaction, so any data it reads or writes commits atomically with the schema change (or rolls back with it on error). This is the seam for data migrations that must run between schema migrations — backfilling a new column, copying rows into a split-out table, rewriting a value before an old column is dropped.

Register hooks with Migrator.BeforeEach / Migrator.AfterEach. A "before" hook runs just before the migration body; an "after" hook runs just after it — in both directions. Use mig.Version / mig.Name to scope a data migration to a specific step, and dir to run it only on the way up (or only on the way down):

m.AfterEach(func(ctx context.Context, tx *sqlite.DB, mig sqlite.Migration, dir sqlite.MigrationDirection) error {
	if dir == sqlite.DirectionUp && mig.Version == "0003" {
		_, err := tx.Exec(ctx, `UPDATE users SET full_name = first_name || ' ' || last_name`)
		return err
	}
	return nil
})

A hook that returns an error aborts the migration: the whole transaction (schema change plus every hook) rolls back and Up/Down return the error.

type Migrator

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

Migrator runs database migrations and tracks their history in a table.

func NewMigrator

func NewMigrator(db *DB) *Migrator

NewMigrator returns a migrator bound to db. Add migrations with Add / AddSQL / AddFS, then call Up.

func (*Migrator) Add

func (m *Migrator) Add(mig Migration) *Migrator

Add registers a single migration.

func (*Migrator) AddFS

func (m *Migrator) AddFS(fsys fs.FS, dir string) error

AddFS scans dir within fsys for migration files and registers them.

Filename format: <version>_<name>.up.sql and (optionally) <version>_<name>.down.sql — for example, "0001_create_users.up.sql". Versions are compared lexicographically; zero-pad numeric versions.

func (*Migrator) AddSQL

func (m *Migrator) AddSQL(version, name, upSQL, downSQL string) *Migrator

AddSQL registers a migration whose Up and Down are raw SQL. downSQL may be empty.

func (*Migrator) AfterEach

func (m *Migrator) AfterEach(h MigrationHook) *Migrator

AfterEach registers a hook that runs immediately after every migration body, within the migration's transaction. Hooks fire in registration order; the first one to error aborts the migration. This is the usual home for a data migration that depends on the schema change having just landed. See MigrationHook.

func (*Migrator) BeforeEach

func (m *Migrator) BeforeEach(h MigrationHook) *Migrator

BeforeEach registers a hook that runs immediately before every migration body, within the migration's transaction. Hooks fire in registration order; the first one to error aborts the migration. See MigrationHook.

func (*Migrator) Down

func (m *Migrator) Down(ctx context.Context) error

Down rolls back the most recently applied migration. Returns ErrNoMigrationsApplied if there are none.

func (*Migrator) Status

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

Status reports every registered migration and whether it has been applied.

func (*Migrator) Up

func (m *Migrator) Up(ctx context.Context) error

Up applies every registered migration that hasn't been applied yet, in version order. Each migration runs in its own transaction.

func (*Migrator) WithTable

func (m *Migrator) WithTable(name string) *Migrator

WithTable overrides the migrations history table (default DefaultMigrationsTable).

type Relation

type Relation struct {
	Name   string
	Kind   RelationKind
	Target *Table

	// Local / Foreign are the join columns for HasMany / HasOne /
	// BelongsTo: Local lives on the owning table, Foreign on Target.
	Local   *Column
	Foreign *Column

	// ManyToMany junction wiring: Through is the junction table;
	// ThroughLocal / ThroughForeign are its FK columns pointing at the
	// owning table and the target respectively; LocalKey / TargetKey
	// are the referenced keys on the owning and target tables.
	Through        *Table
	ThroughLocal   *Column
	ThroughForeign *Column
	LocalKey       *Column
	TargetKey      *Column
}

Relation describes one association edge.

type RelationKind

type RelationKind int

RelationKind enumerates the supported association shapes.

const (
	// HasMany: parent has many children; the child holds the FK.
	HasMany RelationKind = iota
	// HasOne: parent has one child; the child holds the FK.
	HasOne
	// BelongsTo: this table holds the FK pointing at the parent.
	BelongsTo
	// ManyToMany: association through a junction table.
	ManyToMany
)

type RelationsBuilder

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

RelationsBuilder declares relations on a table fluently.

func NewRelations

func NewRelations(t *Table) *RelationsBuilder

NewRelations begins declaring relations on t.

func (*RelationsBuilder) BelongsTo

func (b *RelationsBuilder) BelongsTo(name string, target *Table, local, foreign ColRef) *RelationsBuilder

BelongsTo declares that t holds the FK (local) pointing at Target's key (foreign).

func (*RelationsBuilder) HasMany

func (b *RelationsBuilder) HasMany(name string, target *Table, local, foreign ColRef) *RelationsBuilder

HasMany declares that t has many Target rows, joined local == foreign (foreign is the FK column on Target).

func (*RelationsBuilder) HasOne

func (b *RelationsBuilder) HasOne(name string, target *Table, local, foreign ColRef) *RelationsBuilder

HasOne declares a one-to-one where Target holds the FK.

func (*RelationsBuilder) ManyToMany

func (b *RelationsBuilder) ManyToMany(name string, target, through *Table, throughLocal, throughForeign, localKey, targetKey ColRef) *RelationsBuilder

ManyToMany declares an association through a junction table. throughLocal / throughForeign are the junction FK columns pointing at the owning table and target; localKey / targetKey are the referenced keys on the owning and target tables.

type Schema

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

Schema is a registered set of tables — the input to snapshotting and diffing. SQLite has no schemas (namespaces), so a Schema is just a thin wrapper around a slice of *Table.

func NewSchema

func NewSchema(tables ...*Table) *Schema

NewSchema returns a Schema containing the supplied tables.

func (*Schema) Add

func (s *Schema) Add(t *Table) *Schema

Add appends a table and returns the schema for chaining.

func (*Schema) Tables

func (s *Schema) Tables() []*Table

Tables returns the registered tables in declaration order.

type SelectBuilder

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

SelectBuilder builds a SELECT statement. Create one via DB.Select.

func (*SelectBuilder) All

func (s *SelectBuilder) All(ctx context.Context, dest any) error

All executes the query and scans every row into dest (pointer to slice of struct or *struct).

func (*SelectBuilder) Distinct

func (s *SelectBuilder) Distinct() *SelectBuilder

Distinct adds the DISTINCT keyword.

func (*SelectBuilder) From

func (s *SelectBuilder) From(t *Table) *SelectBuilder

From sets the table to select from.

func (*SelectBuilder) Join

Join adds an INNER JOIN ... ON.

func (*SelectBuilder) LeftJoin

func (s *SelectBuilder) LeftJoin(t *Table, on drops.Expression) *SelectBuilder

LeftJoin adds a LEFT JOIN ... ON.

func (*SelectBuilder) Limit

func (s *SelectBuilder) Limit(n int64) *SelectBuilder

Limit sets a LIMIT.

func (*SelectBuilder) Offset

func (s *SelectBuilder) Offset(n int64) *SelectBuilder

Offset sets an OFFSET.

func (*SelectBuilder) One

func (s *SelectBuilder) One(ctx context.Context, dest any) error

One executes the query and scans the first row into dest (pointer to struct), returning ErrNoRows when empty.

func (*SelectBuilder) OrderBy

func (s *SelectBuilder) OrderBy(exprs ...drops.Expression) *SelectBuilder

OrderBy sets the ORDER BY expressions (use (*Column).WriteSQL refs, or raw drops.Raw("col DESC")).

func (*SelectBuilder) ToSQL

func (s *SelectBuilder) ToSQL() (sql string, args []any)

ToSQL renders the statement with SQLite placeholders.

func (*SelectBuilder) Where

func (s *SelectBuilder) Where(preds ...drops.Expression) *SelectBuilder

Where AND-s the given predicates onto the statement.

func (*SelectBuilder) WriteSQL

func (s *SelectBuilder) WriteSQL(b *drops.Builder)

WriteSQL implements drops.Expression.

type Snapshot

type Snapshot struct {
	ID      string                    `json:"id"`
	PrevID  string                    `json:"prevId"`
	Version string                    `json:"version"`
	Dialect string                    `json:"dialect"`
	Tables  map[string]*TableSnapshot `json:"tables"`
}

Snapshot captures the shape of a SQLite schema — tables, columns and every table-level constraint — so two revisions can be diffed into migration SQL. Unlike the drops/pg snapshot (which mirrors drizzle-kit's PostgreSQL v7 format), this is SQLite-flavoured: type strings are affinity keywords (INTEGER/TEXT/REAL/BLOB/NUMERIC), columns carry an autoincrement flag, and single-column foreign keys and uniques live inline on the column while composite ones are table-level constraints.

func BuildSnapshot

func BuildSnapshot(schema *Schema) *Snapshot

BuildSnapshot constructs a snapshot from a Go schema definition. The resulting ID is a fresh UUID v4; PrevID defaults to zeroUUID and the caller should overwrite it from the previous snapshot, if any.

func EmptySnapshot

func EmptySnapshot() *Snapshot

EmptySnapshot returns a fresh snapshot with no tables. Useful as the "previous" snapshot when diffing the first migration.

func Introspect

func Introspect(ctx context.Context, db *DB) (*Snapshot, error)

Introspect queries a live SQLite database and returns a Snapshot describing its current state — tables, columns (declared type, NOT NULL, default, primary key), single- and multi-column foreign keys with referential actions, composite primary keys, and UNIQUE constraints/indexes.

It mirrors pg.Introspect but reads SQLite's catalog: sqlite_master for the table list and the PRAGMA table_info / foreign_key_list / index_list / index_info functions for per-table detail. The migration-history table (_drops_sqlite_migrations) and SQLite's internal sqlite_* tables are skipped.

func UnmarshalSnapshot

func UnmarshalSnapshot(data []byte) (*Snapshot, error)

UnmarshalSnapshot parses a snapshot from JSON, restoring zero-valued maps for any nil collections so subsequent diffs don't have to check for nil.

func (*Snapshot) Marshal

func (s *Snapshot) Marshal() ([]byte, error)

Marshal returns the snapshot as 2-space-indented JSON.

type Status

type Status struct {
	Version   string
	Name      string
	Applied   bool
	AppliedAt time.Time // zero if not applied (or unparseable)
}

Status is a single row produced by Migrator.Status.

type Table

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

Table represents a SQLite table. SQLite has no schemas (only attached databases), so a table is just a name plus its columns and table-level constraints.

Unlike PostgreSQL, SQLite cannot add most constraints with ALTER TABLE, so composite primary keys, UNIQUE constraints and foreign keys are rendered inside CREATE TABLE (see ddl.go).

func NewTable

func NewTable(name string) *Table

NewTable creates a table. The name is validated; a bad identifier panics at declaration time.

func (*Table) AddCheck

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

AddCheck declares a named CHECK constraint whose value is the raw SQL expression (e.g. "age >= 0").

func (*Table) AddUnique

func (t *Table) AddUnique(name string, cols ...ColRef) *Table

AddUnique declares a named multi-column UNIQUE constraint.

func (*Table) Alias

func (t *Table) Alias() string

func (*Table) As

func (t *Table) As(alias string) *Table

As returns an aliased view of the table for use in joins.

func (*Table) Checks

func (t *Table) Checks() map[string]string

Checks returns the table's CHECK constraints keyed by name.

func (*Table) Col

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

func (*Table) Columns

func (t *Table) Columns() []*Column

func (*Table) CompositeForeignKeys

func (t *Table) CompositeForeignKeys() []*CompositeFK

CompositeForeignKeys returns the table's multi-column foreign keys.

func (*Table) CompositePrimaryKey

func (t *Table) CompositePrimaryKey() []*Column

CompositePrimaryKey returns the composite PK columns, or nil.

func (*Table) CompositeUniques

func (t *Table) CompositeUniques() map[string][]*Column

CompositeUniques returns the table's multi-column unique constraints.

func (*Table) ForeignKey

func (t *Table) ForeignKey(col, target *Column, opts ...func(*FK)) *Table

ForeignKey declares a single-column foreign key from col to target.

func (*Table) ForeignKeyN

func (t *Table) ForeignKeyN(cols []ColRef, target *Table, targetCols []ColRef, opts ...func(*FK)) *Table

ForeignKeyN declares a composite (N-column) foreign key from cols to targetCols on target, paired positionally. len(cols) must equal len(targetCols) and both be non-empty.

func (*Table) Name

func (t *Table) Name() string

func (*Table) PrimaryKey

func (t *Table) PrimaryKey(cols ...ColRef) *Table

PrimaryKey declares a composite (multi-column) primary key. For a single-column key use (*Col[T]).PrimaryKey() instead.

func (*Table) Relation

func (t *Table) Relation(name string) *Relation

Relation returns the named relation declared on t, or nil.

func (*Table) WriteSQL

func (t *Table) WriteSQL(b *drops.Builder)

WriteSQL implements drops.Expression (renders the FROM form).

type TableSnapshot

type TableSnapshot struct {
	Name                 string                          `json:"name"`
	Columns              map[string]*ColumnSnapshot      `json:"columns"`
	ForeignKeys          map[string]*ForeignKeySnapshot  `json:"foreignKeys"`
	CompositePrimaryKeys map[string]*CompositePKSnapshot `json:"compositePrimaryKeys"`
	UniqueConstraints    map[string]*UniqueSnapshot      `json:"uniqueConstraints"`
	CheckConstraints     map[string]*CheckSnapshot       `json:"checkConstraints"`
}

TableSnapshot is one entry in Snapshot.Tables.

type UniqueSnapshot

type UniqueSnapshot struct {
	Name    string   `json:"name"`
	Columns []string `json:"columns"`
}

UniqueSnapshot is one entry in TableSnapshot.UniqueConstraints (multi-column / named UNIQUE declared via Table.AddUnique).

type UpdateBuilder

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

UpdateBuilder builds an UPDATE statement. Create one via DB.Update.

func (*UpdateBuilder) Exec

func (u *UpdateBuilder) Exec(ctx context.Context) (drops.Result, error)

Exec runs the UPDATE.

func (*UpdateBuilder) Set

func (u *UpdateBuilder) Set(vals ...ColumnValue) *UpdateBuilder

Set adds a column assignment.

func (*UpdateBuilder) ToSQL

func (u *UpdateBuilder) ToSQL() (sql string, args []any)

ToSQL renders the statement with SQLite placeholders.

func (*UpdateBuilder) Where

func (u *UpdateBuilder) Where(preds ...drops.Expression) *UpdateBuilder

Where AND-s the given predicates onto the statement.

func (*UpdateBuilder) WriteSQL

func (u *UpdateBuilder) WriteSQL(b *drops.Builder)

WriteSQL implements drops.Expression.

Jump to

Keyboard shortcuts

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