Documentation
¶
Overview ¶
Package filter is a declarative, allowlist-based query engine for list endpoints. A resource declares a Schema[T] of typed Field accessors; the engine parses url.Values into a validated Query and applies it to an in-memory []*T (filter -> sort -> window), returning the page plus the pre-window total.
The contract (shared with the relay UI's filter convention):
- Equality: ?field=value
- One-of (IN): repeat the key — ?id=a&id=b (OR within a field)
- Boolean: ?field=true|false
- Numeric range: ?field_min= / ?field_max=
- Time range: ?field_from= / ?field_to= (RFC3339)
- Free-text: ?q=... (Schema-chosen corpus, case-insensitive)
- Sort: ?sort=field ('-' prefix = descending)
- Window: ?limit= / ?offset=
Filters compose with AND; repeated same-key values are OR within that field. Any query key not in the schema's allowlist (or a malformed value) is rejected with an *Error — the HTTP layer maps it to 400 so typos surface instead of silently matching everything.
Out of scope: SQL pushdown. This engine filters a materialised slice; it suits the config catalog (hundreds of rows read from the in-memory snapshot/store). The usage/event path has its own store-aware query type (pkg/usage.EventQuery) because it pushes filters into ClickHouse SQL.
Index ¶
Constants ¶
const MaxLimit = 10_000
MaxLimit caps ?limit= to bound response size on a hostile request.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Error ¶
Error is a rejected-request error (unknown key, bad value, disallowed sort). The HTTP layer maps it to 400 with Key naming the offending param.
type Field ¶
type Field[T any] struct { Name string // query-param name == JSON field == the allowlist key Kind Kind Repeat bool // String: accept repeated keys, OR within the field MatchAll bool // String+GetMulti+Repeat: require the item's set to contain ALL requested values (AND) instead of any (OR). For "supports both" filters like capability=. Enum []string // String: if set, values must be one of these (else 400) Sortable bool // may appear in ?sort= Get func(*T) string GetMulti func(*T) []string GetBool func(*T) bool GetInt func(*T) int64 GetTime func(*T) time.Time }
Field declares one filterable/sortable dimension of T. Exactly one accessor must be set, matching Kind (String -> Get or GetMulti; Bool -> GetBool; Int -> GetInt; Time -> GetTime). The accessor is a typed closure over T, so renaming the underlying struct field is a compile error here — the param name, allowlist entry, and match logic all derive from this single declaration.
type Kind ¶
type Kind int
Kind tags a field's value domain, which selects the parse + match rules and the accepted query-param spelling (range fields gain _min/_max or _from/_to suffixes).
const ( // String matches by exact equality. With Repeat, the key may appear // multiple times and matches if the field equals ANY given value (IN). // Use Get for a single-valued field or GetMulti for a slice field // (matches if any element equals any requested value). String Kind = iota // Bool matches ?field=true|false against a bool accessor. Bool // Int matches an inclusive numeric range via ?field_min / ?field_max. Int // Time matches an inclusive instant range via ?field_from / ?field_to, // each an RFC3339 timestamp. Time )
type Param ¶
type Param struct {
Name string
Type string // "string" | "integer" | "boolean"
Repeatable bool // array-valued query param (explode)
Enum []string
Description string
}
Param is a framework-agnostic description of one accepted query parameter, derived from the schema. The HTTP layer maps these to its router's parameter type (e.g. huma.Param) so the OpenAPI spec — and any client generated from it — sees exactly the params the engine accepts. Keeping this pure (no web-framework import) preserves the single-source- of-truth property: params are derived from the same Field list that drives matching.
type Query ¶
type Query[T any] struct { // contains filtered or unexported fields }
Query is a parsed, validated request ready to Apply to a slice of T.
type Schema ¶
type Schema[T any] struct { Fields []Field[T] // Q returns the free-text search corpus for one item; ?q= matches when // any corpus string contains the query (case-insensitive). Nil disables // the q param. Q func(*T) []string // Labels returns the item's label map; ?label=k=v (repeatable) matches // when every selector's key equals the given value (AND, like a k8s // label selector). Nil disables the label param. Labels func(*T) map[string]string // DefaultSort is the sort applied when ?sort= is absent, e.g. "name" or // "-created_at". Must reference a Sortable field; empty leaves input // order untouched. DefaultSort string // DefaultLimit is the page size applied when ?limit= is absent, so a // bare list request can't return an unbounded set. 0 keeps the legacy // return-everything behavior. An explicit ?limit=0 opts out (returns // everything up to MaxLimit semantics); the response's pre-window total // always reports the full match count. DefaultLimit int }
Schema is a resource's complete filter contract: its filterable fields, an optional free-text corpus, and a default sort applied when ?sort= is absent.
func (Schema[T]) Params ¶
Params enumerates every query parameter this schema accepts, expanding range fields into their _min/_max or _from/_to pair and appending the engine-owned params (q, label, sort, limit, offset) when applicable. Order is deterministic (field order, then engine params) so generated specs are stable.