Documentation
¶
Overview ¶
Package pg provides PostgreSQL schema declarations and a fluent query builder for use with drops.
Tables are declared with NewTable and a sequence of column constructors (Text, Integer, Serial, Boolean, Timestamp, UUID, JSONB, ...). Columns are themselves drops.Expressions and may be referenced anywhere a SQL fragment is expected.
Queries are composed via the methods on DB (Select, Insert, Update, Delete). Each builder is immutable in spirit — methods return the builder to support chaining — and ends with an executor (All, One, Exec, Returning + Scan).
Templates (Timestamps, SoftDelete, Audit, UUIDPrimaryKey) are reusable column groups that can be applied to any table — see template.go for the function-style pattern, mixin.go for the richer Mixin interface that also contributes indexes / lifecycle hooks / default filters. Libraries and applications expose their own templates by following either recipe.
Lifecycle hooks (OnInsert / OnUpdate / OnDelete on Table) let templates extend INSERT / UPDATE / DELETE statements automatically. User-supplied values always win, so hooks are safe to register on shared tables. Default scopes (Table.DefaultFilter) apply a predicate to every SELECT / UPDATE / DELETE against the table unless the caller opts out with the builder's Unscoped() method — the mechanism behind soft-delete-aware queries.
Entity[T] (see entity.go) binds a Go struct to a Table and exposes type-safe CRUD shortcuts: Get / Create / Update / Save / Delete / Query. It composes with lifecycle hooks and default scopes, so a SoftDelete mixin makes UserEntity.Delete() automatically rewrite into an UPDATE that flips deletedAt.
Entity.Validate registers per-row validators that run before Create / Update / Save. A column marked with OptimisticLock turns Update into a guarded "AND version = current, SET version = version + 1" — mismatched versions return ErrStaleObject.
Entity.SetFastScan plugs in a zero-reflection per-row scanner — typically the Scan<T> helper emitted by cmd/dropsgen. When set, Get / EntityQuery.All / EntityQuery.One skip the reflection path entirely. Eager-loaded relations (via With/WithRel) still need reflection, so the slow path kicks in automatically for those.
AutoTable[T] / NewAutoEntity[T] derive a Table (and an Entity) from extended `drop:"col,primaryKey,autoIncrement,notNull,unique,default=...,version"` struct tags — the struct becomes the single source of truth, and a working ORM falls out of one declaration:
var UserEntity = pg.NewAutoEntity[User]("users")
Entity.WithCache plugs in a drops/cache backend so Get / EntityQuery.All / EntityQuery.One are read-through and Create / Update / Save / Delete are write-invalidate. A built-in single-flight group dedupes concurrent identical PK misses so a thundering herd resolves to one DB query. Query results are keyed by sha256(SQL+args) and rely on the cache's TTL for freshness.
Index ¶
- Constants
- Variables
- func Abs(e any) drops.Expression
- func Acos(e any) drops.Expression
- func ActorFrom(ctx context.Context) string
- func AdvisoryLockKey(key string) int64
- func Age(args ...any) drops.Expression
- func All(value, array any) drops.Expression
- func AllSub(value, sub any) drops.Expression
- func AlterEnumAddValue(enumName, value string, before, after string) drops.Expression
- func AlterEnumRenameValue(enumName, oldValue, newValue string) drops.Expression
- func And(preds ...drops.Expression) drops.Expression
- func Any(value, array any) drops.Expression
- func AnySub(value, sub any) drops.Expression
- func ArrayAgg(e any) drops.Expression
- func ArrayAppend(arr, v any) drops.Expression
- func ArrayConcat(a, b any) drops.Expression
- func ArrayContainedIn(a, b any) drops.Expression
- func ArrayContains(a, b any) drops.Expression
- func ArrayLength(arr, dim any) drops.Expression
- func ArrayLit(values ...any) drops.Expression
- func ArrayLower(arr, dim any) drops.Expression
- func ArrayOverlaps(a, b any) drops.Expression
- func ArrayPosition(arr, v any) drops.Expression
- func ArrayPositions(arr, v any) drops.Expression
- func ArrayPrepend(v, arr any) drops.Expression
- func ArrayRemove(arr, v any) drops.Expression
- func ArrayReplace(arr, oldV, newV any) drops.Expression
- func ArrayToString(arr, sep any) drops.Expression
- func ArrayUpper(arr, dim any) drops.Expression
- func As(e drops.Expression, alias string) drops.Expression
- func Asin(e any) drops.Expression
- func AtTimeZone(ts, zone any) drops.Expression
- func Atan(e any) drops.Expression
- func Avg(e drops.Expression) drops.Expression
- func AvgDistinct(e drops.Expression) drops.Expression
- func Between(left, low, high any) drops.Expression
- func BoolAnd(e any) drops.Expression
- func BoolOr(e any) drops.Expression
- func Cardinality(arr any) drops.Expression
- func Cast(e any, typeSQL string) drops.Expression
- func CastAs(e any, typeSQL string) drops.Expression
- func Ceil(e any) drops.Expression
- func CharLength(e any) drops.Expression
- func Coalesce(args ...any) drops.Expression
- func ColumnExists(ctx context.Context, db *DB, schema, table, column string) (bool, error)
- func CommentOnColumn(c ColRef, text string) drops.Expression
- func CommentOnTable(t *Table, text string) drops.Expression
- func Concat(args ...any) drops.Expression
- func ConcatOp(left, right any) drops.Expression
- func ConcatWS(sep any, args ...any) drops.Expression
- func ConstraintExists(ctx context.Context, db *DB, schema, table, constraint string) (bool, error)
- func CopyFrom[T any](db *DB, ctx context.Context, ent *Entity[T], rs []T) (int64, error)
- func Cos(e any) drops.Expression
- func CosineDistance(left, right any) drops.Expression
- func Count(e drops.Expression) drops.Expression
- func CountAll() drops.Expression
- func CountDistinct(e drops.Expression) drops.Expression
- func CreateEnum(e *PgEnum) drops.Expression
- func CreateExtension(name string) drops.Expression
- func CreateExtensionIfNotExists(name string) drops.Expression
- func CreateFunction(name string, opts FunctionOptions) drops.Expression
- func CreateIndex(idx *Index) drops.Expression
- func CreateIndexIfNotExists(idx *Index) drops.Expression
- func CreateIndexOnline(idx *Index) drops.Expression
- func CreateMaterializedView(name string, query drops.Expression, withData bool) drops.Expression
- func CreateOrReplaceView(name string, query drops.Expression) drops.Expression
- func CreateSchema(name string) drops.Expression
- func CreateSchemaIfNotExists(name string) drops.Expression
- func CreateSequence(name string, opts ...SequenceOptions) drops.Expression
- func CreateSequenceIfNotExists(name string, opts ...SequenceOptions) drops.Expression
- func CreateTable(t *Table) drops.Expression
- func CreateTableIfNotExists(t *Table) drops.Expression
- func CreateTrigger(name string, opts TriggerOptions) drops.Expression
- func CreateView(name string, query drops.Expression) drops.Expression
- func CumeDist() drops.Expression
- func CurrVal(name string) drops.Expression
- func CurrentDate() drops.Expression
- func CurrentTime() drops.Expression
- func CurrentTimestamp() drops.Expression
- func DatePart(field string, ts any) drops.Expression
- func DateTrunc(field string, ts any) drops.Expression
- func Day(n int) drops.Expression
- func Decode(text, format any) drops.Expression
- func DenseRank() drops.Expression
- func Diff(prev, cur *Snapshot, opts ...DiffOptions) []string
- func DiffDown(prev, cur *Snapshot, opts ...DiffOptions) []string
- func DistanceFrom(col ColRef, p Point) drops.Expression
- func Div(left, right any) drops.Expression
- func DropEnum(name string) drops.Expression
- func DropEnumIfExists(name string) drops.Expression
- func DropExtension(name string) drops.Expression
- func DropExtensionIfExists(name string) drops.Expression
- func DropFunction(name, args string) drops.Expression
- func DropFunctionIfExists(name, args string) drops.Expression
- func DropIndex(name string) drops.Expression
- func DropIndexConcurrently(name string) drops.Expression
- func DropIndexIfExists(name string) drops.Expression
- func DropMaterializedView(name string) drops.Expression
- func DropSchema(name string) drops.Expression
- func DropSchemaIfExists(name string, cascade bool) drops.Expression
- func DropSequence(name string) drops.Expression
- func DropSequenceIfExists(name string) drops.Expression
- func DropTable(t *Table) drops.Expression
- func DropTableIfExists(t *Table) drops.Expression
- func DropTrigger(name string, table *Table) drops.Expression
- func DropTriggerIfExists(name string, table *Table) drops.Expression
- func DropView(name string) drops.Expression
- func DropViewIfExists(name string) drops.Expression
- func Encode(bytea, format any) drops.Expression
- func Eq(left, right any) drops.Expression
- func Every(e any) drops.Expression
- func Excluded(c ColRef) drops.Expression
- func Exists(q drops.Expression) drops.Expression
- func Exp(e any) drops.Expression
- func ExponentialJitter(base, max time.Duration) func(attempt int) time.Duration
- func Extract(field string, ts any) drops.Expression
- func Filter(agg drops.Expression, pred drops.Expression) drops.Expression
- func FirstValue(expr any) drops.Expression
- func Floor(e any) drops.Expression
- func ForEachShard(s *Sharded, ctx context.Context, fn func(shardIdx int, drv drops.Driver) error) []error
- func Format(format any, args ...any) drops.Expression
- func FormatLSN(lsn uint64) string
- func Func(name string, args ...any) drops.Expression
- func Greatest(args ...any) drops.Expression
- func Gt(left, right any) drops.Expression
- func Gte(left, right any) drops.Expression
- func HammingDistance(left, right any) drops.Expression
- func HasDangerousMigration(stmts []string) bool
- func HashShardKey(n int) func(key any) int
- func Hour(n int) drops.Expression
- func ILike(left, pattern any) drops.Expression
- func In(left any, values ...any) drops.Expression
- func Initcap(e any) drops.Expression
- func InnerProduct(left, right any) drops.Expression
- func InstallChangeFeed(t *Table, opts ...ChangeFeedOptions) ([]string, error)
- func IntervalLit(literal string) drops.Expression
- func IsNotNull(e any) drops.Expression
- func IsNull(e any) drops.Expression
- func IsPII(v any) bool
- func IsSagaError(err error) bool
- func JSONAgg(e any) drops.Expression
- func JSONArrayLength(e any) drops.Expression
- func JSONBAgg(e any) drops.Expression
- func JSONBArrayLength(e any) drops.Expression
- func JSONBBuildArray(args ...any) drops.Expression
- func JSONBBuildObject(args ...any) drops.Expression
- func JSONBConcat(a, b any) drops.Expression
- func JSONBContainedIn(a, b any) drops.Expression
- func JSONBContains(a, b any) drops.Expression
- func JSONBDelete(e, key any) drops.Expression
- func JSONBHasAllKeys(e, keys any) drops.Expression
- func JSONBHasAnyKey(e, keys any) drops.Expression
- func JSONBHasKey(e, key any) drops.Expression
- func JSONBInsert(target, path, newVal any, insertAfter ...bool) drops.Expression
- func JSONBObjectAgg(k, v any) drops.Expression
- func JSONBPretty(e any) drops.Expression
- func JSONBSet(target, path, value any, createMissing ...bool) drops.Expression
- func JSONBStripNulls(e any) drops.Expression
- func JSONBTypeof(e any) drops.Expression
- func JSONBuildArray(args ...any) drops.Expression
- func JSONBuildObject(args ...any) drops.Expression
- func JSONContains(col ColRef, value any) drops.Expression
- func JSONGet(e, key any) drops.Expression
- func JSONGetPath(e, path any) drops.Expression
- func JSONGetPathText(e, path any) drops.Expression
- func JSONGetText(e, key any) drops.Expression
- func JSONHasAllKeys(col ColRef, keys []string) drops.Expression
- func JSONHasAnyKey(col ColRef, keys []string) drops.Expression
- func JSONHasKey(col ColRef, key string) drops.Expression
- func JSONObjectAgg(k, v any) drops.Expression
- func JSONTypeof(e any) drops.Expression
- func JaccardDistance(left, right any) drops.Expression
- func L1Distance(left, right any) drops.Expression
- func L2Distance(left, right any) drops.Expression
- func LTrim(e any) drops.Expression
- func Lag(expr any, args ...any) drops.Expression
- func LastValue(expr any) drops.Expression
- func Lead(expr any, args ...any) drops.Expression
- func Least(args ...any) drops.Expression
- func Length(e any) drops.Expression
- func Like(left, pattern any) drops.Expression
- func Listen[T any](db *DB, ctx context.Context, channel string) (<-chan T, error)
- func Ln(e any) drops.Expression
- func LocalTime() drops.Expression
- func LocalTimestamp() drops.Expression
- func Log(e any) drops.Expression
- func LoggerHook(log LoggerFunc, opts ...LoggerOptions) drops.Hook
- func Lower(e drops.Expression) drops.Expression
- func Lt(left, right any) drops.Expression
- func Lte(left, right any) drops.Expression
- func MakeDate(y, m, d any) drops.Expression
- func MakeTime(h, m, s any) drops.Expression
- func MakeTimestamp(args ...any) drops.Expression
- func MakeTimestampTZ(args ...any) drops.Expression
- func Max(e drops.Expression) drops.Expression
- func Md5(e any) drops.Expression
- func MermaidDiagram(s *Schema) string
- func Min(e drops.Expression) drops.Expression
- func Minus(left, right any) drops.Expression
- func Minute(n int) drops.Expression
- func Mod(a, b any) drops.Expression
- func Month(n int) drops.Expression
- func Mul(left, right any) drops.Expression
- func N1Hook(ctx context.Context, e drops.QueryEvent)
- func Ne(left, right any) drops.Expression
- func NearestFrom(col ColRef, p Point) drops.Expression
- func NextVal(name string) drops.Expression
- func Not(p drops.Expression) drops.Expression
- func NotExists(q drops.Expression) drops.Expression
- func NotIn(left any, values ...any) drops.Expression
- func Notify(db *DB, ctx context.Context, channel string, payload any) error
- func Now() drops.Expression
- func NthValue(expr, n any) drops.Expression
- func Ntile(n any) drops.Expression
- func OnDelete(action string) func(*FK)
- func OnUpdate(action string) func(*FK)
- func Or(preds ...drops.Expression) drops.Expression
- func Over(fn drops.Expression, win *Window) drops.Expression
- func PII(value any) any
- func ParseLSN(s string) (uint64, error)
- func ParseMigrationName(filename string) (version, name, kind string, ok bool)
- func PercentRank() drops.Expression
- func Plus(left, right any) drops.Expression
- func Position(substring, str any) drops.Expression
- func Power(a, b any) drops.Expression
- func RTrim(e any) drops.Expression
- func Random() drops.Expression
- func Rank() drops.Expression
- func RefreshMaterializedView(name string, concurrently bool) drops.Expression
- func RegexpMatch(e, pattern any) drops.Expression
- func RegexpReplace(e, pattern, replacement any, flags ...string) drops.Expression
- func Replace(e, from, to any) drops.Expression
- func Round(e any, digits ...int) drops.Expression
- func RowNumber() drops.Expression
- func RunJSON[T any](s *IdempotencyStore, ctx context.Context, key string, ...) (T, error)
- func SagaStateGet[T any](s *SagaState, key string) (T, bool)
- func ScanAll(rows drops.Rows, dest any) error
- func ScanOne(rows drops.Rows, dest any) error
- func SchemaExists(ctx context.Context, db *DB, schema string) (bool, error)
- func Second(n int) drops.Expression
- func SetKeyring(k Keyring)
- func SetVal(name string, value any) drops.Expression
- func ShardKeyFrom(ctx context.Context) (any, bool)
- func Sign(e any) drops.Expression
- func Sin(e any) drops.Expression
- func Sqrt(e any) drops.Expression
- func StrPos(str, substring any) drops.Expression
- func StringAgg(e, sep any) drops.Expression
- func StringToArray(str, sep any) drops.Expression
- func SubjectFrom(ctx context.Context) (any, bool)
- func Subquery(q drops.Expression) drops.Expression
- func Subscribe[T any](db *DB, ctx context.Context, e *Entity[T], opts ...SubscribeOptions) (<-chan TypedChange[T], error)
- func Substring(e any, from any, count any) drops.Expression
- func Sum(e drops.Expression) drops.Expression
- func SumDistinct(e drops.Expression) drops.Expression
- func SupportsCopy(db *DB) bool
- func SupportsListen(db *DB) bool
- func SupportsPoolStats(db *DB) bool
- func TableExists(ctx context.Context, db *DB, schema, table string) (bool, error)
- func Tan(e any) drops.Expression
- func TenantFrom(ctx context.Context) (any, bool)
- func TestTx(t TB, db *DB, ctx context.Context, fn func(tx *DB))
- func ToChar(value, pattern any) drops.Expression
- func ToDate(text, pattern any) drops.Expression
- func ToJSON(e any) drops.Expression
- func ToJSONB(e any) drops.Expression
- func ToNumber(text, pattern any) drops.Expression
- func ToTimestamp(text, pattern any) drops.Expression
- func Trim(e any) drops.Expression
- func TryWithAdvisoryLock(db *DB, ctx context.Context, key string, fn func(*DB) error) error
- func UninstallChangeFeed(t *Table) []string
- func Unnest(arr any) drops.Expression
- func Upper(e drops.Expression) drops.Expression
- func Week(n int) drops.Expression
- func WithActor(ctx context.Context, actor any) context.Context
- func WithAdvisoryLock(db *DB, ctx context.Context, key string, fn func(*DB) error) error
- func WithN1Detector(ctx context.Context) (context.Context, func(threshold int) N1Report)
- func WithReadYourWrites(ctx context.Context, d time.Duration) context.Context
- func WithShardKey(ctx context.Context, key any) context.Context
- func WithSubject(ctx context.Context, subject any) context.Context
- func WithTenant(ctx context.Context, tenant any) context.Context
- func Within(col ColRef, box Box) drops.Expression
- func WithinRadius(col ColRef, p Point, metres float64) drops.Expression
- func Year(n int) drops.Expression
- type AggregateRef
- type AggregateSnapshot
- type AuditCols
- type AuditEvent
- type AuditLog
- type AuditMixin
- type Backfill
- func (b *Backfill) ChunkSize(n int) *Backfill
- func (b *Backfill) Fetch(fn func(ctx context.Context, lastID int64, limit int) ([]int64, int64, error)) *Backfill
- func (b *Backfill) OnProgress(fn func(processed, lastID int64)) *Backfill
- func (b *Backfill) PauseIfLag(repl *Replicated, thresholdBytes uint64) *Backfill
- func (b *Backfill) Process(fn func(ctx context.Context, tx *DB, ids []int64) error) *Backfill
- func (b *Backfill) Reset(ctx context.Context) error
- func (b *Backfill) Run(ctx context.Context) error
- func (b *Backfill) StateTable(name string) *Backfill
- func (b *Backfill) Status(ctx context.Context) (BackfillStatus, error)
- func (b *Backfill) Throttle(d time.Duration) *Backfill
- type BackfillStatus
- type Box
- type Budget
- type CTE
- type CaseExpr
- type ChangeEvent
- type ChangeFeedOptions
- type ChangeOp
- type CheckSnapshot
- type Col
- func Add[T any](t *Table, c *Col[T]) *Col[T]
- func BigInt(name string) *Col[int64]
- func BigSerial(name string) *Col[int64]
- func BitVec(name string, dim int) *Col[string]
- func Boolean(name string) *Col[bool]
- func Bytea(name string) *Col[[]byte]
- func Char(name string, n int) *Col[string]
- func Custom[T any](name, typeSQL string) *Col[T]
- func Date(name string) *Col[time.Time]
- func DoublePrecision(name string) *Col[float64]
- func HalfVec(name string, dim int) *Col[[]float32]
- func Integer(name string) *Col[int32]
- func Interval(name string) *Col[string]
- func JSON(name string) *Col[json.RawMessage]
- func JSONB(name string) *Col[json.RawMessage]
- func Numeric(name string, precision, scale int) *Col[string]
- func Real(name string) *Col[float32]
- func Serial(name string) *Col[int32]
- func SmallInt(name string) *Col[int16]
- func SparseVec(name string, dim int) *Col[string]
- func Text(name string) *Col[string]
- func Time(name string) *Col[time.Time]
- func Timestamp(name string, withTimeZone bool) *Col[time.Time]
- func UUID(name string) *Col[string]
- func Varchar(name string, n int) *Col[string]
- func Vector(name string, dim int) *Col[[]float32]
- func (c *Col[T]) AsPII() *Col[T]
- func (c *Col[T]) Between(lo, hi T) drops.Expression
- func (c *Col[T]) Cosine(v any) drops.Expression
- func (c *Col[T]) Default(sqlExpr string) *Col[T]
- func (c *Col[T]) Eq(v T) drops.Expression
- func (c *Col[T]) EqCol(other *Col[T]) drops.Expression
- func (c *Col[T]) Excluded() drops.Expression
- func (c *Col[T]) Expr(e drops.Expression) ColumnValue
- func (c *Col[T]) Gt(v T) drops.Expression
- func (c *Col[T]) GtCol(other *Col[T]) drops.Expression
- func (c *Col[T]) Gte(v T) drops.Expression
- func (c *Col[T]) GteCol(other *Col[T]) drops.Expression
- func (c *Col[T]) ILike(pattern string) drops.Expression
- func (c *Col[T]) IP(v any) drops.Expression
- func (c *Col[T]) In(values ...T) drops.Expression
- func (c *Col[T]) IsNotNull() drops.Expression
- func (c *Col[T]) IsNull() drops.Expression
- func (c *Col[T]) L1(v any) drops.Expression
- func (c *Col[T]) L2(v any) drops.Expression
- func (c *Col[T]) Like(pattern string) drops.Expression
- func (c *Col[T]) Lt(v T) drops.Expression
- func (c *Col[T]) LtCol(other *Col[T]) drops.Expression
- func (c *Col[T]) Lte(v T) drops.Expression
- func (c *Col[T]) LteCol(other *Col[T]) drops.Expression
- func (c *Col[T]) Ne(v T) drops.Expression
- func (c *Col[T]) NeCol(other *Col[T]) drops.Expression
- func (c *Col[T]) NotIn(values ...T) drops.Expression
- func (c *Col[T]) NotNull() *Col[T]
- func (c *Col[T]) OptimisticLock() *Col[T]
- func (c *Col[T]) PrimaryKey() *Col[T]
- func (c *Col[T]) References(target *Col[T], opts ...func(*FK)) *Col[T]
- func (c *Col[T]) SetDefault() ColumnValue
- func (c *Col[T]) Unique() *Col[T]
- func (c *Col[T]) Val(v T) ColumnValue
- type ColRef
- type Column
- func (c *Column) As(alias string) drops.Expression
- func (c *Column) Asc() drops.Expression
- func (c *Column) DefaultSQL() string
- func (c *Column) Desc() drops.Expression
- func (c *Column) ForeignKey() *FK
- func (c *Column) HasDefault() bool
- func (c *Column) IsNotNull() bool
- func (c *Column) IsOptimisticVersion() bool
- func (c *Column) IsPII() bool
- func (c *Column) IsPrimaryKey() bool
- func (c *Column) IsUnique() bool
- func (c *Column) Name() string
- func (c *Column) Table() *Table
- func (c *Column) Type() ColumnType
- func (c *Column) WriteSQL(b *drops.Builder)
- type ColumnSnapshot
- type ColumnType
- type ColumnValue
- type CompositePKSnapshot
- type ConflictUpdate
- type Copier
- type Cursor
- type CursorSpec
- type CustomGuard
- type DB
- func (db *DB) Begin(ctx context.Context) (*DB, drops.Tx, error)
- func (db *DB) Close() error
- func (db *DB) Delete(t *Table) *DeleteBuilder
- func (db *DB) Driver() drops.Driver
- func (db *DB) Exec(ctx context.Context, sql string, args ...any) (drops.Result, error)
- func (db *DB) ExecExpr(ctx context.Context, e drops.Expression) (drops.Result, error)
- func (db *DB) Find(t *Table) *FindBuilder
- func (db *DB) Hook() drops.Hook
- func (db *DB) InTx(ctx context.Context, fn func(*DB) error) error
- func (db *DB) Insert(t *Table) *InsertBuilder
- func (db *DB) Ping(ctx context.Context) error
- func (db *DB) PoolStats() (PoolStats, bool)
- func (db *DB) Query(ctx context.Context, sql string, args ...any) (drops.Rows, error)
- func (db *DB) RetryPolicyValue() RetryPolicy
- func (db *DB) Select(cols ...drops.Expression) *SelectBuilder
- func (db *DB) StartPoolMetrics(ctx context.Context, interval time.Duration, sink func(PoolStats)) func()
- func (db *DB) Tracer() Tracer
- func (db *DB) Update(t *Table) *UpdateBuilder
- func (db *DB) WithHook(hook drops.Hook) *DB
- func (db *DB) WithRetry(policy RetryPolicy) *DB
- func (db *DB) WithTracer(t Tracer) *DB
- type DeleteBuilder
- func (d *DeleteBuilder) All(ctx context.Context, dest any) error
- func (d *DeleteBuilder) DB() *DB
- func (d *DeleteBuilder) Exec(ctx context.Context) (drops.Result, error)
- func (d *DeleteBuilder) IsUnscoped() bool
- func (d *DeleteBuilder) One(ctx context.Context, dest any) error
- func (d *DeleteBuilder) Returning(cols ...drops.Expression) *DeleteBuilder
- func (d *DeleteBuilder) ReturningClauses() []drops.Expression
- func (d *DeleteBuilder) Table() *Table
- func (d *DeleteBuilder) ToSQL() (string, []any)
- func (d *DeleteBuilder) Unscoped() *DeleteBuilder
- func (d *DeleteBuilder) Using(tables ...*Table) *DeleteBuilder
- func (d *DeleteBuilder) Where(preds ...drops.Expression) *DeleteBuilder
- func (d *DeleteBuilder) Wheres() []drops.Expression
- func (d *DeleteBuilder) WriteSQL(b *drops.Builder)
- type DeleteHook
- type DeleteHookFunc
- type DiffOptions
- type DriftReport
- type DrizzleEntry
- type DrizzleMigrator
- func (d *DrizzleMigrator) LoadEntries() ([]DrizzleEntry, error)
- func (d *DrizzleMigrator) Status(ctx context.Context) ([]DrizzleStatus, error)
- func (d *DrizzleMigrator) Up(ctx context.Context) error
- func (d *DrizzleMigrator) WithSchema(schema string) *DrizzleMigrator
- func (d *DrizzleMigrator) WithTable(table string) *DrizzleMigrator
- type DrizzleStatus
- type EmitOptions
- type Entity
- func (e *Entity[T]) AuthorizeWith(g Guard) *Entity[T]
- func (e *Entity[T]) Create(db *DB, ctx context.Context, r *T) error
- func (e *Entity[T]) CreateMany(db *DB, ctx context.Context, rs []T) (drops.Result, error)
- func (e *Entity[T]) Delete(db *DB, ctx context.Context, id any) (drops.Result, error)
- func (e *Entity[T]) Get(db *DB, ctx context.Context, id any) (T, error)
- func (e *Entity[T]) HasCache() bool
- func (e *Entity[T]) HasFastScan() bool
- func (e *Entity[T]) PK() *Column
- func (e *Entity[T]) Page(db *DB) *PageBuilder[T]
- func (e *Entity[T]) Patch(db *DB, ctx context.Context, id any, ops ...PatchOp) (drops.Result, error)
- func (e *Entity[T]) Query(db *DB) *EntityQuery[T]
- func (e *Entity[T]) Save(db *DB, ctx context.Context, r *T) error
- func (e *Entity[T]) ScopeByTenant(col ColRef) *Entity[T]
- func (e *Entity[T]) SetFastScan(scan func(Scanner, *T) error) *Entity[T]
- func (e *Entity[T]) Table() *Table
- func (e *Entity[T]) Update(db *DB, ctx context.Context, r *T) error
- func (e *Entity[T]) UpsertMany(db *DB, ctx context.Context, rs []T) (drops.Result, error)
- func (e *Entity[T]) Validate(v Validator[T]) *Entity[T]
- func (e *Entity[T]) WithBudget(b Budget) *Entity[T]
- func (e *Entity[T]) WithCache(c cache.Cache, ttl time.Duration) *Entity[T]
- type EntityCache
- type EntityQuery
- func (q *EntityQuery[T]) All(ctx context.Context) ([]T, error)
- func (q *EntityQuery[T]) Limit(n int64) *EntityQuery[T]
- func (q *EntityQuery[T]) Offset(n int64) *EntityQuery[T]
- func (q *EntityQuery[T]) One(ctx context.Context) (T, error)
- func (q *EntityQuery[T]) OrderBy(exprs ...drops.Expression) *EntityQuery[T]
- func (q *EntityQuery[T]) Stream(ctx context.Context, fn func(*T) error) error
- func (q *EntityQuery[T]) Unscoped() *EntityQuery[T]
- func (q *EntityQuery[T]) Where(preds ...drops.Expression) *EntityQuery[T]
- func (q *EntityQuery[T]) With(names ...string) *EntityQuery[T]
- func (q *EntityQuery[T]) WithRel(name string, fn func(*RelConfig)) *EntityQuery[T]
- type EnumSnapshot
- type EnvelopeCipher
- type Event
- type EventInput
- type EventStore
- func (s *EventStore) Append(tx *DB, ctx context.Context, aggregateType, aggregateID string, ...) error
- func (s *EventStore) LatestVersion(ctx context.Context, aggregateType, aggregateID string) (int64, error)
- func (s *EventStore) Load(ctx context.Context, aggregateType, aggregateID string, fromVersion int64) ([]Event, error)
- func (s *EventStore) LoadSnapshot(ctx context.Context, table, aggregateType, aggregateID string) (AggregateSnapshot, bool, error)
- func (s *EventStore) SaveSnapshot(ctx context.Context, table string, snap AggregateSnapshot) error
- func (s *EventStore) Stream(ctx context.Context, fromOffset int64, limit int) ([]Event, error)
- type ExplainOptions
- type ExplainPlan
- type FK
- type Factory
- func (f *Factory[T]) Build() T
- func (f *Factory[T]) BuildN(n int) []T
- func (f *Factory[T]) Create(ctx context.Context, db *DB) (T, error)
- func (f *Factory[T]) CreateN(ctx context.Context, db *DB, n int) ([]T, error)
- func (f *Factory[T]) Entity() *Entity[T]
- func (f *Factory[T]) Reset()
- func (f *Factory[T]) Sequence() int
- func (f *Factory[T]) With(mutate func(*T)) *Factory[T]
- type FindBuilder
- func (f *FindBuilder) All(ctx context.Context, dest any) error
- func (f *FindBuilder) HasEagerLoads() bool
- func (f *FindBuilder) Limit(n int64) *FindBuilder
- func (f *FindBuilder) Offset(n int64) *FindBuilder
- func (f *FindBuilder) One(ctx context.Context, dest any) error
- func (f *FindBuilder) OrderBy(exprs ...drops.Expression) *FindBuilder
- func (f *FindBuilder) Select() *SelectBuilder
- func (f *FindBuilder) Unscoped() *FindBuilder
- func (f *FindBuilder) Where(preds ...drops.Expression) *FindBuilder
- func (f *FindBuilder) With(names ...string) *FindBuilder
- func (f *FindBuilder) WithRel(name string, fn func(*RelConfig)) *FindBuilder
- type ForeignKeySnapshot
- type FunctionOptions
- type GenerateOptions
- type GenerateResult
- type Guard
- type IdempotencyStore
- type Index
- func (i *Index) Concurrently() *Index
- func (i *Index) Include(cols ...*Column) *Index
- func (i *Index) Name() string
- func (i *Index) OpClass(class VectorOpClass) *Index
- func (i *Index) Table() *Table
- func (i *Index) Unique() *Index
- func (i *Index) Using(method string) *Index
- func (i *Index) Where(pred drops.Expression) *Index
- func (i *Index) With(spec string) *Index
- type IndexSnapshot
- type InsertBuilder
- func (i *InsertBuilder) All(ctx context.Context, dest any) error
- func (i *InsertBuilder) Exec(ctx context.Context) (drops.Result, error)
- func (i *InsertBuilder) OnConflictDoNothing(target ...ColRef) *InsertBuilder
- func (i *InsertBuilder) OnConflictUpdate(target ...ColRef) *ConflictUpdate
- func (i *InsertBuilder) One(ctx context.Context, dest any) error
- func (i *InsertBuilder) Returning(cols ...drops.Expression) *InsertBuilder
- func (i *InsertBuilder) Row(values ...ColumnValue) *InsertBuilder
- func (i *InsertBuilder) Rows(rows ...[]ColumnValue) *InsertBuilder
- func (i *InsertBuilder) ToSQL() (string, []any)
- func (i *InsertBuilder) WriteSQL(b *drops.Builder)
- type InsertHook
- type InsertHookCtx
- type InsertHookFunc
- type IntrospectOptions
- type JSONPath
- func (j *JSONPath[T]) Column() *Column
- func (j *JSONPath[T]) Eq(v T) drops.Expression
- func (j *JSONPath[T]) Gt(v T) drops.Expression
- func (j *JSONPath[T]) Gte(v T) drops.Expression
- func (j *JSONPath[T]) In(values ...T) drops.Expression
- func (j *JSONPath[T]) IsNotNull() drops.Expression
- func (j *JSONPath[T]) IsNull() drops.Expression
- func (j *JSONPath[T]) Like(pattern string) drops.Expression
- func (j *JSONPath[T]) Lt(v T) drops.Expression
- func (j *JSONPath[T]) Lte(v T) drops.Expression
- func (j *JSONPath[T]) Ne(v T) drops.Expression
- func (j *JSONPath[T]) Path() []string
- func (j *JSONPath[T]) WriteSQL(b *drops.Builder)
- type KMS
- type Keyring
- type Listener
- type LocalKMS
- type LoggerFunc
- type LoggerOptions
- type MatView
- type MatViewManager
- func (m *MatViewManager) Add(v MatView) *MatViewManager
- func (m *MatViewManager) LastRefresh(name string) time.Time
- func (m *MatViewManager) Refresh(ctx context.Context, name string) error
- func (m *MatViewManager) RefreshAll(ctx context.Context) error
- func (m *MatViewManager) RefreshDownstream(ctx context.Context, upstream string) error
- func (m *MatViewManager) Start(ctx context.Context) error
- func (m *MatViewManager) Views() []MatView
- func (m *MatViewManager) WithPollInterval(d time.Duration) *MatViewManager
- type MembershipGuard
- type Migration
- type Migrator
- func (m *Migrator) Add(mig Migration) *Migrator
- func (m *Migrator) AddFS(fsys fs.FS, dir string) error
- func (m *Migrator) AddSQL(version, name, upSQL, downSQL string) *Migrator
- func (m *Migrator) Down(ctx context.Context) error
- func (m *Migrator) Status(ctx context.Context) ([]Status, error)
- func (m *Migrator) Up(ctx context.Context) error
- func (m *Migrator) WithTable(name string) *Migrator
- type Mixin
- type MixinFunc
- type Money
- func (m Money) Add(other Money) Money
- func (m Money) Cents() int64
- func (m Money) Compare(other Money) int
- func (m Money) Exponent() uint8
- func (m Money) IsNegative() bool
- func (m Money) IsZero() bool
- func (m Money) MarshalJSON() ([]byte, error)
- func (m Money) MulInt(n int64) Money
- func (m Money) MulRate(rate float64) Money
- func (m Money) Neg() Money
- func (m *Money) Scan(src any) error
- func (m Money) String() string
- func (m Money) Sub(other Money) Money
- func (m *Money) UnmarshalJSON(b []byte) error
- func (m Money) Value() (driver.Value, error)
- type MorphMap
- type N1Pattern
- type N1Report
- type Notification
- type NullsOrdering
- type OrderKey
- type OrderingColumn
- type Outbox
- func (o *Outbox) Cleanup(ctx context.Context, retainAfter time.Duration) (int64, error)
- func (o *Outbox) Drain(ctx context.Context, limit int) ([]OutboxEvent, error)
- func (o *Outbox) DrainAggregate(ctx context.Context, aggregateType, aggregateID string, limit int, ...) error
- func (o *Outbox) Emit(tx *DB, ctx context.Context, kind string, payload any) error
- func (o *Outbox) EmitWith(tx *DB, ctx context.Context, kind string, payload any, opts EmitOptions) error
- func (o *Outbox) MarkFailed(ctx context.Context, id int64, attempts int, nextRetryAt time.Time, ...) error
- func (o *Outbox) MarkPublished(ctx context.Context, ids ...int64) error
- func (o *Outbox) NotifyChannel() string
- func (o *Outbox) PendingAggregates(ctx context.Context, limit int) ([]AggregateRef, error)
- func (o *Outbox) WithNotifyChannel(channel string) *Outbox
- type OutboxBatchHandler
- type OutboxEvent
- type OutboxHandler
- type OutboxOrdering
- type OutboxWorker
- func (w *OutboxWorker) OnBatch(fn OutboxBatchHandler) *OutboxWorker
- func (w *OutboxWorker) OnError(fn func(error)) *OutboxWorker
- func (w *OutboxWorker) OnEvent(fn OutboxHandler) *OutboxWorker
- func (w *OutboxWorker) Run(ctx context.Context) error
- func (w *OutboxWorker) WithBackoff(fn func(attempt int) time.Duration) *OutboxWorker
- func (w *OutboxWorker) WithBatch(n int) *OutboxWorker
- func (w *OutboxWorker) WithInterval(d time.Duration) *OutboxWorker
- func (w *OutboxWorker) WithMaxAttempts(n int) *OutboxWorker
- func (w *OutboxWorker) WithOrdering(m OutboxOrdering) *OutboxWorker
- type OwnerGuard
- type PIIParam
- type Page
- type PageBuilder
- func (p *PageBuilder[T]) After(cursor string) *PageBuilder[T]
- func (p *PageBuilder[T]) All(ctx context.Context) (*Page[T], error)
- func (p *PageBuilder[T]) Limit(n int) *PageBuilder[T]
- func (p *PageBuilder[T]) OrderBy(cols ...OrderingColumn) *PageBuilder[T]
- func (p *PageBuilder[T]) Where(preds ...drops.Expression) *PageBuilder[T]
- type PatchOp
- type PgEnum
- type PgError
- type PgSequence
- type PgView
- type PlanDiff
- type PlanNode
- type Point
- type Policy
- func (p *Policy) As() string
- func (p *Policy) Command() string
- func (p *Policy) For(cmd string) *Policy
- func (p *Policy) Name() string
- func (p *Policy) Restrictive() *Policy
- func (p *Policy) Roles() []string
- func (p *Policy) To(roles ...string) *Policy
- func (p *Policy) Using(expr string) *Policy
- func (p *Policy) UsingExpr() string
- func (p *Policy) WithCheck(expr string) *Policy
- func (p *Policy) WithCheckExpr() string
- type PolicySnapshot
- type PoolStats
- type PoolStatsProvider
- type PushOptions
- type PushResult
- type RefreshMode
- type RelConfig
- func (c *RelConfig) Limit(n int) *RelConfig
- func (c *RelConfig) Offset(n int) *RelConfig
- func (c *RelConfig) OrderBy(exprs ...drops.Expression) *RelConfig
- func (c *RelConfig) Where(preds ...drops.Expression) *RelConfig
- func (c *RelConfig) With(names ...string) *RelConfig
- func (c *RelConfig) WithRel(name string, fn func(*RelConfig)) *RelConfig
- type Relation
- type RelationKind
- type Relations
- func (r *Relations) BelongsTo(name string, parent *Table, childFK, parentKey ColRef) *Relations
- func (r *Relations) HasMany(name string, child *Table, parentKey, childFK ColRef) *Relations
- func (r *Relations) HasOne(name string, child *Table, parentKey, childFK ColRef) *Relations
- func (r *Relations) ManyToMany(name string, target *Table, through *Table, throughLocal, throughRemote ColRef, ...) *Relations
- func (r *Relations) MorphMany(name string, child *Table, childTypeCol, childIDCol ColRef, parentKey ColRef, ...) *Relations
- func (r *Relations) MorphTo(name string, typeCol, idCol ColRef, morphs *MorphMap) *Relations
- type Replicated
- func (r *Replicated) Begin(ctx context.Context) (drops.Tx, error)
- func (r *Replicated) Close() error
- func (r *Replicated) Exec(ctx context.Context, sql string, args ...any) (drops.Result, error)
- func (r *Replicated) LSNTracking() bool
- func (r *Replicated) Primary() drops.Driver
- func (r *Replicated) Query(ctx context.Context, sql string, args ...any) (drops.Rows, error)
- func (r *Replicated) Replicas() []drops.Driver
- func (r *Replicated) WithLSNTracking(ttl time.Duration) *Replicated
- type RetryPolicy
- type Risk
- type RiskLevel
- type SafetyOptions
- type SafetySeverity
- type SafetyWarning
- type Saga
- type SagaCompensationFailure
- type SagaError
- type SagaState
- type SagaStepFn
- type Scanner
- type Schema
- func (s *Schema) Add(t *Table) *Schema
- func (s *Schema) AddEnum(e *PgEnum) *Schema
- func (s *Schema) AddSequence(seq *PgSequence) *Schema
- func (s *Schema) AddView(v *PgView) *Schema
- func (s *Schema) Enums() []*PgEnum
- func (s *Schema) Sequences() []*PgSequence
- func (s *Schema) Tables() []*Table
- func (s *Schema) Views() []*PgView
- type Secret
- type Seeder
- type SelectBuilder
- func (s *SelectBuilder) AfterCursor(spec CursorSpec, c Cursor) *SelectBuilder
- func (s *SelectBuilder) All(ctx context.Context, dest any) error
- func (s *SelectBuilder) AsSubquery(alias string) drops.Expression
- func (s *SelectBuilder) BeforeCursor(spec CursorSpec, c Cursor) *SelectBuilder
- func (s *SelectBuilder) Count(ctx context.Context) (int64, error)
- func (s *SelectBuilder) Distinct() *SelectBuilder
- func (s *SelectBuilder) DistinctOn(exprs ...drops.Expression) *SelectBuilder
- func (s *SelectBuilder) Except(other *SelectBuilder) *SelectBuilder
- func (s *SelectBuilder) ExceptAll(other *SelectBuilder) *SelectBuilder
- func (s *SelectBuilder) ForUpdate() *SelectBuilder
- func (s *SelectBuilder) From(t *Table) *SelectBuilder
- func (s *SelectBuilder) FromExpr(e drops.Expression) *SelectBuilder
- func (s *SelectBuilder) FullJoin(t *Table, on drops.Expression) *SelectBuilder
- func (s *SelectBuilder) GroupBy(exprs ...drops.Expression) *SelectBuilder
- func (s *SelectBuilder) Having(preds ...drops.Expression) *SelectBuilder
- func (s *SelectBuilder) Intersect(other *SelectBuilder) *SelectBuilder
- func (s *SelectBuilder) IntersectAll(other *SelectBuilder) *SelectBuilder
- func (s *SelectBuilder) Join(t *Table, on drops.Expression) *SelectBuilder
- func (s *SelectBuilder) LeftJoin(t *Table, on drops.Expression) *SelectBuilder
- func (s *SelectBuilder) Limit(n int64) *SelectBuilder
- func (s *SelectBuilder) Offset(n int64) *SelectBuilder
- func (s *SelectBuilder) One(ctx context.Context, dest any) error
- func (s *SelectBuilder) OrderBy(exprs ...drops.Expression) *SelectBuilder
- func (s *SelectBuilder) OrderByCursor(spec CursorSpec) *SelectBuilder
- func (s *SelectBuilder) RightJoin(t *Table, on drops.Expression) *SelectBuilder
- func (s *SelectBuilder) Rows(ctx context.Context) (drops.Rows, error)
- func (s *SelectBuilder) ToSQL() (string, []any)
- func (s *SelectBuilder) Union(other *SelectBuilder) *SelectBuilder
- func (s *SelectBuilder) UnionAll(other *SelectBuilder) *SelectBuilder
- func (s *SelectBuilder) Unscoped() *SelectBuilder
- func (s *SelectBuilder) Where(preds ...drops.Expression) *SelectBuilder
- func (s *SelectBuilder) With(ctes ...*CTE) *SelectBuilder
- func (s *SelectBuilder) WithRecursive(ctes ...*CTE) *SelectBuilder
- func (s *SelectBuilder) WriteSQL(b *drops.Builder)
- type SequenceOptions
- type SequenceSnapshot
- type Sharded
- func (s *Sharded) Begin(ctx context.Context) (drops.Tx, error)
- func (s *Sharded) Close() error
- func (s *Sharded) Exec(ctx context.Context, sql string, args ...any) (drops.Result, error)
- func (s *Sharded) Query(ctx context.Context, sql string, args ...any) (drops.Rows, error)
- func (s *Sharded) Shards() []drops.Driver
- type Snapshot
- type SnapshotMeta
- type SoftDeleteCols
- type SoftDeleteMixin
- type Span
- type Status
- type SubscribeOptions
- type TB
- type Table
- func ApplyMixins(t *Table, mixins ...Mixin) *Table
- func AutoSchemaTable[T any](schema, name string) *Table
- func AutoTable[T any](name string) *Table
- func NewAuditTable(name string) *Table
- func NewBackfillStateTable(name string) *Table
- func NewEventStoreTable(name string) *Table
- func NewIdempotencyTable(name string) *Table
- func NewOutboxTable(name string) *Table
- func NewSchemaTable(schema, name string) *Table
- func NewSnapshotTable(name string) *Table
- func NewTable(name string) *Table
- func (t *Table) AddCheck(name, expr string) *Table
- func (t *Table) AddIndex(idx *Index) *Table
- func (t *Table) AddPolicy(p *Policy) *Table
- func (t *Table) AddUnique(name string, cols ...ColRef) *Table
- func (t *Table) Alias() string
- func (t *Table) As(alias string) *Table
- func (t *Table) Checks() map[string]string
- func (t *Table) Col(name string) *Column
- func (t *Table) Columns() []*Column
- func (t *Table) CompositePrimaryKey() []*Column
- func (t *Table) CompositeUniques() map[string][]*Column
- func (t *Table) DefaultFilter(e drops.Expression) *Table
- func (t *Table) EnableRLS() *Table
- func (t *Table) ForeignKey(col, target *Column, opts ...func(*FK)) *Table
- func (t *Table) Indexes() []*Index
- func (t *Table) Name() string
- func (t *Table) OnDelete(h DeleteHook) *Table
- func (t *Table) OnInsert(h InsertHook) *Table
- func (t *Table) OnUpdate(h UpdateHook) *Table
- func (t *Table) Policies() map[string]*Policy
- func (t *Table) PrimaryKey(cols ...ColRef) *Table
- func (t *Table) RLSEnabled() bool
- func (t *Table) Relation(name string) *Relation
- func (t *Table) Schema() string
- func (t *Table) WriteSQL(b *drops.Builder)
- type TableSnapshot
- type TimeSeriesTable
- func (t *TimeSeriesTable) Bootstrap(db *DB, ctx context.Context) error
- func (t *TimeSeriesTable) DropExpired(db *DB, ctx context.Context) (int, error)
- func (t *TimeSeriesTable) EnsureNext(db *DB, ctx context.Context, count int) error
- func (t *TimeSeriesTable) Maintain(db *DB, ctx context.Context) error
- func (t *TimeSeriesTable) PartitionEvery(d time.Duration) *TimeSeriesTable
- func (t *TimeSeriesTable) Retain(d time.Duration) *TimeSeriesTable
- func (t *TimeSeriesTable) WithBrinIndex(col string) *TimeSeriesTable
- type TimestampsCols
- type TimestampsMixin
- type Tracer
- type TriggerOptions
- type TypedChange
- type UUIDPrimaryKeyCols
- type UUIDPrimaryKeyMixin
- type UniqueSnapshot
- type UpdateBuilder
- func (u *UpdateBuilder) All(ctx context.Context, dest any) error
- func (u *UpdateBuilder) Exec(ctx context.Context) (drops.Result, error)
- func (u *UpdateBuilder) From(tables ...*Table) *UpdateBuilder
- func (u *UpdateBuilder) One(ctx context.Context, dest any) error
- func (u *UpdateBuilder) Returning(cols ...drops.Expression) *UpdateBuilder
- func (u *UpdateBuilder) Set(values ...ColumnValue) *UpdateBuilder
- func (u *UpdateBuilder) ToSQL() (string, []any)
- func (u *UpdateBuilder) Unscoped() *UpdateBuilder
- func (u *UpdateBuilder) Where(preds ...drops.Expression) *UpdateBuilder
- func (u *UpdateBuilder) WriteSQL(b *drops.Builder)
- type UpdateHook
- type UpdateHookCtx
- type UpdateHookFunc
- type Validator
- type VectorOpClass
- type ViewSnapshot
- type Window
Examples ¶
Constants ¶
const ( AttrStatement = "db.statement" AttrArgsCount = "db.args.count" AttrSystem = "db.system" AttrOperation = "db.operation" AttrSystemPG = "postgresql" )
attribute keys used by drops spans — kept as named constants so downstream alerts / dashboards can match them reliably.
const DefaultMigrationsTable = "_drops_migrations"
DefaultMigrationsTable is the table used to track applied migrations when no override is set on the Migrator.
const DrizzleSchema = "drizzle"
DrizzleSchema is the schema where drizzle stores migration history.
const DrizzleTable = "__drizzle_migrations"
DrizzleTable is the migration history table.
const StatementBreakpoint = "--> statement-breakpoint"
StatementBreakpoint is the delimiter drizzle-kit emits between statements when breakpoints are enabled.
Variables ¶
var ( // ErrReturningRequired is returned by *Builder.All / *Builder.One on // INSERT/UPDATE/DELETE statements that were not paired with a // Returning(...) clause. ErrReturningRequired = errors.New("drops/pg: builder.All/One requires Returning(...)") // ErrNoRowsToInsert is returned by InsertBuilder.Exec when no row has // been added via Row / Rows. ErrNoRowsToInsert = errors.New("drops/pg: INSERT with no rows") // ErrNoUpdateAssignments is returned by UpdateBuilder.Exec when no // Set assignment has been added. ErrNoUpdateAssignments = errors.New("drops/pg: UPDATE with no Set assignments") // ErrSchemaRequired is returned by Push when schema is nil. ErrSchemaRequired = errors.New("drops/pg: Schema is required") // ErrInvalidIdentifier is returned when a SQL identifier (table, // column, schema) contains characters that would break out of // double-quoted identifier safety (NUL, embedded double quotes). ErrInvalidIdentifier = errors.New("drops/pg: invalid SQL identifier") )
Package-level sentinel errors. Callers may check them with errors.Is to branch on a specific failure mode without inspecting the message.
The decorating wrappers used by builders use fmt.Errorf("...: %w", err) so the chain stays intact when extra context is added.
var ( // ErrUniqueViolation — SQLSTATE 23505. INSERT / UPDATE collided // with a UNIQUE or PRIMARY KEY constraint. ErrUniqueViolation = errors.New("drops/pg: unique constraint violation") // ErrForeignKeyViolation — SQLSTATE 23503. The referenced row // is missing, or a referenced row is being deleted while still // referenced. ErrForeignKeyViolation = errors.New("drops/pg: foreign-key constraint violation") // ErrCheckViolation — SQLSTATE 23514. A CHECK constraint // returned false for the supplied value. ErrCheckViolation = errors.New("drops/pg: check constraint violation") // ErrNotNullViolation — SQLSTATE 23502. A NOT NULL column // received NULL. ErrNotNullViolation = errors.New("drops/pg: not-null constraint violation") // ErrUndefinedTable — SQLSTATE 42P01. Query referenced an // unknown table. ErrUndefinedTable = errors.New("drops/pg: undefined table") // ErrUndefinedColumn — SQLSTATE 42703. Query referenced an // unknown column. ErrUndefinedColumn = errors.New("drops/pg: undefined column") // ErrSerializationFailure — SQLSTATE 40001. A SERIALIZABLE // transaction must be retried. ErrSerializationFailure = errors.New("drops/pg: serialization failure") // ErrDeadlock — SQLSTATE 40P01. The transaction was aborted // because it was selected as a deadlock victim. ErrDeadlock = errors.New("drops/pg: deadlock detected") )
SQLSTATE-classified errors. Driver-level failures from Exec / Query are wrapped in a PgError whose Sentinel field points at the matching value below, so callers can branch with errors.Is without depending on driver-specific types:
if errors.Is(err, pg.ErrUniqueViolation) {
return "email already taken"
}
PgError exposes the SQLSTATE code and the constraint name when the driver reports them.
var ErrAuditTableMissing = errors.New("drops/pg: audit table not present; create it via NewAuditTable + migration")
ErrAuditTableMissing is returned when an audit operation fails because the configured table does not exist. Surfaces a clearer error than the raw "relation does not exist".
var ErrBudgetExceeded = errors.New("drops/pg: query budget exceeded")
ErrBudgetExceeded is returned when the request would breach the entity's Budget. MaxDuration produces context.DeadlineExceeded directly, which wraps to ErrBudgetExceeded via errors.Is so a single check covers every budget mode.
var ErrCiphertextTooShort = errors.New("drops/pg: ciphertext too short")
ErrCiphertextTooShort is returned when Decrypt receives bytes smaller than a nonce — typically a sign of a corrupt or truncated row.
var ErrCircularDependency = errors.New("drops/pg: MatViewManager: circular dependency")
ErrCircularDependency is returned by topological helpers when a cycle is detected. Kept as a package value so handlers can detect it without string matching.
var ErrConcurrencyConflict = errors.New("drops/pg: event store concurrency conflict")
ErrConcurrencyConflict is returned by Append when the expectedVersion no longer matches the stream's head — another writer beat us to that version. Wrap your callsite in a retry loop that re-reads the stream before retrying.
var ErrCopyNotSupported = errors.New("drops/pg: driver does not implement Copier — fall back to CreateMany")
ErrCopyNotSupported is returned by CopyFrom when the underlying driver does not satisfy Copier. Callers should fall back to Entity.CreateMany / UpsertMany.
var ErrEmptyKey = errors.New("drops/pg: idempotency key cannot be empty")
ErrEmptyKey is returned by Run when key is the empty string. An empty key would collapse every operation onto the same row, which is almost always a bug.
var ErrListenNotSupported = errors.New("drops/pg: driver does not implement Listener")
ErrListenNotSupported is returned by Listen when the driver does not satisfy Listener — fall back to polling or wire pgx / lib/pq's listener APIs into an adapter.
var ErrLockNotAcquired = errors.New("drops/pg: advisory lock not acquired")
ErrLockNotAcquired is returned by TryWithAdvisoryLock when another holder has the lock. Distinct from a SQL error so callers can branch cleanly with errors.Is.
var ErrNoHandler = errors.New("drops/pg: OutboxWorker has no handler")
ErrNoHandler is returned by Run when neither OnEvent nor OnBatch was attached.
var ErrNoKeyring = errors.New("drops/pg: no Keyring registered; call SetKeyring first")
ErrNoKeyring signals that a Secret[T] was used without SetKeyring having been called.
var ErrNoMigrationsApplied = errors.New("drops/pg: no migrations applied")
ErrNoMigrationsApplied is returned by Down when the history table is empty.
var ErrNoReplicas = errors.New("drops/pg: no replicas configured")
ErrNoReplicas is returned by NewReplicated when called with a nil primary. Kept as a package-level value so handlers and config loaders can branch cleanly.
var ErrNoRows = errors.New("drops/pg: no rows in result set")
ErrNoRows is returned by One when the query produced no rows.
var ErrPKNotSet = errors.New("drops/pg: primary key field is the zero value")
ErrPKNotSet is returned by Update / Save when r's primary-key field is the zero value but the operation requires it to be set.
var ErrShardKeyMissing = errors.New("drops/pg: shard key missing; call pg.WithShardKey first")
ErrShardKeyMissing is returned when a sharded driver receives a request without a shard key on ctx. Surfacing this rather than picking a default prevents silent cross-shard data leaks.
var ErrStaleObject = errors.New("drops/pg: stale object — optimistic-lock version mismatch")
ErrStaleObject is returned by Update on an entity whose table declares an OptimisticLock column when no row matches both the PK and the supplied version — another transaction has bumped the version, or the row was deleted between read and write.
var ErrSubjectMissing = errors.New("drops/pg: entity is guarded but ctx has no subject")
ErrSubjectMissing is returned when a guarded entity is invoked on a ctx without WithSubject.
var ErrTenantMismatch = errors.New("drops/pg: row tenant disagrees with ctx tenant")
ErrTenantMismatch is returned by Create when r carries a tenant value that disagrees with the ctx tenant. Catches the "background job stamped the wrong tenant" class of bug.
var ErrTenantMissing = errors.New("drops/pg: entity is tenant-scoped but ctx has no tenant")
ErrTenantMissing is returned when an entity is scoped by tenant but ctx lacks one. Surfacing this error rather than silently running a cross-tenant query is the whole point of the feature.
ErrUnauthorized signals that an operation was rejected by the guard pipeline. Compared to a "no rows" outcome, this means the guard explicitly denied the request (e.g. a custom guard returned the error directly).
Functions ¶
func Abs ¶
func Abs(e any) drops.Expression
func Acos ¶
func Acos(e any) drops.Expression
func AdvisoryLockKey ¶ added in v0.2.0
AdvisoryLockKey returns the int64 key drops would use for the supplied string. Exposed so callers can pass the hashed value directly when they want full control of the lock identifier (e.g. to match a key generated elsewhere).
func Age ¶
func Age(args ...any) drops.Expression
Age renders age(<a>, <b>) — the interval between two timestamps. Pass only one timestamp to compute age(now(), ts).
func AllSub ¶
func AllSub(value, sub any) drops.Expression
AllSub renders <value> = ALL(<subquery>).
func AlterEnumAddValue ¶
func AlterEnumAddValue(enumName, value string, before, after string) drops.Expression
AlterEnumAddValue appends a new label to an existing enum (PG 9.1+). before/after are optional anchors; if both are empty the value is appended at the end.
func AlterEnumRenameValue ¶
func AlterEnumRenameValue(enumName, oldValue, newValue string) drops.Expression
AlterEnumRenameValue renames an existing enum label (PG 10+).
func And ¶
func And(preds ...drops.Expression) drops.Expression
And joins the predicates with AND. With no arguments it renders TRUE.
func AnySub ¶
func AnySub(value, sub any) drops.Expression
AnySub renders <value> = ANY(<subquery>). Use a subquery expression (typically SelectBuilder) as the right-hand side.
func ArrayAgg ¶
func ArrayAgg(e any) drops.Expression
func ArrayAppend ¶
func ArrayAppend(arr, v any) drops.Expression
func ArrayContainedIn ¶
func ArrayContainedIn(a, b any) drops.Expression
ArrayContainedIn renders <a> <@ <b>.
func ArrayContains ¶
func ArrayContains(a, b any) drops.Expression
ArrayContains renders <a> @> <b> (array containment).
func ArrayLength ¶
func ArrayLength(arr, dim any) drops.Expression
func ArrayLit ¶
func ArrayLit(values ...any) drops.Expression
ArrayLit renders an ARRAY[...] literal. Values may be expressions or Go values (bound as params).
func ArrayLower ¶
func ArrayLower(arr, dim any) drops.Expression
func ArrayOverlaps ¶
func ArrayOverlaps(a, b any) drops.Expression
ArrayOverlaps renders <a> && <b>.
func ArrayPosition ¶
func ArrayPosition(arr, v any) drops.Expression
func ArrayPositions ¶
func ArrayPositions(arr, v any) drops.Expression
func ArrayPrepend ¶
func ArrayPrepend(v, arr any) drops.Expression
func ArrayRemove ¶
func ArrayRemove(arr, v any) drops.Expression
func ArrayReplace ¶
func ArrayReplace(arr, oldV, newV any) drops.Expression
func ArrayToString ¶
func ArrayToString(arr, sep any) drops.Expression
func ArrayUpper ¶
func ArrayUpper(arr, dim any) drops.Expression
func As ¶
func As(e drops.Expression, alias string) drops.Expression
As renames an arbitrary expression: "<expr> AS <alias>".
func Asin ¶
func Asin(e any) drops.Expression
func AtTimeZone ¶
func AtTimeZone(ts, zone any) drops.Expression
AtTimeZone renders <ts> AT TIME ZONE <zone>.
func Atan ¶
func Atan(e any) drops.Expression
func Avg ¶
func Avg(e drops.Expression) drops.Expression
func AvgDistinct ¶
func AvgDistinct(e drops.Expression) drops.Expression
func Between ¶
func Between(left, low, high any) drops.Expression
Between renders "left BETWEEN low AND high".
func BoolOr ¶
func BoolOr(e any) drops.Expression
func Cardinality ¶
func Cardinality(arr any) drops.Expression
func Cast ¶
func Cast(e any, typeSQL string) drops.Expression
Cast renders <e>::<type> — the PostgreSQL shorthand for explicit type conversion. Equivalent to CAST(<e> AS <type>).
func CastAs ¶
func CastAs(e any, typeSQL string) drops.Expression
CastAs renders CAST(<e> AS <type>) — the standard-SQL form.
func Ceil ¶
func Ceil(e any) drops.Expression
func Coalesce ¶
func Coalesce(args ...any) drops.Expression
Coalesce renders coalesce(<args...>). Arguments may be Expressions or Go values (bound as parameters).
func ColumnExists ¶
ColumnExists reports whether a column exists on a table. schema may be empty to mean "public".
func CommentOnColumn ¶
func CommentOnColumn(c ColRef, text string) drops.Expression
CommentOnColumn returns COMMENT ON COLUMN <t>.<c> IS 'text'.
func CommentOnTable ¶
func CommentOnTable(t *Table, text string) drops.Expression
CommentOnTable returns COMMENT ON TABLE <t> IS 'text'. text must not contain unsanitised single quotes.
func ConcatOp ¶
func ConcatOp(left, right any) drops.Expression
ConcatOp renders the SQL || concatenation operator: (a || b).
func ConcatWS ¶
func ConcatWS(sep any, args ...any) drops.Expression
ConcatWS renders concat_ws(sep, args...).
func ConstraintExists ¶
ConstraintExists reports whether a named constraint exists on a table. schema may be empty to mean "public".
func CopyFrom ¶ added in v0.2.0
CopyFrom bulk-loads rs into the entity's table via the driver's COPY path. Returns the number of rows accepted. Validators run per row before any bytes hit the wire — bad input aborts the whole batch before the server is touched.
Bypasses the cache (COPY-loaded rows never populate it), the audit log (audit per row would defeat the bandwidth advantage), and the per-row INSERT hooks. Use Entity.CreateMany / UpsertMany when those guarantees matter; use CopyFrom when raw throughput is the point.
func Cos ¶
func Cos(e any) drops.Expression
func CosineDistance ¶
func CosineDistance(left, right any) drops.Expression
CosineDistance renders <col> <=> <vec>.
func CountDistinct ¶
func CountDistinct(e drops.Expression) drops.Expression
CountDistinct renders count(DISTINCT <e>).
func CreateEnum ¶
func CreateEnum(e *PgEnum) drops.Expression
CreateEnum returns a CREATE TYPE ... AS ENUM (...) statement.
func CreateExtension ¶
func CreateExtension(name string) drops.Expression
CreateExtension returns CREATE EXTENSION "name". Common values: "pgcrypto", "uuid-ossp", "postgis", "pg_trgm".
func CreateExtensionIfNotExists ¶
func CreateExtensionIfNotExists(name string) drops.Expression
CreateExtensionIfNotExists is the IF NOT EXISTS variant.
func CreateFunction ¶
func CreateFunction(name string, opts FunctionOptions) drops.Expression
CreateFunction returns a CREATE FUNCTION statement. The body is wrapped in $func$ delimiters so it may contain arbitrary single quotes.
func CreateIndex ¶
func CreateIndex(idx *Index) drops.Expression
CreateIndex returns the CREATE INDEX statement for idx.
func CreateIndexIfNotExists ¶
func CreateIndexIfNotExists(idx *Index) drops.Expression
CreateIndexIfNotExists is the IF NOT EXISTS variant.
func CreateIndexOnline ¶ added in v0.2.0
func CreateIndexOnline(idx *Index) drops.Expression
CreateIndexOnline marks idx as CONCURRENTLY and returns the CREATE INDEX expression. Convenience for online migrations:
stmt := pg.CreateIndexOnline(myIdx) _, err := db.ExecExpr(ctx, stmt)
PostgreSQL forbids CONCURRENTLY inside a transaction, so the caller must invoke it outside InTx — the analyzer will not complain about CONCURRENTLY statements, but a transaction containing one will fail at the database.
func CreateMaterializedView ¶
func CreateMaterializedView(name string, query drops.Expression, withData bool) drops.Expression
CreateMaterializedView returns CREATE MATERIALIZED VIEW. withData=false emits WITH NO DATA so the view is empty until first refreshed.
func CreateOrReplaceView ¶
func CreateOrReplaceView(name string, query drops.Expression) drops.Expression
CreateOrReplaceView returns CREATE OR REPLACE VIEW ...
func CreateSchema ¶
func CreateSchema(name string) drops.Expression
CreateSchema returns CREATE SCHEMA "name".
func CreateSchemaIfNotExists ¶
func CreateSchemaIfNotExists(name string) drops.Expression
CreateSchemaIfNotExists is the IF NOT EXISTS variant.
func CreateSequence ¶
func CreateSequence(name string, opts ...SequenceOptions) drops.Expression
CreateSequence returns a CREATE SEQUENCE statement.
func CreateSequenceIfNotExists ¶
func CreateSequenceIfNotExists(name string, opts ...SequenceOptions) drops.Expression
CreateSequenceIfNotExists is the IF NOT EXISTS variant.
func CreateTable ¶
func CreateTable(t *Table) drops.Expression
CreateTable returns a CREATE TABLE statement for t.
The generated SQL covers column types, NOT NULL, DEFAULT, UNIQUE, PRIMARY KEY (single-column only), and inline FOREIGN KEY references. More elaborate DDL — composite keys, indexes, partitioning — is out of scope; emit it via raw SQL.
func CreateTableIfNotExists ¶
func CreateTableIfNotExists(t *Table) drops.Expression
CreateTableIfNotExists is the IF NOT EXISTS variant.
func CreateTrigger ¶
func CreateTrigger(name string, opts TriggerOptions) drops.Expression
CreateTrigger returns a CREATE TRIGGER statement.
func CreateView ¶
func CreateView(name string, query drops.Expression) drops.Expression
CreateView returns CREATE VIEW "name" AS <select>.
func CumeDist ¶
func CumeDist() drops.Expression
func CurrentTimestamp ¶
func CurrentTimestamp() drops.Expression
CurrentTimestamp renders current_timestamp.
func DatePart ¶
func DatePart(field string, ts any) drops.Expression
DatePart renders date_part('field', <ts>) — the function form of EXTRACT.
func DateTrunc ¶
func DateTrunc(field string, ts any) drops.Expression
DateTrunc renders date_trunc('field', <ts>) — e.g. DateTrunc("day", col).
func Day ¶
func Day(n int) drops.Expression
Day / Hour / Minute / Second build INTERVAL literals from numeric n.
func Decode ¶
func Decode(text, format any) drops.Expression
Decode renders decode(<text>, <format>).
func DenseRank ¶
func DenseRank() drops.Expression
func Diff ¶
func Diff(prev, cur *Snapshot, opts ...DiffOptions) []string
Diff returns the ordered list of SQL statements that, applied in order, evolve a database from prev's schema to cur's. Output is deterministic for a given (prev, cur, opts) — keys are walked in sorted order — so re-running against the same input produces byte-identical SQL.
Operation order:
- DROP TABLE for tables removed entirely
- CREATE TABLE for new tables (column defs + inline UNIQUE only)
- ALTER TABLE for column-level changes on surviving tables (drop, add, type, NOT NULL, DEFAULT)
- UNIQUE constraint adds/drops on surviving tables
- FOREIGN KEY adds/drops on every table — emitted after CREATE TABLEs so cross-table references resolve.
func DiffDown ¶ added in v0.2.0
func DiffDown(prev, cur *Snapshot, opts ...DiffOptions) []string
DiffDown returns the SQL that reverses the migration from cur back to prev — applying these statements after the corresponding Diff(prev, cur) would restore the original schema. Provided as a distinct entry point so generated migration sets can carry the rollback alongside the forward direction without the caller having to swap arguments.
up := pg.Diff(prev, cur, opts) down := pg.DiffDown(prev, cur, opts) // = Diff(cur, prev, opts)
func DistanceFrom ¶ added in v0.2.0
func DistanceFrom(col ColRef, p Point) drops.Expression
DistanceFrom renders ST_Distance(col, point) — distance in metres when col is a geography column. Suitable for SELECT projections and ORDER BY:
q.OrderBy(pg.DistanceFrom(DriversTable.Col("position"), userLoc))
For nearest-N queries that should use the spatial KNN index, prefer NearestFrom (which emits the <-> operator).
func Div ¶
func Div(left, right any) drops.Expression
func DropEnumIfExists ¶
func DropEnumIfExists(name string) drops.Expression
DropEnumIfExists is the IF EXISTS variant.
func DropExtension ¶
func DropExtension(name string) drops.Expression
DropExtension returns DROP EXTENSION "name".
func DropExtensionIfExists ¶
func DropExtensionIfExists(name string) drops.Expression
DropExtensionIfExists is the IF EXISTS variant.
func DropFunction ¶
func DropFunction(name, args string) drops.Expression
DropFunction returns DROP FUNCTION "name"(args). args is the raw argument-types signature, e.g. "integer, integer".
func DropFunctionIfExists ¶
func DropFunctionIfExists(name, args string) drops.Expression
DropFunctionIfExists is the IF EXISTS variant.
func DropIndexConcurrently ¶
func DropIndexConcurrently(name string) drops.Expression
DropIndexConcurrently emits DROP INDEX CONCURRENTLY.
func DropIndexIfExists ¶
func DropIndexIfExists(name string) drops.Expression
DropIndexIfExists is the IF EXISTS variant.
func DropMaterializedView ¶
func DropMaterializedView(name string) drops.Expression
DropMaterializedView returns DROP MATERIALIZED VIEW "name".
func DropSchema ¶
func DropSchema(name string) drops.Expression
DropSchema returns DROP SCHEMA "name".
func DropSchemaIfExists ¶
func DropSchemaIfExists(name string, cascade bool) drops.Expression
DropSchemaIfExists is the IF EXISTS variant. Cascade=true appends CASCADE so dependent objects are dropped too.
func DropSequence ¶
func DropSequence(name string) drops.Expression
DropSequence returns DROP SEQUENCE "name".
func DropSequenceIfExists ¶
func DropSequenceIfExists(name string) drops.Expression
DropSequenceIfExists is the IF EXISTS variant.
func DropTable ¶
func DropTable(t *Table) drops.Expression
DropTable returns a DROP TABLE statement.
func DropTableIfExists ¶
func DropTableIfExists(t *Table) drops.Expression
DropTableIfExists is the IF EXISTS variant of DropTable.
func DropTrigger ¶
func DropTrigger(name string, table *Table) drops.Expression
DropTrigger returns DROP TRIGGER "name" ON <table>.
func DropTriggerIfExists ¶
func DropTriggerIfExists(name string, table *Table) drops.Expression
DropTriggerIfExists is the IF EXISTS variant.
func DropViewIfExists ¶
func DropViewIfExists(name string) drops.Expression
DropViewIfExists is the IF EXISTS variant.
func Encode ¶
func Encode(bytea, format any) drops.Expression
Encode renders encode(<bytea>, <format>) — format is 'base64', 'hex', or 'escape'.
func Eq ¶
func Eq(left, right any) drops.Expression
func Excluded ¶
func Excluded(c ColRef) drops.Expression
Excluded refers to a column in the EXCLUDED pseudo-table inside an ON CONFLICT update — i.e. the value that would have been inserted. Accepts either *Column or *Col[T] via the ColRef interface.
func Exp ¶
func Exp(e any) drops.Expression
func ExponentialJitter ¶ added in v0.2.0
ExponentialJitter returns a backoff that doubles each attempt starting from base, caps at max, and adds [0, base) jitter so concurrent retries don't synchronise into thundering herds.
attempt 1: base + jitter attempt 2: 2*base + jitter attempt 3: 4*base + jitter ... clipped at max + jitter
func Extract ¶
func Extract(field string, ts any) drops.Expression
Extract renders extract(<field> FROM <ts>).
func Filter ¶
func Filter(agg drops.Expression, pred drops.Expression) drops.Expression
Filter wraps an aggregate with a FILTER (WHERE ...) clause:
pg.Filter(pg.Count(UserID), pg.Eq(UserStatus, "active"))
func FirstValue ¶
func FirstValue(expr any) drops.Expression
func Floor ¶
func Floor(e any) drops.Expression
func ForEachShard ¶ added in v0.2.0
func ForEachShard(s *Sharded, ctx context.Context, fn func(shardIdx int, drv drops.Driver) error) []error
ForEachShard runs fn against every shard concurrently — the "scatter" half of scatter/gather. Use for cross-shard reads / admin tasks; results are aggregated by the caller. Errors are collected and returned per-shard.
The supplied ctx is passed to fn unchanged; if fn needs the shard-bound *DB it should call pg.New(drv) inside.
func Format ¶
func Format(format any, args ...any) drops.Expression
Format renders format(<fmt>, args...).
func FormatLSN ¶ added in v0.2.0
FormatLSN renders an LSN back into PG's "X/Y" text shape — the inverse of ParseLSN.
func Func ¶
func Func(name string, args ...any) drops.Expression
Func renders an arbitrary function call <name>(<args...>). Use it as an escape hatch when a built-in helper isn't provided.
func Gt ¶
func Gt(left, right any) drops.Expression
func Gte ¶
func Gte(left, right any) drops.Expression
func HammingDistance ¶
func HammingDistance(left, right any) drops.Expression
HammingDistance renders <col> <~> <vec> — bit-vector Hamming distance (BitVec columns only).
func HasDangerousMigration ¶ added in v0.2.0
HasDangerousMigration reports whether stmts contains at least one RiskDanger finding. Suitable as a CI gate.
func HashShardKey ¶ added in v0.2.0
HashShardKey is a convenience picker for string / []byte keys. Uses FNV-1a (the same hash as advisory locks) and modulo N.
sharded := pg.NewSharded(shards, pg.HashShardKey(len(shards)))
func Hour ¶
func Hour(n int) drops.Expression
func ILike ¶
func ILike(left, pattern any) drops.Expression
func In ¶
func In(left any, values ...any) drops.Expression
In renders "left IN (...)". A single slice argument is expanded so In(col, []int{1, 2, 3}) is equivalent to In(col, 1, 2, 3).
func InnerProduct ¶
func InnerProduct(left, right any) drops.Expression
InnerProduct renders <col> <#> <vec> — pgvector's negative inner product. Smaller is better; for raw inner product, negate the expression or use the cosine helper if your vectors are normalised.
func InstallChangeFeed ¶ added in v0.2.0
func InstallChangeFeed(t *Table, opts ...ChangeFeedOptions) ([]string, error)
InstallChangeFeed returns the DDL statements that wire a NOTIFY trigger onto t. The trigger fires AFTER INSERT/UPDATE/DELETE and emits a JSON payload of {"op": ..., "id": ...} on the channel.
Single-column primary keys only — composite PKs would need a different payload shape and are not yet supported.
func IntervalLit ¶
func IntervalLit(literal string) drops.Expression
IntervalLit renders an INTERVAL literal — e.g. IntervalLit("1 day"), IntervalLit("2 hours 30 minutes"). The value is wrapped in INTERVAL '...' with single quotes doubled.
Named with "Lit" to avoid a collision with the Interval(name) column type constructor in types.go.
func IsNotNull ¶
func IsNotNull(e any) drops.Expression
func IsNull ¶
func IsNull(e any) drops.Expression
func IsSagaError ¶ added in v0.2.0
IsSagaError reports whether err is a *SagaError.
func JSONArrayLength ¶
func JSONArrayLength(e any) drops.Expression
func JSONBAgg ¶
func JSONBAgg(e any) drops.Expression
func JSONBArrayLength ¶
func JSONBArrayLength(e any) drops.Expression
func JSONBBuildArray ¶
func JSONBBuildArray(args ...any) drops.Expression
func JSONBBuildObject ¶
func JSONBBuildObject(args ...any) drops.Expression
JSONBBuildObject / JSONBBuildArray are the jsonb variants.
func JSONBContainedIn ¶
func JSONBContainedIn(a, b any) drops.Expression
JSONBContainedIn renders <a> <@ <b>.
func JSONBContains ¶
func JSONBContains(a, b any) drops.Expression
JSONBContains renders <a> @> <b> (does a contain b? jsonb only).
func JSONBHasAllKeys ¶
func JSONBHasAllKeys(e, keys any) drops.Expression
JSONBHasAllKeys renders <e> ?& <keys>.
func JSONBHasAnyKey ¶
func JSONBHasAnyKey(e, keys any) drops.Expression
JSONBHasAnyKey renders <e> ?| <keys> (keys is text[]).
func JSONBInsert ¶
func JSONBInsert(target, path, newVal any, insertAfter ...bool) drops.Expression
JSONBInsert renders jsonb_insert(<target>, <path>, <newVal>, [<insertAfter>]).
func JSONBObjectAgg ¶
func JSONBObjectAgg(k, v any) drops.Expression
func JSONBSet ¶
func JSONBSet(target, path, value any, createMissing ...bool) drops.Expression
JSONBSet renders jsonb_set(<target>, <path>, <value>, [<createMissing>]).
func JSONBStripNulls ¶
func JSONBStripNulls(e any) drops.Expression
JSONBStripNulls renders jsonb_strip_nulls(<e>).
func JSONBTypeof ¶
func JSONBTypeof(e any) drops.Expression
func JSONBuildArray ¶
func JSONBuildArray(args ...any) drops.Expression
JSONBuildArray renders json_build_array(args...).
func JSONBuildObject ¶
func JSONBuildObject(args ...any) drops.Expression
JSONBuildObject renders json_build_object(args...). Pairs are key/value: JSONBuildObject("name", UserName, "age", UserAge).
func JSONContains ¶ added in v0.2.0
func JSONContains(col ColRef, value any) drops.Expression
JSONContains renders "col @> $1" — the jsonb containment operator. Accepts anything that drivers can serialise as jsonb (json.RawMessage, []byte, or a marshaled struct value).
func JSONGet ¶
func JSONGet(e, key any) drops.Expression
JSONGet renders <e> -> <key> (JSON object/array element, returns json). key may be a string (object key) or int (array index).
func JSONGetPath ¶ added in v0.2.0
func JSONGetPath(e, path any) drops.Expression
JSONGetPath renders <e> #> <path> (path is text[] — pass a Go []string). Renamed from JSONPath to free that name for the typed accessor in jsonpath.go.
func JSONGetPathText ¶ added in v0.2.0
func JSONGetPathText(e, path any) drops.Expression
JSONGetPathText renders <e> #>> <path>.
func JSONGetText ¶
func JSONGetText(e, key any) drops.Expression
JSONGetText renders <e> ->> <key> (as text).
func JSONHasAllKeys ¶ added in v0.2.0
func JSONHasAllKeys(col ColRef, keys []string) drops.Expression
JSONHasAllKeys renders "col ?& $1" — true only when every key in keys is present at the top level.
func JSONHasAnyKey ¶ added in v0.2.0
func JSONHasAnyKey(col ColRef, keys []string) drops.Expression
JSONHasAnyKey renders "col ?| $1" — true when any of keys is present at the jsonb top level.
func JSONHasKey ¶ added in v0.2.0
func JSONHasKey(col ColRef, key string) drops.Expression
JSONHasKey renders "col ? $1" — the jsonb key-existence operator.
func JSONTypeof ¶
func JSONTypeof(e any) drops.Expression
func JaccardDistance ¶
func JaccardDistance(left, right any) drops.Expression
JaccardDistance renders <col> <%> <vec> — bit-vector Jaccard distance.
func L1Distance ¶
func L1Distance(left, right any) drops.Expression
L1Distance renders <col> <+> <vec> — Manhattan distance.
func L2Distance ¶
func L2Distance(left, right any) drops.Expression
L2Distance renders <col> <-> <vec> — Euclidean distance. The right-hand side is typically a Go []float32 (bound as a param) or another vector column.
func Lag ¶
func Lag(expr any, args ...any) drops.Expression
Lag renders lag(expr [, offset [, default]]).
func LastValue ¶
func LastValue(expr any) drops.Expression
func Lead ¶
func Lead(expr any, args ...any) drops.Expression
Lead renders lead(expr [, offset [, default]]).
func Like ¶
func Like(left, pattern any) drops.Expression
func Listen ¶ added in v0.2.0
Listen subscribes to channel and returns a typed channel that receives decoded T values. Payloads that fail JSON decoding are silently dropped — a misaligned producer is a deployment bug, not a per-message error.
The returned channel closes when ctx is done or the driver's underlying subscription terminates. Spawn one goroutine per channel; combine with select to multiplex many channels.
func Ln ¶
func Ln(e any) drops.Expression
func LocalTimestamp ¶
func LocalTimestamp() drops.Expression
func Log ¶
func Log(e any) drops.Expression
func LoggerHook ¶
func LoggerHook(log LoggerFunc, opts ...LoggerOptions) drops.Hook
LoggerHook re-exports drops.LoggerHook. See its documentation for behaviour and tuning options.
func Lt ¶
func Lt(left, right any) drops.Expression
func Lte ¶
func Lte(left, right any) drops.Expression
func MakeDate ¶
func MakeDate(y, m, d any) drops.Expression
MakeDate renders make_date(<y>, <m>, <d>).
func MakeTime ¶
func MakeTime(h, m, s any) drops.Expression
MakeTime renders make_time(<h>, <m>, <s>).
func MakeTimestamp ¶
func MakeTimestamp(args ...any) drops.Expression
MakeTimestamp renders make_timestamp(y, mo, d, h, mi, s).
func MakeTimestampTZ ¶
func MakeTimestampTZ(args ...any) drops.Expression
MakeTimestampTZ is the TZ-aware variant.
func Max ¶
func Max(e drops.Expression) drops.Expression
func MermaidDiagram ¶ added in v0.2.0
MermaidDiagram renders the schema as a Mermaid `erDiagram` block. Pipe it through any Mermaid-aware renderer (web preview tools, Markdown viewers, IDE previews) for an up-to-date ER diagram driven directly by the table declarations.
fmt.Println(pg.MermaidDiagram(pg.NewSchema(Users, Posts)))
// erDiagram
// USERS {
// bigserial id PK
// text name
// }
// POSTS {
// bigserial id PK
// bigint userId FK
// }
// USERS ||--o{ POSTS : posts
Cardinality marks come from the registered Relation metadata:
HasMany → ||--o{
HasOne → ||--o|
BelongsTo → rendered from the parent side as the inverse
ManyToMany → }o--o{ (with the junction omitted for clarity)
MorphTo → rendered as one edge per registered morph entry
func Min ¶
func Min(e drops.Expression) drops.Expression
func Minus ¶
func Minus(left, right any) drops.Expression
func Minute ¶
func Minute(n int) drops.Expression
func Mod ¶
func Mod(a, b any) drops.Expression
func Month ¶
func Month(n int) drops.Expression
func Mul ¶
func Mul(left, right any) drops.Expression
func N1Hook ¶ added in v0.2.0
func N1Hook(ctx context.Context, e drops.QueryEvent)
N1Hook is a drops.Hook that records every query into the tracker attached to ctx by WithN1Detector. Without a tracker the hook is a no-op, so attaching it globally to the DB is free for untracked traffic.
func Ne ¶
func Ne(left, right any) drops.Expression
func NearestFrom ¶ added in v0.2.0
func NearestFrom(col ColRef, p Point) drops.Expression
NearestFrom emits the `<->` operator (KNN distance) which PostgreSQL can plan against a GiST or SP-GiST index on col. Use as an ORDER BY term; the result is ordered by closest-first.
func NextVal ¶
func NextVal(name string) drops.Expression
NextVal returns the SQL expression nextval('"name"'::regclass).
func NotExists ¶
func NotExists(q drops.Expression) drops.Expression
NotExists renders NOT EXISTS (<subquery>).
func NotIn ¶
func NotIn(left any, values ...any) drops.Expression
NotIn renders "left NOT IN (...)".
func Notify ¶ added in v0.2.0
Notify publishes payload on channel. The payload is JSON-encoded before being handed to pg_notify, so any encodable value works — string, struct, json.RawMessage. Empty channel names error at the call site rather than at the database.
PostgreSQL caps NOTIFY payloads at 8000 bytes; anything larger either truncates or errors depending on driver. For larger payloads emit a row id and have the consumer fetch the row.
func NthValue ¶
func NthValue(expr, n any) drops.Expression
func Ntile ¶
func Ntile(n any) drops.Expression
func Or ¶
func Or(preds ...drops.Expression) drops.Expression
Or joins the predicates with OR. With no arguments it renders FALSE.
func Over ¶
func Over(fn drops.Expression, win *Window) drops.Expression
Over wraps an aggregate or window function with an OVER clause.
pg.Over(pg.RowNumber(),
pg.WindowSpec().PartitionBy(UserID).OrderBy(PostCreatedAt.Desc()))
func PII ¶ added in v0.2.0
PII wraps value so it travels through drops as a redaction marker. Use it in raw queries when you don't have an Entity column to tag:
db.Exec(ctx, "UPDATE users SET password = $1 WHERE id = $2",
pg.PII(hashedPw), id)
func ParseLSN ¶ added in v0.2.0
ParseLSN converts PG's "X/Y" hex-pair LSN text format into the underlying byte position. Returns an error on malformed input. Exposed so tests and tooling can build LSN values without going through the driver.
func ParseMigrationName ¶
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 PercentRank ¶
func PercentRank() drops.Expression
func Plus ¶
func Plus(left, right any) drops.Expression
Plus, Minus, Mul, Div: arithmetic operators as parenthesised binary expressions. Useful for column-arithmetic in SELECT lists and updates.
func Position ¶
func Position(substring, str any) drops.Expression
Position renders position(<substring> IN <string>).
func Power ¶
func Power(a, b any) drops.Expression
func Rank ¶
func Rank() drops.Expression
func RefreshMaterializedView ¶
func RefreshMaterializedView(name string, concurrently bool) drops.Expression
RefreshMaterializedView returns REFRESH MATERIALIZED VIEW. concurrently emits the CONCURRENTLY keyword (PG 9.4+) which requires a UNIQUE index.
func RegexpMatch ¶
func RegexpMatch(e, pattern any) drops.Expression
RegexpMatch renders regexp_match(<e>, <pattern>).
func RegexpReplace ¶
func RegexpReplace(e, pattern, replacement any, flags ...string) drops.Expression
RegexpReplace renders regexp_replace(<e>, <pattern>, <replacement>, [<flags>]).
func Replace ¶
func Replace(e, from, to any) drops.Expression
Replace renders replace(<e>, <from>, <to>).
func Round ¶
func Round(e any, digits ...int) drops.Expression
Round renders round(<e>) or round(<e>, <digits>) when digits is non-nil.
func RowNumber ¶
func RowNumber() drops.Expression
func RunJSON ¶ added in v0.2.0
func RunJSON[T any]( s *IdempotencyStore, ctx context.Context, key string, fn func(tx *DB) (T, error), ) (T, error)
RunJSON wraps Run with JSON marshalling on both sides. fn returns a typed result; Run handles the serialisation. Subsequent calls unmarshal the cached bytes back into T.
func SagaStateGet ¶ added in v0.2.0
SagaStateGet is the type-safe getter. Returns the zero value of T plus ok=false when the key is missing OR the stored value is the wrong type.
func ScanAll ¶ added in v0.2.0
ScanAll consumes every row from rows into dest (pointer to slice of struct or *struct). Exported for the same reason as ScanOne.
func ScanOne ¶ added in v0.2.0
ScanOne consumes the first row from rows into dest (pointer to struct), returning ErrNoRows when the cursor is empty. Exported for code generators (cmd/dropsgen sql) that want the reflection scanner without going through a builder.
func SchemaExists ¶
SchemaExists reports whether the named PostgreSQL schema exists.
func Second ¶
func Second(n int) drops.Expression
func SetKeyring ¶ added in v0.2.0
func SetKeyring(k Keyring)
SetKeyring registers the active keyring used by Secret[T] for (de)serialisation. Call once at startup, before issuing the first query. Passing nil clears the keyring — subsequent Secret[T].Value / Scan calls then return ErrNoKeyring.
func SetVal ¶
func SetVal(name string, value any) drops.Expression
SetVal returns setval('"name"', value).
func ShardKeyFrom ¶ added in v0.2.0
ShardKeyFrom returns the shard key stored on ctx, if any.
func Sign ¶
func Sign(e any) drops.Expression
func Sqrt ¶
func Sqrt(e any) drops.Expression
func StrPos ¶
func StrPos(str, substring any) drops.Expression
StrPos renders strpos(<string>, <substring>).
func StringAgg ¶
func StringAgg(e, sep any) drops.Expression
StringAgg renders string_agg(<e>, <sep>).
func StringToArray ¶
func StringToArray(str, sep any) drops.Expression
func SubjectFrom ¶ added in v0.2.0
SubjectFrom returns the subject on ctx and ok=true when set.
func Subquery ¶
func Subquery(q drops.Expression) drops.Expression
Subquery wraps an expression (typically a SELECT) in parentheses for use as a scalar subquery.
func Subscribe ¶ added in v0.2.0
func Subscribe[T any](db *DB, ctx context.Context, e *Entity[T], opts ...SubscribeOptions) (<-chan TypedChange[T], error)
Subscribe returns a typed channel of change events for the entity's table. The channel closes when ctx is done or the driver's underlying LISTEN terminates.
drops dispatches via the Listener interface (see listen.go). Drivers that don't expose listen return ErrListenNotSupported.
func Substring ¶
func Substring(e any, from any, count any) drops.Expression
Substring renders substring(<e> FROM <from> FOR <count>). count may be nil to omit the FOR clause.
func SumDistinct ¶
func SumDistinct(e drops.Expression) drops.Expression
SumDistinct / AvgDistinct apply DISTINCT to the aggregate.
func SupportsCopy ¶ added in v0.2.0
SupportsCopy reports whether the driver behind db exposes the Copier interface. Useful for code paths that want to choose between CopyFrom and CreateMany at runtime.
func SupportsListen ¶ added in v0.2.0
SupportsListen reports whether db's driver implements Listener. Useful for code paths that want to choose between Listen-based push and polling.
func SupportsPoolStats ¶ added in v0.2.0
SupportsPoolStats reports whether the underlying driver implements PoolStatsProvider. Useful for code paths that want to register metrics only when introspection is available.
func TableExists ¶
TableExists reports whether a table exists in the given schema. schema may be empty to mean "public".
func Tan ¶
func Tan(e any) drops.Expression
func TenantFrom ¶ added in v0.2.0
TenantFrom returns the tenant on ctx (and ok=false when absent).
func TestTx ¶ added in v0.2.0
TestTx runs fn inside a freshly-opened transaction that is unconditionally rolled back at the end of the test. The handle passed to fn is a *DB scoped to the transaction; every Exec / Query / Entity operation against it lives or dies with the rollback — the underlying schema and rows are untouched after the test returns.
pg.TestTx(t, db, ctx, func(tx *pg.DB) {
if err := UserEntity.Create(tx, ctx, &u); err != nil {
t.Fatalf("create: %v", err)
}
...
})
Use it to keep test cases hermetic without writing manual setup / teardown. Tests that need to verify post-commit behaviour (triggers that look at xact id, etc.) should open a transaction directly via db.Begin instead.
func ToChar ¶
func ToChar(value, pattern any) drops.Expression
ToChar renders to_char(<value>, <pattern>).
func ToDate ¶
func ToDate(text, pattern any) drops.Expression
ToDate / ToTimestamp / ToNumber — text conversion helpers.
func ToJSON ¶
func ToJSON(e any) drops.Expression
func ToJSONB ¶
func ToJSONB(e any) drops.Expression
func ToNumber ¶
func ToNumber(text, pattern any) drops.Expression
func ToTimestamp ¶
func ToTimestamp(text, pattern any) drops.Expression
func TryWithAdvisoryLock ¶ added in v0.2.0
TryWithAdvisoryLock is the non-blocking variant: returns ErrLockNotAcquired when someone else holds the lock. Useful for "elected leader per tick" patterns where missing the election is better than waiting.
func UninstallChangeFeed ¶ added in v0.2.0
UninstallChangeFeed returns the DDL to remove a previously- installed feed on t.
func Unnest ¶
func Unnest(arr any) drops.Expression
func Upper ¶
func Upper(e drops.Expression) drops.Expression
func Week ¶
func Week(n int) drops.Expression
func WithActor ¶ added in v0.2.0
WithActor annotates ctx with an actor identifier. Pass anything that fmt prints sensibly (string id, int64 user id, struct implementing Stringer).
func WithAdvisoryLock ¶ added in v0.2.0
WithAdvisoryLock opens a transaction, takes the lock keyed by key (FNV-hashed to int64), runs fn against the tx, and releases the lock when the tx ends. Blocks until the lock is free or ctx is cancelled.
func WithN1Detector ¶ added in v0.2.0
WithN1Detector returns a derived context that records every SQL statement issued through pg.DB. Call the returned finisher with a threshold to produce the report; typically wired up in a `defer` so it runs once at the end of the request / job.
func WithReadYourWrites ¶ added in v0.2.0
WithReadYourWrites annotates ctx with a sticky read-your-writes window. The window arms automatically on the first Exec / Replicated.Exec through this context and persists for d after every subsequent write. Reads done within the window go to the primary so callers always observe their own writes.
Pass d=0 to clear the window from a derived context.
func WithShardKey ¶ added in v0.2.0
WithShardKey annotates ctx with the value the picker uses to choose a shard. Typically the user id, customer id, or geographic region.
func WithSubject ¶ added in v0.2.0
WithSubject annotates ctx with the acting subject — typically the user id of the caller. Distinct from WithActor (which records "who did this" for audit): an admin impersonating a user has the user as subject (so authz checks apply to the user) but the admin as actor (so the audit trail captures the real actor).
func WithTenant ¶ added in v0.2.0
WithTenant returns a context that carries tenant. Pass anything drivers can bind — a string id, int64 user id, UUID, or struct implementing driver.Valuer.
func Within ¶ added in v0.2.0
func Within(col ColRef, box Box) drops.Expression
Within renders ST_Within(col, ST_MakeEnvelope(...)::geography), the canonical "is point inside box" predicate. The box is implicit-cast to geography so the result respects the SRID declared on col.
func WithinRadius ¶ added in v0.2.0
func WithinRadius(col ColRef, p Point, metres float64) drops.Expression
WithinRadius renders ST_DWithin(col, point, metres) — true when col is within metres of point. Uses the spherical / spheroidal distance for geography columns, so the result matches the canonical "X km radius" semantics.
func Year ¶
func Year(n int) drops.Expression
Types ¶
type AggregateRef ¶ added in v0.2.0
AggregateRef identifies an aggregate that has pending outbox work.
type AggregateSnapshot ¶ added in v0.2.0
type AggregateSnapshot struct {
AggregateType string
AggregateID string
Version int64
State json.RawMessage
CreatedAt time.Time
}
AggregateSnapshot persists the materialised state of an aggregate at a specific version so reads avoid replaying every event since the beginning of time. Optional — small aggregates can replay fast enough without.
type AuditCols ¶ added in v0.2.0
AuditCols holds the typed handles created by Audit. The type parameter mirrors the referenced PK column.
func Audit ¶ added in v0.2.0
Audit appends nullable "createdBy" and "updatedBy" columns to t and declares foreign keys against target — typically a users.id PK. The referencing columns' SQL type is derived from target; serial-family types are mapped to their underlying integer type (bigserial→bigint, serial→integer, smallserial→smallint).
type AuditEvent ¶ added in v0.2.0
type AuditEvent struct {
Entity string // table name
Op string // "create" | "update" | "delete"
PK json.RawMessage // pk value, JSON-encoded
Payload json.RawMessage // row snapshot (Create / Update only)
Actor string // from ctx via WithActor, "" if absent
}
AuditEvent is the row written per mutation.
type AuditLog ¶ added in v0.2.0
type AuditLog struct {
// contains filtered or unexported fields
}
AuditLog records who-changed-what-when for every Create / Update / Delete on the entities attached to it. The audit row is written in the SAME transaction as the business mutation, so a rollback rolls back both — required for any compliance regime where audit trails must be authoritative.
audit := pg.NewAuditLog(db, "audit_events") pg.WithAudit(UserEntity, audit) pg.WithAudit(PostEntity, audit)
The actor is read from ctx via pg.WithActor:
ctx = pg.WithActor(ctx, currentUserID)
UserEntity.Update(db, ctx, &u)
// inserts an audit row: (entity=users, op=update,
// pk=42, payload={...},
// actor=currentUserID, createdAt=now())
func NewAuditLog ¶ added in v0.2.0
NewAuditLog binds the log to db and a destination table. Pair with NewAuditTable() to provision matching DDL.
type AuditMixin ¶ added in v0.2.0
AuditMixin registers nullable "createdBy" / "updatedBy" foreign keys to target — typically a users.id PK — and exposes typed handles to the rest of the application. Audit information is populated by the caller (e.g. via context-aware middleware); the mixin itself does not infer the current user.
func (*AuditMixin[T]) Apply ¶ added in v0.2.0
func (m *AuditMixin[T]) Apply(t *Table)
Apply implements Mixin.
type Backfill ¶ added in v0.2.0
type Backfill struct {
// contains filtered or unexported fields
}
Backfill orchestrates the chunk loop.
func NewBackfill ¶ added in v0.2.0
NewBackfill returns a Backfill bound to db. Name is the unique state key used for resuming across process restarts; choose something descriptive ("playerRegionFill-2026Q2") so the entry in the state table is self-documenting.
func (*Backfill) ChunkSize ¶ added in v0.2.0
ChunkSize sets the per-chunk row cap. Default 1000. Larger chunks finish faster but hold locks longer and inflate WAL replication volume; smaller chunks are gentler but extend wall-clock time.
func (*Backfill) Fetch ¶ added in v0.2.0
func (b *Backfill) Fetch(fn func(ctx context.Context, lastID int64, limit int) ([]int64, int64, error)) *Backfill
Fetch installs the chunk-fetching callback. It receives the last processed ID and a limit; returns the next batch of IDs, the new last-ID (typically max(ids)), and any error. Return an empty slice to signal completion.
func (*Backfill) OnProgress ¶ added in v0.2.0
OnProgress wires a progress callback fired after each successful chunk commit. The second argument is the latest processed ID so callers can render an ETA against the table's max(id).
func (*Backfill) PauseIfLag ¶ added in v0.2.0
func (b *Backfill) PauseIfLag(repl *Replicated, thresholdBytes uint64) *Backfill
PauseIfLag installs a gate that delays the next chunk while the configured replica set's lag exceeds threshold bytes. Pairs with Replicated.WithLSNTracking — the gate reuses the same primary / replica handles.
func (*Backfill) Process ¶ added in v0.2.0
Process installs the per-chunk worker. The callback runs inside a transaction so partial-chunk failures roll back cleanly.
func (*Backfill) Reset ¶ added in v0.2.0
Reset clears persisted state for the job. Run once before re-executing a completed backfill from scratch.
func (*Backfill) Run ¶ added in v0.2.0
Run drives the backfill loop until the Fetch callback returns an empty batch, ctx is cancelled, or a chunk returns an error. State is persisted between chunks so a crash can resume from the last successful commit.
func (*Backfill) StateTable ¶ added in v0.2.0
StateTable overrides the state table name. Default "backfillJobs".
type BackfillStatus ¶ added in v0.2.0
type BackfillStatus struct {
Name string
LastID int64
Processed int64
CompletedAt *time.Time
UpdatedAt time.Time
LastError string
}
BackfillStatus describes the persisted state of a backfill job.
type Box ¶ added in v0.2.0
Box is an axis-aligned bounding box defined by its south-west / north-east corners.
type Budget ¶ added in v0.2.0
Budget caps the cost of each Entity operation so a single typo or runaway query can't take down the database. Configure one via (*Entity[T]).WithBudget. Zero-valued fields disable that individual limit.
UserEntity.WithBudget(pg.Budget{
MaxArgs: 1000, // catch huge IN clauses early
MaxRows: 10_000, // bound result-set size
MaxDuration: 250 * time.Millisecond,
})
MaxArgs is checked after SQL rendering; MaxRows is enforced by auto-injecting a LIMIT clause on EntityQuery.All when the user hasn't already supplied a tighter one; MaxDuration wraps the caller's context with a deadline.
Get / One / Update / Delete operate on a single row and so bypass MaxRows (they always cap at one). Stream and Page are explicitly paginated and ignore MaxRows. Bulk writes (CreateMany / UpsertMany) are honoured by MaxArgs and MaxDuration but not MaxRows (which is a SELECT concept).
type CTE ¶
type CTE struct {
// contains filtered or unexported fields
}
CTE describes one common table expression.
func CTEDef ¶
func CTEDef(name string, query drops.Expression, columns ...string) *CTE
CTEDef returns a CTE definition with optional column aliasing.
func (*CTE) Col ¶
func (c *CTE) Col(col string) drops.Expression
Col returns a column reference inside the CTE: "<cte>"."<col>".
func (*CTE) Ref ¶
func (c *CTE) Ref() drops.Expression
Ref returns an expression that references the CTE as a relation — useful inside JOIN/FROM clauses on subsequent SELECTs.
type CaseExpr ¶
type CaseExpr struct {
// contains filtered or unexported fields
}
CaseExpr is the in-progress CASE expression.
func Case ¶
func Case() *CaseExpr
Case begins a CASE expression. Chain When / Else / End to finish.
pg.Case().
When(UserAge.Lt(18), "minor").
When(UserAge.Lt(65), "adult").
Else("senior").
End()
type ChangeEvent ¶ added in v0.2.0
type ChangeEvent struct {
// Op is the SQL operation — INSERT, UPDATE, DELETE.
Op ChangeOp `json:"op"`
// ID is the primary-key value of the affected row, coerced
// to text by the trigger so heterogeneous PKs (int / uuid /
// text) flow through the same channel.
ID string `json:"id"`
}
ChangeEvent is one row change captured by the trigger, before any typed hydration. Subscribe[T] wraps it in TypedChange[T] with the row fetched.
func (*ChangeEvent) MarshalJSON ¶ added in v0.2.0
func (e *ChangeEvent) MarshalJSON() ([]byte, error)
MarshalJSON renders the event as `{"op":...,"id":...}`.
func (*ChangeEvent) UnmarshalJSON ¶ added in v0.2.0
func (e *ChangeEvent) UnmarshalJSON(data []byte) error
UnmarshalJSON parses a payload of `{"op":...,"id":...}`.
type ChangeFeedOptions ¶ added in v0.2.0
type ChangeFeedOptions struct {
// Channel is the pg_notify channel name. Defaults to
// "drops_<tablename>" — derived from the table so multiple
// feeds coexist in the same database.
Channel string
}
ChangeFeedOptions tunes the trigger DDL produced by InstallChangeFeed.
type ChangeOp ¶ added in v0.2.0
type ChangeOp string
ChangeOp is the kind of mutation captured by the trigger.
type CheckSnapshot ¶ added in v0.2.0
CheckSnapshot is one entry in TableSnapshot.CheckConstraints. Value is the SQL expression after CHECK (...).
type Col ¶
Col is the typed handle for a column whose Go value type is T.
It embeds *Column so it implements drops.Expression and exposes Asc/Desc/As; its own methods (NotNull, PrimaryKey, Eq, In, Val, ...) preserve the type parameter so the chain stays typed end-to-end.
func Add ¶
Add registers c with t and returns it. It is the primary way to attach columns to a table — type inference keeps the *Col[T] handle typed:
var Users = pg.NewTable("users")
var (
UserID = pg.Add(Users, pg.BigSerial("id").PrimaryKey()) // *Col[int64]
UserName = pg.Add(Users, pg.Text("name").NotNull()) // *Col[string]
UserAge = pg.Add(Users, pg.Integer("age")) // *Col[int32]
)
Go does not allow generic methods, so Add lives as a free function.
Example ¶
ExampleAdd shows the typical schema-declaration pattern: NewTable followed by package-level pg.Add calls, each binding a typed column to the table. Type inference keeps the column handles typed (*pg.Col[int64], *pg.Col[string], …) so subsequent comparisons and value bindings are compile-time checked.
package main
import (
"fmt"
"github.com/bernardoforcillo/drops/pg"
)
func main() {
products := pg.NewTable("products")
id := pg.Add(products, pg.BigSerial("id").PrimaryKey())
name := pg.Add(products, pg.Text("name").NotNull())
priceCents := pg.Add(products, pg.Integer("price_cents").NotNull())
fmt.Printf("%s.%s, %s.%s, %s.%s\n",
products.Name(), id.Name(),
products.Name(), name.Name(),
products.Name(), priceCents.Name(),
)
}
Output: products.id, products.name, products.price_cents
func Custom ¶
Custom creates a column with an arbitrary type literal. Specify the Go value type as the type parameter — e.g. pg.Custom[string]("status", "user_status_enum").
func DoublePrecision ¶
func HalfVec ¶
HalfVec returns a halfvec(N) column (half-precision float). The Go value type stays []float32; the driver converts on the wire.
func Numeric ¶
Numeric returns NUMERIC(precision, scale) — represented as string so arbitrary-precision values aren't truncated. precision=0 means unconstrained NUMERIC.
func SparseVec ¶
SparseVec returns a sparsevec(N) column. Encoding is driver-specific; represented as string for portability.
func Vector ¶
Vector returns a vector(N) column. The Go value type is []float32 — the same shape pgvector exposes through pgx and lib/pq's text codec.
func (*Col[T]) AsPII ¶ added in v0.2.0
AsPII flags the column as carrying PII. Entity binders wrap values for this column so any logger / tracer formatting them sees "<redacted>" instead of the real value. The wire path downstream of db.Exec / db.Query is unchanged — the driver receives the unwrapped value.
func (*Col[T]) Between ¶
func (c *Col[T]) Between(lo, hi T) drops.Expression
func (*Col[T]) Cosine ¶
func (c *Col[T]) Cosine(v any) drops.Expression
Cosine is the method form of CosineDistance.
func (*Col[T]) Default ¶
Default sets a raw SQL default expression — e.g. "now()", "0", "'pending'". PostgreSQL DEFAULT clauses cannot be parameterised.
func (*Col[T]) Eq ¶
func (c *Col[T]) Eq(v T) drops.Expression
Example ¶
ExampleEq shows the type-safe comparison shorthand on a typed column.
package main
import (
"fmt"
"github.com/bernardoforcillo/drops"
"github.com/bernardoforcillo/drops/pg"
)
// Schema fixtures used by the examples. Declaring them at package level
// mirrors how a real application stores its schema and lets every
// example reuse the same definitions.
var (
exUsers = pg.NewTable("users")
exUserName = pg.Add(exUsers, pg.Text("name").NotNull())
)
func main() {
sql, args := drops.String(exUserName.Eq("Alice"))
fmt.Println(sql)
fmt.Println(args)
}
Output: ("users"."name" = $1) [Alice]
func (*Col[T]) Excluded ¶
func (c *Col[T]) Excluded() drops.Expression
Excluded returns an EXCLUDED.<col> reference for use inside an ON CONFLICT DO UPDATE clause.
func (*Col[T]) Expr ¶
func (c *Col[T]) Expr(e drops.Expression) ColumnValue
Expr binds an arbitrary expression to the column.
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]) IP ¶
func (c *Col[T]) IP(v any) drops.Expression
IP is the method form of InnerProduct.
func (*Col[T]) In ¶
func (c *Col[T]) In(values ...T) drops.Expression
func (*Col[T]) IsNotNull ¶
func (c *Col[T]) IsNotNull() drops.Expression
func (*Col[T]) IsNull ¶
func (c *Col[T]) IsNull() drops.Expression
func (*Col[T]) L1 ¶
func (c *Col[T]) L1(v any) drops.Expression
L1 is the method form of L1Distance.
func (*Col[T]) L2 ¶
func (c *Col[T]) L2(v any) drops.Expression
L2 is the method form of L2Distance.
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]) NotIn ¶
func (c *Col[T]) NotIn(values ...T) drops.Expression
func (*Col[T]) OptimisticLock ¶ added in v0.2.0
OptimisticLock marks the column as the version column for optimistic locking. When an Entity bound to the table issues an UPDATE, it automatically guards with "AND version = current" and bumps the column ("SET version = version + 1"). If no row matches the version, ErrStaleObject is returned. Apply this to a single integer column per table.
func (*Col[T]) PrimaryKey ¶
func (*Col[T]) References ¶
References declares a foreign-key constraint to a target column. The target's value type must match — type inference catches mismatches at declaration time.
func (*Col[T]) SetDefault ¶
func (c *Col[T]) SetDefault() ColumnValue
SetDefault binds the SQL DEFAULT keyword.
func (*Col[T]) Val ¶
func (c *Col[T]) Val(v T) ColumnValue
Val binds a typed value as the column's payload in an INSERT row or UPDATE assignment.
type ColRef ¶
type ColRef interface {
drops.Expression
// contains filtered or unexported methods
}
ColRef is implemented by *Column and *Col[T]. It is the type-erased column reference used by APIs that don't depend on the column's Go value type — JOIN ON wiring, ON CONFLICT targets, EXCLUDED references.
type Column ¶
type Column struct {
// contains filtered or unexported fields
}
Column is the type-erased AST node for a column reference. It is registered with a Table and can be written into a drops.Builder.
Most user code holds a *Col[T] instead, which embeds *Column and adds type-safe builder and operator methods. The untyped Column exists so table column lists can be heterogeneous and so generic methods (Go does not allow them on non-generic types) need not be added to Table.
func (*Column) As ¶
func (c *Column) As(alias string) drops.Expression
As returns an aliased column expression: "<col>" AS "<alias>".
func (*Column) Asc ¶
func (c *Column) Asc() drops.Expression
Asc / Desc produce ORDER BY direction expressions.
func (*Column) DefaultSQL ¶
DefaultSQL returns the raw SQL DEFAULT expression.
func (*Column) Desc ¶
func (c *Column) Desc() drops.Expression
func (*Column) ForeignKey ¶
ForeignKey returns the foreign-key reference, or nil if none.
func (*Column) HasDefault ¶
HasDefault reports whether a DEFAULT clause was declared.
func (*Column) IsOptimisticVersion ¶ added in v0.2.0
IsOptimisticVersion reports whether the column is the version column used for optimistic locking. Marked via (*Col[T]).OptimisticLock().
func (*Column) IsPrimaryKey ¶
IsPrimaryKey reports whether the column was declared PRIMARY KEY.
type ColumnSnapshot ¶
type ColumnSnapshot struct {
Name string `json:"name"`
Type string `json:"type"`
PrimaryKey bool `json:"primaryKey"`
NotNull bool `json:"notNull"`
Default *string `json:"default,omitempty"`
}
ColumnSnapshot is one entry in TableSnapshot.Columns.
type ColumnType ¶
type ColumnType interface {
// TypeSQL returns the PostgreSQL type expression as it appears in
// CREATE TABLE — e.g. "text", "integer", "varchar(255)", "uuid".
TypeSQL() string
}
ColumnType describes the SQL type of a column.
type ColumnValue ¶
type ColumnValue interface {
// contains filtered or unexported methods
}
ColumnValue pairs a target column with the value or expression to write for it in an INSERT row or UPDATE SET assignment. Construct one via (*Col[T]).Val, (*Col[T]).Expr, or (*Col[T]).SetDefault.
type CompositePKSnapshot ¶ added in v0.2.0
CompositePKSnapshot is one entry in TableSnapshot.CompositePrimaryKeys.
type ConflictUpdate ¶
type ConflictUpdate struct {
// contains filtered or unexported fields
}
ConflictUpdate is the configuration handle returned by OnConflictUpdate.
func (*ConflictUpdate) Done ¶
func (cu *ConflictUpdate) Done() *InsertBuilder
Done returns the InsertBuilder for further chaining (e.g. Returning).
func (*ConflictUpdate) Set ¶
func (cu *ConflictUpdate) Set(values ...ColumnValue) *ConflictUpdate
Set adds an assignment to the conflict update.
func (*ConflictUpdate) Where ¶
func (cu *ConflictUpdate) Where(preds ...drops.Expression) *ConflictUpdate
Where adds predicates that gate the conflict update.
type Copier ¶ added in v0.2.0
type Copier interface {
// Copy ingests rows into table. cols carries the destination
// columns in order; each entry in rows must align with cols.
// Returns the number of rows accepted by the server.
Copy(ctx context.Context, table string, cols []string, rows [][]any) (int64, error)
}
Copier is the contract drops uses to dispatch a bulk COPY. Any driver that satisfies it (typically by adding a Copy method to the existing drops.Driver implementation) gets the fast path for free.
type Cursor ¶ added in v0.2.0
type Cursor string
Cursor is an opaque page marker — obtain one from EncodeCursor and pass it to SelectBuilder.AfterCursor / BeforeCursor.
func EncodeCursor ¶ added in v0.2.0
func EncodeCursor(spec CursorSpec, values ...any) (Cursor, error)
EncodeCursor builds a cursor from values matching the spec, one per key in declaration order. Returns an error when values is the wrong length or contains an unsupported type.
type CursorSpec ¶ added in v0.2.0
type CursorSpec struct {
Keys []OrderKey
}
CursorSpec is the ordered list of keys that defines the cursor shape — used by OrderByCursor and AfterCursor so the same shape drives both the ORDER BY and the keyset WHERE.
func NewCursorSpec ¶ added in v0.2.0
func NewCursorSpec(keys ...OrderKey) CursorSpec
NewCursorSpec returns a CursorSpec carrying the supplied keys in declaration order. The last key should be a primary key (or otherwise unique column) so equal leading values still resolve to a deterministic page boundary.
type CustomGuard ¶ added in v0.2.0
type CustomGuard func(ctx context.Context) (drops.Expression, error)
CustomGuard wraps a function so application code can compose arbitrary authorization rules without implementing the interface explicitly.
func (CustomGuard) Predicate ¶ added in v0.2.0
func (g CustomGuard) Predicate(ctx context.Context) (drops.Expression, error)
Predicate implements Guard.
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB is the entry point for issuing PostgreSQL queries through a drops.Driver. Any driver implementation — database/sql, pgx, or a custom connection — can back a DB.
A DB is safe for concurrent use by multiple goroutines provided the underlying Driver is. The builder types returned by Select/Insert/ Update/Delete/Find are NOT safe for concurrent use; create one per query.
An optional drops.Hook can be attached via WithHook to observe every driver operation — query logging, slow-query alerts, tracing, metrics. The hook is propagated into the transaction-bound DBs returned by Begin and InTx, and InTx emits "begin"/"commit"/"rollback" events for the transaction lifecycle. For full lifecycle observability prefer InTx; with an explicit Begin you must call Commit/Rollback yourself, and those bypass the hook unless you wrap them.
func (*DB) Begin ¶
Begin opens a transaction and returns a DB bound to it plus the raw Tx handle. Most callers should prefer InTx for automatic commit/ rollback and full hook coverage.
func (*DB) Close ¶
Close shuts down the underlying driver if it implements io.Closer. For Drivers that don't (most pool wrappers do), it is a no-op and returns nil.
Typical usage is `defer db.Close()` next to the connection-open call:
sqlDB, _ := sql.Open("pgx", dsn)
db := pg.New(stdlib.New(sqlDB))
defer db.Close()
func (*DB) Driver ¶
Driver returns the underlying driver. Useful for adapters or for dropping down to raw SQL.
func (*DB) ExecExpr ¶
ExecExpr renders e to SQL and runs it as a statement. 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 what columns are scanned (via the same struct-field mapping rules as Select.All).
func (*DB) InTx ¶
InTx runs fn inside a transaction. The transaction is committed if fn returns nil and rolled back otherwise (including on panic, after which the panic is re-raised). Hook events are emitted for begin, commit and rollback alongside the ordinary exec/query events fn produces.
Rollback uses a detached context with a short timeout so a cancelled or expired caller-ctx doesn't prevent cleanup. When a RetryPolicy is installed via WithRetry, transient failures (those the policy marks retryable) cause the transaction to be re-opened and fn re-run, up to MaxAttempts times.
func (*DB) Insert ¶
func (db *DB) Insert(t *Table) *InsertBuilder
Insert begins an INSERT INTO <t>.
Example ¶
ExampleDB_Insert demonstrates a typed INSERT with RETURNING.
package main
import (
"fmt"
"github.com/bernardoforcillo/drops/pg"
)
// Schema fixtures used by the examples. Declaring them at package level
// mirrors how a real application stores its schema and lets every
// example reuse the same definitions.
var (
exUsers = pg.NewTable("users")
exUserID = pg.Add(exUsers, pg.BigSerial("id").PrimaryKey())
exUserName = pg.Add(exUsers, pg.Text("name").NotNull())
exUserAge = pg.Add(exUsers, pg.Integer("age"))
)
func main() {
db := pg.New(nil)
sql, args := db.Insert(exUsers).
Row(exUserName.Val("Alice"), exUserAge.Val(30)).
Returning(exUserID).
ToSQL()
fmt.Println(sql)
fmt.Println(args)
}
Output: INSERT INTO "users" ("name", "age") VALUES ($1, $2) RETURNING "users"."id" [Alice 30]
func (*DB) PoolStats ¶ added in v0.2.0
PoolStats returns a snapshot when the underlying driver implements PoolStatsProvider, plus ok=true. Drivers without pool introspection return the zero value + ok=false.
func (*DB) RetryPolicyValue ¶ added in v0.2.0
func (db *DB) RetryPolicyValue() RetryPolicy
RetryPolicyValue returns the active retry policy, or the zero RetryPolicy when none is configured.
func (*DB) Select ¶
func (db *DB) Select(cols ...drops.Expression) *SelectBuilder
Select begins a SELECT. With no columns the projection is "*".
Example ¶
ExampleDB_Select shows a typical filtered + ordered SELECT and how the typed column helpers produce parameter-safe SQL.
package main
import (
"fmt"
"github.com/bernardoforcillo/drops/pg"
)
// Schema fixtures used by the examples. Declaring them at package level
// mirrors how a real application stores its schema and lets every
// example reuse the same definitions.
var (
exUsers = pg.NewTable("users")
exUserID = pg.Add(exUsers, pg.BigSerial("id").PrimaryKey())
exUserName = pg.Add(exUsers, pg.Text("name").NotNull())
exUserAge = pg.Add(exUsers, pg.Integer("age"))
)
func main() {
db := pg.New(nil) // no driver — we only render SQL
sql, args := db.Select(exUserID, exUserName).
From(exUsers).
Where(exUserAge.Gte(18)).
OrderBy(exUserName.Asc()).
Limit(10).
ToSQL()
fmt.Println(sql)
fmt.Println(args)
}
Output: SELECT "users"."id", "users"."name" FROM "users" WHERE ("users"."age" >= $1) ORDER BY "users"."name" ASC LIMIT $2 [18 10]
func (*DB) StartPoolMetrics ¶ added in v0.2.0
func (db *DB) StartPoolMetrics(ctx context.Context, interval time.Duration, sink func(PoolStats)) func()
StartPoolMetrics launches a goroutine that polls PoolStats every interval and pushes each snapshot to sink. Returns a cancel function the caller must call to stop the goroutine — usually via defer.
Returns nil (and never starts the goroutine) when the driver does not implement PoolStatsProvider — callers can branch on db.PoolStats's ok return to know in advance.
func (*DB) WithHook ¶
WithHook returns a shallow copy of db with hook installed. Passing nil removes the hook. Compose multiple hooks via drops.ChainHooks.
Example ¶
ExampleDB_WithHook shows attaching a tiny observability hook for query logging. Production code usually pairs LoggerHook with a structured logger and a SlowQuery threshold.
package main
import (
"context"
"fmt"
"github.com/bernardoforcillo/drops"
"github.com/bernardoforcillo/drops/pg"
)
func main() {
hook := func(_ context.Context, e drops.QueryEvent) {
fmt.Printf("%s in %v err=%v\n", e.Kind, e.Duration > 0, e.Err)
}
db := pg.New(&exampleNoopDriver{}).WithHook(hook)
_, _ = db.Exec(context.Background(), "SELECT 1")
}
// exampleNoopDriver lets the examples render SQL through DB.Exec
// without depending on the test-only fakeDriver. It is purely for
// documentation; production code never embeds a no-op driver.
type exampleNoopDriver struct{}
func (exampleNoopDriver) Exec(context.Context, string, ...any) (drops.Result, error) {
return exampleNoopResult{}, nil
}
func (exampleNoopDriver) Query(context.Context, string, ...any) (drops.Rows, error) {
return nil, fmt.Errorf("not implemented")
}
func (exampleNoopDriver) Begin(context.Context) (drops.Tx, error) {
return nil, fmt.Errorf("not implemented")
}
type exampleNoopResult struct{}
func (exampleNoopResult) RowsAffected() (int64, error) { return 0, nil }
Output: exec in true err=<nil>
func (*DB) WithRetry ¶ added in v0.2.0
func (db *DB) WithRetry(policy RetryPolicy) *DB
WithRetry returns a shallow copy of db with policy installed. Passing the zero RetryPolicy clears any previously-installed policy.
func (*DB) WithTracer ¶ added in v0.2.0
WithTracer attaches t. Returns a shallow copy of db so global instances stay unaffected — mirrors the WithHook pattern. Pass nil to clear.
type DeleteBuilder ¶
type DeleteBuilder struct {
// contains filtered or unexported fields
}
DeleteBuilder composes a DELETE statement.
func (*DeleteBuilder) All ¶
func (d *DeleteBuilder) All(ctx context.Context, dest any) error
All executes the DELETE and scans the RETURNING rows into dest.
func (*DeleteBuilder) DB ¶ added in v0.2.0
func (d *DeleteBuilder) DB() *DB
DB returns the executing DB. Hooks that need to build a replacement statement (an UPDATE for soft-delete, for instance) use it.
func (*DeleteBuilder) IsUnscoped ¶ added in v0.2.0
func (d *DeleteBuilder) IsUnscoped() bool
IsUnscoped reports whether the caller opted out of default scopes.
func (*DeleteBuilder) One ¶
func (d *DeleteBuilder) One(ctx context.Context, dest any) error
One executes the DELETE and scans the first RETURNING row into dest.
func (*DeleteBuilder) Returning ¶
func (d *DeleteBuilder) Returning(cols ...drops.Expression) *DeleteBuilder
Returning sets a RETURNING clause.
func (*DeleteBuilder) ReturningClauses ¶ added in v0.2.0
func (d *DeleteBuilder) ReturningClauses() []drops.Expression
ReturningClauses returns a copy of the RETURNING projection list.
func (*DeleteBuilder) Table ¶ added in v0.2.0
func (d *DeleteBuilder) Table() *Table
Table returns the target table.
func (*DeleteBuilder) ToSQL ¶
func (d *DeleteBuilder) ToSQL() (string, []any)
ToSQL renders the statement.
func (*DeleteBuilder) Unscoped ¶ added in v0.2.0
func (d *DeleteBuilder) Unscoped() *DeleteBuilder
Unscoped opts out of both DeleteHooks and DefaultFilters for this statement. On a soft-deleted table it forces a real, hard DELETE that bypasses the rewrite-to-UPDATE behaviour.
func (*DeleteBuilder) Using ¶
func (d *DeleteBuilder) Using(tables ...*Table) *DeleteBuilder
Using adds tables to a PostgreSQL DELETE ... USING clause for joins.
func (*DeleteBuilder) Where ¶
func (d *DeleteBuilder) Where(preds ...drops.Expression) *DeleteBuilder
Where appends predicates joined by AND.
func (*DeleteBuilder) Wheres ¶ added in v0.2.0
func (d *DeleteBuilder) Wheres() []drops.Expression
Wheres returns a copy of the predicate slice — exposed so custom DeleteHooks (e.g. soft-delete rewrites) can read the original WHERE clauses when synthesising replacement SQL.
func (*DeleteBuilder) WriteSQL ¶
func (d *DeleteBuilder) WriteSQL(b *drops.Builder)
WriteSQL renders the DELETE. If the table has DeleteHooks and the caller has not opted out via Unscoped, hooks may replace the statement entirely — used by SoftDelete to flip DELETE into UPDATE.
type DeleteHook ¶ added in v0.2.0
type DeleteHook interface {
BeforeDelete(d *DeleteBuilder) drops.Expression
}
DeleteHook is invoked by DeleteBuilder.WriteSQL. If it returns a non-nil expression, that expression replaces the rendered DELETE entirely — used by SoftDelete to translate DELETE into an UPDATE. Returning nil lets the DELETE render normally.
Hooks are tried in registration order; the first non-nil expression wins.
type DeleteHookFunc ¶ added in v0.2.0
type DeleteHookFunc func(*DeleteBuilder) drops.Expression
DeleteHookFunc adapts a function to the DeleteHook interface.
func (DeleteHookFunc) BeforeDelete ¶ added in v0.2.0
func (f DeleteHookFunc) BeforeDelete(d *DeleteBuilder) drops.Expression
BeforeDelete implements DeleteHook.
type DiffOptions ¶
type DiffOptions struct {
// Safe wraps every destructive or creative DDL in IF [NOT] EXISTS so
// the migration can be re-run without errors. ALTER COLUMN does not
// have an IF EXISTS form in PostgreSQL, so it is emitted unchanged.
Safe bool
}
DiffOptions tunes how Diff renders statements.
type DriftReport ¶ added in v0.2.0
type DriftReport struct {
// PendingMigrations is the statement list drops would emit to
// bring live UP TO repo — empty means production has every
// schema change in the repo applied.
PendingMigrations []string
// bring repo UP TO live — empty means production matches the
// repo with no unrecorded manual edits.
UnauthorizedChanges []string
// InSync is true when both PendingMigrations and
// UnauthorizedChanges are empty.
InSync bool
}
DriftReport summarises the gap between two snapshots — typically the repo's canonical schema and a live introspection of production.
func DetectDrift ¶ added in v0.2.0
func DetectDrift(repo, live *Snapshot) DriftReport
DetectDrift computes the two-way diff between the repo's canonical snapshot and a live introspection. Both arguments must be non-nil — use EmptySnapshot when one side is genuinely empty (e.g. fresh database).
func (DriftReport) HasPendingMigrations ¶ added in v0.2.0
func (r DriftReport) HasPendingMigrations() bool
HasPendingMigrations reports whether production is behind the repo.
func (DriftReport) HasUnauthorizedChanges ¶ added in v0.2.0
func (r DriftReport) HasUnauthorizedChanges() bool
HasUnauthorizedChanges reports whether production has changes the repo doesn't know about — typically the headline CI alert.
type DrizzleEntry ¶
DrizzleEntry is a parsed, hash-computed migration ready to apply.
type DrizzleMigrator ¶
type DrizzleMigrator struct {
// contains filtered or unexported fields
}
DrizzleMigrator runs migrations from a drizzle-kit-formatted directory.
func NewDrizzleMigrator ¶
func NewDrizzleMigrator(db *DB, fsys fs.FS, dir string) *DrizzleMigrator
NewDrizzleMigrator wraps db with a migrator that reads from dir within fsys. dir is typically "drizzle" when using `//go:embed drizzle/*` from a project root that has a `drizzle/` directory; pass "." when fsys is already rooted at the migrations directory.
func (*DrizzleMigrator) LoadEntries ¶
func (d *DrizzleMigrator) LoadEntries() ([]DrizzleEntry, error)
LoadEntries reads and hashes every migration referenced by the journal. Useful for tooling — Up calls it internally.
func (*DrizzleMigrator) Status ¶
func (d *DrizzleMigrator) Status(ctx context.Context) ([]DrizzleStatus, error)
Status reports every entry in the journal and whether it has been applied (matched by hash, the same way drizzle-orm matches).
func (*DrizzleMigrator) Up ¶
func (d *DrizzleMigrator) Up(ctx context.Context) error
Up applies every pending migration in journal order. Each migration runs in its own transaction; failure of any statement rolls back that migration only.
func (*DrizzleMigrator) WithSchema ¶
func (d *DrizzleMigrator) WithSchema(schema string) *DrizzleMigrator
WithSchema overrides the migration history schema. Match drizzle.config.ts's `migrationsSchema` to stay interoperable.
func (*DrizzleMigrator) WithTable ¶
func (d *DrizzleMigrator) WithTable(table string) *DrizzleMigrator
WithTable overrides the migration history table name. Match drizzle.config.ts's `migrationsTable` to stay interoperable.
type DrizzleStatus ¶
type DrizzleStatus struct {
Tag string
Hash string
Applied bool
When int64 // journal timestamp (unix milliseconds)
}
DrizzleStatus is one row of the Status report.
type EmitOptions ¶ added in v0.2.0
type EmitOptions struct {
// AggregateType is the entity kind, e.g. "player", "match",
// "wallet". Optional but recommended — pairs with AggregateID
// to identify the ordering scope.
AggregateType string
// AggregateID is the per-aggregate ordering key, e.g. "42",
// "match-abc". Events sharing the same AggregateID are
// delivered in id order when the worker is configured with
// WithOrdering(OrderingPerAggregate).
AggregateID string
// Headers carry tracing metadata (traceparent, correlationID,
// userID, ...). Stored as jsonb on the row and surfaced to
// the handler so context propagates from emitter to consumer.
Headers map[string]string
}
EmitOptions extends Emit with aggregate metadata and tracing headers. Aggregate fields enable per-aggregate ordering in the worker (see WithOrdering(OrderingPerAggregate)).
type Entity ¶ added in v0.2.0
type Entity[T any] struct { // contains filtered or unexported fields }
Entity binds a Go struct T to a Table and precomputes the metadata the CRUD shortcuts need: the column-to-field index path, the primary-key column, and the PK's field path inside T. It is the entry point for type-safe CRUD operations that scan into T directly, without the caller having to declare scan targets.
Declare an Entity once at package level alongside its table:
type User struct {
ID int64 `drop:"id"`
Name string `drop:"name"`
Email string `drop:"email"`
}
var (
Users = pg.NewTable("users")
UserID = pg.Add(Users, pg.BigSerial("id").PrimaryKey())
UserName = pg.Add(Users, pg.Text("name").NotNull())
UserEmail = pg.Add(Users, pg.Text("email").NotNull().Unique())
UserEntity = pg.NewEntity[User](Users)
)
All Entity methods take *DB as their first argument so the same entity can be reused across transactions and connection pools:
u, err := UserEntity.Get(db, ctx, 42) err = UserEntity.Create(db, ctx, &u) err = UserEntity.Update(db, ctx, &u) err = UserEntity.Save(db, ctx, &u) // INSERT or UPDATE depending on PK res, err := UserEntity.Delete(db, ctx, 42)
Entity composes with Phase-1 features: lifecycle hooks (Timestamps, SoftDelete, …) registered on the table fire normally because every operation routes through the underlying Insert / Update / Delete builders.
func NewAutoEntity ¶ added in v0.2.0
NewAutoEntity bundles AutoTable + NewEntity into one call — typically the only line a small entity needs.
var UserEntity = pg.NewAutoEntity[User]("users")
func NewEntity ¶ added in v0.2.0
NewEntity validates that T has a field bound to every primary-key column on t and precomputes the column ↔ field mapping. It panics on misalignment because schemas are typically declared in package init blocks — bad config should fail at startup, not at the first query.
Field matching rules mirror the row scanner: `drop:"colname"` tag wins; otherwise the field name and its snake_case form are tried. Fields tagged `drop:"-"` are skipped.
func WithAudit ¶ added in v0.2.0
WithAudit attaches log to the entity so subsequent Create / Update / Delete calls record audit events in the same transaction. Free function because Go does not allow generic methods.
func (*Entity[T]) AuthorizeWith ¶ added in v0.2.0
AuthorizeWith installs g on the entity. Subsequent Get / Query / Update / Delete AND the guard's predicate into the WHERE clause; ctx-less subject failures surface as ErrSubjectMissing. Pass nil to clear an existing guard.
func (*Entity[T]) Create ¶ added in v0.2.0
Create INSERTs r and refreshes it from the RETURNING row — useful for picking up generated PKs, server-side defaults, and hook-added values (e.g. createdAt = now()).
Columns whose Go field is the zero value are omitted from the INSERT when the column either has a declared DEFAULT or is the primary key — letting the DB generate the value. To override that behaviour for a specific field, set it to a non-zero value before calling Create.
func (*Entity[T]) CreateMany ¶ added in v0.2.0
CreateMany INSERTs every row in rs in a single statement. Compared to looping over Create, this batches the round-trip cost — large payloads stay one network hop. RETURNING is not used (refreshing N rows is rarely what callers want), so generated PKs and hook-supplied values do not flow back into rs; use Create when you need the post-INSERT row.
func (*Entity[T]) Delete ¶ added in v0.2.0
Delete removes the row whose primary key equals id. The table's DeleteHooks (e.g. SoftDelete) fire normally — so on a soft-deleted table this rewrites to UPDATE deletedAt = now() instead.
func (*Entity[T]) Get ¶ added in v0.2.0
Get fetches the row whose primary key equals id. Returns ErrNoRows if no row matches.
When a cache is attached via WithCache, Get serves hits from the cache and dedupes concurrent cache misses via single-flight so a thundering herd resolves to one DB query.
func (*Entity[T]) HasFastScan ¶ added in v0.2.0
HasFastScan reports whether a zero-reflection scanner is wired up.
func (*Entity[T]) Page ¶ added in v0.2.0
func (e *Entity[T]) Page(db *DB) *PageBuilder[T]
Page returns a cursor-paginated builder for this entity. The default limit is 50; override with Limit.
pg, err := UserEntity.Page(db).
OrderBy(pg.Asc(UserID)).
Limit(20).
After(prevCursor).
All(ctx)
if pg.HasMore {
// request next page with pg.NextCursor
}
func (*Entity[T]) Patch ¶ added in v0.2.0
func (e *Entity[T]) Patch(db *DB, ctx context.Context, id any, ops ...PatchOp) (drops.Result, error)
Patch issues an UPDATE that applies ops to the row whose PK equals id. Honours the entity's tenant scope, authorisation guard, and audit log (the audit row's payload is empty since the post-update state isn't fetched; callers needing post-row snapshots should use Update with a refreshed struct).
Returns the result so callers can detect "no row matched" without an additional SELECT.
func (*Entity[T]) Query ¶ added in v0.2.0
func (e *Entity[T]) Query(db *DB) *EntityQuery[T]
Query returns a typed query builder for ad-hoc Where / OrderBy / Limit / Offset / With chains that scan into T or []T.
When the entity is tenant-scoped the caller must use the ctx-aware All / One / Stream methods so the tenant predicate can be injected; using the builder methods without a ctx-bound tenant returns ErrTenantMissing.
func (*Entity[T]) Save ¶ added in v0.2.0
Save inserts r if its primary-key field is the zero value, or updates it otherwise. Compared to a single ON CONFLICT statement, this incurs an extra branch in Go but keeps the generated SQL straightforward; switch to a hand-written upsert when the race-window between the read and the write matters.
func (*Entity[T]) ScopeByTenant ¶ added in v0.2.0
ScopeByTenant marks col as the entity's tenant axis. Every subsequent Get / Query / Update / Delete reads the tenant from ctx (via WithTenant) and AND-s "<col> = $tenant" into the predicate. Create stamps the tenant onto r automatically.
Panics if col has no matching struct field — fail loudly at startup rather than at the first query.
func (*Entity[T]) SetFastScan ¶ added in v0.2.0
SetFastScan registers a zero-reflection per-row scanner — the generated Scan<T> helper from cmd/dropsgen is the canonical implementation. When set, Get / Query.One / Query.All consume rows directly through scan instead of routing through the reflection scanner. Eager-loaded relations still fall back to the reflection path because they rely on field-map introspection of the loaded slice.
func (*Entity[T]) Update ¶ added in v0.2.0
Update writes r's current field values to the row whose PK equals r's PK and refreshes r from the RETURNING row. ErrPKNotSet is returned if r's PK is the zero value.
All non-PK columns mapped to fields on T are included in the SET list — the typical "blind UPDATE" semantics. Change-tracking is out of scope for now; callers needing finer control use db.Update directly.
func (*Entity[T]) UpsertMany ¶ added in v0.2.0
UpsertMany INSERTs rs and, on PK conflict, updates every non-PK column with the new row's value (ON CONFLICT (pk) DO UPDATE SET col = EXCLUDED.col). Returns the underlying Result so callers can inspect rows-affected; row values are not refreshed.
Useful for idempotent ingestion: the same set of rows can be replayed safely without producing duplicates.
func (*Entity[T]) Validate ¶ added in v0.2.0
Validate registers a validator that runs before Create / Update / Save. Validators are invoked in registration order; the first to return a non-nil error aborts the operation. Returns the entity so the call can be chained next to NewEntity.
func (*Entity[T]) WithBudget ¶ added in v0.2.0
WithBudget attaches the supplied limits to the entity. Returns the entity for chaining at declaration time.
type EntityCache ¶ added in v0.2.0
type EntityCache struct {
// contains filtered or unexported fields
}
EntityCache wires a cache backend into an Entity so reads pass through the cache and writes invalidate the matching entries. Construct one via (*Entity[T]).WithCache; do not instantiate directly.
Cache key conventions:
drops:<table>:pk:<id> — Get by primary key drops:<table>:q:<sql-hash> — query results (best-effort, TTL)
Primary-key entries are invalidated on Update / Save / Delete. Query entries rely on TTL alone — invalidation across an arbitrary WHERE/JOIN topology is intractable in the general case, and TTL is usually the right trade for read-heavy services.
A built-in single-flight group dedupes concurrent identical PK-by-cache-miss reads, so a thundering herd of "give me user 42" resolves to one DB query.
type EntityQuery ¶ added in v0.2.0
type EntityQuery[T any] struct { // contains filtered or unexported fields }
EntityQuery is the typed counterpart of FindBuilder — same shape, but its executors return ([]T, error) and (T, error) directly.
func (*EntityQuery[T]) All ¶ added in v0.2.0
func (q *EntityQuery[T]) All(ctx context.Context) ([]T, error)
All executes the query and returns the matching rows as a typed slice. Uses the fast-scan path (zero reflection) when available and no eager-loaded relations are queued. When the entity has a cache attached and the query has no eager-loaded relations, the result is cached under sha256(SQL+args) with the cache's TTL.
func (*EntityQuery[T]) Limit ¶ added in v0.2.0
func (q *EntityQuery[T]) Limit(n int64) *EntityQuery[T]
Limit sets the LIMIT.
func (*EntityQuery[T]) Offset ¶ added in v0.2.0
func (q *EntityQuery[T]) Offset(n int64) *EntityQuery[T]
Offset sets the OFFSET.
func (*EntityQuery[T]) One ¶ added in v0.2.0
func (q *EntityQuery[T]) One(ctx context.Context) (T, error)
One executes the query and returns the first matching row. Returns ErrNoRows if the query produces no rows. Honours the entity cache the same way All does.
func (*EntityQuery[T]) OrderBy ¶ added in v0.2.0
func (q *EntityQuery[T]) OrderBy(exprs ...drops.Expression) *EntityQuery[T]
OrderBy appends ORDER BY expressions.
func (*EntityQuery[T]) Stream ¶ added in v0.2.0
func (q *EntityQuery[T]) Stream(ctx context.Context, fn func(*T) error) error
Stream iterates the matching rows one at a time, invoking fn for each. Memory stays bounded — Stream never buffers the full result set — which matters for batch jobs and exports. Returning an error from fn aborts the iteration and propagates the error to the caller. Eager-loaded relations are not supported in Stream (relation loaders need the populated parent slice).
func (*EntityQuery[T]) Unscoped ¶ added in v0.2.0
func (q *EntityQuery[T]) Unscoped() *EntityQuery[T]
Unscoped opts out of the table's DefaultFilter predicates.
func (*EntityQuery[T]) Where ¶ added in v0.2.0
func (q *EntityQuery[T]) Where(preds ...drops.Expression) *EntityQuery[T]
Where appends predicates joined by AND.
func (*EntityQuery[T]) With ¶ added in v0.2.0
func (q *EntityQuery[T]) With(names ...string) *EntityQuery[T]
With eager-loads the named relations (see FindBuilder.With).
func (*EntityQuery[T]) WithRel ¶ added in v0.2.0
func (q *EntityQuery[T]) WithRel(name string, fn func(*RelConfig)) *EntityQuery[T]
WithRel eager-loads a relation with per-edge configuration.
type EnumSnapshot ¶ added in v0.2.0
type EnumSnapshot struct {
Name string `json:"name"`
Schema string `json:"schema"`
Values []string `json:"values"`
}
EnumSnapshot is one entry in Snapshot.Enums.
type EnvelopeCipher ¶ added in v0.2.0
type EnvelopeCipher struct {
// contains filtered or unexported fields
}
EnvelopeCipher performs AES-256-GCM with per-call data encryption keys wrapped by the configured KMS. Ciphertext format on the wire:
[wrappedDEK length: uint32 BE] [wrappedDEK] [nonce: 12 bytes] [ciphertext + GCM tag]
The header is fixed-length-prefixed so the decryptor can split without scanning. The format is versioned via the magic byte at position 0 so future revisions stay distinguishable.
func NewEnvelopeCipher ¶ added in v0.2.0
func NewEnvelopeCipher(kms KMS) *EnvelopeCipher
NewEnvelopeCipher wraps kms in the cipher contract. Panics on a nil KMS — encryption with a nil KMS is never a useful programmer intent.
type Event ¶ added in v0.2.0
type Event struct {
// Offset is the store-wide append offset — monotonic across
// all aggregates. Use it as the high-watermark when streaming
// for projections.
Offset int64
// AggregateType / AggregateID identify the stream.
AggregateType string
AggregateID string
// Version is the per-stream offset starting at 0. Append's
// expectedVersion compares against this.
Version int64
// Type is the application-level event name (e.g.
// "matchStarted", "playerJoined").
Type string
// Payload is the JSON-encoded event body — caller-defined
// shape, decoded on read by the consumer.
Payload json.RawMessage
// Headers carry tracing / correlation metadata.
Headers map[string]string
// CreatedAt is the wall-clock time of the append.
CreatedAt time.Time
}
Event is one entry in the store.
type EventInput ¶ added in v0.2.0
type EventInput struct {
// Type is required — names the event.
Type string
// Payload is encoded with encoding/json. Pre-encoded
// json.RawMessage / []byte / string pass through untouched.
Payload any
// Headers attach tracing / correlation metadata. Stored as
// jsonb on the row.
Headers map[string]string
}
EventInput is the per-event payload passed to Append.
type EventStore ¶ added in v0.2.0
type EventStore struct {
// contains filtered or unexported fields
}
EventStore is the append-only event log bound to a single table.
func NewEventStore ¶ added in v0.2.0
func NewEventStore(db *DB, table string) *EventStore
NewEventStore returns a store bound to db. The table name is the SQL identifier; use NewEventStoreTable to declare matching DDL.
func (*EventStore) Append ¶ added in v0.2.0
func (s *EventStore) Append(tx *DB, ctx context.Context, aggregateType, aggregateID string, expectedVersion int64, events ...EventInput) error
Append writes events to the stream identified by (aggregateType, aggregateID) starting at expectedVersion+1. Returns ErrConcurrencyConflict if the stream's head has advanced past expectedVersion — typically resolved by reloading and retrying.
Use tx so the append commits with the rest of the aggregate's transactional work (typically a write to a projection table or to the outbox).
func (*EventStore) LatestVersion ¶ added in v0.2.0
func (s *EventStore) LatestVersion(ctx context.Context, aggregateType, aggregateID string) (int64, error)
LatestVersion returns the highest version recorded for the stream, or -1 when the stream is empty. Use this before Append to compute the expectedVersion for a fresh write.
func (*EventStore) Load ¶ added in v0.2.0
func (s *EventStore) Load(ctx context.Context, aggregateType, aggregateID string, fromVersion int64) ([]Event, error)
Load returns events for an aggregate in version order, starting after fromVersion. Pass 0 to read from the beginning.
func (*EventStore) LoadSnapshot ¶ added in v0.2.0
func (s *EventStore) LoadSnapshot(ctx context.Context, table, aggregateType, aggregateID string) (AggregateSnapshot, bool, error)
LoadSnapshot fetches the latest snapshot for an aggregate. Returns ok=false when no snapshot exists; callers should fall back to replaying from version 0.
func (*EventStore) SaveSnapshot ¶ added in v0.2.0
func (s *EventStore) SaveSnapshot(ctx context.Context, table string, snap AggregateSnapshot) error
SaveSnapshot upserts the supplied snapshot — newer versions replace older ones in place.
type ExplainOptions ¶ added in v0.2.0
type ExplainOptions struct {
// Analyze flips EXPLAIN (ANALYZE) — actually runs the query
// and reports real timings / row counts. Skip for INSERT /
// UPDATE / DELETE in production unless you wrap the call in
// a rolled-back transaction.
Analyze bool
// Buffers adds I/O accounting. Requires Analyze.
Buffers bool
// Verbose includes per-node target lists. Useful for
// fingerprinting projection changes but bloats the JSON.
Verbose bool
}
ExplainOptions tunes the EXPLAIN PG runs.
type ExplainPlan ¶ added in v0.2.0
type ExplainPlan struct {
// JSON is the raw EXPLAIN (FORMAT JSON) payload returned by
// PostgreSQL. Persist this verbatim for debugging — Root and
// the helpers below are derived from it.
JSON json.RawMessage
// Root is the head of the parsed plan tree.
Root *PlanNode
// TotalCost mirrors Root.TotalCost — the planner's estimated
// upper-bound cost in arbitrary units.
TotalCost float64
// PlanRows mirrors Root.PlanRows — the planner's row-count
// estimate.
PlanRows int64
// ActualMs is the actual execution time when Analyze was set.
// Zero otherwise.
ActualMs float64
}
ExplainPlan is the parsed result of an EXPLAIN — the raw JSON, the root node of the plan tree, and a few derived shortcuts.
func Explain ¶ added in v0.2.0
Explain returns the parsed EXPLAIN plan for sql with default options — planner-only, no execution.
func ExplainWith ¶ added in v0.2.0
func ExplainWith(db *DB, ctx context.Context, opts ExplainOptions, sql string, args ...any) (*ExplainPlan, error)
ExplainWith runs EXPLAIN with the supplied options and returns the parsed plan. The supplied sql is not modified — drops prepends "EXPLAIN (...) " with the chosen flags.
func (*ExplainPlan) Fingerprint ¶ added in v0.2.0
func (p *ExplainPlan) Fingerprint() string
Fingerprint returns a stable hash of the plan's structural shape — node types, relations, indexes, join types — without the cost / row estimates that fluctuate between runs. Two fingerprints comparing equal indicate the planner picked the same shape; a mismatch flags a regression candidate.
func (*ExplainPlan) JoinTypes ¶ added in v0.2.0
func (p *ExplainPlan) JoinTypes() []string
JoinTypes returns the join methods used across the plan in pre-order — "Hash Join", "Merge Join", "Nested Loop". Useful when a regression manifests as a nested-loop replacing what used to be a hash join.
func (*ExplainPlan) SeqScans ¶ added in v0.2.0
func (p *ExplainPlan) SeqScans() []string
SeqScans returns the relations scanned with a Seq Scan node — often the headline finding (a missing or unused index).
func (*ExplainPlan) UsedIndexes ¶ added in v0.2.0
func (p *ExplainPlan) UsedIndexes() []string
UsedIndexes returns the index names referenced by Index Scan / Bitmap Index Scan / Index Only Scan nodes — useful for asserting that the planner is honouring an expected index.
type Factory ¶ added in v0.2.0
type Factory[T any] struct { // contains filtered or unexported fields }
Factory builds and inserts test rows for an Entity. The template callback returns a fresh value each call; the supplied seq is a monotonically increasing counter the template can interpolate into fields that need to stay unique across a batch.
var PlayerFactory = pg.NewFactory(PlayerEntity, func(seq int) Player {
return Player{
Name: fmt.Sprintf("player-%d", seq),
Level: 1,
Region: "eu",
CreatedAt: time.Now(),
}
})
// In a test
p, _ := PlayerFactory.Create(ctx, db) // one row, inserted
ps, _ := PlayerFactory.CreateN(ctx, db, 100) // batch insert
admin := PlayerFactory.With(func(p *Player) { p.Role = "admin" })
a, _ := admin.Create(ctx, db)
Factories are safe to share across goroutines — the sequence counter is atomic. Call Reset between subtests if you need stable identifiers.
func NewFactory ¶ added in v0.2.0
NewFactory binds template to entity. The template fires once per Build / Create call; the seq it receives is the post-increment counter so the first invocation sees seq=1.
func (*Factory[T]) Build ¶ added in v0.2.0
func (f *Factory[T]) Build() T
Build returns a fresh value without touching the database.
func (*Factory[T]) BuildN ¶ added in v0.2.0
BuildN returns n freshly templated values without touching the database. Each value receives a distinct seq.
func (*Factory[T]) Create ¶ added in v0.2.0
Create builds one value and inserts it. The returned T reflects any server-side defaults / autogenerated PK fields the entity scans back.
func (*Factory[T]) CreateN ¶ added in v0.2.0
CreateN builds n values and inserts them in a single statement via Entity.CreateMany — vastly cheaper than N Create calls when seeding wide test fixtures. Returns the templated values; note that autogenerated PKs are not currently read back from the batch path (matches Entity.CreateMany's semantics).
func (*Factory[T]) Entity ¶ added in v0.2.0
Entity returns the underlying Entity[T] handle. Tests that need to call entity-level helpers (Find, Delete, ...) skip the indirection through the factory.
func (*Factory[T]) Reset ¶ added in v0.2.0
func (f *Factory[T]) Reset()
Reset rewinds the sequence counter to zero. Typically called in test setup between subtests so identifiers stay stable from one run to the next.
func (*Factory[T]) Sequence ¶ added in v0.2.0
Sequence returns the current sequence value without advancing. Useful for assertions on factory state in test helpers.
func (*Factory[T]) With ¶ added in v0.2.0
With returns a child factory whose Build / Create calls run the parent template, then apply mutate to the result. Use it to spin off variant factories — admins, banned players, expired sessions — without redeclaring the whole template.
Child factories share the parent's sequence counter so identifiers remain unique across both. Call WithSequence to start a new one.
type FindBuilder ¶
type FindBuilder struct {
// contains filtered or unexported fields
}
FindBuilder composes a SELECT and (optionally) eager-loads relations declared via NewRelations. It mirrors a subset of SelectBuilder's API — Where, OrderBy, Limit, Offset — and adds With/WithRel for relations.
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 right field of every parent.
func (*FindBuilder) HasEagerLoads ¶ added in v0.2.0
func (f *FindBuilder) HasEagerLoads() bool
HasEagerLoads reports whether any relations have been queued for eager loading via With / WithRel. Used by Entity[T] to decide whether the fast-scan path is safe — relation loaders need the reflection-populated parent slice.
func (*FindBuilder) Offset ¶
func (f *FindBuilder) Offset(n int64) *FindBuilder
Offset sets the OFFSET.
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 if no row matches.
func (*FindBuilder) OrderBy ¶
func (f *FindBuilder) OrderBy(exprs ...drops.Expression) *FindBuilder
OrderBy appends ORDER BY expressions.
func (*FindBuilder) Select ¶ added in v0.2.0
func (f *FindBuilder) Select() *SelectBuilder
Select exposes the underlying SELECT builder so callers (typically Entity[T]) can stream results through their own scanner.
func (*FindBuilder) Unscoped ¶ added in v0.2.0
func (f *FindBuilder) Unscoped() *FindBuilder
Unscoped opts out of the table's DefaultFilter predicates for the root SELECT. Eager-loaded relations inherit their own table's scopes independently.
func (*FindBuilder) Where ¶
func (f *FindBuilder) Where(preds ...drops.Expression) *FindBuilder
Where appends predicates joined by AND.
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.
Nested relations are expressed with dot paths: With("posts.comments") loads each parent's posts, then every comment of those posts. Paths that share a prefix are merged, so With("posts.comments", "posts.tags") fetches posts once and fans out into comments and tags. Each relation edge costs one extra query regardless of how many parents it spans.
Use WithRel when a relation needs filtering or ordering.
func (*FindBuilder) WithRel ¶
func (f *FindBuilder) WithRel(name string, fn func(*RelConfig)) *FindBuilder
WithRel eager-loads a single relation with per-relation constraints. The callback receives a RelConfig to filter (Where), order (OrderBy), and declare deeper relations (With/WithRel):
db.Find(Users).WithRel("posts", func(p *pg.RelConfig) {
p.Where(Posts.Published.Eq(true)).
OrderBy(Posts.CreatedAt.Desc()).
With("comments")
}).All(ctx, &users)
name may itself be a dot path; the constraints attach to its leaf. A relation configured by WithRel and also named in With merges into the same edge, so it is still fetched once.
type ForeignKeySnapshot ¶
type ForeignKeySnapshot struct {
Name string `json:"name"`
TableFrom string `json:"tableFrom"`
ColumnsFrom []string `json:"columnsFrom"`
TableTo string `json:"tableTo"`
SchemaTo string `json:"schemaTo"`
ColumnsTo []string `json:"columnsTo"`
OnDelete string `json:"onDelete"`
OnUpdate string `json:"onUpdate"`
}
ForeignKeySnapshot is one entry in TableSnapshot.ForeignKeys.
type FunctionOptions ¶
type FunctionOptions struct {
Args string // raw, e.g. "a integer, b integer"
Returns string // raw, e.g. "integer" or "trigger"
Language string // default "plpgsql"
Body string // function body (without surrounding $$ delimiters)
Volatility string // "IMMUTABLE", "STABLE", "VOLATILE" (default omitted)
OrReplace bool
}
FunctionOptions configures CreateFunction.
type GenerateOptions ¶
type GenerateOptions struct {
// Schema is the current desired schema. Required.
Schema *Schema
// Dir is the migration directory — both the root for FS reads (if FS
// is nil) and the destination for Write (if Write is nil). Required.
Dir string
// Name is the suffix appended to the migration tag — e.g. "init"
// produces "0000_init". If empty, a random two-word name is generated.
Name string
// FS is an optional override for reads. When set, the journal and
// previous snapshot are read from FS (paths relative to Dir become
// paths relative to the FS root). When nil, os.DirFS is used.
FS fs.FS
// Write is an optional override for file writes. When set, it is
// called for each output file (relative path within Dir + bytes).
// When nil, files are written to disk under Dir with os.WriteFile.
Write func(relPath string, data []byte) error
// Now overrides the timestamp written into journal entries (unix
// milliseconds). When nil, time.Now().UnixMilli() is used.
Now func() int64
// NameFn overrides the random-name generator used when Name is empty.
NameFn func() string
// Safe wraps every destructive or creative DDL in IF [NOT] EXISTS
// so the migration can be re-run idempotently. See DiffOptions.Safe.
Safe bool
// WithDown enables auto-generated rollback SQL. When true, the
// generator emits a paired <tag>.down.sql file alongside the
// up SQL containing DiffDown(prev, cur). The down direction is
// best-effort and applies cleanly only when the up direction's
// inverse is itself well-defined (column ADD ↔ DROP, type ↔
// type swap, etc.); DROP COLUMN can never be reversed
// losslessly because the data is gone — review generated down
// scripts before relying on them.
WithDown bool
}
GenerateOptions configures a single migration-generation run.
The default behaviour reads from and writes to a single Dir on disk. All FS-touching fields can be overridden for tests or for embedding the generator in tooling that wants to capture output in memory.
type GenerateResult ¶
type GenerateResult struct {
Tag string // e.g. "0003_warm_iron_man"; empty when NoOp
Idx int // sequence index for the new migration
SQL string // statement-breakpoint-joined migration SQL (up)
DownSQL string // rollback SQL; empty unless WithDown was set
NoOp bool // true when prev and cur snapshots are equivalent
Snapshot []byte // bytes written to meta/<idx>_snapshot.json
Journal []byte // bytes written to meta/_journal.json
}
GenerateResult describes what a Run produced.
func GenerateMigration ¶
func GenerateMigration(opts GenerateOptions) (*GenerateResult, error)
GenerateMigration computes the schema diff and writes a new drizzle-kit migration set: <tag>.sql, meta/<idx>_snapshot.json and an updated meta/_journal.json.
It is a no-op when there are no differences between the current Go schema and the latest snapshot; no files are written in that case.
type Guard ¶ added in v0.2.0
type Guard interface {
// Predicate returns the SQL expression to AND into the
// guarded query. ctx carries the subject (set via
// WithSubject); the guard is free to inspect any other ctx
// values (e.g. role, tenant) to compose richer rules.
Predicate(ctx context.Context) (drops.Expression, error)
}
Guard is the interface drops calls to materialise an authorization predicate. Implementations are stateless — every query rebuilds the expression so changes to the subject (e.g. admin impersonating a user) take effect immediately.
type IdempotencyStore ¶ added in v0.2.0
type IdempotencyStore struct {
// contains filtered or unexported fields
}
IdempotencyStore stamps a (response, completed) record per key so retries of the same logical operation observe the original result instead of executing again. The pattern is the canonical "idempotency key" used by payment APIs; every POST endpoint that mutates money or emits events needs one.
store := pg.NewIdempotencyStore(db, "idempotency_keys", 24*time.Hour)
// In the request handler:
raw, err := store.Run(ctx, requestKey, func(tx *pg.DB) ([]byte, error) {
// mutate state inside the tx
_, err := PaymentEntity.Create(tx, ctx, &p)
if err != nil { return nil, err }
return json.Marshal(map[string]any{"paymentId": p.ID})
})
On the FIRST call with a given key the closure runs and its response is stored; subsequent calls with the same key skip the closure entirely and return the cached bytes. A failed closure rolls back the row, so the next attempt with the same key re-executes — exactly what callers expect.
The store leverages SELECT ... FOR UPDATE to serialise concurrent calls with the same key: late arrivals wait for the in-flight callback to commit, then observe its response. The wait window is bounded by the caller's context.
func NewIdempotencyStore ¶ added in v0.2.0
func NewIdempotencyStore(db *DB, table string, ttl time.Duration) *IdempotencyStore
NewIdempotencyStore returns a store bound to db. table is the SQL identifier of the keys table (create one via NewIdempotencyTable); ttl is how long records survive before Cleanup is allowed to reclaim them.
func (*IdempotencyStore) Cleanup ¶ added in v0.2.0
func (s *IdempotencyStore) Cleanup(ctx context.Context) (int64, error)
Cleanup removes records whose expiresAt has passed. Returns the number of rows reclaimed.
func (*IdempotencyStore) Run ¶ added in v0.2.0
func (s *IdempotencyStore) Run( ctx context.Context, key string, fn func(tx *DB) ([]byte, error), ) ([]byte, error)
Run executes fn under key. The first invocation runs fn; later invocations with the same key return fn's previously-stored response without re-running it. A non-nil error from fn rolls back the claim so a subsequent call with the same key retries.
func (*IdempotencyStore) SweepEvery ¶ added in v0.2.0
func (s *IdempotencyStore) SweepEvery(ctx context.Context, interval time.Duration, onError func(error))
SweepEvery launches a background goroutine that calls Cleanup every interval until ctx is cancelled. Errors are forwarded to onError when supplied.
type Index ¶
type Index struct {
// contains filtered or unexported fields
}
Index describes a PostgreSQL index. It is built via NewIndex (or the fluent helpers Unique, Concurrently, Where, Include, Using, On) and rendered with CreateIndex / DropIndex.
func NewIndex ¶
func NewIndex(name string, t *Table, cols ...drops.Expression) *Index
NewIndex declares an index on t spanning cols. Cols may be column references (*Col[T] / *Column) or arbitrary expressions — Lower(c), pg.Func("upper", c), etc. — for functional indexes.
func (*Index) Concurrently ¶
Concurrently emits the CONCURRENTLY keyword (PG creates the index without taking a long-lived ACCESS EXCLUSIVE lock; cannot run inside a transaction).
func (*Index) OpClass ¶
func (i *Index) OpClass(class VectorOpClass) *Index
OpClass attaches a per-column operator class hint to the most recent column in the index. Use it alongside Using("hnsw") or Using("ivfflat") on a vector index:
idx := pg.NewIndex("items_embedding_idx", Items, Embedding).
Using("hnsw").
OpClass(pg.VectorCosineOps).
With("m = 16, ef_construction = 64")
(Index.With and OpClass are pgvector additions to the Index type; see index.go for the underlying fields.)
type IndexSnapshot ¶ added in v0.2.0
type IndexSnapshot struct {
Name string `json:"name"`
Columns []string `json:"columns"`
IsUnique bool `json:"isUnique"`
Where string `json:"where"`
With map[string]any `json:"with"`
Method string `json:"method"`
Concurrently bool `json:"concurrently"`
NullsNotDistinct bool `json:"nullsNotDistinct"`
}
IndexSnapshot is one entry in TableSnapshot.Indexes. JSON keys follow drizzle-kit's v7 PostgreSQL schema.
type InsertBuilder ¶
type InsertBuilder struct {
// contains filtered or unexported fields
}
InsertBuilder composes an INSERT statement.
Rows are supplied via Row (one row at a time) or Rows (a batch). The column order across rows is fixed by the first Row call — subsequent rows must target the same set of columns; columns not bound on a row receive DEFAULT.
func (*InsertBuilder) All ¶
func (i *InsertBuilder) All(ctx context.Context, dest any) error
All executes the INSERT and scans the RETURNING rows into dest.
func (*InsertBuilder) OnConflictDoNothing ¶
func (i *InsertBuilder) OnConflictDoNothing(target ...ColRef) *InsertBuilder
OnConflictDoNothing adds ON CONFLICT [(target...)] DO NOTHING.
func (*InsertBuilder) OnConflictUpdate ¶
func (i *InsertBuilder) OnConflictUpdate(target ...ColRef) *ConflictUpdate
OnConflictUpdate begins an ON CONFLICT (target...) DO UPDATE SET ... clause. Pair with Set / Where to populate the update.
func (*InsertBuilder) One ¶
func (i *InsertBuilder) One(ctx context.Context, dest any) error
One executes the INSERT and scans the first RETURNING row into dest.
func (*InsertBuilder) Returning ¶
func (i *InsertBuilder) Returning(cols ...drops.Expression) *InsertBuilder
Returning sets a RETURNING clause.
func (*InsertBuilder) Row ¶
func (i *InsertBuilder) Row(values ...ColumnValue) *InsertBuilder
Row appends a single row. The first Row determines the column list.
func (*InsertBuilder) Rows ¶
func (i *InsertBuilder) Rows(rows ...[]ColumnValue) *InsertBuilder
Rows appends multiple rows in a single call. Equivalent to calling Row once per slice element.
func (*InsertBuilder) ToSQL ¶
func (i *InsertBuilder) ToSQL() (string, []any)
ToSQL renders the statement.
func (*InsertBuilder) WriteSQL ¶
func (i *InsertBuilder) WriteSQL(b *drops.Builder)
WriteSQL renders the INSERT statement.
type InsertHook ¶ added in v0.2.0
type InsertHook interface {
BeforeInsert(ctx *InsertHookCtx)
}
InsertHook is invoked once per INSERT statement, before rendering. It receives an InsertHookCtx that exposes which columns the caller already bound and lets the hook append further bindings that apply to every row.
type InsertHookCtx ¶ added in v0.2.0
type InsertHookCtx struct {
// contains filtered or unexported fields
}
InsertHookCtx is the controlled handle a hook uses to inspect the statement and append hook-supplied values. Hook-added expressions apply uniformly to every row in the INSERT.
func (*InsertHookCtx) Has ¶ added in v0.2.0
func (c *InsertHookCtx) Has(col *Column) bool
Has reports whether c is already bound on the INSERT — either by the user or by an earlier hook.
func (*InsertHookCtx) Set ¶ added in v0.2.0
func (c *InsertHookCtx) Set(v ColumnValue)
Set binds a typed ColumnValue, e.g. the result of (*Col[T]).Val(v). Equivalent to SetExpr with the binding's writer.
func (*InsertHookCtx) SetExpr ¶ added in v0.2.0
func (c *InsertHookCtx) SetExpr(col *Column, expr drops.Expression)
SetExpr binds expr to col across every row, unless col is already bound. Use this for DB-evaluated defaults (e.g. drops.Raw("now()")).
type InsertHookFunc ¶ added in v0.2.0
type InsertHookFunc func(*InsertHookCtx)
InsertHookFunc adapts a plain function to the InsertHook interface.
func (InsertHookFunc) BeforeInsert ¶ added in v0.2.0
func (f InsertHookFunc) BeforeInsert(ctx *InsertHookCtx)
BeforeInsert implements InsertHook.
type IntrospectOptions ¶
type IntrospectOptions struct {
// Schemas restricts the introspection to these schema names. Empty
// means just "public".
Schemas []string
}
IntrospectOptions tunes which schemas Introspect inspects.
type JSONPath ¶
type JSONPath[T any] struct { // contains filtered or unexported fields }
JSONPath is a typed accessor inside a jsonb column. The type parameter T fixes the Go type of the leaf value, which in turn drives the SQL cast emitted at the comparison site so the resulting predicate stays index-friendly and type-safe at declaration time:
type Settings struct {
Theme string `json:"theme"`
LangCode string `json:"lang"`
Beta bool `json:"beta"`
}
var (
Users = pg.NewTable("users")
UserID = pg.Add(Users, pg.BigSerial("id").PrimaryKey())
UserMeta = pg.Add(Users, pg.JSONB("meta"))
)
beta := pg.JSONField[bool](UserMeta, "settings", "beta")
db.Select(UserID).From(Users).Where(beta.Eq(true))
// SELECT "users"."id" FROM "users"
// WHERE (("users"."meta" -> 'settings' ->> 'beta')::boolean = $1)
JSONField stitches arbitrary-length path segments together. The final accessor uses `->>` (text) so the cast lands on a scalar; the intermediate segments use `->` so they stay jsonb until the last step.
Containment / existence operators live alongside as JSONContains / JSONHasKey — they don't need a typed leaf.
func JSONField ¶ added in v0.2.0
JSONField builds a typed JSONPath. col is the jsonb column, path the keys to walk. An empty path targets the column itself (useful with JSONContains).
func (*JSONPath[T]) Eq ¶ added in v0.2.0
func (j *JSONPath[T]) Eq(v T) drops.Expression
func (*JSONPath[T]) Gt ¶ added in v0.2.0
func (j *JSONPath[T]) Gt(v T) drops.Expression
func (*JSONPath[T]) Gte ¶ added in v0.2.0
func (j *JSONPath[T]) Gte(v T) drops.Expression
func (*JSONPath[T]) In ¶ added in v0.2.0
func (j *JSONPath[T]) In(values ...T) drops.Expression
In tests whether the path's value is one of values.
func (*JSONPath[T]) IsNotNull ¶ added in v0.2.0
func (j *JSONPath[T]) IsNotNull() drops.Expression
IsNotNull renders "(path) IS NOT NULL".
func (*JSONPath[T]) IsNull ¶ added in v0.2.0
func (j *JSONPath[T]) IsNull() drops.Expression
IsNull renders "(path) IS NULL". Useful to filter rows where the key is absent from the json structure entirely.
func (*JSONPath[T]) Like ¶ added in v0.2.0
func (j *JSONPath[T]) Like(pattern string) drops.Expression
Like applies the SQL LIKE operator. Only meaningful when T is a string; the call compiles for any T but won't be useful elsewhere.
func (*JSONPath[T]) Lt ¶ added in v0.2.0
func (j *JSONPath[T]) Lt(v T) drops.Expression
func (*JSONPath[T]) Lte ¶ added in v0.2.0
func (j *JSONPath[T]) Lte(v T) drops.Expression
func (*JSONPath[T]) Ne ¶ added in v0.2.0
func (j *JSONPath[T]) Ne(v T) drops.Expression
type KMS ¶ added in v0.2.0
type KMS interface {
// Wrap encrypts dek under the master key. drops calls this
// once per encrypted column write.
Wrap(ctx context.Context, dek []byte) ([]byte, error)
// Unwrap decrypts wrappedDEK. drops calls this once per
// encrypted column read.
Unwrap(ctx context.Context, wrappedDEK []byte) ([]byte, error)
}
KMS is the key-management contract drops uses for envelope encryption. It wraps and unwraps a data encryption key (DEK) without exposing the master key to drops.
Real implementations live in user code so drops doesn't carry a dependency on any specific KMS SDK. Common adapters are around 30 lines each — see the docs.
type Keyring ¶ added in v0.2.0
type Keyring interface {
// Encrypt seals plaintext. The returned bytes must include any
// nonce / authentication tag — drops treats them as opaque.
Encrypt(plaintext []byte) ([]byte, error)
// Decrypt undoes Encrypt. Implementations should return a
// distinct error (typed or sentinel) on tampered / corrupted
// ciphertext so callers can react.
Decrypt(ciphertext []byte) ([]byte, error)
}
Keyring abstracts the encryption operation drops uses for column-level secrets. Production keyrings wrap a KMS (AWS KMS, GCP KMS, HashiCorp Vault, ...) and rotate keys behind the scenes; drops ships AESGCMKeyring as a zero-dep default for dev / smaller deployments.
func AESGCMKeyring ¶ added in v0.2.0
AESGCMKeyring returns a Keyring backed by AES-GCM with the supplied key (16, 24 or 32 bytes for AES-128/192/256). Nonces are 96-bit random per Seal and prepended to the ciphertext.
For production: derive the key from a KMS-backed wrapping key; rotate by re-encrypting columns under a new ring and swapping it in via SetKeyring.
func ActiveKeyring ¶ added in v0.2.0
func ActiveKeyring() Keyring
ActiveKeyring returns the registered keyring or nil.
type Listener ¶ added in v0.2.0
type Listener interface {
Listen(ctx context.Context, channel string) (<-chan Notification, error)
}
Listener is the driver contract drops uses to subscribe to a channel. Implementations should keep their own goroutine pumping notifications onto the returned channel and close it when ctx is done.
type LocalKMS ¶ added in v0.2.0
type LocalKMS struct {
// contains filtered or unexported fields
}
LocalKMS is an in-process KMS backed by a 32-byte master key. Useful for tests and local development — DO NOT use in production where the master key needs to come from an HSM / KMS service.
func NewLocalKMS ¶ added in v0.2.0
NewLocalKMS wraps key (must be 32 bytes for AES-256-GCM) as a LocalKMS. The same key must be supplied on every process restart — losing it loses every encrypted row.
type LoggerFunc ¶
type LoggerFunc = drops.LoggerFunc
LoggerFunc / LoggerOptions / LoggerHook are aliases for the dialect-neutral versions in the root drops package. They are kept here so existing pg-only call sites compile unchanged.
New code should prefer drops.LoggerHook + drops.LoggerOptions directly — the same hook works against pg.DB, clickhouse.DB and qdrant.Client without modification.
type LoggerOptions ¶
type LoggerOptions = drops.LoggerOptions
LoggerFunc / LoggerOptions / LoggerHook are aliases for the dialect-neutral versions in the root drops package. They are kept here so existing pg-only call sites compile unchanged.
New code should prefer drops.LoggerHook + drops.LoggerOptions directly — the same hook works against pg.DB, clickhouse.DB and qdrant.Client without modification.
type MatView ¶ added in v0.2.0
type MatView struct {
// Name is the (unquoted) view name.
Name string
// DependsOn lists the upstream relations (base tables and
// other materialised views) feeding into this view. Used to
// pick refresh order in RefreshDownstream.
DependsOn []string
// Mode controls REFRESH's lock semantics.
Mode RefreshMode
// Every, when non-zero, schedules a periodic refresh under
// Start.
Every time.Duration
}
MatView registers one materialised view with the manager.
type MatViewManager ¶ added in v0.2.0
type MatViewManager struct {
// contains filtered or unexported fields
}
MatViewManager tracks the registered views and coordinates refresh across dependents.
func NewMatViewManager ¶ added in v0.2.0
func NewMatViewManager(db *DB) *MatViewManager
NewMatViewManager returns an empty manager bound to db.
func (*MatViewManager) Add ¶ added in v0.2.0
func (m *MatViewManager) Add(v MatView) *MatViewManager
Add registers v. Returns the manager for chaining. Duplicate names overwrite the prior entry — typically used when the schedule changes between deployments.
func (*MatViewManager) LastRefresh ¶ added in v0.2.0
func (m *MatViewManager) LastRefresh(name string) time.Time
LastRefresh reports the last successful refresh time for a view, or zero if it has never been refreshed by this manager.
func (*MatViewManager) Refresh ¶ added in v0.2.0
func (m *MatViewManager) Refresh(ctx context.Context, name string) error
Refresh issues REFRESH MATERIALIZED VIEW (with optional CONCURRENTLY) on the single view name. Returns an error when the view is not registered or the SQL fails.
func (*MatViewManager) RefreshAll ¶ added in v0.2.0
func (m *MatViewManager) RefreshAll(ctx context.Context) error
RefreshAll refreshes every registered view in topological order. Failures abort the run.
func (*MatViewManager) RefreshDownstream ¶ added in v0.2.0
func (m *MatViewManager) RefreshDownstream(ctx context.Context, upstream string) error
RefreshDownstream refreshes every view registered with the manager that transitively depends on upstream, in topological order. Used when an upstream base table has been written to and callers want to fan the refresh out to derived views.
func (*MatViewManager) Start ¶ added in v0.2.0
func (m *MatViewManager) Start(ctx context.Context) error
Start runs the periodic scheduler honouring each view's Every interval. Blocks until ctx is cancelled.
func (*MatViewManager) Views ¶ added in v0.2.0
func (m *MatViewManager) Views() []MatView
Views returns the registered views in name-sorted order.
func (*MatViewManager) WithPollInterval ¶ added in v0.2.0
func (m *MatViewManager) WithPollInterval(d time.Duration) *MatViewManager
WithPollInterval overrides how often Start wakes to check for due refreshes. The default (250ms) is fine for typical schedules measured in seconds; turn it down for sub-second cadences or up when refreshes are minute-scale and you want to spare the timer.
type MembershipGuard ¶ added in v0.2.0
type MembershipGuard struct {
// Junction is the table that proves membership (e.g.
// organization_members, project_collaborators).
Junction *Table
// JunctionSubject is the column of Junction holding the
// subject identifier (the "who").
JunctionSubject *Column
// JunctionResource is the column of Junction pointing at the
// resource's containing group (the "what").
JunctionResource *Column
// ResourceOwner is the column on the GUARDED table that
// matches JunctionResource — e.g. invoices.organizationId
// when invoices belong to an organization.
ResourceOwner *Column
}
MembershipGuard authorises when the subject is a member of the resource's containing group, expressed as a junction table. Implements the M-N relationship pattern: "user can access invoice if user is in invoice's organization".
MembershipGuard{
Junction: OrgMembersTable,
JunctionSubject: OrgMembersTable.Col("userId"),
JunctionResource: OrgMembersTable.Col("organizationId"),
ResourceOwner: InvoicesTable.Col("organizationId"),
}
// emits: WHERE "invoices"."organizationId" IN (
// SELECT "organizationId" FROM "org_members"
// WHERE "userId" = $subject
// )
func (MembershipGuard) Predicate ¶ added in v0.2.0
func (g MembershipGuard) Predicate(ctx context.Context) (drops.Expression, error)
Predicate implements Guard.
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 Migrator ¶
type Migrator struct {
// contains filtered or unexported fields
}
Migrator runs database migrations and tracks their history in a table.
func NewMigrator ¶
NewMigrator returns a migrator bound to db. Add migrations with Add / AddSQL / AddFS, then call Up.
func (*Migrator) AddFS ¶
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 ¶
AddSQL registers a migration whose Up and Down are raw SQL. downSQL may be empty.
func (*Migrator) Down ¶
Down rolls back the most recently applied migration. Returns ErrNoMigrationsApplied if there are none.
func (*Migrator) Status ¶
Status reports every registered migration and whether it has been applied.
type Mixin ¶ added in v0.2.0
type Mixin interface {
Apply(*Table)
}
Mixin is the richer companion of the plain template functions in template.go. While a template function (Timestamps, SoftDelete, ...) only contributes columns, a Mixin can also register indexes, foreign keys, lifecycle hooks, and default filters in a single Apply call.
The two styles compose freely:
pg.ApplyMixins(Users,
pg.UUIDPrimaryKeyMixin{},
pg.TimestampsMixin{}, // adds timestamps + bumps updatedAt on UPDATE
pg.SoftDeleteMixin{}, // adds deletedAt, default-scopes queries,
// and rewrites DELETE into UPDATE
)
External libraries follow the same recipe: define a struct that holds the typed handles it will expose, implement Apply, and register whatever side effects the template needs.
type MixinFunc ¶ added in v0.2.0
type MixinFunc func(*Table)
MixinFunc adapts a plain function to the Mixin interface — useful when a template doesn't need its own state.
type Money ¶ added in v0.2.0
type Money struct {
// contains filtered or unexported fields
}
Money is a precision-safe monetary amount represented as a signed 64-bit integer in minor units (cents for USD, eurocents for EUR, etc.). The default exponent is 2 decimal places — override at declaration time when the currency uses something else (JPY=0, BTC=8).
type Payment struct {
ID int64 `drop:"id,primaryKey,autoIncrement"`
Amount pg.Money `drop:"amount"`
}
p := Payment{Amount: pg.MoneyFromString("12.34")}
p.Amount = p.Amount.Add(pg.MoneyFromCents(50))
p.Amount = p.Amount.MulRate(0.10) // apply 10% (banker's rounding)
Floats in monetary code are bugs waiting to ship — Money never converts to float for storage or comparison; only MulRate uses a floating-point factor and rounds half-to-even at the end. For chains of percentage operations, use Decimal in a future commit.
Wire / storage: bigint (cents). JSON: string in canonical "<sign>?<integer>.<fraction>" form so JavaScript clients don't lose precision on values > 2^53.
Equality, ordering and zero-checks compare cents directly, so two Money values with the same cents but different exponents are NOT equal — wrap mixed-exponent stores carefully.
func MoneyFromCents ¶ added in v0.2.0
MoneyFromCents returns a Money expressed as a count of minor units at the default 2-place exponent.
func MoneyFromString ¶ added in v0.2.0
MoneyFromString parses "12.34", "-1.5", "10" into Money at the default 2-place exponent. Truncates extra fractional digits; callers needing different rounding should pre-round.
func MoneyFromUnits ¶ added in v0.2.0
MoneyFromUnits returns a Money for the supplied whole-number amount (units) plus a minor-unit remainder (cents). 12.34 -> MoneyFromUnits(12, 34).
func MoneyWithExponent ¶ added in v0.2.0
MoneyWithExponent returns a Money with explicit precision. Use for currencies whose minor unit isn't 1/100 (JPY uses 0, BTC often uses 8).
func (Money) Add ¶ added in v0.2.0
Add returns m + other. Panics on exponent mismatch — the caller should normalise first.
func (Money) Compare ¶ added in v0.2.0
Compare returns -1, 0, +1 if m is less than, equal to, greater than other.
func (Money) IsNegative ¶ added in v0.2.0
IsNegative reports whether the amount is < 0.
func (Money) MarshalJSON ¶ added in v0.2.0
MarshalJSON renders as a string to preserve precision on JS clients (numbers > 2^53 lose precision in JSON.parse).
func (Money) MulRate ¶ added in v0.2.0
MulRate scales m by a floating-point rate (e.g. tax 0.07). The result is rounded half-to-even (banker's rounding) to keep rounding bias out of long sums. Use for tax / fee / interest calculations where the rate is genuinely a fraction.
Float precision means MulRate is appropriate for rates with at most ~12 significant digits; for sub-cent precision over many operations, use a dedicated decimal library and round once at the end.
func (*Money) UnmarshalJSON ¶ added in v0.2.0
UnmarshalJSON accepts string ("12.34"), number (123) or null.
type MorphMap ¶ added in v0.2.0
type MorphMap struct {
// contains filtered or unexported fields
}
MorphMap binds a polymorphic discriminator string to the target table and Go struct it identifies. Build it once and share it between the MorphTo declarations that need it.
func NewMorphMap ¶ added in v0.2.0
func NewMorphMap() *MorphMap
NewMorphMap returns an empty MorphMap.
type N1Report ¶ added in v0.2.0
N1Report summarises the queries observed during a tracked context's lifetime. Patterns lists every SQL skeleton that fired at least Threshold times.
type Notification ¶ added in v0.2.0
Notification is one delivery from PG's NOTIFY mechanism.
type NullsOrdering ¶ added in v0.2.0
type NullsOrdering string
NullsOrdering is the NULLS FIRST / NULLS LAST modifier on an ORDER BY clause.
const ( // NullsDefault inherits PostgreSQL's per-direction default. NullsDefault NullsOrdering = "" // NullsFirst pushes NULL values to the start of the order. NullsFirst NullsOrdering = "FIRST" // NullsLast pushes NULL values to the end of the order. NullsLast NullsOrdering = "LAST" )
type OrderKey ¶ added in v0.2.0
type OrderKey struct {
// Col is the column referenced by both the ORDER BY clause
// and the keyset WHERE comparison.
Col ColRef
// Desc selects descending order. Defaults to ascending.
Desc bool
// Nulls picks the NULLS FIRST / NULLS LAST clause. Leaving
// it empty inherits PG's default ("NULLS LAST" for ASC,
// "NULLS FIRST" for DESC). Cursor columns are typically
// non-null (timestamps, IDs) so the default is fine — but
// when you cursor on nullable columns set this explicitly
// so the WHERE clause and ORDER BY agree.
Nulls NullsOrdering
}
OrderKey is one (column, direction) pair making up a cursor shape. Combine multiple OrderKey values in a CursorSpec to form a stable ordering — the typical pattern is (sort_column DESC, primary_key DESC) so rows with identical sort values still produce a unique page boundary.
type OrderingColumn ¶ added in v0.2.0
type OrderingColumn struct {
// contains filtered or unexported fields
}
OrderingColumn pairs a *Column with its sort direction. Build one with Asc / Desc.
func Asc ¶ added in v0.2.0
func Asc(c ColRef) OrderingColumn
Asc returns an OrderingColumn for c sorted ascending. Accepts either *Column or *Col[T] via ColRef.
func Desc ¶ added in v0.2.0
func Desc(c ColRef) OrderingColumn
Desc returns an OrderingColumn for c sorted descending.
type Outbox ¶ added in v0.2.0
type Outbox struct {
// contains filtered or unexported fields
}
Outbox is the transactional outbox pattern wired to drops/pg. It solves the "publish only if the DB write committed" problem by writing the event into a co-resident outbox table inside the same transaction as the business write; a background worker then drains the table and hands rows to a publisher.
// Schema setup (once)
OutboxTable := pg.NewOutboxTable("outbox")
schema := pg.NewSchema(Users, OutboxTable)
_ = pg.Push(ctx, db, schema)
// Emit inside the business transaction
ob := pg.NewOutbox(db, "outbox").WithNotifyChannel("outbox_event")
err := db.InTx(ctx, func(tx *pg.DB) error {
if err := UserEntity.Create(tx, ctx, &u); err != nil { return err }
return ob.EmitWith(tx, ctx, "user.created", u, pg.EmitOptions{
AggregateType: "user",
AggregateID: fmt.Sprintf("%d", u.ID),
Headers: map[string]string{"traceparent": tp},
})
})
// Drain in a worker goroutine
worker := pg.NewOutboxWorker(ob).
WithInterval(1 * time.Second).
WithMaxAttempts(10).
WithBackoff(pg.ExponentialJitter(time.Second, 5*time.Minute)).
WithOrdering(pg.OrderingPerAggregate).
OnEvent(func(ctx context.Context, e pg.OutboxEvent) error {
return publisher.Publish(ctx, e.Kind, e.Payload)
})
go worker.Run(ctx)
The pattern is at-least-once: a crash between publish and the follow-up UPDATE marking the row published will replay it. Make the publisher idempotent on Kind+Payload — or use the per-event id as the dedup key downstream.
func NewOutbox ¶ added in v0.2.0
NewOutbox returns an Outbox bound to db. Table is the SQL identifier of the outbox table; use NewOutboxTable to declare matching DDL.
func (*Outbox) Cleanup ¶ added in v0.2.0
Cleanup deletes rows that were published more than retainAfter ago. Run periodically (typically once per minute) to keep the outbox table small; without it the table grows unbounded and the drain index, although partial, still has to skip stale rows during VACUUM.
Failed (terminal) rows are intentionally kept — they're the audit log of poison messages. Drop them manually after triage.
func (*Outbox) Drain ¶ added in v0.2.0
Drain fetches up to limit unpublished, non-failed, available events for processing. Uses SKIP LOCKED so multiple workers can drain in parallel without stepping on each other. Caller must mark rows published via MarkPublished when the handler succeeds, or MarkFailed when it errors.
func (*Outbox) DrainAggregate ¶ added in v0.2.0
func (o *Outbox) DrainAggregate(ctx context.Context, aggregateType, aggregateID string, limit int, fn func(tx *DB, events []OutboxEvent) error) error
DrainAggregate fetches events for a single aggregate in id order, under a transaction-scoped advisory lock keyed on the aggregate ID. Parallel workers calling DrainAggregate for the same aggregate skip silently (the lock is non-blocking), so per-aggregate order is preserved without serialising the whole worker pool.
The callback executes within the lock-holding transaction; the lock auto-releases when the transaction ends. Returning an error rolls the transaction back — typically used so partial progress (MarkPublished calls) inside the callback is undone on failure.
func (*Outbox) Emit ¶ added in v0.2.0
Emit inserts an event using tx (typically the *DB passed into the InTx callback). Encodes payload as JSON; pass an already-encoded json.RawMessage to keep control of the serialisation.
Equivalent to EmitWith with zero EmitOptions.
func (*Outbox) EmitWith ¶ added in v0.2.0
func (o *Outbox) EmitWith(tx *DB, ctx context.Context, kind string, payload any, opts EmitOptions) error
EmitWith is the extended variant carrying aggregate metadata and tracing headers — see EmitOptions.
func (*Outbox) MarkFailed ¶ added in v0.2.0
func (o *Outbox) MarkFailed(ctx context.Context, id int64, attempts int, nextRetryAt time.Time, lastErr string) error
MarkFailed records a handler failure on the supplied event. When nextRetryAt is the zero value the row is parked as terminally failed (failedAt set, won't be drained again). Otherwise the row becomes available for retry at nextRetryAt with attempts bumped and the error message stored in lastError.
func (*Outbox) MarkPublished ¶ added in v0.2.0
MarkPublished updates the publishedAt timestamp for the supplied event ids. Safe to call repeatedly; subsequent drains skip published rows.
func (*Outbox) NotifyChannel ¶ added in v0.2.0
NotifyChannel returns the configured pg_notify channel, or "" if none was set.
func (*Outbox) PendingAggregates ¶ added in v0.2.0
PendingAggregates returns up to limit distinct aggregate keys that have unpublished work available right now. Used by the per- aggregate worker mode to discover which advisory locks to try.
func (*Outbox) WithNotifyChannel ¶ added in v0.2.0
WithNotifyChannel makes Emit also issue pg_notify(channel, id) so a worker that LISTENs on the same channel wakes immediately instead of waiting for the polling tick. Falls back gracefully when the driver does not implement Listener — Emit succeeds either way; only the wakeup latency degrades.
type OutboxBatchHandler ¶ added in v0.2.0
type OutboxBatchHandler func(ctx context.Context, events []OutboxEvent) error
OutboxBatchHandler is the batched alternative — receives the entire drain batch in one call. Useful for message brokers with expensive per-call overhead (Kafka producer, etc.).
Returning nil marks every event in the batch published; returning an error fails every event in the batch (each row's attempts is bumped). Use OnEvent if you need per-event success granularity.
type OutboxEvent ¶ added in v0.2.0
type OutboxEvent struct {
ID int64
Kind string
AggregateType string
AggregateID string
Payload json.RawMessage
Headers map[string]string
Attempts int
LastError string
CreatedAt time.Time
}
OutboxEvent is one drained row.
type OutboxHandler ¶ added in v0.2.0
type OutboxHandler func(ctx context.Context, e OutboxEvent) error
OutboxHandler is the per-event callback the worker invokes when configured via OnEvent. Returning nil marks the row published; returning an error schedules a retry (or terminal failure when MaxAttempts has been reached).
type OutboxOrdering ¶ added in v0.2.0
type OutboxOrdering int
OutboxOrdering controls how the worker schedules events.
const ( // OrderingNone delivers events as soon as drain returns them. // Highest throughput; events for different aggregates can // interleave, and parallel workers may deliver out of order // within the same aggregate when timestamps tie. OrderingNone OutboxOrdering = iota // OrderingPerAggregate preserves emission order within each // (AggregateType, AggregateID) by routing each aggregate // through a single worker at a time via advisory locks. // Events that lack an AggregateID fall back to OrderingNone. OrderingPerAggregate )
type OutboxWorker ¶ added in v0.2.0
type OutboxWorker struct {
// contains filtered or unexported fields
}
OutboxWorker polls the outbox table and forwards rows to a handler. Single goroutine per worker; spin up several with distinct names to parallelise drain — SKIP LOCKED keeps them from collisions.
func NewOutboxWorker ¶ added in v0.2.0
func NewOutboxWorker(ob *Outbox) *OutboxWorker
NewOutboxWorker returns a worker with sensible defaults: 1s polling interval, 50-row batch, exponential-jitter backoff (1s base, capped at 5min), unlimited retries.
func (*OutboxWorker) OnBatch ¶ added in v0.2.0
func (w *OutboxWorker) OnBatch(fn OutboxBatchHandler) *OutboxWorker
OnBatch attaches the batch handler. Mutually exclusive with OnEvent — whichever was set last wins.
func (*OutboxWorker) OnError ¶ added in v0.2.0
func (w *OutboxWorker) OnError(fn func(error)) *OutboxWorker
OnError attaches an error sink for drain / mark-published failures. Handler errors are reported through MarkFailed and do not surface here.
func (*OutboxWorker) OnEvent ¶ added in v0.2.0
func (w *OutboxWorker) OnEvent(fn OutboxHandler) *OutboxWorker
OnEvent attaches the per-event handler. Mutually exclusive with OnBatch — whichever was set last wins.
func (*OutboxWorker) Run ¶ added in v0.2.0
func (w *OutboxWorker) Run(ctx context.Context) error
Run drains the outbox until ctx is cancelled. Blocks the calling goroutine; typically invoked via go worker.Run(ctx). Returns the reason for termination — typically ctx.Err().
When the underlying Outbox was configured with WithNotifyChannel and the driver implements Listener, Run wakes immediately on each NOTIFY in addition to the periodic tick — sub-second delivery without hammering the database.
func (*OutboxWorker) WithBackoff ¶ added in v0.2.0
func (w *OutboxWorker) WithBackoff(fn func(attempt int) time.Duration) *OutboxWorker
WithBackoff overrides the per-attempt retry delay. The function receives the new attempt count (1-based) and returns how long to wait before the next try. Defaults to ExponentialJitter(1s, 5min).
func (*OutboxWorker) WithBatch ¶ added in v0.2.0
func (w *OutboxWorker) WithBatch(n int) *OutboxWorker
WithBatch overrides the per-tick batch size.
func (*OutboxWorker) WithInterval ¶ added in v0.2.0
func (w *OutboxWorker) WithInterval(d time.Duration) *OutboxWorker
WithInterval overrides the polling cadence. Returns the worker for chaining.
func (*OutboxWorker) WithMaxAttempts ¶ added in v0.2.0
func (w *OutboxWorker) WithMaxAttempts(n int) *OutboxWorker
WithMaxAttempts caps the retry count. After n attempts the row is marked terminally failed (failedAt set) and never drained again — surface it via metrics / alerting and drop manually after triage. Zero means unlimited retries.
func (*OutboxWorker) WithOrdering ¶ added in v0.2.0
func (w *OutboxWorker) WithOrdering(m OutboxOrdering) *OutboxWorker
WithOrdering selects the scheduling strategy. See OutboxOrdering.
type OwnerGuard ¶ added in v0.2.0
type OwnerGuard struct {
Owner *Column
}
OwnerGuard authorises when the subject matches an ownership column on the resource — the simplest possible rule.
OwnerGuard{Owner: PostsTable.Col("authorId")}
// emits: WHERE "posts"."authorId" = $subject
func (OwnerGuard) Predicate ¶ added in v0.2.0
func (g OwnerGuard) Predicate(ctx context.Context) (drops.Expression, error)
Predicate implements Guard.
type PIIParam ¶ added in v0.2.0
type PIIParam struct{ Value any }
PIIParam is a drops.Expression that AddArgs a value already wrapped in the redaction marker. Used internally by entity bindings when the column is flagged PII.
type Page ¶ added in v0.2.0
Page is the typed result of a cursor-based pagination. NextCursor is empty when no further rows exist; HasMore short-circuits the presence check.
type PageBuilder ¶ added in v0.2.0
type PageBuilder[T any] struct { // contains filtered or unexported fields }
PageBuilder composes a cursor-paginated query. It exists to keep the cursor encoding/decoding internal — callers never construct or inspect cursors directly.
Cursors are opaque, URL-safe base64 strings whose payload is a gob-encoded slice of the ordering columns' values. Stable as long as the OrderBy spec doesn't change between calls.
func (*PageBuilder[T]) After ¶ added in v0.2.0
func (p *PageBuilder[T]) After(cursor string) *PageBuilder[T]
After resumes iteration after the supplied cursor. Pass the empty string for the first page.
func (*PageBuilder[T]) All ¶ added in v0.2.0
func (p *PageBuilder[T]) All(ctx context.Context) (*Page[T], error)
All runs the query and returns the page.
func (*PageBuilder[T]) Limit ¶ added in v0.2.0
func (p *PageBuilder[T]) Limit(n int) *PageBuilder[T]
Limit caps the page size. Defaults to 50.
func (*PageBuilder[T]) OrderBy ¶ added in v0.2.0
func (p *PageBuilder[T]) OrderBy(cols ...OrderingColumn) *PageBuilder[T]
OrderBy fixes the cursor's stability axis. At least one column is required; the last column should be unique (typically the PK) so every row has a distinct cursor.
func (*PageBuilder[T]) Where ¶ added in v0.2.0
func (p *PageBuilder[T]) Where(preds ...drops.Expression) *PageBuilder[T]
Where appends predicates joined by AND. Composes with the cursor guard so additional filters narrow the page set.
type PatchOp ¶ added in v0.2.0
type PatchOp interface {
// contains filtered or unexported methods
}
PatchOp describes one SET assignment in a Patch. Construct one with Inc / Dec / SetVal / SetIfGreater / SetIfLess / SetIfChanged.
func Inc ¶ added in v0.2.0
Inc emits "col = col + delta". For unsigned counters use a non-negative delta; for decrements pass a negative one or use Dec.
func Set ¶ added in v0.2.0
Set is a typed plain assignment — equivalent to (*Col[T]).Val but usable in the Patch op list alongside the SQL-side ops.
func SetIfChanged ¶ added in v0.2.0
SetIfChanged emits "col = $1" only when $1 differs from the current value — implemented as a CASE WHEN so the row is touched (and triggers fire) even if no change happens. Useful when the surrounding entity has hook-driven side effects you don't want to elide silently.
func SetIfGreater ¶ added in v0.2.0
SetIfGreater emits "col = GREATEST(col, $1)" — only raises the value, never lowers it. Useful for high-watermark counters (max score, last-seen timestamp).
type PgEnum ¶
type PgEnum struct {
// contains filtered or unexported fields
}
PgEnum describes a PostgreSQL enum type. Use it to declare the type once and then reference it from one or more columns via EnumCol.
type PgError ¶ added in v0.2.0
type PgError struct {
// Code is the five-character SQLSTATE class returned by the
// driver, e.g. "23505".
Code string
// Constraint is the offending constraint name when the driver
// reports it. Empty for failures unrelated to a constraint.
Constraint string
// Sentinel is the package-level Err* value classifying the
// error. nil when the SQLSTATE was recognised but is not
// mapped, or when no SQLSTATE was reported at all.
Sentinel error
// Err is the original driver error. Use errors.Unwrap to reach
// it directly.
Err error
}
PgError wraps a driver-level error with the matching typed Sentinel, the SQLSTATE class, and (when available) the constraint name. Use errors.Is(err, pg.ErrXxx) to branch on the failure mode, or type-assert through errors.As to read Code / Constraint.
type PgSequence ¶ added in v0.2.0
type PgSequence struct {
// contains filtered or unexported fields
}
PgSequence describes a top-level PostgreSQL sequence. Wrap SequenceOptions (already used by CreateSequence) so the configuration matches whatever DDL the runtime emits at apply time.
func NewSequence ¶ added in v0.2.0
func NewSequence(name string, opts ...SequenceOptions) *PgSequence
NewSequence declares a sequence by name with optional configuration. opts is variadic so the common "default everything" case is a single-arg call.
func (*PgSequence) Name ¶ added in v0.2.0
func (s *PgSequence) Name() string
Name returns the sequence's identifier.
func (*PgSequence) Options ¶ added in v0.2.0
func (s *PgSequence) Options() SequenceOptions
Options returns the configuration the sequence was declared with.
type PgView ¶ added in v0.2.0
type PgView struct {
// contains filtered or unexported fields
}
PgView describes a (regular or materialized) view. Definition is the body that follows AS — typically a SELECT.
func MaterializedView ¶ added in v0.2.0
MaterializedView is the materialised counterpart of View — the same fluent builder with the materialised flag pre-set so the chain reads naturally.
func NewMaterializedView ¶ added in v0.2.0
NewMaterializedView declares a materialized view.
func View ¶ added in v0.2.0
View opens a fluent builder for a regular view. Chain As (typed SelectBuilder) or AsSQL (raw SELECT text), optionally Materialized, to finalise:
pg.View("activeUsers").As(
db.Select(Users.ID, Users.Name).
From(Users).
Where(Users.Active.Eq(true)))
pg.View("playerStats").
Materialized().
As(query)
NewView / NewMaterializedView remain available for the definition-as-string fast path.
func (*PgView) As ¶ added in v0.2.0
func (v *PgView) As(sel *SelectBuilder) *PgView
As wires the view body from a SelectBuilder. Parameter bindings ($1, $2, ...) are inlined as SQL literals because view definitions are static SQL — CREATE VIEW doesn't accept bound parameters. Unsupported parameter types panic at declaration time so the schema fails loudly at startup instead of producing broken DDL.
func (*PgView) AsSQL ¶ added in v0.2.0
AsSQL sets the view body from raw SQL — escape hatch for SELECT shapes the builder doesn't cover (recursive CTEs, dialect-specific functions, hand-tuned plans). Caller is responsible for any literal escaping.
func (*PgView) Definition ¶ added in v0.2.0
Definition returns the view's SELECT body.
func (*PgView) IsMaterialized ¶ added in v0.2.0
IsMaterialized reports whether this is a materialized view.
func (*PgView) Materialized ¶ added in v0.2.0
Materialized flips the view kind to materialised. Returns the same *PgView for chaining.
type PlanDiff ¶ added in v0.2.0
type PlanDiff struct {
// BeforeFingerprint / AfterFingerprint are the structural
// hashes used to detect change. Identical values mean the
// planner produced equivalent shapes.
BeforeFingerprint string
AfterFingerprint string
// Same is shorthand for BeforeFingerprint == AfterFingerprint.
Same bool
// SeqScansAdded / SeqScansRemoved name the relations that
// gained / lost a Seq Scan between the two plans. A regression
// commonly shows up as a relation moving from index to seq.
SeqScansAdded []string
SeqScansRemoved []string
// IndexesAdded / IndexesRemoved name the indexes the planner
// started / stopped using.
IndexesAdded []string
IndexesRemoved []string
// CostDelta is the difference in TotalCost (after - before).
// Positive means the new plan is more expensive.
CostDelta float64
// RowsDelta is the difference in estimated rows
// (after - before).
RowsDelta int64
}
PlanDiff describes the structural change between two plans for the same query. Same is true when fingerprints match — every other field is then zero / empty.
func DiffPlans ¶ added in v0.2.0
func DiffPlans(before, after *ExplainPlan) PlanDiff
DiffPlans compares two captured plans of the same query. Returns a structured diff highlighting plan shape changes that typically matter for tail latency.
type PlanNode ¶ added in v0.2.0
type PlanNode struct {
// Type is the PostgreSQL node label — "Seq Scan", "Index
// Scan", "Hash Join", "Sort", "Aggregate", ...
Type string
// Relation is the table name when Type touches a relation.
Relation string
// Index is the index name when Type is an index scan / search.
Index string
// JoinType is the join kind when Type is a join node.
JoinType string
// StartupCost / TotalCost are the planner's cost estimates.
StartupCost float64
TotalCost float64
// PlanRows is the planner's row-count estimate; ActualRows
// the EXPLAIN ANALYZE measured value (0 without Analyze).
PlanRows int64
ActualRows int64
// ActualMs is the total time spent in this node when Analyze
// was set. Zero otherwise.
ActualMs float64
// Children are the sub-plans feeding into this node, in
// declaration order.
Children []*PlanNode
}
PlanNode is one node in the plan tree.
type Point ¶ added in v0.2.0
Point is a (latitude, longitude) pair in WGS84 (SRID 4326).
func (*Point) Scan ¶ added in v0.2.0
Scan implements sql.Scanner. Accepts:
- WKT text: "POINT(lon lat)" or "SRID=4326;POINT(lon lat)"
- EWKB hex: the default form PostGIS returns from a geography column.
Drivers that pre-parse the geometry into a custom type are not supported; force text output via ST_AsText if needed.
type Policy ¶ added in v0.2.0
type Policy struct {
// contains filtered or unexported fields
}
Policy is a row-level security policy attached to a table. The shape mirrors PostgreSQL's CREATE POLICY syntax exactly so emitting DDL stays mechanical.
func NewPolicy ¶ added in v0.2.0
NewPolicy declares a row-level security policy by name. Pair with Table.AddPolicy.
func (*Policy) For ¶ added in v0.2.0
For sets the command the policy applies to ("ALL", "SELECT", "INSERT", "UPDATE", "DELETE"). Defaults to "ALL".
func (*Policy) Restrictive ¶ added in v0.2.0
Restrictive flips the policy to RESTRICTIVE (default is PERMISSIVE).
func (*Policy) Roles ¶ added in v0.2.0
Roles returns the roles the policy is scoped to (or nil for PUBLIC).
func (*Policy) To ¶ added in v0.2.0
To restricts the policy to the named roles. Without any role the policy applies to PUBLIC.
func (*Policy) Using ¶ added in v0.2.0
Using sets the USING expression — the predicate that decides which rows are visible / mutable.
func (*Policy) WithCheck ¶ added in v0.2.0
WithCheck sets the WITH CHECK expression — the predicate that rows must satisfy after an INSERT / UPDATE. Defaults to the USING expression when omitted.
func (*Policy) WithCheckExpr ¶ added in v0.2.0
WithCheckExpr returns the WITH CHECK expression text.
type PolicySnapshot ¶ added in v0.2.0
type PolicySnapshot struct {
Name string `json:"name"`
As string `json:"as"`
For string `json:"for"`
To []string `json:"to"`
Using string `json:"using"`
WithCheck string `json:"withCheck"`
}
PolicySnapshot is one entry in TableSnapshot.Policies.
type PoolStats ¶ added in v0.2.0
type PoolStats struct {
// MaxOpenConnections is the configured pool ceiling.
MaxOpenConnections int
// OpenConnections is the current count of live conns.
OpenConnections int
// InUse is the count currently held by a caller.
InUse int
// Idle is the count parked in the pool.
Idle int
// WaitCount is the cumulative count of waits for a free
// conn since pool creation.
WaitCount int64
// WaitDuration is the cumulative time waited.
WaitDuration time.Duration
// MaxIdleClosed is the cumulative count of conns closed
// because Idle exceeded MaxIdleConns.
MaxIdleClosed int64
// MaxIdleTimeClosed is the cumulative count closed because
// they sat idle longer than MaxIdleTime.
MaxIdleTimeClosed int64
// MaxLifetimeClosed is the cumulative count closed because
// they lived longer than ConnMaxLifetime.
MaxLifetimeClosed int64
}
PoolStats is a snapshot of the underlying pool's health counters. Mirrors database/sql.DBStats with descriptive names so prometheus / OpenTelemetry adapters are direct.
type PoolStatsProvider ¶ added in v0.2.0
type PoolStatsProvider interface {
Stats() PoolStats
}
PoolStatsProvider is the contract a driver implements when it can surface pool stats. database/sql.DB satisfies it natively (Stats() returns sql.DBStats which is the same shape).
type PushOptions ¶
type PushOptions struct {
// Schema restricts introspection to one PostgreSQL schema. Empty
// defaults to "public".
Schema string
// Safe wraps every destructive or creative DDL in IF [NOT] EXISTS
// so the apply is idempotent and safe to retry.
Safe bool
// DryRun returns the statements that would be applied without
// executing them. Useful for previewing changes in CI.
DryRun bool
}
PushOptions tunes how Push applies schema changes.
type PushResult ¶
type PushResult struct {
// Statements is the ordered SQL diff between the live database and
// the supplied Go schema.
Statements []string
// Applied is true when the statements were executed (false for
// DryRun, or when the diff was empty).
Applied bool
}
PushResult is the outcome of a Push call.
func Push ¶
func Push(ctx context.Context, db *DB, schema *Schema, opts ...PushOptions) (*PushResult, error)
Push introspects the live database, diffs it against the supplied Go schema, and applies the changes — drops's equivalent of drizzle-kit's `push` command.
Behaviour:
- Reads the current state of the configured schema via Introspect.
- Builds a target snapshot from `schema`.
- Diffs the two using DiffOptions{Safe: opts.Safe}.
- If DryRun, returns the statements unexecuted.
- Otherwise applies them inside a single transaction; any failure rolls back the whole push.
Push is convenient for development but skips migration history. For production use, prefer GenerateMigration + DrizzleMigrator so changes are reviewable and reproducible.
type RefreshMode ¶ added in v0.2.0
type RefreshMode int
RefreshMode controls whether REFRESH locks the view or runs CONCURRENTLY (no lock, but the view must have a UNIQUE index).
const ( // RefreshLocking issues plain REFRESH MATERIALIZED VIEW — // fastest but takes ACCESS EXCLUSIVE on the view for the // duration. Acceptable on small views during quiet hours. RefreshLocking RefreshMode = iota // RefreshConcurrently issues REFRESH MATERIALIZED VIEW // CONCURRENTLY — readers stay unblocked but the view must // have a UNIQUE index defined. RefreshConcurrently )
type RelConfig ¶
type RelConfig struct {
// contains filtered or unexported fields
}
RelConfig configures a single eager-loaded relation: filter the related rows with Where, order them with OrderBy, and declare deeper relations with With/WithRel. It is handed to the callback passed to WithRel.
Where predicates and OrderBy expressions reference the related table's columns and are applied to that relation's batched query, so they cost nothing extra — one query per edge, just narrower or sorted.
func (*RelConfig) Limit ¶ added in v0.2.0
Limit caps the number of related rows attached PER PARENT. Implemented via a ROW_NUMBER() window over the join key:
SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY <fk> ORDER BY <orderBy>) AS _rn FROM <child> WHERE <fk> IN (...) ) AS _ranked WHERE _rn > <offset> AND _rn <= <offset> + <limit>
so each parent's slice gets the first N children (after the configured ORDER BY), not the first N rows globally. Mirrors drizzle's with: { posts: { limit: 5 } } shape.
Limit only applies to HasMany / MorphMany / ManyToMany — single-row relations (HasOne / BelongsTo) already cap at 1. Limit ≤ 0 disables the cap.
func (*RelConfig) Offset ¶ added in v0.2.0
Offset skips the first N matching rows per parent. Requires Limit to be set (offset alone produces every row past N which rarely matches caller intent — when you really need that, combine Offset with a very large Limit).
func (*RelConfig) OrderBy ¶
func (c *RelConfig) OrderBy(exprs ...drops.Expression) *RelConfig
OrderBy appends ORDER BY expressions to this relation's batched query. Each parent's loaded slice ends up in this order.
func (*RelConfig) Where ¶
func (c *RelConfig) Where(preds ...drops.Expression) *RelConfig
Where AND-s predicates into this relation's batched query, filtering the related rows (e.g. only published posts).
type Relation ¶
type Relation struct {
Name string
Kind RelationKind
From *Table
To *Table
ParentKey *Column
ChildKey *Column
// Junction-table fields, populated only for ManyToManyKind.
Through *Table
ThroughFK1 *Column
ThroughFK2 *Column
// Polymorphic fields, populated for MorphToKind / MorphManyKind.
// MorphTypeCol is the discriminator column.
// MorphMap maps the discriminator value to a target table + Go
// struct type (MorphToKind only).
// MorphType is the discriminator value identifying this side of
// the polymorphic edge (MorphManyKind only).
MorphTypeCol *Column
MorphMap *MorphMap
MorphType string
}
Relation describes a foreign-key relationship between two tables.
HasMany / HasOne: From is the parent, To is the child. ParentKey is the column on From (typically the PK). ChildKey is the FK column on To pointing back at ParentKey. BelongsTo: From is the child, To is the parent. ChildKey is the FK column on From. ParentKey is the column on To pointed at by ChildKey. ManyToMany: From and To are joined through a junction Table. ParentKey is the column on From (typically the PK). ChildKey is the column on To (typically the PK). Through is the junction table. ThroughFK1 is the FK on Through pointing back to ParentKey. ThroughFK2 is the FK on Through pointing to ChildKey.
type RelationKind ¶
type RelationKind int
RelationKind identifies the cardinality of a Relation.
const ( // HasMany: the parent owns zero or more children. The relation is // loaded as a slice on the parent struct. HasManyKind RelationKind = iota // HasOne: the parent owns at most one child. The relation is loaded // as a struct or pointer-to-struct on the parent. HasOneKind // BelongsTo: this row references one parent. The relation is loaded // as a struct or pointer-to-struct. BelongsToKind // ManyToMany: parent and target are linked through a junction table. // The relation is loaded as a slice on the parent struct. ManyToManyKind // MorphTo: a polymorphic belongs-to — each row references a parent // in one of several possible tables, identified by a type // discriminator column. The relation field is typed `any` and // holds a pointer to the loaded parent struct after eager loading. MorphToKind // MorphMany: the inverse of MorphTo — fetches every child whose // morph_type equals a fixed value and morph_id equals the parent's // PK. The relation is loaded as a slice on the parent struct. MorphManyKind )
type Relations ¶
type Relations struct {
// contains filtered or unexported fields
}
Relations is the registration handle for one table. Use NewRelations followed by HasMany/HasOne/BelongsTo to declare relations:
pg.NewRelations(Users).
HasMany("posts", Posts, UserID, PostUserID).
HasOne("profile", Profiles, UserID, ProfileUserID)
pg.NewRelations(Posts).
BelongsTo("author", Users, PostUserID, UserID)
func NewRelations ¶
NewRelations begins relation declarations for t. The returned handle stores its declarations on t directly.
func (*Relations) BelongsTo ¶
BelongsTo declares a many-to-one relation.
childFK: FK column on the current table. parentKey: column on `parent` pointed at by childFK.
func (*Relations) HasMany ¶
HasMany declares a one-to-many relation.
parentKey: column on the current table (usually the PK). childFK: FK column on `child` pointing at parentKey.
func (*Relations) HasOne ¶
HasOne declares a one-to-one relation. The cardinality is enforced by data conventions, not by SQL — it loads at most one row per parent.
func (*Relations) ManyToMany ¶
func (r *Relations) ManyToMany( name string, target *Table, through *Table, throughLocal, throughRemote ColRef, localKey, targetKey ColRef, ) *Relations
ManyToMany declares a many-to-many relation through a junction table.
target: the related table through: the junction table throughLocal: FK on through pointing back at the current table throughRemote: FK on through pointing at the target table localKey: key on the current table (typically the PK) targetKey: key on the target table (typically the PK)
Loading runs two queries: one to fetch the junction rows for the parent IDs, one to fetch the target rows for the unique remote IDs. The relation field on the parent struct must be a slice.
func (*Relations) MorphMany ¶ added in v0.2.0
func (r *Relations) MorphMany( name string, child *Table, childTypeCol, childIDCol ColRef, parentKey ColRef, typeValue string, ) *Relations
MorphMany declares the inverse of MorphTo: every row in `child` whose typeCol equals typeValue and whose idCol equals the parent's PK becomes a member of the parent's named relation.
pg.NewRelations(Users).
MorphMany("comments", Comments,
CommentCommentableType, CommentCommentableID,
UserID, "users")
typeValue is the literal string the child's typeCol carries when it points at this side of the morph — typically the parent's table name in the MorphMap registered on the MorphTo side.
func (*Relations) MorphTo ¶ added in v0.2.0
MorphTo declares a polymorphic belongs-to relation. The current table has two columns — typeCol holding a discriminator string and idCol holding the target's primary-key value. Each entry registered on morphs binds a discriminator value to a target table and the Go struct used to scan its rows.
morphs := pg.NewMorphMap()
pg.RegisterMorph[User](morphs, "users", Users)
pg.RegisterMorph[Post](morphs, "posts", Posts)
pg.NewRelations(Comments).
MorphTo("commentable", CommentCommentableType, CommentCommentableID, morphs)
The relation field on the child struct must be declared `any` (or any interface type) — the loader stores a *Parent pointer into it and the caller dispatches with a type switch.
type Replicated ¶ added in v0.2.0
type Replicated struct {
// contains filtered or unexported fields
}
Replicated wraps a primary driver and any number of read-only replicas. Exec / Begin always go to the primary; Query is routed round-robin to a replica unless the caller is inside a read-your-writes window (see WithReadYourWrites), in which case reads stick to the primary so a follow-up SELECT after a write observes the new state.
It implements drops.Driver, so you wire it into a regular *pg.DB:
primary := stdlib.New(primarySQL) r1 := stdlib.New(replica1SQL) r2 := stdlib.New(replica2SQL) repl := pg.NewReplicated(primary, r1, r2) db := pg.New(repl) // Sticky read-your-writes: any Exec on ctx starts a 2s window; // follow-up Queries stay on the primary for that window so // the read observes the prior write. ctx = pg.WithReadYourWrites(ctx, 2*time.Second) _ = UserEntity.Update(db, ctx, &u) got, _ := UserEntity.Get(db, ctx, u.ID) // hits primary
Without replicas, Replicated is identical to wrapping primary directly — Query falls back to the primary.
func NewReplicated ¶ added in v0.2.0
func NewReplicated(primary drops.Driver, replicas ...drops.Driver) *Replicated
NewReplicated returns a Replicated driver. Pass zero replicas for a primary-only setup that still respects WithReadYourWrites.
func (*Replicated) Begin ¶ added in v0.2.0
Begin opens a transaction on the primary. Transactional reads share the same connection as the writes, so consistency is guaranteed without needing the read-your-writes window.
func (*Replicated) Close ¶ added in v0.2.0
func (r *Replicated) Close() error
Close closes every underlying driver that exposes Close, returning the first error encountered.
func (*Replicated) Exec ¶ added in v0.2.0
Exec routes through the primary. The call also re-arms any read-your-writes window attached to ctx so subsequent reads on the same context stay sticky — and, when LSN tracking is enabled, captures pg_current_wal_lsn() so reads can route to a caught-up replica instead of unconditionally pinning to primary.
func (*Replicated) LSNTracking ¶ added in v0.2.0
func (r *Replicated) LSNTracking() bool
LSNTracking reports whether LSN routing is active.
func (*Replicated) Primary ¶ added in v0.2.0
func (r *Replicated) Primary() drops.Driver
Primary returns the primary driver, useful for code paths that must opt out of replica routing.
func (*Replicated) Query ¶ added in v0.2.0
Query routes to a replica unless ctx is inside an active read-your-writes window. With LSN tracking enabled, reads inside a window route to whichever replica has replayed past the captured write LSN — only falling back to primary when none have caught up. Without LSN tracking, the time-based stickiness pins reads to primary for the configured duration.
func (*Replicated) Replicas ¶ added in v0.2.0
func (r *Replicated) Replicas() []drops.Driver
Replicas returns the configured replicas in declaration order.
func (*Replicated) WithLSNTracking ¶ added in v0.2.0
func (r *Replicated) WithLSNTracking(ttl time.Duration) *Replicated
WithLSNTracking enables LSN-based replica routing on r. TTL is the max age of cached per-replica LSN samples; a query asks a replica for a fresh value when its cache entry is older than TTL.
Without LSN tracking, the read-your-writes window falls back to the time-based stickiness inherited from Replicated.
type RetryPolicy ¶ added in v0.2.0
type RetryPolicy struct {
// MaxAttempts caps the total runs of the callback. Values < 1
// are treated as 1 (no retries).
MaxAttempts int
// Errors are sentinel values; a returned error is retried when
// errors.Is(err, e) is true for any e in the slice. Nil means
// "retry on every error", which is almost always wrong — set
// this explicitly.
Errors []error
// Backoff returns the wait between attempt and attempt+1
// (1-based). Use ExponentialJitter or supply your own. nil
// disables sleeping between attempts.
Backoff func(attempt int) time.Duration
}
RetryPolicy declares how InTx (and InTxRetry) should react to transient failures — typically SerializationFailure and Deadlock under SERIALIZABLE isolation. Without a policy InTx behaves as before: every error propagates immediately.
Configure once at DB setup:
db := pg.New(drv).WithRetry(pg.RetryPolicy{
MaxAttempts: 3,
Errors: []error{pg.ErrSerializationFailure, pg.ErrDeadlock},
Backoff: pg.ExponentialJitter(10*time.Millisecond, 1*time.Second),
})
InTx then retries the supplied callback up to MaxAttempts times. Between attempts it sleeps for Backoff(attempt) — attempts are 1-based, so Backoff(1) returns the wait BEFORE the second try. Context cancellation short-circuits both the sleep and the loop.
The retry is at the transaction level — the entire callback is re-run inside a fresh transaction each time. Callbacks must be idempotent across retries. Read what you wrote before the rollback? Re-do it. Side effects (emails, HTTP, …)? Push them to the outbox so the rollback also rolls them back.
func DefaultRetryPolicy ¶ added in v0.2.0
func DefaultRetryPolicy() RetryPolicy
DefaultRetryPolicy returns the conventional safe default: up to 3 attempts, retry on SerializationFailure and Deadlock, 10ms base exponential backoff capped at 1s.
type Risk ¶ added in v0.2.0
Risk is one finding from AnalyzeMigrationRisks.
func AnalyzeMigrationRisks ¶ added in v0.2.0
AnalyzeMigrationRisks returns a Risk for every statement in stmts that needs a second look. Statements considered safe produce no entry. The matcher is a pragmatic regex-based scan — false positives are preferred to false negatives.
type RiskLevel ¶ added in v0.2.0
type RiskLevel string
RiskLevel categorises how unsafe a statement is on a table that might be large or under read/write load.
const ( // RiskInfo is for changes that are safe but worth flagging // (irreversible, requires app deploys, etc.). RiskInfo RiskLevel = "info" // RiskWarn covers changes that lock briefly or rewrite a // small amount of data. Often safe but worth scheduling. RiskWarn RiskLevel = "warn" // RiskDanger reserves catastrophic-on-large-tables changes: // table rewrites, blocking index builds, dropping tables. RiskDanger RiskLevel = "danger" )
type SafetyOptions ¶ added in v0.2.0
type SafetyOptions struct {
// Ignore lists rule IDs to skip. Useful when a particular
// migration is known-safe (e.g. small table, scheduled
// downtime).
Ignore []string
}
SafetyOptions tunes the analyser — currently used for rule suppression. Add to it as the rule set grows.
type SafetySeverity ¶ added in v0.2.0
type SafetySeverity int
SafetySeverity ranks a warning's urgency.
const ( // SeverityInfo is a heads-up — usually fine, occasionally // worth a second look. SeverityInfo SafetySeverity = iota // SeverityWarn flags a statement that will likely cause // downtime or visible behaviour change on a non-trivial // table. Reviewable. SeverityWarn // SeverityError flags a statement that almost certainly // breaks production at any reasonable table size — full // table rewrites, exclusive locks held indefinitely, // unrecoverable data loss. SeverityError )
func (SafetySeverity) String ¶ added in v0.2.0
func (s SafetySeverity) String() string
String renders the level as "info" / "warn" / "error".
type SafetyWarning ¶ added in v0.2.0
type SafetyWarning struct {
// Severity ranks the urgency — info / warn / error.
Severity SafetySeverity
// Rule is a stable identifier for the check (e.g.
// "add-not-null-column"). Use it to suppress a known-
// acceptable warning via SafetyOptions.Ignore.
Rule string
// Statement is the offending SQL fragment, trimmed of
// surrounding whitespace and statement breakpoints.
Statement string
// Message describes the problem in plain language.
Message string
// Suggestion is a short hint on how to fix the issue —
// typically a safer migration shape.
Suggestion string
}
SafetyWarning is one finding from the migration analyser.
func AnalyzeMigration ¶ added in v0.2.0
func AnalyzeMigration(sql string, opts ...SafetyOptions) []SafetyWarning
AnalyzeMigration splits a migration script on the drizzle-kit "--> statement-breakpoint" boundary and runs the per-statement analyser on each piece. Pass the SQL field of a GenerateResult.
func AnalyzeStatements ¶ added in v0.2.0
func AnalyzeStatements(stmts []string, opts ...SafetyOptions) []SafetyWarning
AnalyzeStatements runs the safety rules against each statement in order. The output preserves statement order so callers can align warnings with their migration text.
type Saga ¶ added in v0.2.0
type Saga struct {
// contains filtered or unexported fields
}
Saga collects a named sequence of steps to run.
func NewSaga ¶ added in v0.2.0
NewSaga returns a saga with the supplied name. Use Step to add steps in execution order.
func (*Saga) Run ¶ added in v0.2.0
Run executes the saga against db. state may be nil (a fresh state is allocated). Each step runs in its own transaction; on failure, compensations of completed steps run in reverse order. Returns nil on full success, *SagaError on partial failure, or the bare error from a step when nothing prior had completed.
func (*Saga) Step ¶ added in v0.2.0
func (s *Saga) Step(name string, forward, compensate SagaStepFn) *Saga
Step appends a step. compensate may be nil — drops will skip the step on rollback in that case (suitable for read-only or inherently-idempotent side effects like sending a not-already-sent email).
type SagaCompensationFailure ¶ added in v0.2.0
SagaCompensationFailure is one compensation that itself errored.
type SagaError ¶ added in v0.2.0
type SagaError struct {
SagaName string
FailedStep string
FailedStepIdx int
Cause error
CompFailures []SagaCompensationFailure
}
SagaError is returned by Saga.Run when a step fails. It exposes the failing step's index / name, the original error, and any errors that surfaced during compensation. Use errors.As to reach it.
type SagaState ¶ added in v0.2.0
type SagaState struct {
// contains filtered or unexported fields
}
SagaState is the typed bag flowing between steps. Concurrent access is safe because steps run sequentially, but the mutex keeps things tidy if a step spawns helpers that touch state.
type SagaStepFn ¶ added in v0.2.0
SagaStepFn is the signature for forward and compensating actions. The tx is a fresh transaction per step. State is shared across the saga; mutations made before an error are visible to compensations.
type Scanner ¶ added in v0.2.0
Scanner mirrors the subset of drops.Rows the fast scan helpers need: one Scan call per row. Generated code is written against this narrower interface so it does not depend on drops internals.
type Schema ¶
type Schema struct {
// contains filtered or unexported fields
}
Schema is a registered set of tables — the input to snapshotting, diffing and migration generation. It is just a thin wrapper around a slice of *Table plus optional top-level objects (enums, sequences, views); the table declarations themselves are unaffected.
func (*Schema) AddEnum ¶ added in v0.2.0
AddEnum registers a top-level enum type with the schema so the snapshot / diff generator emits the matching CREATE TYPE.
func (*Schema) AddSequence ¶ added in v0.2.0
func (s *Schema) AddSequence(seq *PgSequence) *Schema
AddSequence registers a top-level sequence with the schema so the snapshot / diff generator emits the matching CREATE SEQUENCE.
func (*Schema) AddView ¶ added in v0.2.0
AddView registers a view with the schema so the snapshot / diff generator emits the matching CREATE VIEW.
func (*Schema) Enums ¶ added in v0.2.0
Enums returns the registered enum types in declaration order.
func (*Schema) Sequences ¶ added in v0.2.0
func (s *Schema) Sequences() []*PgSequence
Sequences returns the registered sequences.
type Secret ¶ added in v0.2.0
type Secret[T any] struct { // Plain is the un-encrypted value. Reads / writes through this // field are normal Go field access; encryption / decryption // happens only when the secret crosses the driver boundary via // Value() / Scan(). Plain T }
Secret wraps a value of type T so it round-trips as encrypted bytea through the driver. Encrypt on Value(), decrypt on Scan(). The wire format is AES-GCM(gob-encoded T), keyed by the active keyring set via SetKeyring.
type User struct {
ID int64 `drop:"id,primaryKey,autoIncrement"`
Email pg.Secret[string] `drop:"email"`
}
AutoTable recognises Secret[T] and emits a bytea column. Build the value via NewSecret(v) or by assigning to Secret[T]{Plain: v}.
type Seeder ¶ added in v0.2.0
type Seeder struct {
// contains filtered or unexported fields
}
Seeder accumulates seed data declarations and applies them in order. Use it to populate dev / test databases and fixture scenarios without hand-wiring transactions:
seeder := pg.NewSeeder(db)
pg.SeedAdd(seeder, UserEntity, alice, bob)
pg.SeedAdd(seeder, PostEntity, post1, post2)
if err := seeder.Apply(ctx); err != nil { ... }
Apply runs every op inside a single transaction by default, so a failure rolls back every prior insert. Pass WithoutTransaction() to opt out — useful when the seeded data spans tables that the surrounding migration tool can't tx-wrap together.
func SeedAdd ¶ added in v0.2.0
SeedAdd registers rows for entity ent. It is a free function because Go does not allow generic methods. Returns s so calls chain.
func SeedAddCreate ¶ added in v0.2.0
SeedAddCreate registers rows for ent and uses Create per row, which populates RETURNING fields back into the pointed-to values. Use this when later seeds depend on generated PKs from earlier seeds.
func SeedDo ¶ added in v0.2.0
SeedDo registers an arbitrary function. Use it for cross-entity fixups or seed steps that don't map cleanly to Create / CreateMany.
func (*Seeder) Apply ¶ added in v0.2.0
Apply runs every registered op in declaration order. By default wraps the run in a transaction; on first error the transaction rolls back and the failure is returned.
func (*Seeder) WithoutTransaction ¶ added in v0.2.0
WithoutTransaction disables the transactional wrapper Apply uses by default. Returns the seeder for chaining.
type SelectBuilder ¶
type SelectBuilder struct {
// contains filtered or unexported fields
}
SelectBuilder composes a SELECT statement.
func (*SelectBuilder) AfterCursor ¶ added in v0.2.0
func (s *SelectBuilder) AfterCursor(spec CursorSpec, c Cursor) *SelectBuilder
AfterCursor appends the keyset WHERE clause for forward paging past cursor c. Decoding errors fall through to the next builder method — execution-time scan will surface the wrapped error so callers don't have to guard every chained call.
func (*SelectBuilder) All ¶
func (s *SelectBuilder) All(ctx context.Context, dest any) error
All executes the SELECT and scans every row into dest, which must be a pointer to a slice of structs (or pointer-to-structs).
func (*SelectBuilder) AsSubquery ¶
func (s *SelectBuilder) AsSubquery(alias string) drops.Expression
AsSubquery returns a parenthesised, aliased form of the SELECT for use as a subquery in another statement.
func (*SelectBuilder) BeforeCursor ¶ added in v0.2.0
func (s *SelectBuilder) BeforeCursor(spec CursorSpec, c Cursor) *SelectBuilder
BeforeCursor is the reverse — appends WHERE constraints that page backward past c. Combine with a reversed ORDER BY (or reverse the returned slice on the caller side) to present the page in the expected order.
func (*SelectBuilder) Count ¶
func (s *SelectBuilder) Count(ctx context.Context) (int64, error)
Count returns the number of rows the current SELECT would produce, computed as SELECT count(*) FROM (<original>) AS _drops_count. The original ORDER BY / LIMIT / OFFSET are kept inside the subquery so LIMIT-aware page counts work correctly.
For un-paginated counts on simple SELECTs, this is the natural and safe shape — PostgreSQL will optimise the inner query as needed.
func (*SelectBuilder) Distinct ¶
func (s *SelectBuilder) Distinct() *SelectBuilder
Distinct toggles SELECT DISTINCT.
func (*SelectBuilder) DistinctOn ¶
func (s *SelectBuilder) DistinctOn(exprs ...drops.Expression) *SelectBuilder
DistinctOn renders SELECT DISTINCT ON (exprs...). Mutually exclusive with Distinct().
func (*SelectBuilder) Except ¶
func (s *SelectBuilder) Except(other *SelectBuilder) *SelectBuilder
Except appends EXCEPT <select>.
func (*SelectBuilder) ExceptAll ¶
func (s *SelectBuilder) ExceptAll(other *SelectBuilder) *SelectBuilder
ExceptAll appends EXCEPT ALL <select>.
func (*SelectBuilder) ForUpdate ¶
func (s *SelectBuilder) ForUpdate() *SelectBuilder
ForUpdate appends FOR UPDATE row locking.
func (*SelectBuilder) From ¶
func (s *SelectBuilder) From(t *Table) *SelectBuilder
From sets the FROM clause. Required before execution.
func (*SelectBuilder) FromExpr ¶
func (s *SelectBuilder) FromExpr(e drops.Expression) *SelectBuilder
FromExpr appends an arbitrary FROM source — a subquery, CTE reference, set-returning function, etc. Multiple FROMs are comma-joined (i.e. cross-joined).
func (*SelectBuilder) FullJoin ¶
func (s *SelectBuilder) FullJoin(t *Table, on drops.Expression) *SelectBuilder
FullJoin appends a FULL OUTER JOIN.
func (*SelectBuilder) GroupBy ¶
func (s *SelectBuilder) GroupBy(exprs ...drops.Expression) *SelectBuilder
GroupBy appends GROUP BY expressions.
func (*SelectBuilder) Having ¶
func (s *SelectBuilder) Having(preds ...drops.Expression) *SelectBuilder
Having appends predicates to the HAVING clause (joined by AND).
func (*SelectBuilder) Intersect ¶
func (s *SelectBuilder) Intersect(other *SelectBuilder) *SelectBuilder
Intersect appends INTERSECT <select>.
func (*SelectBuilder) IntersectAll ¶
func (s *SelectBuilder) IntersectAll(other *SelectBuilder) *SelectBuilder
IntersectAll appends INTERSECT ALL <select>.
func (*SelectBuilder) Join ¶
func (s *SelectBuilder) Join(t *Table, on drops.Expression) *SelectBuilder
Join appends an INNER JOIN.
func (*SelectBuilder) LeftJoin ¶
func (s *SelectBuilder) LeftJoin(t *Table, on drops.Expression) *SelectBuilder
LeftJoin appends a LEFT JOIN.
func (*SelectBuilder) Limit ¶
func (s *SelectBuilder) Limit(n int64) *SelectBuilder
Limit sets the LIMIT.
func (*SelectBuilder) Offset ¶
func (s *SelectBuilder) Offset(n int64) *SelectBuilder
Offset sets the OFFSET.
func (*SelectBuilder) One ¶
func (s *SelectBuilder) One(ctx context.Context, dest any) error
One executes the SELECT and scans the first row into dest. Returns ErrNoRows if no row is produced.
func (*SelectBuilder) OrderBy ¶
func (s *SelectBuilder) OrderBy(exprs ...drops.Expression) *SelectBuilder
OrderBy appends ORDER BY expressions. Use Column.Asc / Column.Desc for direction.
func (*SelectBuilder) OrderByCursor ¶ added in v0.2.0
func (s *SelectBuilder) OrderByCursor(spec CursorSpec) *SelectBuilder
OrderByCursor sets ORDER BY according to spec. The same spec must be passed to AfterCursor / BeforeCursor on subsequent pages so the keyset WHERE matches.
func (*SelectBuilder) RightJoin ¶
func (s *SelectBuilder) RightJoin(t *Table, on drops.Expression) *SelectBuilder
RightJoin appends a RIGHT JOIN.
func (*SelectBuilder) Rows ¶
Rows executes the SELECT and returns the raw cursor for manual scanning.
func (*SelectBuilder) ToSQL ¶
func (s *SelectBuilder) ToSQL() (string, []any)
ToSQL renders the statement to a SQL string and arg list.
func (*SelectBuilder) Union ¶
func (s *SelectBuilder) Union(other *SelectBuilder) *SelectBuilder
Union appends UNION <select>. Multiple set operations are chainable.
func (*SelectBuilder) UnionAll ¶
func (s *SelectBuilder) UnionAll(other *SelectBuilder) *SelectBuilder
UnionAll appends UNION ALL <select>.
func (*SelectBuilder) Unscoped ¶ added in v0.2.0
func (s *SelectBuilder) Unscoped() *SelectBuilder
Unscoped opts out of the FROM table's DefaultFilter predicates for this SELECT. Use to bypass a soft-delete or tenant guard.
func (*SelectBuilder) Where ¶
func (s *SelectBuilder) Where(preds ...drops.Expression) *SelectBuilder
Where appends predicates joined by AND.
func (*SelectBuilder) With ¶
func (s *SelectBuilder) With(ctes ...*CTE) *SelectBuilder
With prepends a WITH clause to the SELECT. Multiple calls accumulate.
func (*SelectBuilder) WithRecursive ¶
func (s *SelectBuilder) WithRecursive(ctes ...*CTE) *SelectBuilder
WithRecursive marks the WITH clause as RECURSIVE. Only one mode is possible per statement; calling this is sticky.
func (*SelectBuilder) WriteSQL ¶
func (s *SelectBuilder) WriteSQL(b *drops.Builder)
WriteSQL renders the SELECT into a Builder. Wrapped in parentheses so the same builder can be embedded as a subquery.
type SequenceOptions ¶
type SequenceOptions struct {
Start *int64
Increment *int64
MinValue *int64
MaxValue *int64
Cache *int64
Cycle bool
OwnedBy *Column // optional: link sequence ownership to a column
}
SequenceOptions configures CreateSequence.
type SequenceSnapshot ¶ added in v0.2.0
type SequenceSnapshot struct {
Name string `json:"name"`
Schema string `json:"schema"`
Start *int64 `json:"startWith,omitempty"`
Increment *int64 `json:"incrementBy,omitempty"`
MinValue *int64 `json:"minValue,omitempty"`
MaxValue *int64 `json:"maxValue,omitempty"`
Cache *int64 `json:"cacheSize,omitempty"`
Cycle bool `json:"cycle"`
}
SequenceSnapshot is one entry in Snapshot.Sequences.
type Sharded ¶ added in v0.2.0
type Sharded struct {
// contains filtered or unexported fields
}
Sharded routes every query to one of N underlying drivers based on a shard key the caller stamps on ctx. This is the opposite end of the Replicated wrapper: where Replicated splits reads across replicas of a single dataset, Sharded splits the entire dataset across N independent primaries. Use it to scale beyond what a single primary's write throughput allows — typical shard axes are user id (social-feed services), chat id (messaging), or geographic region (mobility / dispatch).
shards := []drops.Driver{db1, db2, db3, db4}
sharded := pg.NewSharded(shards, func(key any) int {
return int(key.(int64) % int64(len(shards)))
})
db := pg.New(sharded)
ctx = pg.WithShardKey(ctx, userID)
got, err := UserEntity.Get(db, ctx, userID)
// the shard for userID handles the query
Missing shard key on ctx returns ErrShardKeyMissing — the bad code path fails closed (a "default to shard 0" policy would silently route writes to the wrong shard and leak data across customers). Cross-shard queries need explicit opt-in via ForEachShard.
Transactions stay on a single shard — a tx that spans shards would need 2PC and drops doesn't model it. Begin uses the shard for ctx's shard key.
func NewSharded ¶ added in v0.2.0
NewSharded wires the shards with a picker that maps a key to an index in [0, len(shards)). The picker is called for every query; keep it cheap. Drops does not enforce that the picker is deterministic, but non-determinism causes data corruption, so don't.
func (*Sharded) Begin ¶ added in v0.2.0
Begin opens a transaction on the ctx's shard. The tx stays on that shard for its lifetime — drops does not model cross- shard 2PC.
func (*Sharded) Close ¶ added in v0.2.0
Close closes every shard that exposes a Close method, returning the first error encountered.
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"`
Enums map[string]*EnumSnapshot `json:"enums"`
Schemas map[string]any `json:"schemas"`
Sequences map[string]*SequenceSnapshot `json:"sequences"`
Roles map[string]any `json:"roles"`
Policies map[string]any `json:"policies"`
Views map[string]*ViewSnapshot `json:"views"`
Meta SnapshotMeta `json:"_meta"`
}
Snapshot is the on-disk representation of a database schema as written to drizzle-kit's meta/<idx>_snapshot.json. The JSON keys match drizzle-kit's PostgreSQL snapshot v7 format so a Snapshot produced by drops is round-trippable through drizzle-kit, and vice versa.
func BuildSnapshot ¶
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 ¶
Introspect queries the live database and returns a Snapshot describing its current state — tables, columns (with type normalisation matching drizzle-kit's conventions: bigserial / serial / smallserial detected from int + nextval default), primary keys, single-column unique constraints, and single-column foreign keys with referential actions.
The returned snapshot is in the same format as BuildSnapshot's output and can be diffed against a Go-schema snapshot via Diff. It deliberately leaves indexes, composite keys, enums, sequences and views empty — those features aren't yet representable in drops's schema layer.
func UnmarshalSnapshot ¶
UnmarshalSnapshot parses a snapshot from JSON, restoring zero-valued maps for any nil collections (so subsequent reads/diffs don't have to check for nil).
type SnapshotMeta ¶
type SnapshotMeta struct {
Columns map[string]any `json:"columns"`
Schemas map[string]any `json:"schemas"`
Tables map[string]any `json:"tables"`
}
SnapshotMeta carries rename-tracking annotations. drops never sets these; the field is present for drizzle-kit compatibility.
type SoftDeleteCols ¶ added in v0.2.0
SoftDeleteCols holds the typed handle created by SoftDelete.
func SoftDelete ¶ added in v0.2.0
func SoftDelete(t *Table) SoftDeleteCols
SoftDelete appends a nullable "deletedAt" TIMESTAMPTZ column. A record is treated as live while deletedAt IS NULL.
type SoftDeleteMixin ¶ added in v0.2.0
type SoftDeleteMixin struct {
Cols SoftDeleteCols
}
SoftDeleteMixin registers a "deletedAt" column, a DefaultFilter (deletedAt IS NULL), and a DeleteHook that rewrites DELETE statements as UPDATE deletedAt = now() — i.e. the row stays in the table but is hidden by default. Use Unscoped() on any builder to bypass the guard and operate on every row (including the already-deleted ones).
func (*SoftDeleteMixin) Apply ¶ added in v0.2.0
func (m *SoftDeleteMixin) Apply(t *Table)
Apply implements Mixin.
type Status ¶
type Status struct {
Version string
Name string
Applied bool
AppliedAt time.Time // zero if not applied
}
Status is a single row produced by Migrator.Status.
type SubscribeOptions ¶ added in v0.2.0
type SubscribeOptions struct {
// Hydrate fetches the full row for insert/update events so
// downstream consumers receive typed values instead of bare
// IDs. Disabled by default — enable when the consumer needs
// the row body and the per-event Get cost is acceptable.
Hydrate bool
// Channel overrides the pg_notify channel. Defaults to
// "drops_<tablename>" matching InstallChangeFeed's default.
Channel string
// Buffer sizes the returned channel; events are dropped when
// the channel is full so a slow consumer doesn't backlog
// memory. Defaults to 64.
Buffer int
}
SubscribeOptions controls subscription behaviour.
type TB ¶ added in v0.2.0
type TB interface {
Helper()
Errorf(format string, args ...any)
Fatalf(format string, args ...any)
Logf(format string, args ...any)
Cleanup(fn func())
}
TB is the subset of *testing.T the helpers below need. Mirroring the testing.TB interface lets the helpers be called from anything that satisfies it (including testing.T and testing.B) without pulling testing into the import graph of production code.
type Table ¶
type Table struct {
// contains filtered or unexported fields
}
Table represents a schema-qualified PostgreSQL table.
func ApplyMixins ¶ added in v0.2.0
ApplyMixins runs each mixin against t in order and returns t. Mixins applied later observe the columns / hooks installed by earlier mixins.
func AutoSchemaTable ¶ added in v0.2.0
AutoSchemaTable is the schema-qualified twin of AutoTable.
func AutoTable ¶ added in v0.2.0
AutoTable derives a Table from the `drop` struct tags on T. Tag syntax:
drop:"<col_name>[,opt[,opt[,...]]]"
where each opt is one of:
primaryKey — PRIMARY KEY
autoIncrement — use the serial family (BigSerial / Serial /
SmallSerial) for the column's type
notNull — NOT NULL
unique — UNIQUE
default=<sql> — raw DEFAULT clause (no parameterisation)
version — mark as the optimistic-lock version column
Use `drop:"-"` to skip a field entirely. Untagged exported fields are also skipped.
Go type ↔ ColumnType mapping mirrors the manual constructors:
bool → boolean
int16 → smallint (smallserial if autoIncrement)
int32 / int → integer (serial if autoIncrement)
int64 → bigint (bigserial if autoIncrement)
float32 → real
float64 → double precision
string → text
[]byte → bytea
time.Time → timestamptz
json.RawMessage → jsonb
*T → same as T, column is nullable unless
`notNull` is set explicitly
Custom types — uuid, jsonb columns backed by app structs, etc. — fall back to drops.Custom; declare them by hand instead.
func NewAuditTable ¶ added in v0.2.0
NewAuditTable declares the canonical audit table:
id bigserial PRIMARY KEY, entity text NOT NULL, op text NOT NULL, pk jsonb, payload jsonb, actor text, createdAt timestamptz NOT NULL DEFAULT now()
func NewBackfillStateTable ¶ added in v0.2.0
NewBackfillStateTable declares the canonical state table layout. Add to your schema once; every Backfill in the system shares the same table keyed by name.
func NewEventStoreTable ¶ added in v0.2.0
NewEventStoreTable declares the canonical event-store layout. Run the DDL once alongside the rest of your schema.
func NewIdempotencyTable ¶ added in v0.2.0
NewIdempotencyTable declares the canonical idempotency table. Add it to your schema:
schema := pg.NewSchema(Users, pg.NewIdempotencyTable("idempotency_keys"))
pg.Push(ctx, db, schema)
func NewOutboxTable ¶ added in v0.2.0
NewOutboxTable declares the canonical outbox table layout. Add it to your schema and let Push / Migrator manage the DDL. The table ships with a partial index that keeps the drain query O(log n) no matter how many published rows accumulate before cleanup.
func NewSchemaTable ¶
NewSchemaTable creates a table in an explicit schema.
func NewSnapshotTable ¶ added in v0.2.0
NewSnapshotTable declares the snapshot store. Pair with NewEventStoreTable; snapshots live in a separate table so the event log stays append-only.
func NewTable ¶
NewTable creates a table in the default ("public") schema. The name is validated and the constructor panics on invalid identifiers — see ErrInvalidIdentifier — because schemas are typically declared in package init / var blocks where a bad name should fail loudly at startup rather than at the first query.
func (*Table) AddCheck ¶ added in v0.2.0
AddCheck declares a CHECK constraint with the given name. expr is the raw SQL expression after CHECK (...), e.g. "age >= 0 AND age < 200".
func (*Table) AddIndex ¶ added in v0.2.0
AddIndex registers an index to be created alongside the table. The index is not emitted by CreateTable; use CreateTableWithIndexes or emit pg.CreateIndex(idx) explicitly.
func (*Table) AddPolicy ¶ added in v0.2.0
AddPolicy attaches a row-level security policy to the table. Policies are inert until EnableRLS is also called.
func (*Table) AddUnique ¶ added in v0.2.0
AddUnique declares a multi-column UNIQUE constraint named name spanning cols. Single-column uniques continue to live on the column via *Col[T].Unique().
func (*Table) CompositePrimaryKey ¶ added in v0.2.0
CompositePrimaryKey returns the composite PK columns, or nil when the table uses a single-column PK (or none).
func (*Table) CompositeUniques ¶ added in v0.2.0
CompositeUniques returns the table's multi-column unique constraints.
func (*Table) DefaultFilter ¶ added in v0.2.0
func (t *Table) DefaultFilter(e drops.Expression) *Table
DefaultFilter appends a predicate applied to every Select / Update / Delete against the table, unless the builder is marked Unscoped(). Filters compose with AND.
func (*Table) EnableRLS ¶ added in v0.2.0
EnableRLS marks the table as having Row-Level Security enabled. The snapshot/diff generator emits the matching ALTER TABLE ... ENABLE ROW LEVEL SECURITY when the flag flips from false to true.
func (*Table) ForeignKey ¶ added in v0.2.1
ForeignKey attaches a foreign-key constraint from col to target on this table. Both must be non-nil registered columns. It is the untyped companion to (*Col[T]).References — use it to add FKs to AutoTable-derived columns. The FK is recorded on the column, so CreateTable and the schema diff/Push see it.
func (*Table) OnDelete ¶ added in v0.2.0
func (t *Table) OnDelete(h DeleteHook) *Table
OnDelete registers a hook invoked by DeleteBuilder.WriteSQL. A hook may return a non-nil expression to replace the rendered DELETE entirely — used by SoftDelete to flip DELETE into UPDATE.
func (*Table) OnInsert ¶ added in v0.2.0
func (t *Table) OnInsert(h InsertHook) *Table
OnInsert registers a hook invoked by InsertBuilder.WriteSQL. The hook can fill column values the caller didn't explicitly bind; user values always win.
func (*Table) OnUpdate ¶ added in v0.2.0
func (t *Table) OnUpdate(h UpdateHook) *Table
OnUpdate registers a hook invoked by UpdateBuilder.WriteSQL.
func (*Table) PrimaryKey ¶ added in v0.2.0
PrimaryKey declares a composite PRIMARY KEY spanning cols. Call only when the PK has more than one column; single-column PKs continue to be declared on the column via *Col[T].PrimaryKey().
func (*Table) RLSEnabled ¶ added in v0.2.0
RLSEnabled reports whether the table has RLS enabled.
func (*Table) Relation ¶
Relation looks up a registered relation by name. Returns nil if no such relation exists.
type TableSnapshot ¶
type TableSnapshot struct {
Name string `json:"name"`
Schema string `json:"schema"`
Columns map[string]*ColumnSnapshot `json:"columns"`
Indexes map[string]*IndexSnapshot `json:"indexes"`
ForeignKeys map[string]*ForeignKeySnapshot `json:"foreignKeys"`
CompositePrimaryKeys map[string]*CompositePKSnapshot `json:"compositePrimaryKeys"`
UniqueConstraints map[string]*UniqueSnapshot `json:"uniqueConstraints"`
Policies map[string]*PolicySnapshot `json:"policies"`
CheckConstraints map[string]*CheckSnapshot `json:"checkConstraints"`
IsRLSEnabled bool `json:"isRLSEnabled"`
}
TableSnapshot is one entry in Snapshot.Tables.
type TimeSeriesTable ¶ added in v0.2.0
type TimeSeriesTable struct {
// contains filtered or unexported fields
}
TimeSeriesTable declares a partition-by-range pattern with time-bucketed children and an automatic retention window.
func NewTimeSeriesTable ¶ added in v0.2.0
func NewTimeSeriesTable(parent, timeCol string) *TimeSeriesTable
NewTimeSeriesTable returns a fresh descriptor. parent is the SQL identifier of the partitioned parent table; timeCol is the column the parent is partitioned by.
func (*TimeSeriesTable) Bootstrap ¶ added in v0.2.0
func (t *TimeSeriesTable) Bootstrap(db *DB, ctx context.Context) error
Bootstrap creates the partition that covers now (rounded down to the bucket boundary) and BRIN-indexes it when configured. Idempotent — re-running it is safe.
func (*TimeSeriesTable) DropExpired ¶ added in v0.2.0
DropExpired removes every child partition whose upper bound is older than now-retention. Disabled when retention is 0. Partition discovery uses pg_inherits + pg_class, so it skips the parent and any partitions belonging to a different schema.
func (*TimeSeriesTable) EnsureNext ¶ added in v0.2.0
EnsureNext creates the next `count` partitions ahead of now, rounded to bucket boundaries. Scheduled invocation keeps the window of "ready" partitions ahead of traffic.
func (*TimeSeriesTable) Maintain ¶ added in v0.2.0
func (t *TimeSeriesTable) Maintain(db *DB, ctx context.Context) error
Maintain runs EnsureNext(2) followed by DropExpired — the typical "every hour" scheduled invocation.
func (*TimeSeriesTable) PartitionEvery ¶ added in v0.2.0
func (t *TimeSeriesTable) PartitionEvery(d time.Duration) *TimeSeriesTable
PartitionEvery sets the bucket size — the duration each child partition covers. Defaults to 24h.
func (*TimeSeriesTable) Retain ¶ added in v0.2.0
func (t *TimeSeriesTable) Retain(d time.Duration) *TimeSeriesTable
Retain sets the retention window — partitions whose upper bound is older than now-retention are dropped by DropExpired. Pass 0 to disable retention.
func (*TimeSeriesTable) WithBrinIndex ¶ added in v0.2.0
func (t *TimeSeriesTable) WithBrinIndex(col string) *TimeSeriesTable
WithBrinIndex names the column that EnsureNext / Bootstrap will BRIN-index on each newly created partition. BRIN is the canonical time-series index — tiny, fast to build, great for range scans on naturally-ordered columns.
type TimestampsCols ¶ added in v0.2.0
TimestampsCols holds the typed handles created by Timestamps.
func Timestamps ¶ added in v0.2.0
func Timestamps(t *Table) TimestampsCols
Timestamps appends NOT NULL "createdAt" and "updatedAt" TIMESTAMPTZ columns defaulting to now() to t.
type TimestampsMixin ¶ added in v0.2.0
type TimestampsMixin struct {
Cols TimestampsCols
}
TimestampsMixin registers "createdAt" and "updatedAt" columns and an UpdateHook that bumps updatedAt to now() on every UPDATE the caller hasn't already touched. INSERT is left to the column's DEFAULT now() — no hook needed.
After Apply, the embedded Cols field exposes typed handles to the columns so the rest of the application can reference them.
func (*TimestampsMixin) Apply ¶ added in v0.2.0
func (m *TimestampsMixin) Apply(t *Table)
Apply implements Mixin.
type Tracer ¶ added in v0.2.0
Tracer is the minimal contract drops needs to emit a distributed trace span around every Exec / Query. It deliberately mirrors a subset of OpenTelemetry's trace.Tracer without importing it, so drops carries no external tracing dependency. Wire it up with db.WithTracer; pass an adapter that bridges to your real tracer:
type otelAdapter struct{ tracer trace.Tracer }
func (a otelAdapter) Start(ctx context.Context, name string) (context.Context, pg.Span) {
ctx, span := a.tracer.Start(ctx, name)
return ctx, otelSpan{span}
}
db := pg.New(drv).WithTracer(otelAdapter{tracer: otel.Tracer("myapp")})
The Span surface mirrors the methods drops needs: SetAttribute for query metadata, RecordError to mark failures, End to close the span. Implementations are expected to be safe for concurrent use — drops calls them from whichever goroutine happens to run the query.
type TriggerOptions ¶
type TriggerOptions struct {
Timing string // "BEFORE" | "AFTER" | "INSTEAD OF"
Events string // "INSERT" | "UPDATE" | "DELETE" | combinations like "INSERT OR UPDATE"
Table *Table
ForEach string // "ROW" or "STATEMENT" (default "ROW")
When string // raw SQL condition (optional)
Execute string // raw, e.g. "my_func()"
OrReplace bool
}
TriggerOptions configures CreateTrigger.
type TypedChange ¶ added in v0.2.0
type TypedChange[T any] struct { // Op is the underlying SQL operation. Op ChangeOp // ID is the primary-key value (text-coerced). ID string // Row is the fetched row body. Nil for OpDelete (the row is // already gone) and for any event when Hydrate is false. Row *T // At is the wall-clock time the event arrived in-process — // approximate by ~one network hop from the trigger fire. At time.Time }
TypedChange[T] decorates a ChangeEvent with the optional fetched row body.
type UUIDPrimaryKeyCols ¶ added in v0.2.0
UUIDPrimaryKeyCols holds the typed handle created by UUIDPrimaryKey.
func UUIDPrimaryKey ¶ added in v0.2.0
func UUIDPrimaryKey(t *Table) UUIDPrimaryKeyCols
UUIDPrimaryKey appends an "id" UUID PRIMARY KEY column defaulting to gen_random_uuid() — the function shipped by the pgcrypto extension and built into PostgreSQL 13+.
type UUIDPrimaryKeyMixin ¶ added in v0.2.0
type UUIDPrimaryKeyMixin struct {
Cols UUIDPrimaryKeyCols
}
UUIDPrimaryKeyMixin registers an "id" UUID PRIMARY KEY column defaulting to gen_random_uuid().
func (*UUIDPrimaryKeyMixin) Apply ¶ added in v0.2.0
func (m *UUIDPrimaryKeyMixin) Apply(t *Table)
Apply implements Mixin.
type UniqueSnapshot ¶
type UniqueSnapshot struct {
Name string `json:"name"`
NullsNotDistinct bool `json:"nullsNotDistinct"`
Columns []string `json:"columns"`
}
UniqueSnapshot is one entry in TableSnapshot.UniqueConstraints.
type UpdateBuilder ¶
type UpdateBuilder struct {
// contains filtered or unexported fields
}
UpdateBuilder composes an UPDATE statement.
func (*UpdateBuilder) All ¶
func (u *UpdateBuilder) All(ctx context.Context, dest any) error
All executes the UPDATE and scans the RETURNING rows into dest.
func (*UpdateBuilder) From ¶
func (u *UpdateBuilder) From(tables ...*Table) *UpdateBuilder
From adds tables to a PostgreSQL UPDATE ... FROM clause for joins.
func (*UpdateBuilder) One ¶
func (u *UpdateBuilder) One(ctx context.Context, dest any) error
One executes the UPDATE and scans the first RETURNING row into dest.
func (*UpdateBuilder) Returning ¶
func (u *UpdateBuilder) Returning(cols ...drops.Expression) *UpdateBuilder
Returning sets a RETURNING clause.
func (*UpdateBuilder) Set ¶
func (u *UpdateBuilder) Set(values ...ColumnValue) *UpdateBuilder
Set adds one or more assignments. Use (*Col[T]).Val(v) to bind a typed value or (*Col[T]).Expr(e) to bind an expression.
func (*UpdateBuilder) ToSQL ¶
func (u *UpdateBuilder) ToSQL() (string, []any)
ToSQL renders the statement.
func (*UpdateBuilder) Unscoped ¶ added in v0.2.0
func (u *UpdateBuilder) Unscoped() *UpdateBuilder
Unscoped opts out of the table's DefaultFilter predicates for this UPDATE. Use when an administrative job must bypass a soft-delete or tenant guard registered on the table.
func (*UpdateBuilder) Where ¶
func (u *UpdateBuilder) Where(preds ...drops.Expression) *UpdateBuilder
Where appends predicates joined by AND.
func (*UpdateBuilder) WriteSQL ¶
func (u *UpdateBuilder) WriteSQL(b *drops.Builder)
WriteSQL renders the UPDATE.
type UpdateHook ¶ added in v0.2.0
type UpdateHook interface {
BeforeUpdate(ctx *UpdateHookCtx)
}
UpdateHook is invoked once per UPDATE statement, before rendering.
type UpdateHookCtx ¶ added in v0.2.0
type UpdateHookCtx struct {
// contains filtered or unexported fields
}
UpdateHookCtx is the controlled handle a hook uses to add SET assignments without clobbering user-supplied values.
func (*UpdateHookCtx) Has ¶ added in v0.2.0
func (c *UpdateHookCtx) Has(col *Column) bool
Has reports whether col is already bound on the UPDATE.
func (*UpdateHookCtx) Set ¶ added in v0.2.0
func (c *UpdateHookCtx) Set(v ColumnValue)
Set appends v to the UPDATE's SET list, unless its column is already bound.
func (*UpdateHookCtx) SetExpr ¶ added in v0.2.0
func (c *UpdateHookCtx) SetExpr(col *Column, expr drops.Expression)
SetExpr is the raw-expression variant of Set — useful for hooks that want to assign e.g. drops.Raw("now()") to a column.
type UpdateHookFunc ¶ added in v0.2.0
type UpdateHookFunc func(*UpdateHookCtx)
UpdateHookFunc adapts a plain function to the UpdateHook interface.
func (UpdateHookFunc) BeforeUpdate ¶ added in v0.2.0
func (f UpdateHookFunc) BeforeUpdate(ctx *UpdateHookCtx)
BeforeUpdate implements UpdateHook.
type Validator ¶ added in v0.2.0
Validator is called before Create / Update / Save with a pointer to the candidate row. Returning a non-nil error aborts the operation before any SQL is issued. Validators compose: register as many as you need, the first to fail wins.
type VectorOpClass ¶
type VectorOpClass string
VectorOpClass is one of the per-distance-metric operator classes pgvector exposes for indexing. Pass the relevant value to (*Index).OpClass() on a Vector column.
const ( VectorL2Ops VectorOpClass = "vector_l2_ops" VectorIPOps VectorOpClass = "vector_ip_ops" VectorCosineOps VectorOpClass = "vector_cosine_ops" VectorL1Ops VectorOpClass = "vector_l1_ops" HalfVecL2Ops VectorOpClass = "halfvec_l2_ops" HalfVecIPOps VectorOpClass = "halfvec_ip_ops" HalfVecCosineOps VectorOpClass = "halfvec_cosine_ops" BitHammingOps VectorOpClass = "bit_hamming_ops" BitJaccardOps VectorOpClass = "bit_jaccard_ops" )
type ViewSnapshot ¶ added in v0.2.0
type ViewSnapshot struct {
Name string `json:"name"`
Schema string `json:"schema"`
Definition string `json:"definition"`
Materialized bool `json:"materialized"`
}
ViewSnapshot is one entry in Snapshot.Views.
type Window ¶
type Window struct {
// contains filtered or unexported fields
}
Window describes the contents of an OVER (...) clause.
func (*Window) Frame ¶
Frame sets the raw frame specification — e.g. "ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING".
func (*Window) OrderBy ¶
func (w *Window) OrderBy(exprs ...drops.Expression) *Window
OrderBy adds ORDER BY entries to the window.
func (*Window) PartitionBy ¶
func (w *Window) PartitionBy(exprs ...drops.Expression) *Window
PartitionBy adds PARTITION BY columns.
Source Files
¶
- array.go
- audit.go
- authz.go
- autotable.go
- backfill.go
- binding.go
- budget.go
- cache.go
- cast.go
- changefeed.go
- column.go
- copy.go
- crypto.go
- cte.go
- cursor.go
- datetime.go
- db.go
- ddl.go
- delete.go
- diagram.go
- diff.go
- doc.go
- drift.go
- drizzle.go
- entity.go
- enum.go
- errors.go
- eventstore.go
- exists.go
- explain.go
- factory.go
- find.go
- funcs.go
- generate.go
- geo.go
- hook_logger.go
- hooks.go
- idempotency.go
- ident.go
- index.go
- insert.go
- introspect.go
- json.go
- jsonpath.go
- listen.go
- lock.go
- math.go
- matview.go
- migrate.go
- mixin.go
- money.go
- n1.go
- objects.go
- online.go
- op.go
- outbox.go
- page.go
- patch.go
- pgvector.go
- pii.go
- poolstats.go
- push.go
- relations.go
- replica.go
- replica_lsn.go
- retry.go
- safety.go
- saga.go
- scan.go
- schema.go
- secret.go
- seed.go
- select.go
- shard.go
- snapshot.go
- strings.go
- subquery.go
- table.go
- template.go
- tenant.go
- testing.go
- timeseries.go
- tracing.go
- types.go
- update.go
- window.go