sqldsl

package
v0.7.0 Latest Latest
Warning

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

Go to latest
Published: Feb 8, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package sqldsl provides a type-safe DSL for building PostgreSQL queries.

Overview

Rather than constructing SQL strings through concatenation or templating, this package provides typed building blocks that compose together to form complete queries. The DSL models authorization query patterns directly, making it easier to construct correct queries and avoiding common SQL injection vulnerabilities.

Core Interfaces

All DSL types implement one of two interfaces:

  • Expr: Represents SQL expressions (columns, literals, operators, function calls)
  • SQLer: Represents complete SQL statements (SELECT, WITH, etc.)

Both interfaces define a SQL() method that renders the PostgreSQL syntax.

Expression Types

Basic expressions:

Param("p_subject_type")           // Function parameter reference
Col{Table: "t", Column: "id"}     // Column reference: t.id
Lit("document")                   // String literal: 'document'
Int(42)                           // Integer literal: 42
Bool(true)                        // Boolean literal: TRUE
Null{}                            // NULL literal
Raw("CURRENT_TIMESTAMP")          // Raw SQL (escape hatch)

Operators:

Eq{Left: col, Right: param}       // col = param
In{Expr: col, Values: []string}   // col IN ('a', 'b')
And(expr1, expr2, expr3)          // (expr1 AND expr2 AND expr3)
Or(expr1, expr2)                  // (expr1 OR expr2)
Not(expr)                         // NOT (expr)
Exists{Query: subquery}           // EXISTS (subquery)

Authorization-specific helpers:

SubjectIDMatch(col, id, wildcard) // Match subject_id with optional wildcard
HasUserset{Source: col}           // Check if subject_id contains '#'
UsersetObjectID{Source: col}      // Extract object ID from userset (split_part)

Statement Types

SELECT statements:

SelectStmt{
    Columns: []string{"object_id", "relation"},
    From: "melange_tuples",
    Alias: "t",
    Where: And(condition1, condition2),
    Limit: 100,
}

Common Table Expressions:

WithCTE{
    Recursive: true,
    CTEs: []CTEDef{
        {Name: "accessible", Query: cteQuery},
    },
    Query: finalSelect,
}

Query Builders

The tuples subpackage provides a fluent builder for common tuple queries:

query := Tuples("t").
    ObjectType("document").
    Relations("viewer", "editor").
    WhereSubjectType(SubjectType).
    WhereSubjectID(SubjectID, true).
    Select("t.object_id").
    Distinct()

sql := query.SQL()

Design Rationale

Type safety: The compiler catches many errors that would otherwise only be found at runtime when executing the generated SQL.

Composition: Complex queries are built from simple parts that can be tested and reasoned about independently.

Authorization semantics: The DSL includes domain-specific helpers like SubjectIDMatch and UsersetObjectID that encode OpenFGA authorization patterns directly, reducing boilerplate and errors.

SQL visibility: Unlike heavy ORMs, the DSL stays close to SQL syntax. Developers familiar with PostgreSQL can easily read and write DSL code.

Package sqldsl provides a domain-specific SQL DSL for generating Melange authorization queries. It models authorization concepts directly rather than generic SQL syntax.

Index

Constants

This section is empty.

Variables

View Source
var (
	SubjectType = Param("p_subject_type")
	SubjectID   = Param("p_subject_id")
	ObjectType  = Param("p_object_type")
	ObjectID    = Param("p_object_id")
	Visited     = Param("p_visited")
)

Common parameter constants.

Functions

func Ident

func Ident(name string) string

Ident sanitizes an identifier for use in SQL. Replaces non-alphanumeric characters with underscores.

func IndentLines

func IndentLines(input, indent string) string

IndentLines adds the given indent prefix to each line of input.

func ListObjectsFunctionName

func ListObjectsFunctionName(objectType, relation string) string

ListObjectsFunctionName generates a list_TYPE_RELATION_objects function name.

func ListSubjectsFunctionName

func ListSubjectsFunctionName(objectType, relation string) string

ListSubjectsFunctionName generates a list_TYPE_RELATION_subjects function name.

func Optf

func Optf(cond bool, format string, args ...any) string

Optf returns formatted string if condition is true, empty string otherwise. Useful for optional SQL clauses.

func RenderBlocks

func RenderBlocks(blocks []QueryBlock) string

RenderBlocks renders multiple query blocks sequentially. Each block is indented and comments are rendered as SQL comments.

func RenderUnionBlocks

func RenderUnionBlocks(blocks []QueryBlock) string

RenderUnionBlocks renders query blocks joined with UNION. Each block is indented and comments are rendered as SQL comments.

func Sqlf

func Sqlf(format string, args ...any) string

Sqlf formats SQL with automatic dedenting and blank line removal. The SQL shape is visible in the format string.

func WrapWithExclusionCTEAndPagination

func WrapWithExclusionCTEAndPagination(query, exclusionCTE string) string

WrapWithExclusionCTEAndPagination wraps a query with exclusion CTE precomputation and wildcard-first pagination.

Optimization: Materializes excluded subjects once in a CTE, then applies a single LEFT JOIN...WHERE IS NULL anti-pattern instead of repeated NOT EXISTS subqueries.

Structure:

WITH excluded_subjects AS (SELECT subject_id FROM melange_tuples WHERE ...),
candidates AS (...original UNION without exclusion predicates...),
base_results AS (
  SELECT DISTINCT s.subject_id FROM candidates s
  LEFT JOIN excluded_subjects excl
    ON excl.subject_id = s.subject_id OR excl.subject_id = '*'
  WHERE excl.subject_id IS NULL
),
...pagination CTEs...

Parameters:

query: UNION of all access paths (without exclusion predicates)
exclusionCTE: SQL for exclusion CTE (SELECT subject_id FROM ...)

Returns: Complete paginated query with exclusion anti-join

func WrapWithPagination

func WrapWithPagination(query, idColumn string) string

WrapWithPagination wraps a query with cursor-based pagination. The idColumn parameter specifies which column to use for ordering and cursoring.

func WrapWithPaginationWildcardFirst

func WrapWithPaginationWildcardFirst(query string) string

WrapWithPaginationWildcardFirst wraps a query for list_subjects with wildcard-first ordering. Wildcards ('*') are sorted before all other subject IDs to ensure consistent pagination. Uses a compound sort key: (is_not_wildcard, subject_id) where is_not_wildcard is 0 for '*', 1 otherwise.

Types

type Add

type Add struct {
	Left  Expr
	Right Expr
}

Add represents addition (+).

func (Add) SQL

func (a Add) SQL() string

type Alias

type Alias struct {
	Expr Expr
	Name string
}

Alias wraps an expression with an alias (expr AS alias).

func SelectAs

func SelectAs(expr Expr, alias string) Alias

SelectAs creates an aliased column expression (expr AS alias). Shorthand for Alias{Expr: expr, Name: alias}.

func (Alias) SQL

func (a Alias) SQL() string

SQL renders the aliased expression.

type AndExpr

type AndExpr struct {
	Exprs []Expr
}

AndExpr represents a logical AND of multiple expressions.

func And

func And(exprs ...Expr) AndExpr

And creates an AND expression from multiple expressions.

func (AndExpr) SQL

func (a AndExpr) SQL() string

type ArrayAppend

type ArrayAppend struct {
	Array  Expr   // The base array expression
	Values []Expr // Values to append (rendered as ARRAY[...])
}

ArrayAppend represents array concatenation: arr || ARRAY[values]. Used for building the visited array in recursive check functions.

Example:

ArrayAppend{
    Array:  Param("p_visited"),
    Values: []Expr{Concat{Parts: []Expr{Lit("doc:"), ObjectID, Lit(":viewer")}}},
}

Renders: p_visited || ARRAY['doc:' || p_object_id || ':viewer']

func VisitedWithKey

func VisitedWithKey(objectType, relation string, objectID Expr) ArrayAppend

VisitedWithKey creates the p_visited || ARRAY[key] expression. This is the standard pattern for passing updated visited arrays to recursive calls.

Example:

VisitedWithKey("document", "viewer", ObjectID)

Renders: p_visited || ARRAY['document:' || p_object_id || ':viewer']

func (ArrayAppend) SQL

func (a ArrayAppend) SQL() string

SQL renders the array concatenation.

type ArrayContains

type ArrayContains struct {
	Value Expr
	Array Expr
}

ArrayContains represents the ANY() check: value = ANY(array).

func (ArrayContains) SQL

func (a ArrayContains) SQL() string

SQL renders the ANY check.

type ArrayLength

type ArrayLength struct {
	Array     Expr
	Dimension int // Usually 1
}

ArrayLength represents array_length(arr, dim).

func (ArrayLength) SQL

func (a ArrayLength) SQL() string

SQL renders the array_length call.

type ArrayLiteral

type ArrayLiteral struct {
	Values []Expr
}

ArrayLiteral represents a SQL array literal: ARRAY[values].

func (ArrayLiteral) SQL

func (a ArrayLiteral) SQL() string

SQL renders the array literal.

type Bool

type Bool bool

Bool represents a boolean literal.

func (Bool) SQL

func (b Bool) SQL() string

SQL renders the boolean.

type CTEDef

type CTEDef struct {
	Name         string   // CTE name (e.g., "accessible", "base_results")
	Columns      []string // Optional column names (e.g., ["object_id", "depth"])
	Materialized bool     // If true, renders "AS MATERIALIZED" (PostgreSQL 12+)
	Query        SQLer    // The CTE query body
}

CTEDef represents a single Common Table Expression definition. Used within WithCTE to define named subqueries.

func (CTEDef) SQL

func (c CTEDef) SQL() string

SQL renders the CTE definition as "name [(columns)] AS (query)".

type CaseExpr

type CaseExpr struct {
	Whens []CaseWhen
	Else  Expr // optional default value
}

CaseExpr represents a CASE expression with multiple WHEN clauses.

func (CaseExpr) SQL

func (c CaseExpr) SQL() string

type CaseWhen

type CaseWhen struct {
	Cond   Expr
	Result Expr
}

CaseWhen represents a single WHEN clause in a CASE expression.

type Cast added in v0.7.0

type Cast struct {
	Expr Expr
	Type string
}

Cast represents a PostgreSQL type cast (expr::type).

func (Cast) SQL added in v0.7.0

func (c Cast) SQL() string

SQL renders the cast expression.

type Col

type Col struct {
	Table  string
	Column string
}

Col represents a table column reference (e.g., t.object_id).

func (Col) SQL

func (c Col) SQL() string

SQL renders the column reference.

type CommentedSQL

type CommentedSQL struct {
	Comment string // Comment text (without -- prefix)
	Query   SQLer  // The query to render after the comment
}

CommentedSQL wraps a query with a SQL comment prefix. Useful for adding descriptive comments to parts of a UNION or CTE body.

Example:

CommentedSQL{Comment: "Base case: seed with starting value", Query: baseQuery}

Renders:

-- Base case: seed with starting value
<base query>

func MultiLineComment

func MultiLineComment(comments []string, query SQLer) CommentedSQL

MultiLineComment creates a CommentedSQL with multiple comment lines. The query follows after all comment lines.

func (CommentedSQL) SQL

func (c CommentedSQL) SQL() string

SQL renders the comment followed by the query.

type Concat

type Concat struct {
	Parts []Expr
}

Concat represents SQL string concatenation (||).

func (Concat) SQL

func (c Concat) SQL() string

SQL renders the concatenation.

type EmptyArray

type EmptyArray struct{}

EmptyArray represents an empty text array (ARRAY[]::TEXT[]).

func (EmptyArray) SQL

func (EmptyArray) SQL() string

SQL renders the empty array.

type Eq

type Eq struct {
	Left  Expr
	Right Expr
}

Eq represents an equality comparison (=).

func (Eq) SQL

func (e Eq) SQL() string

type Exists

type Exists struct {
	Query interface{ SQL() string }
}

Exists represents an EXISTS subquery.

func ExistsExpr

func ExistsExpr(stmt SelectStmt) Exists

ExistsExpr creates an Exists expression from a SelectStmt.

func (Exists) SQL

func (e Exists) SQL() string

type Expr

type Expr interface {
	SQL() string
}

Expr is the interface that all SQL expression types implement.

func NormalizedUsersetSubject

func NormalizedUsersetSubject(subjectID, relation Expr) Expr

NormalizedUsersetSubject combines the object_id from a userset with a new relation. Example: split_part(subject_id, '#', 1) || '#' || v_filter_relation

func SubjectIDMatch

func SubjectIDMatch(column, subjectID Expr, allowWildcard bool) Expr

SubjectIDMatch creates a condition for matching subject IDs. When allowWildcard is true, matches exact ID or wildcard tuples. When allowWildcard is false, matches exact ID and excludes wildcard tuples.

func VisitedKey

func VisitedKey(objectType, relation string, objectID Expr) Expr

VisitedKey creates the standard visited key expression for cycle detection. The key format is: 'objectType:' || objectID || ':relation'

Example:

VisitedKey("document", "viewer", ObjectID)

Renders the expression: 'document:' || p_object_id || ':viewer'

type Func

type Func struct {
	Name string
	Args []Expr
}

Func represents a SQL function call.

func (Func) SQL

func (f Func) SQL() string

SQL renders the function call.

type FuncCallEq

type FuncCallEq struct {
	FuncName string
	Args     []Expr
	Value    Expr // The value to compare against (typically Int(1) or Int(0))
}

FuncCallEq compares a function call result to a value. Used for authorization check expressions like "check_permission(...) = 1".

Example:

FuncCallEq{
    FuncName: "check_doc_viewer",
    Args:     []Expr{SubjectType, SubjectID, ObjectID, Visited},
    Value:    Int(1),
}

Renders: check_doc_viewer(p_subject_type, p_subject_id, p_object_id, p_visited) = 1

func InternalCheckCall

func InternalCheckCall(subjectType, subjectID Expr, relation string, parentType, parentID, visited Expr) FuncCallEq

InternalCheckCall creates a check_permission_internal call with explicit subject/object types. Used in parent relation (TTU) checks where the linking tuple provides the parent object.

Example:

InternalCheckCall(SubjectType, SubjectID, "viewer", Col{Table: "link", Column: "subject_type"}, Col{Table: "link", Column: "subject_id"}, visited)

Renders: check_permission_internal(p_subject_type, p_subject_id, 'viewer', link.subject_type, link.subject_id, <visited>) = 1

func InternalPermissionCheckCall

func InternalPermissionCheckCall(relation, objectType string, objectID, visited Expr) FuncCallEq

InternalPermissionCheckCall creates a check_permission_internal function call comparison. This is the most common pattern in the codebase for recursive permission checks.

Example:

InternalPermissionCheckCall("viewer", "document", Col{Table: "t", Column: "object_id"}, Visited)

Renders: check_permission_internal(p_subject_type, p_subject_id, 'viewer', 'document', t.object_id, p_visited) = 1

func NoWildcardPermissionCheckCall

func NoWildcardPermissionCheckCall(relation, objectType string, subjectID, objectID Expr) FuncCallEq

NoWildcardPermissionCheckCall creates a check_permission_no_wildcard function call.

func SpecializedCheckCall

func SpecializedCheckCall(funcName string, subjectType, subjectID, objectID, visited Expr) FuncCallEq

SpecializedCheckCall creates a call to a specialized check function. Used for implied relations and parent relation checks.

Example:

SpecializedCheckCall("check_doc_owner", SubjectType, SubjectID, ObjectID, Visited)

Renders: check_doc_owner(p_subject_type, p_subject_id, p_object_id, p_visited) = 1

func (FuncCallEq) SQL

func (f FuncCallEq) SQL() string

SQL renders the function call comparison.

type FuncCallNe

type FuncCallNe struct {
	FuncName string
	Args     []Expr
	Value    Expr
}

FuncCallNe compares a function call result for inequality. Used for negative authorization checks like "check_permission(...) <> 1".

func (FuncCallNe) SQL

func (f FuncCallNe) SQL() string

SQL renders the function call not-equal comparison.

type FunctionCallExpr

type FunctionCallExpr struct {
	Name  string // Function name
	Args  []Expr // Function arguments
	Alias string // Table alias for the result
}

FunctionCallExpr represents a function call that can be used as a table expression. Used for LATERAL joins with table-returning functions.

func (FunctionCallExpr) TableAlias

func (f FunctionCallExpr) TableAlias() string

TableAlias implements TableExpr.

func (FunctionCallExpr) TableSQL

func (f FunctionCallExpr) TableSQL() string

TableSQL implements TableExpr.

type Gt

type Gt struct {
	Left  Expr
	Right Expr
}

Gt represents a greater-than comparison (>).

func (Gt) SQL

func (g Gt) SQL() string

type Gte

type Gte struct {
	Left  Expr
	Right Expr
}

Gte represents a greater-than-or-equal comparison (>=).

func (Gte) SQL

func (g Gte) SQL() string

type HasUserset

type HasUserset struct {
	Source Expr
}

HasUserset checks if an expression contains a userset marker (#).

func (HasUserset) SQL

func (h HasUserset) SQL() string

type In

type In struct {
	Expr   Expr
	Values []string
}

In represents an IN clause for string values.

func (In) SQL

func (i In) SQL() string

type InFunctionSelect

type InFunctionSelect struct {
	Expr      Expr   // The expression to check (left side of IN)
	FuncName  string // The function to call
	Args      []Expr // Function arguments
	Alias     string // Alias for the function result
	SelectCol string // Column to select from the function result
}

InFunctionSelect represents "expr IN (SELECT column FROM func(args...) alias)". Used for checking membership against results of a list function.

Example:

InFunctionSelect{
    Expr:       Col{Table: "t", Column: "subject_id"},
    FuncName:   "list_doc_viewer_objects",
    Args:       []Expr{SubjectType, SubjectID, Null{}, Null{}},
    Alias:      "obj",
    SelectCol:  "object_id",
}

Renders: t.subject_id IN (SELECT obj.object_id FROM list_doc_viewer_objects(p_subject_type, p_subject_id, NULL, NULL) obj)

func (InFunctionSelect) SQL

func (i InFunctionSelect) SQL() string

SQL renders the IN subquery expression.

type Int

type Int int

Int represents an integer literal.

func (Int) SQL

func (i Int) SQL() string

SQL renders the integer.

type IntersectSubquery

type IntersectSubquery struct {
	Queries []SelectStmt
	Alias   string
}

IntersectSubquery represents an INTERSECT of multiple queries as a subquery. Used for intersection groups where all parts must be satisfied.

Example: IntersectSubquery{Queries: [q1, q2], Alias: "ig"} Renders: (q1 INTERSECT q2) AS ig

func (IntersectSubquery) TableAlias

func (i IntersectSubquery) TableAlias() string

TableAlias implements TableExpr.

func (IntersectSubquery) TableSQL

func (i IntersectSubquery) TableSQL() string

TableSQL renders the INTERSECT subquery as a FROM clause table expression.

type IsNotNull

type IsNotNull struct {
	Expr Expr
}

IsNotNull represents IS NOT NULL check.

func (IsNotNull) SQL

func (i IsNotNull) SQL() string

type IsNull

type IsNull struct {
	Expr Expr
}

IsNull represents IS NULL check.

func (IsNull) SQL

func (i IsNull) SQL() string

type IsWildcard

type IsWildcard struct {
	Source Expr
}

IsWildcard checks if an expression equals the wildcard value "*".

func (IsWildcard) SQL

func (w IsWildcard) SQL() string

type JoinClause

type JoinClause struct {
	Type      string    // "INNER", "LEFT", etc.
	Table     string    // Deprecated: use TableExpr instead
	TableExpr TableExpr // Preferred: typed table expression
	Alias     string    // Deprecated: use TableExpr's alias instead
	On        Expr
}

JoinClause represents a SQL JOIN clause.

func (JoinClause) SQL

func (j JoinClause) SQL() string

SQL renders the JOIN clause.

type LateralFunction

type LateralFunction struct {
	Name  string
	Args  []Expr
	Alias string
}

LateralFunction represents a LATERAL function call in a JOIN. Example: LateralFunction{Name: "list_doc_viewer_subjects", Args: []Expr{...}, Alias: "s"} Renders: LATERAL list_doc_viewer_subjects(...) AS s

func (LateralFunction) SQL

func (l LateralFunction) SQL() string

SQL renders the LATERAL function expression.

func (LateralFunction) TableAlias

func (l LateralFunction) TableAlias() string

TableAlias implements TableExpr.

func (LateralFunction) TableSQL

func (l LateralFunction) TableSQL() string

TableSQL implements TableExpr.

type Like

type Like struct {
	Expr    Expr
	Pattern Expr
}

Like represents a LIKE pattern match.

func (Like) SQL

func (l Like) SQL() string

type Lit

type Lit string

Lit represents a literal string value (auto-quoted with single quotes).

func LitText

func LitText(v string) Lit

LitText creates a Lit from a string value. This is an explicit alias for Lit, useful when the intent is to create a text literal. Example: LitText("document") renders as 'document'

func (Lit) SQL

func (l Lit) SQL() string

SQL renders the literal with single quotes.

type Lt

type Lt struct {
	Left  Expr
	Right Expr
}

Lt represents a less-than comparison (<).

func (Lt) SQL

func (l Lt) SQL() string

type Lte

type Lte struct {
	Left  Expr
	Right Expr
}

Lte represents a less-than-or-equal comparison (<=).

func (Lte) SQL

func (l Lte) SQL() string

type Ne

type Ne struct {
	Left  Expr
	Right Expr
}

Ne represents a not-equal comparison (<>).

func (Ne) SQL

func (n Ne) SQL() string

type NoUserset

type NoUserset struct {
	Source Expr
}

NoUserset checks if an expression does NOT contain a userset marker (#).

func (NoUserset) SQL

func (n NoUserset) SQL() string

type NotExists

type NotExists struct {
	Query interface{ SQL() string }
}

NotExists represents a NOT EXISTS subquery.

func (NotExists) SQL

func (n NotExists) SQL() string

type NotExpr

type NotExpr struct {
	Expr Expr
}

NotExpr represents a logical NOT of an expression.

func Not

func Not(expr Expr) NotExpr

Not creates a NOT expression.

func (NotExpr) SQL

func (n NotExpr) SQL() string

type NotIn

type NotIn struct {
	Expr   Expr
	Values []string
}

NotIn represents a NOT IN clause for string values.

func (NotIn) SQL

func (n NotIn) SQL() string

type NotLike

type NotLike struct {
	Expr    Expr
	Pattern Expr
}

NotLike represents a NOT LIKE pattern match.

func (NotLike) SQL

func (n NotLike) SQL() string

type Null

type Null struct{}

Null represents SQL NULL.

func (Null) SQL

func (Null) SQL() string

SQL renders NULL.

type ObjectRef

type ObjectRef struct {
	Type Expr
	ID   Expr
}

ObjectRef represents an object reference (type + id).

func LiteralObject

func LiteralObject(objectType string, id Expr) ObjectRef

LiteralObject creates an ObjectRef with literal type and expression ID.

type OrExpr

type OrExpr struct {
	Exprs []Expr
}

OrExpr represents a logical OR of multiple expressions.

func Or

func Or(exprs ...Expr) OrExpr

Or creates an OR expression from multiple expressions.

func (OrExpr) SQL

func (o OrExpr) SQL() string

type Param

type Param string

Param represents a function parameter (e.g., p_subject_type, p_object_id).

func ParamRef

func ParamRef(name string) Param

ParamRef creates a Param from a variable name. Use this for local PL/pgSQL variables (e.g., "v_filter_type", "v_filter_relation").

func (Param) SQL

func (p Param) SQL() string

SQL renders the parameter.

type Paren

type Paren struct {
	Expr Expr
}

Paren wraps an expression in parentheses.

func (Paren) SQL

func (p Paren) SQL() string

SQL renders the parenthesized expression.

type Position

type Position struct {
	Needle   Expr
	Haystack Expr
}

Position represents SQL position(needle in haystack). Returns the position of the first occurrence of needle in haystack.

func (Position) SQL

func (p Position) SQL() string

SQL renders the position expression.

type QueryBlock

type QueryBlock struct {
	Comments []string // Comment lines (without -- prefix)
	Query    SQLer    // The query as typed DSL (SelectStmt, Raw, etc.)
}

QueryBlock represents a query with optional comments. Used to build UNION queries with descriptive comments for each branch.

type Raw

type Raw string

Raw is an escape hatch for arbitrary SQL expressions.

func (Raw) SQL

func (r Raw) SQL() string

SQL renders the raw SQL as-is.

type SQLer

type SQLer interface {
	SQL() string
}

SQLer is an interface for types that can render SQL. SelectStmt, Raw, and other query types implement this interface.

type SelectIntoVar

type SelectIntoVar struct {
	Query    SQLer  // The query (e.g., a CTE)
	Variable string // Variable name to select into
}

SelectIntoVar wraps a query for use with PL/pgSQL SELECT INTO. Appends "INTO <variable>" after the query.

Example:

SelectIntoVar{Query: cteQuery, Variable: "v_max_depth"}

Renders:

<query> INTO v_max_depth

func (SelectIntoVar) SQL

func (s SelectIntoVar) SQL() string

SQL renders the query with INTO clause appended.

type SelectStmt

type SelectStmt struct {
	Distinct    bool
	Columns     []string  // Deprecated: use ColumnExprs instead
	ColumnExprs []Expr    // Preferred: typed column expressions
	From        string    // Deprecated: use FromExpr instead
	FromExpr    TableExpr // Preferred: typed table expression
	Alias       string    // Deprecated: use FromExpr's alias instead
	Joins       []JoinClause
	Where       Expr
	Limit       int
}

SelectStmt represents a SELECT query.

func (SelectStmt) Exists

func (s SelectStmt) Exists() string

Exists wraps a query in EXISTS(...).

func (SelectStmt) NotExists

func (s SelectStmt) NotExists() string

NotExists wraps a query in NOT EXISTS(...).

func (SelectStmt) SQL

func (s SelectStmt) SQL() string

SQL renders the SELECT statement.

type Sub

type Sub struct {
	Left  Expr
	Right Expr
}

Sub represents subtraction (-).

func (Sub) SQL

func (s Sub) SQL() string

type SubjectRef

type SubjectRef struct {
	Type Expr
	ID   Expr
}

SubjectRef represents a subject reference (type + id).

func SubjectParams

func SubjectParams() SubjectRef

SubjectParams creates a SubjectRef from the standard function parameters.

type Substring

type Substring struct {
	Source Expr
	From   Expr
	For    Expr // optional
}

Substring represents SQL substring(source from start [for length]). If For is nil, renders substring(source from start). If For is provided, renders substring(source from start for length).

func (Substring) SQL

func (s Substring) SQL() string

SQL renders the substring expression.

type SubstringUsersetRelation

type SubstringUsersetRelation struct {
	Source Expr
}

SubstringUsersetRelation extracts the relation portion after the '#' marker. Used when the input contains a userset marker and we need just the relation.

func (SubstringUsersetRelation) SQL

type TableExpr

type TableExpr interface {
	// TableSQL returns the SQL for use in FROM/JOIN clauses.
	TableSQL() string
	// TableAlias returns the alias if any (empty string if none).
	TableAlias() string
}

TableExpr is the interface for table expressions in FROM and JOIN clauses. Types that can be used as table sources implement this interface.

func ClosureTable

func ClosureTable(rows []ValuesRow, alias string) TableExpr

ClosureTable returns a typed closure VALUES table.

func UsersetTable

func UsersetTable(rows []ValuesRow, alias string) TableExpr

UsersetTable returns a typed userset VALUES table.

type TableRef

type TableRef struct {
	Name  string
	Alias string
}

TableRef wraps a raw table name for use as a TableExpr.

func TableAs

func TableAs(name, alias string) TableRef

TableAs creates a table reference with an alias.

func (TableRef) TableAlias

func (t TableRef) TableAlias() string

TableAlias implements TableExpr.

func (TableRef) TableSQL

func (t TableRef) TableSQL() string

TableSQL implements TableExpr.

type TupleNotIn added in v0.7.0

type TupleNotIn struct {
	Exprs []Expr     // Column expressions (e.g., object_type, relation)
	Pairs [][]string // Pairs of literal values to exclude
}

TupleNotIn represents a composite NOT IN clause for multiple columns. Renders (expr1, expr2) NOT IN (('a','b'), ('c','d')).

func (TupleNotIn) SQL added in v0.7.0

func (t TupleNotIn) SQL() string

type TypedValuesTable

type TypedValuesTable struct {
	Rows    []ValuesRow // Typed expression rows
	Alias   string      // Table alias
	Columns []string    // Column names
}

TypedValuesTable represents a VALUES clause with typed expression rows. Unlike ValuesTable which uses a pre-formatted string, TypedValuesTable uses structured ValuesRow elements that render via the Expr DSL.

Example:

TypedValuesTable{
    Rows: []ValuesRow{{Lit("doc"), Lit("viewer"), Lit("editor")}},
    Alias: "c",
    Columns: []string{"object_type", "relation", "satisfying_relation"},
}

Renders: (VALUES ('doc', 'viewer', 'editor')) AS c(object_type, relation, satisfying_relation)

func TypedClosureValuesTable

func TypedClosureValuesTable(rows []ValuesRow, alias string) TypedValuesTable

TypedClosureValuesTable creates a typed closure VALUES table. The table has columns: object_type, relation, satisfying_relation

func TypedUsersetValuesTable

func TypedUsersetValuesTable(rows []ValuesRow, alias string) TypedValuesTable

TypedUsersetValuesTable creates a typed userset VALUES table. The table has columns: object_type, relation, subject_type, subject_relation

func (TypedValuesTable) SQL

func (v TypedValuesTable) SQL() string

SQL renders the typed VALUES table expression.

func (TypedValuesTable) TableAlias

func (v TypedValuesTable) TableAlias() string

TableAlias implements TableExpr.

func (TypedValuesTable) TableSQL

func (v TypedValuesTable) TableSQL() string

TableSQL implements TableExpr.

type UnionAll

type UnionAll struct {
	Queries []SQLer
	Indent  string // Optional indent prefix for each query (default: empty)
}

UnionAll represents multiple queries combined with UNION ALL. Each query is rendered and joined with UNION ALL.

Example:

UnionAll{Queries: []SQLer{query1, query2}}

Renders:

query1
UNION ALL
query2

func (UnionAll) SQL

func (u UnionAll) SQL() string

SQL renders the UNION of all queries.

type UsersetNormalized

type UsersetNormalized struct {
	Source   Expr
	Relation Expr
}

UsersetNormalized replaces the relation in a userset with a new relation. Example: "group:1#admin" with relation "member" -> "group:1#member"

func (UsersetNormalized) SQL

func (u UsersetNormalized) SQL() string

type UsersetObjectID

type UsersetObjectID struct {
	Source Expr
}

UsersetObjectID extracts the object ID: "group:1#member" -> "group:1"

func (UsersetObjectID) SQL

func (u UsersetObjectID) SQL() string

type UsersetRelation

type UsersetRelation struct {
	Source Expr
}

UsersetRelation extracts the relation: "group:1#member" -> "member"

func (UsersetRelation) SQL

func (u UsersetRelation) SQL() string

type ValuesRow

type ValuesRow []Expr

ValuesRow represents a single row in a VALUES clause as typed expressions. Each element in the slice corresponds to a column value.

func (ValuesRow) SQL

func (r ValuesRow) SQL() string

SQL renders the row as (expr1, expr2, ...).

type ValuesTable

type ValuesTable struct {
	Values  string   // The VALUES content (e.g., "('a', 'b'), ('c', 'd')")
	Alias   string   // Table alias (e.g., "c")
	Columns []string // Column names (e.g., ["object_type", "relation"])
}

ValuesTable represents a VALUES clause as a table expression. Used to inline data like closure values without database tables.

Example: ValuesTable{Values: "('doc', 'viewer', 'editor')", Alias: "c", Columns: []string{"object_type", "relation", "satisfying_relation"}} Renders: (VALUES ('doc', 'viewer', 'editor')) AS c(object_type, relation, satisfying_relation)

func (ValuesTable) SQL

func (v ValuesTable) SQL() string

SQL renders the VALUES table expression.

func (ValuesTable) TableAlias

func (v ValuesTable) TableAlias() string

TableAlias implements TableExpr.

func (ValuesTable) TableSQL

func (v ValuesTable) TableSQL() string

TableSQL implements TableExpr.

type WithCTE

type WithCTE struct {
	Recursive bool     // If true, renders WITH RECURSIVE
	CTEs      []CTEDef // One or more CTE definitions
	Query     SQLer    // The final SELECT that uses the CTEs
}

WithCTE represents a WITH clause wrapping a final query. Supports both regular and recursive CTEs.

Example:

WithCTE{
    Recursive: true,
    CTEs: []CTEDef{{Name: "accessible", Columns: []string{"object_id", "depth"}, Query: cteQuery}},
    Query: finalSelect,
}

Renders:

WITH RECURSIVE accessible(object_id, depth) AS (
    <cte query>
)
<final query>

func MultiCTE

func MultiCTE(recursive bool, ctes []CTEDef, finalQuery SQLer) WithCTE

MultiCTE creates a WITH clause with multiple CTEs. Useful for complex queries with subject_pool, base_results, has_wildcard, etc.

func RecursiveCTE

func RecursiveCTE(name string, columns []string, cteQuery, finalQuery SQLer) WithCTE

RecursiveCTE is a convenience constructor for a single recursive CTE.

func SimpleCTE

func SimpleCTE(name string, cteQuery, finalQuery SQLer) WithCTE

SimpleCTE is a convenience constructor for a single non-recursive CTE.

func (WithCTE) SQL

func (w WithCTE) SQL() string

SQL renders the complete WITH clause and final query.

Jump to

Keyboard shortcuts

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