operation

package
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Aug 28, 2026 License: Apache-2.0 Imports: 4 Imported by: 0

Documentation

Overview

Package operation is the base module's contract layer: constructors shaped by what a consumer means to do, lowering to rendered statements from the ast package's vocabulary. The query side is a Projection of name-to-expression fields with its two queries — Projection.List lowers Directives of page, sort, and operator-keyed filters into a count-and-page pair over one WHERE clause, and Projection.One forms the single-row read. The command side is Insertion, GuardedUpdate, and GuardedDelete: the identity-returning insert and the two optimistic-concurrency commands, each lowering through its SQL method. The exec package runs what this layer produces.

The field contract

Directives reference a projection's field names, never SQL. An unknown name or operator is a typed error — UnknownFieldError, UnknownOperatorError — the consumer maps to its own response, and the projection's key field joins every ORDER BY as the tie-breaker, so offset paging is stable.

The guard contract

A guarded command matches its row by key and expected version and increments the version itself, so the new version is deterministic. The Guard names the consumer's version column — the library fixes the mechanism, never the schema — and the Guarded pair keeps the contract in pure standard SQL: the command first, the check only when no row was touched, splitting not-found from version-mismatch. Insertion is the one command needing a dialect capability: its returning clause renders only through ast.ReturningRenderer and fails typed without it.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Columns

func Columns(prefix string, names []string, extra ...ast.Column) []ast.Column

Columns builds a select list from column names under one table prefix, with extra appended for computed columns. An empty prefix renders bare names.

Types

type Directives

type Directives struct {
	Page    Page
	Sort    []Sort
	Filters []Filter
	Where   ast.Predicate
}

Directives is one read request against a projection. Filters and Sort reference projected field names — an unknown name is an UnknownFieldError, never SQL. Where optionally carries a composed [Predicate] beyond the field vocabulary, ANDed with the filters: the door back down to the composition core.

type Field

type Field struct {
	Name string
	Expr ast.Expression
}

Field is the contract layer's shared field vocabulary: a contract name and the expression that computes it. Both CQRS sides speak it — a projection's key and fields on the query side, a command's identity on the command side.

func Fields

func Fields(names []string) []Field

Fields builds projected fields whose contract names are their column names.

type FieldUse

type FieldUse string

FieldUse names the directive position where a projected field was referenced, carried by UnknownFieldError.

const (
	FieldUseSort   FieldUse = "sort"
	FieldUseFilter FieldUse = "filter"
)

type Filter

type Filter struct {
	Field string
	Op    Op
	Value any
}

Filter is one filter directive: a projected field name, an operator, and the value. OpIsNull and OpIsNotNull ignore Value; OpIn requires Value to be a []any.

type Guard

type Guard struct {
	Column  string
	Version int64
}

Guard is the optimistic-concurrency spec: the consumer's version column — a schema decision the library never fixes — and the version the caller expects. Within a guarded command the contract manages that column exclusively: the guard appends the increment itself and rejects a caller assignment to it, which is what makes the new version deterministic.

type Guarded

type Guarded struct {
	Command ast.SQL
	Check   ast.SQL
}

Guarded is a guarded command's envelope: the command statement, run first, and the check statement, run only when the command touched no row, splitting not-found from version-mismatch. Both are pure standard SQL; the runner in the exec package is the contract and this portable pair sits behind it.

type GuardedDelete

type GuardedDelete struct {
	Table string
	Key   Field
	ID    any
	Guard Guard
}

GuardedDelete is the guarded delete command: the row goes only when both the key and the expected version match.

func (GuardedDelete) SQL

func (del GuardedDelete) SQL(d database.Dialect) (Guarded, error)

SQL lowers the command to its Guarded pair.

type GuardedUpdate

type GuardedUpdate struct {
	Table string
	Key   Field
	ID    any
	Guard Guard
	Set   []ast.Assignment
}

GuardedUpdate is the guarded update command: SET under the key and version guard, the version increment appended by the guard itself.

func (GuardedUpdate) SQL

SQL lowers the command to its Guarded pair.

type Insertion

type Insertion struct {
	Into     string
	Values   []ast.Assignment
	Identity Field
	Version  Field
}

Insertion is the identity-returning insert command: one row of values, with the engine handing back the caller-named identity and version fields it minted. It lowers through the write statements' Returning clause, so it requires a dialect implementing ast.ReturningRenderer and fails typed otherwise. Which columns exist, including what the version column is called, is the consumer's schema decision.

func (Insertion) SQL

func (i Insertion) SQL(d database.Dialect) (ast.SQL, error)

SQL lowers the command to its statement: INSERT with one bound row, returning the identity and version aliased to their contract names — the scan order a runner reads them in.

type List

type List struct {
	Count ast.SQL
	Page  ast.SQL
}

List is the list query's envelope: the count and page statements over one shared WHERE clause. The consumer runs both — Count for the total, Page for the rows — and they can never disagree.

type Op

type Op string

Op is a filter directive's operator. The values are short strings so a read contract can carry them verbatim.

const (
	OpEq        Op = "eq"
	OpNe        Op = "ne"
	OpGt        Op = "gt"
	OpGe        Op = "ge"
	OpLt        Op = "lt"
	OpLe        Op = "le"
	OpLike      Op = "like"
	OpIsNull    Op = "null"
	OpIsNotNull Op = "notnull"
	OpIn        Op = "in"
)

type Page

type Page struct {
	Number int
	Size   int
}

Page is the 1-based page directive of a read: which page, and how many rows per page. Both fields must be at least 1.

type Projection

type Projection struct {
	With   []ast.CTE
	From   ast.TableRef
	Key    Field
	Fields []Field
}

Projection is a read model over one FROM: name-to-expression fields, one key field, and the CTEs the FROM references. It is plain data; every read against it goes through the query operations Projection.List and Projection.One. The key field is the identity a read pages by — it joins every ORDER BY as the tie-breaker, so offset paging is stable. CTEs declared here hoist to the top of every generated statement, the one placement every engine accepts.

func (Projection) List

func (p Projection) List(d database.Dialect, dir Directives) (List, error)

List forms the list query, lowering the directives onto the projection: field names resolve to expressions or fail with UnknownFieldError, filters become the shared WHERE clause, sorts gain the key tie-breaker whenever the caller didn't sort by it, and the page directive becomes bound offset/fetch arguments.

func (Projection) One

func (p Projection) One(d database.Dialect, field string, value any) (ast.SQL, error)

One forms the single-row query: the full projection under one equality filter on a projected field, with no ordering, no paging, and no count. An unknown field is an UnknownFieldError. When the filtered field is not unique, the first row wins; execution outcomes, sql.ErrNoRows included, belong to the runner.

type RecursivePath

type RecursivePath struct {
	Table     string
	Key       string
	Parent    string
	Segment   string
	Field     string
	Separator string
	Rooted    bool
	Columns   []string
}

RecursivePath is a computed-field pattern: a self-referencing table whose rows compose a path by walking the parent chain — Segment joined by Separator, prefixed with it when Rooted ("/acme/engineering"; unrooted, "v1.data.reads"). Parent names the self-reference, Key the column it joins, and Columns the carried set, Key included, in scan order.

func (RecursivePath) Projection

func (r RecursivePath) Projection() Projection

Projection builds the pattern's whole read model: a recursive CTE (standard SQL:1999) re-presenting the table with Field as one extra column, and the projection reading from it — Key first, the carried columns, Field last. The pattern owns the full projection because the CTE replaces the FROM and already requires every input the projection needs; a consumer composing several computed fields would decompose this into projection transformers each contributing a CTE and a field, a seam recorded in the design notes and not yet built. An empty Separator panics as a wiring mistake.

type Sort

type Sort struct {
	Field      string
	Descending bool
}

Sort is one sort directive, naming a projected field.

type UnknownFieldError

type UnknownFieldError struct {
	Field string
	Use   FieldUse
}

UnknownFieldError reports a sort or filter directive naming a field the projection does not declare. It is the field contract's boundary: the name never reaches the SQL, and a consumer maps the error to its own response with errors.As.

func (*UnknownFieldError) Error

func (e *UnknownFieldError) Error() string

type UnknownOperatorError

type UnknownOperatorError struct {
	Op Op
}

UnknownOperatorError reports a filter directive carrying an operator the vocabulary does not define, mapped by the consumer the same way as UnknownFieldError.

func (*UnknownOperatorError) Error

func (e *UnknownOperatorError) Error() string

Jump to

Keyboard shortcuts

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