Documentation
¶
Overview ¶
Package expr is the typed half of the builder: a table, a column with a Go type, a bound parameter, a predicate, an aggregate, a window, and the operators that join them.
Everything here renders through the layer below and knows nothing about statements. An Expr does not know it will appear in a SELECT, and a Predicate does not know whether it is a WHERE or a JOIN condition, which is what lets the statement layer put them wherever the grammar allows.
The one type that cannot be implemented from outside is Expr itself. It is a concrete generic struct rather than an interface, because being impossible to satisfy is exactly what makes its type parameter a guarantee rather than a suggestion. A package that needs an untyped fragment uses render.Raw and says so in its signature.
Index ¶
- Constants
- Variables
- func CheckedFunctionName(a *render.Args, name, what string) string
- func CheckedKeyword(a *render.Args, s, what string) string
- func CheckedOperator(a *render.Args, op, what string) string
- func EscapeLike(s string) string
- func PredicateSQL(p Predicate, a *render.Args) string
- func QuoteList(d render.Dialect, names []string) string
- func Row(items ...render.SQLer) render.SQLer
- type AggOption
- type AggSpec
- type CaseBuilder
- type Expr
- func Add[T Number](l, r Expr[T]) Expr[T]
- func Aggregate[R any](name string, args []render.SQLer, opts ...AggOption) Expr[R]
- func As[T any](e Expr[T], name string) Expr[T]
- func AssertNotNull[T any](e Expr[*T]) Expr[T]
- func Avg[T Number](e Expr[T], opts ...AggOption) Expr[float64]
- func Binary[R any](left render.SQLer, op string, right render.SQLer) Expr[R]
- func BoolExpr(p Predicate) Expr[bool]
- func Cast[R, T any](e Expr[T], sqlType string) Expr[R]
- func Coalesce[T any](first Expr[T], rest ...Expr[T]) Expr[T]
- func Col[T any](t Table, name string) Expr[T]
- func Concat(parts ...Expr[string]) Expr[string]
- func Count(opts ...AggOption) Expr[int64]
- func CountOf[T any](e Expr[T], opts ...AggOption) Expr[int64]
- func Div[T Number](l, r Expr[T]) Expr[T]
- func Fn[R any](name string, args ...render.SQLer) Expr[R]
- func Literal[T any](sql string) Expr[T]
- func Lower(e Expr[string]) Expr[string]
- func Max[T any](e Expr[T], opts ...AggOption) Expr[T]
- func Min[T any](e Expr[T], opts ...AggOption) Expr[T]
- func Mod[T Number](l, r Expr[T]) Expr[T]
- func Mul[T Number](l, r Expr[T]) Expr[T]
- func Neg[T Number](e Expr[T]) Expr[T]
- func New[T any](render func(a *render.Args) string) Expr[T]
- func NullIf[T any](l, r Expr[T]) Expr[*T]
- func Nullable[T any](e Expr[T]) Expr[*T]
- func OutputCol[T any](name string) Expr[T]
- func Over[T any](e Expr[T], w Window) Expr[T]
- func OverNamed[T any](e Expr[T], name string) Expr[T]
- func Param[T any](v T) Expr[T]
- func Sub[T Number](l, r Expr[T]) Expr[T]
- func Sum[T Number](e Expr[T], opts ...AggOption) Expr[T]
- func Upper(e Expr[string]) Expr[string]
- type FrameBound
- type FrameExclude
- type FrameMode
- type NullsOrder
- type Number
- type OrderTerm
- type Predicate
- func And(preds ...Predicate) Predicate
- func Between[T any](e Expr[T], lo, hi T) Predicate
- func Compare(left render.SQLer, op string, right render.SQLer) Predicate
- func Contains(e Expr[string], value string) Predicate
- func ContainsFold(e Expr[string], value string) Predicate
- func EndsWith(e Expr[string], value string) Predicate
- func EndsWithFold(e Expr[string], value string) Predicate
- func Eq[T any](e Expr[T], v T) Predicate
- func EqExpr[T any](left, right Expr[T]) Predicate
- func EqFold(e Expr[string], value string) Predicate
- func False() Predicate
- func Greater[T any](e Expr[T], v T) Predicate
- func GreaterEq[T any](e Expr[T], v T) Predicate
- func GreaterEqExpr[T any](left, right Expr[T]) Predicate
- func GreaterExpr[T any](left, right Expr[T]) Predicate
- func In[T any](e Expr[T], values ...T) Predicate
- func InExprs[T any](e Expr[T], items ...Expr[T]) Predicate
- func InFold(e Expr[string], values ...string) Predicate
- func IsNotNull[T any](e Expr[T]) Predicate
- func IsNull[T any](e Expr[T]) Predicate
- func Less[T any](e Expr[T], v T) Predicate
- func LessEq[T any](e Expr[T], v T) Predicate
- func LessEqExpr[T any](left, right Expr[T]) Predicate
- func LessExpr[T any](left, right Expr[T]) Predicate
- func Like(e Expr[string], pattern string) Predicate
- func Not(p Predicate) Predicate
- func NotBetween[T any](e Expr[T], lo, hi T) Predicate
- func NotContains(e Expr[string], value string) Predicate
- func NotEq[T any](e Expr[T], v T) Predicate
- func NotEqExpr[T any](left, right Expr[T]) Predicate
- func NotIn[T any](e Expr[T], values ...T) Predicate
- func NotInFold(e Expr[string], values ...string) Predicate
- func NotLike(e Expr[string], pattern string) Predicate
- func Or(preds ...Predicate) Predicate
- func PredicateOf(render func(a *render.Args) string) Predicate
- func RowEq(l, r render.SQLer) Predicate
- func RowGreater(l, r render.SQLer) Predicate
- func RowIn(row render.SQLer, rows ...render.SQLer) Predicate
- func RowLess(l, r render.SQLer) Predicate
- func RowNotIn(row render.SQLer, rows ...render.SQLer) Predicate
- func StartsWith(e Expr[string], value string) Predicate
- func StartsWithFold(e Expr[string], value string) Predicate
- func True() Predicate
- type SortDirection
- type Source
- type Statement
- type Table
- type WinFn
- type Window
Constants ¶
const ( OpEq = "=" OpNotEq = "<>" OpLess = "<" OpLessEq = "<=" OpGreater = ">" OpGreaterEq = ">=" OpIn = "IN" OpNotIn = "NOT IN" OpIsNull = "IS NULL" OpIsNotNull = "IS NOT NULL" OpAdd = "+" OpSub = "-" OpMul = "*" OpDiv = "/" OpMod = "%" OpConcat = "||" OpIsDistinctFrom = "IS DISTINCT FROM" OpIsNotDistinctFrom = "IS NOT DISTINCT FROM" OpIsTrue = "IS TRUE" OpIsFalse = "IS FALSE" OpIsUnknown = "IS UNKNOWN" OpLike = "LIKE" OpNotLike = "NOT LIKE" )
Comparison and logical operators emitted into WHERE / ON clauses.
Why they are constants rather than inline literals: a predicate constructor is one line of string concatenation, and a typo there produces SQL that is syntactically valid but semantically wrong (">=" typed as "=>" fails loudly, but "<>" typed as "<" does not). Naming them removes the class.
const ( LogicAnd = "AND" LogicOr = "OR" LogicNot = "NOT" )
Logical connectives used to combine predicates.
Variables ¶
var ErrNoLikeEscape = errors.New("sqlb: dialect does not support ESCAPE on LIKE, so a user's text cannot be escaped safely")
ErrNoLikeEscape is recorded when a dialect cannot express an ESCAPE clause.
Refusing is the right failure. The alternative is to render the pattern without the clause and match the wrong rows, and a search that returns too much looks like it worked.
var ErrUnknownValue = errors.New("sqlb: value is not one of its type's constants")
ErrUnknownValue reports a closed-set value outside its constants, which is refused rather than written: the constants are the whole set the grammar allows, so a value outside them is either a typo or text from somewhere it should never have come from.
var ErrZeroExpr = errors.New("sqlb: a zero Expr was rendered; make expressions with Col, Param or a constructor")
ErrZeroExpr is recorded when a zero Expr[T]{}, one no constructor made, is rendered. Until 2026-09-22 rendering one called a nil function and panicked inside Build.
var FrameModeValues = []FrameMode{FrameRows, FrameRange}
FrameModeValues is the canonical iteration order over the frame modes every engine here has.
It is NOT the whole set a caller may write, which is why FrameMode is not validated against it. GROUPS is the case that proves it: Postgres and SQLite have it, MySQL 8 does not, so by the universality rule it is an engine's constant rather than one of this package's — and `examples/pgsurface` writes GROUPS today. FrameMode is the same shape as FrameExclude: the mechanism is here and the vocabulary belongs to the engine, so the value reaches the statement as the author wrote it. A closed check here was tried on 2026-09-24 and reverted within the hour, because it refused a frame the module's own example builds.
var NullsOrderValues = []NullsOrder{NullsFirst, NullsLast}
NullsOrderValues is the canonical iteration order over NULL placements.
var OpValues = []string{ OpEq, OpNotEq, OpLess, OpLessEq, OpGreater, OpGreaterEq, OpIn, OpNotIn, OpIsNull, OpIsNotNull, }
OpValues is the canonical iteration order over comparison operators. It exists so a future validator or documentation generator reads the same list the builder writes from, instead of drifting into its own copy.
var SortDirectionValues = []SortDirection{SortAsc, SortDesc}
SortDirectionValues is the canonical iteration order over sort directions.
Functions ¶
func CheckedFunctionName ¶
CheckedFunctionName writes name, or fails the render naming it.
func CheckedKeyword ¶
CheckedKeyword writes s, or fails the render naming it.
func CheckedOperator ¶
CheckedOperator writes op, or fails the render naming it. The failure is ErrUnknownValue, the same error every closed set in this module reports, because a caller reading it wants the same thing in both cases: the value that was refused and which argument it came from.
func EscapeLike ¶
EscapeLike escapes the characters LIKE treats as syntax, so a value can be used inside a pattern the caller builds.
Exported because Contains, StartsWith and EndsWith cover the three common shapes and not every shape. A caller assembling something else needs the same escaping and should not have to rediscover which characters matter. Doing so by hand also means writing the ESCAPE clause, which is what these predicates exist to stop you forgetting.
func PredicateSQL ¶
PredicateSQL renders p to a string with the statement's Args. Engine packages use it to embed a predicate inside a function call such as sumIf.
Types ¶
type AggSpec ¶
type AggSpec struct {
Distinct bool
// Inner renders after the arguments, inside the parentheses.
Inner func(a *render.Args) string
// Suffix renders after the closing parenthesis.
Suffix func(a *render.Args) string
}
AggSpec is what an aggregate call can carry beyond its arguments. The fields are hooks, not decisions: the core renders whatever they hold, and an engine package decides what goes in. Distinct is here because every engine has count(DISTINCT x). FILTER and ORDER BY inside the call are not universal, so pg sets Inner and Suffix instead.
type CaseBuilder ¶
type CaseBuilder[T any] struct { // contains filtered or unexported fields }
CaseBuilder accumulates a searched CASE. Else yields Expr[T]; End yields Expr[*T], because a CASE with no ELSE is null when no branch matches.
func (CaseBuilder[T]) Else ¶
func (c CaseBuilder[T]) Else(e Expr[T]) Expr[T]
Else closes the CASE with an ELSE branch. Not null when every branch is not null.
func (CaseBuilder[T]) End ¶
func (c CaseBuilder[T]) End() Expr[*T]
End closes the CASE without ELSE. The result is nullable.
func (CaseBuilder[T]) When ¶
func (c CaseBuilder[T]) When(cond Predicate, then Expr[T]) CaseBuilder[T]
When adds a branch. The builder is a value and When copies the branch list, so a partially built CASE can be shared as a base without a later When on one copy appearing in another.
type Expr ¶
type Expr[T any] struct { // contains filtered or unexported fields }
Expr is a SQL expression that evaluates to the Go type T.
It is a concrete generic struct, not an interface, because an interface whose method set never mentions T makes T a phantom parameter that Go cannot infer; every call site would then need an explicit type argument. The struct keeps inference working.
The render function receives *Args rather than only the Dialect so an expression can bind a parameter (see Param) and can record that it is not supported by the dialect it is being rendered through (see Args.Unsupported).
func Add ¶
Add renders l + r.
The result of this family is typed as the operand type, which matches SQL for same-type operands. The trap is Div: integer division truncates in SQL as it does in Go, so a ratio needs a cast first.
func Aggregate ¶
Aggregate renders name(args...) with the options applied, typed R. It is the constructor every specific aggregate uses, and the typed door for an aggregate the package does not name.
func As ¶
As aliases a select item: expr AS name. Needed for a CTE or derived table whose columns the outer query references by name, and for ORDER BY alias.
func AssertNotNull ¶
AssertNotNull reinterprets a nullable expression as T without changing the SQL. It is the opposite of Nullable and it is a promise: the author knows a run-time fact the builder cannot prove, such as "lag() is null only on the first row, where this branch is never taken". Scanning a NULL through it fails at run time, so write the reason beside every use.
func Avg ¶
Avg is float64. SQL returns numeric for integer input; scanning numeric into float64 loses precision beyond 2^53, which is acceptable for an average and stated here.
func Binary ¶
Binary renders "(left op right)" typed R. Engine packages use it for their operators; the core uses it for arithmetic.
op is checked for the SHAPE of an operator, not against a list: the operators an engine has come from its extensions, so a list would refuse a valid one. See CheckedOperator for what the shape is and why an operator cannot simply be quoted instead.
func BoolExpr ¶
BoolExpr turns a predicate into a boolean expression, so it can be selected, aliased or used in a CASE.
func Cast ¶
Cast renders CAST(e AS sqlType) and re-types the expression as R. The SQL type is a constant chosen by the author, never request data.
func Coalesce ¶
Coalesce renders COALESCE(first, rest...). The result type is T; the caller decides nullability by choosing a not-null last argument.
A bare integer parameter among the arguments is typed on a dialect that asks through render.NumericParameters, because MySQL otherwise returns COALESCE(sum(x), ?) as DECIMAL(65,30) and the result no longer scans into T.
func Concat ¶
Concat renders concat(a, b, ...), the function form, because the || operator is not concatenation in MySQL. Every target engine has concat().
concat takes any type, so Postgres cannot infer one for a bare bound parameter among its arguments and refuses the statement; the conformance suite found that on its first Postgres run. An argument that rendered as exactly one new placeholder is therefore given a type through render.UntypedParameters when the dialect asks for it, and every other argument, and every other dialect, renders as it always did.
func Div ¶
Div renders l / r, which truncates on integer operands. Cast one side for a real quotient.
func Fn ¶
Fn renders a function call name(args...) typed R. It is the typed door for the long tail of SQL functions; the author states the result type once, at the call, and a search for "sqlb.Fn[" lists every such promise.
name is checked for the shape of a function name — an identifier, or a schema-qualified pair — because it cannot be quoted: quoting pg_catalog.date_trunc as one identifier names a function that does not exist. A function whose name needs quoting is reachable through Raw.
func Literal ¶
Literal is a constant SQL fragment typed as T.
It is the documented exception to "no raw fragments". It exists for constants such as ” or FALSE as COALESCE fallbacks and must never be fed request data; use Param for anything that varies.
func Lower ¶
Lower wraps a string expression in lower(). Used on both sides of an identifier comparison so the comparison matches a lower() uniqueness index.
func Min ¶
Min renders min(e). Typed as T rather than *T: a group that exists has at least one row, and a group with no rows produces no result row at all.
func Neg ¶
Neg renders (-e), parenthesised so it composes without a precedence surprise next to another operator.
func New ¶
New makes an expression from a render function. It is the single typed escape hatch: the caller states the Go type the expression evaluates to, and the compiler holds every downstream use to that statement.
func Nullable ¶
Nullable reinterprets an expression of T as *T without changing the SQL.
The same physical column is non-null under an INNER join and nullable under a LEFT join. Discovered when an integration test failed with "couldn't convert <nil> into type time.Time", a failure no test over SQL text catches.
func OutputCol ¶
OutputCol references a select-list alias by name, typed T. It is how an ORDER BY over a UNION names its sort key, since SQL requires an output column name there and rejects a table-qualified one.
func Over ¶
Over turns any expression, in practice an aggregate, into a window function call: sum(x) OVER (...).
func Param ¶
Param binds a Go value as an expression of its own type.
With Param, Eq(col, v) is the same as EqExpr(col, Param(v)), and every function that accepts an Expr[T] also accepts a bound value. That is what a JSON path with a bound key, a vector distance with a bound vector, or any SQL function with a bound argument needs.
func Sum ¶
Sum keeps the operand type. SQL widens sum(int4) to int8; database/sql scans an int64 into any Go integer that fits, so the Go type is the author's choice of width. Sum of an empty group is NULL: wrap in Nullable for an ungrouped query.
func Upper ¶
Upper wraps a string expression in upper(). It is core for the reason Lower is: Postgres, MySQL 8, SQLite and ClickHouse all spell it upper() and mean the same thing by it for ASCII, which is the case a CHECK or a generated column relies on.
type FrameBound ¶
type FrameBound struct {
// contains filtered or unexported fields
}
FrameBound is one end of a frame. Use the constructors below.
func CurrentRow ¶
func CurrentRow() FrameBound
CurrentRow bounds a frame at the current row. Under RANGE that means the whole peer group, not one row, which is the default frame most people are surprised by.
func FollowingExpr ¶
func FollowingExpr(sql string) FrameBound
FollowingExpr bounds a frame with an expression rather than a count, for a RANGE frame whose offset is an interval.
func Preceding ¶
func Preceding(n int) FrameBound
Preceding bounds a frame n rows back under ROWS, or n units back under RANGE.
func PrecedingExpr ¶
func PrecedingExpr(sql string) FrameBound
PrecedingExpr and FollowingExpr take a constant SQL expression as the offset, for RANGE frames over a time column: PrecedingExpr("interval '7 days'").
func UnboundedFollowing ¶
func UnboundedFollowing() FrameBound
UnboundedFollowing ends a frame at the last row of the partition.
func UnboundedPreceding ¶
func UnboundedPreceding() FrameBound
UnboundedPreceding starts a frame at the first row of the partition.
type FrameExclude ¶
type FrameExclude string
FrameExclude is the EXCLUDE part of a frame. The constants are in pg, because MySQL and ClickHouse have no EXCLUDE.
type FrameMode ¶
type FrameMode string
FrameMode selects ROWS or RANGE for a window frame. GROUPS is Postgres and SQLite only and lives in pg.
type NullsOrder ¶
type NullsOrder string
NullsOrder is where NULLs sort relative to values, the NULLS FIRST or NULLS LAST of an ORDER BY term.
A named type with constants rather than the bare string this was until 2026-09-24: the set is closed, it is written into the statement verbatim, and an OrderTerm is a struct literal a caller fills, so nothing stopped an arbitrary string reaching the text. The empty value is legitimate and means the engine's own default, which is why it is not an error.
const ( NullsFirst NullsOrder = "NULLS FIRST" NullsLast NullsOrder = "NULLS LAST" )
The two placements every engine here spells the same way.
type Number ¶
type Number interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
~float32 | ~float64
}
Number is the set of Go types that arithmetic operators accept.
type OrderTerm ¶
type OrderTerm struct {
Expr func(a *render.Args) string
Direction SortDirection
// Nulls places NULLs relative to values. Empty means the engine's own
// default, which differs between them: Postgres sorts NULLs last when
// ascending, SQLite and MySQL first.
Nulls NullsOrder
// Using renders "USING op" instead of ASC/DESC, for an ordering defined by
// an operator rather than by a direction.
//
// It is a bare string and stays one, for the reason expr.Binary's operator
// does: the legal operators are whatever the engine's operator classes
// define, so a list here would refuse a valid one. It is an author's
// constant, never a value from a request, and it reaches the statement
// text unquoted because an operator cannot be quoted.
Using string
}
OrderTerm is one ORDER BY item. Nulls and Using are hooks the core renders when set; the engine package that has NULLS FIRST or USING op sets them. The core names neither, because MySQL has no NULLS FIRST.
type Predicate ¶
Predicate is a boolean condition for WHERE or ON.
It is an open interface so a consumer can add an operator the package does not ship. It has no type parameter, so an interface costs nothing here, unlike Expr. Constructors below are the only way to build a typed comparison; a raw fragment cannot be smuggled in as one.
func Compare ¶
Compare renders "left op right" as a predicate. Engine packages use it for operators the core does not name.
op is checked for the shape of an operator, as Binary's is. This is the door a request-derived operator reaches in practice: examples/pgsurface/periodcompare/filters.go maps a request's comparison enum through a lookup table and hands the result here. That code is right, and its comment says the map is "a lookup, never a format" — but the discipline was the caller's alone until the shape was checked here.
func Contains ¶
Contains renders e LIKE '%value%' with value escaped, the predicate behind a search box.
func ContainsFold ¶
ContainsFold is Contains regardless of case: the value is escaped, wrapped in %, and matched with ILIKE on Postgres and lower() LIKE lower() elsewhere.
The spelling differs by engine and the answer does not, for ASCII; see the block comment above for the collation's say beyond it. Its negation is Not(ContainsFold(...)), which is NOT (e ILIKE ...) and means the same thing, NULL included, so there is no NotContainsFold.
func EndsWithFold ¶
EndsWithFold is EndsWith regardless of case.
func Eq ¶
Eq and its family compare an expression with a bound value of the same Go type. Comparing a time column with a string does not compile.
func EqExpr ¶
EqExpr compares two expressions of the same Go type. It is the join condition, and it is where the compiler earns its keep: a join between a string column and a bool column does not compile.
func EqFold ¶
EqFold matches e against value regardless of case: lower(e) = lower(value) on every engine.
The spelling is the same on Postgres, which has ILIKE, because ILIKE with no wildcard would still read a typed % or _ as one, and because lower(e) is the expression a case-insensitive unique index is declared on. Declare that index and this is an index lookup; with only a plain index on e, it is a scan.
A NULL e matches nothing, on every engine, as with Eq.
func False ¶
func False() Predicate
False renders FALSE, which fails a query closed. It is what an empty IN list renders as, since IN () is a syntax error in every engine.
func GreaterEqExpr ¶
GreaterEqExpr renders left >= right.
func GreaterExpr ¶
GreaterExpr renders left > right.
func InExprs ¶
InExprs renders e IN (x, y, ...) over expressions, for a membership test against columns rather than bound values.
func InFold ¶
InFold matches e against any of values regardless of case. An empty list renders FALSE, as In does.
func LessEqExpr ¶
LessEqExpr renders left <= right.
func NotBetween ¶
NotBetween is the negated form.
func NotContains ¶
NotContains renders e NOT LIKE '%value%' with value escaped.
func NotEq ¶
NotEq renders e <> $n. NULL <> v is NULL, not true, so this does not match rows where the column is NULL; add IsNull when it should.
func NotEqExpr ¶
NotEqExpr renders left <> right.
This family compares two expressions rather than an expression and a value, for conditions between columns or against a Param passed as an expression. Both sides share T, so a mismatched join does not compile.
func NotInFold ¶
NotInFold matches e against none of values regardless of case. An empty list renders TRUE, as NotIn does. A NULL e matches nothing, which is SQL's rule for NOT IN and the same on every engine.
func Or ¶
Or groups predicates with OR. Empty renders TRUE, which is the safe value for a filter that nobody narrowed; an empty OR that rendered FALSE would hide every row without an error.
func PredicateOf ¶
PredicateOf makes a Predicate from a render function. Engine packages use it for their operators.
func RowGreater ¶
RowGreater renders l > r for two row constructors.
func RowIn ¶
RowIn renders (a, b) IN ((?, ?), (?, ?)), a membership test for a composite key against a list of tuples.
It exists because the single-column forms cannot express it. In and InExprs take an Expr[T], and a row constructor is a bare SQLer with no element type to be T, so before this the only way to ask "is this pair one of these pairs" was to OR a chain of RowEq, which asks the planner a different question and grows a clause per pair.
Every element is whatever the caller passed, so bind the values with Param rather than writing them into the row. The subquery form needs nothing new: stmt.SubqueryCompare takes a SQLer, so (a, b) IN (SELECT a, b FROM ...) is SubqueryCompare(Row(a, b), OpIn, "", sel).
Arity is not checked, for the same reason RowLess cannot check it: Row returns an opaque SQLer and the number of elements is gone by the time this sees it. A pair tested against a triple is an error from the database.
An empty list renders FALSE, matching In: an IN with nothing in it is a syntax error, and dropping the predicate would widen the result set.
func RowLess ¶
RowLess renders l < r for two row constructors, the shape a keyset page uses to say "after this row" in one comparison.
Element types are not checked across the two rows; the database checks them. That is the one place in this package where the compiler cannot help, so keep the rows short and adjacent in the source.
func RowNotIn ¶
RowNotIn renders (a, b) NOT IN ((?, ?), ...). An empty list renders TRUE.
The NULL rule that applies to NotIn applies here and is easier to hit, because a row is NULL if any element of it is: one nullable column in the list makes the whole predicate NULL, which matches nothing. Where that is possible, an anti-join with NotExists says what was meant.
func StartsWith ¶
StartsWith renders e LIKE 'value%' with value escaped.
Worth preferring to Contains where it fits: a prefix match can use a B-tree index on the column and a leading wildcard cannot, so on a table of any size the two differ by an index scan versus a sequential one.
func StartsWithFold ¶
StartsWithFold is StartsWith regardless of case.
Unlike StartsWith, a plain B-tree index on e does not serve it on any engine, because the column is wrapped or the operator is ILIKE. On SQLite and MySQL an index on lower(e) can serve the prefix; on Postgres a pg_trgm GIN index serves ILIKE.
type SortDirection ¶
type SortDirection string
SortDirection is the ORDER BY direction.
const ( SortAsc SortDirection = "ASC" SortDesc SortDirection = "DESC" )
Supported sort directions.
type Source ¶
Source is anything that can stand in FROM or be joined: a table, a derived table, or an engine-specific source such as VALUES, a set-returning function or a LATERAL body.
Every source has an alias, because columns are referenced through the alias and Build checks alias uniqueness across every source in a statement.
type Statement ¶
Statement is any statement that renders into a parent's Args: a Select used as a subquery or CTE body, or a data-modifying statement in a CTE.
type Table ¶
type Table struct {
Name string
Alias string
// Schema is optional. When set, the table renders as "schema"."name".
Schema string
}
Table is a physical table with a fixed alias.
The alias lives here, not on the statement, because a plugin in another module declares its join at package level before any statement exists. Build rejects two tables that share one alias in a statement, because the collision otherwise surfaces as an ambiguous-column error from the database pointing at a column neither author wrote.
func Ref ¶
Ref returns a Table value that references a source by its alias only, for making Col values against a derived table, a CTE or a VALUES list:
t := sqlb.Derived(sub, "t") n := sqlb.Col[int64](sqlb.Ref(t), "n") // renders "t"."n"
Name is the alias too, so Ref(t) used as a FROM source renders "alias" AS "alias", which is what a CTE reference needs.
func (Table) Qualified ¶
Qualified renders the table's physical name, with its schema prefix when set. Exported because the statement layer builds INSERT and UPDATE targets from it, and a layer boundary that forces a duplicate of this rule would be worse than exporting it.
This is the name of the thing, not the name a column qualifies with; those differ the moment a table has an alias, and Qualifier is the other one. The comment here used to claim it returned the alias when one was set, which it has never done — a write target must name the table, not its alias.
func (Table) Qualifier ¶
Qualifier is the identifier a column of this table qualifies with: the alias when there is one, otherwise the table's own name.
Schema is deliberately not part of it. A column is qualified by how the table is named in the FROM clause, so a table declared as "public"."users" is still referenced as "users"."id".
func (Table) SQL ¶
SQL renders "name AS alias", both quoted for the dialect, with the schema prefix when set.
An empty Alias renders no AS clause at all, because the alternative is worse than it looks: a quoted empty identifier. Postgres rejects "zero-length delimited identifier" outright, and the shape that produces one is ordinary — a CTE is referenced by its name and has no alias to give, so Table{Name: "regional_sales"} is the natural thing to write.
func (Table) SourceAlias ¶
SourceAlias returns the name this source is known by in the statement: the alias when there is one, otherwise the table's own name. Table satisfies Source.
The fallback is what makes the duplicate-alias check mean something for unaliased tables. Returning "" for every one of them made two different tables collide under the empty key, and made a genuine self-join with no aliases — which really is ambiguous — indistinguishable from it.
type WinFn ¶
type WinFn[T any] struct { // contains filtered or unexported fields }
WinFn is a window function or an aggregate that has not yet been given its OVER clause. It is not an Expr, so it cannot be selected without OVER; a window function without OVER is a SQL error, and the type makes it a compile error instead.
func FirstValue ¶
FirstValue renders first_value(e).
This and the two below are typed nullable on purpose: a frame can be empty, and the pointer is what makes the caller handle that instead of scanning a NULL into a value type at run time.
func LastValue ¶
LastValue renders last_value(e). With the default frame it returns the current row, not the partition's last, so it usually needs an explicit frame ending at UnboundedFollowing.
func NewWinFn ¶
NewWinFn makes a window function from a render function. Engine packages use it for functions the core does not name.
func RowNumber ¶
RowNumber renders row_number(), a distinct number per row.
This and the two below are the ranking functions every engine has. All three are typed non-null, because a rank always exists for a row.
type Window ¶
type Window struct {
// contains filtered or unexported fields
}
Window is a window specification: PARTITION BY, ORDER BY and a frame. It is a value; each method returns a modified copy, so a base window can be shared.
func (Window) Exclude ¶
func (w Window) Exclude(x FrameExclude) Window
Exclude sets the EXCLUDE part of the frame. The mechanism is here; the values are engine constants.
func (Window) Frame ¶
func (w Window) Frame(mode FrameMode, start, end FrameBound) Window
Frame sets the frame clause: mode BETWEEN start AND end.
func (Window) OrderBy ¶
OrderBy adds ordering terms. Under RANGE the ordering decides what counts as a peer, so it changes the frame and not just the sequence.
func (Window) PartitionBy ¶
PartitionBy adds partition expressions. Window is a value, so each method returns a copy and a shared base window cannot be mutated by a caller.