stmt

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 11, 2026 License: Apache-2.0 Imports: 8 Imported by: 0

README

stmt — statements, clauses and Query

SELECT, INSERT, UPDATE and DELETE, the clause slots that let a package outside this module add a clause, and the Query a statement builds to.

A builder method returns a derived statement and never writes to its receiver. base.Where(x) leaves base alone, so deriving several queries from one template is safe by construction rather than by remembering Clone. And a write cannot be built until it is complete: an unfiltered UPDATE has no Build method at all, so it does not compile. Both are pinned by tests that were verified by breaking them.

Full documentation

The page for this package is docs/stmt/README.md, with runnable snippets — every one of them copied from a test whose expected output go test checks. The documentation index is ../docs/README.md and the repository README is ../README.md.

Documentation

Overview

Package stmt assembles SQL statements: SELECT, INSERT, UPDATE and DELETE, the clause positions they can carry, and the Query a build produces.

It knows the grammar and nothing about meaning. A Predicate is something that can render itself, and this package writes it after WHERE without knowing what it compares; a Clause is something that names a Slot, and this package writes it at that position without knowing what it says. That is what lets an engine package add a construct, and an outside package add a whole statement kind, with no change here.

This is also the highest layer that is still purely about text. A Query is a string and a slice of values; how those values come back into Go is the concern of the layers above.

Index

Constants

View Source
const (
	OpEq     = expr.OpEq
	OpIn     = expr.OpIn
	OpNotIn  = expr.OpNotIn
	LogicAnd = expr.LogicAnd
	SortAsc  = expr.SortAsc
	SortDesc = expr.SortDesc
)

The operator and sort vocabulary this layer emits. Constants cannot be aliased, so each is a new constant with the same value.

Variables

View Source
var (
	// ErrNoColumns is returned by a SELECT with no bindings and no
	// expressions. There is nothing to select.
	ErrNoColumns = errors.New("sqlb: select has no columns")

	// ErrJoinWithoutFrom is returned when a statement has joins but no
	// driving source to join them to.
	ErrJoinWithoutFrom = errors.New("sqlb: select has joins but no FROM")

	// ErrDuplicateAlias is returned when two sources in one statement share
	// an alias. Rendering it would produce a statement whose column
	// references are ambiguous, which the database reports far less clearly.
	ErrDuplicateAlias = errors.New("sqlb: duplicate table alias in one statement")

	// ErrNoTargets is returned when One or Each is given a query whose select
	// list has items with no scan target. Such a query was built with Exprs
	// and is meant for use as a subquery, not for execution.
	ErrNoTargets = errors.New("sqlb: query has select items without scan targets")
)
View Source
var (
	// ErrNotAColumn is returned when an assignment target or an INSERT column
	// list holds something other than a bare column made by Col. An
	// expression has no name to assign to, and rendering it as an empty
	// identifier would produce SQL the database rejects much later.
	ErrNotAColumn = errors.New("sqlb: assignment target is not a column")

	// ErrNoAssignments is returned by an UPDATE with nothing to SET, or an
	// INSERT with neither rows nor a source query. There is nothing to write.
	ErrNoAssignments = errors.New("sqlb: statement has no assignments")

	// ErrNoWhere is returned by an UPDATE or DELETE with no WHERE and no
	// All(). The whole table is a real target, but it must be said out loud,
	// because the cost of the accidental case is the entire table.
	ErrNoWhere = errors.New("sqlb: update or delete has no WHERE; call All() to affect every row")

	// ErrRowWidth is returned when an INSERT row has a different number of
	// values from the column list. The builder cannot know which value was
	// meant for which column, so it refuses rather than aligning by position.
	ErrRowWidth = errors.New("sqlb: insert row width differs from column list")
)
View Source
var ErrNoReturning = errors.New("sqlb: dialect has no RETURNING; use the two-statement fallback")

ErrNoReturning is returned when RETURNING was requested on a dialect that does not have it. The message names the fallback: insert, then select.

View Source
var ErrQueryInUse = errors.New("sqlb: query is already executing; build it where its scan targets live rather than sharing one")

ErrQueryInUse is returned by One and Each when a statement is executed while the same statement is already executing.

It means a DATA RACE was about to happen: a Query is not safe for concurrent use, and executing one from two goroutines is a race condition on its scan targets. Go's race detector reports it as a data race on the bound variables, and `go test -race` is how you would otherwise find this.

Why this is an error and not a lock: a Query looks like inert data, a string and some values, and that reading is what makes the mistake easy. It is not inert. Targets holds pointers into the caller's variables, so two goroutines running one Query write to the same memory, and the result is interleaved rows rather than a crash. Serialising them with a lock would hide that: the second caller would get the first caller's rows in its own variables and never know. Refusing says what actually happened.

The fix at the call site is to build the query where its destination lives, which is what the cookbook recipes do, rather than hoisting one query or one builder to package scope and sharing it.

View Source
var ErrSetOpArity = errors.New("sqlb: set operation branches select different numbers of columns")

ErrSetOpArity reports that the branches of a set operation select different numbers of columns, which every engine refuses.

Build fails rather than the server, because the message a caller gets back otherwise describes SQL they did not write: scan.All and exec's binding append the reader's columns to the statement they are given, which is the left branch, so a left branch that also declares its own select list ends up one column wider than the right. The engine then reports a mismatch against a query the caller never typed.

View Source
var ErrUnknownSlot = errors.New("sqlb: clause asks for a slot this statement does not render")

ErrUnknownSlot is returned when a statement carries a clause for a slot that statement does not render.

Why it is an error and not a shrug: a clause in an unrendered slot used to vanish, producing a statement that built cleanly and silently omitted what the caller asked for. That is the one failure shape this package exists to prevent, and it is reachable from outside the module, where a third-party dialect cannot add a slot of its own. Failing closed turns a missing clause into a message naming the slot.

View Source
var ErrUnsupportedDialect = render.ErrUnsupportedDialect

ErrUnsupportedDialect is returned by Build when a construct was rendered through a dialect that does not support it.

JoinTypeValues is the canonical iteration order over join types.

SlotValues lists every slot.

Functions

func DialectName

func DialectName(d Dialect) string

DialectName reports the engine name of d, or DialectUnknown.

func EngineGuard

func EngineGuard(a *Args, engine, construct string) bool

EngineGuard reports whether a is rendering for engine, and records the construct as unsupported when it is not.

It is the one place the guard rule lives. A constructor calls it first and returns an empty fragment on false; Build then fails with ErrUnsupportedDialect naming the construct and the dialect it met.

func EngineList

func EngineList(a *Args, items []SQLer) string

EngineList renders SQLers comma-separated, for a constructor assembling its own argument list.

func QuoteList

func QuoteList(d Dialect, names []string) string

QuoteList renders identifiers comma-separated and quoted for the dialect.

func Targets

func Targets(bs []Binding) []any

Targets returns the scan destinations of a binding list, in order.

A nil result when the list is empty is deliberate: Query.Targets being nil is what One and Each check to report ErrNoTargets, and an empty non-nil slice would pass that check while scanning nothing.

Types

type AnyClause

type AnyClause interface {
	Slot() Slot
	WriteSQL(b *strings.Builder, args *Args)
}

AnyClause is a statement part that is neither an expression nor a predicate, with no dialect or kind in its type: what a Join carries for a per-table hint, and what every typed Clause also satisfies. It is an open interface, like Predicate, so an engine package can add one without a method per clause on Select. A clause must call Args.Unsupported when rendered through a dialect it does not belong to.

type AnySelect

type AnySelect = Select[render.Dialect]

AnySelect is a Select whose engine is only known at runtime. It accepts every universal construct and no engine clause, which is exactly what a portable library should be building.

type Args

type Args = render.Args

Args collects bound values during one render and carries the first error.

func NewArgs

func NewArgs(d Dialect) *Args

NewArgs starts an empty argument list for d.

type Assignment

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

Assignment is one column = value pair for INSERT and UPDATE. Built with Set, SetExpr or SetDefault, so the value type matches the column type.

func AssignTarget

func AssignTarget(col string, target func(a *Args) string, value SQLer) Assignment

AssignTarget makes an assignment whose target is an expression over col, for engine packages: doc['customer']['tier'] = value. col is the base column, kept for the INSERT column list and for error messages.

func Set

func Set[T any](col Expr[T], v T) Assignment

Set assigns a bound value to a column of the same Go type.

func SetDefault

func SetDefault[T any](col Expr[T]) Assignment

SetDefault assigns DEFAULT.

func SetExpr

func SetExpr[T any](col Expr[T], e Expr[T]) Assignment

SetExpr assigns an expression of the column's type: SET n = n + 1.

func (Assignment) Column

func (as Assignment) Column() string

Column returns the target column name.

This accessor and the two below exist for the engine packages: ON CONFLICT and MERGE render assignments outside the core's UPDATE and need the parts separately, which is the only reason an Assignment is not opaque.

func (Assignment) SQL

func (as Assignment) SQL(a *Args) string

SQL renders the whole assignment, "column = value".

func (Assignment) ValueSQL

func (as Assignment) ValueSQL(a *Args) string

ValueSQL renders the assigned value alone, without the column or the equals.

type Binding

type Binding interface {
	// SQL renders the item.
	SQL(a *Args) string
	// Target is the scan destination, or nil when the item has none.
	Target() any
	// ColumnName is the bare column name when the item came from a column, and
	// "" otherwise. RETURNING on an unaliased INSERT renders it.
	ColumnName() string
}

Binding is a select or RETURNING item that carries a scan destination.

It is an interface, and that is the whole point of this file. The statement layer has to put something in Query.Targets, but it must not know that the something is a pointer into a caller's variable: the moment it does, the hazard belongs to this layer, and a second result strategy has to fight a statement that already took an opinion.

So the statement layer knows only that an item renders, may carry a target, and may know its own bare column name. Whether the target is a pointer, a channel, a slot in an arena, or nil is decided above, by whichever package constructs the item. github.com/ubgo/sqlb/bind is the one that makes it a pointer, and it is where the concurrency warning lives because it is the layer that captured the memory.

Being an interface rather than a struct is also what kept the split from breaking callers. Every existing use was a slice of Binding values produced by Bind, never a struct literal, so the same code compiles against the interface unchanged.

type CTE

type CTE struct {
	Name    string
	Columns []string
	Body    Statement
	Prefix  SQLer
	// Suffix renders after the body's closing parenthesis, for the SEARCH
	// and CYCLE clauses of a recursive CTE.
	Suffix SQLer
	// contains filtered or unexported fields
}

CTE is one common table expression. Columns renders the optional column list. Prefix renders between AS and the body, for engine words such as MATERIALIZED; the core renders it and an engine package decides it.

type Clause

type Clause[D render.Dialect, K any] interface {
	AnyClause
	ClauseOf(D, K)
}

Clause is a clause typed to the dialect D it belongs to and the statement kind K it may appear in.

Both parameters are phantom, and the marker method is what makes them bite: an interface whose type parameters appeared nowhere in its method set would be satisfied by every clause for every instantiation, and the check would be decoration. Because ClauseOf names D and K, a value built for Postgres and SELECT satisfies exactly Clause[postgres.Dialect, SelectKind], so a Select for SQLite refuses it at compile time and an Update for Postgres refuses it too. The method does nothing; its signature is the whole point.

EngineClause is how one is made. A package outside this module builds clauses for its own dialect through the same factory, and a statement of its own declares its own kind beside it: the kind set is open like the dialect set, and nothing engine-specific enters this package's list.

func EngineClause

func EngineClause[D render.Dialect, K any](construct string, slot Slot, render func(a *Args) string) Clause[D, K]

EngineClause makes a guarded clause for a statement slot.

A statement that does not render the given slot fails at Build with ErrUnknownSlot, so a clause aimed at a position a statement does not have is reported rather than dropped.

D is the dialect the clause belongs to and K the statement kind it may appear in; both are type arguments written once, in the engine package, and never in user code. The engine name the runtime guard compares against is derived from D, so there is no string to misspell and no way to register a clause under one engine and use it from another. The guard stays as belt-and-braces: a statement typed to D can only hold a Clause[D, K], so it never fires for a clause that reached its statement through the types.

D must be usable as a zero value — a plain struct, as every dialect here is. A dialect that is an interface type yields no name and the guard refuses at Build, which is right: an engine clause on a statement whose engine is not statically known has already been refused by the compiler.

type Delete

type Delete[D render.Dialect] struct {
	// contains filtered or unexported fields
}

Delete is a DELETE whose target rows are not yet stated. It has no Build method. Where and All each return a FilteredDelete, which does.

func NewDelete

func NewDelete[D render.Dialect](d D) *Delete[D]

NewDelete starts a DELETE for d.

func (*Delete[D]) All

func (x *Delete[D]) All() *FilteredDelete[D]

All says the whole table is the target and completes the statement, which is what makes a DELETE with no WHERE deliberate rather than an omission.

func (*Delete[D]) Clause

func (x *Delete[D]) Clause(cs ...Clause[D, DeleteKind]) *Delete[D]

Clause adds an engine clause, such as pg.DeleteUsing in SlotAfterTarget.

func (*Delete[D]) Clone

func (x *Delete[D]) Clone() *Delete[D]

Clone returns an independent copy with its own execution guard.

func (*Delete[D]) Dialect

func (x *Delete[D]) Dialect() Dialect

Dialect reports the dialect this statement renders for, so an Option or a helper can branch on the engine without the caller threading it through.

func (*Delete[D]) From

func (x *Delete[D]) From(t Table) *Delete[D]

From names the table to delete from.

func (*Delete[D]) Where

func (x *Delete[D]) Where(ps ...Predicate) *FilteredDelete[D]

Where states the target rows and completes the statement.

func (*Delete[D]) With

func (x *Delete[D]) With(name string, body Statement) *Delete[D]

With attaches a CTE, for "delete the rows this query found".

type DeleteKind

type DeleteKind struct{}

DeleteKind marks a clause for DELETE.

type Dialect

type Dialect = render.Dialect

Dialect is how an engine writes a placeholder and quotes an identifier.

type Expr

type Expr[T any] = expr.Expr[T]

Expr is a SQL expression evaluating to the Go type T.

func EngineBinOp

func EngineBinOp[R any](engine, construct, op string, l, r SQLer) Expr[R]

EngineBinOp renders "(left op right)" as a guarded expression typed R.

The parentheses matter. Without them an engine operator nested inside a core one takes its meaning from the engine's precedence table rather than from the author's nesting: pg.BitAnd inside expr.Mul rendered "tag & $1 * $2", which Postgres reads as tag & (16 * 2) because * binds tighter than &. That is valid SQL returning the wrong rows, which is the worst shape a bug can take. Pinned by TestEngineBinOp_NestsCorrectly. op is checked for the shape of an operator rather than against a list, for the reason expr.Binary's is: the operators an engine has come from its extensions, and a list here would refuse a valid one. An extension author writing a helper is still the one choosing the operator; what the shape stops is a payload that closes the expression and appends a statement.

func EngineExpr

func EngineExpr[T any](engine, construct string, render func(a *Args) string) Expr[T]

EngineExpr makes a guarded expression typed T from a render function. It is the general case; the constructors below are the shapes that recur.

func EngineFn

func EngineFn[R any](engine, construct, name string, args ...SQLer) Expr[R]

EngineFn renders a guarded function call typed R.

func EngineLit

func EngineLit[T any](engine, construct, sql string) Expr[T]

EngineLit makes a guarded expression from a constant fragment.

Use it rather than Literal for anything only one engine accepts. Literal has no dialect to consult, so a constant such as '{}'::jsonb built on it renders under every dialect and is rejected by the database instead of by Build.

func New

func New[T any](f func(a *Args) string) Expr[T]

New makes a typed expression from a render function.

func Param

func Param[T any](v T) Expr[T]

Param binds a Go value as an expression of its own type.

func Subquery

func Subquery[T any, D render.Dialect](s *Select[D]) Expr[*T]

Subquery uses a Select as a scalar expression: (SELECT ...). The author states the type; the result is nullable because a subquery that returns no row yields NULL.

type FilteredDelete

type FilteredDelete[D render.Dialect] struct {
	// contains filtered or unexported fields
}

FilteredDelete is a DELETE whose target rows are stated — by a WHERE or by All — and can therefore be built. Build lives here and not on Delete, for the reason given on FilteredUpdate.

func DeleteReturning

func DeleteReturning[D ReturningDialect](s *FilteredDelete[D], bs ...Binding) *FilteredDelete[D]

DeleteReturning adds RETURNING with scan targets to a DELETE, so the deleted rows can be read back in the same statement.

func (*FilteredDelete[D]) Build

func (x *FilteredDelete[D]) Build() (Query, error)

Build renders the statement, or returns the first error it found. The scan targets come from the RETURNING bindings, so One and Each work on the result without a second list.

func (*FilteredDelete[D]) Clause

func (x *FilteredDelete[D]) Clause(cs ...Clause[D, DeleteKind]) *FilteredDelete[D]

Clause adds an engine clause.

func (*FilteredDelete[D]) Clone

func (x *FilteredDelete[D]) Clone() *FilteredDelete[D]

Clone returns an independent copy of the DELETE with its own guard.

func (*FilteredDelete[D]) Dialect

func (x *FilteredDelete[D]) Dialect() Dialect

Dialect reports the dialect this statement renders for.

func (*FilteredDelete[D]) Where

func (x *FilteredDelete[D]) Where(ps ...Predicate) *FilteredDelete[D]

Where adds predicates, joined with AND.

func (*FilteredDelete[D]) With

func (x *FilteredDelete[D]) With(name string, body Statement) *FilteredDelete[D]

With attaches a CTE.

func (*FilteredDelete[D]) WriteSQL

func (x *FilteredDelete[D]) WriteSQL(b *strings.Builder, args *Args)

WriteSQL renders the DELETE into b. It satisfies Statement, which is what lets this statement be the body of a CTE in another one.

type FilteredUpdate

type FilteredUpdate[D render.Dialect] struct {
	// contains filtered or unexported fields
}

FilteredUpdate is an UPDATE whose target rows are stated — by a WHERE or by All — and can therefore be built.

Build lives here and not on Update, so an UPDATE with no WHERE does not compile into existence. That sentence was the task list's day-one promise; it shipped as ErrNoWhere at Build, and this is what makes it true. A value made as a struct literal has no predicate, no table and no dialect and is rejected at Build, which is the documented literal hole.

func UpdateReturning

func UpdateReturning[D ReturningDialect](s *FilteredUpdate[D], bs ...Binding) *FilteredUpdate[D]

UpdateReturning adds RETURNING with scan targets to an UPDATE.

func (*FilteredUpdate[D]) Build

func (u *FilteredUpdate[D]) Build() (Query, error)

Build renders the statement, or returns the first error it found. The scan targets come from the RETURNING bindings, so One and Each work on the result without a second list.

func (*FilteredUpdate[D]) Clause

func (u *FilteredUpdate[D]) Clause(cs ...Clause[D, UpdateKind]) *FilteredUpdate[D]

Clause adds an engine clause.

func (*FilteredUpdate[D]) Clone

func (u *FilteredUpdate[D]) Clone() *FilteredUpdate[D]

Clone returns an independent copy of the UPDATE with its own guard.

func (*FilteredUpdate[D]) Dialect

func (u *FilteredUpdate[D]) Dialect() Dialect

Dialect reports the dialect this statement renders for.

func (*FilteredUpdate[D]) Set

func (u *FilteredUpdate[D]) Set(as ...Assignment) *FilteredUpdate[D]

Set adds assignments.

func (*FilteredUpdate[D]) Where

func (u *FilteredUpdate[D]) Where(ps ...Predicate) *FilteredUpdate[D]

Where adds predicates, joined with AND.

func (*FilteredUpdate[D]) With

func (u *FilteredUpdate[D]) With(name string, body Statement) *FilteredUpdate[D]

With attaches a CTE.

func (*FilteredUpdate[D]) WriteSQL

func (u *FilteredUpdate[D]) WriteSQL(b *strings.Builder, args *Args)

WriteSQL renders the UPDATE into b. It satisfies Statement, which is what lets this statement be the body of a CTE in another one.

type Guard

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

Guard is the execution guard an engine package's statement builder owns.

A builder whose statements carry scan targets must hand every Query it builds one shared guard, and so must every statement derived from it, because derived statements share the caller's target pointers: two Queries from one builder running at once write into the same variables. The core's builders do this internally; Guard is how a statement kind written outside the core, pg.Merge for one, does the same. Create it once, in the constructor, copy it into every derived statement, and build through NewGuardedQuery.

The zero Guard detects nothing, like a Query struct literal. That is the documented hole in the detection, not a way to opt out: a builder that captures targets has no reason to leave it zero.

func NewGuard

func NewGuard() Guard

NewGuard creates a guard for one builder and everything derived from it.

type Insert

type Insert[D render.Dialect] struct {
	// contains filtered or unexported fields
}

Insert is an INSERT that has no body yet. It has no Build method.

Row, Select and Body each return an InsertReady, which does. That is the whole of the typestate: the only way to obtain a value with Build is to have given the statement something to insert, so the empty INSERT that used to be ErrNoAssignments at Build is now a type error at the call site.

func NewInsert

func NewInsert[D render.Dialect](d D) *Insert[D]

NewInsert starts an INSERT for d.

func (*Insert[D]) Body

func (i *Insert[D]) Body(c Clause[D, InsertKind]) *InsertReady[D]

Body completes the statement with an engine clause that supplies the whole body, such as pg.DefaultValues. It is the third door to InsertReady, and it exists because DEFAULT VALUES is a legitimate INSERT with no rows and no query, which the typestate would otherwise make unwritable.

func (*Insert[D]) Clause

func (i *Insert[D]) Clause(cs ...Clause[D, InsertKind]) *Insert[D]

Clause adds an engine clause in a slot other than the body: pg.OnConflict at the tail, pg.OverridingSystemValue after the target. A clause that supplies the whole body, pg.DefaultValues, goes through Body instead, because it is what makes the statement complete.

func (*Insert[D]) Clone

func (i *Insert[D]) Clone() *Insert[D]

Clone returns an independent copy with its own execution guard.

func (*Insert[D]) Columns

func (i *Insert[D]) Columns(cols ...SQLer) *Insert[D]

Columns names the columns for an INSERT ... SELECT.

func (*Insert[D]) Dialect

func (i *Insert[D]) Dialect() Dialect

Dialect reports the dialect this statement renders for, so an Option or a helper can branch on the engine without the caller threading it through.

func (*Insert[D]) Into

func (i *Insert[D]) Into(t Table) *Insert[D]

Into names the table. The alias renders only when the dialect satisfies InsertAliasing; otherwise the bare table renders and RETURNING uses bare column names for bindings made from Col.

func (*Insert[D]) Row

func (i *Insert[D]) Row(as ...Assignment) *InsertReady[D]

Row adds one row of assignments and completes the statement. The first row fixes the column list; every later row must assign the same columns in the same order.

func (*Insert[D]) Select

func (i *Insert[D]) Select(s *Select[D]) *InsertReady[D]

Select makes the rows come from a query, INSERT INTO t (cols) SELECT ..., and completes the statement.

func (*Insert[D]) With

func (i *Insert[D]) With(name string, body Statement) *Insert[D]

With adds a CTE, for INSERT ... SELECT from a CTE or a data-modifying CTE.

type InsertAliasing

type InsertAliasing = render.InsertAliasing

InsertAliasing is satisfied by dialects accepting INSERT INTO t AS alias.

type InsertKind

type InsertKind struct{}

InsertKind marks a clause for INSERT.

type InsertReady

type InsertReady[D render.Dialect] struct {
	// contains filtered or unexported fields
}

InsertReady is an INSERT that has a body — rows, a query, or an engine clause supplying one — and can therefore be built.

It is the second of two types because an INSERT with nothing to insert is a mistake the compiler can catch: Build lives here and not on Insert, so NewInsert(d).Into(t).Build() does not compile. Reaching this type is what Row, Select and Body do. A value made as a struct literal has no body and no dialect and is rejected at Build, which is the documented literal hole.

func InsertReturning

func InsertReturning[D ReturningDialect](s *InsertReady[D], bs ...Binding) *InsertReady[D]

InsertReturning adds RETURNING with scan targets to an INSERT, so One and Each work on the result. D must have RETURNING, or this does not compile.

func (*InsertReady[D]) Build

func (i *InsertReady[D]) Build() (Query, error)

Build renders the statement, or returns the first error it found. The scan targets come from the RETURNING bindings, so One and Each work on the result without a second list.

func (*InsertReady[D]) Clause

func (i *InsertReady[D]) Clause(cs ...Clause[D, InsertKind]) *InsertReady[D]

Clause adds an engine clause: pg.OnConflict at the tail, pg.OverridingSystemValue after the target.

func (*InsertReady[D]) Clone

func (i *InsertReady[D]) Clone() *InsertReady[D]

Clone returns an independent copy of the INSERT with its own guard.

func (*InsertReady[D]) Dialect

func (i *InsertReady[D]) Dialect() Dialect

Dialect reports the dialect this statement renders for.

func (*InsertReady[D]) Row

func (i *InsertReady[D]) Row(as ...Assignment) *InsertReady[D]

Row adds another row. The column list was fixed by the first.

func (*InsertReady[D]) With

func (i *InsertReady[D]) With(name string, body Statement) *InsertReady[D]

With adds a CTE.

func (*InsertReady[D]) WriteSQL

func (i *InsertReady[D]) WriteSQL(b *strings.Builder, args *Args)

WriteSQL renders the INSERT into b. It satisfies Statement, which is what lets this statement be the body of a CTE in another one.

type Join

type Join struct {
	Type   JoinType
	Table  Table
	Source Source
	On     []Predicate
	// Using renders JOIN ... USING (cols) instead of ON. Named columns only,
	// never NATURAL, because a natural join changes meaning when a column is
	// added.
	Using []string
	// Clauses render immediately after this join's table reference and before
	// its ON or USING, which is where an engine puts a per-table hint:
	// SQLite's INDEXED BY, MySQL's USE INDEX, T-SQL's WITH (NOLOCK).
	//
	// This is the one position a Slot cannot name, because there is one per
	// join rather than one per statement. A clause here is still a Clause, so
	// it still carries its dialect guard; its Slot is not consulted, because
	// the join itself is the position.
	Clauses []AnyClause
}

Join brings a source into a statement. Table is the common case; Source covers a derived table, VALUES, a function or a LATERAL body, and wins when both are set. On is ANDed; an empty On renders no ON clause, which CROSS JOIN and LATERAL ... ON TRUE need, so give a CROSS or LATERAL join sqlb.True() when the dialect requires an ON.

type JoinType

type JoinType string

JoinType is the SQL join keyword. It is a distinct string type rather than a bare string so a caller cannot pass an arbitrary fragment into the FROM clause, which would be an injection point in an otherwise parameterised builder.

const (
	JoinInner JoinType = "INNER JOIN"
	JoinLeft  JoinType = "LEFT JOIN"
	JoinRight JoinType = "RIGHT JOIN"
	JoinCross JoinType = "CROSS JOIN"
)

The join types the core names.

These four are what Postgres, MySQL 8, SQLite and ClickHouse all accept with the same meaning, which is the same rule every other construct here follows.

FULL OUTER JOIN is absent for that reason rather than for want of a use case: MySQL has no FULL OUTER JOIN and emulates it with a UNION of a LEFT and a RIGHT join, so naming it here would mean shipping a constant that works on three engines and silently fails on the fourth.

It is still reachable, because JoinType is an ordinary string type and Join takes whatever it is given:

Join(Join{Type: JoinType("FULL OUTER JOIN"), ...})

That is the documented escape hatch and the SET stays open: no list here decides which joins exist, so an engine's own keyword is reachable without this module naming it. An engine package wanting a version checked against what it supports would wrap it and record Args.Unsupported, the way every other engine-specific construct does.

The TEXT is checked, which is a different thing and was added on 2026-09-24. The keyword is written into the FROM clause verbatim and cannot be quoted — a join keyword in quotes is an identifier — so a JoinType holding "INNER JOIN t ON 1=1; DROP TABLE users; --" was a statement, not a join. It now has to have the shape of a keyword: letters and single spaces, in either case. That enforces the word "keyword" this decision already rested on and refuses nothing a caller could legitimately write; TestJoinAndSetOp_TheEscapeHatchStillWorks builds FULL OUTER JOIN to prove the hatch is intact.

NATURAL joins are absent and will stay absent. A natural join changes which columns it matches on when somebody adds a column, so a query that was correct yesterday returns different rows today with nothing in the diff to show why.

type Named

type Named = render.Named

Named is satisfied by dialects that can name their engine.

type Option

type Option func(*selectCore)

Option extends a statement that a library built, from code that the library does not know. It carries an extra join, predicate, binding or ordering term. The library applies options before Build and keeps ownership of Build, so its mandatory predicates cannot be removed by an option: options only add.

An Option edits the universal core of a statement and nothing else, which is why it has no dialect type parameter. Go infers a type parameter from a function's arguments, never from where its result is used, so an Option[D] returned by WithWhere(p) could not have inferred D and every caller would have written it out — on the one seam that exists for callers. Editing the core sidesteps that: a clause carries a dialect and an option does not, so clauses are added with Clause on the statement, where the compiler checks them, and there is no WithClause.

func WithColumns

func WithColumns(bs ...Binding) Option

WithColumns adds bindings after the library's own, so the library's scan targets keep their positions.

func WithJoin

func WithJoin(js ...Join) Option

WithJoin adds joins to the statement.

func WithOrder

func WithOrder(ts ...OrderTerm) Option

WithOrder adds order terms after the library's own.

func WithWhere

func WithWhere(ps ...Predicate) Option

WithWhere adds predicates. They are ANDed with the library's own.

type OrderTerm

type OrderTerm = expr.OrderTerm

OrderTerm is one ORDER BY item.

type Predicate

type Predicate = expr.Predicate

Predicate is a boolean condition for WHERE or ON.

func And

func And(ps ...Predicate) Predicate

And combines predicates with AND.

func EngineBinPred

func EngineBinPred(engine, construct, op string, l, r SQLer) Predicate

EngineBinPred renders "(left op right)" as a guarded predicate.

Parenthesised for the same reason as EngineBinOp: a caller nests these inside And, Or and Not, and the author's nesting must decide the meaning rather than the engine's precedence table. The parentheses are never wrong where the bare form is valid, so this is the safe default rather than a judgement about which operators need them.

func EnginePred

func EnginePred(engine, construct string, render func(a *Args) string) Predicate

EnginePred makes a guarded predicate from a render function.

func Exists

func Exists[D render.Dialect](s *Select[D]) Predicate

Exists and NotExists. The subquery may be correlated: it references the outer sources by their aliases, which the outer statement's alias check does not see, so a collision between an inner and an outer alias is the author's responsibility.

func InSubquery

func InSubquery[T any, D render.Dialect](e Expr[T], s *Select[D]) Predicate

InSubquery renders e IN (SELECT ...). The subquery must select one item whose type is T; the compiler cannot check that across the Select, so it is stated in the signature by convention and checked by the database.

func NotExists

func NotExists[D render.Dialect](s *Select[D]) Predicate

NotExists renders NOT EXISTS (SELECT ...), the anti-join. It is usually faster than NOT IN and, unlike NOT IN, it is not defeated by a NULL in the subquery result.

func NotInSubquery

func NotInSubquery[T any, D render.Dialect](e Expr[T], s *Select[D]) Predicate

NotInSubquery renders e NOT IN (SELECT ...). Beware the NULL rule: if the subquery returns a single NULL the whole predicate is NULL and matches nothing. NotExists does not have that failure.

func PredicateOf

func PredicateOf(f func(a *Args) string) Predicate

PredicateOf makes a Predicate from a render function.

func SubqueryCompare

func SubqueryCompare[D render.Dialect](e SQLer, op, quantifier string, s *Select[D]) Predicate

SubqueryCompare renders "e op [quantifier] (SELECT ...)". It is the mechanism behind InSubquery and behind the ANY/ALL forms in engine packages.

Both op and quantifier reach the statement text and neither can be quoted, so both are checked for their shape: op for an operator's and quantifier for a keyword's, which is what ANY, ALL and SOME are. An empty quantifier is legitimate and means the form without one, which is what IN and NOT IN use.

type Query

type Query struct {
	SQL     string
	Args    []any
	Targets []any
	// contains filtered or unexported fields
}

Query is a rendered statement: SQL text, the bound values in placeholder order, and the scan targets in select-list order. Targets is nil when any select item has no target.

A Query is NOT SAFE FOR CONCURRENT USE. Executing one from two goroutines is a data race: it reads like inert data and is not, because Targets holds pointers into the caller's variables, so both write to the same memory and interleave each other's rows. Go's race detector reports it as a data race on those variables. Build the query where its destination lives, per call, which is what the cookbook recipes do. Reusing one sequentially is fine.

One and Each refuse an overlapping execution with ErrQueryInUse rather than corrupting the result, for a Query made by a builder or by NewQuery. A Query assembled as a struct literal carries no guard and gets no check.

func NewGuardedQuery

func NewGuardedQuery(g Guard, sql string, args, targets []any) Query

NewGuardedQuery is NewQuery for a builder that owns a Guard: every Query it returns for the same guard is detected as sharing targets with the others, so ErrQueryInUse fires when two of them overlap.

func NewQuery

func NewQuery(sql string, args, targets []any) Query

NewQuery assembles a rendered statement with its bound values and scan targets.

It is for an engine package rendering a statement kind the core does not have, such as pg's MERGE. Building the Query through here rather than with a struct literal is what gives it the concurrent-use check; a literal is still valid and simply has none.

func (Query) Acquire

func (q Query) Acquire() bool

Acquire reports whether execution of q may start, and claims it if so.

It is exported because executing a statement is a layer above building one, and the two live in different packages. The guard has to be reachable from there without exposing how it works: a caller learns only yes or no, and must call Release when the execution finishes.

A Query built as a struct literal has no guard and is always allowed to proceed, which is the documented hole in the detection rather than a bug. The guard detects the overlap it can see; it does not prevent the hazard.

func (Query) Release

func (q Query) Release()

Release ends the execution claimed by Acquire. Calling it without a matching Acquire is safe and does nothing.

type Returning

type Returning = render.Returning

Returning is satisfied by dialects that support RETURNING.

type ReturningDialect

type ReturningDialect interface {
	render.Dialect
	SupportsReturning() bool
}

ReturningDialect is a dialect that has RETURNING: render.Dialect plus the capability method. It is a constraint rather than an interface value on purpose. RETURNING used to be a method on the complete write types, checked at Build by a type assertion, which meant an INSERT ... RETURNING on ClickHouse compiled and failed later. A method cannot be conditional on a statement's dialect, but a function's type parameter can be, so the three functions below take the statement, infer D from it, and refuse a D without the method at compile time. A dialect declines the capability by not implementing it, never by returning false, and the runtime check in writeReturning is what happens when one breaks that rule: an outside dialect that implements SupportsReturning and answers false gets ErrNoReturning at Build rather than SQL its engine rejects. It does not guard a statement built as a literal, which this comment claimed until 2026-09-24: a literal still carries a D, and every D satisfying this constraint answers true, so a literal never reaches it.

type SQLer

type SQLer = render.SQLer

SQLer is anything that renders itself with the statement's Args.

func EngineQuoteLit

func EngineQuoteLit(s string) SQLer

EngineQuoteLit renders s as a string literal, written by the dialect's own quoter.

For author-chosen constants only, such as a config name or a jsonpath the grammar will not take as a parameter. Request data goes through Param; this puts its argument straight into the statement text.

It asks the dialect rather than doubling quotes itself, because that was not enough: on Postgres with standard_conforming_strings off, a backslash in a plain literal is an escape, and a jsonpath's like_regex "^\\d$" matched with the setting on and silently did not with it off. A dialect that does not implement LiteralQuoting cannot be given a literal, and Build fails with ErrNoLiteralQuoting naming it rather than writing one by a guessed rule.

func EngineRaw

func EngineRaw(engine, construct string, render func(a *Args) string) SQLer

EngineRaw makes a guarded fragment that is neither an expression nor a predicate, such as an argument decorator or a CTE suffix.

func Raw

func Raw(f func(a *Args) string) SQLer

Raw makes a SQLer from a render function.

type Select

type Select[D render.Dialect] struct {
	// contains filtered or unexported fields
}

Select is a SELECT for the dialect D.

D is inferred from NewSelect's argument and never written: a concrete dialect gives a statement that accepts that engine's clauses, and a render.Dialect interface value — the engine chosen at runtime — gives Select[render.Dialect], which accepts only universal constructs, because no engine clause is a Clause[render.Dialect, SelectKind]. That is the portability rule as a type rather than a convention. AnySelect names it.

The universal parts live in the embedded selectCore, which is what an Option edits; the dialect-typed parts — the clauses and the dialect itself — live here.

func NewSelect

func NewSelect[D render.Dialect](d D) *Select[D]

NewSelect starts a statement for d.

The execution guard is created here rather than at Build, and that is load-bearing now that every method returns a derived statement. Two statements derived from one base still share their bindings, which are pointers into the caller's variables, so they must share a guard: creating it lazily would have given each derivation its own and quietly allowed the overlapping execution the guard exists to refuse. A Select made as a struct literal still has no guard and still gets no check, which TestQuery_LiteralHasNoGuard pins.

func (*Select[D]) Apply

func (s *Select[D]) Apply(opts ...Option) *Select[D]

Apply runs each option against a derived copy of the statement, in order, and returns it. The receiver is not modified.

func (*Select[D]) Build

func (s *Select[D]) Build() (Query, error)

Build renders the statement. Every check fails closed; the builder spec lists the order.

func (*Select[D]) Clause

func (s *Select[D]) Clause(cs ...Clause[D, SelectKind]) *Select[D]

Clause adds engine clauses. Each is written in its slot, in insertion order within the slot.

func (*Select[D]) Clone

func (s *Select[D]) Clone() *Select[D]

Clone returns a copy that shares nothing with the original, including its execution guard.

Deriving a query no longer needs it: every builder method copies, so base.Where(x) leaves base alone. What Clone means now is narrower and still necessary — a derived statement inherits the guard, because it holds the same bindings, which are pointers into the caller's variables, so two queries derived from one base must not execute at once. A clone is a separate statement and is not refused because the one it came from is running.

Why this is worth its own file rather than a one-line struct copy: a shallow copy shares the backing arrays, so appending to the copy can write into the original's spare capacity and change it. Every slice is therefore copied, and the clause map is rebuilt.

What is deliberately not deep: the expressions, predicates and clauses themselves. Those are values that render and do not mutate, so sharing them is safe and copying them would be pointless work.

func (*Select[D]) Columns

func (s *Select[D]) Columns(bs ...Binding) *Select[D]

Columns adds bindings: select items with scan targets.

func (*Select[D]) Dialect

func (s *Select[D]) Dialect() Dialect

Dialect returns the dialect the statement renders for.

func (*Select[D]) Distinct

func (s *Select[D]) Distinct() *Select[D]

Distinct adds DISTINCT. For DISTINCT ON use the pg package.

func (*Select[D]) Except

func (s *Select[D]) Except(o *Select[D]) *Select[D]

Except renders EXCEPT, the rows in the receiver and not in the argument.

func (*Select[D]) Exprs

func (s *Select[D]) Exprs(es ...SQLer) *Select[D]

Exprs adds select items without scan targets. A query with such items cannot be run through One or Each (ErrNoTargets); it is for a subquery, a CTE body, an INSERT ... SELECT, or a caller that scans on its own.

func (*Select[D]) From

func (s *Select[D]) From(src Source) *Select[D]

From sets the driving source. Table satisfies Source.

func (*Select[D]) GroupBy

func (s *Select[D]) GroupBy(es ...SQLer) *Select[D]

GroupBy adds grouping expressions. Standard SQL, so it is core. Mixed Go types are fine, which is why it takes SQLer. GroupingSets, Cube and Rollup are SQLers too.

func (*Select[D]) Having

func (s *Select[D]) Having(ps ...Predicate) *Select[D]

Having adds HAVING predicates, ANDed.

func (*Select[D]) Intersect

func (s *Select[D]) Intersect(o *Select[D]) *Select[D]

Intersect renders INTERSECT, the rows in both branches.

func (*Select[D]) Join

func (s *Select[D]) Join(js ...Join) *Select[D]

Join adds joins, in order. Accumulates across calls, so a library and its caller can each contribute one.

func (*Select[D]) Limit

func (s *Select[D]) Limit(n int) *Select[D]

Limit sets the row limit, which binds as a parameter rather than being rendered into the statement.

func (*Select[D]) Offset

func (s *Select[D]) Offset(n int) *Select[D]

Offset sets the row offset, also bound. Paging far into a large result with OFFSET is slow on every engine; a keyset predicate in Where is the alternative.

func (*Select[D]) Order

func (s *Select[D]) Order(ts ...OrderTerm) *Select[D]

Order adds ordering terms, in order of significance.

func (*Select[D]) SetOp

func (s *Select[D]) SetOp(keyword string, o *Select[D]) *Select[D]

SetOp adds a set operation with the given keyword. Engine packages use it for INTERSECT ALL and EXCEPT ALL, which SQLite lacks.

The keyword is a string rather than a closed type for the reason JoinType is open: INTERSECT ALL is absent from this module's constants because SQLite has no such thing, and naming it here would ship a constant that works on three engines and fails on the fourth. So the set is the caller's.

The text is not. It is written between the two branches verbatim and cannot be quoted, so it is checked for the shape of a keyword — letters and single spaces. Until 2026-09-24 it was unchecked, and this doc comment said only who used it, which is the failure that hid it: an escape hatch nobody has written down as one reads like an ordinary argument.

func (*Select[D]) Union

func (s *Select[D]) Union(o *Select[D]) *Select[D]

Union renders UNION, which removes duplicate rows.

Each branch of a set operation renders parenthesised, so a branch may carry its own ORDER BY and LIMIT. The receiver's ORDER BY, LIMIT and OFFSET apply to the whole compound, as in SQL, and an ORDER BY over a compound must name an output column: use OutputCol, not a table column.

func (*Select[D]) UnionAll

func (s *Select[D]) UnionAll(o *Select[D]) *Select[D]

UnionAll renders UNION ALL, which keeps duplicates and does not sort.

func (*Select[D]) Where

func (s *Select[D]) Where(ps ...Predicate) *Select[D]

Where adds predicates, joined with AND. Accumulates across calls, which is what lets a caller narrow a query a library built.

func (*Select[D]) Window

func (s *Select[D]) Window(name string, w Window) *Select[D]

Window declares a named window for OverNamed.

func (*Select[D]) With

func (s *Select[D]) With(name string, body Statement) *Select[D]

With adds a common table expression. A later CTE may reference an earlier one. Reference the CTE as a source with Table{Name: name, Alias: alias}.

func (*Select[D]) WithCTE

func (s *Select[D]) WithCTE(cte CTE) *Select[D]

WithCTE adds a fully specified CTE, for a column list or an engine prefix.

func (*Select[D]) WithRecursive

func (s *Select[D]) WithRecursive(name string, seed, step *Select[D]) *Select[D]

WithRecursive adds WITH RECURSIVE name AS (seed UNION ALL step). The step references name as a source; the seed and the step must select the same number of items, which the database checks.

func (*Select[D]) WithRecursiveCTE

func (s *Select[D]) WithRecursiveCTE(cte CTE) *Select[D]

WithRecursiveCTE adds a fully specified recursive CTE: use it for a UNION (not UNION ALL) step, a column list, or a SEARCH or CYCLE suffix.

func (*Select[D]) WriteSQL

func (s *Select[D]) WriteSQL(b *strings.Builder, args *Args)

WriteSQL renders into a parent's builder and Args, so a Select is a Statement: usable as a subquery, a CTE body or an INSERT source with one shared placeholder numbering.

type SelectKind

type SelectKind struct{}

SelectKind marks a clause for SELECT.

type Slot

type Slot int

Slot is a fixed position in a statement where an engine-specific clause may be written. The core defines the slots; engine packages define the clauses.

The set is complete rather than minimal: there is a slot at every boundary the renderer emits, so every position in a statement has a name. That is a deliberate change from "no slot ships ahead of a clause". A slot is the one extension point a package outside this module cannot add for itself, since a position only means something if the renderer writes it, and completeness is what keeps an outside engine package first class. Several slots therefore have no clause in this module; the doc comment on each says which engine's clause it is for, or says plainly that none is known.

A clause aimed at a slot a statement does not render fails at Build with ErrUnknownSlot rather than being dropped.

const (
	// SlotAfterSelect sits between SELECT and the column list: DISTINCT ON, TOP.
	SlotAfterSelect Slot = iota
	// SlotAfterColumns sits after the select list and before FROM. T-SQL puts
	// INTO there. No engine in this module uses it; it exists so the set has
	// no hole between the column list and FROM.
	SlotAfterColumns
	// SlotAfterFrom sits after the driving table and before joins: FINAL,
	// SAMPLE, TABLESAMPLE, ARRAY JOIN.
	SlotAfterFrom
	// SlotBeforeWhere sits after joins and before WHERE: PREWHERE.
	SlotBeforeWhere
	// SlotAfterWhere sits after WHERE and before GROUP BY, in a SELECT, an
	// UPDATE or a DELETE. No engine in this module uses it; it exists so the
	// set has no hole on either side of WHERE.
	SlotAfterWhere
	// SlotAfterGroupBy sits after the GROUP BY list: MySQL's WITH ROLLUP and
	// WITH CUBE, which are a suffix there rather than a wrapper as they are
	// in Postgres.
	SlotAfterGroupBy
	// SlotAfterHaving sits after HAVING and before WINDOW. No engine in this
	// module uses it; it exists so the set has no hole between the two.
	SlotAfterHaving
	// SlotBeforeOrder sits after HAVING and WINDOW and before ORDER BY:
	// QUALIFY, which DuckDB, Snowflake and BigQuery use to filter on a window
	// result without a subquery.
	SlotBeforeOrder
	// SlotAfterOrder sits after ORDER BY and before LIMIT: LIMIT n BY.
	SlotAfterOrder
	// SlotAfterOffset sits after OFFSET and before the tail: FETCH FIRST.
	SlotAfterOffset
	// SlotTail sits last: FOR UPDATE, SETTINGS, ON CONFLICT.
	SlotTail
	// SlotAfterInsert sits between the INSERT keyword and INTO: SQLite's
	// OR REPLACE and its siblings, which no other engine spells there.
	SlotAfterInsert
	// SlotAfterVerb sits between the UPDATE or DELETE keyword and its target,
	// where MySQL puts LOW_PRIORITY, QUICK and IGNORE. SlotAfterInsert is the
	// same position in an INSERT, and is separate because SQLite's OR REPLACE
	// family renders there and reads as part of the keyword.
	SlotAfterVerb
	// SlotBeforeValues is an INSERT slot between the column list and VALUES
	// or SELECT: OVERRIDING SYSTEM VALUE.
	SlotBeforeValues
	// SlotInsertBody replaces the VALUES part of an INSERT: DEFAULT VALUES.
	SlotInsertBody
	// SlotAfterSet is an UPDATE slot after the SET list: FROM sources.
	SlotAfterSet
	// SlotAfterTarget sits after the target table of an INSERT, UPDATE or
	// DELETE and before whatever follows it: DELETE's USING sources, and the
	// place T-SQL puts a table hint such as WITH (TABLOCK).
	SlotAfterTarget
)

func (Slot) String

func (s Slot) String() string

String names the slot, so an error can say which position was asked for.

type SortDirection

type SortDirection = expr.SortDirection

SortDirection is the ORDER BY direction.

type Source

type Source = expr.Source

Source is anything that can appear in FROM or JOIN.

func EngineSource

func EngineSource(engine, construct, alias string, render func(a *Args) string) Source

EngineSource makes a guarded FROM source, for a set-returning function or any other table expression only one engine has.

func SourceOf

func SourceOf(alias string, f func(a *Args) string) Source

SourceOf makes a Source from a render function and an alias.

type Statement

type Statement = expr.Statement

Statement is anything that renders as a complete statement.

type Table

type Table = expr.Table

Table is a physical table with a fixed alias.

type Update

type Update[D render.Dialect] struct {
	// contains filtered or unexported fields
}

Update is an UPDATE whose target rows are not yet stated. It has no Build method. Where and All each return a FilteredUpdate, which does.

func NewUpdate

func NewUpdate[D render.Dialect](d D) *Update[D]

NewUpdate starts an UPDATE for d.

func (*Update[D]) All

func (u *Update[D]) All() *FilteredUpdate[D]

All states that every row is the target and completes the statement. It is what makes an UPDATE with no WHERE deliberate rather than an omission.

func (*Update[D]) Clause

func (u *Update[D]) Clause(cs ...Clause[D, UpdateKind]) *Update[D]

Clause adds an engine clause, such as pg.UpdateFrom in SlotAfterSet.

func (*Update[D]) Clone

func (u *Update[D]) Clone() *Update[D]

Clone returns an independent copy with its own execution guard.

func (*Update[D]) Dialect

func (u *Update[D]) Dialect() Dialect

Dialect reports the dialect this statement renders for, so an Option or a helper can branch on the engine without the caller threading it through.

func (*Update[D]) Set

func (u *Update[D]) Set(as ...Assignment) *Update[D]

Set adds assignments. Calling it more than once accumulates rather than replacing, so a library and a caller can each contribute.

func (*Update[D]) Table

func (u *Update[D]) Table(t Table) *Update[D]

Table names the table to update.

func (*Update[D]) Where

func (u *Update[D]) Where(ps ...Predicate) *FilteredUpdate[D]

Where states the target rows and completes the statement. Predicates are joined with AND, and more may be added on the result.

func (*Update[D]) With

func (u *Update[D]) With(name string, body Statement) *Update[D]

With attaches a CTE, for "update the rows this query found". It renders before the UPDATE keyword, not inside it.

type UpdateKind

type UpdateKind struct{}

UpdateKind marks a clause for UPDATE.

type Window

type Window = expr.Window

Window is a window definition for a window function.

Jump to

Keyboard shortcuts

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