Documentation
¶
Overview ¶
Package momo is a typed Go ORM. A generator turns plain Go structs into typed column and relation descriptors, and this package builds and runs SQL from them: select, insert, update, delete, soft delete, upserts, subqueries and CTEs, relations with eager loading, transactions with savepoints, and vector search.
Momo supports PostgreSQL 16 and 17 with pgvector, through the pgx driver in the driver/pgxdriver package. The SQLite and MySQL dialect descriptors exist but have no driver yet. The module is pre-v1, with no compatibility promise between releases.
A program opens a database with New and a driver, then runs queries against the DB or a Tx, both of which implement Querier:
db := momo.New(pgxdriver.New(pool)) docs, err := momo.Select[models.Document](db). Where(document.Published.Eq(true)). All(ctx)
The descriptors (document.Published above) come from the momo command, which reads the model structs and writes a momo_gen.go file next to them. The same command manages versioned SQL migrations.
Documentation for people and for AI coding agents:
- docs/ai-guide.md is the guide to read first: setup, modeling, migrations, queries, relations, vectors, errors and the known pitfalls.
- docs/capabilities.md and docs/supported-versions.md say what is supported and tested.
- docs/ARCHITECTURE.md describes the packages and their contracts, and lists what is only planned.
All paths are relative to the module root, https://github.com/azrtydxb/momo.
Example (VectorDimensionMismatch) ¶
A query vector of the wrong dimension is a build error, not a server error.
package main
import (
"fmt"
"github.com/azrtydxb/momo"
"github.com/azrtydxb/momo/driver/pgxdriver"
"github.com/azrtydxb/momo/internal/testmodels/example"
"github.com/azrtydxb/momo/internal/testmodels/example/document"
"github.com/azrtydxb/momo/vecop"
"github.com/azrtydxb/momo/vector"
)
func main() {
db := momo.New(pgxdriver.New(nil))
_, err := momo.Select[example.Document](db).
OrderBy(vecop.L2(document.Embedding, vector.Vector{1, 2, 3}).Asc()).
SQL()
fmt.Println(err != nil)
}
Output: true
Example (VectorMigration) ¶
A migration creates the extension, the table and the ANN index from the schema description.
package main
import (
"fmt"
"github.com/azrtydxb/momo/dialect"
"github.com/azrtydxb/momo/migrate"
migratepg "github.com/azrtydxb/momo/migrate/postgres"
"github.com/azrtydxb/momo/schema"
)
func main() {
to := &schema.Schema{
Dialect: dialect.Postgres,
Extensions: []schema.Extension{{Name: "vector"}},
Tables: []schema.Table{{
Name: "documents",
Columns: []schema.Column{
{Name: "id", Type: "bigint"},
{Name: "embedding", Type: "vector(3)"},
},
PrimaryKey: []string{"id"},
Indexes: []schema.Index{{
Name: "documents_embedding_hnsw", Method: "hnsw",
Parts: []schema.IndexPart{{Column: "embedding", OpClass: "vector_cosine_ops"}},
With: []schema.KV{{Key: "m", Value: "16"}, {Key: "ef_construction", Value: "64"}},
}},
}},
}
changes, _, err := migrate.Diff(nil, to, migrate.DiffOptions{})
if err != nil {
fmt.Println(err)
return
}
stmts, err := migratepg.New().Render(migrate.Order(changes))
if err != nil {
fmt.Println(err)
return
}
for _, s := range stmts {
fmt.Println(s.SQL)
}
}
Output: CREATE EXTENSION IF NOT EXISTS "vector" CREATE TABLE "documents" ("id" bigint NOT NULL, "embedding" vector(3) NOT NULL, CONSTRAINT "documents_pkey" PRIMARY KEY ("id")) CREATE INDEX "documents_embedding_hnsw" ON "documents" USING "hnsw" ("embedding" "vector_cosine_ops") WITH ("m" = 16, "ef_construction" = 64)
Example (VectorNearest) ¶
A nearest-neighbour query orders by a typed distance expression. The query vector is bound as an argument and checked against the column dimension when the SQL is built.
package main
import (
"fmt"
"github.com/azrtydxb/momo"
"github.com/azrtydxb/momo/driver/pgxdriver"
"github.com/azrtydxb/momo/internal/testmodels/example"
"github.com/azrtydxb/momo/internal/testmodels/example/document"
"github.com/azrtydxb/momo/vecop"
"github.com/azrtydxb/momo/vector"
)
func main() {
// SQL() only compiles the statement, so no connection is needed here.
db := momo.New(pgxdriver.New(nil))
query := make(vector.Vector, 1536)
query[0] = 1
c, err := momo.Select[example.Document](db).
OrderBy(vecop.Cosine(document.Embedding, query).Asc()).
Limit(5).
SQL()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(c.SQL)
}
Output: SELECT "documents"."id", "documents"."tenant_id", "documents"."title", "documents"."body", "documents"."embedding", "documents"."status", "documents"."created_at" FROM "documents" ORDER BY ("documents"."embedding" <=> $1) ASC LIMIT $2
Index ¶
- Constants
- Variables
- func AllowStaleReads(ctx context.Context) context.Context
- func Batches[T any](ctx context.Context, sq SelectQuery[T], n int, fn func([]T) error) error
- func CreateGraph[P any, PP Modeler[P]](ctx context.Context, q Querier, p *P, includes ...Association[P]) error
- func EscapeLike(s string) string
- func Exec(ctx context.Context, q Querier, sql string, args ...any) (int64, error)
- func Explain(ctx context.Context, q Querier, c Compiled) ([]string, error)
- func ExplainAnalyze(ctx context.Context, q Querier, c Compiled) ([]string, error)
- func FindAndCount[T any](ctx context.Context, sq SelectQuery[T]) ([]T, int64, error)
- func FindOrCreate[T any, PT Modeler[T]](ctx context.Context, q Querier, key []ColumnRef, m *T) (created bool, err error)
- func FirstID[T any](ctx context.Context, sq SelectQuery[T]) (int64, error)
- func FlagsOf(e Expr) uint16
- func IDs[T any](ctx context.Context, sq SelectQuery[T]) ([]int64, error)
- func Ident(name string) any
- func In(values any) any
- func IsBound(e Expr) bool
- func Load[P, C any](ctx context.Context, q Querier, parents []P, rel Relation[P, C], ...) error
- func LoadAll[P any](ctx context.Context, q Querier, parents []P, loaders ...Loader[P]) error
- func LoadCounts[P, C any](ctx context.Context, q Querier, parents []P, rel Relation[P, C], ...) ([]int64, error)
- func MapRows(ctx context.Context, q Querier, sql string, args ...any) ([]map[string]any, error)
- func MySQLVectorType(flavor dialect.Flavor, serverVersion string, dim int) (string, error)
- func NewUnitOfWork(ctx context.Context) context.Context
- func Pluck[T, V any](ctx context.Context, sq SelectQuery[T], c Expression[V]) ([]V, error)
- func Query[T any, PT Modeler[T]](ctx context.Context, q Querier, sql string, args ...any) ([]T, error)
- func QueryRows[T any, PT Modeler[T]](ctx context.Context, q Querier, sql string, args ...any) iter.Seq2[T, error]
- func RecordPoolWait(ctx context.Context, d time.Duration)
- func RegisterQuery(name string, build func(q Querier) Compilable)
- func SQLiteBitsType(column string, n int) (string, error)
- func SQLiteVectorType(column string, dim int) (string, error)
- func Scalars[V any](ctx context.Context, q Querier, sql string, args ...any) ([]V, error)
- func SetConfigLocal(ctx context.Context, tx *Tx, key, value string) error
- func Truncate[T any, PT Modeler[T]](ctx context.Context, q Querier) error
- func UpsertByPK[T any, PT Modeler[T]](ctx context.Context, q Querier, m *T) error
- func ValidName(s string) error
- func ValidTypeName(s string) error
- func WithDetail(err error, detail string) error
- func WithQueryScope(ctx context.Context) context.Context
- func WithTenant(ctx context.Context, tenant any) context.Context
- type Agg
- type Aliased
- type Allowlist
- type Assignment
- type Association
- type Batcher
- type Builder
- func (b *Builder) AppendFilter(p Predicate)
- func (b *Builder) Arg(v any)
- func (b *Builder) ArgFor(flags uint16, v any)
- func (b *Builder) Args() []any
- func (b *Builder) Dialect() *dialect.Dialect
- func (b *Builder) Err() error
- func (b *Builder) ExprFor(flags uint16, e Expr)
- func (b *Builder) Ident(name string)
- func (b *Builder) MarkSensitive()
- func (b *Builder) QualifiedIdent(qualifier, name string)
- func (b *Builder) RenderSensitive(e Expr, flags uint16) uint16
- func (b *Builder) SetErr(err error)
- func (b *Builder) String() string
- func (b *Builder) Unsupported(feature string)
- func (b *Builder) WriteByte(c byte) error
- func (b *Builder) WriteString(s string)
- type Capabilities
- type CapabilityReporter
- type Column
- func (c Column) AppendSQL(b *Builder)
- func (c Column[T]) As(alias string) Column[T]
- func (c Column) AsExpr() Expression[T]
- func (c Column) Asc() Order
- func (c Column) ColumnName() string
- func (c Column) Desc() Order
- func (c Column) Excluded() ExcludedExpr[T]
- func (c Column) Flags() uint16
- func (c Column) ParseCmp(op, raw string) (Predicate, error)
- func (c Column) ParseEq(raw string) (Predicate, error)
- func (c Column[T]) Set(v T) Assignment
- func (c Column[T]) SetDefault() Assignment
- func (c Column[T]) SetExcluded() Assignment
- func (c Column[T]) SetExpr(e Expression[T]) Assignment
- func (c Column) Table() string
- type ColumnMeta
- type ColumnNamer
- type ColumnRef
- type Compilable
- type Compiled
- type Config
- func (c *Config) Check(name, expr string)
- func (c *Config) Collate(field any, collation string)
- func (c *Config) Comment(field any, text string)
- func (c *Config) Default(field any, expr string)
- func (c *Config) Enum(name string, values ...string)
- func (c *Config) FKName(field any, name string)
- func (c *Config) ForeignKey(name string, cols []any, refTable string, refColumns []string) *ForeignKeyOpts
- func (c *Config) Function(f schema.Function)
- func (c *Config) IDGen(field any, name string)
- func (c *Config) Index(name string, cols ...any) *IndexOpts
- func (c *Config) IndexExpr(name string, exprs ...string) *IndexOpts
- func (c *Config) Partition(p schema.Partition)
- func (c *Config) PartitionOf(p schema.PartitionOf)
- func (c *Config) Policy(p schema.Policy)
- func (c *Config) PrimaryKey(fields ...any)
- func (c *Config) RLS(r schema.RLS)
- func (c *Config) Trigger(t schema.Trigger)
- func (c *Config) Unique(name string, cols ...any) *IndexOpts
- func (c *Config) View(v schema.View)
- type ConflictQuery
- type Copier
- type CreateOnlyColumn
- func (c CreateOnlyColumn) AppendSQL(b *Builder)
- func (c CreateOnlyColumn[T]) As(alias string) CreateOnlyColumn[T]
- func (c CreateOnlyColumn) AsExpr() Expression[T]
- func (c CreateOnlyColumn) Asc() Order
- func (c CreateOnlyColumn) ColumnName() string
- func (c CreateOnlyColumn) Desc() Order
- func (c CreateOnlyColumn[T]) Excluded() Expression[T]
- func (c CreateOnlyColumn) Flags() uint16
- func (c CreateOnlyColumn) ParseCmp(op, raw string) (Predicate, error)
- func (c CreateOnlyColumn) ParseEq(raw string) (Predicate, error)
- func (c CreateOnlyColumn[T]) Set(v T) InsertAssignment
- func (c CreateOnlyColumn) Table() string
- type CreateOnlyVectorColumn
- func (c CreateOnlyVectorColumn) AppendSQL(b *Builder)
- func (c CreateOnlyVectorColumn[V]) As(alias string) CreateOnlyVectorColumn[V]
- func (c CreateOnlyVectorColumn) AsExpr() Expression[V]
- func (c CreateOnlyVectorColumn) Asc() Order
- func (c CreateOnlyVectorColumn) ColumnName() string
- func (c CreateOnlyVectorColumn) Desc() Order
- func (c CreateOnlyVectorColumn) Dim() int
- func (c CreateOnlyVectorColumn) Eq(v V) Predicate
- func (c CreateOnlyVectorColumn) EqExpr(e Expression[V]) Predicate
- func (c CreateOnlyVectorColumn) Flags() uint16
- func (c CreateOnlyVectorColumn) In(vs ...V) Predicate
- func (c CreateOnlyVectorColumn) InQuery(q Subquery) Predicate
- func (c CreateOnlyVectorColumn) IsDistinctFrom(v V) Predicate
- func (c CreateOnlyVectorColumn) IsNotDistinctFrom(v V) Predicate
- func (c CreateOnlyVectorColumn) IsNotNull() Predicate
- func (c CreateOnlyVectorColumn) IsNull() Predicate
- func (c CreateOnlyVectorColumn) Ne(v V) Predicate
- func (c CreateOnlyVectorColumn) NeExpr(e Expression[V]) Predicate
- func (c CreateOnlyVectorColumn) NotIn(vs ...V) Predicate
- func (c CreateOnlyVectorColumn) NotInQuery(q Subquery) Predicate
- func (c CreateOnlyVectorColumn) ParseCmp(string, string) (Predicate, error)
- func (c CreateOnlyVectorColumn) ParseEq(string) (Predicate, error)
- func (c CreateOnlyVectorColumn[V]) Set(v V) InsertAssignment
- func (c CreateOnlyVectorColumn) Table() string
- type DB
- func (db *DB) AdoptTx(dtx DriverTx) *Tx
- func (db *DB) Begin(ctx context.Context, opts TxOptions) (*Tx, error)
- func (db *DB) Dialect() *dialect.Dialect
- func (db *DB) Driver() Driver
- func (db *DB) IsPinned() bool
- func (db *DB) OnConn(pc PinnedConn) *DB
- func (db *DB) Replica(i int) (*DB, error)
- func (db *DB) Tx(ctx context.Context, opts TxOptions, fn func(tx *Tx) error) (err error)
- type DeleteQuery
- func (d DeleteQuery[T]) AllRows() DeleteQuery[T]
- func (d DeleteQuery[T]) AppendSQL(b *Builder)
- func (d DeleteQuery[T]) Exec(ctx context.Context) (Result, error)
- func (d DeleteQuery[T]) Model(m *T) DeleteQuery[T]
- func (d DeleteQuery[T]) Returning(cols ...ColumnRef) DeleteQuery[T]
- func (d DeleteQuery[T]) ReturningAll() DeleteQuery[T]
- func (d DeleteQuery[T]) Rows(ctx context.Context) (*ModelRows[T], error)
- func (d DeleteQuery[T]) SQL() (Compiled, error)
- func (d DeleteQuery[T]) Using(src TableSource) DeleteQuery[T]
- func (d DeleteQuery[T]) Where(ps ...Predicate) DeleteQuery[T]
- func (d DeleteQuery[T]) With(name string, q Subquery, cols ...string) DeleteQuery[T]
- func (d DeleteQuery[T]) WithRecursive(name string, q Subquery, cols ...string) DeleteQuery[T]
- type DialectValuer
- type Direction
- type Discarder
- type Discriminator
- type Driver
- type DriverTx
- type Error
- type ErrorClassifier
- type ExcludedExpr
- type Expr
- type ExprSelect
- type Expression
- type FieldHook
- type Filter
- type FilteredAgg
- type Flagged
- type ForeignKeyOpts
- type FrameBound
- type FuncExpr
- type Hook
- type HookSet
- type HybridQuery
- type HybridResult
- type HybridSpec
- type IDGen
- type ImmutableColumn
- func (c ImmutableColumn) AppendSQL(b *Builder)
- func (c ImmutableColumn[T]) As(alias string) ImmutableColumn[T]
- func (c ImmutableColumn) AsExpr() Expression[T]
- func (c ImmutableColumn) Asc() Order
- func (c ImmutableColumn) ColumnName() string
- func (c ImmutableColumn) Desc() Order
- func (c ImmutableColumn[T]) Excluded() Expression[T]
- func (c ImmutableColumn) Flags() uint16
- func (c ImmutableColumn) ParseCmp(op, raw string) (Predicate, error)
- func (c ImmutableColumn) ParseEq(raw string) (Predicate, error)
- func (c ImmutableColumn[T]) Set(v T) InsertAssignment
- func (c ImmutableColumn) Table() string
- type ImmutableVectorColumn
- func (c ImmutableVectorColumn) AppendSQL(b *Builder)
- func (c ImmutableVectorColumn[V]) As(alias string) ImmutableVectorColumn[V]
- func (c ImmutableVectorColumn) AsExpr() Expression[V]
- func (c ImmutableVectorColumn) Asc() Order
- func (c ImmutableVectorColumn) ColumnName() string
- func (c ImmutableVectorColumn) Desc() Order
- func (c ImmutableVectorColumn) Dim() int
- func (c ImmutableVectorColumn) Eq(v V) Predicate
- func (c ImmutableVectorColumn) EqExpr(e Expression[V]) Predicate
- func (c ImmutableVectorColumn) Flags() uint16
- func (c ImmutableVectorColumn) In(vs ...V) Predicate
- func (c ImmutableVectorColumn) InQuery(q Subquery) Predicate
- func (c ImmutableVectorColumn) IsDistinctFrom(v V) Predicate
- func (c ImmutableVectorColumn) IsNotDistinctFrom(v V) Predicate
- func (c ImmutableVectorColumn) IsNotNull() Predicate
- func (c ImmutableVectorColumn) IsNull() Predicate
- func (c ImmutableVectorColumn) Ne(v V) Predicate
- func (c ImmutableVectorColumn) NeExpr(e Expression[V]) Predicate
- func (c ImmutableVectorColumn) NotIn(vs ...V) Predicate
- func (c ImmutableVectorColumn) NotInQuery(q Subquery) Predicate
- func (c ImmutableVectorColumn) ParseCmp(string, string) (Predicate, error)
- func (c ImmutableVectorColumn) ParseEq(string) (Predicate, error)
- func (c ImmutableVectorColumn[V]) Set(v V) InsertAssignment
- func (c ImmutableVectorColumn) Table() string
- type IndexOpts
- func (o *IndexOpts) Concurrently() *IndexOpts
- func (o *IndexOpts) Desc(field any) *IndexOpts
- func (o *IndexOpts) Method(m string) *IndexOpts
- func (o *IndexOpts) Nulls(field any, order string) *IndexOpts
- func (o *IndexOpts) Opclass(field any, opclass string) *IndexOpts
- func (o *IndexOpts) Unique() *IndexOpts
- func (o *IndexOpts) Where(pred string) *IndexOpts
- func (o *IndexOpts) With(key, value string) *IndexOpts
- type InsertAssignment
- type InsertIDExecer
- type InsertQuery
- func (q InsertQuery[T]) AppendSQL(b *Builder)
- func (q InsertQuery[T]) Copy(ctx context.Context, ms []T) (Result, error)
- func (q InsertQuery[T]) Exec(ctx context.Context) (Result, error)
- func (q InsertQuery[T]) FromSelect(sel Subquery, cols ...ColumnRef) InsertQuery[T]
- func (q InsertQuery[T]) Model(m *T) InsertQuery[T]
- func (q InsertQuery[T]) Models(ms []T) InsertQuery[T]
- func (q InsertQuery[T]) Omit(cols ...ColumnRef) InsertQuery[T]
- func (q InsertQuery[T]) OnConflict(cols ...ColumnRef) ConflictQuery[T]
- func (q InsertQuery[T]) Returning(cols ...ColumnRef) InsertQuery[T]
- func (q InsertQuery[T]) ReturningAll() InsertQuery[T]
- func (q InsertQuery[T]) Rows(ctx context.Context) (*ModelRows[T], error)
- func (q InsertQuery[T]) SQL() (Compiled, error)
- func (q InsertQuery[T]) Unnest() InsertQuery[T]
- func (q InsertQuery[T]) Values(assigns ...InsertValue) InsertQuery[T]
- func (q InsertQuery[T]) ValuesRows(rows ...[]Assignment) InsertQuery[T]
- func (q InsertQuery[T]) Where(preds ...Predicate) InsertQuery[T]
- func (q InsertQuery[T]) With(name string, body Subquery, cols ...string) InsertQuery[T]
- func (q InsertQuery[T]) WithRecursive(name string, body Subquery, cols ...string) InsertQuery[T]
- type InsertValue
- type Interceptor
- type LoadOption
- type Loader
- type MergeQuery
- func (m MergeQuery[T]) Exec(ctx context.Context) (Result, error)
- func (m MergeQuery[T]) On(ps ...Predicate) MergeQuery[T]
- func (m MergeQuery[T]) Returning(cols ...ColumnRef) MergeQuery[T]
- func (m MergeQuery[T]) Rows(ctx context.Context) (*ModelRows[T], error)
- func (m MergeQuery[T]) SQL() (Compiled, error)
- func (m MergeQuery[T]) WhenMatchedUpdate(assigns ...Assignment) MergeQuery[T]
- func (m MergeQuery[T]) WhenNotMatchedInsert(cols []ColumnRef, values ...Expr) MergeQuery[T]
- type Meta
- type Model
- type ModelRows
- type Modeler
- type NPlusOneFinding
- type NamedArg
- type NullColumn
- func (c NullColumn) AppendSQL(b *Builder)
- func (c NullColumn[T]) As(alias string) NullColumn[T]
- func (c NullColumn) AsExpr() Expression[T]
- func (c NullColumn) Asc() Order
- func (c NullColumn) ColumnName() string
- func (c NullColumn) Desc() Order
- func (c NullColumn) Excluded() ExcludedExpr[T]
- func (c NullColumn) Flags() uint16
- func (c NullColumn) ParseCmp(op, raw string) (Predicate, error)
- func (c NullColumn) ParseEq(raw string) (Predicate, error)
- func (c NullColumn[T]) SetNull() Assignment
- func (c NullColumn) Table() string
- type NullReadOnlyColumn
- func (c NullReadOnlyColumn) AppendSQL(b *Builder)
- func (c NullReadOnlyColumn[T]) As(alias string) NullReadOnlyColumn[T]
- func (c NullReadOnlyColumn) AsExpr() Expression[T]
- func (c NullReadOnlyColumn) Asc() Order
- func (c NullReadOnlyColumn) ColumnName() string
- func (c NullReadOnlyColumn) Desc() Order
- func (c NullReadOnlyColumn[T]) Excluded() Expression[T]
- func (c NullReadOnlyColumn) Flags() uint16
- func (c NullReadOnlyColumn) ParseCmp(op, raw string) (Predicate, error)
- func (c NullReadOnlyColumn) ParseEq(raw string) (Predicate, error)
- func (c NullReadOnlyColumn) Table() string
- type NullVectorColumn
- func (c NullVectorColumn) AppendSQL(b *Builder)
- func (c NullVectorColumn[V]) As(alias string) NullVectorColumn[V]
- func (c NullVectorColumn) AsExpr() Expression[V]
- func (c NullVectorColumn) Asc() Order
- func (c NullVectorColumn) ColumnName() string
- func (c NullVectorColumn) Desc() Order
- func (c NullVectorColumn) Dim() int
- func (c NullVectorColumn) Eq(v V) Predicate
- func (c NullVectorColumn) EqExpr(e Expression[V]) Predicate
- func (c NullVectorColumn) Flags() uint16
- func (c NullVectorColumn) In(vs ...V) Predicate
- func (c NullVectorColumn) InQuery(q Subquery) Predicate
- func (c NullVectorColumn) IsDistinctFrom(v V) Predicate
- func (c NullVectorColumn) IsNotDistinctFrom(v V) Predicate
- func (c NullVectorColumn) IsNotNull() Predicate
- func (c NullVectorColumn) IsNull() Predicate
- func (c NullVectorColumn) Ne(v V) Predicate
- func (c NullVectorColumn) NeExpr(e Expression[V]) Predicate
- func (c NullVectorColumn) NotIn(vs ...V) Predicate
- func (c NullVectorColumn) NotInQuery(q Subquery) Predicate
- func (c NullVectorColumn) ParseCmp(string, string) (Predicate, error)
- func (c NullVectorColumn) ParseEq(string) (Predicate, error)
- func (c NullVectorColumn[V]) SetNull() Assignment
- func (c NullVectorColumn) Table() string
- type Nulls
- type Number
- type Operation
- type Ops
- func (o Ops[T]) Asc() Order
- func (o Ops[T]) Between(lo, hi T) Predicate
- func (o Ops[T]) Desc() Order
- func (o Ops[T]) Eq(v T) Predicate
- func (o Ops[T]) EqExpr(x Expression[T]) Predicate
- func (o Ops[T]) Ge(v T) Predicate
- func (o Ops[T]) GeExpr(x Expression[T]) Predicate
- func (o Ops[T]) Gt(v T) Predicate
- func (o Ops[T]) GtExpr(x Expression[T]) Predicate
- func (o Ops[T]) In(vs ...T) Predicate
- func (o Ops[T]) InQuery(q Subquery) Predicate
- func (o Ops[T]) IsDistinctFrom(v T) Predicate
- func (o Ops[T]) IsNotDistinctFrom(v T) Predicate
- func (o Ops[T]) IsNotNull() Predicate
- func (o Ops[T]) IsNull() Predicate
- func (o Ops[T]) Le(v T) Predicate
- func (o Ops[T]) LeExpr(x Expression[T]) Predicate
- func (o Ops[T]) Lt(v T) Predicate
- func (o Ops[T]) LtExpr(x Expression[T]) Predicate
- func (o Ops[T]) Ne(v T) Predicate
- func (o Ops[T]) NeExpr(x Expression[T]) Predicate
- func (o Ops[T]) NotIn(vs ...T) Predicate
- func (o Ops[T]) NotInQuery(q Subquery) Predicate
- type Option
- func WithArgLogging() Option
- func WithClock(now func() time.Time) Option
- func WithFieldHooks[T any, PT Modeler[T]](hooks []FieldHook[T]) Option
- func WithHook(h Hook) Option
- func WithIDGenerator(name string, fn func() string) Option
- func WithImplicitTx() Option
- func WithInterceptor(i Interceptor) Option
- func WithMaxInList(n int) Option
- func WithMaxParams(n int) Option
- func WithReplicas(replicas ...Driver) Option
- func WithTxSetup(fn func(ctx context.Context, tx *Tx) error) Option
- type Order
- type Orderable
- type PinnedConn
- type Pinner
- type PoolStater
- type PoolStats
- type Predicate
- func And(ps ...Predicate) Predicate
- func ContainsLiteral(e Expression[string], s string) Predicate
- func Exists(q Subquery) Predicate
- func ILike(e Expression[string], pattern string) Predicate
- func JoinSQL(sep string, parts ...Expr) Predicate
- func Like(e Expression[string], pattern string) Predicate
- func Not(p Predicate) Predicate
- func NotExists(q Subquery) Predicate
- func Or(ps ...Predicate) Predicate
- func SQL(sql string, args ...any) Predicate
- func TenantFilter[T any](ctx context.Context, col Column[T]) Predicate
- type PredicateFunc
- type Projection
- type Querier
- type QueryEvent
- type QueryRegistry
- type ReadOnlyColumn
- func (c ReadOnlyColumn) AppendSQL(b *Builder)
- func (c ReadOnlyColumn[T]) As(alias string) ReadOnlyColumn[T]
- func (c ReadOnlyColumn) AsExpr() Expression[T]
- func (c ReadOnlyColumn) Asc() Order
- func (c ReadOnlyColumn) ColumnName() string
- func (c ReadOnlyColumn) Desc() Order
- func (c ReadOnlyColumn[T]) Excluded() Expression[T]
- func (c ReadOnlyColumn) Flags() uint16
- func (c ReadOnlyColumn) ParseCmp(op, raw string) (Predicate, error)
- func (c ReadOnlyColumn) ParseEq(raw string) (Predicate, error)
- func (c ReadOnlyColumn) Table() string
- type ReadOnlyVectorColumn
- func (c ReadOnlyVectorColumn) AppendSQL(b *Builder)
- func (c ReadOnlyVectorColumn[V]) As(alias string) ReadOnlyVectorColumn[V]
- func (c ReadOnlyVectorColumn) AsExpr() Expression[V]
- func (c ReadOnlyVectorColumn) Asc() Order
- func (c ReadOnlyVectorColumn) ColumnName() string
- func (c ReadOnlyVectorColumn) Desc() Order
- func (c ReadOnlyVectorColumn) Dim() int
- func (c ReadOnlyVectorColumn) Eq(v V) Predicate
- func (c ReadOnlyVectorColumn) EqExpr(e Expression[V]) Predicate
- func (c ReadOnlyVectorColumn) Flags() uint16
- func (c ReadOnlyVectorColumn) In(vs ...V) Predicate
- func (c ReadOnlyVectorColumn) InQuery(q Subquery) Predicate
- func (c ReadOnlyVectorColumn) IsDistinctFrom(v V) Predicate
- func (c ReadOnlyVectorColumn) IsNotDistinctFrom(v V) Predicate
- func (c ReadOnlyVectorColumn) IsNotNull() Predicate
- func (c ReadOnlyVectorColumn) IsNull() Predicate
- func (c ReadOnlyVectorColumn) Ne(v V) Predicate
- func (c ReadOnlyVectorColumn) NeExpr(e Expression[V]) Predicate
- func (c ReadOnlyVectorColumn) NotIn(vs ...V) Predicate
- func (c ReadOnlyVectorColumn) NotInQuery(q Subquery) Predicate
- func (c ReadOnlyVectorColumn) ParseCmp(string, string) (Predicate, error)
- func (c ReadOnlyVectorColumn) ParseEq(string) (Predicate, error)
- func (c ReadOnlyVectorColumn) Table() string
- type RegisteredQuery
- type Relation
- func (r Relation[P, C]) Count(ctx context.Context, q Querier, p *P) (int64, error)
- func (r Relation[P, C]) CountOrder(dir Direction) Orderable
- func (r Relation[P, C]) From(parents SelectQuery[P]) SelectQuery[C]
- func (r Relation[P, C]) Has(scope ...Predicate) Predicate
- func (r Relation[P, C]) HasFrom(parentAlias string, scope ...Predicate) Predicate
- func (r Relation[P, C]) HasNo(scope ...Predicate) Predicate
- func (r Relation[P, C]) Include() Association[P]
- func (r Relation[P, C]) Joined() Loader[P]
- func (r Relation[P, C]) Link(ctx context.Context, q Querier, p *P, cs ...*C) error
- func (r Relation[P, C]) Replace(ctx context.Context, q Querier, p *P, cs ...*C) error
- func (r Relation[P, C]) Scope(opts ...LoadOption[C]) RelationLoader[P, C]
- func (r Relation[P, C]) Then(nested ...Loader[C]) RelationLoader[P, C]
- func (r Relation[P, C]) Unlink(ctx context.Context, q Querier, p *P, cs ...*C) error
- type RelationEvent
- type RelationHook
- type RelationKind
- type RelationLoader
- type Result
- type ReturningList
- type Row1
- type Row2
- type Row3
- type Row4
- type Row5
- type Row6
- type Row7
- type Row8
- type Row9
- type Row10
- type Rows
- type Scope
- type SelectQuery
- func (sq SelectQuery[T]) After(values ...any) SelectQuery[T]
- func (sq SelectQuery[T]) All(ctx context.Context) ([]T, error)
- func (sq SelectQuery[T]) AppendSQL(b *Builder)
- func (sq SelectQuery[T]) Columns(es ...Expr) SelectQuery[T]
- func (sq SelectQuery[T]) Count(ctx context.Context) (int64, error)
- func (sq SelectQuery[T]) CrossJoin(src TableSource) SelectQuery[T]
- func (sq SelectQuery[T]) Distinct() SelectQuery[T]
- func (sq SelectQuery[T]) DistinctOn(es ...Expr) SelectQuery[T]
- func (sq SelectQuery[T]) Each(ctx context.Context, fn func(*T) error) error
- func (sq SelectQuery[T]) Exists(ctx context.Context) (bool, error)
- func (sq SelectQuery[T]) Explain(ctx context.Context) (string, error)
- func (sq SelectQuery[T]) First(ctx context.Context) (T, error)
- func (sq SelectQuery[T]) ForKeyShare(opt ...string) SelectQuery[T]
- func (sq SelectQuery[T]) ForNoKeyUpdate(opt ...string) SelectQuery[T]
- func (sq SelectQuery[T]) ForShare(opt ...string) SelectQuery[T]
- func (sq SelectQuery[T]) ForUpdate(opt ...string) SelectQuery[T]
- func (sq SelectQuery[T]) From(src TableSource) SelectQuery[T]
- func (sq SelectQuery[T]) GroupBy(es ...Expr) SelectQuery[T]
- func (sq SelectQuery[T]) Having(ps ...Predicate) SelectQuery[T]
- func (sq SelectQuery[T]) IndexedBy(index string) SelectQuery[T]
- func (sq SelectQuery[T]) Iter(ctx context.Context) iter.Seq2[T, error]
- func (sq SelectQuery[T]) Join(src TableSource, on ...Predicate) SelectQuery[T]
- func (sq SelectQuery[T]) LeftJoin(src TableSource, on ...Predicate) SelectQuery[T]
- func (sq SelectQuery[T]) Limit(n int64) SelectQuery[T]
- func (sq SelectQuery[T]) LockOf(tables ...string) SelectQuery[T]
- func (sq SelectQuery[T]) MaxRows(n int) SelectQuery[T]
- func (sq SelectQuery[T]) Offset(n int64) SelectQuery[T]
- func (sq SelectQuery[T]) One(ctx context.Context) (T, error)
- func (sq SelectQuery[T]) OnlyDeleted() SelectQuery[T]
- func (sq SelectQuery[T]) OrderBy(items ...Orderable) SelectQuery[T]
- func (sq SelectQuery[T]) Preload(loaders ...Loader[T]) SelectQuery[T]
- func (sq SelectQuery[T]) SQL() (Compiled, error)
- func (sq SelectQuery[T]) Scope(s ...Scope[T]) SelectQuery[T]
- func (sq SelectQuery[T]) Where(ps ...Predicate) SelectQuery[T]
- func (sq SelectQuery[T]) With(name string, q Subquery, cols ...string) SelectQuery[T]
- func (sq SelectQuery[T]) WithDeleted() SelectQuery[T]
- func (sq SelectQuery[T]) WithRecursive(name string, q Subquery, cols ...string) SelectQuery[T]
- func (sq SelectQuery[T]) WithTableName(name string) SelectQuery[T]
- type Series
- type SeriesInt
- type ServerVersioner
- type SoftDeleteKind
- type Subquery
- type TableRef
- type TableSource
- type Through
- type Tx
- func (tx *Tx) Commit(ctx context.Context) error
- func (tx *Tx) Dialect() *dialect.Dialect
- func (tx *Tx) DriverTx() DriverTx
- func (tx *Tx) Release(ctx context.Context, name string) error
- func (tx *Tx) Rollback(ctx context.Context) error
- func (tx *Tx) RollbackTo(ctx context.Context, name string) error
- func (tx *Tx) Savepoint(ctx context.Context, name string) error
- func (tx *Tx) SetLocal(ctx context.Context, name, value string) error
- func (tx *Tx) Tx(ctx context.Context, fn func(tx *Tx) error) error
- type TxOptions
- type UnnestArray
- type UnnestCol
- type UnnestSource
- type UpdateQuery
- func (u UpdateQuery[T]) AllRows() UpdateQuery[T]
- func (u UpdateQuery[T]) AppendSQL(b *Builder)
- func (u UpdateQuery[T]) Exec(ctx context.Context) (Result, error)
- func (u UpdateQuery[T]) From(src TableSource) UpdateQuery[T]
- func (u UpdateQuery[T]) Model(m *T) UpdateQuery[T]
- func (u UpdateQuery[T]) Returning(cols ...ColumnRef) UpdateQuery[T]
- func (u UpdateQuery[T]) ReturningAll() UpdateQuery[T]
- func (u UpdateQuery[T]) Rows(ctx context.Context) (*ModelRows[T], error)
- func (u UpdateQuery[T]) SQL() (Compiled, error)
- func (u UpdateQuery[T]) Set(assigns ...Assignment) UpdateQuery[T]
- func (u UpdateQuery[T]) Where(ps ...Predicate) UpdateQuery[T]
- func (u UpdateQuery[T]) With(name string, q Subquery, cols ...string) UpdateQuery[T]
- func (u UpdateQuery[T]) WithRecursive(name string, q Subquery, cols ...string) UpdateQuery[T]
- type VectorColumn
- func (c VectorColumn) AppendSQL(b *Builder)
- func (c VectorColumn[V]) As(alias string) VectorColumn[V]
- func (c VectorColumn) AsExpr() Expression[V]
- func (c VectorColumn) Asc() Order
- func (c VectorColumn) ColumnName() string
- func (c VectorColumn) Desc() Order
- func (c VectorColumn) Dim() int
- func (c VectorColumn) Eq(v V) Predicate
- func (c VectorColumn) EqExpr(e Expression[V]) Predicate
- func (c VectorColumn[V]) Excluded() Expression[V]
- func (c VectorColumn) Flags() uint16
- func (c VectorColumn) In(vs ...V) Predicate
- func (c VectorColumn) InQuery(q Subquery) Predicate
- func (c VectorColumn) IsDistinctFrom(v V) Predicate
- func (c VectorColumn) IsNotDistinctFrom(v V) Predicate
- func (c VectorColumn) IsNotNull() Predicate
- func (c VectorColumn) IsNull() Predicate
- func (c VectorColumn) Ne(v V) Predicate
- func (c VectorColumn) NeExpr(e Expression[V]) Predicate
- func (c VectorColumn) NotIn(vs ...V) Predicate
- func (c VectorColumn) NotInQuery(q Subquery) Predicate
- func (c VectorColumn) ParseCmp(string, string) (Predicate, error)
- func (c VectorColumn) ParseEq(string) (Predicate, error)
- func (c VectorColumn[V]) Set(v V) Assignment
- func (c VectorColumn[V]) SetDefault() Assignment
- func (c VectorColumn[V]) SetExcluded() Assignment
- func (c VectorColumn[V]) SetExpr(e Expression[V]) Assignment
- func (c VectorColumn) Table() string
- type VectorSource
- type VectorValue
- type View
- type WindowExpr
- type WindowFunc
- func DenseRank() WindowFunc[int64]
- func FirstValue[T any](e Expression[T]) WindowFunc[T]
- func Lag[T any](e Expression[T], offset int) WindowFunc[T]
- func LagDefault[T any](e Expression[T], offset int, def T) WindowFunc[T]
- func LastValue[T any](e Expression[T]) WindowFunc[T]
- func Lead[T any](e Expression[T], offset int) WindowFunc[T]
- func LeadDefault[T any](e Expression[T], offset int, def T) WindowFunc[T]
- func Rank() WindowFunc[int64]
- func RowNumber() WindowFunc[int64]
- type WindowSpec
Examples ¶
Constants ¶
const ( FlagPK uint16 = 1 << iota FlagUnique FlagNullable FlagIdentity // generated identity; omitted from inserts FlagReadOnly // DB-generated or computed; never written FlagVersion // optimistic-lock version column FlagSoftDelete FlagHasDefault FlagCreateOnly FlagImmutable FlagSensitive FlagCreatedAt FlagUpdatedAt // FlagDBDefault: a Model or Models insert leaves the column out when the // field holds its zero value, so the database default applies, and reads // the stored value back. Set by the dbdefault tag. FlagDBDefault )
Column flags carried by generated column descriptors and ColumnMeta.
const ( // DefaultHybridCandidates is the candidate count of each leg when // HybridSpec.TextCandidates or VectorCandidates is zero. DefaultHybridCandidates = 100 // DefaultHybridRRFK is the rank constant used when HybridSpec.RRFK is // zero (Cormack, Clarke and Buettcher, 2009). DefaultHybridRRFK = 60 )
Defaults and limits of HybridSpec.
const RedactedArg = redact.Arg
RedactedArg replaces, in QueryEvent.Args, every value bound from a column tagged sensitive. Only the copy handed to hooks is masked.
Variables ¶
var ( // ErrNotFound: a single-row operation (One, First, Model update/delete) // matched no row. Multi-row reads (All, Each, Iter) never return it. ErrNotFound = errors.New("momo: not found") // ErrTooManyRows: One matched more than one row. ErrTooManyRows = errors.New("momo: more than one row") ErrUniqueViolation = errors.New("momo: unique constraint violation") ErrForeignKeyViolation = errors.New("momo: foreign key constraint violation") ErrCheckViolation = errors.New("momo: check constraint violation") ErrNotNullViolation = errors.New("momo: not-null constraint violation") // ErrSerialization: the database aborted the transaction because of a // serialization failure or deadlock. Retrying the whole transaction // may succeed; Momo never retries on its own. ErrSerialization = errors.New("momo: serialization failure") // ErrOptimisticLock: an update or delete guarded by an expected // version matched no row because the version changed (or the row is // gone). ErrOptimisticLock = errors.New("momo: optimistic lock conflict") // ErrUnsupported: the dialect or driver cannot express the request. ErrUnsupported = errors.New("momo: unsupported by dialect or driver") // ErrUnfilteredMutation: an UPDATE or DELETE without a WHERE clause was // attempted without calling AllRows. ErrUnfilteredMutation = errors.New("momo: refusing UPDATE/DELETE without WHERE; call AllRows to confirm") // ErrTxDone: the transaction was already committed or rolled back. ErrTxDone = errors.New("momo: transaction already finished") // ErrAdoptedTx: Commit or Rollback was called on a Tx from DB.AdoptTx. // The caller owns that transaction and finishes it itself; nothing was // committed or rolled back. ErrAdoptedTx = errors.New("momo: transaction is owned by the caller") // ErrValidation: a value failed validation before reaching the database. ErrValidation = errors.New("momo: validation failed") // ErrBusy: the database is busy or locked and could not serve the request. ErrBusy = errors.New("momo: database is busy") // ErrPinnedBusy: PinnedConn.Release was called while a statement was // still executing on the connection from another goroutine. Nothing was // released; call Release again once the statement has finished. ErrPinnedBusy = errors.New("momo: pinned connection is busy") // ErrLimitExceeded: a configured limit (rows, size, parameters) was exceeded. ErrLimitExceeded = errors.New("momo: limit exceeded") // ErrCanceled: a streaming read stopped because its context ended. The // context's own error (context.Canceled or context.DeadlineExceeded) is // wrapped too, so errors.Is matches it as well. ErrCanceled = errors.New("momo: operation canceled") // ErrInvalidVector: a vector value failed validation. ErrInvalidVector = vector.ErrInvalidVector )
Sentinel error kinds. Errors returned by Momo wrap one of these (match with errors.Is) and, when a database error caused them, also wrap the original driver error (reach it with errors.As, e.g. *pgconn.PgError).
Functions ¶
func AllowStaleReads ¶ added in v0.4.0
AllowStaleReads returns a context that opts reads of a Replica handle back to the replica even after a write in the same unit of work.
func Batches ¶ added in v0.4.0
Batches visits every row sq matches in batches of at most n rows, in primary-key order, calling fn for each batch. It pages with keyset pagination on the primary key, never OFFSET, so each row is visited exactly once even while rows with higher keys are inserted, and a deep batch costs the same as the first. sq must not set OrderBy, After, Limit, Offset or MaxRows: Batches owns the order and the page window. An error from fn stops the iteration and is returned.
func CreateGraph ¶
func CreateGraph[P any, PP Modeler[P]](ctx context.Context, q Querier, p *P, includes ...Association[P]) error
CreateGraph inserts p and the children of the listed relations in one transaction. Listed BelongsTo children are written before p and their key is copied into p; the other listed children are written after p, with p's key (read back with RETURNING when it is generated) copied into each child and, for a polymorphic relation, the discriminator set. ManyToMany children are inserted and then linked through the join table. Relations are processed in the order listed. Unlisted relations are not written, and the children's own relations are not followed.
The children of a HasMany or ManyToMany relation are inserted with the chunked bulk insert (InsertQuery.Models): one multi-row statement per bind-limit chunk instead of one statement per child, so 1000 children cost one statement, not 1000. A HasOne or BelongsTo child is a single insert.
Every listed child is inserted as a new row, including a ManyToMany child that is already stored: it is not linked, it is inserted again and fails with ErrUniqueViolation (undoing the whole graph) when its primary key exists. To associate children that already exist, use Relation.Link (or insert them first and Link them) instead of listing the relation here.
A bulk insert returns its rows in insertion order, and CreateGraph matches them to the children by position. If the database returns a different number of rows than were inserted (for example a BEFORE INSERT trigger skipped one), the graph fails with ErrValidation and is undone, rather than leaving the remaining children without their generated keys.
On a *DB the graph runs in a new transaction; on a *Tx it runs in a savepoint, so a failure undoes the whole graph and leaves the caller's transaction usable (a dialect without savepoints returns ErrUnsupported). A model that appears as its own child fails with ErrValidation.
CreateGraph needs a transaction, so a *DB pinned with OnConn fails with ErrUnsupported (Op "begin"); run it on the pool or inside a *Tx. After a failure the database is unchanged, but p and the children keep the generated keys and foreign keys already written into them; do not reuse them as if they were unsaved.
CreateGraph needs RETURNING to read generated keys back: a dialect without it (MySQL) fails with ErrUnsupported before a transaction is opened.
Example ¶
CreateGraph inserts a parent and the children of the listed relations in one transaction.
package main
import (
"context"
"fmt"
"github.com/azrtydxb/momo"
"github.com/azrtydxb/momo/driver/pgxdriver"
"github.com/azrtydxb/momo/internal/relfixture/document"
"github.com/azrtydxb/momo/internal/relfixture/models"
)
func main() {
var (
ctx = context.Background()
db = momo.New(pgxdriver.New(nil))
doc = models.Document{
Title: "Hello",
Comments: []models.Comment{{Body: "first"}},
}
)
err := momo.CreateGraph(ctx, db, &doc, document.Comments.Include())
fmt.Println(err)
}
Output:
func EscapeLike ¶
EscapeLike escapes %, _ and the escape character ! (each is prefixed with !) so the result matches literally inside a LIKE pattern rendered with ESCAPE '!', which Like, ILike and ContainsLiteral always emit. The escape character is deliberately not a backslash: the meaning of a backslash in a string literal depends on server settings (MySQL NO_BACKSLASH_ESCAPES, PostgreSQL standard_conforming_strings), that of ! does not.
func Exec ¶
Exec runs a raw statement. See SQL for the placeholder and safety contract: '?' placeholders, "??" for a literal '?', and on PostgreSQL native $n placeholders.
func Explain ¶ added in v0.5.0
Explain returns the database's plan for the compiled statement c without executing it: EXPLAIN on PostgreSQL, EXPLAIN FORMAT=JSON on MySQL and MariaDB (one text column) and EXPLAIN QUERY PLAN on SQLite. Any statement can be explained, writes included; c.Args are bound, never interpolated. Hooks see the statement with Op "explain". Momo never calls Explain on its own.
SelectQuery.Explain is the shorthand for a select; Explain takes the Compiled value of any query's SQL method.
func ExplainAnalyze ¶ added in v0.5.0
ExplainAnalyze runs c under EXPLAIN (ANALYZE, FORMAT TEXT) and returns the plan with actual timings. ANALYZE executes the statement, so every call runs inside a transaction (or, on a *Tx, a savepoint) that is always rolled back: a write leaves no row behind, and a SELECT that calls a writing function does not keep its writes. A rollback cannot undo effects outside the transaction: sequence values taken by nextval, NOTIFY sent by a function, work done through dblink or a foreign data wrapper, and anything else the statement does outside the database. PostgreSQL only: other dialects return ErrUnsupported and issue nothing. Momo never calls ExplainAnalyze on its own.
func FindAndCount ¶ added in v0.4.0
FindAndCount returns the rows of sq (with its LIMIT and OFFSET) and the total number of rows it matches without them (and without After, ordering and any row lock), using two statements. The two are not one snapshot: run them in a transaction when a consistent pair is required.
func FindOrCreate ¶
func FindOrCreate[T any, PT Modeler[T]](ctx context.Context, q Querier, key []ColumnRef, m *T) (created bool, err error)
FindOrCreate inserts m unless a row with the same key columns exists; then m holds the stored row. The statement is INSERT ... ON CONFLICT (key) DO NOTHING, so the unique constraint on key (which must exist) decides the winner and concurrent callers never create duplicates: the losers re-select the winner's row. created reports whether this call inserted. When the row exists, all of m's mapped columns are overwritten by the stored values; its relation fields are reset (the row is loaded as a plain model).
A soft-deleted row does not count as found: FindOrCreate never returns or restores a row the application deleted. The insert is attempted. When the unique constraint on key covers soft-deleted rows (a plain unique constraint or index, the case FindOrCreate supports), it still holds the deleted row's key, the insert conflicts and the call fails with ErrUniqueViolation (Op "find or create") instead of returning the deleted row: a soft-deleted match is an error, not a surprise resurrection. To reuse the old row, restore it first (update the soft-delete marker back) or pick a new key. A partial unique index (WHERE deleted_at IS NULL) would let the new row in, but FindOrCreate cannot target it: ON CONFLICT (key) without the index predicate does not match a partial index and the database rejects the statement. For a key that soft-deleted rows may release, use Insert(...).OnConflict(key).Where(indexPredicate).DoNothing() and re-select yourself. A model without a soft-delete column is unaffected.
Under READ COMMITTED the conflicting insert waits for a concurrent transaction and the re-select then sees its row. Under REPEATABLE READ or SERIALIZABLE the re-select can miss a row committed after the snapshot and returns ErrNotFound. A dialect without ON CONFLICT or RETURNING (MySQL) returns ErrUnsupported before any statement runs.
Example ¶
FindOrCreate needs a unique key; UpsertByPK inserts or updates by primary key.
package main
import (
"context"
"fmt"
"github.com/azrtydxb/momo"
"github.com/azrtydxb/momo/driver/pgxdriver"
"github.com/azrtydxb/momo/internal/relfixture/author"
"github.com/azrtydxb/momo/internal/relfixture/models"
)
func main() {
var (
ctx = context.Background()
db = momo.New(pgxdriver.New(nil))
a = models.Author{ID: 7, Name: "Ada"}
)
created, err := momo.FindOrCreate(ctx, db, []momo.ColumnRef{author.ID}, &a)
fmt.Println(created, err)
fmt.Println(momo.UpsertByPK(ctx, db, &a))
}
Output:
func FirstID ¶ added in v0.4.0
FirstID returns the primary key of the first row sq matches, or ErrNotFound when none matches.
func FlagsOf ¶ added in v0.4.0
FlagsOf returns the column flags of e, or 0 when e does not implement Flagged. Pass the result to Builder.ArgFor, Builder.RenderSensitive or Builder.ExprFor so values compared with a sensitive column are masked in hook events. FlagsOf is an extension point; see Ops.
func IDs ¶ added in v0.4.0
IDs returns the primary-key value of every row sq matches, in the query's order. The model needs a single-column integer primary key.
func Ident ¶
Ident renders name as a quoted identifier in the dialect's style. It is never bound as a value.
func In ¶
In expands a slice argument into a comma-separated list of bind markers, one per element, for a raw placeholder written inside the parentheses of IN (?). An empty slice, or a value that is not a slice, is a build error, as is an element that is an Ident, In, Named or Expr argument. A []byte is a slice like any other: In([]byte) expands to one bind per byte.
func IsBound ¶ added in v0.4.0
IsBound reports whether e is a Go value bound as a parameter by Value, possibly wrapped by Typed. A feature package uses it to cast a bound operand whose type the server cannot infer (a timestamp inside EXTRACT on PostgreSQL). It is false for a column, a function call or any other expression. IsBound is an extension point; see Ops.
func Load ¶
func Load[P, C any](ctx context.Context, q Querier, parents []P, rel Relation[P, C], opts ...LoadOption[C]) error
Load loads rel for parents and assigns the result onto each parent. Parent order and length are unchanged. Parents with a NULL key get an empty association (nil pointer or nil slice).
Children of a model with a soft-delete column are excluded by default, as in Select; LoadWithDeleted and LoadOnlyDeleted change that.
Associations are cleared up front, so a load that fails part-way leaves the parents with empty associations rather than stale or partial ones. Children are copied per parent: a to-one child shared by several parents is copied shallowly for each, so pointers inside it (including relations loaded with Then) are shared among those copies.
Example ¶
Load fills an association for a slice of parents with one statement per bind-limit chunk. Options scope the child statement.
package main
import (
"context"
"fmt"
"github.com/azrtydxb/momo"
"github.com/azrtydxb/momo/driver/pgxdriver"
"github.com/azrtydxb/momo/internal/relfixture/comment"
"github.com/azrtydxb/momo/internal/relfixture/document"
"github.com/azrtydxb/momo/internal/relfixture/models"
)
func main() {
var (
ctx = context.Background()
db = momo.New(pgxdriver.New(nil))
docs []models.Document
)
err := momo.Load(ctx, db, docs, document.Comments,
momo.LoadWhere[models.Comment](comment.Approved.Eq(true)),
momo.LoadOrderBy[models.Comment](comment.ID.Desc()),
momo.LoadPerParentLimit[models.Comment](3),
)
fmt.Println(err)
}
Output:
func LoadAll ¶
LoadAll loads several relations for the same parents, in order. The top level of each relation is one statement per bind-limit chunk; nested loads run once over all children of the level above.
On a connection whose driver implements Batcher (pgx), the statements of all relations of a level, and every bind-limit chunk, are pipelined in one round trip; other drivers load sequentially. Results are the same either way; hook event order differs (see rel_pipeline.go). A pipelined level buffers all of its child rows in memory before assigning them (roughly twice the peak of sequential loading). There is no per-call opt-out: a driver or connection without Batcher loads sequentially.
Example ¶
LoadAll loads several relations together.
package main
import (
"context"
"fmt"
"github.com/azrtydxb/momo"
"github.com/azrtydxb/momo/driver/pgxdriver"
"github.com/azrtydxb/momo/internal/relfixture/document"
"github.com/azrtydxb/momo/internal/relfixture/models"
)
func main() {
var (
ctx = context.Background()
db = momo.New(pgxdriver.New(nil))
docs []models.Document
)
err := momo.LoadAll(ctx, db, docs,
document.Author,
document.Tags,
document.Comments,
)
fmt.Println(err)
}
Output:
func LoadCounts ¶ added in v0.4.0
func LoadCounts[P, C any](ctx context.Context, q Querier, parents []P, rel Relation[P, C], opts ...LoadOption[C]) ([]int64, error)
LoadCounts counts the children of every parent in parents with one grouped statement per bind-limit chunk, instead of one Relation.Count call per parent. The result has one entry per parent, in parents order; a parent with no children, or with a NULL key, counts zero. Parents sharing a key share the count.
counts, err := momo.LoadCounts(ctx, db, docs, document.Comments, momo.LoadWhere[models.Comment](comment.Approved.Eq(true)))
It supports has-one, has-many and many-to-many relations, including composite keys and polymorphic (Discriminator) relations; belongs-to fails with ErrUnsupported, as Count does. Load options narrow what is counted: LoadWhere filters the children (it may reference the child table), and soft-deleted children are excluded unless LoadWithDeleted or LoadOnlyDeleted says otherwise, exactly like Load. LoadOrderBy has no effect, and LoadPerParentLimit fails with ErrValidation.
Many-to-many counts join-table rows, as Count does: the join to the far table is added only when the child has a soft-delete column or a filter applies. Statements are SELECT key, COUNT(*) ... GROUP BY key.
func MapRows ¶ added in v0.4.0
MapRows renders sql through the raw path (see Exec) and returns every row as a map from column name to value. Names are as the driver reports them (for PostgreSQL, the folded column name or alias), and values have the driver's native Go types. Two result columns with the same name are ambiguous in a map, so they fail with ErrValidation: alias them in the SQL. It needs a driver whose rows implement ColumnNamer and returns ErrUnsupported otherwise. MapRows buffers the whole result in memory and ignores MaxRows, which is a SelectQuery option; bound the SQL with LIMIT. An empty result is a nil slice and a nil error.
func MySQLVectorType ¶ added in v0.4.0
MySQLVectorType returns the column type for a vector of dim elements on a MySQL or MariaDB server: "VECTOR(N)". serverVersion is the result of SELECT VERSION(). MySQL has the type from 9.0 and MariaDB from 11.7; an older server, a dimensionless column and an unreadable version fail with an error that wraps ErrUnsupported and, for a version problem, names the version. Migration code calls this when it renders a vector column.
func NewUnitOfWork ¶ added in v0.4.0
NewUnitOfWork returns a context in which every write made through any handle is recorded. A Replica handle reads from the primary once a write has been recorded in that context, so a request reads its own writes.
func Pluck ¶ added in v0.4.0
func Pluck[T, V any](ctx context.Context, sq SelectQuery[T], c Expression[V]) ([]V, error)
Pluck runs sq selecting only the expression c and returns that column of every row. The query keeps its WHERE, ORDER BY, LIMIT and MaxRows; Preload does not apply. An empty result is a nil slice and a nil error.
func Query ¶ added in v0.5.0
func Query[T any, PT Modeler[T]](ctx context.Context, q Querier, sql string, args ...any) ([]T, error)
Query renders sql through the raw path (see Exec: '?' binds, "??" is a literal '?', Expr arguments render inline, an argument-count mismatch is a build error; on PostgreSQL native $n placeholders bind argument n, see SQL) and scans every row into a T. T is a model, a projection struct, or one of the tuple rows Row1 to Row10. It is the multi-column counterpart of Scalars for a hand-written SELECT or a statement with RETURNING:
rows, err := momo.Query[momo.Row2[string, int64]](ctx, db, `SELECT title, count(*) FROM documents WHERE tenant_id = $1 GROUP BY title`, tenant)
Columns are matched as for a typed select. A tuple row scans positionally, and the result must have exactly as many columns as the row has fields. A model or projection scans by column name, whatever order the SQL lists them (names compare exactly, then case-insensitively, since PostgreSQL folds unquoted names): a result column that no field maps to, a mapped column the result lacks, or two result columns with the same name is an ErrValidation. A driver whose rows cannot report column names falls back to the positional order of the type's columns.
The statement runs with the same hooks, interceptors, error classification and argument redaction as Exec, on a *DB, a *Tx or a pinned handle; its hook event has the op "raw". The rows bypass soft-delete filters, AfterLoad hooks and timestamps. Query buffers the whole result in memory and ignores MaxRows, so bound the SQL with LIMIT or use QueryRows. An empty result is a nil slice and a nil error.
func QueryRows ¶ added in v0.5.0
func QueryRows[T any, PT Modeler[T]](ctx context.Context, q Querier, sql string, args ...any) iter.Seq2[T, error]
QueryRows is the streaming form of Query: it yields one T per row without buffering the result. Breaking out of the loop closes the cursor, and an error (a build, driver, scan or column-matching error, or a canceled context as ErrCanceled) is yielded once, as the final element. The placeholder, matching, hook and redaction rules are those of Query.
for row, err := range momo.QueryRows[momo.Row2[int64, string]](ctx, db,
`SELECT id, title FROM documents ORDER BY id`) {
if err != nil {
return err
}
use(row.C1, row.C2)
}
func RecordPoolWait ¶
RecordPoolWait adds d to the pool wait of the statement whose context is ctx. Drivers call it when a connection acquisition waited (pgxdriver does so from its pgxpool AcquireTracer). It is a no-op when ctx does not belong to a hooked statement, so it costs nothing when no hook is registered.
func RegisterQuery ¶ added in v0.5.0
func RegisterQuery(name string, build func(q Querier) Compilable)
RegisterQuery registers build under name in the DefaultQueries registry. See QueryRegistry.Register.
func SQLiteBitsType ¶ added in v0.4.0
SQLiteBitsType is SQLiteVectorType for a bit vector of n bits: a BLOB whose length is the packed size, (n+7)/8 bytes. An n below one is ErrUnsupported and one above vector.MaxBits is ErrValidation.
func SQLiteVectorType ¶ added in v0.4.0
SQLiteVectorType returns the column definition of a float32 vector of dim elements on SQLite: a BLOB whose length is checked, for example BLOB CHECK (length("emb") = 12) for dim 3. sqlite-vec stores vectors in plain BLOB columns and has no declared dimension, so the CHECK is what keeps a vector of the wrong size out of the table. column is the name of the column being declared and is quoted. A dim below one is ErrUnsupported (a dimensionless column has no length to check) and one above vector.MaxDim is ErrValidation. Migration code calls this when it renders a vector column.
func Scalars ¶
Scalars renders sql through the raw path (see Exec: '?' binds, "??" is a literal '?', Expr arguments render inline, an argument-count mismatch is a build error; on PostgreSQL native $n placeholders bind argument n, see SQL) and returns the first column of every row as V. An empty result returns a nil slice and a nil error.
func SetConfigLocal ¶ added in v0.4.0
SetConfigLocal sets the configuration parameter key to value for the rest of the current transaction only (set_config with is_local = true). It is the building block for tenant scoping inside WithTxSetup. Because the setting ends with the transaction it is safe behind PgBouncer in transaction mode; never use a session-level SET for this. key must not come from untrusted input (see Tx.SetLocal). It returns ErrUnsupported on dialects without transaction-scoped settings.
func Truncate ¶ added in v0.4.0
Truncate removes all rows of T's table, soft-deleted rows included, with no filter. PostgreSQL and MySQL run TRUNCATE TABLE with no RESTART IDENTITY and no CASCADE: PostgreSQL keeps the identity sequence and fails when another table has a foreign key to this one, and MySQL resets its AUTO_INCREMENT counter. SQLite runs DELETE FROM and deletes the table's sqlite_sequence row when that table exists, so a SQLite autoincrement key restarts. The two SQLite statements are atomic: on a DB they run in one transaction, on a Tx in a savepoint.
MySQL TRUNCATE is DDL and commits implicitly, so inside a Tx it is refused with ErrUnsupported. On a MySQL DB made with WithImplicitTx the statement is still wrapped in the implicit BEGIN and COMMIT, and MySQL commits it at once, so that transaction (and any WithTxSetup setting in it) ends with the TRUNCATE; the wrapper is harmless but gives no atomicity. The handle's interceptors run first with the kind "truncate" and can deny it; a predicate they add is ignored, so a tenant-scoped handle should deny the kind.
func UpsertByPK ¶
UpsertByPK inserts m, or updates the row with the same primary key: INSERT ... ON CONFLICT (pk) DO UPDATE SET col = EXCLUDED.col for every column an update may change (the primary key, version, soft-delete and created-at columns are never overwritten; see Upsert for the exact rules and for an upsert on another conflict target). Generated columns are read back into m. It is the one-call form of Upsert(q).Model(m).
func ValidName ¶ added in v0.4.0
ValidName checks an identifier-like name: non-empty, at most 63 bytes, a letter or underscore first, then letters, digits, underscores or dollar signs. It returns a descriptive error otherwise. Code outside the package uses it to check a function name or alias before writing it with Builder.Ident. ValidName is an extension point; see Ops.
func ValidTypeName ¶ added in v0.4.0
ValidTypeName checks a "word word(1,2)" shaped SQL type name: words of letters, digits and underscores separated by single spaces, with an optional (n) or (n,m) suffix, such as bigint, double precision or numeric(10,2). It returns a descriptive error otherwise. Code outside the package uses it to check a type name before writing it into a CAST. ValidTypeName is an extension point; see Ops.
func WithDetail ¶ added in v0.4.0
WithDetail returns a copy of err with the raw driver detail set, so Detail can return it while Error keeps hiding it. Drivers call it from their classifier. An err that is not a *Error is returned unchanged.
func WithQueryScope ¶ added in v0.4.0
WithQueryScope returns a context that groups statements for the N+1 detector. Wrap one unit of work (an HTTP request, a job) and pass the context to every query in it. Contexts without a scope are not tracked.
Types ¶
type Agg ¶
type Agg[T any] struct { // contains filtered or unexported fields }
Agg is a typed aggregate expression such as COUNT(*) or SUM(col). Besides being an Expression[T] usable in a select list, it carries the comparison methods HAVING needs.
func Avg ¶
func Avg(e Expression[float64]) Agg[float64]
Avg is AVG(expr) as float64. It is NULL over zero rows: scan it into *float64 (or sql.NullFloat64), or wrap it in Coalesce.
func Min ¶
func Min[T any](e Expression[T]) Agg[T]
Min is MIN(expr) (NULL over zero rows). T is any type the database can order, such as time.Time, a decimal, or a string.
func Sum ¶
func Sum[T Number](e Expression[T]) Agg[T]
Sum is SUM(expr). The result is NULL over zero rows, so scan it into a nullable destination such as *int64 or *float64 (sql.Null types work too), or wrap it in Coalesce. Scanning NULL into a plain int64 returns an error.
func (Agg[T]) Filter ¶ added in v0.4.0
func (a Agg[T]) Filter(p Predicate) FilteredAgg[T]
Filter restricts the rows the aggregate sees: COUNT(*) FILTER (WHERE p). PostgreSQL and SQLite support it; MySQL has no FILTER clause and fails the build with ErrUnsupported (write SUM(CASE WHEN ...) there).
func (Agg[T]) Over ¶ added in v0.4.0
func (a Agg[T]) Over(w WindowSpec) WindowExpr[T]
Over turns an aggregate into a window function: SUM(x) OVER (...).
type Aliased ¶
type Aliased[T any] struct { // contains filtered or unexported fields }
Aliased is a select-list item "expr AS alias". T is the expression's result type, which Ref carries to the outer query.
func As ¶
func As[T any](e Expression[T], alias string) Aliased[T]
As aliases an expression in a select list: expr AS alias. The alias is quoted and must be a plain identifier (letters, digits, underscore, "$", not starting with a digit, at most 63 bytes), otherwise the build fails with ErrValidation. Use it on columns, aggregates, CASE, function calls and TypedSQL fragments; to alias a scalar subquery wrap it in TypedSQL[T] with "?". Column.As is the table alias, so use As[T](col, name) for a column.
type Allowlist ¶
type Allowlist struct {
// contains filtered or unexported fields
}
Allowlist maps external names to typed column descriptors. Unknown names are an error: a name that arrives from outside (a sort key, a filter field) is only ever turned into SQL through the descriptor it resolves to, whose identifier is quoted by the builder, never by splicing the string.
func NewAllowlist ¶
NewAllowlist builds an allowlist keyed by ColumnName(). A later column with the same name replaces an earlier one. nil entries are skipped.
type Assignment ¶
type Assignment struct {
// contains filtered or unexported fields
}
Assignment is one explicit column write. Constructing one is the only way to include a column in a typed INSERT or UPDATE, which is how Momo keeps omitted, zero, NULL and DEFAULT distinct.
func (Assignment) ColumnName ¶
func (a Assignment) ColumnName() string
ColumnName returns the assigned column.
type Association ¶
type Association[P any] interface { // contains filtered or unexported methods }
Association is one relation listed for CreateGraph. It is produced only by Relation.Include, so unlisted relations are never written.
type Batcher ¶
Batcher is implemented by drivers that send several statements in one round trip. Every statement is executed with Query; a statement without result rows yields a Rows whose Next returns false.
type Builder ¶
type Builder struct {
// contains filtered or unexported fields
}
Builder accumulates SQL text and bind arguments for one statement.
Identifiers go through Ident (always quoted); values go through Arg (always bound as parameters). Raw text is only written by Momo itself or by the explicit raw-SQL escape hatches (SQL and RawSubquery), whose safety contract is documented on those functions.
func NewBuilder ¶
NewBuilder returns a builder for the dialect.
func (*Builder) AppendFilter ¶ added in v0.4.0
AppendFilter writes " FILTER (WHERE p)" for an aggregate call that was just rendered. A nil predicate fails the build with ErrValidation instead of silently leaving the aggregate unfiltered; MySQL has no FILTER clause and fails with ErrUnsupported. AppendFilter is an extension point; see Ops.
func (*Builder) ArgFor ¶ added in v0.4.0
ArgFor binds v like Arg and records it as sensitive when flags carries FlagSensitive, so QueryEvent.Args shows RedactedArg instead of the value. Take flags from FlagsOf of the column the value is compared with, or from RenderSensitive. ArgFor is an extension point; see Ops.
func (*Builder) ExprFor ¶ added in v0.4.0
ExprFor renders e with every argument it binds recorded as sensitive when flags carries FlagSensitive, for an expression compared with or assigned to such a column. ExprFor is an extension point; see Ops.
func (*Builder) MarkSensitive ¶ added in v0.4.0
func (b *Builder) MarkSensitive()
MarkSensitive records that the expression being rendered read a sensitive column, so an enclosing predicate that compares it masks its other operands in hook events. A column reference does this by itself; call MarkSensitive from a custom expression that writes a sensitive column's identifier directly with Ident or QualifiedIdent instead of rendering the column. It does not change the SQL. MarkSensitive is an extension point; see Ops.
func (*Builder) QualifiedIdent ¶
QualifiedIdent appends qualifier.name, both quoted. An empty qualifier (or an unqualified context) renders the bare quoted name.
func (*Builder) RenderSensitive ¶ added in v0.4.0
RenderSensitive renders e and returns flags with FlagSensitive added when e read a sensitive column. The result is the flag to bind the other operands of the predicate with, through ArgFor or ExprFor. RenderSensitive is an extension point; see Ops.
func (*Builder) SetErr ¶
SetErr records the first build error; rendering continues but the statement will not be executed.
func (*Builder) Unsupported ¶ added in v0.4.0
Unsupported records an ErrUnsupported build error for feature, naming the dialect being rendered. Call it from a custom expression that the dialect cannot express, instead of rendering SQL that would fail at the database. Unsupported is an extension point; see Ops.
func (*Builder) WriteByte ¶
WriteByte appends a trusted SQL byte. It always returns nil; the error result exists only so Builder satisfies io.ByteWriter.
func (*Builder) WriteString ¶
WriteString appends trusted SQL text.
type Capabilities ¶
type Capabilities struct {
Vectors bool // sqlite-vec or pgvector functions are available
Batch bool
Copy bool
}
Capabilities describes what a driver can execute beyond the dialect.
type CapabilityReporter ¶
type CapabilityReporter interface {
Capabilities() Capabilities
}
CapabilityReporter is implemented by drivers that report driver-level capabilities. Vector builders check Vectors and return ErrUnsupported when it is false.
type Column ¶
type Column[T any] struct { // contains filtered or unexported fields }
Column is a typed column descriptor generated for each model field. T is the column's Go value type with nullability removed (a *string field has a Column[string]-compatible NullColumn[string]).
Column values are small, immutable and safe to share between goroutines. Build one with NewColumn, ColumnOf or the generated descriptors: the zero value Column[T]{} has no column reference, so using it in a comparison fails the build with ErrValidation.
func ColumnOf ¶
ColumnOf declares a typed column of an ad-hoc source (CTE, subquery alias). Momo cannot check that the column exists or has type T.
func (Column) AsExpr ¶
func (c Column) AsExpr() Expression[T]
AsExpr returns the column as an Expression[T], so a projection list reads explicitly: DocTitle.As("l").AsExpr().
func (Column) Asc ¶
func (c Column) Asc() Order
Asc orders by the column ascending. The order item is the column itself, a ColumnRef, so keyset pagination recognizes a primary-key column.
func (Column) ColumnName ¶
func (c Column) ColumnName() string
ColumnName returns the unquoted column name.
func (Column) Excluded ¶ added in v0.2.0
func (c Column) Excluded() ExcludedExpr[T]
Excluded is the value proposed for insertion in an upsert, rendered as EXCLUDED.<col>. Use it on the right-hand side of a comparison in the DO UPDATE WHERE or ON CONFLICT predicates, for example until.LtExpr(until.Excluded()). It is only meaningful inside an ON CONFLICT clause; the database rejects it elsewhere.
func (Column) ParseCmp ¶ added in v0.4.0
ParseCmp parses raw with the column's Go type and returns the comparison predicate for op, one of eq, ne, lt, le, gt and ge. An unknown op or a value that does not parse is an *Error with Kind ErrValidation. It is meant for a filter value that arrives as text from outside; the column comes from the generated ColumnByName allowlist.
func (Column) ParseEq ¶ added in v0.4.0
ParseEq parses raw with the column's Go type and returns the equality predicate on it. A value that does not parse is an *Error with Kind ErrValidation; the error does not echo raw, which may be attacker controlled.
func (Column[T]) Set ¶
func (c Column[T]) Set(v T) Assignment
Set assigns a value (including the zero value) in INSERT or UPDATE.
func (Column[T]) SetDefault ¶
func (c Column[T]) SetDefault() Assignment
SetDefault assigns the column's database default. PostgreSQL supports it in INSERT and UPDATE; SQLite only by omitting the column from an INSERT, so an UPDATE with SetDefault fails with ErrUnsupported there.
func (Column[T]) SetExcluded ¶
func (c Column[T]) SetExcluded() Assignment
SetExcluded assigns the value proposed for insertion in an upsert (ON CONFLICT ... DO UPDATE SET col = excluded.col).
func (Column[T]) SetExpr ¶
func (c Column[T]) SetExpr(e Expression[T]) Assignment
SetExpr assigns an expression.
type ColumnMeta ¶
ColumnMeta describes one mapped field.
type ColumnNamer ¶ added in v0.4.0
ColumnNamer is implemented by Rows that can report the names of their result columns, in order, as the database reports them. MapRows needs it. Rows that cannot report names return an empty slice and a nil error (the wrapper momo puts around rows for hooks implements the interface for every driver), which makes MapRows return ErrUnsupported.
type ColumnRef ¶
type ColumnRef interface {
Expr
ColumnName() string
// ParseEq parses raw with the column's Go type and returns the equality
// predicate; a value that does not parse is an ErrValidation error.
ParseEq(raw string) (Predicate, error)
// ParseCmp is ParseEq for op eq, ne, lt, le, gt or ge.
ParseCmp(op, raw string) (Predicate, error)
}
ColumnRef is an untyped reference to a column of a table source. It is used where only the identity of the column matters (ON CONFLICT targets, Omit lists, GROUP BY).
type Compilable ¶ added in v0.5.0
Compilable is a statement that renders to SQL without running it. The query builders (SelectQuery, InsertQuery, UpdateQuery, DeleteQuery, MergeQuery) implement it through their SQL method, and RawQuery wraps a hand-written statement.
func RawQuery ¶ added in v0.5.0
func RawQuery(q Querier, sql string, args ...any) Compilable
RawQuery wraps a hand-written statement as a Compilable, with the placeholder rules of Exec ('?' binds, "??" is a literal '?', on PostgreSQL native $n placeholders). It is for QueryRegistry builders:
momo.RegisterQuery("open_tasks", func(q momo.Querier) momo.Compilable {
return momo.RawQuery(q, "SELECT id, title FROM tasks WHERE owner = $1 AND NOT done", 0)
})
A malformed statement shows as the error of SQL.
type Config ¶
type Config struct{}
Config is the receiver of a model's MomoConfig companion method. Every method is read statically by the generator from the Go source and is never executed for its effect; at runtime they are all no-ops. Field arguments are pointers taken from the model receiver (&d.Field); their value is ignored.
func (*Config) Check ¶
Check declares a named check constraint. Read statically by the generator; never executed for its effect.
func (*Config) Collate ¶
Collate sets a column collation. Read statically by the generator; never executed for its effect.
func (*Config) Comment ¶
Comment sets a column comment. Read statically by the generator; never executed for its effect.
func (*Config) Default ¶
Default sets a column default expression. Read statically by the generator; never executed for its effect.
func (*Config) Enum ¶
Enum declares a named enum type with its values. Read statically by the generator; never executed for its effect.
func (*Config) FKName ¶ added in v0.5.0
FKName names the foreign key constraint of the belongs_to relation whose key field is field, for a name other than the derived <table>_<column>_fkey (for example _fkey1 on a partitioned table). Read statically by the generator; never executed for its effect.
func (*Config) ForeignKey ¶ added in v0.5.0
func (c *Config) ForeignKey(name string, cols []any, refTable string, refColumns []string) *ForeignKeyOpts
ForeignKey declares a named foreign key over one or more fields of the model: cols is a []any literal of field references, refTable the referenced table and refColumns its columns, which must be its primary key or the columns of a unique constraint or unique index on it. Read statically by the generator; never executed for its effect.
func (*Config) Function ¶
Function declares a function. The argument must be a composite literal; read statically by the generator, never executed.
func (*Config) IDGen ¶ added in v0.4.0
IDGen declares a Go-side id generator for a string field: an insert fills the field when it holds the zero value. The name is a string literal: cuid, uuid or ulid, or one registered with WithIDGenerator. Read statically by the generator; never executed for its effect.
func (*Config) Index ¶
Index declares a non-unique index over the given field references. Read statically by the generator; never executed for its effect.
func (*Config) IndexExpr ¶
IndexExpr declares an expression index. Each argument is one key: an expression such as "lower(email)", or the exact name of a column of the table, which is a plain column key (so "company_id", "lower(name)" mixes the two). Chain Unique for a unique index and Where for a partial one. Read statically by the generator; never executed for its effect.
func (*Config) Partition ¶
Partition declares the table's partitioning. The argument must be a composite literal; read statically by the generator, never executed.
func (*Config) PartitionOf ¶
func (c *Config) PartitionOf(p schema.PartitionOf)
PartitionOf declares the table as a partition of a parent. The argument must be a composite literal; read statically by the generator, never executed.
func (*Config) Policy ¶
Policy declares a row-level security policy. The argument must be a composite literal; read statically by the generator, never executed.
func (*Config) PrimaryKey ¶ added in v0.5.0
PrimaryKey orders the columns of a composite primary key, for a key whose column order differs from the field order (the order is the btree order that lookups rely on). The fields must be exactly the fields tagged pk. Read statically by the generator; never executed for its effect.
func (*Config) RLS ¶
RLS declares the table's row-level security flags. The argument must be a composite literal; read statically by the generator, never executed.
func (*Config) Trigger ¶
Trigger declares a trigger. The argument must be a composite literal; read statically by the generator, never executed.
type ConflictQuery ¶
type ConflictQuery[T any] struct { // contains filtered or unexported fields }
ConflictQuery is an INSERT awaiting its ON CONFLICT action.
func (ConflictQuery[T]) DoNothing ¶
func (c ConflictQuery[T]) DoNothing() InsertQuery[T]
DoNothing skips rows that conflict.
func (ConflictQuery[T]) DoUpdate ¶
func (c ConflictQuery[T]) DoUpdate(assigns ...Assignment) InsertQuery[T]
DoUpdate updates the existing row on conflict. Use SetExcluded to take the value proposed for insertion.
func (ConflictQuery[T]) Where ¶ added in v0.2.0
func (c ConflictQuery[T]) Where(preds ...Predicate) ConflictQuery[T]
Where adds predicates to the conflict target, rendered as ON CONFLICT (cols) WHERE <preds>. PostgreSQL and SQLite need it to infer a partial unique index: the predicate must imply the index predicate, and without it the database rejects the statement. Several calls AND together. It needs target columns in OnConflict (otherwise the build fails with ErrValidation) and works with both DoNothing and DoUpdate. Columns render without a table qualifier, as the database requires in an index predicate. On SQLite, bool, integer and string values render inline (SQLite matches the predicate against the index text, so a bound value never matches), which also puts them in logs and traces. Only bool, integer, finite float and string values (after Value()) can be inlined; any other value fails with ErrValidation. SQLite compares the literal text with the index, so write index literals as Momo renders them: integers as 2, floats in plain decimal with .0 for whole numbers (2.0) for magnitudes from 1e-6 up to 1e21, and exponent form (1e-07, 1e+21) outside that range; otherwise use momo.SQL. Excluded() in the predicate fails with ErrValidation. MySQL has no ON CONFLICT and fails with ErrUnsupported.
type Copier ¶
type Copier interface {
CopyFrom(ctx context.Context, table string, cols []string, rows [][]any) (int64, error)
}
Copier is implemented by drivers with a native bulk-copy path.
func CopierOf ¶
CopierOf returns the Copier behind q: the driver for a *DB, the transaction for a *Tx. For a *DB made with OnConn it is the pinned connection, so COPY runs on the pinned session. A *DB made with WithReplicas or Replica always reports a Copier, because the router forwards COPY to the primary; its CopyFrom returns ErrUnsupported when the primary has none. Insert.Copy checks the primary itself and fails before it runs hooks or opens a transaction.
type CreateOnlyColumn ¶
type CreateOnlyColumn[T any] struct { // contains filtered or unexported fields }
CreateOnlyColumn is the descriptor of a column writable in INSERT only. Its Set returns an InsertAssignment, which Update.Set does not accept.
func NewCreateOnlyColumn ¶
func NewCreateOnlyColumn[T any](table, name string, flags uint16) CreateOnlyColumn[T]
NewCreateOnlyColumn is used by generated code.
func (CreateOnlyColumn[T]) As ¶
func (c CreateOnlyColumn[T]) As(alias string) CreateOnlyColumn[T]
As returns the same column qualified by a table alias.
func (CreateOnlyColumn) AsExpr ¶
func (c CreateOnlyColumn) AsExpr() Expression[T]
AsExpr returns the column as an Expression[T], so a projection list reads explicitly: DocTitle.As("l").AsExpr().
func (CreateOnlyColumn) Asc ¶
func (c CreateOnlyColumn) Asc() Order
Asc orders by the column ascending. The order item is the column itself, a ColumnRef, so keyset pagination recognizes a primary-key column.
func (CreateOnlyColumn) ColumnName ¶
func (c CreateOnlyColumn) ColumnName() string
ColumnName returns the unquoted column name.
func (CreateOnlyColumn) Desc ¶
func (c CreateOnlyColumn) Desc() Order
Desc orders by the column descending.
func (CreateOnlyColumn[T]) Excluded ¶ added in v0.2.0
func (c CreateOnlyColumn[T]) Excluded() Expression[T]
Excluded is the value proposed for insertion, for an upsert condition.
func (CreateOnlyColumn) Flags ¶
func (c CreateOnlyColumn) Flags() uint16
Flags returns the generated column flags.
func (CreateOnlyColumn) ParseCmp ¶ added in v0.4.0
ParseCmp parses raw with the column's Go type and returns the comparison predicate for op, one of eq, ne, lt, le, gt and ge. An unknown op or a value that does not parse is an *Error with Kind ErrValidation. It is meant for a filter value that arrives as text from outside; the column comes from the generated ColumnByName allowlist.
func (CreateOnlyColumn) ParseEq ¶ added in v0.4.0
ParseEq parses raw with the column's Go type and returns the equality predicate on it. A value that does not parse is an *Error with Kind ErrValidation; the error does not echo raw, which may be attacker controlled.
func (CreateOnlyColumn[T]) Set ¶
func (c CreateOnlyColumn[T]) Set(v T) InsertAssignment
Set assigns v on insert. The result is an InsertAssignment, which only Insert accepts.
type CreateOnlyVectorColumn ¶
type CreateOnlyVectorColumn[V VectorValue] struct { // contains filtered or unexported fields }
CreateOnlyVectorColumn is a vector column writable in INSERT only. Its Set returns an InsertAssignment, which Update.Set does not accept.
func NewCreateOnlyVectorColumn ¶
func NewCreateOnlyVectorColumn[V VectorValue](table, name string, dim int, flags uint16) CreateOnlyVectorColumn[V]
NewCreateOnlyVectorColumn is used by generated code.
func (CreateOnlyVectorColumn) AppendSQL ¶
func (c CreateOnlyVectorColumn) AppendSQL(b *Builder)
AppendSQL renders the qualified, quoted column.
func (CreateOnlyVectorColumn[V]) As ¶
func (c CreateOnlyVectorColumn[V]) As(alias string) CreateOnlyVectorColumn[V]
As returns the same column qualified by a table alias.
func (CreateOnlyVectorColumn) AsExpr ¶
func (c CreateOnlyVectorColumn) AsExpr() Expression[V]
AsExpr returns the column as an Expression[V].
func (CreateOnlyVectorColumn) ColumnName ¶
func (c CreateOnlyVectorColumn) ColumnName() string
ColumnName returns the unquoted column name.
func (CreateOnlyVectorColumn) Dim ¶
func (c CreateOnlyVectorColumn) Dim() int
Dim returns the declared dimension. Zero marks a dimensionless column: a distance argument of any size is accepted and checked against itself.
func (CreateOnlyVectorColumn) EqExpr ¶
func (c CreateOnlyVectorColumn) EqExpr(e Expression[V]) Predicate
func (CreateOnlyVectorColumn) Flags ¶
func (c CreateOnlyVectorColumn) Flags() uint16
Flags returns the generated column flags.
func (CreateOnlyVectorColumn) IsDistinctFrom ¶
func (c CreateOnlyVectorColumn) IsDistinctFrom(v V) Predicate
IsDistinctFrom is a NULL-safe inequality.
func (CreateOnlyVectorColumn) IsNotDistinctFrom ¶
func (c CreateOnlyVectorColumn) IsNotDistinctFrom(v V) Predicate
IsNotDistinctFrom is a NULL-safe equality.
func (CreateOnlyVectorColumn) IsNotNull ¶
func (c CreateOnlyVectorColumn) IsNotNull() Predicate
IsNotNull is true when the column holds a value.
func (CreateOnlyVectorColumn) IsNull ¶
func (c CreateOnlyVectorColumn) IsNull() Predicate
IsNull is true when the column holds SQL NULL.
func (CreateOnlyVectorColumn) NeExpr ¶
func (c CreateOnlyVectorColumn) NeExpr(e Expression[V]) Predicate
func (CreateOnlyVectorColumn) NotInQuery ¶
func (CreateOnlyVectorColumn) ParseCmp ¶ added in v0.4.0
ParseCmp always fails: a vector has no text form to filter by.
func (CreateOnlyVectorColumn) ParseEq ¶ added in v0.4.0
ParseEq always fails: a vector has no text form to filter by.
func (CreateOnlyVectorColumn[V]) Set ¶
func (c CreateOnlyVectorColumn[V]) Set(v V) InsertAssignment
Set assigns v on insert; only Insert accepts the result.
type DB ¶
type DB struct {
// contains filtered or unexported fields
}
DB is a Momo handle over a driver. It is safe for concurrent use and holds no state besides configuration: no background goroutines, no implicit migrations, no caches.
func NewOffline ¶ added in v0.5.0
NewOffline returns a *DB for dialect d that compiles statements but never reaches a database: every execution returns an error matching ErrUnsupported. Use it to call SQL on a query builder in a unit test. The dialect is the default one for d, without a MySQL flavor or a server version.
NewOffline panics for a dialect name that is not postgres, mysql or sqlite.
func (*DB) AdoptTx ¶ added in v0.3.0
AdoptTx binds a Tx to dtx, a driver transaction the caller already began and keeps ownership of. Statements, hooks, error classification, the dialect and savepoints (Tx.Tx, Savepoint, ...) behave as on a Tx begun by DB.Begin, but Commit and Rollback on the returned Tx (not on a savepoint scope, which still releases and rolls back its savepoint) return an error matching ErrAdoptedTx and never touch dtx: the caller commits or rolls back its own transaction. Obtain a dtx from the driver package, for example pgxdriver.SQLTx or pgxdriver.PgxTx. Once the caller finishes the transaction, further statements fail with the driver's finished-transaction error (ErrTxDone). AdoptTx panics when dtx is nil, a programming error like a nil Driver in New. It does not fire begin hooks: momo did not begin it.
func (*DB) Begin ¶
Begin starts an explicit transaction. The caller must Commit or Rollback; a deferred Rollback after Commit is a harmless no-op returning ErrTxDone.
func (*DB) IsPinned ¶ added in v0.5.0
IsPinned reports whether db is a handle from OnConn, whose statements all run on one pinned connection. A *DB over a pool reports false. Session-scoped helpers such as the session locks of package advisory use it to refuse a pooled handle, where two statements can reach two connections.
func (*DB) OnConn ¶
func (db *DB) OnConn(pc PinnedConn) *DB
OnConn returns a handle whose statements all run on pc, a connection pinned with Pinner.Pin. It is a copy of db: it keeps db's hooks, error classifier and options (WithHook, WithArgLogging, ...). Begin and Tx on it return ErrUnsupported with Op "begin": a pinned connection is not a pool, so transactions are not started on it. Non-transactional Go migrations and session-scoped work use it. The caller still owns pc and releases it.
func (*DB) Replica ¶ added in v0.4.0
Replica returns a read handle whose plain reads go to replica i, unless the context is a unit of work that has written: then reads go to the primary. Writes, transactions, INSERT/UPDATE/DELETE ... RETURNING, locking reads (FOR UPDATE and FOR SHARE), and any statement that readOnlySQL cannot prove read-only, such as a WITH that contains DML or a call to nextval, always go to the primary, and count as a write of the unit of work. If the replica cannot be reached when a read starts, that read runs on the primary; there is no retry once rows have been returned.
It returns ErrUnsupported when replica i is not configured, and when the DB was built with WithImplicitTx: that option runs every statement in its own primary transaction, so a Replica handle could never use the replica, and failing is clearer than silently reading the primary. A read on the replica runs outside any transaction, so WithTxSetup does not apply to it; do not rely on a setting that WithTxSetup installs (for example a row-level-security tenant) for replica reads.
func (*DB) Tx ¶
Tx runs fn in a transaction. It commits if fn returns nil and rolls back if fn returns an error or panics. A panic is re-raised after the rollback completes (the rollback uses a context detached from ctx's cancellation so it still reaches the database). fn is called exactly once: Momo never retries it.
type DeleteQuery ¶
type DeleteQuery[T any] struct { // contains filtered or unexported fields }
DeleteQuery builds a DELETE of one model table. It is a value: every method returns a copy, so a base query can be reused safely.
A statement without an effective WHERE clause is refused with ErrUnfilteredMutation unless AllRows confirms it. An empty And or Or is not an effective filter.
func Delete ¶
func Delete[T any, PT Modeler[T]](q Querier) DeleteQuery[T]
Delete starts a DELETE from T's table.
func ForceDelete ¶
func ForceDelete[T any, PT Modeler[T]](q Querier) DeleteQuery[T]
ForceDelete is the hard delete for soft-deleting models. It removes rows whether or not they are soft-deleted, and bypasses the refusal a plain Delete gives on such models. The mutation guard still applies.
func (DeleteQuery[T]) AllRows ¶
func (d DeleteQuery[T]) AllRows() DeleteQuery[T]
AllRows confirms that a DELETE without WHERE is intended.
func (DeleteQuery[T]) AppendSQL ¶ added in v0.5.0
func (d DeleteQuery[T]) AppendSQL(b *Builder)
AppendSQL renders the statement in parentheses as a WITH clause body. It runs the handle's interceptors with a background context, as SQL does, but not the beforeWrite checks of Exec. Only PostgreSQL accepts the result.
func (DeleteQuery[T]) Exec ¶
func (d DeleteQuery[T]) Exec(ctx context.Context) (Result, error)
Exec runs the DELETE.
func (DeleteQuery[T]) Model ¶
func (d DeleteQuery[T]) Model(m *T) DeleteQuery[T]
Model deletes the row identified by m's primary key. The version column of a versioned model is not checked: unlike a Model update, Model delete removes the row whatever version m carries. Add a Where on the version column for a version-checked delete.
func (DeleteQuery[T]) Returning ¶
func (d DeleteQuery[T]) Returning(cols ...ColumnRef) DeleteQuery[T]
Returning appends a RETURNING list; read the rows with Rows.
func (DeleteQuery[T]) ReturningAll ¶
func (d DeleteQuery[T]) ReturningAll() DeleteQuery[T]
ReturningAll returns every column mapped by T, in metadata order.
func (DeleteQuery[T]) Rows ¶
func (d DeleteQuery[T]) Rows(ctx context.Context) (*ModelRows[T], error)
Rows runs the DELETE and returns its RETURNING rows. It fails with ErrValidation when no Returning list was set.
func (DeleteQuery[T]) SQL ¶
func (d DeleteQuery[T]) SQL() (Compiled, error)
SQL renders the statement without executing it. Guardrail violations are reported here, before anything can reach the database.
Interceptors run with a background context here; the execution methods pass the statement's own context.
func (DeleteQuery[T]) Using ¶ added in v0.5.0
func (d DeleteQuery[T]) Using(src TableSource) DeleteQuery[T]
Using adds a second source, rendering DELETE FROM t USING src WHERE ...: the WHERE may reference src's columns. src is a table, aliased table, CTE or FromSubquery, as in a join; join it to the target in Where. Calling Using again replaces the source.
PostgreSQL renders DELETE ... USING. MySQL and MariaDB render the multi-table form DELETE t FROM t, src WHERE .... SQLite has no such form and fails with ErrUnsupported (use a subquery in Where). Soft-deleted rows of src are not filtered: add that predicate to Where. Interceptors apply to the target table only, not to src.
With a Using source the unfiltered-mutation guard is stricter: at least one Where predicate must reference a column of the target table, otherwise the statement joins every target row to src and fails with ErrUnfilteredMutation unless AllRows confirms it. A raw SQL fragment does not count as such a reference.
func (DeleteQuery[T]) Where ¶
func (d DeleteQuery[T]) Where(ps ...Predicate) DeleteQuery[T]
Where adds predicates combined with AND.
func (DeleteQuery[T]) With ¶ added in v0.5.0
func (d DeleteQuery[T]) With(name string, q Subquery, cols ...string) DeleteQuery[T]
With prefixes the statement with a common table expression; see UpdateQuery.With for the allowed bodies and the dialect rules (MariaDB refuses the clause with ErrUnsupported).
func (DeleteQuery[T]) WithRecursive ¶ added in v0.5.0
func (d DeleteQuery[T]) WithRecursive(name string, q Subquery, cols ...string) DeleteQuery[T]
WithRecursive is With for a recursive CTE.
type DialectValuer ¶
DialectValuer is implemented by values whose wire encoding depends on the dialect, such as vectors (pgvector text vs. sqlite-vec float32 blobs).
type Direction ¶
type Direction uint8
Direction orders by relation count. DirAsc and DirDesc avoid the names Asc(e Expr) and Desc(e Expr) already used in expr.go.
type Discarder ¶
type Discarder interface {
Discard() error
}
Discarder is implemented by pinned connections that can be thrown away instead of returned to the pool. Discard closes the underlying connection and then releases it, so the pool destroys it and no session state (advisory locks, SET values, an open transaction) can reach the next user. Like Release it closes open Rows first, returns an error matching ErrPinnedBusy while a Query, Exec or Begin call is executing (leaving the connection pinned), and returns nil after a successful Release or Discard. Callers that cannot restore a session (for example a failed unlock or RESET) type-assert a PinnedConn to Discarder and call it.
type Discriminator ¶
Discriminator restricts a polymorphic has-one/has-many to rows whose type column equals Value.
type Driver ¶
type Driver interface {
Dialect() *dialect.Dialect
Query(ctx context.Context, sql string, args []any) (Rows, error)
Exec(ctx context.Context, sql string, args []any) (int64, error)
Begin(ctx context.Context, opts TxOptions) (DriverTx, error)
}
Driver is the connection-adapter contract. Adapters live in github.com/azrtydxb/momo/driver/... (pgx native, database/sql). The adapter owns the connection pool; Momo never opens or closes connections on its own.
type DriverTx ¶
type DriverTx interface {
Query(ctx context.Context, sql string, args []any) (Rows, error)
Exec(ctx context.Context, sql string, args []any) (int64, error)
Commit(ctx context.Context) error
Rollback(ctx context.Context) error
}
DriverTx is a driver-level transaction.
type Error ¶
type Error struct {
Kind error // one of the Err* sentinels
Op string // "select", "insert", "update", "delete", "exec", "build", ...
Table string // when known
Column string // when known
Constraint string // when known
Err error // underlying (often driver) error; may be nil
// contains filtered or unexported fields
}
Error is a structured Momo error.
func (*Error) Detail ¶
Detail returns the raw driver detail captured by the classifier (it can quote row values, so handle it as sensitive). Without a captured detail it falls back to the underlying error text, or "" when there is none.
func (*Error) Error ¶
Error returns the kind, the operation and its identifying fields, followed by the text of the wrapped error. It never renders the raw driver detail, which can quote row values.
type ErrorClassifier ¶
ErrorClassifier converts a raw driver error into a structured *Error when it recognizes it, and returns err unchanged otherwise. Drivers implement it; the root package stays free of driver imports.
type ExcludedExpr ¶ added in v0.3.0
type ExcludedExpr[T any] struct { // contains filtered or unexported fields }
ExcludedExpr is the EXCLUDED.<col> reference returned by Column.Excluded. Besides being an Expression[T], it carries value comparisons for CASE and DO UPDATE WHERE predicates, for example hostname.Excluded().Ne("").
func (ExcludedExpr[T]) AppendSQL ¶ added in v0.3.0
func (e ExcludedExpr[T]) AppendSQL(b *Builder)
AppendSQL writes the EXCLUDED column reference to b.
type Expr ¶
type Expr interface {
AppendSQL(b *Builder)
}
Expr is any SQL expression fragment. Implementations must write identifiers through Builder.Ident and values through Builder.Arg.
type ExprSelect ¶ added in v0.3.0
type ExprSelect struct {
// contains filtered or unexported fields
}
ExprSelect is a SELECT of explicit expressions that needs no result type: a FROM-less list of values or parameters with an optional WHERE, or a plain SELECT over one source. It is a Subquery, so it is the row source of InsertQuery.FromSelect and also works as an EXISTS operand:
momo.SelectExprs(momo.Value(1)).From(meters).Where(meter.Legacy.Eq(true))
ExprSelect is an immutable value: every method returns a new one.
func SelectExprs ¶ added in v0.3.0
func SelectExprs(cols ...Expr) ExprSelect
SelectExprs starts a SELECT of the given expressions with no FROM clause. Add a source with From and conditions with Where. Pass every literal as a momo.Value so it is bound as a parameter and nothing is concatenated into the SQL text.
func (ExprSelect) AppendSQL ¶ added in v0.3.0
func (s ExprSelect) AppendSQL(b *Builder)
AppendSQL renders the select in parentheses, for use as a subquery.
func (ExprSelect) From ¶ added in v0.3.0
func (s ExprSelect) From(src TableSource) ExprSelect
From sets the FROM source. Without it the SELECT has no FROM clause, which PostgreSQL and SQLite accept and MySQL accepts only as FROM DUAL (added automatically when a WHERE is present). The soft-delete filter is added only when src is a TableRef whose SoftDelete marker is set: generated Table refs carry it, a hand-built TableRef{Name: ...} does not and then counts soft-deleted rows, so set SoftDelete and SoftDeleteKind on it.
func (ExprSelect) Where ¶ added in v0.3.0
func (s ExprSelect) Where(ps ...Predicate) ExprSelect
Where adds predicates combined with AND. On a FROM-less select the WHERE guards the single row, so the select yields zero rows when it is false.
type Expression ¶
Expression is an Expr whose SQL result type corresponds to the Go type T. The type parameter lets the compiler reject comparisons between incompatible operands, e.g. an int64 column against a string.
func Coalesce ¶
func Coalesce[T any](e Expression[T], fallback T) Expression[T]
Coalesce returns the first non-NULL argument.
func JoinTypedSQL ¶ added in v0.4.0
func JoinTypedSQL[T any](sep string, parts ...Expr) Expression[T]
JoinTypedSQL is JoinSQL with a declared result type, for a join used in a projection or a typed comparison, for example a "+" sum of columns. Momo cannot verify that the declaration is truthful.
func Typed ¶ added in v0.4.0
func Typed[T any](e Expr) Expression[T]
Typed wraps e as an Expression[T], for an expression whose SQL is built elsewhere and whose result type the caller knows. It does not change the SQL e renders and adds no comparison methods; embed Ops[T] in your own type for those. Typed is an extension point: e must write identifiers through Builder.Ident and values through Builder.Arg.
func TypedSQL ¶
func TypedSQL[T any](sql string, args ...any) Expression[T]
TypedSQL is SQL with a declared result type, for use in projections and typed comparisons. Momo cannot verify that the declaration is truthful.
func Value ¶
func Value[T any](v T) Expression[T]
Value wraps a Go value as a typed bound parameter.
type FieldHook ¶
type FieldHook[T any] struct { // Column is the index into Meta.Columns. Column int // Default supplies the value of the column when a write omits it: a // Values or ValuesRows row that does not assign the column (an explicit // SetDefault, SetNull or zero value counts as assigned and wins), or a // Model insert that lists the column in Omit. It never replaces a zero // value, because a Model insert writes every column it does not omit. For // Values and ValuesRows rows there is no model, so m points to a zero T. Default func(m *T) any // OnUpdate supplies the value of the column on every update statement // that does not assign the column itself with Set; an explicit Set wins. // For a Model update m is the model, otherwise a zero T. It overrides the // value Model would write from the struct. OnUpdate func(m *T) any // Validate checks the value the statement will write for the column and // runs before SQL is built. v is the Go value bound for the column; it is // nil when the statement writes NULL or DEFAULT, or (insert only) omits // the column without a Default, so a required-field validator should // reject nil. A SQL expression assignment is not validated, and an // update validates only the columns it sets. A non-nil error becomes // *Error{Kind: ErrValidation, Op, Table, Column} wrapping it. Validate func(v any) error }
FieldHook attaches Go-side behavior to one column of Meta[T].
Hooks are declared in Meta.Fields (generated or hand-written) or per DB with WithFieldHooks. Write builders run them before the statement is built, in this order: Default (insert), OnUpdate (update), Validate. A failing validator makes SQL, Exec and Rows return an *Error of kind ErrValidation before anything reaches the database.
A hook for a column the statement cannot write is handled per statement:
- Insert: Default is ignored for a column that is not assignable on INSERT (identity or read-only; see columnAssignable with writeInsert).
- Update: OnUpdate is refused with ErrValidation for the key, version, soft-delete, created-at and updated-at columns (updated_at is already maintained automatically; see WithClock) and for a column that is not assignable on UPDATE (identity, read-only, create-only or immutable).
OnUpdate is not a trigger: it adds a value to an update that already sets something. An update with only OnUpdate hooks and no Set still fails with "no columns to update".
A Default or OnUpdate function runs once per row and statement: a chunked bulk insert computes and validates every value before the first chunk and binds those same values, so a random default is safe.
type Filter ¶ added in v0.4.0
Filter is a runtime-built predicate tree, for filters that arrive from outside the program (a query string, an API body). Exactly one of And, Or, Not or Field must be set on each node. Field is an external name resolved through an Allowlist; it never becomes SQL text itself. Op is one of eq, ne, lt, le, gt, ge, in, null, notnull and like; Value is bound as a parameter (null and notnull ignore it, in takes a slice, like takes a string pattern already escaped with EscapeLike).
type FilteredAgg ¶ added in v0.4.0
type FilteredAgg[T any] struct { // contains filtered or unexported fields }
FilteredAgg is an aggregate with a FILTER (WHERE ...) clause, built with Agg.Filter. It is an Expression[T], carries the comparison methods HAVING needs, and can be turned into a window function with Over.
func (FilteredAgg[T]) AppendSQL ¶ added in v0.4.0
func (f FilteredAgg[T]) AppendSQL(b *Builder)
AppendSQL writes the aggregate and its FILTER clause to b.
func (FilteredAgg[T]) As ¶ added in v0.4.0
func (f FilteredAgg[T]) As(alias string) Aliased[T]
As names the aggregate in a select list.
func (FilteredAgg[T]) Over ¶ added in v0.4.0
func (f FilteredAgg[T]) Over(w WindowSpec) WindowExpr[T]
Over turns the filtered aggregate into a window function.
type Flagged ¶ added in v0.4.0
type Flagged interface{ Flags() uint16 }
Flagged is implemented by column descriptors, whose flags decide masking. A custom expression that wraps a column implements it by returning FlagsOf of the wrapped expression, so a sensitive column stays masked through the wrapper. Flagged is an extension point; see Ops.
type ForeignKeyOpts ¶ added in v0.5.0
type ForeignKeyOpts struct{}
ForeignKeyOpts carries the optional referential actions of a foreign key declaration. Its methods are read statically by the generator and are no-ops at runtime.
func (*ForeignKeyOpts) OnDelete ¶ added in v0.5.0
func (o *ForeignKeyOpts) OnDelete(action string) *ForeignKeyOpts
OnDelete sets the ON DELETE action of a foreign key ("CASCADE", "RESTRICT", "SET NULL", "SET DEFAULT" or "NO ACTION"). Read statically; no-op at runtime.
func (*ForeignKeyOpts) OnUpdate ¶ added in v0.5.0
func (o *ForeignKeyOpts) OnUpdate(action string) *ForeignKeyOpts
OnUpdate sets the ON UPDATE action of a foreign key, with the same values as OnDelete. Read statically; no-op at runtime.
type FrameBound ¶ added in v0.4.0
type FrameBound struct {
// contains filtered or unexported fields
}
FrameBound is one end of a window frame.
func Following ¶ added in v0.4.0
func Following(n int) FrameBound
Following is n FOLLOWING. n must not be negative.
func Preceding ¶ added in v0.4.0
func Preceding(n int) FrameBound
Preceding is n PRECEDING. n must not be negative.
func UnboundedFollowing ¶ added in v0.4.0
func UnboundedFollowing() FrameBound
UnboundedFollowing is UNBOUNDED FOLLOWING (an end bound).
func UnboundedPreceding ¶ added in v0.4.0
func UnboundedPreceding() FrameBound
UnboundedPreceding is UNBOUNDED PRECEDING (a start bound).
type FuncExpr ¶ added in v0.3.0
type FuncExpr[T any] struct { // contains filtered or unexported fields }
FuncExpr is a function call whose SQL result type corresponds to T. It is an Expression[T] and can be aliased with As.
func Func ¶ added in v0.3.0
Func is a typed call of the SQL function name. name must be a plain identifier, optionally schema-qualified (lower, pg_catalog.lower); anything else fails the build with ErrValidation, so a name cannot smuggle SQL. An argument that is an Expr (a column, another call, Value, ...) renders inline; any other Go value is bound as a parameter. Momo cannot verify that T is what the function returns.
type Hook ¶
type Hook interface {
BeforeQuery(ctx context.Context, e *QueryEvent) context.Context
AfterQuery(ctx context.Context, e *QueryEvent)
}
Hook observes statements. BeforeQuery may return a derived context (for tracing spans); AfterQuery receives that context. Hooks run synchronously on the calling goroutine and must be safe for concurrent use.
func NewNPlusOneHook ¶ added in v0.4.0
func NewNPlusOneHook(threshold int, report func(NPlusOneFinding)) Hook
NewNPlusOneHook returns a development hook that calls report once per statement shape per scope when the shape has run more than threshold times (a threshold below 1 counts as 1). Transaction control and EXPLAIN statements are ignored. A scope tracks at most 1024 distinct shapes; later new shapes in the same scope are not counted. report runs synchronously on the querying goroutine and must not query the database; a panic in report is recovered and dropped.
type HookSet ¶ added in v0.4.0
type HookSet[T any] struct { BeforeInsert func(ctx context.Context, m *T) error BeforeUpdate func(ctx context.Context, m *T) error BeforeDelete func(ctx context.Context, m *T) error AfterLoad func(ctx context.Context, m *T) error }
HookSet holds the typed model hooks of Meta[T]. Generated code or hand-written metadata sets the fields; the builders call them with the statement's context.
A hook runs only for the builder kind it names and only when it is set:
- BeforeInsert runs for each model of an Insert (Model, Models, Upsert) before id generators run and before the statement is built, so it sees a zero id and an id it sets is not written back to the caller. It does not run for Values, ValuesRows or FromSelect inserts, which have no model. The hook receives a copy of the model, so it may change the values that are written without touching the caller's value.
- BeforeUpdate runs for a Model update, on the caller's model.
- BeforeDelete runs for a Model delete and a Model SoftDelete, on the caller's model.
- AfterLoad runs for every model returned by All, One, First, Each and Iter, and for every model a write scans from its RETURNING rows (ModelRows.ScanModel), after the row is scanned.
momo generate fills the hooks from the model's own methods: a method named BeforeInsert, BeforeUpdate, BeforeDelete or AfterLoad with the signature func(context.Context) error becomes the hook of that name, with the model as its receiver. A method with a hook name and another signature is a generator diagnostic, and a model without such methods keeps the zero HookSet.
Set the hooks on the metadata value that MomoMeta returns, for example in the declaration of the package-level Meta:
var documentMeta = momo.Meta[Document]{ /* ... */ Hooks: momo.HookSet[Document]{
BeforeInsert: func(ctx context.Context, d *Document) error { /* ... */ return nil },
}}
Generated metadata is not edited by hand; assign the field once at start-up before any statement runs. Momo never mutates a Meta, so concurrent reads are safe once it is set.
Interceptors run before the Before hooks, so a statement an interceptor denies never reaches them. A Before hook can still change the caller's model (BeforeUpdate, BeforeDelete) when the statement then fails to build or run, for example on the unfiltered-mutation guard or a database error.
A returned error aborts the statement before any SQL runs (a Before hook) or ends the read (AfterLoad); it is wrapped in an *Error of kind ErrValidation that still reaches the hook's own error with errors.Is. A hook may set values through the *T pointer but cannot change the SQL. Hooks run on the execution methods (Exec, Rows, All and so on); SQL does not run them. The hook dispatch itself performs no reflection and allocates nothing (TestModelHookDispatchAllocations measures runModelHook and the AfterLoad wrapper); the builders around it do allocate, and a hook that allocates is the caller's cost.
Relations loaded with Load or Preload and joined relations are scanned by the relation machinery and do not run the AfterLoad hook of the related type.
type HybridQuery ¶ added in v0.5.0
type HybridQuery[T any] struct { // contains filtered or unexported fields }
HybridQuery is a prepared hybrid search; see HybridSearch.
func HybridSearch ¶ added in v0.5.0
func HybridSearch[T any, PT Modeler[T]](q Querier, spec HybridSpec) HybridQuery[T]
HybridSearch builds the fused full-text and vector query for model T. It runs on PostgreSQL with pgvector only; on another dialect SQL and All return an error that wraps ErrUnsupported. The model needs a single-column primary key. Soft-deleted rows are excluded.
The statement binds, in order: the text configuration, the query text, the text candidate count, the query vector, the vector candidate count, the RRF constant and the limit.
func (HybridQuery[T]) All ¶ added in v0.5.0
func (h HybridQuery[T]) All(ctx context.Context) ([]HybridResult[T], error)
All runs the query and returns the fused rows, best first.
func (HybridQuery[T]) SQL ¶ added in v0.5.0
func (h HybridQuery[T]) SQL() (Compiled, error)
SQL compiles the statement without running it. The result has the seven bound arguments described at HybridSearch.
type HybridResult ¶ added in v0.5.0
type HybridResult[T any] struct { Row T // Score is the sum of 1/(RRFK+rank) over the legs the row appears in. Score float64 }
HybridResult is one fused row.
type HybridSpec ¶ added in v0.5.0
type HybridSpec struct {
// Text is the full-text column of the model, a text column of the same
// table as Vector.
Text Column[string]
TextConfig string // regconfig name such as "english"; bound as a parameter
Query string // websearch_to_tsquery input
Vector VectorColumn[vector.Vector]
// QueryVector must match the column's dimension (any dimension for a
// dimensionless column).
QueryVector vector.Vector
// TextCandidates and VectorCandidates are the candidates each leg
// contributes, 1..1000; zero means DefaultHybridCandidates (100).
TextCandidates int
VectorCandidates int
// RRFK is the RRF rank constant, at least 1; zero means DefaultHybridRRFK (60).
RRFK int
// Limit is the number of rows returned, 1..1000.
Limit int
}
HybridSpec describes a PostgreSQL hybrid search: a full-text leg and a vector leg over one model, fused by reciprocal rank fusion (RRF).
Each leg picks its own candidates (the best TextCandidates rows by ts_rank_cd, and the nearest VectorCandidates rows by cosine distance), ranks them, and a row scores the sum of 1/(RRFK+rank) over the legs it appears in. Ties on the score are broken by primary key ascending, within each leg's ranking and in the final order, so the result does not depend on row or insertion order. The one exception is the candidate cut-off: the vector leg orders by distance alone (so an hnsw or ivfflat index can serve it), and when rows tie on distance at the cut-off, which of them become candidates is not defined.
The vector leg takes the dense vector type only (not halfvec, sparsevec or bit) and skips rows with a NULL embedding and rows whose cosine distance is NaN (a zero vector). The text leg computes to_tsvector over the column with the bound TextConfig; a GIN expression index needs a constant configuration in its definition, and a bound regconfig parameter may not match it, so without a matching plan the text leg scans the table.
type IDGen ¶ added in v0.4.0
type IDGen struct {
// Column is the index into Meta.Columns.
Column int
// Name is the generator name.
Name string
}
IDGen declares a Go-side id generator for one column of a model: the generated code sets it from the idgen tag or the IDGen companion call. Name is a built-in generator (cuid, uuid, ulid) or one registered with WithIDGenerator.
type ImmutableColumn ¶
type ImmutableColumn[T any] struct { // contains filtered or unexported fields }
ImmutableColumn is the descriptor of a column that is set on insert and never changed. Its Set returns an InsertAssignment, which Update.Set does not accept.
func NewImmutableColumn ¶
func NewImmutableColumn[T any](table, name string, flags uint16) ImmutableColumn[T]
NewImmutableColumn is used by generated code.
func (ImmutableColumn[T]) As ¶
func (c ImmutableColumn[T]) As(alias string) ImmutableColumn[T]
As returns the same column qualified by a table alias.
func (ImmutableColumn) AsExpr ¶
func (c ImmutableColumn) AsExpr() Expression[T]
AsExpr returns the column as an Expression[T], so a projection list reads explicitly: DocTitle.As("l").AsExpr().
func (ImmutableColumn) Asc ¶
func (c ImmutableColumn) Asc() Order
Asc orders by the column ascending. The order item is the column itself, a ColumnRef, so keyset pagination recognizes a primary-key column.
func (ImmutableColumn) ColumnName ¶
func (c ImmutableColumn) ColumnName() string
ColumnName returns the unquoted column name.
func (ImmutableColumn) Desc ¶
func (c ImmutableColumn) Desc() Order
Desc orders by the column descending.
func (ImmutableColumn[T]) Excluded ¶ added in v0.2.0
func (c ImmutableColumn[T]) Excluded() Expression[T]
Excluded is the value proposed for insertion, for an upsert condition.
func (ImmutableColumn) Flags ¶
func (c ImmutableColumn) Flags() uint16
Flags returns the generated column flags.
func (ImmutableColumn) ParseCmp ¶ added in v0.4.0
ParseCmp parses raw with the column's Go type and returns the comparison predicate for op, one of eq, ne, lt, le, gt and ge. An unknown op or a value that does not parse is an *Error with Kind ErrValidation. It is meant for a filter value that arrives as text from outside; the column comes from the generated ColumnByName allowlist.
func (ImmutableColumn) ParseEq ¶ added in v0.4.0
ParseEq parses raw with the column's Go type and returns the equality predicate on it. A value that does not parse is an *Error with Kind ErrValidation; the error does not echo raw, which may be attacker controlled.
func (ImmutableColumn[T]) Set ¶
func (c ImmutableColumn[T]) Set(v T) InsertAssignment
Set assigns v on insert. The result is an InsertAssignment, which only Insert accepts.
type ImmutableVectorColumn ¶
type ImmutableVectorColumn[V VectorValue] struct { // contains filtered or unexported fields }
ImmutableVectorColumn is a vector column set on insert and never changed. Its Set returns an InsertAssignment, which Update.Set does not accept.
func NewImmutableVectorColumn ¶
func NewImmutableVectorColumn[V VectorValue](table, name string, dim int, flags uint16) ImmutableVectorColumn[V]
NewImmutableVectorColumn is used by generated code.
func (ImmutableVectorColumn) AppendSQL ¶
func (c ImmutableVectorColumn) AppendSQL(b *Builder)
AppendSQL renders the qualified, quoted column.
func (ImmutableVectorColumn[V]) As ¶
func (c ImmutableVectorColumn[V]) As(alias string) ImmutableVectorColumn[V]
As returns the same column qualified by a table alias.
func (ImmutableVectorColumn) AsExpr ¶
func (c ImmutableVectorColumn) AsExpr() Expression[V]
AsExpr returns the column as an Expression[V].
func (ImmutableVectorColumn) ColumnName ¶
func (c ImmutableVectorColumn) ColumnName() string
ColumnName returns the unquoted column name.
func (ImmutableVectorColumn) Dim ¶
func (c ImmutableVectorColumn) Dim() int
Dim returns the declared dimension. Zero marks a dimensionless column: a distance argument of any size is accepted and checked against itself.
func (ImmutableVectorColumn) EqExpr ¶
func (c ImmutableVectorColumn) EqExpr(e Expression[V]) Predicate
func (ImmutableVectorColumn) Flags ¶
func (c ImmutableVectorColumn) Flags() uint16
Flags returns the generated column flags.
func (ImmutableVectorColumn) IsDistinctFrom ¶
func (c ImmutableVectorColumn) IsDistinctFrom(v V) Predicate
IsDistinctFrom is a NULL-safe inequality.
func (ImmutableVectorColumn) IsNotDistinctFrom ¶
func (c ImmutableVectorColumn) IsNotDistinctFrom(v V) Predicate
IsNotDistinctFrom is a NULL-safe equality.
func (ImmutableVectorColumn) IsNotNull ¶
func (c ImmutableVectorColumn) IsNotNull() Predicate
IsNotNull is true when the column holds a value.
func (ImmutableVectorColumn) IsNull ¶
func (c ImmutableVectorColumn) IsNull() Predicate
IsNull is true when the column holds SQL NULL.
func (ImmutableVectorColumn) NeExpr ¶
func (c ImmutableVectorColumn) NeExpr(e Expression[V]) Predicate
func (ImmutableVectorColumn) NotInQuery ¶
func (ImmutableVectorColumn) ParseCmp ¶ added in v0.4.0
ParseCmp always fails: a vector has no text form to filter by.
func (ImmutableVectorColumn) ParseEq ¶ added in v0.4.0
ParseEq always fails: a vector has no text form to filter by.
func (ImmutableVectorColumn[V]) Set ¶
func (c ImmutableVectorColumn[V]) Set(v V) InsertAssignment
Set assigns v on insert; only Insert accepts the result.
type IndexOpts ¶
type IndexOpts struct{}
IndexOpts carries the optional parts of an index declaration. Its methods are read statically by the generator and are no-ops at runtime.
func (*IndexOpts) Concurrently ¶
Concurrently marks the index to be built concurrently. Read statically; no-op at runtime.
func (*IndexOpts) Desc ¶
Desc marks one indexed field descending. Read statically; no-op at runtime.
func (*IndexOpts) Nulls ¶
Nulls sets NULLS ordering ("first" or "last") for one indexed field. Read statically; no-op at runtime.
func (*IndexOpts) Opclass ¶
Opclass sets the operator class of one indexed field. Read statically; no-op at runtime.
func (*IndexOpts) Unique ¶ added in v0.5.0
Unique makes the index a unique index. Read statically; no-op at runtime.
type InsertAssignment ¶
type InsertAssignment struct {
// contains filtered or unexported fields
}
InsertAssignment is one explicit column write that is valid in an INSERT only. Create-only and immutable columns produce it from Set; it is not an Assignment, so Update.Set rejects it at compile time. Raw SQL is outside this guarantee.
func (InsertAssignment) ColumnName ¶
func (a InsertAssignment) ColumnName() string
ColumnName returns the assigned column.
type InsertIDExecer ¶ added in v0.4.0
type InsertIDExecer interface {
ExecInsertID(ctx context.Context, sql string, args []any) (rows, lastInsertID int64, err error)
}
InsertIDExecer is implemented by drivers, transactions and pinned connections that report the auto-increment key of an INSERT (MySQL and MariaDB LAST_INSERT_ID). The key is meaningful for a single-row insert only.
type InsertQuery ¶
type InsertQuery[T any] struct { // contains filtered or unexported fields }
InsertQuery builds and runs an INSERT into T's table.
Columns come from T's generated metadata only, so no caller-supplied string becomes an identifier. Identity columns and FlagReadOnly columns are never written, and values are always bound. InsertQuery is an immutable value: every method returns a new query.
func Insert ¶
func Insert[T any, PT Modeler[T]](q Querier) InsertQuery[T]
Insert starts an INSERT for model T. Use Model or Models to write whole models, or Values to write explicit columns.
func Upsert ¶
func Upsert[T any, PT Modeler[T]](q Querier) InsertQuery[T]
Upsert starts an INSERT ... ON CONFLICT DO UPDATE for model T. Unless the caller chooses otherwise with OnConflict, the conflict target is T's primary key, and DoUpdate (when not given, or given without assignments) assigns every written column that an update may change with SetExcluded. The primary key, version, soft-delete and created-at columns are never part of DO UPDATE SET, and an explicit assignment to one (or to updated-at) is refused with ErrValidation. When the model has an updated-at column, DO UPDATE SET always ends with updated_at = EXCLUDED.updated_at, also after an explicit DoUpdate list, so a conflict refreshes the timestamp just as Update does; created_at is never overwritten.
The version column is neither advanced nor checked on conflict: an upsert overwrites the existing row without optimistic-lock detection. Explicit identity values inserted with OVERRIDING SYSTEM VALUE do not advance the PostgreSQL identity sequence, and explicit serial ids do not advance the serial sequence either, so later generated keys may collide with them; the caller must setval the sequence. FromSelect cannot supply serial ids at all.
When the conflict target is the primary key and every model carries a non-zero identity value, the identity column joins the INSERT column list (PostgreSQL renders OVERRIDING SYSTEM VALUE), so the statement can hit an existing row. A model whose identity is zero is inserted with a generated identity. Mixing both in one Models call is refused with ErrValidation. Dialects without ON CONFLICT (MySQL) fail with ErrUnsupported.
func (InsertQuery[T]) AppendSQL ¶ added in v0.5.0
func (q InsertQuery[T]) AppendSQL(b *Builder)
AppendSQL renders the statement in parentheses as a WITH clause body, as SQL would, without running interceptors or the BeforeInsert hook. Only PostgreSQL accepts the result.
func (InsertQuery[T]) Copy ¶ added in v0.4.0
func (q InsertQuery[T]) Copy(ctx context.Context, ms []T) (Result, error)
Copy streams ms through the driver's Copier (PostgreSQL COPY) and reports the rows written. It writes the same columns as a model insert (Omit applies, identity and read-only columns are never written, an unset created-at or updated-at field takes the statement time, Go-side defaults and field validators run) but binds no parameters, so there is no parameter limit and no chunking: one COPY is one atomic statement.
Copy returns ErrUnsupported when the driver has no COPY path (SQLite, and PostgreSQL through FromSQLDB). Model, Models, Values, ValuesRows, FromSelect, Returning, OnConflict and Upsert cannot be combined with it (ErrValidation): COPY has no conflict handling and returns no rows.
Copy respects WithTxSetup. On a DB made with WithImplicitTx it runs inside its own short transaction, so the setup functions run before the COPY. On a DB pinned with OnConn that has WithTxSetup it fails closed with ErrUnsupported, because the setup could not run. On a Tx it uses the transaction's own COPY path. Query hooks see one event with Op "copy" and no arguments, so no value reaches a hook.
Copy runs the insert interceptors (they can deny it, but a predicate they add is ignored, as for any insert) and the BeforeInsert hook of the model over a copy of ms, so a hook that stamps a tenant applies to every row. It skips OnConflict handling, RETURNING and the chunking of Exec. It counts as a write for NewUnitOfWork, so later reads on a Replica handle in the same unit of work stay on the primary.
func (InsertQuery[T]) Exec ¶
func (q InsertQuery[T]) Exec(ctx context.Context) (Result, error)
Exec runs the statement and reports the rows it inserted.
A Models call whose rows would exceed the dialect's bind-parameter limit is split into several multi-row statements, run in order, and the rows affected are summed. The chunks are atomic: on a DB they run in one transaction, on a Tx inside a savepoint (when the dialect has them), so a failing chunk undoes the earlier ones. A Tx on a dialect without savepoints runs the chunks directly in the caller's transaction, which stays atomic as a whole. A DB pinned to one connection by OnConn cannot begin a transaction, so a chunked insert there fails with ErrUnsupported before any statement runs. A panic during a chunk rolls the scope back and is re-raised. All chunks share one clock read, so every row gets the same automatic timestamp. A single row with more bound columns than the limit fails with ErrLimitExceeded.
func (InsertQuery[T]) FromSelect ¶ added in v0.3.0
func (q InsertQuery[T]) FromSelect(sel Subquery, cols ...ColumnRef) InsertQuery[T]
FromSelect makes the rows of a SELECT the source of the INSERT, rendering INSERT INTO t (cols) SELECT ... in one atomic statement. cols are the typed target columns of T, in the order of the select list; the select must yield exactly that many columns, otherwise the build fails with ErrValidation (a RawSubquery or set operation has no known width, so the database checks it).
The select is the row source, for example a FROM-less select guarded by NOT EXISTS so the row is inserted only when none exists yet:
momo.Insert[Meter](db).
FromSelect(
momo.SelectExprs(momo.Value(p), momo.Value(id), momo.Value("distinct")).
Where(momo.NotExists(momo.SelectExprs(momo.Value(1)).From(meterTable).Where(meter.Product.Eq(p)))),
meter.Product, meter.ID, meter.Kind).
OnConflict(meter.Product, meter.ID).DoNothing().
Exec(ctx)
FromSelect composes with OnConflict (DoNothing, DoUpdate and their Where), with Returning, ReturningAll and Rows, and with Upsert[T], whose default DO UPDATE list then covers the listed columns only. The bind parameters of the select come first, then those of the ON CONFLICT part; each dialect numbers them in order. Exec reports the rows inserted (0 when the select yields no row or every row conflicts).
Only the listed columns are written. Nothing is injected: the automatic created-at and updated-at timestamps, Go-side defaults and field validators do not apply, so list those columns and select their values yourself. A column that is an identity, read-only, or otherwise not writable by INSERT is refused with ErrValidation, as are an unmapped or repeated column, an empty list, and combining FromSelect with Model, Models, Values, ValuesRows or Omit. Calling FromSelect again replaces the source. FromSelect runs no model hooks.
func (InsertQuery[T]) Model ¶
func (q InsertQuery[T]) Model(m *T) InsertQuery[T]
Model adds one model, writing every column except identity, read-only and omitted columns. Zero values are written, never skipped, except in a column tagged dbdefault: when that field holds its zero value (or a nil pointer) the column is left out of the INSERT so the database default applies, and Exec reads the stored value back into the model with RETURNING. See Models for several rows and the dialects that cannot do this.
func (InsertQuery[T]) Models ¶
func (q InsertQuery[T]) Models(ms []T) InsertQuery[T]
Models adds every element of ms as one row of a multi-row VALUES list. With an empty list the query fails with ErrValidation.
A dbdefault column that is zero in every row leaves the column list; when some rows set it and others do not, the unset rows write DEFAULT. SQLite and Unnest cannot put DEFAULT in a row and fail with ErrUnsupported for such a mix; MySQL has no RETURNING to read the value back and fails with ErrUnsupported when a dbdefault column is zero. Exec writes the stored values of the unset rows back into the caller's elements after the statement committed. A single Model that a conflict action skips reports 0 rows affected and stays unchanged. A bulk insert that returns fewer rows than models is matched by key (conflict target, else primary key) when the key is written from the model and not a zero dbdefault column; unmatched models stay untouched, and Exec fails only when DoNothing left a dbdefault column unread. Without a usable key a short result fails with ErrUnsupported and writes nothing back; the insert is rolled back (to a savepoint inside a Tx; a pinned OnConn handle keeps the rows and says so). A caller's own Returning list turns the automatic read-back off: Rows returns the columns it names.
func (InsertQuery[T]) Omit ¶
func (q InsertQuery[T]) Omit(cols ...ColumnRef) InsertQuery[T]
Omit excludes columns from a model insert, leaving their database default. Combined with Values or ValuesRows the query fails with ErrValidation: those already list exactly the columns they write.
func (InsertQuery[T]) OnConflict ¶
func (q InsertQuery[T]) OnConflict(cols ...ColumnRef) ConflictQuery[T]
OnConflict starts an ON CONFLICT clause with the given conflict target. With no columns the target is omitted, which only DoNothing allows.
func (InsertQuery[T]) Returning ¶
func (q InsertQuery[T]) Returning(cols ...ColumnRef) InsertQuery[T]
Returning appends a RETURNING list; read the rows with Rows.
func (InsertQuery[T]) ReturningAll ¶
func (q InsertQuery[T]) ReturningAll() InsertQuery[T]
ReturningAll returns every column mapped by T, in metadata order.
func (InsertQuery[T]) Rows ¶
func (q InsertQuery[T]) Rows(ctx context.Context) (*ModelRows[T], error)
Rows runs the statement and returns its RETURNING rows. It fails with ErrValidation when no RETURNING list was set. A chunked bulk insert (see Exec) returns the rows of all chunks in insertion order. The first chunk runs inside Rows, so its errors are returned here; the remaining chunks run as the rows are consumed, and Close runs any that are left so the insert stays whole. The caller MUST check the error from Close (and Err): a later chunk can fail there, which rolls the whole insert back.
func (InsertQuery[T]) SQL ¶
func (q InsertQuery[T]) SQL() (Compiled, error)
SQL compiles the statement without executing it.
func (InsertQuery[T]) Unnest ¶ added in v0.4.0
func (q InsertQuery[T]) Unnest() InsertQuery[T]
Unnest switches a Model or Models insert to one statement that binds one array parameter per column. It is a method of InsertQuery and is not the package-level FROM source Unnest (see UnnestValues), which turns bound arrays into rows of a SELECT.
INSERT INTO t (c1, c2) SELECT * FROM unnest($1::bigint[], $2::text[])
The statement has as many bind parameters as the table has written columns, however many rows are inserted, so the bind-parameter limit does not split the insert into chunks. The column array types come from the table schema recorded in the generated metadata, so a model without a table schema fails with ErrValidation. Generated keys come back through RETURNING as for any insert. PostgreSQL only: other dialects fail with ErrUnsupported. Values and ValuesRows inserts are not supported, because their columns can differ per row.
Column values are bound as typed slices (int, float, bool, string, time.Time and []byte columns, as []*T when a value is NULL). An element type this does not know (uuid, json, decimal, a named enum) falls back to []any, which pgx may reject for the array type; use Models for such a model. OnConflict, Returning, hooks, interceptors, automatic timestamps and id generators work as for Models. A sensitive column's array is redacted in query events.
func (InsertQuery[T]) Values ¶
func (q InsertQuery[T]) Values(assigns ...InsertValue) InsertQuery[T]
Values adds one row of explicit column writes. A column that is not assigned is omitted from the statement, so its database default applies.
func (InsertQuery[T]) ValuesRows ¶
func (q InsertQuery[T]) ValuesRows(rows ...[]Assignment) InsertQuery[T]
ValuesRows adds one row per element to a multi-row VALUES list; each row is a list of assignments, like the argument of Values. The column list is the union of the columns the rows assign, in order of first appearance. A column a row does not assign takes its database default for that row (DEFAULT), and SetDefault renders DEFAULT inline. A dialect that cannot put DEFAULT inside VALUES (SQLite) omits a column that is default in every row and fails with ErrUnsupported when a column is default in some rows and given in others. ValuesRows cannot be combined with Values, Model, Models or Omit, and a statement over the dialect's bind-parameter limit fails with ErrLimitExceeded (DEFAULT and NULL bind no parameter).
func (InsertQuery[T]) Where ¶ added in v0.2.0
func (q InsertQuery[T]) Where(preds ...Predicate) InsertQuery[T]
Where adds a condition to the DO UPDATE action: the existing row is updated only when the predicates hold, rendered as DO UPDATE SET ... WHERE <preds>. When they do not, the conflicting row is left untouched and the statement affects 0 rows (with Returning, no row comes back). Several calls AND together.
Columns are qualified by the table name, so they mean the existing row; use Column.Excluded for the value proposed for insertion, for example until.LtExpr(until.Excluded()). It is valid only when the conflict action is DoUpdate, including Upsert[T], whose default update set is kept; after DoNothing, or without any conflict clause, the build fails with ErrValidation. MySQL fails with ErrUnsupported.
func (InsertQuery[T]) With ¶ added in v0.5.0
func (q InsertQuery[T]) With(name string, body Subquery, cols ...string) InsertQuery[T]
With prefixes the INSERT with a common table expression that FromSelect's select can read: WITH x AS (...) INSERT INTO t (cols) SELECT ... FROM x. cols optionally names the CTE's columns. The body may be a SelectQuery, an ExprSelect, a Union or (PostgreSQL only) another INSERT, UPDATE or DELETE with RETURNING; a data-modifying body on another dialect fails with ErrUnsupported. MySQL and MariaDB do not accept WITH before INSERT and fail with ErrUnsupported; put the WITH inside the select there. A WITH clause cannot be combined with a bulk insert that is split into chunks at the parameter limit (ErrValidation), since it would run once per chunk.
func (InsertQuery[T]) WithRecursive ¶ added in v0.5.0
func (q InsertQuery[T]) WithRecursive(name string, body Subquery, cols ...string) InsertQuery[T]
WithRecursive is With for a recursive CTE.
type InsertValue ¶
type InsertValue interface {
// contains filtered or unexported methods
}
InsertValue is an explicit column write accepted by Insert.Values: an Assignment, or an InsertAssignment from a create-only or immutable column.
type Interceptor ¶ added in v0.4.0
Interceptor may append predicates or return an error to deny the statement. It runs before SQL is built, in registration order. It is attached per handle with WithInterceptor and inherited by transactions begun from that handle only.
An interceptor is an application-level guard, not a database security boundary. It covers only the primary table of these typed statements of the handle: Select (All, One, First, Each, Iter, Count, Explain), Insert, Upsert, Update, BulkUpdate, SoftDelete, Delete, Merge, Truncate and InsertQuery.Copy. It does NOT cover: relation loading (Load, Preload, LoadCounts); the tables of joined relations (only the primary table is filtered); the association helpers (Link, Unlink, Replace and the like); subqueries and other sources rendered inside a statement (subquery operands, UPDATE ... FROM, the FromSelect source of an insert); raw SQL of any kind (Exec, MapRows, Scalars, Query, QueryRows, SQL fragments and RawSubquery); the raw driver CopyFrom (InsertQuery.Copy does run the insert interceptors, deny only); and anything run on the driver directly. A predicate an interceptor adds to an insert, a Copy or a Truncate is ignored, and one added to a Merge fails it with ErrValidation. SQL() runs the interceptors with a background context for Select, Update (BulkUpdate, SoftDelete), Delete and Merge; InsertQuery.SQL (also for an Upsert) runs neither interceptors nor hooks. The internal count that tells a stale version from a missing row after a version-checked update is a Select, so select interceptors apply to it. See docs/PRIVACY_RULES.md.
type LoadOption ¶
type LoadOption[C any] func(*loadConfig)
LoadOption configures one relation load.
func LoadOnlyDeleted ¶
func LoadOnlyDeleted[C any]() LoadOption[C]
LoadOnlyDeleted loads only soft-deleted children, like SelectQuery.OnlyDeleted.
func LoadOrderBy ¶
func LoadOrderBy[C any](items ...Orderable) LoadOption[C]
LoadOrderBy sets the child order. Stable tie-breakers (relation key columns, then child primary key) are always appended after it.
func LoadPerParentLimit ¶
func LoadPerParentLimit[C any](n int) LoadOption[C]
LoadPerParentLimit keeps at most n children per parent, in load order (LoadOrderBy, then the relation key and child primary key), using a window function so the load stays one statement per bind-limit chunk. It applies to has-many and many-to-many relations; on belongs-to and has-one the load fails with ErrUnsupported, and a negative n fails with ErrValidation (both with Op "load", before any statement runs). Zero leaves the load unlimited. Nested loads (Then) run over the kept children only. A many-to-many relation whose child has a primary key ranks with DENSE_RANK, so duplicated join-table rows share a rank and cannot use up the limit; without a child primary key (Relation.ChildPK empty) it ranks with ROW_NUMBER, so duplicated join rows each take a rank and can count against the limit before duplicates collapse. Window functions need PostgreSQL, MySQL 8 / MariaDB 10.2 or SQLite 3.25 and later.
func LoadWhere ¶
func LoadWhere[C any](ps ...Predicate) LoadOption[C]
LoadWhere adds predicates on the child table to the child statement.
func LoadWithDeleted ¶
func LoadWithDeleted[C any]() LoadOption[C]
LoadWithDeleted includes soft-deleted children for child models with a soft-delete column, like SelectQuery.WithDeleted. They are excluded by default.
type Loader ¶
type Loader[P any] interface { // contains filtered or unexported methods }
Loader is one relation load request, optionally scoped and nested. It is sealed: only Relation, RelationLoader (from Relation.Scope and Relation.Then) and Relation.Joined implement it.
type MergeQuery ¶ added in v0.4.0
type MergeQuery[T any] struct { // contains filtered or unexported fields }
MergeQuery builds a MERGE into one model table. It is a value: every method returns a copy.
func Merge ¶ added in v0.4.0
func Merge[T any, PT Modeler[T]](q Querier, source Subquery) MergeQuery[T]
Merge starts a MERGE into T from a source, which the statement names src. PostgreSQL 15 or later only (dialect.Merge); RETURNING on MERGE needs PostgreSQL 17 or later. The dialect is checked when the statement is built, before any server call, and the server version is read through ServerVersioner (or, on a Tx or an OnConn handle, on that connection) just before the statement runs. A driver that cannot report its version fails with ErrUnsupported. The version is read on every Exec or Rows call.
Matched rows are updated through WhenMatchedUpdate, which keeps the updated-at and version columns up to date like Update does; the values of WhenNotMatchedInsert come from the source, so field validators do not run on them. Nothing is written without On, and at least one WHEN clause is required.
func (MergeQuery[T]) Exec ¶ added in v0.4.0
func (m MergeQuery[T]) Exec(ctx context.Context) (Result, error)
Exec runs the MERGE and reports the rows it inserted or updated.
func (MergeQuery[T]) On ¶ added in v0.4.0
func (m MergeQuery[T]) On(ps ...Predicate) MergeQuery[T]
On sets the join condition between the target table and src. Several predicates are ANDed. Reference the source as src, for example with TypedSQL.
func (MergeQuery[T]) Returning ¶ added in v0.4.0
func (m MergeQuery[T]) Returning(cols ...ColumnRef) MergeQuery[T]
Returning appends a RETURNING list; read the rows with Rows. It needs PostgreSQL 17 or later.
func (MergeQuery[T]) Rows ¶ added in v0.4.0
func (m MergeQuery[T]) Rows(ctx context.Context) (*ModelRows[T], error)
Rows runs the MERGE and returns its RETURNING rows. It fails with ErrValidation when no Returning list was set and with ErrUnsupported on a server older than PostgreSQL 17.
func (MergeQuery[T]) SQL ¶ added in v0.4.0
func (m MergeQuery[T]) SQL() (Compiled, error)
SQL renders the statement without executing it. It checks the dialect but not the server version, which needs a connection.
func (MergeQuery[T]) WhenMatchedUpdate ¶ added in v0.4.0
func (m MergeQuery[T]) WhenMatchedUpdate(assigns ...Assignment) MergeQuery[T]
WhenMatchedUpdate adds WHEN MATCHED THEN UPDATE SET with the assignments. The primary key, version, soft-delete, created-at and updated-at columns cannot be assigned directly, as in Update.
func (MergeQuery[T]) WhenNotMatchedInsert ¶ added in v0.4.0
func (m MergeQuery[T]) WhenNotMatchedInsert(cols []ColumnRef, values ...Expr) MergeQuery[T]
WhenNotMatchedInsert adds WHEN NOT MATCHED THEN INSERT with one value expression per column. An identity column in the list is written with OVERRIDING SYSTEM VALUE.
type Meta ¶
type Meta[T any] struct { // Table is empty for projections. Table string // Schema is the database schema qualifying Table; empty for the default. Schema string Columns []ColumnMeta // Ptr returns the address of the field for column i, for scanning. Ptr func(m *T, i int) any // Value returns the value of the field for column i, for binding. Value func(m *T, i int) any // TableSchema is the normalized table definition; nil for projections. TableSchema *schema.Table // Derived column indexes, filled by generated code. -1 means absent for // Identity, Version, SoftDelete, CreatedAt and UpdatedAt. Identity int Version int SoftDelete int // SoftDeleteKind is the type of the soft-delete marker column; the zero // value is a nullable timestamp. SoftDeleteKind SoftDeleteKind CreatedAt int UpdatedAt int PK []int // Fields are Go-side defaults and validators per column, run by the // write builders before SQL is built. See FieldHook. Fields []FieldHook[T] // IDGens declares Go-side id generators per column; an insert fills the // column when its field holds the zero value. See WithIDGenerator. IDGens []IDGen // Hooks are the typed model hooks the write and read builders call. See // HookSet. Hooks HookSet[T] // View marks a model backed by a database view. Generated code sets it // for a model that embeds View. Insert, Upsert, Update, SoftDelete, // BulkUpdate, Delete and Merge refuse such a model with ErrValidation. View bool }
Meta is the generated, reflection-free description of a model or projection type T. Generated code returns a pointer to a package-level Meta value; Momo never mutates it.
type Model ¶
type Model struct{}
Model is embedded in a struct to declare it a Momo model. The struct tag on the embedded field carries table-level options:
type Document struct {
momo.Model `momo:"table:documents"`
...
}
It is zero-sized and has no behavior at runtime.
type ModelRows ¶
type ModelRows[T any] struct { // contains filtered or unexported fields }
ModelRows is the cursor of a write statement with a RETURNING list. Each row scans into the model fields named by the list; other fields are left untouched.
func (*ModelRows[T]) Close ¶
Close releases the cursor. It is safe to call more than once. Deferred directly (defer rows.Close()), it also rolls back an implicit transaction when a panic unwinds through the caller, so a RETURNING write is never committed by a panicking iteration.
type Modeler ¶
Modeler is implemented (by generated code) on pointers to model and projection types. It ties T to its metadata at compile time.
type NPlusOneFinding ¶ added in v0.4.0
type NPlusOneFinding struct {
Shape string // SQL with placeholders and IN lists collapsed
Example string // the SQL text of the statement that crossed the threshold
Count int
}
NPlusOneFinding reports a statement shape that repeated more than the threshold within one query scope. Count is the number of executions when the threshold was first exceeded.
type NamedArg ¶
NamedArg is a named argument for an @name placeholder in raw SQL. Build it with Named.
func Named ¶
Named binds value to every @name placeholder in a raw fragment. An @name with no matching argument is a build error, except on MySQL where it is a user variable and is left verbatim. A Named argument that no @name in the fragment references is a build error on every dialect, so a typo cannot run silently.
Raw scanner assumptions: MySQL NO_BACKSLASH_ESCAPES and PostgreSQL standard_conforming_strings=off are not supported (MySQL strings always honour backslash escapes, PostgreSQL ones only after E). MySQL /*! ... */ executable comments are treated as ordinary comments. On PostgreSQL the operators ?| and ?& are operators, not binds followed by | or &: write "? |" with a space for a bind followed by OR. A "<@" on PostgreSQL is the containment operator, never an @name. On PostgreSQL a native $n binds positional argument n (a reused $n shares one bind); a fragment uses one style, so mixing $n with ? or @name is a build error, and so is a $n off PostgreSQL. An unterminated string, quoted identifier, block comment or dollar quote is a build error.
type NullColumn ¶
NullColumn is the descriptor for a nullable column. It adds SetNull.
func NewNullColumn ¶
func NewNullColumn[T any](table, name string, flags uint16) NullColumn[T]
NewNullColumn is used by generated code.
func (NullColumn[T]) As ¶
func (c NullColumn[T]) As(alias string) NullColumn[T]
As returns the same column qualified by a table alias.
func (NullColumn) AsExpr ¶ added in v0.4.0
func (c NullColumn) AsExpr() Expression[T]
AsExpr returns the column as an Expression[T], so a projection list reads explicitly: DocTitle.As("l").AsExpr().
func (NullColumn) Asc ¶ added in v0.4.0
func (c NullColumn) Asc() Order
Asc orders by the column ascending. The order item is the column itself, a ColumnRef, so keyset pagination recognizes a primary-key column.
func (NullColumn) ColumnName ¶ added in v0.4.0
func (c NullColumn) ColumnName() string
ColumnName returns the unquoted column name.
func (NullColumn) Desc ¶ added in v0.4.0
func (c NullColumn) Desc() Order
Desc orders by the column descending.
func (NullColumn) Excluded ¶ added in v0.4.0
func (c NullColumn) Excluded() ExcludedExpr[T]
Excluded is the value proposed for insertion in an upsert, rendered as EXCLUDED.<col>. Use it on the right-hand side of a comparison in the DO UPDATE WHERE or ON CONFLICT predicates, for example until.LtExpr(until.Excluded()). It is only meaningful inside an ON CONFLICT clause; the database rejects it elsewhere.
func (NullColumn) Flags ¶ added in v0.4.0
func (c NullColumn) Flags() uint16
Flags returns the generated column flags.
func (NullColumn) ParseCmp ¶ added in v0.4.0
ParseCmp parses raw with the column's Go type and returns the comparison predicate for op, one of eq, ne, lt, le, gt and ge. An unknown op or a value that does not parse is an *Error with Kind ErrValidation. It is meant for a filter value that arrives as text from outside; the column comes from the generated ColumnByName allowlist.
func (NullColumn) ParseEq ¶ added in v0.4.0
ParseEq parses raw with the column's Go type and returns the equality predicate on it. A value that does not parse is an *Error with Kind ErrValidation; the error does not echo raw, which may be attacker controlled.
func (NullColumn[T]) SetNull ¶
func (c NullColumn[T]) SetNull() Assignment
SetNull assigns SQL NULL.
type NullReadOnlyColumn ¶
type NullReadOnlyColumn[T any] struct { // contains filtered or unexported fields }
NullReadOnlyColumn is the descriptor of a nullable read-only column. It has predicate and ordering methods only.
func NewNullReadOnlyColumn ¶
func NewNullReadOnlyColumn[T any](table, name string, flags uint16) NullReadOnlyColumn[T]
NewNullReadOnlyColumn is used by generated code.
func (NullReadOnlyColumn[T]) As ¶
func (c NullReadOnlyColumn[T]) As(alias string) NullReadOnlyColumn[T]
As returns the same column qualified by a table alias.
func (NullReadOnlyColumn) AsExpr ¶
func (c NullReadOnlyColumn) AsExpr() Expression[T]
AsExpr returns the column as an Expression[T], so a projection list reads explicitly: DocTitle.As("l").AsExpr().
func (NullReadOnlyColumn) Asc ¶
func (c NullReadOnlyColumn) Asc() Order
Asc orders by the column ascending. The order item is the column itself, a ColumnRef, so keyset pagination recognizes a primary-key column.
func (NullReadOnlyColumn) ColumnName ¶
func (c NullReadOnlyColumn) ColumnName() string
ColumnName returns the unquoted column name.
func (NullReadOnlyColumn) Desc ¶
func (c NullReadOnlyColumn) Desc() Order
Desc orders by the column descending.
func (NullReadOnlyColumn[T]) Excluded ¶ added in v0.2.0
func (c NullReadOnlyColumn[T]) Excluded() Expression[T]
Excluded is the value proposed for insertion, for an upsert condition.
func (NullReadOnlyColumn) Flags ¶
func (c NullReadOnlyColumn) Flags() uint16
Flags returns the generated column flags.
func (NullReadOnlyColumn) ParseCmp ¶ added in v0.4.0
ParseCmp parses raw with the column's Go type and returns the comparison predicate for op, one of eq, ne, lt, le, gt and ge. An unknown op or a value that does not parse is an *Error with Kind ErrValidation. It is meant for a filter value that arrives as text from outside; the column comes from the generated ColumnByName allowlist.
type NullVectorColumn ¶
type NullVectorColumn[V VectorValue] struct{ VectorColumn[V] }
NullVectorColumn is the descriptor of a nullable vector column. It adds SetNull.
func NewNullVectorColumn ¶
func NewNullVectorColumn[V VectorValue](table, name string, dim int, flags uint16) NullVectorColumn[V]
NewNullVectorColumn is used by generated code.
func (NullVectorColumn) AppendSQL ¶
func (c NullVectorColumn) AppendSQL(b *Builder)
AppendSQL renders the qualified, quoted column.
func (NullVectorColumn[V]) As ¶
func (c NullVectorColumn[V]) As(alias string) NullVectorColumn[V]
As returns the same column qualified by a table alias.
func (NullVectorColumn) AsExpr ¶
func (c NullVectorColumn) AsExpr() Expression[V]
AsExpr returns the column as an Expression[V].
func (NullVectorColumn) ColumnName ¶
func (c NullVectorColumn) ColumnName() string
ColumnName returns the unquoted column name.
func (NullVectorColumn) Dim ¶
func (c NullVectorColumn) Dim() int
Dim returns the declared dimension. Zero marks a dimensionless column: a distance argument of any size is accepted and checked against itself.
func (NullVectorColumn) EqExpr ¶
func (c NullVectorColumn) EqExpr(e Expression[V]) Predicate
func (NullVectorColumn) Flags ¶
func (c NullVectorColumn) Flags() uint16
Flags returns the generated column flags.
func (NullVectorColumn) IsDistinctFrom ¶
func (c NullVectorColumn) IsDistinctFrom(v V) Predicate
IsDistinctFrom is a NULL-safe inequality.
func (NullVectorColumn) IsNotDistinctFrom ¶
func (c NullVectorColumn) IsNotDistinctFrom(v V) Predicate
IsNotDistinctFrom is a NULL-safe equality.
func (NullVectorColumn) IsNotNull ¶
func (c NullVectorColumn) IsNotNull() Predicate
IsNotNull is true when the column holds a value.
func (NullVectorColumn) IsNull ¶
func (c NullVectorColumn) IsNull() Predicate
IsNull is true when the column holds SQL NULL.
func (NullVectorColumn) NeExpr ¶
func (c NullVectorColumn) NeExpr(e Expression[V]) Predicate
func (NullVectorColumn) NotInQuery ¶
func (NullVectorColumn) ParseCmp ¶ added in v0.4.0
ParseCmp always fails: a vector has no text form to filter by.
func (NullVectorColumn) ParseEq ¶ added in v0.4.0
ParseEq always fails: a vector has no text form to filter by.
func (NullVectorColumn[V]) SetNull ¶
func (c NullVectorColumn[V]) SetNull() Assignment
SetNull assigns SQL NULL.
type Operation ¶ added in v0.4.0
type Operation struct {
// Kind is "select", "insert", "upsert", "update", "delete" or "truncate".
// Every write path reports one kind:
//
// Insert (and Copy) insert
// Insert with OnConflict DoNothing insert
// Insert with OnConflict DoUpdate, Upsert upsert
// Update, BulkUpdate update
// SoftDelete, Delete delete
// Merge with WhenMatchedUpdate upsert
// Merge without WhenMatchedUpdate insert
// Truncate truncate
//
// ON CONFLICT DO UPDATE and a matched MERGE can overwrite an existing
// row, so a tenant rule must deny an "upsert" or constrain it (for
// example by requiring the tenant column).
Kind string
Table string
// Where starts empty. An interceptor appends predicates to it; they are
// ANDed to the predicates of a select, update or delete and are rendered
// in the compiled SQL. Predicates an insert interceptor appends are
// ignored. They do not count as a caller filter, so an update or delete
// without a Where of its own is still refused with ErrUnfilteredMutation.
Where []Predicate
}
Operation is what an interceptor sees and may change before a typed statement compiles.
type Ops ¶ added in v0.4.0
type Ops[T any] struct { // contains filtered or unexported fields }
Ops gives a scalar expression of result type T the comparison and ordering methods of Column: Eq, Ne, Lt, Le, Gt, Ge, the ...Expr forms, In, NotIn, Between, IsNull, IsNotNull, Asc and Desc. FuncExpr and the expressions of the sqlfn package (CaseExpr, ArithExpr, CastExpr, ConcatExpr, LengthExpr) embed it, so each method exists once.
Ops is an extension point. Embedding momo.Ops[T] in your own struct makes that struct an Expression[T] (an Expression[bool] is a Predicate), which is how code outside this package defines custom expressions. Build the Ops value with NewOps and give it the finished host, then write the host's AppendSQL with Builder.Ident for identifiers and Builder.Arg (or ArgFor) for values, never by concatenating text into the SQL.
The zero value is not bound to a host: rendering a comparison made from it fails the build with ErrValidation.
Example ¶
A custom expression embeds momo.Ops[T], writes identifiers through the builder and binds values as arguments. The result works in Columns, Where and OrderBy like a built-in expression.
// SQL() only compiles the statement, so no connection is needed here.
db := momo.New(pgxdriver.New(nil))
title := momo.NewColumn[string]("documents", "title", 0)
c, err := momo.Select[unitTally](db).
From(momo.TableRef{Name: "documents"}).
Columns(newShout(title)).
Where(newStartsWith(title, "ab")).
SQL()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(c.SQL)
fmt.Println(c.Args)
Output: SELECT upper("documents"."title") FROM "documents" WHERE "documents"."title" LIKE $1 [ab%]
func NewOps ¶ added in v0.4.0
NewOps binds the embedded comparison methods to host, the expression that embeds the returned Ops. Call it from the host's constructor on a copy of the host whose Ops field is still empty:
u := upper{src: src}
u.Ops = momo.NewOps[string](u)
NewOps is an extension point; see Ops.
func (Ops[T]) EqExpr ¶ added in v0.4.0
func (o Ops[T]) EqExpr(x Expression[T]) Predicate
EqExpr is true when the expression equals x.
func (Ops[T]) GeExpr ¶ added in v0.4.0
func (o Ops[T]) GeExpr(x Expression[T]) Predicate
GeExpr is true when the expression is greater than or equal to x.
func (Ops[T]) GtExpr ¶ added in v0.4.0
func (o Ops[T]) GtExpr(x Expression[T]) Predicate
GtExpr is true when the expression is greater than x.
func (Ops[T]) IsDistinctFrom ¶ added in v0.4.0
IsDistinctFrom is a NULL-safe inequality.
func (Ops[T]) IsNotDistinctFrom ¶ added in v0.4.0
IsNotDistinctFrom is a NULL-safe equality.
func (Ops[T]) LeExpr ¶ added in v0.4.0
func (o Ops[T]) LeExpr(x Expression[T]) Predicate
LeExpr is true when the expression is less than or equal to x.
func (Ops[T]) LtExpr ¶ added in v0.4.0
func (o Ops[T]) LtExpr(x Expression[T]) Predicate
LtExpr is true when the expression is less than x.
func (Ops[T]) NeExpr ¶ added in v0.4.0
func (o Ops[T]) NeExpr(x Expression[T]) Predicate
NeExpr is true when the expression differs from x.
func (Ops[T]) NotInQuery ¶ added in v0.4.0
NotInQuery is the negation of InQuery. Beware SQL's NOT IN semantics when the subquery can yield NULL.
type Option ¶
type Option func(*DB)
Option configures a DB.
func WithArgLogging ¶
func WithArgLogging() Option
WithArgLogging includes bind-parameter values in QueryEvent.Args. It is off by default because parameters often contain personal data.
func WithClock ¶
WithClock sets the clock used for automatic timestamps and soft-delete markers. The clock is read once per statement. A nil clock keeps the default, time.Now.
func WithFieldHooks ¶
WithFieldHooks registers Go-side defaults and validators for model T on this DB. They apply in addition to T's Meta.Fields, after them, and are looked up by the Meta pointer, so no reflection or tag inspection runs per query. Several calls for the same T accumulate. Hooks are keyed by the *Meta[T] that T's MomoMeta returns, so MomoMeta must return the same pointer on every call (a package-level variable); a method that builds a fresh Meta each time never matches the registered hooks.
func WithHook ¶
WithHook registers an observability hook. Hooks run in registration order.
A hook that also implements RelationHook receives relation load events.
func WithIDGenerator ¶ added in v0.4.0
WithIDGenerator registers the id generator name on this DB, or replaces the built-in of that name (cuid, uuid, ulid). A model column declared with idgen:name takes its id from fn when an insert writes the zero value. fn must return a non-empty string and be safe for concurrent use. An empty id, a panic in fn and a nil fn fail the insert with ErrValidation. A model that names a generator that is neither built in nor registered fails with ErrValidation when it is inserted.
func WithImplicitTx ¶ added in v0.4.0
func WithImplicitTx() Option
WithImplicitTx makes every auto-commit statement on a *DB run inside its own short transaction, so WithTxSetup applies to it too. This covers Select, Insert, Update, Delete, Exec, Scalars and the relation loads. Statements on a *Tx are unaffected, and a *DB pinned with OnConn keeps running on its connection without a transaction.
A streaming read (Iter, Each, Rows) holds its transaction, and so its connection, until the rows are exhausted or closed, then commits. It rolls back instead when iteration failed (a scan or driver error, or a cancelled context). Close the rows, or range to the end or break out of Iter, as for any rows, so the connection returns to the pool.
Each statement is its own transaction: a relation load or a multi-statement call is no longer one snapshot unless you wrap it in DB.Tx. Pipelined (Batch) relation loading and the COPY fast path are not used on the *DB, because they would bypass the setup; bulk inserts use chunked multi-row INSERTs instead. Hooks see the BEGIN and COMMIT of each implicit transaction, and its statements report InTx.
func WithInterceptor ¶ added in v0.4.0
func WithInterceptor(i Interceptor) Option
WithInterceptor attaches i to the handle. Several calls accumulate and run in order. A handle made with New from the same driver does not inherit it.
func WithMaxInList ¶ added in v0.4.0
WithMaxInList caps the number of values in one typed IN or NOT IN list, and in one In argument of raw SQL, at n. A longer list fails the build with ErrLimitExceeded instead of reaching the database. Tuple IN lists that momo builds itself for relation loading are not capped here: they are chunked under the bind-parameter limit (WithMaxParams) instead. n must be positive: WithMaxInList panics otherwise, like WithMaxParams. The dialect value is copied; the shared dialect is never mutated.
func WithMaxParams ¶
WithMaxParams lowers the dialect bind-parameter limit for this DB to n. It is for tests and for drivers or proxies with tighter limits than the dialect default.
n must be positive: zero or a negative n would read as "no limit" in every guard, so WithMaxParams panics at New with a message naming the value (a programmer error, like a bad regexp.MustCompile). An n above the dialect's own limit is clamped to it, because the wire protocol rejects more parameters than that; a dialect that declares no limit takes n as given.
The limit applies to everything the DB runs: relation-load chunking (Load, LoadAll), bulk-insert chunking, raw SQL bind checks including In, transactions begun from the DB (Tx), and handles from OnConn. The dialect value is copied; the shared dialect is never mutated.
func WithReplicas ¶ added in v0.4.0
WithReplicas registers read-replica drivers. Replicas are used only through DB.Replica; the primary handle never reads from them.
func WithTxSetup ¶ added in v0.4.0
WithTxSetup registers fn to run right after every transaction momo begins, before any other statement of that transaction. It covers DB.Begin and DB.Tx, and every transaction momo opens on its own: chunked inserts, graph creation, relation writes, vecsearch.With and the short transactions of WithImplicitTx. Typical use is row-level-security scoping:
db := momo.New(drv, momo.WithTxSetup(func(ctx context.Context, tx *momo.Tx) error {
return momo.SetConfigLocal(ctx, tx, "app.tenant_id", tenantFrom(ctx))
}))
fn runs once per real transaction. It does not run again for a savepoint (Tx.Tx, or the savepoint a chunked insert opens on a Tx), because a savepoint stays inside the transaction whose setting is already applied. It does not run for AdoptTx either: momo did not begin that transaction, so the caller owns its setup.
When fn returns an error the transaction is rolled back and Begin (or the call that needed the transaction) returns that error; nothing else runs. Without WithImplicitTx, auto-commit statements on a *DB do not run in a transaction, so fn never runs for them and they are unscoped: enable WithImplicitTx whenever the setup enforces a security boundary. Statements issued through db.Driver() bypass momo entirely and are never scoped either. fn must not commit or roll back tx. Use transaction-local settings only (SetConfigLocal, Tx.SetLocal): a session-level SET would outlive the transaction and, behind PgBouncer in transaction mode, leak to another client. With several options the functions run in registration order.
type Order ¶
Order is one ORDER BY item.
func (Order) AppendOrder ¶ added in v0.4.0
AppendOrder renders the item as "expr ASC|DESC [NULLS FIRST|LAST]", failing the build with ErrUnsupported where the dialect has no NULLS ordering. Code outside this package that renders an ORDER BY inside its own expression (an ordered aggregate) calls it. AppendOrder is an extension point; see Ops.
func (Order) NullsFirst ¶
NullsFirst returns o with explicit NULLS FIRST.
type Orderable ¶
type Orderable interface {
// contains filtered or unexported methods
}
Orderable is accepted by OrderBy: an Order or any Expression.
type PinnedConn ¶
type PinnedConn interface {
Query(ctx context.Context, sql string, args []any) (Rows, error)
Exec(ctx context.Context, sql string, args []any) (int64, error)
Begin(ctx context.Context, opts TxOptions) (DriverTx, error)
Release() error
}
PinnedConn is one database connection checked out of a driver's pool. Statements on it run on the same session. Begin starts a transaction on that session; Release returns the connection to the pool.
Release contract: Release closes any Rows from Query that are still open (a forgotten Rows.Close cannot leak the connection), then returns the connection; those Rows are unusable afterwards. Rows must not be in use by another goroutine at that moment. If a Query, Exec or Begin call is still executing in another goroutine, Release does nothing and returns an error matching ErrPinnedBusy (errors.Is); call it again once that call has returned. Release after a successful Release returns nil. Callers must finish transactions begun on the connection before Release; whether one left open is rolled back or discarded with the session is driver-specific (the database/sql adapter rolls it back; the pgx pool adapter discards the session).
type Pinner ¶
type Pinner interface {
Pin(ctx context.Context) (PinnedConn, error)
}
Pinner is implemented by drivers that can pin one connection.
type PoolStater ¶
type PoolStater interface {
PoolStats() PoolStats
}
PoolStater is implemented by drivers that expose pool statistics.
type PoolStats ¶
type PoolStats struct {
MaxConns int
TotalConns int
AcquiredConns int
IdleConns int
AcquireCount int64
EmptyAcquireCount int64
EmptyAcquireWaitNS int64
}
PoolStats is a snapshot of a driver's connection pool.
type Predicate ¶
type Predicate = Expression[bool]
Predicate is a boolean expression usable in WHERE, ON and HAVING.
func ContainsLiteral ¶
func ContainsLiteral(e Expression[string], s string) Predicate
ContainsLiteral matches rows whose string expression contains s literally. s is escaped with EscapeLike, wrapped in % and bound as a parameter; the statement carries ESCAPE '!' on every dialect. Case sensitivity follows the dialect and the column collation (PostgreSQL LIKE is case-sensitive, SQLite LIKE is ASCII case-insensitive, MySQL depends on the collation).
func ILike ¶
func ILike(e Expression[string], pattern string) Predicate
ILike is PostgreSQL's case-insensitive LIKE. On SQLite, whose LIKE is already ASCII case-insensitive by default, it is ErrUnsupported to avoid implying Unicode case folding SQLite does not perform. Like Like, it always carries ESCAPE '!' to match EscapeLike.
func JoinSQL ¶ added in v0.4.0
JoinSQL composes raw SQL fragments and their arguments into one expression, the equivalent of Prisma.join: each part is typically SQL("status = ?", s), and the result can be used wherever SQL can. Because every part keeps its own arguments and placeholders are numbered as the whole statement renders, fragments can be collected in a slice and combined without hand-counting binds:
var conds []momo.Expr
if status != "" { conds = append(conds, momo.SQL("status = ?", status)) }
if owner != 0 { conds = append(conds, momo.SQL("owner_id = ?", owner)) }
where := momo.JoinSQL(" AND ", conds...)
sep must be a fixed literal and is checked against an allowlist, ignoring surrounding spaces and letter case: a comma, AND, OR, ||, + or a plain space (sep empty or only spaces). Any other separator fails the build with ErrValidation, so the separator can never carry caller-controlled SQL. For AND, OR, || and + every part and the whole join are parenthesised, which keeps operator precedence intact; a comma or a space writes the parts as they are. On MySQL, where || is logical OR, a "||" join renders CONCAT of the parenthesised parts. A NULL part makes a "||" join NULL on every dialect (wrap nullable parts in COALESCE), and on PostgreSQL every part of a "||" join must already be text: cast other types, for example SQL("?::text", n) or SQL("CAST(n AS text)"). A join of no parts renders 1 = 1 for AND and 1 = 0 for OR, like And and Or; with any other separator, or with a nil part, the build fails with ErrValidation. Use JoinTypedSQL when the join must carry a Go type.
func Like ¶
func Like(e Expression[string], pattern string) Predicate
Like matches a string expression against a LIKE pattern. The pattern is bound as a parameter and the statement always carries ESCAPE '!' on every dialect, the escape character EscapeLike uses. % and _ in the pattern stay wildcards; a ! in the pattern makes the next character literal. Escape user input with EscapeLike (or use ContainsLiteral) so it cannot act as a wildcard. A literal ! in a hand-written pattern must be written as !!.
func SQL ¶
SQL is an explicit escape hatch: a raw SQL fragment usable anywhere an expression or predicate is accepted.
Safety contract: sql is inserted verbatim and must be a trusted constant. Every '?' is replaced by a bound parameter for the next argument (an Expr argument is rendered inline instead). Write "??" for a literal '?'. Never build sql from user input; pass user input as arguments.
Raw arguments: In(slice) expands to a bind list (an empty slice is a build error), Ident(name) renders a quoted identifier, and @name binds Named(name, value). A ? or @name inside a string literal, quoted identifier, comment or dollar-quoted string is text, as are the PostgreSQL operators ?| ?& @? @@ @>.
On PostgreSQL, native $n placeholders bind positional argument n instead of ?, and a reused $n shares one bind. A fragment uses one style: mixing $n with ? or @name is ErrValidation, a $n with no argument or an argument no $n uses is ErrValidation, and a $n on another dialect is ErrUnsupported. The number is the position within this fragment's own arguments, not the final statement's, so a fragment embedded after other binds is renumbered.
func TenantFilter ¶ added in v0.4.0
TenantFilter returns col = <tenant from ctx>. When ctx has no tenant, or the tenant's dynamic type is not exactly T, building the query fails with ErrValidation ("no tenant in context"), so a missing tenant never widens a query, also not under Not or Or. The zero value of T (0, "") is a real tenant value and is filtered on like any other.
TenantFilter is an application-side convenience, NOT a security boundary. It is applied only where you add it to a Where: not automatically on Update or Delete, not to the tenant column of an Insert, not to Preload, Load or LoadCounts queries, joins or subqueries, and not to raw SQL. Enforce isolation in the database with row-level security. That is configured by your own WithTxSetup function, which reads whatever your code put in the context; to drive both from WithTenant, read the tenant there and call SetConfigLocal. Without WithImplicitTx, non-transactional queries get no setting.
type PredicateFunc ¶ added in v0.4.0
type PredicateFunc func(b *Builder)
PredicateFunc adapts a render function to a Predicate. The function writes the condition into the builder, using Builder.Ident for identifiers and Builder.Arg or Builder.ArgFor for values. PredicateFunc is an extension point; see Ops.
Example ¶
PredicateFunc turns a render function into a Predicate without defining a type.
db := momo.New(pgxdriver.New(nil))
active := momo.PredicateFunc(func(b *momo.Builder) {
b.Ident("active")
b.WriteString(" IS TRUE")
})
c, err := momo.Select[unitTally](db).
From(momo.TableRef{Name: "documents"}).
Columns(momo.NewColumn[string]("documents", "title", 0)).
Where(active).
SQL()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(c.SQL)
Output: SELECT "documents"."title" FROM "documents" WHERE "active" IS TRUE
func (PredicateFunc) AppendSQL ¶ added in v0.4.0
func (f PredicateFunc) AppendSQL(b *Builder)
AppendSQL calls f.
type Projection ¶
type Projection struct{}
Projection is embedded in a struct to declare it a result type for typed projections. Its fields are scanned positionally from the select list.
type Querier ¶
Querier is implemented by *DB and *Tx. Query builders take a Querier so the same code runs inside or outside a transaction. It is sealed.
type QueryEvent ¶
type QueryEvent struct {
Op string // "select", "insert", "update", "delete", "exec", "raw", "explain", "begin", "commit", "rollback", "savepoint"
Table string // model table when known
// Relation is set while eager-loading a relation ("documents.author").
Relation string
SQL string
// Args is nil unless the DB was opened with WithArgLogging. Treat
// parameter values as sensitive.
Args []any
// NumArgs is always set: the number of bound parameters.
NumArgs int
// InTx reports that the statement ran on a *Tx.
InTx bool
// PoolWait is the summed RecordPoolWait for this statement.
PoolWait time.Duration
// Dialect is the dialect of the DB the statement ran on.
Dialect *dialect.Dialect
// Querier is the *DB or *Tx the statement ran on.
Querier Querier
Start time.Time
// Duration is filled for AfterQuery. For reads it covers execution
// and iteration until the rows are closed.
Duration time.Duration
// Rows is the number of rows read (queries) or affected (exec);
// -1 when unknown.
Rows int64
Err error
// contains filtered or unexported fields
}
QueryEvent describes one statement for observability hooks.
type QueryRegistry ¶ added in v0.5.0
type QueryRegistry struct {
// contains filtered or unexported fields
}
QueryRegistry holds named query builders so a test can list the SQL an application issues without a database. It replaces the .sql files of a code generator: lint the listed SQL, freeze it in golden files (see momotest.QueryGolden), or run the previous release's list against a new schema. It is safe for concurrent use.
func DefaultQueries ¶ added in v0.5.0
func DefaultQueries() *QueryRegistry
DefaultQueries returns the process-wide registry that RegisterQuery fills.
func NewQueryRegistry ¶ added in v0.5.0
func NewQueryRegistry() *QueryRegistry
NewQueryRegistry returns an empty registry, for a test that wants one isolated from the process-wide DefaultQueries.
func (*QueryRegistry) Compile ¶ added in v0.5.0
func (r *QueryRegistry) Compile(d dialect.Name) ([]RegisteredQuery, error)
Compile renders every registered query for dialect d, sorted by name, without a database. The SQL has surrounding whitespace trimmed, so the text is stable whatever the indentation of a raw string literal. A builder that fails, returns nil or renders an error (for example ErrUnsupported on a dialect that lacks the feature) fails the whole call with an error naming the query. An unknown dialect panics, see NewOffline.
func (*QueryRegistry) Names ¶ added in v0.5.0
func (r *QueryRegistry) Names() []string
Names returns the registered names in sorted order.
func (*QueryRegistry) Register ¶ added in v0.5.0
func (r *QueryRegistry) Register(name string, build func(q Querier) Compilable)
Register adds a named query. build receives a Querier that only compiles (see NewOffline) and returns the statement, for example a SelectQuery or a RawQuery. It runs once per Compile and dialect, so it must not touch a database, and the argument values it binds are placeholders that never reach the listed SQL. Register panics when name is empty or contains a line break, build is nil or name is already registered, programming errors like a duplicate http.HandleFunc pattern.
type ReadOnlyColumn ¶
type ReadOnlyColumn[T any] struct { // contains filtered or unexported fields }
ReadOnlyColumn is the descriptor of a read-only column (DB generated or computed). It has predicate and ordering methods only; no write method exists, so a Set on it does not compile.
func NewReadOnlyColumn ¶
func NewReadOnlyColumn[T any](table, name string, flags uint16) ReadOnlyColumn[T]
NewReadOnlyColumn is used by generated code.
func (ReadOnlyColumn[T]) As ¶
func (c ReadOnlyColumn[T]) As(alias string) ReadOnlyColumn[T]
As returns the same column qualified by a table alias.
func (ReadOnlyColumn) AsExpr ¶
func (c ReadOnlyColumn) AsExpr() Expression[T]
AsExpr returns the column as an Expression[T], so a projection list reads explicitly: DocTitle.As("l").AsExpr().
func (ReadOnlyColumn) Asc ¶
func (c ReadOnlyColumn) Asc() Order
Asc orders by the column ascending. The order item is the column itself, a ColumnRef, so keyset pagination recognizes a primary-key column.
func (ReadOnlyColumn) ColumnName ¶
func (c ReadOnlyColumn) ColumnName() string
ColumnName returns the unquoted column name.
func (ReadOnlyColumn) Desc ¶
func (c ReadOnlyColumn) Desc() Order
Desc orders by the column descending.
func (ReadOnlyColumn[T]) Excluded ¶ added in v0.2.0
func (c ReadOnlyColumn[T]) Excluded() Expression[T]
Excluded is the value proposed for insertion, for an upsert condition.
func (ReadOnlyColumn) Flags ¶
func (c ReadOnlyColumn) Flags() uint16
Flags returns the generated column flags.
func (ReadOnlyColumn) ParseCmp ¶ added in v0.4.0
ParseCmp parses raw with the column's Go type and returns the comparison predicate for op, one of eq, ne, lt, le, gt and ge. An unknown op or a value that does not parse is an *Error with Kind ErrValidation. It is meant for a filter value that arrives as text from outside; the column comes from the generated ColumnByName allowlist.
type ReadOnlyVectorColumn ¶
type ReadOnlyVectorColumn[V VectorValue] struct { // contains filtered or unexported fields }
ReadOnlyVectorColumn is a read-only vector column (database generated or computed). It can be searched and filtered but has no write method, so a Set on it does not compile. Nullability comes from the flags.
func NewReadOnlyVectorColumn ¶
func NewReadOnlyVectorColumn[V VectorValue](table, name string, dim int, flags uint16) ReadOnlyVectorColumn[V]
NewReadOnlyVectorColumn is used by generated code.
func (ReadOnlyVectorColumn) AppendSQL ¶
func (c ReadOnlyVectorColumn) AppendSQL(b *Builder)
AppendSQL renders the qualified, quoted column.
func (ReadOnlyVectorColumn[V]) As ¶
func (c ReadOnlyVectorColumn[V]) As(alias string) ReadOnlyVectorColumn[V]
As returns the same column qualified by a table alias.
func (ReadOnlyVectorColumn) AsExpr ¶
func (c ReadOnlyVectorColumn) AsExpr() Expression[V]
AsExpr returns the column as an Expression[V].
func (ReadOnlyVectorColumn) ColumnName ¶
func (c ReadOnlyVectorColumn) ColumnName() string
ColumnName returns the unquoted column name.
func (ReadOnlyVectorColumn) Dim ¶
func (c ReadOnlyVectorColumn) Dim() int
Dim returns the declared dimension. Zero marks a dimensionless column: a distance argument of any size is accepted and checked against itself.
func (ReadOnlyVectorColumn) EqExpr ¶
func (c ReadOnlyVectorColumn) EqExpr(e Expression[V]) Predicate
func (ReadOnlyVectorColumn) Flags ¶
func (c ReadOnlyVectorColumn) Flags() uint16
Flags returns the generated column flags.
func (ReadOnlyVectorColumn) IsDistinctFrom ¶
func (c ReadOnlyVectorColumn) IsDistinctFrom(v V) Predicate
IsDistinctFrom is a NULL-safe inequality.
func (ReadOnlyVectorColumn) IsNotDistinctFrom ¶
func (c ReadOnlyVectorColumn) IsNotDistinctFrom(v V) Predicate
IsNotDistinctFrom is a NULL-safe equality.
func (ReadOnlyVectorColumn) IsNotNull ¶
func (c ReadOnlyVectorColumn) IsNotNull() Predicate
IsNotNull is true when the column holds a value.
func (ReadOnlyVectorColumn) IsNull ¶
func (c ReadOnlyVectorColumn) IsNull() Predicate
IsNull is true when the column holds SQL NULL.
func (ReadOnlyVectorColumn) NeExpr ¶
func (c ReadOnlyVectorColumn) NeExpr(e Expression[V]) Predicate
func (ReadOnlyVectorColumn) NotInQuery ¶
func (ReadOnlyVectorColumn) ParseCmp ¶ added in v0.4.0
ParseCmp always fails: a vector has no text form to filter by.
type RegisteredQuery ¶ added in v0.5.0
type RegisteredQuery struct {
// Name is the name the query was registered under.
Name string
// SQL is the statement text with the dialect's placeholders. Argument
// values are not part of it.
SQL string
}
RegisteredQuery is the compiled SQL of one named query for one dialect.
type Relation ¶
type Relation[P, C any] struct { Name string Kind RelationKind Parent TableRef Child TableRef ParentMeta *Meta[P] ChildMeta *Meta[C] ParentCols []string ChildCols []string ChildPK []string Through *Through Discriminator *Discriminator ParentKey func(p *P) ([]any, bool) ChildKey func(c *C) ([]any, bool) SetParentKey func(p *P, key []any) SetChildKey func(c *C, key []any) GetOne func(p *P) *C SetOne func(p *P, c *C) GetMany func(p *P) []C SetMany func(p *P, cs []C) }
Relation describes relation Name from parent P to child C. Generated code emits one value per relation field. Relation values are immutable and safe for concurrent use.
func (Relation[P, C]) Count ¶
Count returns the number of children associated with p in one SELECT COUNT(*). A NULL parent key counts zero. For ManyToMany it counts join rows (joined to the far table only when that table has a soft-delete column, so soft-deleted children are not counted). BelongsTo returns ErrUnsupported.
func (Relation[P, C]) CountOrder ¶
CountOrder orders parents by the number of related children, using a correlated COUNT(*) subquery.
func (Relation[P, C]) From ¶
func (r Relation[P, C]) From(parents SelectQuery[P]) SelectQuery[C]
From returns the children whose key is in the parents' key set. The parents query is embedded as a subquery, so no parent row is fetched. Many-to-many relations are not supported by From; the returned query fails with ErrValidation.
func (Relation[P, C]) Has ¶
Has returns EXISTS over the child table, correlated with the parent. The predicate is a subquery, never a JOIN, so it cannot duplicate parent rows.
Scope predicates must reference the child through the alias "momo_r": build them with As on the generated column, for example comment.Approved.As("momo_r").Eq(true). Soft-deleted children do not count. For many-to-many relations the join table gets no soft-delete filter: only the child table's marker is applied.
Example ¶
Has filters parents by a correlated EXISTS subquery. Scope predicates name the child through the alias "momo_r".
package main
import (
"fmt"
"github.com/azrtydxb/momo"
"github.com/azrtydxb/momo/driver/pgxdriver"
"github.com/azrtydxb/momo/internal/relfixture/comment"
"github.com/azrtydxb/momo/internal/relfixture/document"
"github.com/azrtydxb/momo/internal/relfixture/models"
)
func main() {
db := momo.New(pgxdriver.New(nil))
c, err := momo.Select[models.Document](db).
Where(document.Comments.Has(comment.Approved.As("momo_r").Eq(true))).
OrderBy(document.Comments.CountOrder(momo.DirDesc)).
SQL()
if err != nil {
fmt.Println(err)
return
}
fmt.Println(c.SQL != "")
}
Output: true
func (Relation[P, C]) HasFrom ¶
HasFrom is Has correlated on an explicit parent alias. Self-referencing relations need it: the parent table is aliased in the outer query and the alias is passed here.
func (Relation[P, C]) HasNo ¶
HasNo returns NOT EXISTS over the child table. Scope predicates follow the rules of Has.
func (Relation[P, C]) Include ¶
func (r Relation[P, C]) Include() Association[P]
Include lists the relation for CreateGraph: the children held in the parent's field are inserted in the same transaction. Only the listed relation is written; the children's own relations are not (a graph is one level deep), so a self-referencing relation or a cycle in memory cannot recurse.
func (Relation[P, C]) Joined ¶
Joined returns a loader that fetches the parent's belongs-to child in the parent statement itself, as a LEFT JOIN with aliased columns (momo_j<n>), so the relation costs no extra round trip. Pass it to SelectQuery.Preload; Load, LoadAll, Scope and Then do not take it.
Only belongs-to relations are joinable, and only when the relation's child key is the child's primary key or a single unique column, because then the join cannot multiply parent rows: Limit, Offset, OrderBy and Where of the parent query keep their meaning. has-one, has-many and many-to-many fail with ErrUnsupported (Op "select") when the query runs, as do GroupBy, Having and row locking on the same query (FOR UPDATE cannot lock the nullable side of an outer join), and Each and Iter.
Semantics match Load for belongs-to: a NULL (or part-NULL composite) foreign key, or a key matching no child, leaves the field nil, never a zero struct; children are excluded when soft-deleted, by a condition in the ON clause so the parent row survives; each parent gets its own copy of a shared child. The select list names parent columns by their qualifier, so a raw unqualified column in the parent's Where may become ambiguous.
A joined load runs no statement of its own, so it emits no RelationEvent; the parent statement is reported to Hook as usual. Loaders for other relations in the same Preload still load as separate statements.
func (Relation[P, C]) Link ¶
Link associates the listed children with p: HasOne and HasMany set the children's foreign key (UPDATE), ManyToMany inserts the join rows (INSERT, existing pairs are kept; the join columns need a unique or primary key). Sets larger than the bind limit are split into one statement per chunk. It writes directly: no model hooks, field hooks or UpdatedAt. BelongsTo returns ErrUnsupported.
func (Relation[P, C]) Replace ¶
Replace makes the listed children the complete set associated with p, in one transaction (a savepoint on a *Tx). It first locks the parent row (SELECT 1 FROM parent WHERE key = ? FOR UPDATE) on dialects with row locks (PostgreSQL, MySQL), so concurrent Replace calls on the same parent run one after the other and each reads the set the previous one committed; without that, two callers under READ COMMITTED could produce unique violations, duplicate join rows or a mix of both sets. SQLite serialises writers and skips the lock. On a *Tx the lock is held until the caller's transaction ends, because the savepoint does not release it. The lock is a row lock, so a parent row that does not exist locks nothing: concurrent Replace calls on a missing parent are not serialised. Link and Unlink take no parent lock, so they can interleave with a concurrent Replace on the same parent. With no children it clears the whole set in one statement. Otherwise it reads the current child keys, diffs them in Go against cs, unlinks only the removed keys and links only the added keys, each in chunks that respect the bind limit, so a set of any size works and kept children are not rewritten. It writes directly: no model hooks, field hooks or UpdatedAt. HasOne/HasMany need a nullable foreign key. BelongsTo returns ErrUnsupported. Replace needs a transaction, so a *DB pinned with OnConn fails with ErrUnsupported (Op "begin"); run it on the pool or inside a *Tx. Link, Unlink and Count accept a pinned handle.
Example ¶
The association helpers write the link between a parent and its children.
package main
import (
"context"
"fmt"
"github.com/azrtydxb/momo"
"github.com/azrtydxb/momo/driver/pgxdriver"
"github.com/azrtydxb/momo/internal/relfixture/document"
"github.com/azrtydxb/momo/internal/relfixture/models"
)
func main() {
var (
ctx = context.Background()
db = momo.New(pgxdriver.New(nil))
doc = models.Document{ID: 1}
tags = []*models.Tag{{ID: 1}, {ID: 2}}
)
_ = document.Tags.Link(ctx, db, &doc, tags...)
_ = document.Tags.Unlink(ctx, db, &doc, tags[0])
err := document.Tags.Replace(ctx, db, &doc, tags[1])
n, cerr := document.Tags.Count(ctx, db, &doc)
fmt.Println(err, n, cerr)
}
Output:
func (Relation[P, C]) Scope ¶
func (r Relation[P, C]) Scope(opts ...LoadOption[C]) RelationLoader[P, C]
Scope returns a loader for r with per-load options. The result can be scoped further and given nested loads: r.Scope(opts...).Then(nested...) filters and orders the relation and loads nested relations over exactly the children that remain.
func (Relation[P, C]) Then ¶
func (r Relation[P, C]) Then(nested ...Loader[C]) RelationLoader[P, C]
Then returns a loader for r that also loads nested relations on the children. The result can be scoped: r.Then(nested...).Scope(opts...) is the same loader as r.Scope(opts...).Then(nested...).
func (Relation[P, C]) Unlink ¶
Unlink removes the association between p and the listed children: HasOne and HasMany clear the children's foreign key (UPDATE; the key columns must be nullable), ManyToMany deletes the join rows (DELETE). Children that are not associated with p are left alone. Sets larger than the bind limit are split into one statement per chunk. It writes directly: no model hooks, field hooks or UpdatedAt. BelongsTo returns ErrUnsupported.
type RelationEvent ¶
type RelationEvent struct {
Parent string
Name string
Kind RelationKind
Parents int
Children int64
Queries int
Duration time.Duration
Err error
}
RelationEvent describes one relation load. Queries is the number of child statements compiled for the load (a failed load may have run fewer). Children is set only when the load's statements succeeded; on error it is zero and Err holds the error. Duration is filled before AfterRelation.
Events fire only for loads that execute statements: not when there are no parents, and not when the load fails while being prepared (validation, unsupported options), before any statement runs.
type RelationHook ¶
type RelationHook interface {
BeforeRelation(ctx context.Context, e *RelationEvent) context.Context
AfterRelation(ctx context.Context, e *RelationEvent)
}
RelationHook is an optional extension of Hook. Hooks registered with WithHook that implement it receive relation events.
type RelationKind ¶
type RelationKind uint8
RelationKind is the shape of a relation.
const ( // BelongsTo has its foreign key on the parent; the child is matched by its key. BelongsTo RelationKind = iota + 1 // HasOne has its foreign key on the child; at most one child per parent. HasOne // HasMany has its foreign key on the child; any number of children per parent. HasMany // ManyToMany goes through a join table between parent and child. ManyToMany )
func (RelationKind) String ¶
func (k RelationKind) String() string
String returns the lower-case name of the relation kind.
type RelationLoader ¶ added in v0.3.0
type RelationLoader[P, C any] struct { // contains filtered or unexported fields }
RelationLoader is a loader for one relation that carries per-load options (Scope) and nested loads (Then) together, so "approved comments, newest first, each with its author" is one loader:
document.Comments.Scope( momo.LoadWhere[models.Comment](comment.Approved.Eq(true)), momo.LoadOrderBy[models.Comment](comment.ID.Desc()), ).Then(comment.Author)
It is a value: Scope and Then return a new loader and leave the receiver unchanged, so a base loader can be shared. Scope may be called several times (predicates AND together, order items append, a later LoadPerParentLimit replaces an earlier one). Then appends nested loaders. The options apply to this relation's children only; nested loaders carry their own options. Nested loads run once over exactly the children that survive the options, so the statement count stays one per bind-limit chunk at the top and one per level below it.
A RelationLoader with no options and no nested loaders behaves like the plain Relation. It implements Loader[P]; Loader stays sealed.
func (RelationLoader[P, C]) Scope ¶ added in v0.3.0
func (l RelationLoader[P, C]) Scope(opts ...LoadOption[C]) RelationLoader[P, C]
Scope returns a copy of l with opts applied after its existing options.
func (RelationLoader[P, C]) Then ¶ added in v0.3.0
func (l RelationLoader[P, C]) Then(nested ...Loader[C]) RelationLoader[P, C]
Then returns a copy of l with nested appended after its existing nested loads.
type Result ¶
type Result struct {
RowsAffected int64
// InsertID is the auto-increment key a single-row insert generated, on
// dialects whose driver reports it (MySQL and MariaDB); zero otherwise.
InsertID int64
}
Result reports the outcome of a write statement.
type ReturningList ¶
type ReturningList struct {
// contains filtered or unexported fields
}
ReturningList is a RETURNING column list shared by the write builders.
func Returning ¶
func Returning(cols ...ColumnRef) ReturningList
Returning builds a RETURNING list from column descriptors.
type Row1 ¶ added in v0.3.0
type Row1[A any] struct { Projection C1 A }
Row1 is a result row of 1 column, scanned positionally into C1. Row1 to Row10 are the tuple rows: generic result types for queries that do not read a whole model: aggregates, joins and column subsets. They replace a hand-written projection struct and Meta per result shape:
rows, err := momo.Select[momo.Row2[string, int64]](db). From(document.Table). Columns(document.Title, momo.CountAll()). GroupBy(document.Title). All(ctx) // rows[i].C1 is the title, rows[i].C2 the count
Row1 to Row10 take 1 to 10 columns. The Columns list is scanned positionally: expression i fills field Ci, so the number of Columns must equal the row's arity (ErrValidation otherwise, at SQL or execution time). Names play no part. Use a pointer type parameter, such as Row2[string, *int64], for a column that can be NULL (a LEFT JOIN side, an aggregate over no rows).
A tuple row is a projection: it has no table, so Insert, Update and Delete refuse it with ErrValidation, and it carries no soft-delete column of its own. As for any projection the live-row filter comes from the From table (and WithDeleted or OnlyDeleted adjust it). After works when OrderBy names a unique key, because a tuple has no primary key to break ties with.
type Row2 ¶ added in v0.3.0
type Row2[A, B any] struct { Projection C1 A C2 B }
Row2 is a result row of 2 columns, scanned positionally into C1..C2. Use a pointer type parameter for a column that can be NULL; see Row1.
type Row3 ¶ added in v0.3.0
type Row3[A, B, C any] struct { Projection C1 A C2 B C3 C }
Row3 is a result row of 3 columns, scanned positionally into C1..C3. Use a pointer type parameter for a column that can be NULL; see Row1.
type Row4 ¶ added in v0.3.0
type Row4[A, B, C, D any] struct { Projection C1 A C2 B C3 C C4 D }
Row4 is a result row of 4 columns, scanned positionally into C1..C4. Use a pointer type parameter for a column that can be NULL; see Row1.
type Row5 ¶ added in v0.3.0
type Row5[A, B, C, D, E any] struct { Projection C1 A C2 B C3 C C4 D C5 E }
Row5 is a result row of 5 columns, scanned positionally into C1..C5. Use a pointer type parameter for a column that can be NULL; see Row1.
type Row6 ¶ added in v0.3.0
type Row6[A, B, C, D, E, F any] struct { Projection C1 A C2 B C3 C C4 D C5 E C6 F }
Row6 is a result row of 6 columns, scanned positionally into C1..C6. Use a pointer type parameter for a column that can be NULL; see Row1.
type Row7 ¶ added in v0.3.0
type Row7[A, B, C, D, E, F, G any] struct { Projection C1 A C2 B C3 C C4 D C5 E C6 F C7 G }
Row7 is a result row of 7 columns, scanned positionally into C1..C7. Use a pointer type parameter for a column that can be NULL; see Row1.
type Row8 ¶ added in v0.3.0
type Row8[A, B, C, D, E, F, G, H any] struct { Projection C1 A C2 B C3 C C4 D C5 E C6 F C7 G C8 H }
Row8 is a result row of 8 columns, scanned positionally into C1..C8. Use a pointer type parameter for a column that can be NULL; see Row1.
type Row9 ¶ added in v0.3.0
type Row9[A, B, C, D, E, F, G, H, I any] struct { Projection C1 A C2 B C3 C C4 D C5 E C6 F C7 G C8 H C9 I }
Row9 is a result row of 9 columns, scanned positionally into C1..C9. Use a pointer type parameter for a column that can be NULL; see Row1.
type Row10 ¶ added in v0.3.0
type Row10[A, B, C, D, E, F, G, H, I, J any] struct { Projection C1 A C2 B C3 C C4 D C5 E C6 F C7 G C8 H C9 I C10 J }
Row10 is a result row of 10 columns, scanned positionally into C1..C10. Use a pointer type parameter for a column that can be NULL; see Row1.
type Scope ¶ added in v0.4.0
type Scope[T any] func(SelectQuery[T]) SelectQuery[T]
Scope is a named, reusable query transformation, for example a tenant or visibility filter shared by many call sites. A Scope receives and returns a SelectQuery value, so it composes with every other builder method.
type SelectQuery ¶
type SelectQuery[T any] struct { // contains filtered or unexported fields }
SelectQuery builds and runs a SELECT whose rows scan into T.
SelectQuery is an immutable value: every method returns a new query and leaves the receiver unchanged, so a base query can be extended concurrently from many goroutines. Executing a query does not modify it.
func Select ¶
func Select[T any, PT Modeler[T]](q Querier) SelectQuery[T]
Select starts a query for model or projection T:
momo.Select[models.Document](db).Where(document.Published.Eq(true)).All(ctx)
For a model, FROM and the select list default to the model's table and mapped columns. For a projection, call From and Columns.
func (SelectQuery[T]) After ¶
func (sq SelectQuery[T]) After(values ...any) SelectQuery[T]
After restricts the result to rows strictly after the cursor given by values, one per effective ORDER BY key in order. The effective keys are the OrderBy items followed by the primary key ascending when it is not already an item, which makes the order total. Ascending keys compare with >, descending keys with <. After needs OrderBy, a value count equal to the number of effective keys (ErrValidation otherwise), and non-nullable keys (ErrUnsupported otherwise).
func (SelectQuery[T]) All ¶
func (sq SelectQuery[T]) All(ctx context.Context) ([]T, error)
All runs the query and collects every row. An empty result is an empty (nil) slice and a nil error, never ErrNotFound.
func (SelectQuery[T]) AppendSQL ¶
func (sq SelectQuery[T]) AppendSQL(b *Builder)
AppendSQL renders the query in parentheses, for use as a subquery.
func (SelectQuery[T]) Columns ¶
func (sq SelectQuery[T]) Columns(es ...Expr) SelectQuery[T]
Columns replaces the select list. For model results the expressions must match the model's mapped columns one-to-one; for projections they map to the projection's fields in order.
func (SelectQuery[T]) Count ¶
func (sq SelectQuery[T]) Count(ctx context.Context) (int64, error)
Count runs SELECT COUNT(*) over this query (as a subquery, so DISTINCT, GROUP BY, LIMIT and OFFSET keep their meaning).
func (SelectQuery[T]) CrossJoin ¶
func (sq SelectQuery[T]) CrossJoin(src TableSource) SelectQuery[T]
CrossJoin adds a CROSS JOIN.
func (SelectQuery[T]) Distinct ¶
func (sq SelectQuery[T]) Distinct() SelectQuery[T]
Distinct adds DISTINCT.
func (SelectQuery[T]) DistinctOn ¶ added in v0.4.0
func (sq SelectQuery[T]) DistinctOn(es ...Expr) SelectQuery[T]
DistinctOn keeps the first row of each group of rows that agree on es: SELECT DISTINCT ON (es). Which row is first is decided by OrderBy, so DistinctOn requires an OrderBy whose leading items are exactly es (in any order) followed by the tie-breakers that pick the row; otherwise the build fails with ErrValidation, the same rule PostgreSQL enforces. DistinctOn replaces Distinct. PostgreSQL only; other dialects fail the build with ErrUnsupported.
func (SelectQuery[T]) Each ¶
func (sq SelectQuery[T]) Each(ctx context.Context, fn func(*T) error) error
Each streams rows to fn without collecting them. The *T passed to fn is reused for the next row; copy it to retain it. Returning an error from fn stops iteration, closes the cursor and returns that error.
func (SelectQuery[T]) Exists ¶
func (sq SelectQuery[T]) Exists(ctx context.Context) (bool, error)
Exists reports whether the query yields any row.
func (SelectQuery[T]) Explain ¶
func (sq SelectQuery[T]) Explain(ctx context.Context) (string, error)
Explain runs EXPLAIN (never EXPLAIN ANALYZE) for the query and returns the plan text, one line per row joined by newlines. Parameters are bound, never interpolated.
EXPLAIN plans the statement without executing it, so Explain has no side effects on data. It runs on the query's own connection, so inside a Tx the plan reflects that transaction's settings (for example SetLocal planner switches). PostgreSQL uses EXPLAIN and SQLite uses EXPLAIN QUERY PLAN. MySQL and MariaDB return ErrUnsupported: their tabular EXPLAIN has no single plan column.
Example ¶
Explain returns the plan text without executing the query, so a test can check that a vector query uses its index.
package main
import (
"context"
"fmt"
"github.com/azrtydxb/momo"
"github.com/azrtydxb/momo/internal/testmodels/example"
"github.com/azrtydxb/momo/internal/testmodels/example/document"
"github.com/azrtydxb/momo/vecop"
"github.com/azrtydxb/momo/vector"
)
func main() {
var db *momo.DB
ctx := context.Background()
plan, err := momo.Select[example.Document](db).
OrderBy(vecop.L2(document.Embedding, make(vector.Vector, 1536)).Asc()).
Limit(10).
Explain(ctx)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(plan) // look for "Index Scan using documents_embedding_hnsw"
}
Output:
func (SelectQuery[T]) First ¶
func (sq SelectQuery[T]) First(ctx context.Context) (T, error)
First applies LIMIT 1 and returns the first row, or ErrNotFound.
func (SelectQuery[T]) ForKeyShare ¶ added in v0.5.0
func (sq SelectQuery[T]) ForKeyShare(opt ...string) SelectQuery[T]
ForKeyShare adds FOR KEY SHARE (PostgreSQL only): the weakest row lock, which only blocks changes to the key columns and deletes. Options and restrictions are those of ForUpdate, and LockOf works with it. MySQL, MariaDB and SQLite return ErrUnsupported when the query is built.
func (SelectQuery[T]) ForNoKeyUpdate ¶ added in v0.5.0
func (sq SelectQuery[T]) ForNoKeyUpdate(opt ...string) SelectQuery[T]
ForNoKeyUpdate adds FOR NO KEY UPDATE (PostgreSQL only): a write lock that does not block foreign-key inserts and FOR KEY SHARE locks on the same row, so it suits a row update that leaves the key columns alone. Options and restrictions are those of ForUpdate, and LockOf works with it. MySQL, MariaDB and SQLite have no such mode and return ErrUnsupported when the query is built.
func (SelectQuery[T]) ForShare ¶
func (sq SelectQuery[T]) ForShare(opt ...string) SelectQuery[T]
ForShare adds FOR SHARE (PostgreSQL). Options and restrictions are those of ForUpdate.
func (SelectQuery[T]) ForUpdate ¶
func (sq SelectQuery[T]) ForUpdate(opt ...string) SelectQuery[T]
ForUpdate adds FOR UPDATE (PostgreSQL). Options: "NOWAIT", "SKIP LOCKED"; naming both is an ErrValidation, repeating one is not. A row lock cannot be combined with DISTINCT, GROUP BY or HAVING: the build fails with ErrValidation. Count and Exists wrap the whole statement, so they keep the lock clause and lock the rows they count.
func (SelectQuery[T]) From ¶
func (sq SelectQuery[T]) From(src TableSource) SelectQuery[T]
From replaces the FROM source (a table, aliased table, CTE or subquery).
func (SelectQuery[T]) GroupBy ¶
func (sq SelectQuery[T]) GroupBy(es ...Expr) SelectQuery[T]
GroupBy sets GROUP BY expressions.
func (SelectQuery[T]) Having ¶
func (sq SelectQuery[T]) Having(ps ...Predicate) SelectQuery[T]
Having adds HAVING predicates combined with AND.
func (SelectQuery[T]) IndexedBy ¶
func (sq SelectQuery[T]) IndexedBy(index string) SelectQuery[T]
IndexedBy renders SQLite's INDEXED BY hint after the FROM table. The index name is quoted, never spliced. PostgreSQL and MySQL have no such clause and return ErrUnsupported when the query is built. The FROM source must be a plain table (TableRef).
func (SelectQuery[T]) Iter ¶
Iter streams rows as a range-over-func sequence. Breaking out of the loop closes the cursor. An error is yielded once, as the final element.
func (SelectQuery[T]) Join ¶
func (sq SelectQuery[T]) Join(src TableSource, on ...Predicate) SelectQuery[T]
Join adds an INNER JOIN.
func (SelectQuery[T]) LeftJoin ¶
func (sq SelectQuery[T]) LeftJoin(src TableSource, on ...Predicate) SelectQuery[T]
LeftJoin adds a LEFT JOIN. Columns of src may be NULL in the result: project them into nullable fields (pointer or sql.Null types). Scanning a NULL into a non-nullable field fails with a driver error; it never silently yields a zero value.
func (SelectQuery[T]) Limit ¶
func (sq SelectQuery[T]) Limit(n int64) SelectQuery[T]
Limit sets LIMIT.
func (SelectQuery[T]) LockOf ¶ added in v0.4.0
func (sq SelectQuery[T]) LockOf(tables ...string) SelectQuery[T]
LockOf narrows the row lock of ForUpdate, ForShare, ForNoKeyUpdate or ForKeyShare to the named tables (FOR UPDATE OF t1, t2). A joined select needs it to lock only the claimed side: a LEFT JOIN cannot lock its nullable side, and a job-claim join locks the job table and leaves the parent alone. Each name is the qualifier the table has in the query, its alias when it has one, and is quoted as an identifier. The names render after the lock mode and before NOWAIT or SKIP LOCKED, whatever the call order. Without one of the four lock modes the build fails with ErrValidation; like them, LockOf returns ErrUnsupported on SQLite, and MySQL and MariaDB refuse the PostgreSQL-only modes. Each name must be the table or alias of the FROM or a joined table, else the build fails with ErrValidation naming it. A lock cannot be combined with DISTINCT, DISTINCT ON, GROUP BY or HAVING (ErrValidation); other invalid combinations, such as aggregates or UNION, are left to the server.
func (SelectQuery[T]) MaxRows ¶ added in v0.4.0
func (sq SelectQuery[T]) MaxRows(n int) SelectQuery[T]
MaxRows caps the rows a collecting read (All, Pluck) may return. When the query yields more than n rows the read fails with ErrLimitExceeded; rows are never silently truncated. Streaming reads (Each, Iter) and Count are not capped, and n must be positive.
func (SelectQuery[T]) Offset ¶
func (sq SelectQuery[T]) Offset(n int64) SelectQuery[T]
Offset sets OFFSET. Prefer keyset pagination (After) for deep pages.
func (SelectQuery[T]) One ¶
func (sq SelectQuery[T]) One(ctx context.Context) (T, error)
One returns the single matching row: ErrNotFound when none matches and ErrTooManyRows when more than one does. It adds no LIMIT.
func (SelectQuery[T]) OnlyDeleted ¶
func (sq SelectQuery[T]) OnlyDeleted() SelectQuery[T]
OnlyDeleted narrows a select to soft-deleted rows of a model with a soft-delete column. A later WithDeleted overrides it.
func (SelectQuery[T]) OrderBy ¶
func (sq SelectQuery[T]) OrderBy(items ...Orderable) SelectQuery[T]
OrderBy appends ORDER BY items. Pass Column.Asc()/Desc(), or a typed expression (e.g. a vector distance), which orders ascending.
func (SelectQuery[T]) Preload ¶
func (sq SelectQuery[T]) Preload(loaders ...Loader[T]) SelectQuery[T]
Preload returns a copy of the query that loads the given relations for every row that All, One and First return. The receiver is unchanged, and queries derived from one base never share their preload lists.
The relations load with LoadAll after the parent rows are read: one statement per relation (per bind-limit chunk), run on the query's Querier, so inside a transaction they run in that transaction. A result with no rows issues no relation statement, and an error from a relation load is returned instead of the rows. Relation hooks fire as they do for LoadAll.
Loaders from Relation.Joined are not loaded afterwards but joined into the query itself; see Joined for their rules.
Each and Iter stream rows without collecting them, so they cannot batch relation loads: with preloads they return an error matching ErrUnsupported.
Example ¶
Preload runs the loads after the query's rows are read; Joined fetches a belongs-to relation in the parent statement itself.
package main
import (
"context"
"fmt"
"github.com/azrtydxb/momo"
"github.com/azrtydxb/momo/driver/pgxdriver"
"github.com/azrtydxb/momo/internal/relfixture/document"
"github.com/azrtydxb/momo/internal/relfixture/models"
)
func main() {
var (
ctx = context.Background()
db = momo.New(pgxdriver.New(nil))
)
docs, err := momo.Select[models.Document](db).
Preload(document.Author.Joined(), document.Comments).
Limit(20).
All(ctx)
fmt.Println(docs, err)
}
Output:
func (SelectQuery[T]) SQL ¶
func (sq SelectQuery[T]) SQL() (Compiled, error)
SQL compiles the query without executing it.
Interceptors run with a background context here; the execution methods pass the statement's own context.
func (SelectQuery[T]) Scope ¶ added in v0.4.0
func (sq SelectQuery[T]) Scope(s ...Scope[T]) SelectQuery[T]
Scope applies each scope to the query in order and returns the result. A nil scope is skipped.
func (SelectQuery[T]) Where ¶
func (sq SelectQuery[T]) Where(ps ...Predicate) SelectQuery[T]
Where adds predicates combined with AND.
func (SelectQuery[T]) With ¶
func (sq SelectQuery[T]) With(name string, q Subquery, cols ...string) SelectQuery[T]
With adds a common table expression. cols optionally names its columns.
func (SelectQuery[T]) WithDeleted ¶
func (sq SelectQuery[T]) WithDeleted() SelectQuery[T]
WithDeleted includes soft-deleted rows for models with a soft-delete column (they are excluded by default).
func (SelectQuery[T]) WithRecursive ¶
func (sq SelectQuery[T]) WithRecursive(name string, q Subquery, cols ...string) SelectQuery[T]
WithRecursive adds a recursive CTE; q is typically a UNION ALL built with SQL or Union.
func (SelectQuery[T]) WithTableName ¶
func (sq SelectQuery[T]) WithTableName(name string) SelectQuery[T]
WithTableName replaces the FROM table name at runtime, for example to run one query shape over several identically shaped tables. The name is quoted; it is never spliced. The replacement is aliased to the model's table name, so the model's column expressions and the soft-delete filter keep resolving. It needs a plain table as the FROM source.
type Series ¶ added in v0.4.0
type Series[T any] struct { // contains filtered or unexported fields }
Series is a generate_series(...) source producing one column of type T. Build it with GenerateSeries or GenerateTimeSeries.
func GenerateSeries ¶ added in v0.4.0
GenerateSeries is generate_series(start, stop[, step]) AS alias (col) over integers: the values from start to stop inclusive. A zero step fails the build with ErrValidation; a negative step counts down. More than one step is also a validation error. PostgreSQL only.
func GenerateTimeSeries ¶ added in v0.4.0
func GenerateTimeSeries(alias, col string, start, stop time.Time, step time.Duration) Series[time.Time]
GenerateTimeSeries is generate_series over timestamptz: start, start+step, ... up to stop. step is truncated to whole microseconds; a step that truncates to zero fails the build with ErrValidation. PostgreSQL only.
type ServerVersioner ¶
ServerVersioner is implemented by drivers that report the server version (PostgreSQL server_version_num, e.g. 170002). MERGE gates read it.
type SoftDeleteKind ¶
type SoftDeleteKind uint8
SoftDeleteKind is the type of a model's soft-delete marker column. The zero value is the nullable timestamp, so metadata that predates the field keeps working. Generated code records the kind from the field's Go type: *time.Time, *int64 or bool.
const ( // SoftDeleteTimestamp is a nullable timestamp, set to the statement time. SoftDeleteTimestamp SoftDeleteKind = iota // SoftDeleteUnix is a nullable integer, set to the statement time in Unix seconds. SoftDeleteUnix // SoftDeleteBool is a boolean, set to true. SoftDeleteBool )
type Subquery ¶
type Subquery interface {
Expr
// contains filtered or unexported methods
}
Subquery is a query usable as an expression: IN (...), EXISTS (...), scalar subqueries and FROM sources. *SelectQuery satisfies it.
func RawSubquery ¶
RawSubquery is an explicit escape hatch: a raw SELECT usable as a Subquery (IN, EXISTS, CTE body, set operation member, FromSubquery source).
Safety contract: as for SQL, sql is inserted verbatim and must be a trusted constant; '?' binds the next argument and "??" is a literal '?'. Momo cannot check which tables the fragment references. On PostgreSQL a native $n placeholder binds the nth argument of this fragment (see SQL), so pgx and sqlc statements port unchanged; momo renumbers it. For a scalar subquery as a typed comparison operand use TypedSQL[T]("?", sub): the subquery renders its own parentheses.
type TableRef ¶
type TableRef struct {
Name string
Alias string
Schema string
// SoftDelete is the name of the table's soft-delete marker column; empty
// when the table has none.
SoftDelete string
// SoftDeleteKind is the type of that marker column.
SoftDeleteKind SoftDeleteKind
}
TableRef names a table source in FROM and JOIN clauses, optionally aliased. Generated per-model packages embed it in their Table type.
Generated code sets SoftDelete and SoftDeleteKind on a model's Table when the model has a soft-delete column. A projection read FROM such a table then excludes soft-deleted rows like a model does. Use As to alias it.
func CTE ¶
CTE references a common table expression (or any table not described by a model) by name. Reference its columns with ColumnOf.
func (TableRef) As ¶ added in v0.3.0
As returns a copy of t under the alias, keeping everything else, including the soft-delete column that a projection read FROM t is filtered by.
func (TableRef) Qualifier ¶
Qualifier returns the name columns of this source are qualified with. An unaliased schema-qualified table ("tenant"."documents") is exposed under its bare name, so its columns render as "documents"."id"; alias one side to join two same-named tables from different schemas.
type TableSource ¶
type TableSource interface {
// contains filtered or unexported methods
}
TableSource is anything usable in FROM / JOIN.
func FromSubquery ¶
func FromSubquery(q Subquery, alias string) TableSource
FromSubquery uses a subquery as a FROM/JOIN source under alias. Reference its columns with ColumnOf.
func Lateral ¶ added in v0.4.0
func Lateral(q Subquery, alias string) TableSource
Lateral uses a subquery as a LATERAL FROM/JOIN source under alias. The subquery may reference columns of the FROM and JOIN sources before it:
momo.Select[row](db). From(accounts). CrossJoin(momo.Lateral(latestOrder, "lo"))
renders CROSS JOIN LATERAL (...) AS "lo". A LEFT JOIN needs an ON condition, so pass momo.SQL("true") when there is nothing to join on. Reference the subquery's columns with ColumnOf. PostgreSQL and MySQL 8 support LATERAL; SQLite and MariaDB fail the build with ErrUnsupported.
type Through ¶
type Through struct {
Table TableRef
ParentCols []string // join columns referencing Relation.ParentCols, same order
ChildCols []string // join columns referencing Relation.ChildCols, same order
}
Through names the join table of a ManyToMany relation.
type Tx ¶
type Tx struct {
// contains filtered or unexported fields
}
Tx is an explicit transaction handle. It is not safe for concurrent use: a transaction is bound to one connection, which processes one statement at a time.
func (*Tx) Commit ¶
Commit commits the transaction. On a Tx from AdoptTx it returns an error matching ErrAdoptedTx and does nothing.
func (*Tx) DriverTx ¶ added in v0.3.0
DriverTx returns the driver-level transaction behind tx, for driver packages that unwrap it (pgxdriver.UnwrapSQLTx, pgxdriver.UnwrapPgxTx). A savepoint scope returns the same outer transaction. Calling Commit or Rollback on it directly bypasses Momo's bookkeeping; prefer the unwrap helpers of the driver package.
func (*Tx) Rollback ¶
Rollback aborts the transaction. On a Tx from AdoptTx it returns an error matching ErrAdoptedTx and does nothing.
func (*Tx) RollbackTo ¶
RollbackTo rolls back to a named savepoint, keeping it defined.
func (*Tx) SetLocal ¶
SetLocal sets a run-time parameter for the rest of this transaction only (set_config with is_local = true). Name and value are bound parameters, so the setting reverts at commit or rollback and never reaches a pooled connection, which makes it safe behind PgBouncer in transaction mode. It returns ErrUnsupported on dialects without transaction-scoped settings.
name must never come from untrusted input. It is bound, so it cannot inject SQL, but set_config can change security-relevant parameters such as role, session_authorization or search_path for the rest of the transaction.
type TxOptions ¶
type TxOptions struct {
// Isolation is passed through to the driver. SQLite supports only
// serializable semantics; any other non-default level is rejected
// with ErrUnsupported rather than silently ignored.
Isolation sql.IsolationLevel
ReadOnly bool
}
TxOptions configures a transaction.
type UnnestArray ¶ added in v0.4.0
type UnnestArray interface {
// contains filtered or unexported methods
}
UnnestArray is one array argument of Unnest; UnnestCol implements it.
type UnnestCol ¶ added in v0.4.0
type UnnestCol[T any] struct { // contains filtered or unexported fields }
UnnestCol is one bound array of an Unnest source and the name of the column it produces. Build it with UnnestValues or UnnestValuesAs.
func UnnestValues ¶ added in v0.4.0
UnnestValues binds vals as one array argument that unnest turns into the column name. The array's SQL element type is derived from T: string is text, int64 and int bigint, int32 integer, int16 smallint, float64 double precision, float32 real, bool boolean, time.Time timestamptz, []byte bytea and a 16-byte array uuid (a pointer to any of these allows NULL elements; named types follow their underlying kind). The array is bound as one parameter and is not masked in logs or traces, even for sensitive values; do not unnest secrets. Any other T fails the build with ErrValidation; use UnnestValuesAs to name the type.
func UnnestValuesAs ¶ added in v0.4.0
UnnestValuesAs is UnnestValues with an explicit SQL element type such as numeric or timestamp (words of letters, digits and underscores, with an optional length suffix). The bound array is cast to sqlType[].
type UnnestSource ¶ added in v0.4.0
type UnnestSource struct {
// contains filtered or unexported fields
}
UnnestSource is unnest(a1, a2, ...) AS alias (c1, c2, ...) used as a FROM or JOIN source. Build it with Unnest.
func Unnest ¶ added in v0.4.0
func Unnest(alias string, cols ...UnnestArray) UnnestSource
Unnest expands one or more bound arrays into rows, one column per array:
momo.Select[fx](db).From(momo.Unnest("fx", currency, rate))
renders FROM unnest($1::text[], $2::double precision[]) AS "fx" ("currency", "rate"). Arrays of different lengths are padded with NULL to the longest. Read the columns through UnnestCol.Ref(alias). Unnest also serves as a CTE body source and as the right side of a Join. PostgreSQL only.
func (UnnestSource) Qualifier ¶ added in v0.4.0
func (u UnnestSource) Qualifier() string
Qualifier is the alias the source's columns are qualified with.
func (UnnestSource) WithOrdinality ¶ added in v0.4.0
func (u UnnestSource) WithOrdinality(name string) UnnestSource
WithOrdinality adds WITH ORDINALITY: an extra 1-based bigint column called name, read as an int64 column through ColumnOf.
type UpdateQuery ¶
type UpdateQuery[T any] struct { // contains filtered or unexported fields }
UpdateQuery builds an UPDATE of one model table. It is a value: every method returns a copy, so a base query can be reused safely.
Column identifiers come only from typed column descriptors and the model's MomoMeta, are always quoted, and every value is bound. A statement without a WHERE clause is refused with ErrUnfilteredMutation unless AllRows confirms it.
func BulkUpdate ¶ added in v0.4.0
func BulkUpdate[T any, PT Modeler[T]](q Querier, key ColumnRef, cols []ColumnRef, rows [][]any) UpdateQuery[T]
BulkUpdate updates rows of T from a list of rows keyed by key. Only listed keys change. Each row holds the key value first, then one value per column of cols, in order:
BulkUpdate[Document](db, DocID, []ColumnRef{DocTitle}, [][]any{{int64(2), "new"}})
It renders UPDATE t SET c = v.c FROM (one SELECT per row, joined by UNION ALL) AS v WHERE t.key = v.key with every value bound, so a row whose key is not in the table changes nothing. The rows take their column types from the table. A key listed twice applies one of its rows. The statement also maintains the updated-at and version columns, runs the OnUpdate defaults and the field validators over each row, and honours Where for extra conditions; Set and Model cannot be combined with it. PostgreSQL only (dialect.Merge gates both): other dialects fail with ErrUnsupported. A statement over the bind-parameter limit fails with ErrLimitExceeded: BulkUpdate does not chunk, so split a larger list across calls (in a transaction if it must be atomic).
func SoftDelete ¶
func SoftDelete[T any, PT Modeler[T]](q Querier) UpdateQuery[T]
SoftDelete returns an UpdateQuery that marks rows deleted instead of removing them. The marker follows the model's soft-delete column: a nullable timestamp (set to the statement time from the Go-side clock, WithClock or time.Now, bound as UTC; it is not the database's now()), a Unix integer (seconds) or a boolean (set true). Rows already soft-deleted are not touched, and updated_at is not modified.
It keeps the mutation guard: without a Where (or Model) that restricts the rows it fails with ErrUnfilteredMutation unless AllRows confirms it. Set is refused, and a model without a soft-delete column fails with ErrValidation. Model identifies the row by primary key only; no column is written from it.
func Update ¶
func Update[T any, PT Modeler[T]](q Querier) UpdateQuery[T]
Update starts an UPDATE of T's table.
func (UpdateQuery[T]) AllRows ¶
func (u UpdateQuery[T]) AllRows() UpdateQuery[T]
AllRows confirms that an UPDATE without WHERE is intended.
func (UpdateQuery[T]) AppendSQL ¶ added in v0.5.0
func (u UpdateQuery[T]) AppendSQL(b *Builder)
AppendSQL renders the statement in parentheses as a WITH clause body. It runs the handle's interceptors with a background context, as SQL does, but not the beforeWrite checks of Exec. Only PostgreSQL accepts the result.
func (UpdateQuery[T]) Exec ¶
func (u UpdateQuery[T]) Exec(ctx context.Context) (Result, error)
Exec runs the UPDATE. A version-checked Model update that matches no row looks the row up inside the same transaction (one is started when q is a *DB) to tell ErrOptimisticLock from ErrNotFound.
func (UpdateQuery[T]) From ¶ added in v0.5.0
func (u UpdateQuery[T]) From(src TableSource) UpdateQuery[T]
From adds a second source to the statement, rendering UPDATE t SET ... FROM src WHERE ...: the SET expressions and the WHERE may reference src's columns (ColumnOf on a CTE or FromSubquery alias, or a model's columns). src is a table, aliased table, CTE or FromSubquery, as in a join. Join src to the target in Where. Calling From again replaces the source.
PostgreSQL and SQLite (3.33 or later) render UPDATE ... FROM. MySQL and MariaDB render the multi-table form UPDATE t, src SET t.col = ... WHERE ..., qualifying the assigned columns. Soft-deleted rows of src are not filtered: add that predicate to Where. Interceptors apply to the target table only, not to src.
With a From source the unfiltered-mutation guard is stricter: at least one Where predicate must reference a column of the target table, otherwise the statement joins every target row to src and fails with ErrUnfilteredMutation unless AllRows confirms it. A raw SQL fragment does not count as such a reference. From cannot be combined with BulkUpdate (ErrValidation).
func (UpdateQuery[T]) Model ¶
func (u UpdateQuery[T]) Model(m *T) UpdateQuery[T]
Model updates the row identified by m's primary key with m's writable column values. When the model has a version column the statement is version-checked (WHERE pk = ? AND version = ?, SET version = version + 1): a stale m fails with ErrOptimisticLock and a missing row with ErrNotFound. After a successful versioned update m's version field is advanced. The identity, read-only, create-only, immutable, soft-delete, created-at and updated-at columns are not written from m; use Set for explicit writes.
func (UpdateQuery[T]) Returning ¶
func (u UpdateQuery[T]) Returning(cols ...ColumnRef) UpdateQuery[T]
Returning appends a RETURNING list; read the rows with Rows.
func (UpdateQuery[T]) ReturningAll ¶
func (u UpdateQuery[T]) ReturningAll() UpdateQuery[T]
ReturningAll returns every column mapped by T, in metadata order.
func (UpdateQuery[T]) Rows ¶
func (u UpdateQuery[T]) Rows(ctx context.Context) (*ModelRows[T], error)
Rows runs the UPDATE and returns its RETURNING rows. It fails with ErrValidation when no Returning list was set, and for a version-checked Model update, whose stale-row classification needs the affected-row count (use Exec for that).
func (UpdateQuery[T]) SQL ¶
func (u UpdateQuery[T]) SQL() (Compiled, error)
SQL renders the statement without executing it. Guardrail violations are reported here, before anything can reach the database.
Interceptors run with a background context here; the execution methods pass the statement's own context.
func (UpdateQuery[T]) Set ¶
func (u UpdateQuery[T]) Set(assigns ...Assignment) UpdateQuery[T]
Set adds explicit column assignments. An assignment to a column that is read-only, identity, create-only or immutable in the model's metadata is refused with ErrValidation when the statement is built. A later assignment to the same column replaces an earlier one.
func (UpdateQuery[T]) Where ¶
func (u UpdateQuery[T]) Where(ps ...Predicate) UpdateQuery[T]
Where adds predicates combined with AND.
func (UpdateQuery[T]) With ¶ added in v0.5.0
func (u UpdateQuery[T]) With(name string, q Subquery, cols ...string) UpdateQuery[T]
With prefixes the statement with a common table expression. cols optionally names its columns. The body may be a SelectQuery, an ExprSelect, a Union or (on PostgreSQL only) an INSERT, UPDATE or DELETE with RETURNING; a data-modifying body on another dialect fails with ErrUnsupported. Reference the CTE with CTE and ColumnOf, for instance as the From source. MariaDB does not accept the clause here (ErrUnsupported), and BulkUpdate cannot be combined with it (ErrValidation).
func (UpdateQuery[T]) WithRecursive ¶ added in v0.5.0
func (u UpdateQuery[T]) WithRecursive(name string, q Subquery, cols ...string) UpdateQuery[T]
WithRecursive is With for a recursive CTE.
type VectorColumn ¶
type VectorColumn[V VectorValue] struct { // contains filtered or unexported fields }
VectorColumn is a typed, writable vector column descriptor. Its dimension is known at generation time so distance arguments are validated at build time. It offers the same predicate, ordering and write methods as Column except the range comparisons.
Example ¶
The metrics and index methods each dialect supports come from dialect.Dialect.Vector. A distance the dialect lacks fails at build time with ErrUnsupported.
package main
import (
"fmt"
"github.com/azrtydxb/momo/dialect"
)
func main() {
for _, name := range []dialect.Name{dialect.Postgres, dialect.SQLite} {
caps := dialect.For(name).Vector
fmt.Println(name, caps.Metrics, caps.Indexes)
}
}
Output: postgres [l2 ip cosine l1 hamming jaccard] [hnsw ivfflat] sqlite [l2 l1 cosine hamming] []
func NewVectorColumn ¶
func NewVectorColumn[V VectorValue](table, name string, dim int, flags uint16) VectorColumn[V]
NewVectorColumn is used by generated code.
func VectorColumnOf ¶ added in v0.4.0
func VectorColumnOf[V VectorValue](s VectorSource[V]) VectorColumn[V]
VectorColumnOf returns the VectorColumn behind any vector column descriptor that satisfies VectorSource: VectorColumn itself, its nullable variant and the permission variants. Code outside this package uses it to read a source's table, column name, dimension and flags when it builds a distance expression. VectorColumnOf is an extension point; see Ops.
func (VectorColumn) AppendSQL ¶
func (c VectorColumn) AppendSQL(b *Builder)
AppendSQL renders the qualified, quoted column.
func (VectorColumn[V]) As ¶
func (c VectorColumn[V]) As(alias string) VectorColumn[V]
As returns the same column qualified by a table alias.
func (VectorColumn) AsExpr ¶
func (c VectorColumn) AsExpr() Expression[V]
AsExpr returns the column as an Expression[V].
func (VectorColumn) ColumnName ¶
func (c VectorColumn) ColumnName() string
ColumnName returns the unquoted column name.
func (VectorColumn) Dim ¶
func (c VectorColumn) Dim() int
Dim returns the declared dimension. Zero marks a dimensionless column: a distance argument of any size is accepted and checked against itself.
func (VectorColumn) EqExpr ¶
func (c VectorColumn) EqExpr(e Expression[V]) Predicate
func (VectorColumn[V]) Excluded ¶ added in v0.2.0
func (c VectorColumn[V]) Excluded() Expression[V]
Excluded is the vector proposed for insertion in an upsert, rendered as EXCLUDED.<col>. See Column.Excluded.
func (VectorColumn) Flags ¶
func (c VectorColumn) Flags() uint16
Flags returns the generated column flags.
func (VectorColumn) IsDistinctFrom ¶
func (c VectorColumn) IsDistinctFrom(v V) Predicate
IsDistinctFrom is a NULL-safe inequality.
func (VectorColumn) IsNotDistinctFrom ¶
func (c VectorColumn) IsNotDistinctFrom(v V) Predicate
IsNotDistinctFrom is a NULL-safe equality.
func (VectorColumn) IsNotNull ¶
func (c VectorColumn) IsNotNull() Predicate
IsNotNull is true when the column holds a value.
func (VectorColumn) IsNull ¶
func (c VectorColumn) IsNull() Predicate
IsNull is true when the column holds SQL NULL.
func (VectorColumn) NeExpr ¶
func (c VectorColumn) NeExpr(e Expression[V]) Predicate
func (VectorColumn) NotInQuery ¶
func (VectorColumn) ParseCmp ¶ added in v0.4.0
ParseCmp always fails: a vector has no text form to filter by.
func (VectorColumn) ParseEq ¶ added in v0.4.0
ParseEq always fails: a vector has no text form to filter by.
func (VectorColumn[V]) Set ¶
func (c VectorColumn[V]) Set(v V) Assignment
Set assigns a value in INSERT or UPDATE.
func (VectorColumn[V]) SetDefault ¶
func (c VectorColumn[V]) SetDefault() Assignment
SetDefault assigns the column's database default.
func (VectorColumn[V]) SetExcluded ¶
func (c VectorColumn[V]) SetExcluded() Assignment
SetExcluded assigns the value proposed for insertion in an upsert.
func (VectorColumn[V]) SetExpr ¶
func (c VectorColumn[V]) SetExpr(e Expression[V]) Assignment
SetExpr assigns an expression.
type VectorSource ¶
type VectorSource[V VectorValue] interface { // contains filtered or unexported methods }
VectorSource is any vector column descriptor a distance builder accepts: VectorColumn and its nullable and permission variants (ReadOnlyVectorColumn, CreateOnlyVectorColumn, ImmutableVectorColumn). A write restriction does not stop a column from being searched.
type VectorValue ¶
type VectorValue interface {
vector.Vector | vector.HalfVector | vector.SparseVector | vector.Bits
}
VectorValue is the set of Go types a vector column can hold.
type View ¶ added in v0.5.0
type View struct{}
View is embedded next to Model in a struct that maps a database view or materialized view. The generator records it in Meta.View, and every write builder (Insert, Upsert, Update, SoftDelete, BulkUpdate, Delete, Merge) then fails with ErrValidation naming the model; reads work as for any model. Declare the view itself in the model's MomoConfig with c.View.
type ActiveUser struct {
momo.Model `momo:"table:active_users"`
momo.View
ID int64 `momo:"pk"`
}
It is zero-sized and has no behavior at runtime.
type WindowExpr ¶ added in v0.4.0
type WindowExpr[T any] struct { // contains filtered or unexported fields }
WindowExpr is call OVER (...). It is an Expression[T]; name it with As.
func WindowOf ¶ added in v0.4.0
func WindowOf[T any](call Expr, w WindowSpec) WindowExpr[T]
WindowOf turns the aggregate call into a window function: call OVER (...). Code outside this package that defines its own aggregate type (agg.Call) builds its Over method on it; call must write identifiers through Builder.Ident and values through Builder.Arg. WindowOf is an extension point; see Ops.
func (WindowExpr[T]) AppendSQL ¶ added in v0.4.0
func (e WindowExpr[T]) AppendSQL(b *Builder)
AppendSQL writes the window expression to b.
func (WindowExpr[T]) As ¶ added in v0.4.0
func (e WindowExpr[T]) As(alias string) Aliased[T]
As names the window expression in a select list.
type WindowFunc ¶ added in v0.4.0
type WindowFunc[T any] struct { // contains filtered or unexported fields }
WindowFunc is a window function that needs its OVER clause: RowNumber, Rank, DenseRank, Lag, Lead, FirstValue and LastValue. Aggregates take theirs through Agg.Over.
func DenseRank ¶ added in v0.4.0
func DenseRank() WindowFunc[int64]
DenseRank is dense_rank(): the rank without gaps. It needs an ORDER BY.
func FirstValue ¶ added in v0.4.0
func FirstValue[T any](e Expression[T]) WindowFunc[T]
FirstValue is first_value(e) over the window frame. It requires an ORDER BY in the window on purpose: without one the first row is arbitrary.
func Lag ¶ added in v0.4.0
func Lag[T any](e Expression[T], offset int) WindowFunc[T]
Lag is lag(e, offset): the value offset rows before the current row, NULL when there is none (scan into a nullable destination). It needs an ORDER BY and rejects a frame.
func LagDefault ¶ added in v0.4.0
func LagDefault[T any](e Expression[T], offset int, def T) WindowFunc[T]
LagDefault is lag(e, offset, def): def replaces the NULL of a missing row. def is masked in logs and traces when e is a sensitive column.
func LastValue ¶ added in v0.4.0
func LastValue[T any](e Expression[T]) WindowFunc[T]
LastValue is last_value(e) over the window frame. The default frame ends at the current row; add Rows(UnboundedPreceding(), UnboundedFollowing()) for the last row of the partition.
func Lead ¶ added in v0.4.0
func Lead[T any](e Expression[T], offset int) WindowFunc[T]
Lead is lead(e, offset): the value offset rows after the current row.
func LeadDefault ¶ added in v0.4.0
func LeadDefault[T any](e Expression[T], offset int, def T) WindowFunc[T]
LeadDefault is lead(e, offset, def).
func Rank ¶ added in v0.4.0
func Rank() WindowFunc[int64]
Rank is rank(): the rank with gaps after ties. It needs an ORDER BY.
func RowNumber ¶ added in v0.4.0
func RowNumber() WindowFunc[int64]
RowNumber is row_number(): the row's 1-based position in its partition.
func (WindowFunc[T]) Over ¶ added in v0.4.0
func (f WindowFunc[T]) Over(w WindowSpec) WindowExpr[T]
Over attaches the window specification.
type WindowSpec ¶ added in v0.4.0
type WindowSpec struct {
// contains filtered or unexported fields
}
WindowSpec is the OVER (...) clause: PARTITION BY, ORDER BY and a frame. It is an immutable value; every method returns a new one.
func Over ¶ added in v0.4.0
func Over() WindowSpec
Over starts an empty window specification: OVER ().
func (WindowSpec) Groups ¶ added in v0.4.0
func (w WindowSpec) Groups(start, end FrameBound) WindowSpec
Groups sets a GROUPS BETWEEN start AND end frame (PostgreSQL and SQLite; MySQL fails the build with ErrUnsupported). It needs an ORDER BY.
func (WindowSpec) OrderBy ¶ added in v0.4.0
func (w WindowSpec) OrderBy(items ...Orderable) WindowSpec
OrderBy adds ORDER BY items, exactly like SelectQuery.OrderBy.
func (WindowSpec) PartitionBy ¶ added in v0.4.0
func (w WindowSpec) PartitionBy(es ...Expr) WindowSpec
PartitionBy adds PARTITION BY expressions.
func (WindowSpec) Range ¶ added in v0.4.0
func (w WindowSpec) Range(start, end FrameBound) WindowSpec
Range sets a RANGE BETWEEN start AND end frame. An offset bound needs exactly one ORDER BY item, and the offset is an integer literal, so it suits integer (or numeric) ordering columns; interval offsets for timestamp ordering are not expressible.
func (WindowSpec) Rows ¶ added in v0.4.0
func (w WindowSpec) Rows(start, end FrameBound) WindowSpec
Rows sets a ROWS BETWEEN start AND end frame.
Source Files
¶
- build.go
- build_mysql.go
- build_mysql_lock.go
- col_parse.go
- col_permissions.go
- col_vector.go
- col_vector_mysql.go
- col_vector_sqlite.go
- db.go
- db_atomic.go
- db_clock.go
- db_hook_relation.go
- db_hooks.go
- db_interceptor.go
- db_limits.go
- db_nplusone.go
- db_onconn.go
- db_options.go
- db_replica.go
- db_result.go
- db_tenant.go
- db_txsetup.go
- delete.go
- doc.go
- driver.go
- driver_access.go
- driver_optional.go
- err.go
- expr.go
- expr_allowlist.go
- expr_funcs.go
- expr_in_tuple.go
- expr_ops.go
- expr_window.go
- insert.go
- insert_chunk.go
- insert_copy.go
- insert_dbdefault.go
- insert_render.go
- insert_select.go
- insert_unnest.go
- meta.go
- meta_companion.go
- meta_fields.go
- meta_softdelete.go
- meta_timestamps.go
- raw_args.go
- raw_join.go
- raw_query.go
- raw_registry.go
- raw_scalars.go
- rel.go
- rel_assoc.go
- rel_counts.go
- rel_graph.go
- rel_join.go
- rel_load.go
- rel_loader.go
- rel_pipeline.go
- rel_pred.go
- select.go
- select_compose.go
- select_distinct_on.go
- select_explain.go
- select_explainstmt.go
- select_hybrid.go
- select_lateral.go
- select_meta.go
- select_preload.go
- select_render.go
- select_results.go
- select_rows.go
- select_srf.go
- tx.go
- update.go
- upsert.go
- write_guard.go
- write_idgen.go
- write_merge.go
- write_returning.go
- write_with.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package advisory takes PostgreSQL advisory locks through momo.
|
Package advisory takes PostgreSQL advisory locks through momo. |
|
Package agg holds the aggregates that the basic Agg of the root package does not cover: ORDER BY inside the call, WITHIN GROUP ordered-set aggregates, string, array and JSON array aggregation, and the JSON object builders that feed them.
|
Package agg holds the aggregates that the basic Agg of the root package does not cover: ORDER BY inside the call, WITHIN GROUP ordered-set aggregates, string, array and JSON array aggregation, and the JSON object builders that feed them. |
|
Package arrayop holds the PostgreSQL array predicates: containment, contained-by, overlap and the single-bind "= ANY" membership test.
|
Package arrayop holds the PostgreSQL array predicates: containment, contained-by, overlap and the single-bind "= ANY" membership test. |
|
Package cli is the momo command line tool as a library.
|
Package cli is the momo command line tool as a library. |
|
cmd
|
|
|
momo
command
Command momo is the momo command line tool.
|
Command momo is the momo command line tool. |
|
momovet
command
Command momovet reports non-constant SQL passed to Momo's raw-SQL functions.
|
Command momovet reports non-constant SQL passed to Momo's raw-SQL functions. |
|
Package dialect describes the SQL language differences between the databases Momo supports.
|
Package dialect describes the SQL language differences between the databases Momo supports. |
|
driver
|
|
|
mysqldriver
Package mysqldriver adapts database/sql on github.com/go-sql-driver/mysql to momo for MySQL 8.4 and 9.7 LTS and MariaDB 11.8 LTS.
|
Package mysqldriver adapts database/sql on github.com/go-sql-driver/mysql to momo for MySQL 8.4 and 9.7 LTS and MariaDB 11.8 LTS. |
|
pgxdriver
Package pgxdriver adapts jackc/pgx v5 to momo.
|
Package pgxdriver adapts jackc/pgx v5 to momo. |
|
sqlitedriver
Package sqlitedriver adapts mattn/go-sqlite3 and sqlite-vec to momo.
|
Package sqlitedriver adapts mattn/go-sqlite3 and sqlite-vec to momo. |
|
sqlitepure
Package sqlitepure adapts the pure-Go SQLite driver modernc.org/sqlite to momo.
|
Package sqlitepure adapts the pure-Go SQLite driver modernc.org/sqlite to momo. |
|
examples
|
|
|
adopt-existing-schema
command
Command adopt-existing-schema reads a database that began as plain SQL (legacy.sql) and was then adopted with `momo migrate baseline`.
|
Command adopt-existing-schema reads a database that began as plain SQL (legacy.sql) and was then adopted with `momo migrate baseline`. |
|
adopt-existing-schema/models
Package models describes a schema that already exists in a database.
|
Package models describes a schema that already exists in a database. |
|
adopt-existing-schema/models/order
Package order holds typed column descriptors and relation descriptors for the Order model.
|
Package order holds typed column descriptors and relation descriptors for the Order model. |
|
adopt-existing-schema/models/user
Package user holds typed column descriptors and relation descriptors for the User model.
|
Package user holds typed column descriptors and relation descriptors for the User model. |
|
crud-zero-null
command
Command crud-zero-null shows insert, select, update and delete, and above all how Momo tells a zero value from NULL from "leave it alone".
|
Command crud-zero-null shows insert, select, update and delete, and above all how Momo tells a zero value from NULL from "leave it alone". |
|
crud-zero-null/models
Package models is the schema of the crud-zero-null example: one table of tasks that shows how a write tells zero from NULL from "not mentioned".
|
Package models is the schema of the crud-zero-null example: one table of tasks that shows how a write tells zero from NULL from "not mentioned". |
|
crud-zero-null/models/task
Package task holds typed column descriptors and relation descriptors for the Task model.
|
Package task holds typed column descriptors and relation descriptors for the Task model. |
|
custom-sql-migration
command
Command custom-sql-migration looks accounts up by email, ignoring case, on a database whose migrations (generated and hand-written) are applied.
|
Command custom-sql-migration looks accounts up by email, ignoring case, on a database whose migrations (generated and hand-written) are applied. |
|
custom-sql-migration/models
Package models is the schema of the custom-sql-migration example.
|
Package models is the schema of the custom-sql-migration example. |
|
custom-sql-migration/models/account
Package account holds typed column descriptors and relation descriptors for the Account model.
|
Package account holds typed column descriptors and relation descriptors for the Account model. |
|
internal/exampletest
Package exampletest is the harness every examples/<name> test uses.
|
Package exampletest is the harness every examples/<name> test uses. |
|
projection-pagination
command
Command projection-pagination shows how to read only the columns a screen needs, page through a large table with a keyset cursor, and count.
|
Command projection-pagination shows how to read only the columns a screen needs, page through a large table with a keyset cursor, and count. |
|
projection-pagination/models
Package models is the schema of the projection-pagination example: a table of articles, plus two small result types that read only some of its columns.
|
Package models is the schema of the projection-pagination example: a table of articles, plus two small result types that read only some of its columns. |
|
projection-pagination/models/article
Package article holds typed column descriptors and relation descriptors for the Article model.
|
Package article holds typed column descriptors and relation descriptors for the Article model. |
|
quickstart
command
Command quickstart is the compiled source of the snippets in the root README.
|
Command quickstart is the compiled source of the snippets in the root README. |
|
quickstart/models
Package models is the schema of the quickstart: authors and their posts, each post carrying an embedding for similarity search.
|
Package models is the schema of the quickstart: authors and their posts, each post carrying an embedding for similarity search. |
|
quickstart/models/author
Package author holds typed column descriptors and relation descriptors for the Author model.
|
Package author holds typed column descriptors and relation descriptors for the Author model. |
|
quickstart/models/post
Package post holds typed column descriptors and relation descriptors for the Post model.
|
Package post holds typed column descriptors and relation descriptors for the Post model. |
|
relations
command
Command relations shows how to declare relations (see models/models.go), load them without N+1 queries, filter by them, change them and write whole graphs.
|
Command relations shows how to declare relations (see models/models.go), load them without N+1 queries, filter by them, change them and write whole graphs. |
|
relations/models
Package models is the schema of the relations example: authors write documents, documents have comments and are tagged with many tags.
|
Package models is the schema of the relations example: authors write documents, documents have comments and are tagged with many tags. |
|
relations/models/author
Package author holds typed column descriptors and relation descriptors for the Author model.
|
Package author holds typed column descriptors and relation descriptors for the Author model. |
|
relations/models/comment
Package comment holds typed column descriptors and relation descriptors for the Comment model.
|
Package comment holds typed column descriptors and relation descriptors for the Comment model. |
|
relations/models/document
Package document holds typed column descriptors and relation descriptors for the Document model.
|
Package document holds typed column descriptors and relation descriptors for the Document model. |
|
relations/models/tag
Package tag holds typed column descriptors and relation descriptors for the Tag model.
|
Package tag holds typed column descriptors and relation descriptors for the Tag model. |
|
testing
command
Command testing shows how to test application code against a real PostgreSQL database with momotest: a database or a transaction per test, the project's embedded migrations applied, seeded fixtures, and tests that run in parallel.
|
Command testing shows how to test application code against a real PostgreSQL database with momotest: a database or a transaction per test, the project's embedded migrations applied, seeded fixtures, and tests that run in parallel. |
|
testing/models
Package models is the schema of the testing example: bank accounts whose balance the database refuses to take below zero.
|
Package models is the schema of the testing example: bank accounts whose balance the database refuses to take below zero. |
|
testing/models/account
Package account holds typed column descriptors and relation descriptors for the Account model.
|
Package account holds typed column descriptors and relation descriptors for the Account model. |
|
transactions
command
Command transactions shows how to group writes so they all happen or none do: db.Tx, rollback on error, savepoints for a step that may fail, read-only and isolation options, and a retry loop for serialization failures.
|
Command transactions shows how to group writes so they all happen or none do: db.Tx, rollback on error, savepoints for a step that may fail, read-only and isolation options, and a retry loop for serialization failures. |
|
transactions/models
Package models is the schema of the transactions example: bank accounts whose balance the database refuses to take below zero.
|
Package models is the schema of the transactions example: bank accounts whose balance the database refuses to take below zero. |
|
transactions/models/account
Package account holds typed column descriptors and relation descriptors for the Account model.
|
Package account holds typed column descriptors and relation descriptors for the Account model. |
|
upgrade-database
command
Command upgrade-database reads the customers of a database that was upgraded from schema v1 to the latest version with `momo migrate apply`.
|
Command upgrade-database reads the customers of a database that was upgraded from schema v1 to the latest version with `momo migrate apply`. |
|
upgrade-database/models
Package models is the schema of the upgrade-database example, at its latest version.
|
Package models is the schema of the upgrade-database example, at its latest version. |
|
upgrade-database/models/customer
Package customer holds typed column descriptors and relation descriptors for the Customer model.
|
Package customer holds typed column descriptors and relation descriptors for the Customer model. |
|
vector-search
command
Command vector-search shows nearest-neighbour search with pgvector: the column and HNSW index (see models/models.go and the migration), a query ordered by a distance, filters, a limit, and per-search settings.
|
Command vector-search shows nearest-neighbour search with pgvector: the column and HNSW index (see models/models.go and the migration), a query ordered by a distance, filters, a limit, and per-search settings. |
|
vector-search/models
Package models is the schema of the vector-search example: items with an embedding, indexed for nearest-neighbour search.
|
Package models is the schema of the vector-search example: items with an embedding, indexed for nearest-neighbour search. |
|
vector-search/models/item
Package item holds typed column descriptors and relation descriptors for the Item model.
|
Package item holds typed column descriptors and relation descriptors for the Item model. |
|
Package fts holds the PostgreSQL full-text search expressions: to_tsvector, the tsquery builders, the @@ match, ts_rank, ts_rank_cd and ts_headline.
|
Package fts holds the PostgreSQL full-text search expressions: to_tsvector, the tsquery builders, the @@ match, ts_rank, ts_rank_cd and ts_headline. |
|
Package gen implements the momo code generator: it loads model packages with full type information, builds a model graph and emits code.
|
Package gen implements the momo code generator: it loads model packages with full type information, builds a model graph and emits code. |
|
apiquery
Package apiquery holds the request-side helpers the GraphQL, gRPC and OpenAPI generators share: opaque keyset cursors, page-size limits and filters resolved through the generated column allowlist.
|
Package apiquery holds the request-side helpers the GraphQL, gRPC and OpenAPI generators share: opaque keyset cursors, page-size limits and filters resolved through the generated column allowlist. |
|
config
Package config reads momo.yaml and converts it into a gen.Config.
|
Package config reads momo.yaml and converts it into a gen.Config. |
|
fromdb
Package fromdb turns an inspected database schema into Go model source and the schema the matching init snapshot is written from.
|
Package fromdb turns an inspected database schema into Go model source and the schema the matching init snapshot is written from. |
|
graphql
Package graphql generates a GraphQL schema from momo models: Relay connections with keyset cursors, typed filter and order inputs and one query per model.
|
Package graphql generates a GraphQL schema from momo models: Relay connections with keyset cursors, typed filter and order inputs and one query per model. |
|
grpc
Package grpc generates protobuf messages and CRUD/list services from momo models.
|
Package grpc generates protobuf messages and CRUD/list services from momo models. |
|
naming
Package naming maps Go model and field names to SQL identifiers through named presets.
|
Package naming maps Go model and field names to SQL identifiers through named presets. |
|
openapi
Package openapi generates an OpenAPI 3.1 document from momo models.
|
Package openapi generates an OpenAPI 3.1 document from momo models. |
|
tags
Package tags parses the `momo` struct tag grammar: a comma-separated list of `key` or `key:value` options.
|
Package tags parses the `momo` struct tag grammar: a comma-separated list of `key` or `key:value` options. |
|
typemap
Package typemap maps the Go types the generator understands to SQL column types per dialect.
|
Package typemap maps the Go types the generator understands to SQL column types per dialect. |
|
viz
Package viz draws entity-relationship diagrams of momo models or of a migration snapshot, as Mermaid erDiagram text or Graphviz DOT.
|
Package viz draws entity-relationship diagrams of momo models or of a migration snapshot, as Mermaid erDiagram text or Graphviz DOT. |
|
Package importer converts models written for another Go ORM into Momo models.
|
Package importer converts models written for another Go ORM into Momo models. |
|
bun
Package bun reads Bun models from Go source without running it and turns them into importer models plus a report of every behaviour that changes when the project moves to Momo.
|
Package bun reads Bun models from Go source without running it and turns them into importer models plus a report of every behaviour that changes when the project moves to Momo. |
|
ent
Package ent reads an Ent schema package from Go source without running it and turns it into importer models plus a report of every behaviour that changes when the project moves to Momo.
|
Package ent reads an Ent schema package from Go source without running it and turns it into importer models plus a report of every behaviour that changes when the project moves to Momo. |
|
gorm
Package gorm reads GORM models from Go source without running it and turns them into importer models plus a report of every behaviour that changes when the project moves to Momo.
|
Package gorm reads GORM models from Go source without running it and turns them into importer models plus a report of every behaviour that changes when the project moves to Momo. |
|
history
Package history converts the migration history of another tool (Atlas, goose, golang-migrate, Bun) into a Momo migration directory plus the history rows that mark those migrations as applied, so none of them runs again.
|
Package history converts the migration history of another tool (Atlas, goose, golang-migrate, Bun) into a Momo migration directory plus the history rows that mark those migrations as applied, so none of them runs again. |
|
history/atlas
Package atlas reads an Atlas migration directory (<version>_<name>.sql files and atlas.sum) and the atlas_schema_revisions table into a history.Source.
|
Package atlas reads an Atlas migration directory (<version>_<name>.sql files and atlas.sum) and the atlas_schema_revisions table into a history.Source. |
|
history/bun
Package bun reads the SQL migrations of a Bun project and its bun_migrations table into a history.Source.
|
Package bun reads the SQL migrations of a Bun project and its bun_migrations table into a history.Source. |
|
history/golangmigrate
Package golangmigrate reads a golang-migrate directory and its schema_migrations table into a history.Source.
|
Package golangmigrate reads a golang-migrate directory and its schema_migrations table into a history.Source. |
|
history/goose
Package goose reads a goose migration directory and its version table into a history.Source.
|
Package goose reads a goose migration directory and its version table into a history.Source. |
|
history/internal/histutil
Package histutil holds the small helpers the tool-specific history readers share.
|
Package histutil holds the small helpers the tool-specific history readers share. |
|
internal
|
|
|
chunk
Package chunk holds the bind-limit arithmetic that splits a long key list into statements.
|
Package chunk holds the bind-limit arithmetic that splits a long key list into statements. |
|
compat/schemafixture
Package schemafixture holds the helpers the importer fixture modules share: reading the schema a source ORM created, building the schema Momo derives from the imported models through the real generator, and comparing the two with migrate.Diff.
|
Package schemafixture holds the helpers the importer fixture modules share: reading the schema a source ORM created, building the schema Momo derives from the imported models through the real generator, and comparing the two with migrate.Diff. |
|
docscheck
Package docscheck holds the checks that keep the documentation site honest: the navigation lists real pages, every page is reachable, the Go code blocks compile, and the agent guide carries its rules.
|
Package docscheck holds the checks that keep the documentation site honest: the navigation lists real pages, every page is reachable, the Go code blocks compile, and the agent guide carries its rules. |
|
exprtest
Package exprtest holds the render-only fixtures that the tests of a feature package (arrayop, fts, ...) need to see the SQL and arguments of a predicate or expression: a one-column projection row and a DB over the recording fake driver.
|
Package exprtest holds the render-only fixtures that the tests of a feature package (arrayop, fts, ...) need to see the SQL and arguments of a predicate or expression: a one-column projection row and a DB over the recording fake driver. |
|
fakedriver
Package fakedriver is a database-free momo.Driver used by unit tests.
|
Package fakedriver is a database-free momo.Driver used by unit tests. |
|
fkcase
Package fkcase builds the schemas of the foreign key action tests of every migration dialect from models, through the generator's own schema builder, so the tests run the path a user's model takes: the on_delete, on_update and no_constraint tags become foreign keys (or none) before the diff sees them.
|
Package fkcase builds the schemas of the foreign key action tests of every migration dialect from models, through the generator's own schema builder, so the tests run the path a user's model takes: the on_delete, on_update and no_constraint tags become foreign keys (or none) before the diff sees them. |
|
gendocs
Package gendocs writes the parts of the documentation that restate facts the code already holds: which databases are usable, the dialect capability flags, the Go to SQL type table and the dependency versions.
|
Package gendocs writes the parts of the documentation that restate facts the code already holds: which databases are usable, the dialect capability flags, the Go to SQL type table and the dependency versions. |
|
gendocs/cmd/gendocs
command
Command gendocs rewrites the generated blocks of the documentation.
|
Command gendocs rewrites the generated blocks of the documentation. |
|
gendocs/reference
command
Command reference writes docs/reference.md: every exported identifier of the core and feature packages with the first sentence of its doc comment.
|
Command reference writes docs/reference.md: every exported identifier of the core and feature packages with the first sentence of its doc comment. |
|
golden
Package golden compares generated output with golden files.
|
Package golden compares generated output with golden files. |
|
importtest
Package importtest is the shared end-to-end check for history importers.
|
Package importtest is the shared end-to-end check for history importers. |
|
keyenc
Package keyenc encodes relation key tuples as comparable strings.
|
Package keyenc encodes relation key tuples as comparable strings. |
|
obstest
Package obstest is test support for the observability tests.
|
Package obstest is test support for the observability tests. |
|
redact
Package redact masks sensitive query arguments before they reach hooks.
|
Package redact masks sensitive query arguments before they reach hooks. |
|
relfixture
Package relfixture is the shared relation test fixture: models, descriptors (see the momo-06 plan's generator contract) and seeded test databases.
|
Package relfixture is the shared relation test fixture: models, descriptors (see the momo-06 plan's generator contract) and seeded test databases. |
|
relfixture/models
Package models holds the relation fixture's model structs.
|
Package models holds the relation fixture's model structs. |
|
sqliteconf
Package sqliteconf holds the settings type shared by driver/sqlitedriver (cgo, mattn/go-sqlite3) and driver/sqlitepure (pure Go, modernc).
|
Package sqliteconf holds the settings type shared by driver/sqlitedriver (cgo, mattn/go-sqlite3) and driver/sqlitepure (pure Go, modernc). |
|
sqlmask
Package sqlmask hides the text of database/sql conversion failures.
|
Package sqlmask hides the text of database/sql conversion failures. |
|
sqlscan
Package sqlscan tokenizes raw SQL fragments into verbatim text and placeholders.
|
Package sqlscan tokenizes raw SQL fragments into verbatim text and placeholders. |
|
sqlshared
Package sqlshared holds the part of the SQLite adapters that does not depend on the SQLite driver: the momo.Driver implementation over database/sql, transactions, read-only transactions, pinned connections and time scanning.
|
Package sqlshared holds the part of the SQLite adapters that does not depend on the SQLite driver: the momo.Driver implementation over database/sql, transactions, read-only transactions, pinned connections and time scanning. |
|
sqlstub
Package sqlstub opens a database/sql pool over a stub driver that answers every query with one row holding one fixed value.
|
Package sqlstub opens a database/sql pool over a stub driver that answers every query with one row holding one fixed value. |
|
suite
Package suite holds the integration fixtures and the feature suites that every dialect's tests run.
|
Package suite holds the integration fixtures and the feature suites that every dialect's tests run. |
|
testdb
Package testdb returns connection URLs and paths for integration tests.
|
Package testdb returns connection URLs and paths for integration tests. |
|
testdb/testopen
Package testopen opens the integration-test databases as *momo.DB.
|
Package testopen opens the integration-test databases as *momo.DB. |
|
testmodels/example
Package example is the reference schema for momo: a multi-tenant document store with comments, tags and a pgvector embedding.
|
Package example is the reference schema for momo: a multi-tenant document store with comments, tags and a pgvector embedding. |
|
testmodels/example/comment
Package comment holds typed column descriptors and relation descriptors for the Comment model.
|
Package comment holds typed column descriptors and relation descriptors for the Comment model. |
|
testmodels/example/document
Package document holds typed column descriptors and relation descriptors for the Document model.
|
Package document holds typed column descriptors and relation descriptors for the Document model. |
|
testmodels/example/tag
Package tag holds typed column descriptors and relation descriptors for the Tag model.
|
Package tag holds typed column descriptors and relation descriptors for the Tag model. |
|
testmodels/example/tenant
Package tenant holds typed column descriptors and relation descriptors for the Tenant model.
|
Package tenant holds typed column descriptors and relation descriptors for the Tenant model. |
|
vectorparity
Package vectorparity holds the dataset and the exact reference that the vector parity tests share, so that PostgreSQL pgvector and MariaDB are both held to one answer computed in plain Go.
|
Package vectorparity holds the dataset and the exact reference that the vector parity tests share, so that PostgreSQL pgvector and MariaDB are both held to one answer computed in plain Go. |
|
Package jsonop holds the JSON operators over types.JSON[T] columns (jsonb on PostgreSQL): text extraction, nested paths, containment and key tests.
|
Package jsonop holds the JSON operators over types.JSON[T] columns (jsonb on PostgreSQL): text extraction, nested paths, containment and key tests. |
|
Package migrate runs schema migrations.
|
Package migrate runs schema migrations. |
|
migratetest
Package migratetest holds helpers shared by the migrate engine tests.
|
Package migratetest holds helpers shared by the migrate engine tests. |
|
mysql
Package mysql is the MySQL and MariaDB migration dialect: it reads a live database into a schema.Schema through information_schema, renders DDL, and serializes migration runs with GET_LOCK.
|
Package mysql is the MySQL and MariaDB migration dialect: it reads a live database into a schema.Schema through information_schema, renders DDL, and serializes migration runs with GET_LOCK. |
|
postgres
Package postgres is the PostgreSQL migration dialect: it reads a live database into a schema.Schema through catalog queries.
|
Package postgres is the PostgreSQL migration dialect: it reads a live database into a schema.Schema through catalog queries. |
|
sqlite
Package sqlite is the SQLite migration dialect: it reads a live database into a schema.Schema through the SQLite catalog (sqlite_schema and the table-valued pragmas), renders a change plan as SQLite DDL, and rebuilds a table with the twelve-step procedure of https://www.sqlite.org/lang_altertable.html#otheralter when ALTER TABLE cannot make the change.
|
Package sqlite is the SQLite migration dialect: it reads a live database into a schema.Schema through the SQLite catalog (sqlite_schema and the table-valued pragmas), renders a change plan as SQLite DDL, and rebuilds a table with the twelve-step procedure of https://www.sqlite.org/lang_altertable.html#otheralter when ALTER TABLE cannot make the change. |
|
Package momolog provides a log/slog hook for Momo.
|
Package momolog provides a log/slog hook for Momo. |
|
Package momotest gives an application's tests a real PostgreSQL database with the project's migrations applied, isolated per test.
|
Package momotest gives an application's tests a real PostgreSQL database with the project's migrations applied, isolated per test. |
|
sqlitetest
Package sqlitetest gives an application's tests an ephemeral SQLite database: a new file in the test's own temporary directory, opened through driver/sqlitedriver (mattn/go-sqlite3 with sqlite-vec), closed and deleted when the test ends.
|
Package sqlitetest gives an application's tests an ephemeral SQLite database: a new file in the test's own temporary directory, opened through driver/sqlitedriver (mattn/go-sqlite3 with sqlite-vec), closed and deleted when the test ends. |
|
Package momovet provides a go/analysis analyzer that reports SQL text built at run time and passed to Momo's raw-SQL functions.
|
Package momovet provides a go/analysis analyzer that reports SQL text built at run time and passed to Momo's raw-SQL functions. |
|
Package obs holds ready-made observability hooks for Momo: a Recorder that keeps every statement and relation load, an NPlusOne detector that reports a relation loaded once per row, and a slow-query hook (NewSlowQuery) that can capture a plain EXPLAIN plan.
|
Package obs holds ready-made observability hooks for Momo: a Recorder that keeps every statement and relation load, an NPlusOne detector that reports a relation loaded once per row, and a slow-query hook (NewSlowQuery) that can capture a plain EXPLAIN plan. |
|
Package schema is Momo's normalized, dialect-aware schema representation.
|
Package schema is Momo's normalized, dialect-aware schema representation. |
|
Package sqlfn holds the typed scalar SQL functions and operators: Substr, Lower, Upper, Length, CurrentSchema, Case, the arithmetic helpers Add, Sub and Mul, CoalesceExpr, Cast and Concat.
|
Package sqlfn holds the typed scalar SQL functions and operators: Substr, Lower, Upper, Length, CurrentSchema, Case, the arithmetic helpers Add, Sub and Mul, CoalesceExpr, Cast and Concat. |
|
Package timeop holds the typed date and time expressions: Extract, AtTimeZone, intervals with AddInterval and SubInterval, Now, CurrentTimestamp, ClockTimestamp, StatementTimestamp and Trunc.
|
Package timeop holds the typed date and time expressions: Extract, AtTimeZone, intervals with AddInterval and SubInterval, Now, CurrentTimestamp, ClockTimestamp, StatementTimestamp and Trunc. |
|
Package types holds the custom column types Momo understands: each is a Codec, so database/sql can scan it, drivers can bind it and the schema layer can name its SQL type per dialect.
|
Package types holds the custom column types Momo understands: each is a Codec, so database/sql can scan it, drivers can bind it and the schema layer can name its SQL type per dialect. |
|
Package vecop holds the vector distance builders: L2, InnerProduct, Cosine, L1, Hamming and Jaccard.
|
Package vecop holds the vector distance builders: L2, InnerProduct, Cosine, L1, Hamming and Jaccard. |
|
Package vecsearch applies pgvector search settings (hnsw and ivfflat) to one transaction.
|
Package vecsearch applies pgvector search settings (hnsw and ivfflat) to one transaction. |
|
Package vector holds the vector value types.
|
Package vector holds the vector value types. |