query

package
v0.43.0 Latest Latest
Warning

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

Go to latest
Published: Sep 28, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package query builds SQL: the Builder, the raw Expression, the index hint and the join clause.

Builder is split across files by what each half does: builder.go holds the state and the clauses everything else builds on, wheres.go and havings.go the two filter vocabularies, joins.go and subqueries.go the join and subquery families, aggregates.go the counting and the pagination, chunk.go the walks, write.go the statements that change rows, execute.go the ones that read them, and misc.go the rest.

Nothing here decides who may run what

A Builder compiles SQL. The tenant of the security.Grant is put on the statement at execution, in scoped, and on every subquery the statement carries -- a union, a `where exists`, a from, a join or a select subquery. That is not optional: a subquery is compiled whole, so a filter on the outer query says which of its rows survive and nothing about which rows went in.

A lateral join is JoinClause.Lateral rather than a type of its own, so the grammar has one type to hold. Dumping a query is Builder.Dump and Builder.DumpRawSQL, and neither ends the process.

Index

Constants

View Source
const GroupLimitGroup = "@hesape_group := "

GroupLimitGroup is the prefix of the user-variable assignment the MySQL group-limit compilation puts in the select list, and the second key Get strips.

View Source
const GroupLimitRow = "hesape_row"

GroupLimitRow is the alias the group-limit compilation gives its row-number column. Get strips it out of every row, because it is scaffolding of the query rather than data anybody asked for.

It is exported because the grammar that emits the alias and the builder that strips it have to agree on one string, and two spellings of it is a stray column in somebody's result set.

View Source
const TenantColumn = "tenant_id"

TenantColumn is the column every statement this package issues is filtered by, and the column every row it writes carries.

It is a constant and not a setting. The tenant comes off the Grant and from nowhere else; a per-query column name would be a second place for it to come from, and the query that got it wrong would still compile, still run, and still return another customer's rows.

Variables

View Source
var (
	// ErrRecordNotFound is what FirstOrFail returns when nothing matched.
	ErrRecordNotFound = errors.New("query: no record found for the given query")

	// ErrRecordsNotFound is what Sole returns when nothing matched.
	ErrRecordsNotFound = errors.New("query: no records found for the given query")

	// ErrMultipleRecordsFound is what Sole returns when more than one row
	// matched. The message carries the count.
	ErrMultipleRecordsFound = errors.New("query: multiple records found")
)

The execution half of the query builder, and the errors it raises.

The errors are declared here for the reason the Connection interface is declared here -- database imports this package, so naming them there would close the cycle.

View Source
var ErrInvalidDirection = errors.New("query: invalid order direction")

ErrInvalidDirection is returned when an order-by clause carries a direction that is neither ascending nor descending.

View Source
var ErrInvalidOperator = errors.New("query: invalid operator")

ErrInvalidOperator is returned when a non-raw query clause contains an operator the active grammar does not explicitly support.

Functions

func IsExpression

func IsExpression(value any) bool

IsExpression reports whether value is an Expression or a *Expression.

Types

type AffectingConnection

type AffectingConnection interface {
	// AffectingStatement runs a statement and returns the number of rows
	// affected.
	AffectingStatement(ctx context.Context, query string, bindings []any) (int64, error)
}

AffectingConnection is the part of a connection that the write half of the builder reaches for and Connection does not declare: the statement that returns a row count.

A connection that does not implement it still works: Update is what the fallback uses, and the count means the same thing.

type Aggregate

type Aggregate struct {
	Function string
	Columns  []any
}

Aggregate is the aggregate a Builder is compiled as: the function name and the columns it is applied to.

type BaseGrammar

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

BaseGrammar is everything a grammar can spell without knowing its dialect.

A driver grammar embeds it and overrides what its dialect spells differently. It is exported because query/grammars has to embed it.

func (*BaseGrammar) Columnize

func (g *BaseGrammar) Columnize(columns []any) string

Columnize quotes a list of columns and joins them with commas.

func (*BaseGrammar) CompileRandom

func (g *BaseGrammar) CompileRandom(seed string) string

CompileRandom compiles a random ordering expression, optionally seeded.

func (*BaseGrammar) CompileSavepoint

func (g *BaseGrammar) CompileSavepoint(name string) string

CompileSavepoint compiles a statement that creates the named savepoint.

func (*BaseGrammar) CompileSavepointRollBack

func (g *BaseGrammar) CompileSavepointRollBack(name string) string

CompileSavepointRollBack compiles a statement that rolls back to the named savepoint.

func (*BaseGrammar) Escape

func (g *BaseGrammar) Escape(value any, binary bool) (string, error)

Escape returns a value escaped for inclusion directly in SQL.

The base grammar has no connection to escape through, so it refuses. A driver grammar that can escape overrides it. This is deliberately not a best-effort quote: a caller reaching for Escape is building SQL by hand, and a value that looks escaped but is not is worse than one that refuses.

func (*BaseGrammar) GetBitwiseOperators

func (g *BaseGrammar) GetBitwiseOperators() []string

GetBitwiseOperators returns the operators treated as bitwise rather than comparison.

func (*BaseGrammar) GetDateFormat

func (g *BaseGrammar) GetDateFormat() string

GetDateFormat returns the layout the engine's date columns are formatted with, in Go's reference-time syntax.

func (*BaseGrammar) GetOperators

func (g *BaseGrammar) GetOperators() []string

GetOperators returns the comparison operators the grammar accepts.

func (*BaseGrammar) GetTablePrefix

func (g *BaseGrammar) GetTablePrefix() string

GetTablePrefix returns the prefix applied to every table name.

func (*BaseGrammar) Parameter

func (g *BaseGrammar) Parameter(value any) string

Parameter returns the placeholder for a value, or the value itself when it is an Expression.

The placeholder is "?". A grammar for an engine that numbers its placeholders overrides this, and overrides it knowing the number comes from the position in the binding list rather than from the value.

func (*BaseGrammar) Parameterize

func (g *BaseGrammar) Parameterize(values []any) string

Parameterize returns the comma-separated placeholders for a list of values.

func (*BaseGrammar) QuoteString

func (g *BaseGrammar) QuoteString(value any) string

QuoteString quotes a string literal, or each one in a list.

func (*BaseGrammar) SetTablePrefix

func (g *BaseGrammar) SetTablePrefix(prefix string) Grammar

SetTablePrefix sets the prefix applied to every table name.

func (*BaseGrammar) SupportsSavepoints

func (g *BaseGrammar) SupportsSavepoints() bool

SupportsSavepoints reports whether the engine can savepoint within a transaction.

func (*BaseGrammar) Wrap

func (g *BaseGrammar) Wrap(value any) string

Wrap quotes an identifier, splitting an aliased name into its two quoted halves.

An Expression passes through untouched, which is the whole reason Expression exists: it is how a caller says "this is SQL, not a name".

func (*BaseGrammar) WrapArray

func (g *BaseGrammar) WrapArray(values []any) []string

WrapArray quotes each value in a list of identifiers.

func (*BaseGrammar) WrapTable

func (g *BaseGrammar) WrapTable(table any) string

WrapTable quotes a table name. The table prefix is applied here and nowhere else, which is why a raw table name in a where clause is a bug that only shows up on a prefixed connection.

type Builder

type Builder struct {

	// Grammar is what compiles the query to SQL for a specific engine.
	Grammar Grammar

	// Processor is the hook that adjusts results as they come back from the
	// engine.
	Processor Processor

	// Bindings holds the query's parameter values, keyed by the seven
	// segments of a statement they belong to. The order of the keys is the
	// order they are concatenated in, which is why GetBindings walks
	// bindingOrder rather than ranging the map.
	Bindings map[string][]any

	// Columns is the select list. Nil means "not selected yet", which is
	// what lets Get default to * while an explicit Select of nothing selects
	// nothing.
	Columns []any

	// Wheres is the list of where clauses.
	Wheres []Where

	// Joins is the list of join clauses.
	Joins []*JoinClause

	// Groups is the GROUP BY column list.
	Groups []any

	// Havings is the list of having clauses.
	Havings []Having

	// Orders is the list of order-by clauses.
	Orders []Order

	// Unions is the list of queries unioned onto this one.
	Unions []Union

	// UnionOrders is the order-by list that applies to the union as a whole.
	UnionOrders []Order

	// UnionLimit is the limit that applies to the union as a whole.
	UnionLimit *int

	// UnionOffset is the offset that applies to the union as a whole.
	UnionOffset *int

	// BeforeQueryCallbacks run immediately before the query is compiled.
	BeforeQueryCallbacks []func(*Builder)

	// AfterQueryCallbacks each run over the result of Get, Pluck or Cursor
	// before it is handed back.
	AfterQueryCallbacks []func([]Record) []Record
	// contains filtered or unexported fields
}

Builder is the fluent query builder.

It builds SQL and does not decide who may run it. Authorization lives one layer up, in the repository that holds a security.Grant and filters by the tenant that Grant carries -- on reads exactly as on writes. A Builder reached without going through that layer is SQL nobody authorized, which is why nothing outside a repository should be constructing one.

Which fields are exported, and which are read through a getter

The grammar reads the builder's state directly, so the state is exported. Nine of them cannot be: from, limit, offset, distinct, lock, aggregate, timeout, groupLimit and indexHint are all a field AND a fluent method, and Go holds both in one namespace. Those are unexported and reachable through GetFrom, GetLimit, GetOffset, GetColumns, GetDistinct, GetLock, GetAggregate, GetTimeout, GetGroupLimit and GetIndexHint.

func NewBuilder

func NewBuilder(connection Connection, grammar Grammar, processor Processor) *Builder

NewBuilder creates a Builder for the given connection, grammar and processor, with an empty binding slice for each of the seven segments.

func (*Builder) AddBinding

func (b *Builder) AddBinding(value []any, typ string) *Builder

AddBinding appends value to the named binding segment.

An unknown binding type is dropped rather than appended to a key the grammar never reads. The seven names are in bindingOrder and are not open to extension.

func (*Builder) AddNestedHavingQuery

func (b *Builder) AddNestedHavingQuery(query *Builder, boolean string) *Builder

AddNestedHavingQuery folds query's havings into b as one parenthesised group.

A group with no clauses is dropped rather than compiled, for the reason AddNestedWhereQuery gives: "()" is a syntax error on every engine, and an empty callback is an ordinary outcome of a conditional filter.

func (*Builder) AddNestedWhereQuery

func (b *Builder) AddNestedWhereQuery(query *Builder, boolean string) *Builder

AddNestedWhereQuery adds query as a parenthesised group of clauses under boolean.

A group with no clauses is dropped rather than compiled, because "()" is a syntax error on every engine and an empty callback is an ordinary outcome of a conditional filter.

func (*Builder) AddSelect

func (b *Builder) AddSelect(columns ...any) *Builder

AddSelect appends columns to the select list.

func (*Builder) AddWhereExistsQuery

func (b *Builder) AddWhereExistsQuery(query *Builder, boolean string, not bool) *Builder

AddWhereExistsQuery adds query as an exists (or not-exists) clause under boolean.

func (*Builder) AfterQuery

func (b *Builder) AfterQuery(callback func([]Record) []Record) *Builder

AfterQuery registers a callback to run over the result after the query executes.

func (*Builder) Aggregate

func (b *Builder) Aggregate(ctx context.Context, g auth.Grant, function string, columns ...any) (any, error)

Aggregate runs an aggregate function over columns and returns the engine's raw result.

The result is whatever the engine returned for the aggregate column -- an int64, a float64, a string or a []byte, depending on the driver and the function. Count and NumericAggregate are the two that commit to a Go type. A nil result means the query matched nothing, which for min and max is the answer rather than an error.

func (*Builder) ApplyAfterQueryCallbacks

func (b *Builder) ApplyAfterQueryCallbacks(result []Record) []Record

ApplyAfterQueryCallbacks runs every registered AfterQuery callback over result. Each callback receives what the one before it returned, so they compose.

func (*Builder) ApplyBeforeQueryCallbacks

func (b *Builder) ApplyBeforeQueryCallbacks()

ApplyBeforeQueryCallbacks drains registered callbacks across the complete query graph, then validates every non-raw operator and order direction. Callbacks registered by callbacks are part of the same preparation and cannot run midway through SQL compilation. A callback cycle fails closed after a bounded number of rounds.

func (*Builder) Average

func (b *Builder) Average(ctx context.Context, g auth.Grant, column any) (any, error)

Average is an alias of Avg.

func (*Builder) Avg

func (b *Builder) Avg(ctx context.Context, g auth.Grant, column any) (any, error)

Avg returns the average value of column.

func (*Builder) BeforeQuery

func (b *Builder) BeforeQuery(callback func(*Builder)) *Builder

BeforeQuery registers a callback to run immediately before the query is compiled.

func (*Builder) CastBinding

func (b *Builder) CastBinding(value any) any

CastBinding returns value unchanged.

A named type over a scalar is already seen by the driver as the scalar, so there is nothing to unwrap. It stays because it is the one place a future cast would go, and because a caller looking for it should find it rather than conclude it is missing.

func (*Builder) Chunk

func (b *Builder) Chunk(ctx context.Context, g auth.Grant, count int, callback func(rows []Record, page int) bool) (bool, error)

Chunk walks the result set by offset, a page at a time, and stops when the callback returns false.

This is the chunking that skips rows. Between two pages the table can change, and every insert before the offset shifts a row past the boundary that was already read. ChunkById does not have that failure, and is what to reach for on a table that is being written to.

A limit or an offset already on the query is honoured: the offset is where the walk starts, and the limit is how many rows it reads in total.

func (*Builder) ChunkById

func (b *Builder) ChunkById(ctx context.Context, g auth.Grant, count int, callback func(rows []Record, page int) bool, column, alias string) (bool, error)

ChunkById is the chunk that does not skip rows.

Instead of counting rows to reach page n, each page asks for the rows after the last id of the page before it, so an insert or a delete anywhere in the table moves no boundary. It is the one to use for anything that walks a table while the application is running.

An empty column means the id. alias is the name that column comes back under when the select renames it -- give it whenever the query selects the key column under another name, because the walk reads the boundary out of the row by that name, and a boundary it cannot read stops the walk with an error rather than silently repeating the first page forever.

func (*Builder) ChunkByIdDesc

func (b *Builder) ChunkByIdDesc(ctx context.Context, g auth.Grant, count int, callback func(rows []Record, page int) bool, column, alias string) (bool, error)

ChunkByIdDesc is ChunkById walking from the highest id down.

func (*Builder) ChunkMap

func (b *Builder) ChunkMap(ctx context.Context, g auth.Grant, callback func(row Record) any, count int) ([]any, error)

ChunkMap chunks the query and runs callback over every row, collecting the results into a single slice.

The return type is any rather than a type parameter: a method in Go cannot introduce a type parameter of its own, and making this a function instead of a method would take it out of the chain it is written in.

func (*Builder) CleanBindings

func (b *Builder) CleanBindings(bindings []any) []any

CleanBindings drops the expressions from bindings, which were compiled into the statement and have no placeholder to fill.

func (*Builder) Clone

func (b *Builder) Clone() *Builder

Clone returns a copy of the builder.

The slices and the binding map are copied, so a clone that gains a where does not grow one on the query it was cloned from. That sharing is the bug behind every "the count query has the pagination limit on it" report.

func (*Builder) CloneWithout

func (b *Builder) CloneWithout(properties ...string) *Builder

CloneWithout returns a clone with the named properties reset to their zero value.

func (*Builder) CloneWithoutBindings

func (b *Builder) CloneWithoutBindings(except ...string) *Builder

CloneWithoutBindings returns a clone with the named binding segments cleared.

func (*Builder) Count

func (b *Builder) Count(ctx context.Context, g auth.Grant, columns ...any) (int, error)

Count returns the number of rows matching the query.

func (*Builder) CrossJoin

func (b *Builder) CrossJoin(table any, first ...any) *Builder

CrossJoin adds a cross join. With no condition it is a bare cross join; with one it compiles as an inner join.

func (*Builder) CrossJoinSub

func (b *Builder) CrossJoinSub(query any, as string) *Builder

CrossJoinSub is a cross join against a subquery, which has no condition at all.

A cross join multiplies the rows of both sides, so the subquery is the whole of what the join contributes: without a tenant filter of its own it would pair this customer's rows with every customer's. It gets one in scopeSubqueryClauses, like every other subquery here.

func (*Builder) Cursor

func (b *Builder) Cursor(ctx context.Context, g auth.Grant) iter.Seq2[Record, error]

Cursor streams the query's rows one at a time, without loading the result set into memory.

It is the one read that does not materialise its rows: the connection hands them over one at a time, and nothing here holds more than the row being yielded. That needs a connection that can stream, which is CursorConnection; a connection without it gets an error rather than a select that quietly reads the whole table into memory.

func (*Builder) CursorPaginate

func (b *Builder) CursorPaginate(ctx context.Context, g auth.Grant, perPage int, cursor *pagination.Cursor, columns []any, opts pagination.Options) (*pagination.CursorPaginator[Record], error)

CursorPaginate pages through the query using a keyset cursor instead of an offset.

The cursor is resolved by the caller -- pagination.ResolveCurrentCursor reads it off a URL -- because no request is reachable from here. A nil cursor is the first page.

func (*Builder) Decrement

func (b *Builder) Decrement(ctx context.Context, g auth.Grant, column string, amount float64, extra map[string]any) (int64, error)

Decrement subtracts amount from column. See Increment.

func (*Builder) DecrementEach

func (b *Builder) DecrementEach(ctx context.Context, g auth.Grant, columns map[string]float64, extra map[string]any) (int64, error)

DecrementEach subtracts separate amounts from multiple columns, along with any extra columns to set.

func (*Builder) Delete

func (b *Builder) Delete(ctx context.Context, g auth.Grant, id ...any) (int64, error)

Delete deletes the rows matching the query.

The optional id, when given, adds a where on the primary key, so that a single row can be removed without writing one.

func (*Builder) Distinct

func (b *Builder) Distinct(columns ...any) *Builder

Distinct marks the query as distinct.

With no argument it is a plain DISTINCT; with columns it is the engine's DISTINCT ON, which only Postgres compiles.

func (*Builder) DoesntExist

func (b *Builder) DoesntExist(ctx context.Context, g auth.Grant) (bool, error)

DoesntExist reports whether the query matches no rows.

func (*Builder) DoesntExistOr

func (b *Builder) DoesntExistOr(ctx context.Context, g auth.Grant, callback func() error) (bool, error)

DoesntExistOr reports whether the query matches no rows, running callback when rows do exist. The bool is read as ExistsOr's is.

func (*Builder) Dump

func (b *Builder) Dump(w io.Writer, args ...any) *Builder

Dump writes the statement and its bindings, and hands the query back so the chain continues.

The destination is an argument, as it is on DumpRawSQL.

What it prints is the query as written, without the tenant filter, because the filter belongs to the statement and not to the builder. DumpRawSQL takes a Grant and prints what would actually run.

func (*Builder) DumpRawSQL

func (b *Builder) DumpRawSQL(ctx context.Context, g auth.Grant, w io.Writer) *Builder

DumpRawSQL writes the statement with its bindings substituted in.

The destination is an argument, and a failed substitution is written out too -- a dump that printed nothing and returned would be the least helpful debugging tool there is.

func (*Builder) DynamicWhere

func (b *Builder) DynamicWhere(method string, parameters []any) *Builder

DynamicWhere reads a where clause out of a method name, as in "whereNameAndEmail", and binds the values positionally.

The name is an argument rather than something dispatched to, so a caller with a column list coming from configuration has one string to turn into clauses.

func (*Builder) Each

func (b *Builder) Each(ctx context.Context, g auth.Grant, callback func(row Record, index int) bool, count int) (bool, error)

Each chunks the query and runs callback over every row, passing each row's position inside its own chunk as the index.

EachById counts from the start of the walk instead, and the difference is deliberate in both.

func (*Builder) EachById

func (b *Builder) EachById(ctx context.Context, g auth.Grant, callback func(row Record, index int) bool, count int, column, alias string) (bool, error)

EachById chunks the query by id and runs callback over every row, passing each row's position since the start of the walk as the index.

The index counts from the start of the walk, not from the start of the chunk: it is (page-1)*count + i, computed from the page ChunkById reports and the row's position inside it.

func (*Builder) Err added in v0.22.0

func (b *Builder) Err() error

Err returns the first final-validation error recorded by the builder or one of its child queries.

func (*Builder) Exists

func (b *Builder) Exists(ctx context.Context, g auth.Grant) (bool, error)

Exists reports whether the query matches at least one row.

It compiles to the grammar's exists statement -- a select wrapped so the engine can stop at the first row -- rather than counting.

func (*Builder) ExistsOr

func (b *Builder) ExistsOr(ctx context.Context, g auth.Grant, callback func() error) (bool, error)

ExistsOr reports whether the query matches at least one row, running callback when it does not.

The bool is the answer to the question -- did rows exist -- and the callback contributes only its error, because a callback that returned a value would have to return the same type as `true`.

func (*Builder) Find

func (b *Builder) Find(ctx context.Context, g auth.Grant, id any, columns ...any) (Record, error)

Find adds an id filter and returns the first matching row.

It adds the where to the builder it is called on, so calling it twice with two ids asks for a row that is both.

func (*Builder) FindOr

func (b *Builder) FindOr(ctx context.Context, g auth.Grant, id any, columns []any, callback func() (Record, error)) (Record, error)

FindOr adds an id filter and returns the first matching row, or the result of callback if none matched. The columns may be nil.

func (*Builder) First

func (b *Builder) First(ctx context.Context, g auth.Grant, columns ...any) (Record, error)

First returns the first row the query matches, or nil if none did.

A nil Record means no row matched. The error is for a statement that failed, which is a different outcome and reads differently at the call site.

func (*Builder) FirstOr

func (b *Builder) FirstOr(ctx context.Context, g auth.Grant, columns []any, callback func() (Record, error)) (Record, error)

FirstOr returns the first row the query matches, or the result of callback if none did. It is the sibling of FindOr, spelled out here as well so that the two read the same and a caller who reaches for one finds the other.

The result is a Record rather than a type parameter of the callback's own choosing: a method cannot declare type parameters beyond what its receiver already has, and *Builder has none.

func (*Builder) FirstOrFail

func (b *Builder) FirstOrFail(ctx context.Context, g auth.Grant, columns []any, message ...string) (Record, error)

FirstOrFail returns the first row the query matches, or an error if none did.

The message is a variadic string wrapping ErrRecordNotFound, so errors.Is still recognises it however it was worded.

func (*Builder) ForNestedWhere

func (b *Builder) ForNestedWhere() *Builder

ForNestedWhere returns a new query sharing this one's table, for building a nested group of clauses.

func (*Builder) ForPage

func (b *Builder) ForPage(page, perPage int) *Builder

ForPage sets the limit and offset for the given page of results.

It is offset pagination, and it is the wrong tool past the first few pages: the engine counts and discards every row it skips, and a row inserted between two requests shifts the boundary so that a row is never shown. CursorPaginate in the pagination package names the boundary by value instead.

func (*Builder) ForPageAfterId

func (b *Builder) ForPageAfterId(perPage int, lastId any, column string) *Builder

ForPageAfterId narrows the query to the next page of results after a given id.

The existing ordering on that column is dropped and the column is ordered by again, last: the boundary is only a boundary if the rows come back in the order the boundary was taken from. Other orderings are kept, and the id becomes their tiebreaker.

A nil lastId is the first page, and asks for the column not to be null -- a null id can never be compared past, so a row holding one would be returned by every page.

func (*Builder) ForPageBeforeId

func (b *Builder) ForPageBeforeId(perPage int, lastId any, column string) *Builder

ForPageBeforeId narrows the query to the previous page of results before a given id. See ForPageAfterId.

func (*Builder) ForceIndex

func (b *Builder) ForceIndex(index string) *Builder

ForceIndex hints the engine to force the named index.

func (*Builder) From

func (b *Builder) From(table any, as ...string) *Builder

From sets the table the query reads from. The table may be a string or an Expression.

func (*Builder) FromRaw

func (b *Builder) FromRaw(expression string, bindings ...any) *Builder

FromRaw sets the table to a raw expression, with its own bindings.

func (*Builder) FromSub

func (b *Builder) FromSub(query any, as string) *Builder

FromSub makes the query read from a subquery rather than from a table.

func (*Builder) Get

func (b *Builder) Get(ctx context.Context, g auth.Grant, columns ...any) ([]Record, error)

Get runs the query and returns its rows.

The columns are variadic and default to every column; they only apply when nothing was selected already. They are set on the scoped copy the tenant clause is added to, so the builder the caller holds is never mutated.

func (*Builder) GetAggregate

func (b *Builder) GetAggregate() *Aggregate

GetAggregate returns the aggregate being compiled, if any. Mechanical, for the same reason as GetFrom.

func (*Builder) GetBindings

func (b *Builder) GetBindings() []any

GetBindings returns every binding, flattened in the order the compiled statement consumes them.

func (*Builder) GetColumns

func (b *Builder) GetColumns() []any

GetColumns returns the select list, with any Expression rendered to the SQL it carries rather than returned as the object.

It returns an empty slice rather than nil when nothing was selected, so a caller ranging the result never has to special-case nil.

func (*Builder) GetConnection

func (b *Builder) GetConnection() Connection

GetConnection returns the connection the query runs against.

func (*Builder) GetCountForPagination

func (b *Builder) GetCountForPagination(ctx context.Context, g auth.Grant, columns ...any) (int, error)

GetCountForPagination returns the total number of rows the query matches, ignoring any limit or offset.

func (*Builder) GetDistinct

func (b *Builder) GetDistinct() any

GetDistinct returns the DISTINCT state: false, true, or the columns of a DISTINCT ON. Mechanical, for the same reason as GetFrom.

func (*Builder) GetFrom

func (b *Builder) GetFrom() any

GetFrom returns the table the query reads from.

The fluent From method claimed the name "from" in Go's single namespace, so the underlying state is unexported and reachable only through this getter.

func (*Builder) GetGrammar

func (b *Builder) GetGrammar() Grammar

GetGrammar returns the grammar the query compiles through.

func (*Builder) GetGroupLimit

func (b *Builder) GetGroupLimit() *GroupLimit

GetGroupLimit returns the per-group limit, if one was set. Mechanical, for the same reason as GetFrom.

func (*Builder) GetIndexHint

func (b *Builder) GetIndexHint() *IndexHint

GetIndexHint returns the index hint, if one was set. Mechanical, for the same reason as GetFrom.

func (*Builder) GetLimit

func (b *Builder) GetLimit() *int

GetLimit returns the row limit, if one was set. Mechanical, for the same reason as GetFrom.

func (*Builder) GetLock

func (b *Builder) GetLock() any

GetLock returns the lock state. Mechanical, for the same reason as GetFrom.

func (*Builder) GetOffset

func (b *Builder) GetOffset() *int

GetOffset returns the row offset, if one was set. Mechanical, for the same reason as GetFrom.

func (*Builder) GetProcessor

func (b *Builder) GetProcessor() Processor

GetProcessor returns the processor that adjusts the query's results.

func (*Builder) GetRawBindings

func (b *Builder) GetRawBindings() map[string][]any

GetRawBindings returns the bindings keyed by segment, unflattened.

func (*Builder) GetTimeout

func (b *Builder) GetTimeout() *int

GetTimeout returns the statement timeout in seconds, if one was set. Mechanical, for the same reason as GetFrom.

func (*Builder) GroupBy

func (b *Builder) GroupBy(groups ...any) *Builder

GroupBy adds columns to the GROUP BY list.

func (*Builder) GroupByRaw

func (b *Builder) GroupByRaw(sql string, bindings ...any) *Builder

GroupByRaw adds a raw expression to the GROUP BY list, with its own bindings.

func (*Builder) GroupLimit

func (b *Builder) GroupLimit(value int, column string) *Builder

GroupLimit limits the number of rows per group of column, for a "top N per group" query.

func (*Builder) Having

func (b *Builder) Having(column any, args ...any) *Builder

Having adds a having clause. The body is in havings.go, shared with OrHaving: the two differ by their conjunction and by nothing else.

func (*Builder) HavingBetween

func (b *Builder) HavingBetween(column any, values []any, boolean string, not bool) *Builder

HavingBetween adds a having that requires column to fall between the first two values, or outside them when not is true.

Only the first two values are bound: a between has two bounds, and a longer list is a caller mistake that would otherwise leave bindings with no placeholder to fill.

func (*Builder) HavingNested

func (b *Builder) HavingNested(callback func(*Builder), boolean string) *Builder

HavingNested runs callback against a fresh nested query and folds its havings in as one parenthesised group.

func (*Builder) HavingNotBetween

func (b *Builder) HavingNotBetween(column any, values []any, boolean string) *Builder

HavingNotBetween is HavingBetween with not set to true.

func (*Builder) HavingNotNull

func (b *Builder) HavingNotNull(columns []any, boolean string) *Builder

HavingNotNull is HavingNull with not set to true.

func (*Builder) HavingNull

func (b *Builder) HavingNull(columns []any, boolean string, not bool) *Builder

HavingNull adds a having that requires columns to be null, or not null when not is true.

func (*Builder) HavingRaw

func (b *Builder) HavingRaw(sql string, bindings ...any) *Builder

HavingRaw adds a raw having clause, with its own bindings.

func (*Builder) IgnoreIndex

func (b *Builder) IgnoreIndex(index string) *Builder

IgnoreIndex hints the engine to ignore the named index.

func (*Builder) Implode

func (b *Builder) Implode(ctx context.Context, g auth.Grant, column any, glue string) (string, error)

Implode plucks column across every matching row and joins the values with glue.

func (*Builder) InRandomOrder

func (b *Builder) InRandomOrder(seed ...string) *Builder

InRandomOrder orders the results randomly, optionally seeded.

func (*Builder) Increment

func (b *Builder) Increment(ctx context.Context, g auth.Grant, column string, amount float64, extra map[string]any) (int64, error)

Increment adds amount to column, along with any extra columns to set.

A non-numeric amount does not compile: Go's float64 parameter type enforces that guarantee at the call site, before the query ever runs.

extra is the columns to set alongside, and may be nil.

func (*Builder) IncrementEach

func (b *Builder) IncrementEach(ctx context.Context, g auth.Grant, columns map[string]float64, extra map[string]any) (int64, error)

IncrementEach adds separate amounts to multiple columns, along with any extra columns to set.

func (*Builder) Insert

func (b *Builder) Insert(ctx context.Context, g auth.Grant, values ...map[string]any) (bool, error)

Insert inserts one row or many.

Variadic arguments accept either shape directly, without needing to inspect whether the caller passed one row or a list.

The rows are copied before the tenant is stamped into them, so a caller's map does not gain a column it never asked for.

func (*Builder) InsertGetID

func (b *Builder) InsertGetID(ctx context.Context, g auth.Grant, values map[string]any, sequence string) (int64, error)

InsertGetID inserts a row and returns the id the engine assigned it.

sequence is the name of the sequence the id comes from, which Postgres needs and the other engines ignore. Empty means the engine's default.

func (*Builder) InsertOrIgnore

func (b *Builder) InsertOrIgnore(ctx context.Context, g auth.Grant, values ...map[string]any) (int64, error)

InsertOrIgnore inserts rows, letting the engine drop the ones that would violate a unique constraint, and returns how many it kept.

func (*Builder) InsertOrIgnoreReturning

func (b *Builder) InsertOrIgnoreReturning(ctx context.Context, g auth.Grant, values []map[string]any, uniqueBy, returning []string) ([]Record, error)

InsertOrIgnoreReturning inserts rows, letting the engine drop the ones that would collide, and returns the rows it kept rather than a count.

The rows carry the tenant of the Grant, as every insert here does, and the statement goes to the write connection: the rows it returns were written microseconds ago and a replica has not seen them.

func (*Builder) InsertOrIgnoreUsing

func (b *Builder) InsertOrIgnoreUsing(ctx context.Context, g auth.Grant, columns []any, query any) (int64, error)

InsertOrIgnoreUsing is InsertUsing letting the engine drop the rows that would collide.

func (*Builder) InsertUsing

func (b *Builder) InsertUsing(ctx context.Context, g auth.Grant, columns []any, query any) (int64, error)

InsertUsing is an insert whose rows come from a select rather than from values.

query may be a *Builder, a func(*Builder) or a string of SQL. A *Builder or a callback is scoped by the same Grant before it is compiled -- an insert reading from a select is a read, and a read that skipped the tenant would copy another customer's rows into this one's table.

A string is taken as written. Nothing here can add a tenant filter to SQL it did not build, which is the reason to hand it a builder instead.

func (*Builder) Join

func (b *Builder) Join(table any, first any, args ...any) *Builder

Join adds an inner join.

func (*Builder) JoinLateral

func (b *Builder) JoinLateral(query any, as string, typ string) *Builder

JoinLateral joins against a subquery that may name the columns of the rows already joined.

func (*Builder) JoinSub

func (b *Builder) JoinSub(query any, as string, first any, operator, second any, typ string, isWhere bool) *Builder

JoinSub joins against a subquery.

typ is the join type -- inner, left, right, cross or straight_join -- and isWhere says whether the condition compares a column with a value rather than with another column.

func (*Builder) JoinWhere

func (b *Builder) JoinWhere(table any, first any, operator, second any, typ string) *Builder

JoinWhere adds a join whose condition compares a column with a value.

func (*Builder) Latest

func (b *Builder) Latest(column ...any) *Builder

Latest adds a descending order-by clause. The column defaults to created_at.

func (*Builder) Lazy

func (b *Builder) Lazy(ctx context.Context, g auth.Grant, chunkSize int) iter.Seq2[Record, error]

Lazy walks the result set by offset, a page at a time, and returns an iter.Seq2 that yields one row at a time without materialising the whole result set.

The second value is the error, because a walk that fails halfway has nowhere else to report it and a sequence that just stopped early would read as "the table ended here" -- which is the same answer as success and is why this is not a Seq of rows.

The sequence walks by offset and skips rows for the reason Chunk does. LazyById is the one that holds still.

func (*Builder) LazyById

func (b *Builder) LazyById(ctx context.Context, g auth.Grant, chunkSize int, column, alias string) iter.Seq2[Record, error]

LazyById is Lazy walking by key instead of by offset, so that a table written to during the walk neither repeats a row nor skips one.

func (*Builder) LazyByIdDesc

func (b *Builder) LazyByIdDesc(ctx context.Context, g auth.Grant, chunkSize int, column, alias string) iter.Seq2[Record, error]

LazyByIdDesc is LazyById walking from the highest id down.

func (*Builder) LeftJoin

func (b *Builder) LeftJoin(table any, first any, args ...any) *Builder

LeftJoin adds a left join.

func (*Builder) LeftJoinLateral

func (b *Builder) LeftJoinLateral(query any, as string) *Builder

LeftJoinLateral is JoinLateral with typ set to "left".

func (*Builder) LeftJoinSub

func (b *Builder) LeftJoinSub(query any, as string, first any, operator, second any) *Builder

LeftJoinSub is JoinSub with typ set to "left".

func (*Builder) LeftJoinWhere

func (b *Builder) LeftJoinWhere(table any, first any, operator, second any) *Builder

LeftJoinWhere is JoinWhere with typ set to "left".

func (*Builder) Limit

func (b *Builder) Limit(value int) *Builder

Limit sets the row limit. A negative limit is dropped rather than applied.

func (*Builder) Lock

func (b *Builder) Lock(value any) *Builder

Lock sets the row-locking clause.

func (*Builder) LockForUpdate

func (b *Builder) LockForUpdate() *Builder

LockForUpdate locks the selected rows for update.

func (*Builder) Max

func (b *Builder) Max(ctx context.Context, g auth.Grant, column any) (any, error)

Max returns the maximum value of column.

func (*Builder) MergeBindings

func (b *Builder) MergeBindings(query *Builder) *Builder

MergeBindings appends query's bindings onto this builder's, segment by segment.

func (*Builder) MergeWheres

func (b *Builder) MergeWheres(wheres []Where, bindings []any) *Builder

MergeWheres appends another query's where clauses and bindings onto this one.

The bindings are appended to the where segment as given. They are the caller's to line up with the clauses: the two arguments are the two halves of somebody else's query, and nothing here can check that they match.

func (*Builder) Min

func (b *Builder) Min(ctx context.Context, g auth.Grant, column any) (any, error)

Min returns the minimum value of column.

func (*Builder) NewQuery

func (b *Builder) NewQuery() *Builder

NewQuery returns a new Builder sharing this one's connection, grammar and processor.

func (*Builder) NumericAggregate

func (b *Builder) NumericAggregate(ctx context.Context, g auth.Grant, function string, columns ...any) (float64, error)

NumericAggregate runs an aggregate function and casts the result to a number.

It returns a float64 rather than committing to int or float depending on the driver's answer: Go has one number type that holds both, and nothing is lost -- an int64 that survives a float64 round trip is every count a database will produce short of 2^53 rows.

func (*Builder) Offset

func (b *Builder) Offset(value int) *Builder

Offset sets the row offset. A negative offset reads as zero.

func (*Builder) Oldest

func (b *Builder) Oldest(column ...any) *Builder

Oldest adds an ascending order-by clause. The column defaults to created_at.

func (*Builder) OrHaving

func (b *Builder) OrHaving(column any, args ...any) *Builder

OrHaving is addHaving joined with "or".

func (*Builder) OrHavingBetween

func (b *Builder) OrHavingBetween(column any, values []any) *Builder

OrHavingBetween is HavingBetween joined with "or".

func (*Builder) OrHavingNotBetween

func (b *Builder) OrHavingNotBetween(column any, values []any) *Builder

OrHavingNotBetween is HavingBetween joined with "or" and not set to true.

func (*Builder) OrHavingNotNull

func (b *Builder) OrHavingNotNull(columns ...any) *Builder

OrHavingNotNull is HavingNotNull joined with "or".

func (*Builder) OrHavingNull

func (b *Builder) OrHavingNull(columns ...any) *Builder

OrHavingNull is HavingNull joined with "or".

func (*Builder) OrHavingRaw

func (b *Builder) OrHavingRaw(sql string, bindings ...any) *Builder

OrHavingRaw adds a raw having clause joined with "or".

func (*Builder) OrWhere

func (b *Builder) OrWhere(column any, args ...any) *Builder

OrWhere adds an "or" basic where clause.

func (*Builder) OrWhereAll

func (b *Builder) OrWhereAll(columns []any, args ...any) *Builder

OrWhereAll adds an "or" version of WhereAll.

func (*Builder) OrWhereAny

func (b *Builder) OrWhereAny(columns []any, args ...any) *Builder

OrWhereAny adds an "or" version of WhereAny.

func (*Builder) OrWhereBetween

func (b *Builder) OrWhereBetween(column any, from, to any) *Builder

OrWhereBetween adds an "or" between clause.

func (*Builder) OrWhereBetweenColumns

func (b *Builder) OrWhereBetweenColumns(column any, values []any) *Builder

OrWhereBetweenColumns adds an "or" between-columns clause.

func (*Builder) OrWhereColumn

func (b *Builder) OrWhereColumn(first any, args ...any) *Builder

OrWhereColumn adds an "or" clause comparing two columns.

func (*Builder) OrWhereDate

func (b *Builder) OrWhereDate(column any, args ...any) *Builder

OrWhereDate adds an "or" date clause.

func (*Builder) OrWhereDay

func (b *Builder) OrWhereDay(column any, args ...any) *Builder

OrWhereDay adds an "or" day clause.

func (*Builder) OrWhereExists

func (b *Builder) OrWhereExists(callback func(*Builder), not ...bool) *Builder

OrWhereExists adds an "or exists" clause for the subquery the callback builds, optionally negated.

func (*Builder) OrWhereFullText

func (b *Builder) OrWhereFullText(columns []any, value any, options map[string]any) *Builder

OrWhereFullText adds an "or" full-text search clause.

func (*Builder) OrWhereIn

func (b *Builder) OrWhereIn(column any, values []any) *Builder

OrWhereIn adds an "or" where-in clause.

func (*Builder) OrWhereIntegerInRaw

func (b *Builder) OrWhereIntegerInRaw(column any, values []any) *Builder

OrWhereIntegerInRaw adds an "or" where-in clause with raw integer values.

func (*Builder) OrWhereIntegerNotInRaw

func (b *Builder) OrWhereIntegerNotInRaw(column any, values []any) *Builder

OrWhereIntegerNotInRaw adds an "or" where-not-in clause with raw integer values.

func (*Builder) OrWhereJSONContains

func (b *Builder) OrWhereJSONContains(column any, value any) *Builder

OrWhereJSONContains adds an "or" JSON-contains clause.

func (*Builder) OrWhereJSONContainsKey

func (b *Builder) OrWhereJSONContainsKey(column any) *Builder

OrWhereJSONContainsKey adds an "or" JSON-contains-key clause.

func (*Builder) OrWhereJSONDoesntContain

func (b *Builder) OrWhereJSONDoesntContain(column any, value any) *Builder

OrWhereJSONDoesntContain adds an "or" JSON-does-not-contain clause.

func (*Builder) OrWhereJSONDoesntContainKey

func (b *Builder) OrWhereJSONDoesntContainKey(column any) *Builder

OrWhereJSONDoesntContainKey adds an "or" JSON-does-not-contain-key clause.

func (*Builder) OrWhereJSONDoesntOverlap

func (b *Builder) OrWhereJSONDoesntOverlap(column any, value any) *Builder

OrWhereJSONDoesntOverlap adds an "or" JSON-does-not-overlap clause.

func (*Builder) OrWhereJSONLength

func (b *Builder) OrWhereJSONLength(column any, args ...any) *Builder

OrWhereJSONLength adds an "or" JSON-length clause.

func (*Builder) OrWhereJSONOverlaps

func (b *Builder) OrWhereJSONOverlaps(column any, value any) *Builder

OrWhereJSONOverlaps adds an "or" JSON-overlaps clause.

func (*Builder) OrWhereLike

func (b *Builder) OrWhereLike(column any, value any, caseSensitive bool) *Builder

OrWhereLike adds an "or" LIKE clause.

func (*Builder) OrWhereMonth

func (b *Builder) OrWhereMonth(column any, args ...any) *Builder

OrWhereMonth adds an "or" month clause.

func (*Builder) OrWhereNone

func (b *Builder) OrWhereNone(columns []any, args ...any) *Builder

OrWhereNone adds an "or" version of WhereNone.

func (*Builder) OrWhereNotBetween

func (b *Builder) OrWhereNotBetween(column any, from, to any) *Builder

OrWhereNotBetween adds an "or" not-between clause.

func (*Builder) OrWhereNotBetweenColumns

func (b *Builder) OrWhereNotBetweenColumns(column any, values []any) *Builder

OrWhereNotBetweenColumns adds an "or" not-between-columns clause.

func (*Builder) OrWhereNotExists

func (b *Builder) OrWhereNotExists(callback func(*Builder)) *Builder

OrWhereNotExists adds an "or not exists" clause for the subquery the callback builds.

func (*Builder) OrWhereNotIn

func (b *Builder) OrWhereNotIn(column any, values []any) *Builder

OrWhereNotIn adds an "or" where-not-in clause.

func (*Builder) OrWhereNotLike

func (b *Builder) OrWhereNotLike(column any, value any, caseSensitive bool) *Builder

OrWhereNotLike adds an "or" NOT LIKE clause.

func (*Builder) OrWhereNotNull

func (b *Builder) OrWhereNotNull(columns ...any) *Builder

OrWhereNotNull adds an "or" is-not-NULL clause.

func (*Builder) OrWhereNull

func (b *Builder) OrWhereNull(columns ...any) *Builder

OrWhereNull adds an "or" is-NULL clause.

func (*Builder) OrWhereRaw

func (b *Builder) OrWhereRaw(sql string, bindings ...any) *Builder

OrWhereRaw adds an "or" raw SQL where clause.

func (*Builder) OrWhereRowValues

func (b *Builder) OrWhereRowValues(columns []any, operator string, values []any) *Builder

OrWhereRowValues adds an "or" row-values clause.

func (*Builder) OrWhereTime

func (b *Builder) OrWhereTime(column any, args ...any) *Builder

OrWhereTime adds an "or" time clause.

func (*Builder) OrWhereValueBetween

func (b *Builder) OrWhereValueBetween(value any, columns []any) *Builder

OrWhereValueBetween adds an "or" value-between-columns clause.

func (*Builder) OrWhereValueNotBetween

func (b *Builder) OrWhereValueNotBetween(value any, columns []any) *Builder

OrWhereValueNotBetween adds an "or" value-not-between-columns clause.

func (*Builder) OrWhereVectorDistanceLessThan

func (b *Builder) OrWhereVectorDistanceLessThan(column any, vector []float64, maxDistance float64) *Builder

OrWhereVectorDistanceLessThan adds an "or" vector-distance clause.

func (*Builder) OrWhereYear

func (b *Builder) OrWhereYear(column any, args ...any) *Builder

OrWhereYear adds an "or" year clause.

func (*Builder) OrderBy

func (b *Builder) OrderBy(column any, direction ...string) *Builder

OrderBy adds an order-by clause. A direction other than asc or desc is a caller writing SQL into a direction, so anything else reads as asc.

func (*Builder) OrderByDesc

func (b *Builder) OrderByDesc(column any) *Builder

OrderByDesc adds a descending order-by clause.

func (*Builder) OrderByRaw

func (b *Builder) OrderByRaw(sql string, bindings ...any) *Builder

OrderByRaw adds a raw order-by expression, with its own bindings.

func (*Builder) OrderByVectorDistance

func (b *Builder) OrderByVectorDistance(column any, vector []float64) *Builder

OrderByVectorDistance orders by the distance between a column's embedding and the vector given, nearest first.

func (*Builder) OrderedChunkById

func (b *Builder) OrderedChunkById(ctx context.Context, g auth.Grant, count int, callback func(rows []Record, page int) bool, column, alias string, descending bool) (bool, error)

OrderedChunkById is the shared body of ChunkById and ChunkByIdDesc.

Each page runs on a copy of the query, because ForPageAfterId adds a where and rewrites the ordering: applying that to the query itself would leave the previous page's boundary on the next page's statement, and the walk would stand still.

An offset already on the query applies to the first page only. After that the id boundary is doing the skipping, and skipping again would drop a page's worth of rows on every page.

func (*Builder) Paginate

func (b *Builder) Paginate(ctx context.Context, g auth.Grant, perPage, page int, columns []any, opts pagination.Options, total ...int) (*pagination.LengthAwarePaginator[Record], error)

Paginate runs the query for one page and returns a length-aware paginator.

No request is reachable from here, so the page number is an argument and the path is a field of pagination.Options, along with the name of the page parameter.

total is a count the caller already has. Leaving it out runs GetCountForPagination, which is one extra statement -- the one SimplePaginate exists to avoid.

func (*Builder) Pipe

func (b *Builder) Pipe(callback func(*Builder) *Builder) *Builder

Pipe hands the query to callback, and returns what callback returned, or the query itself if callback returned nil.

func (*Builder) Pluck

func (b *Builder) Pluck(ctx context.Context, g auth.Grant, column any, key ...any) (values []any, keyed map[string]any, err error)

Pluck returns the values of column across every matching row, in row order, and -- only when a key column is named -- the same values keyed by it. keyed is nil when no key column was given.

The keys are always strings: a key value is formatted to a string on the way in, whatever type it arrived as.

func (*Builder) PrepareValueAndOperator

func (b *Builder) PrepareValueAndOperator(value, operator any, useDefault bool) (any, string, error)

PrepareValueAndOperator resolves the value and operator for a where clause that may have been built from two arguments or three.

When useDefault is true, operator is treated as the value and the comparison operator defaults to "="; otherwise value and operator are returned as given, after checking the combination.

It returns an error for the combination it refuses: an operator with no value, such as where('votes', '>'), which would otherwise compile to a comparison against NULL and quietly match nothing.

The fluent methods do not call it; they use the unexported prepareValueAndOperator, which reads the same two-or-three-argument distinction off the length of a variadic slice. This one is exported because a caller assembling an operator and a value from user input has the same combination to validate.

It screens and reports; it does not record the refusal on the builder. A caller validating a combination is expected to handle the error and fall back to something safe, and a builder that had been disabled by the question would drop every clause added after it. Nothing is given up by staying quiet: the operator returned here is not what reaches SQL. Where, Having and On screen what they are given, and the final barrier screens the whole graph again against the compiling grammar before a statement is built.

func (*Builder) Raw

func (b *Builder) Raw(value any) Expression

Raw returns value wrapped as an Expression.

It is a method on Builder for symmetry with the fluent chain; Raw is the package function that actually builds one.

func (*Builder) RawValue

func (b *Builder) RawValue(ctx context.Context, g auth.Grant, expression string, bindings ...any) (any, error)

RawValue returns the value of a raw expression from the query's first matching row.

Alias the expression -- rawValue("count(*) as total") -- when the query already selects something: a Go map has no first column, so the alias is the name the value is found under.

func (*Builder) Reorder

func (b *Builder) Reorder(column any, direction ...string) *Builder

Reorder drops every order-by clause, and adds one back when given a column. Pass nil to drop the ordering and add nothing.

func (*Builder) ReorderDesc

func (b *Builder) ReorderDesc(column any) *Builder

ReorderDesc drops every order-by clause and adds one back in descending order.

func (*Builder) RightJoin

func (b *Builder) RightJoin(table any, first any, args ...any) *Builder

RightJoin adds a right join.

func (*Builder) RightJoinSub

func (b *Builder) RightJoinSub(query any, as string, first any, operator, second any) *Builder

RightJoinSub is JoinSub with typ set to "right".

func (*Builder) RightJoinWhere

func (b *Builder) RightJoinWhere(table any, first any, operator, second any) *Builder

RightJoinWhere is JoinWhere with typ set to "right".

func (*Builder) ScopeNested

func (b *Builder) ScopeNested(ctx context.Context, g auth.Grant) error

ScopeNested puts the tenant on every query nested inside this one: the far side of a union, the subquery of a `where exists`, of a `where in` and of a count comparison, and the subqueries compiled into a from, a select or a join.

It is the second half of scoped, and it is exported because it is the half the model builder has to end in too. That builder cannot call scoped whole: it filters by the model's own tenant column, which a model whose table has none sets to the empty string, and TenantColumn here is a constant on purpose -- see its comment. The nested half has no such difference, and it is where every leak found so far lived, so there is one of it and both builders run it.

Until it was exported the model builder reached none of it. GetModels sent b.query.ToSQL() straight to the connection, so scopeUnions, scopeSubqueries and scopeSubqueryClauses were dead code on the path the application uses: Users.WithCount("posts").Get(g) came back with every tenant's posts counted into posts_count, and WhereHas("posts", ...) filtered one tenant's users by another tenant's rows.

It runs on the statement being built and never on the builder the caller holds -- scoped calls it on a clone, and the model builder on the clone ApplyScopes made.

func (*Builder) Select

func (b *Builder) Select(columns ...any) *Builder

Select sets the columns to select, replacing any previous selection. AddSelect is how a column is appended instead.

func (*Builder) SelectExistsSub

func (b *Builder) SelectExistsSub(query any, as string) *Builder

SelectExistsSub is SelectSub for a subquery asked as a yes or no: it compiles to `exists (select ...) as alias`.

The model builder's WithExists used to write the whole column as raw SQL, which is a subquery nothing can scope afterwards -- and that is what Users.WithExists("posts").Get(g) proved: the column asked whether ANY tenant had a post for that user. This is selectSub with the one operator that column needs, so the exists form goes through the same bookkeeping every other subquery does. See pendingSub.

func (*Builder) SelectExpression

func (b *Builder) SelectExpression(expression any, as string) *Builder

SelectExpression adds an expression as one column, under an alias. It binds nothing, because an expression is SQL.

func (*Builder) SelectRaw

func (b *Builder) SelectRaw(expression string, bindings ...any) *Builder

SelectRaw adds a raw expression to the select list, with its own bindings.

func (*Builder) SelectSub

func (b *Builder) SelectSub(query any, as string) *Builder

SelectSub adds a subquery as one column of the select list.

func (*Builder) SelectVectorDistance

func (b *Builder) SelectVectorDistance(column any, vector []float64, as string) *Builder

SelectVectorDistance adds the distance between a column's embedding and the vector given, as a column of the result.

as defaults to the column's name with _distance appended.

Accepting a string as the vector, and turning it into an embedding through a model provider, is not supported here, for the reason WhereVectorDistanceLessThan gives.

func (*Builder) SetAggregate

func (b *Builder) SetAggregate(function string, columns []any) *Builder

SetAggregate sets the aggregate function and columns being compiled.

It also drops the ordering when there is no GROUP BY, which is easy to miss and is the half that matters: ORDER BY on an aggregate with no grouping is a sort of one row, and MySQL in strict mode refuses it outright when the ordering column is not in the select. The order bindings go with it, or the placeholders and the values stop lining up.

func (*Builder) SetBindings

func (b *Builder) SetBindings(bindings []any, typ string) *Builder

SetBindings replaces the bindings of the named segment.

func (*Builder) SharedLock

func (b *Builder) SharedLock() *Builder

SharedLock locks the selected rows with a shared lock.

func (*Builder) SimplePaginate

func (b *Builder) SimplePaginate(ctx context.Context, g auth.Grant, perPage, page int, columns []any, opts pagination.Options) (*pagination.Paginator[Record], error)

SimplePaginate runs the query for one page without counting the total.

It reads one row more than the page holds, and that extra row is the whole of how it resolves "is there a next page" without a count. pagination.SimplePaginate drops it before anybody sees it.

func (*Builder) Skip

func (b *Builder) Skip(value int) *Builder

Skip is an alias of Offset.

func (*Builder) Sole

func (b *Builder) Sole(ctx context.Context, g auth.Grant, columns ...any) (Record, error)

Sole returns the query's only matching row, and errors if there is not exactly one.

It reads two rows to find out whether there is more than one, and reports ErrRecordsNotFound or ErrMultipleRecordsFound.

func (*Builder) SoleValue

func (b *Builder) SoleValue(ctx context.Context, g auth.Grant, column any) (any, error)

SoleValue returns the value of column from the query's only matching row, erroring as Sole does if there is not exactly one.

func (*Builder) StraightJoin

func (b *Builder) StraightJoin(table any, first any, operator, second any) *Builder

StraightJoin is MySQL's join that forbids the planner from reordering the tables.

Every other engine is handed the type as written and rejects it, which is what the grammar's SupportsStraightJoins reports.

func (*Builder) StraightJoinSub

func (b *Builder) StraightJoinSub(query any, as string, first any, operator, second any) *Builder

StraightJoinSub is JoinSub with typ set to "straight_join".

func (*Builder) StraightJoinWhere

func (b *Builder) StraightJoinWhere(table any, first any, operator, second any) *Builder

StraightJoinWhere is JoinWhere with typ set to "straight_join".

func (*Builder) Sum

func (b *Builder) Sum(ctx context.Context, g auth.Grant, column any) (any, error)

Sum returns the sum of column. A sum over no rows is zero rather than nil.

func (*Builder) Take

func (b *Builder) Take(value int) *Builder

Take is an alias of Limit.

func (*Builder) Tap

func (b *Builder) Tap(callback func(*Builder)) *Builder

Tap hands the query to callback and returns the query.

func (*Builder) Timeout

func (b *Builder) Timeout(seconds int) *Builder

Timeout sets the statement timeout, in seconds.

func (*Builder) ToRawSQL

func (b *Builder) ToRawSQL(ctx context.Context, g auth.Grant) (string, error)

ToRawSQL returns the statement with the bindings written into it, for reading rather than for running.

It carries an error because escaping a value needs a connection to escape through, and Grammar.Escape reports that rather than handing back a value that looks quoted and is not.

It takes the Grant because what it prints has to be what would run, tenant clause and all. A raw SQL dump that showed a query without its tenant filter would teach the reader that the filter is not there.

func (*Builder) ToSQL

func (b *Builder) ToSQL() string

ToSQL runs the before-query callbacks and compiles the query to a select statement.

func (*Builder) Truncate

func (b *Builder) Truncate(ctx context.Context, g auth.Grant) error

Truncate empties the entire table, all tenants at once.

Read this before calling it. A truncate takes no where clause on any engine, so this is the one statement in the package that cannot carry the tenant: it empties the table for every customer in it, and the Grant it requires authorizes that rather than narrowing it. Deleting one tenant's rows is Delete, which is filtered.

It is more than one statement on some engines -- Postgres and SQL Server reset the sequence separately -- which is why the grammar returns a map of statements to bindings.

func (*Builder) Union

func (b *Builder) Union(query *Builder, all ...bool) *Builder

Union appends query as a union, or a union all when all is true.

func (*Builder) UnionAll

func (b *Builder) UnionAll(query *Builder) *Builder

UnionAll appends query as a union all.

func (*Builder) Unless

func (b *Builder) Unless(condition bool, callback, otherwise func(*Builder)) *Builder

Unless is When with the condition negated.

func (*Builder) Update

func (b *Builder) Update(ctx context.Context, g auth.Grant, values map[string]any) (int64, error)

Update updates the rows matching the query with the given column values.

A value may be a *Builder, which becomes the subquery it compiles to, with its bindings landing where its placeholders are. Such a subquery is scoped by the Grant first, for the reason InsertUsing's is.

A value under TenantColumn is replaced by the Grant's tenant rather than written: an update that moved a row to another tenant would pass its own where clause on the way out and be unreachable afterwards.

Two maps go to the grammar -- the values to compile and the bindings to send -- and both are keyed by column, so the grammar has to walk them in sorted key order for the placeholders and the values to line up.

func (*Builder) UpdateFrom

func (b *Builder) UpdateFrom(ctx context.Context, g auth.Grant, values map[string]any) (int64, error)

UpdateFrom runs an "update ... from" statement, which only Postgres compiles.

func (*Builder) UpdateOrInsert

func (b *Builder) UpdateOrInsert(ctx context.Context, g auth.Grant, attributes, values map[string]any) (bool, error)

UpdateOrInsert updates the first row matching attributes, or inserts one combining attributes and values if none matches.

attributes expands into one where clause per pair, added in sorted key order, so that two calls with the same attributes compile to the same statement.

values may be nil, which updates nothing and reports that the row is there.

func (*Builder) Upsert

func (b *Builder) Upsert(ctx context.Context, g auth.Grant, values []map[string]any, uniqueBy []string, update []string) (int64, error)

Upsert inserts these rows, and updates the ones that collide on uniqueBy.

update names the columns an existing row takes from the new one. Nil means all of them; an empty non-nil slice means none, and turns the whole statement into a plain insert. Go's nil/empty-slice distinction is what keeps the two cases apart.

uniqueBy should name the tenant column too. The rows carry the tenant, but the conflict target is a unique index, and an index that does not include the tenant is a constraint shared between customers.

func (*Builder) UseIndex

func (b *Builder) UseIndex(index string) *Builder

UseIndex hints the engine to use the named index.

func (*Builder) UseWritePDO

func (b *Builder) UseWritePDO() *Builder

UseWritePDO sends the read to the write connection, for the case a replica has not caught up yet: a row inserted and read back in the same request is not there on a replica that is two hundred milliseconds behind.

The state behind it is unexported and read through UsingWritePDO, for the same reason From, Limit and Offset are: it is both a field and a fluent method, and Go holds both in one namespace.

func (*Builder) UsingWritePDO

func (b *Builder) UsingWritePDO() bool

UsingWritePDO reports whether the read goes to the write connection. Mechanical, for the reason UseWritePDO gives.

func (*Builder) ValidateForCompilation added in v0.22.0

func (b *Builder) ValidateForCompilation() error

ValidateForCompilation applies the final barrier to the complete query graph without executing callbacks: every non-raw operator and every order direction has to be one the grammar declares. Grammar compilers use it to reject direct public-field mutations while leaving callback lifecycle ownership to Builder execution methods.

func (*Builder) ValidateForCompilationWith added in v0.22.0

func (b *Builder) ValidateForCompilationWith(compiler Grammar) error

ValidateForCompilationWith applies the same barrier under the operator policy of the grammar that is about to spell the SQL, which is not always the one the builder was given: a builder assembled for one dialect can be handed straight to another dialect's compiler, and the engine that receives the statement is the one that decides how each token reads.

The grammar the builder carries stays in the conversation, but only for word operators, which is how a grammar extending a dialect keeps the operators it adds. A nil compiler leaves the operators every dialect shares.

func (*Builder) Value

func (b *Builder) Value(ctx context.Context, g auth.Grant, column any) (any, error)

Value returns the value of column from the query's first matching row.

A Record is a map and a map has no first, so the value is the only one when the row holds one, and otherwise the one under the column's own name -- with the table qualifier and the alias stripped, which is what the driver keys it by.

func (*Builder) When

func (b *Builder) When(condition bool, callback, otherwise func(*Builder)) *Builder

When runs the callback only if the condition holds, and hands the builder back either way.

The condition is a bool, because the caller writing the expression is the one who knows what makes it true. The callback mutates the builder and returns nothing: every method on Builder already mutates and returns the receiver, so a callback that returned something would be a second convention.

A nil callback on a true condition leaves the builder untouched instead of failing, which is what Collection.When does with the same argument.

q.From("posts").
	When(published, func(q *query.Builder) { q.Where("published", true) }, nil).
	OrderBy("id")

func (*Builder) Where

func (b *Builder) Where(column any, args ...any) *Builder

Where adds a basic where clause, in either its two or three argument form.

Called with two arguments the operator is "=": where('id', 1) and where('id', '=', 1) are the same clause. Called with a func it opens a nested group instead.

func (*Builder) WhereAll

func (b *Builder) WhereAll(columns []any, args ...any) *Builder

WhereAll adds a clause requiring every one of the columns to compare with the same value, joined by "and" inside one group.

func (*Builder) WhereAny

func (b *Builder) WhereAny(columns []any, args ...any) *Builder

WhereAny adds a clause requiring any one of the columns to compare with the same value, joined by "or" inside one group.

func (*Builder) WhereBetween

func (b *Builder) WhereBetween(column any, from, to any) *Builder

WhereBetween adds a clause requiring column to fall between from and to.

func (*Builder) WhereBetweenColumns

func (b *Builder) WhereBetweenColumns(column any, values []any, boolean string, not bool) *Builder

WhereBetweenColumns adds a clause requiring column to be between two other columns, so nothing here is bound.

func (*Builder) WhereBindings

func (b *Builder) WhereBindings() []any

WhereBindings rebuilds the where segment from the clauses, in the order the compiled statement consumes them.

It exists so that a clause carrying a subquery can be replaced -- which is what putting the tenant on a subquery does -- without the values afterwards sliding onto the wrong placeholders. Every clause type that contributes a binding is listed here, and a type that starts contributing one has to be added: a clause this does not know about loses its values silently, which is a wrong answer rather than an error.

func (*Builder) WhereColumn

func (b *Builder) WhereColumn(first any, args ...any) *Builder

WhereColumn adds a clause comparing two columns.

func (*Builder) WhereDate

func (b *Builder) WhereDate(column any, args ...any) *Builder

WhereDate adds a clause comparing the date part of a timestamp column with a date.

The operator is optional, as it is on Where: two arguments are a column and a value compared with "=". A time.Time value is formatted down to the day.

func (*Builder) WhereDay

func (b *Builder) WhereDay(column any, args ...any) *Builder

WhereDay adds a clause comparing the day part of a timestamp column.

func (*Builder) WhereExists

func (b *Builder) WhereExists(callback func(*Builder), boolean string, not bool) *Builder

WhereExists adds an exists clause for the subquery the callback builds.

func (*Builder) WhereFullText

func (b *Builder) WhereFullText(columns []any, value any, options map[string]any, boolean string) *Builder

WhereFullText adds a full-text search clause over the given columns.

options carries the engine's search modes -- MySQL reads "mode" and "expanded", Postgres reads "language" -- and a grammar that has none ignores it.

func (*Builder) WhereIn

func (b *Builder) WhereIn(column any, values []any) *Builder

WhereIn adds a where-in clause.

An empty list is kept rather than dropped: it compiles to "0 = 1", so a filter over an empty set returns nothing. Dropping it would return everything, which is the difference between an empty page and a data leak.

func (*Builder) WhereIntegerInRaw

func (b *Builder) WhereIntegerInRaw(column any, values []any, boolean string, not bool) *Builder

WhereIntegerInRaw adds a where-in clause whose values are written directly into the statement as integers rather than bound.

Every value is cast to an integer first: an integer has no quoting to escape. A value that is not a number at all becomes zero rather than reaching the statement as itself.

func (*Builder) WhereIntegerNotInRaw

func (b *Builder) WhereIntegerNotInRaw(column any, values []any, boolean string) *Builder

WhereIntegerNotInRaw adds a where-not-in clause with raw integer values.

func (*Builder) WhereJSONContains

func (b *Builder) WhereJSONContains(column any, value any, boolean string, not bool) *Builder

WhereJSONContains adds a clause requiring the JSON column to contain value.

func (*Builder) WhereJSONContainsKey

func (b *Builder) WhereJSONContainsKey(column any, boolean string, not bool) *Builder

WhereJSONContainsKey adds a clause requiring the JSON column to contain the given key path. The key is part of the path, so there is nothing to bind.

func (*Builder) WhereJSONDoesntContain

func (b *Builder) WhereJSONDoesntContain(column any, value any, boolean string) *Builder

WhereJSONDoesntContain adds a clause requiring the JSON column not to contain value.

func (*Builder) WhereJSONDoesntContainKey

func (b *Builder) WhereJSONDoesntContainKey(column any, boolean string) *Builder

WhereJSONDoesntContainKey adds a clause requiring the JSON column not to contain the given key path.

func (*Builder) WhereJSONDoesntOverlap

func (b *Builder) WhereJSONDoesntOverlap(column any, value any, boolean string) *Builder

WhereJSONDoesntOverlap adds a clause requiring the JSON column not to overlap value.

func (*Builder) WhereJSONLength

func (b *Builder) WhereJSONLength(column any, args ...any) *Builder

WhereJSONLength adds a clause comparing the length of a JSON column. The bound value is an integer: it is compared with a length.

func (*Builder) WhereJSONOverlaps

func (b *Builder) WhereJSONOverlaps(column any, value any, boolean string, not bool) *Builder

WhereJSONOverlaps adds a clause requiring the JSON column to overlap value.

func (*Builder) WhereLike

func (b *Builder) WhereLike(column any, value any, caseSensitive bool, boolean string, not bool) *Builder

WhereLike adds a LIKE clause comparing column against a pattern, optionally case sensitive.

The clause carries the value that is bound rather than the pattern that was written, because a grammar may rewrite it -- SQLite spells a case sensitive like as a glob, whose wildcards are the other way round -- and the tenant scoping rebuilds the binding list from the clauses. A clause that did not carry its own value would lose it there.

func (*Builder) WhereMonth

func (b *Builder) WhereMonth(column any, args ...any) *Builder

WhereMonth adds a clause comparing the month part of a timestamp column.

func (*Builder) WhereNested

func (b *Builder) WhereNested(callback func(*Builder), boolean string) *Builder

WhereNested opens a nested group of clauses, built by the callback, and adds it under boolean.

func (*Builder) WhereNone

func (b *Builder) WhereNone(columns []any, args ...any) *Builder

WhereNone adds a clause requiring none of the columns to compare with the same value: WhereAny negated, with the group joined by "and not".

func (*Builder) WhereNotBetween

func (b *Builder) WhereNotBetween(column any, from, to any) *Builder

WhereNotBetween adds a not-between clause.

func (*Builder) WhereNotBetweenColumns

func (b *Builder) WhereNotBetweenColumns(column any, values []any, boolean string) *Builder

WhereNotBetweenColumns adds a not-between-columns clause.

func (*Builder) WhereNotIn

func (b *Builder) WhereNotIn(column any, values []any) *Builder

WhereNotIn adds a where-not-in clause.

func (*Builder) WhereNotLike

func (b *Builder) WhereNotLike(column any, value any, caseSensitive bool, boolean string) *Builder

WhereNotLike adds a NOT LIKE clause.

func (*Builder) WhereNotNull

func (b *Builder) WhereNotNull(columns ...any) *Builder

WhereNotNull adds a clause requiring the named columns not to be NULL.

func (*Builder) WhereNull

func (b *Builder) WhereNull(columns ...any) *Builder

WhereNull adds a clause requiring the named columns to be NULL.

func (*Builder) WhereRaw

func (b *Builder) WhereRaw(sql string, bindings ...any) *Builder

WhereRaw adds a raw SQL where clause, with its own bindings.

The bindings are recorded on the clause as well as appended to the segment, because the tenant filter needs to rebuild the flat list -- scoping a subquery changes how many bindings it contributes, and the list can only be put back in order if every clause knows which of them are its own.

func (*Builder) WhereRowValues

func (b *Builder) WhereRowValues(columns []any, operator string, values []any, boolean string) *Builder

WhereRowValues adds a clause comparing a tuple of columns with a tuple of values.

func (*Builder) WhereSubCount

func (b *Builder) WhereSubCount(sub *Builder, operator string, count int, boolean string) *Builder

WhereSubCount adds a where clause with a subquery on the LEFT of a comparison: a subquery like `(select count(*) from posts where posts.user_id = users.id) > 3`.

The builder had no method for that shape, so both copies of the model has-query wrote the clause by hand, as a Basic where whose column was Raw("(" + sub.ToSQL() + ")"). A subquery frozen into a Raw is a subquery nothing can scope afterwards, and this one was never scoped by anything: Users.Has("posts", ">", 3).Get(auth.SystemGrant("user.list", "acme")) emitted `(select count(*) from "posts" where "users"."id" = "posts"."user_id") > 3`, with no posts.tenant_id anywhere in it, so one tenant's users were filtered by every tenant's posts.

The clause keeps the builder it was compiled from, which is why it can be scoped: scopeSubqueries scopes that builder under the Grant and renders the column again from it. The SQL written here is what an unscoped ToSQL shows, exactly as it is for every other subquery in this file.

func (*Builder) WhereTime

func (b *Builder) WhereTime(column any, args ...any) *Builder

WhereTime adds a clause comparing the time part of a timestamp column with a time.

func (*Builder) WhereValueBetween

func (b *Builder) WhereValueBetween(value any, columns []any, boolean string, not bool) *Builder

WhereValueBetween adds a clause requiring value to fall between two columns, which is the between comparison the other way round.

func (*Builder) WhereValueNotBetween

func (b *Builder) WhereValueNotBetween(value any, columns []any, boolean string) *Builder

WhereValueNotBetween adds a value-not-between-columns clause.

func (*Builder) WhereVectorDistanceLessThan

func (b *Builder) WhereVectorDistanceLessThan(column any, vector []float64, maxDistance float64, boolean string) *Builder

WhereVectorDistanceLessThan adds a clause matching rows whose embedding is nearer than maxDistance to the given vector.

It takes the vector directly rather than accepting text and computing an embedding from it, because a query builder that makes a network call to an embedding provider is a query builder that can time out. The caller fetches the embedding and passes it in.

Nothing here checks that the connection is Postgres: the operator is Postgres's, and a fluent method has nothing to report an error through, so an unsupported connection fails when the engine refuses the SQL rather than before.

func (*Builder) WhereVectorSimilarTo

func (b *Builder) WhereVectorSimilarTo(column any, vector []float64, minSimilarity float64, order bool) *Builder

WhereVectorSimilarTo adds the distance filter and, optionally, the ordering that goes with it, given a similarity between 0 and 1.

func (*Builder) WhereYear

func (b *Builder) WhereYear(column any, args ...any) *Builder

WhereYear adds a clause comparing the year part of a timestamp column.

type Connection

type Connection interface {
	// Select runs a select and returns its rows.
	Select(ctx context.Context, query string, bindings []any, useReadPDO bool) ([]Record, error)

	// Insert runs an insert.
	Insert(ctx context.Context, query string, bindings []any) (bool, error)

	// Update runs an update and returns the number of rows affected.
	Update(ctx context.Context, query string, bindings []any) (int64, error)

	// Delete runs a delete and returns the number of rows affected.
	Delete(ctx context.Context, query string, bindings []any) (int64, error)

	// Statement runs a statement that returns neither rows nor a count.
	Statement(ctx context.Context, query string, bindings []any) (bool, error)
}

Connection is what a query builder asks of the thing that runs its statements.

It is declared here rather than imported from the database package because the interface belongs with its consumer in Go, and because database imports this package: naming it there would close the cycle. Every method takes a context, and it is the request's -- not one the connection was built with. A statement that cannot be cancelled outlives the request that asked for it, and a deadline that stops at the handler is a deadline the database never hears about.

type CursorConnection

type CursorConnection interface {
	// Cursor runs a select and yields its rows one at a time.
	Cursor(ctx context.Context, query string, bindings []any, useReadPDO bool) (func(yield func(Record, error) bool), error)
}

CursorConnection is the part of a connection that Cursor needs: a select that yields its rows one at a time instead of materialising them.

A connection that does not implement it makes Cursor fail rather than fall back to a buffered select. The fallback would work and would be a lie: the whole reason to reach for a cursor is the result set that does not fit in memory, and finding out by being killed is worse than finding out by an error.

type Expression

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

Expression is a value the grammar must not wrap in identifier quotes and must not turn into a placeholder.

Everything the query builder accepts as a column or a value also accepts an Expression.

func Raw

func Raw(value any) Expression

Raw builds an Expression out of a value.

func (Expression) GetValue

func (e Expression) GetValue(grammar Grammar) any

GetValue returns the wrapped value. The grammar parameter is accepted and ignored: the value carried here is already final, and the parameter exists only so Expression satisfies the same signature as a grammar-aware value.

func (Expression) String

func (e Expression) String() string

String renders the expression the way the grammar concatenates it.

func (Expression) Value

func (e Expression) Value() any

Value returns the wrapped value without requiring a grammar argument, for callers that have no grammar handy and do not need one.

type Grammar

type Grammar interface {
	// CompileSelect compiles a select statement for the query.
	CompileSelect(query *Builder) string

	// CompileInsert compiles an insert statement for the given rows.
	CompileInsert(query *Builder, values []map[string]any) string

	// CompileInsertOrIgnore compiles an insert that silently skips rows that
	// would violate a constraint.
	CompileInsertOrIgnore(query *Builder, values []map[string]any) string

	// CompileInsertGetID compiles an insert and reports the SQL that reads
	// back the inserted row's ID from the given sequence.
	CompileInsertGetID(query *Builder, values map[string]any, sequence string) string

	// CompileUpdate compiles an update statement for the given values.
	CompileUpdate(query *Builder, values map[string]any) string

	// CompileUpsert compiles an insert that updates the named columns when a
	// row conflicts on uniqueBy.
	CompileUpsert(query *Builder, values []map[string]any, uniqueBy []string, update []string) string

	// CompileDelete compiles a delete statement for the query.
	CompileDelete(query *Builder) string

	// CompileTruncate compiles a truncate. A truncate is more than one
	// statement on some engines, so the result is a map from each statement
	// to its bindings.
	CompileTruncate(query *Builder) map[string][]any

	// CompileExists compiles a select wrapped so the engine can report only
	// whether a row matches.
	CompileExists(query *Builder) string

	// CompileRandom compiles a random ordering expression, optionally seeded.
	CompileRandom(seed string) string

	// PrepareBindingsForUpdate arranges the where bindings after the update
	// values, in the order the compiled statement consumes them.
	PrepareBindingsForUpdate(bindings map[string][]any, values map[string]any) []any

	// PrepareBindingsForDelete returns the where bindings for a delete
	// statement.
	PrepareBindingsForDelete(bindings map[string][]any) []any

	// SupportsSavepoints reports whether the engine can savepoint within a
	// transaction.
	SupportsSavepoints() bool

	// CompileSavepoint compiles a statement that creates the named savepoint.
	CompileSavepoint(name string) string

	// CompileSavepointRollBack compiles a statement that rolls back to the
	// named savepoint.
	CompileSavepointRollBack(name string) string

	// GetOperators returns the comparison operators the grammar accepts.
	GetOperators() []string

	// GetBitwiseOperators returns the operators treated as bitwise rather
	// than comparison.
	GetBitwiseOperators() []string

	// Wrap quotes an identifier, leaving an Expression alone.
	Wrap(value any) string

	// WrapTable quotes a table name, applying the table prefix and any alias.
	WrapTable(table any) string

	// WrapArray quotes each value in a list of identifiers.
	WrapArray(values []any) []string

	// Columnize quotes a list of columns and joins them with commas.
	Columnize(columns []any) string

	// Parameterize returns the comma-separated placeholders for a list of
	// values.
	Parameterize(values []any) string

	// Parameter returns the placeholder for a value, or the value itself when
	// it is an Expression.
	Parameter(value any) string

	// QuoteString quotes a string literal, or each one in a list.
	QuoteString(value any) string

	// Escape returns a value escaped for inclusion directly in SQL, for a
	// caller building a statement by hand rather than through a placeholder.
	//
	// It returns an error rather than panicking: a grammar with no connection
	// cannot escape safely, and returning the unescaped value in that case
	// would be an injection with a reassuring name.
	Escape(value any, binary bool) (string, error)

	// GetDateFormat returns the layout the engine's date columns are
	// formatted with, in Go's reference-time syntax.
	GetDateFormat() string

	// GetTablePrefix returns the prefix applied to every table name.
	GetTablePrefix() string

	// SetTablePrefix sets the prefix applied to every table name.
	SetTablePrefix(prefix string) Grammar
}

Grammar is what a Builder needs of the thing that spells its SQL.

It is an interface, declared in the package that consumes it, because the concrete grammars live in query/grammars and naming them here would close an import cycle: grammars imports query for *Builder, so query cannot import grammars for the type.

A driver grammar embeds BaseGrammar and overrides what its dialect spells differently.

type GroupLimit

type GroupLimit struct {
	Value  int
	Column string
}

GroupLimit is the per-group row limit a Builder was given.

type Having

type Having struct {
	Type     string
	Column   any
	Operator string
	Value    any
	Values   []any
	Boolean  string
	Not      bool
	SQL      string
	Query    *Builder
}

Having is one having clause of a Builder.

type IndexHint

type IndexHint struct {
	Type  string
	Index string
}

IndexHint is the index a query asks the planner to use, force or ignore: what Builder.UseIndex, ForceIndex and IgnoreIndex record, and what the grammar compiles into the from clause.

Type is one of "hint", "force" and "ignore", and Index is the index name. A builder holds at most one, so setting a second replaces the first.

A hint changes the plan and never the rows, which is why a grammar is free to compile it to nothing: the base Grammar does, SQLite honours only "force", and an index name that is not a bare identifier is dropped rather than interpolated, because an identifier cannot be bound.

func NewIndexHint

func NewIndexHint(typ, index string) *IndexHint

NewIndexHint builds an IndexHint of the given type and index name.

type InsertOrIgnoreReturningGrammar

type InsertOrIgnoreReturningGrammar interface {
	// CompileInsertOrIgnoreReturning compiles an insert that skips colliding
	// rows and returns the ones it wrote.
	CompileInsertOrIgnoreReturning(query *Builder, values []map[string]any, uniqueBy, returning []string) (string, error)
}

InsertOrIgnoreReturningGrammar is the part of a grammar that compiles an insert which skips the rows that would collide and reports the ones it wrote. It is asked for rather than declared on Grammar, for the reason InsertUsingGrammar is.

type InsertUsingGrammar

type InsertUsingGrammar interface {
	// CompileInsertUsing compiles an insert that reads its rows from a select
	// query.
	CompileInsertUsing(query *Builder, columns []any, sql string) string

	// CompileInsertOrIgnoreUsing compiles CompileInsertUsing's insert-or-ignore
	// variant.
	CompileInsertOrIgnoreUsing(query *Builder, columns []any, sql string) string
}

InsertUsingGrammar is the part of a grammar that compiles an insert reading from a select. It is asked for rather than declared on Grammar because the Grammar interface is closed and this is not on it.

type InvalidDirectionError added in v0.22.0

type InvalidDirectionError struct {
	Direction string
}

InvalidDirectionError identifies the order direction a query refused.

Use errors.Is with ErrInvalidDirection when the concrete value is not needed.

func (*InvalidDirectionError) Error added in v0.22.0

func (e *InvalidDirectionError) Error() string

Error returns a deterministic description of the refused direction.

func (*InvalidDirectionError) Unwrap added in v0.22.0

func (e *InvalidDirectionError) Unwrap() error

Unwrap makes InvalidDirectionError match ErrInvalidDirection with errors.Is.

type InvalidOperatorError added in v0.22.0

type InvalidOperatorError struct {
	Operator string
}

InvalidOperatorError identifies the operator a query refused.

Use errors.Is with ErrInvalidOperator when the concrete value is not needed.

func (*InvalidOperatorError) Error added in v0.22.0

func (e *InvalidOperatorError) Error() string

Error returns a deterministic description of the refused operator.

func (*InvalidOperatorError) Unwrap added in v0.22.0

func (e *InvalidOperatorError) Unwrap() error

Unwrap makes InvalidOperatorError match ErrInvalidOperator with errors.Is.

type JSONContainsGrammar

type JSONContainsGrammar interface {
	// PrepareBindingForJSONContains turns a value into the JSON binding the
	// grammar's engine expects.
	PrepareBindingForJSONContains(binding any) (any, error)
}

JSONContainsGrammar is the part of a grammar that turns a value into the JSON binding its engine expects. It is asked for rather than declared on Grammar, for the reason InsertUsingGrammar is.

type JoinClause

type JoinClause struct {
	*Builder

	// Type is the join type: inner, left, right or cross.
	Type string

	// Table is the table or subquery expression being joined.
	Table any

	// Lateral marks the join as lateral. It is a flag rather than a second
	// type, so the grammar and Joins have one type to hold.
	Lateral bool
	// contains filtered or unexported fields
}

JoinClause is one join, and the condition it is joined on.

It embeds *Builder, so a join condition is written with the same where vocabulary as the query itself -- On is where for two columns, and Where inside a join is a where. Every Builder method is reachable on a JoinClause, and the two that behave differently are declared below and shadow the embedded ones.

func NewJoinClause

func NewJoinClause(parentQuery *Builder, typ string, table any) *JoinClause

NewJoinClause builds a JoinClause for a join against table.

The clause carries the parent's connection, grammar and processor so that a nested query built inside the join compiles against the same dialect.

func NewJoinLateralClause

func NewJoinLateralClause(parentQuery *Builder, typ string, table any) *JoinClause

NewJoinLateralClause builds a JoinClause with Lateral already set. See Lateral.

func (*JoinClause) NewJoinClause

func (j *JoinClause) NewJoinClause() *JoinClause

NewJoinClause returns another JoinClause rather than a Builder.

Go resolves an embedded method by name, and a method on JoinClause called NewQuery could not return *JoinClause while the embedded one returns *Builder, so the two are separate names: NewQuery still returns a plain builder, for a subquery inside the join, and this returns the clause.

func (*JoinClause) NewParentQuery

func (j *JoinClause) NewParentQuery() *Builder

NewParentQuery returns a fresh builder on the table the join was declared against.

func (*JoinClause) On

func (j *JoinClause) On(first any, args ...any) *JoinClause

On adds a join condition.

It compares two columns, so neither side becomes a binding: `on('users.id', '=', 'posts.user_id')` names a column on the right, not the string "posts.user_id". This is the one difference that catches people moving a condition from where to on -- in a where, the right side is a value.

Passing a func opens a nested group.

func (*JoinClause) OrOn

func (j *JoinClause) OrOn(first any, args ...any) *JoinClause

OrOn is On joined with "or" instead of "and".

type LikeBindingGrammar

type LikeBindingGrammar interface {
	// PrepareWhereLikeBinding rewrites a like pattern into the binding the
	// grammar's engine expects.
	PrepareWhereLikeBinding(value string, caseSensitive bool) string
}

LikeBindingGrammar is the part of a grammar that rewrites a like pattern for the engine. A grammar that does not implement it leaves the pattern alone.

type Order

type Order struct {
	Column    any
	Direction string
	SQL       any
}

Order is one order-by clause of a Builder.

type PreparesBindings

type PreparesBindings interface {
	// PrepareBindings turns a driver-specific value into one the driver
	// accepts.
	PrepareBindings(bindings []any) []any
}

PreparesBindings turns a driver-specific value into one the driver accepts. ToRawSQL asks for it, and takes the bindings unchanged from a connection that has no opinion.

type Processor

type Processor interface {
	// ProcessSelect adjusts the rows a select returned before they reach the
	// caller.
	ProcessSelect(query *Builder, results []Record) []Record

	// ProcessInsertGetID runs an insert and reports the ID of the inserted
	// row, read back from the named sequence.
	ProcessInsertGetID(ctx context.Context, query *Builder, sql string, values []any, sequence string) (int64, error)
}

Processor is the hook that lets a driver adjust results on the way out.

type Record

type Record = map[string]any

Record is one row as the connection hands it back: column name to value.

type Union

type Union struct {
	Query *Builder
	All   bool
}

Union is one query unioned onto a Builder.

type UpdateFromGrammar

type UpdateFromGrammar interface {
	// CompileUpdateFrom compiles an "update ... from" statement.
	CompileUpdateFrom(query *Builder, values map[string]any) string

	// PrepareBindingsForUpdateFrom orders the bindings for an "update ... from"
	// statement to match the placeholders CompileUpdateFrom produces.
	PrepareBindingsForUpdateFrom(bindings map[string][]any, values map[string]any) []any
}

UpdateFromGrammar is the part of the grammar that compiles Postgres's "update ... from" syntax.

Not every grammar implements it, so callers use a type assertion against this interface and return an error when it fails, rather than calling a method that might not exist.

type Where

type Where struct {
	Type          string
	Column        any
	Columns       []any
	First         any
	Second        any
	Operator      string
	Value         any
	Values        []any
	Boolean       string
	Not           bool
	SQL           any
	Query         *Builder
	CaseSensitive bool
	Options       map[string]any
}

Where is one where clause of a Builder.

Each Type reads a different subset of the fields; the union of them is spelled out here so the grammar can read them.

Directories

Path Synopsis
Package grammars holds one grammar per engine, each one compiling a *query.Builder into the SQL that engine speaks: MySQLGrammar, MariaDBGrammar, PostgresGrammar and SQLiteGrammar, over the shared Grammar in grammar.go.
Package grammars holds one grammar per engine, each one compiling a *query.Builder into the SQL that engine speaks: MySQLGrammar, MariaDBGrammar, PostgresGrammar and SQLiteGrammar, over the shared Grammar in grammar.go.
Package processors holds the hook a driver takes to adjust results on the way out of the connection: MySQLProcessor, MariaDBProcessor, PostgresProcessor and SQLiteProcessor over the shared Processor.
Package processors holds the hook a driver takes to adjust results on the way out of the connection: MySQLProcessor, MariaDBProcessor, PostgresProcessor and SQLiteProcessor over the shared Processor.

Jump to

Keyboard shortcuts

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