Documentation
¶
Overview ¶
Package filterquery parses, validates, and emits boolean filter expressions (AIP-160-derived grammar) as parameterized SQL. It is schema-agnostic: adopters supply a FieldRegistry; the package knows nothing about any caller's tables. See docs/superpowers/specs/ 2026-07-25-filter-query-language-design.md.
Grammar sharp edges, by design:
- One negation per term: NOT NOT x and -NOT x are parse errors.
- A leading "-" starts a negation, so unquoted negative values do not parse; quote them (price="-5").
- A quoted field name ("name":x) parses, but validation still requires an exact registered field and emission uses registry constants.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type And ¶
And is a conjunction — explicit (expression level) or implicit (sequence level). The two levels share a node type; precedence is settled at parse.
type Bare ¶
Bare is an unqualified term (AIP-160 global restriction). The v1 registry rejects these at validation; the parser still produces them so the rejection error can name the term precisely.
type Comparison ¶
type Comparison struct {
Field string // dotted path, e.g. "label" or "metrics.latency"
Op string // one of ":", "=", "!=", "<", "<=", ">", ">="
Raw string // value text (unescaped contents for quoted strings)
Quoted bool // value was a quoted string
Value any // coerced value, set by Validate
At int
// contains filtered or unexported fields
}
Comparison is `field op value`. Value holds the coerced value and is set by Registry.Validate; before validation only Raw is meaningful. A comparison may emit only through the registry that validated it.
func (*Comparison) Pos ¶
func (n *Comparison) Pos() int
type Dialect ¶
Dialect abstracts SQL placeholder style. Task 4 adds the built-in Postgres adapter; defining the interface here keeps EmitCtx compilable.
type EmitCtx ¶
type EmitCtx struct {
// contains filtered or unexported fields
}
EmitCtx hands FieldSpec.Emit sequential placeholders and collects args.
type ErrKind ¶
type ErrKind int
ErrKind classifies an *Error for the HTTP layer (all map to 400 today; the distinction exists for metrics and future client hints).
type Error ¶
Error is a positioned filter-language error. Pos is a 0-based byte offset into the input; -1 when not position-specific. The displayed column is therefore byte-based: with multibyte input before the error position it overcounts runes. Inputs are short (capped) and the column is a hint, so this is accepted rather than paying for rune indexing.
type Expr ¶
type Expr struct {
// contains filtered or unexported fields
}
Expr is a parsed + validated filter, ready to emit at any placeholder offset. Safe for concurrent Emit calls: the AST is immutable after Parse, and Emit constructs a fresh EmitCtx per call.
func Parse ¶
Parse lexes, parses, and validates q. Empty/whitespace-only q yields a nil Expr and nil error (no constraint).
type FieldSpec ¶
type FieldSpec struct {
Name string
Ops []string // allowed operators, e.g. []string{":"}
// Coerce converts the raw value text into the typed value stored on
// Comparison.Value. quoted reports that the input was a quoted string.
Coerce func(raw string, quoted bool) (any, error)
// Emit renders one boolean predicate. Placeholders and args are bound
// through EmitCtx.PH. Fields binding no value (boolean flags) simply
// don't call PH.
Emit func(c *Comparison, e *EmitCtx) (string, error)
}
FieldSpec describes one filterable field: which operators it accepts, how raw values coerce, and how a validated comparison emits SQL. Coerce and Emit must be deterministic and safe for concurrent calls: emission re-coerces a private comparison copy on every call.
type Node ¶
type Node interface {
Pos() int
}
Node is one AST node. Pos is the 0-based byte offset of the node's first character in the input, for error messages.
type PostgresDialect ¶
type PostgresDialect struct{}
PostgresDialect uses $n placeholders.
func (PostgresDialect) Placeholder ¶
func (PostgresDialect) Placeholder(n int) string
type Registry ¶
type Registry struct {
// contains filtered or unexported fields
}
Registry is the adopter-supplied field set. Construct once at startup; safe for concurrent use after construction. Note the concurrency guarantee covers the REGISTRY, not a shared AST: Validate coerces Comparison values in place, so a single parsed AST must not be validated (or compiled) concurrently — parse per request. The Expr flow (Parse once, then concurrent Expr.Emit) is immutable and is the supported shared path.
func NewRegistry ¶
func (*Registry) Emit ¶
Emit renders a validated AST as a parenthesized boolean SQL fragment plus its bound args. Placeholders are numbered from start (1-based index of the next free parameter in the caller's query).
func (*Registry) Validate ¶
Validate checks the AST against the registry and coerces every value in place (Comparison.Value). Bare terms are rejected here — the grammar accepts them, the v1 vocabulary does not. Because coercion mutates the nodes, do not Validate the same AST from concurrent goroutines; see the Registry doc comment.