Documentation
¶
Overview ¶
Package filtertest is the filter conformance fixture: one entity with a field of every filterable type, its rows, and the rows every backend must return for each filter. SQL dialects and in-memory evaluators run the same cases through Run, so an operator means one thing everywhere .
Index ¶
- Variables
- func Lookups() filter.MembershipLookup
- func Parser(t testing.TB) *filter.FilterParser
- func PathParser(schema *filter.ResourceSchema) *filter.FilterParser
- func PathSchema() (*filter.ResourceSchema, error)
- func Run(t *testing.T, name string, backend Backend)
- func RunMembership(t *testing.T, backend Backend)
- func RunPaths(t *testing.T, schema *filter.ResourceSchema, backend Backend)
- func Schema() (*filter.ResourceSchema, error)
- type Backend
- type Case
- type LookupColumn
- type LookupTable
- type MembershipCase
- type PathRecord
- type Record
- type Settings
- type Window
Constants ¶
This section is empty.
Variables ¶
var ( Base = time.Date(2026, 1, 2, 3, 4, 5, 0, time.UTC) Now = func() time.Time { return Base.Add(3 * time.Second) } )
Base is the instant timestamps are offset from; Now is the parser clock relative tokens resolve against.
var PathFacets = map[string]map[string]int64{
"attrs.color": {"red": 1, "blue": 1, "Red": 1},
"attrs.on": {"true": 2, "false": 1},
"settings.mode": {"auto": 2, "manual": 1, "": 1},
"settings.level": {"0-5": 2, "5+": 2},
"attrs.price": {"10.25": 1, "9.5": 1, "-1": 1, "100": 1},
}
PathFacets are the buckets path facets count over PathRecords; an absent member is in no bucket.
var PathOrders = map[string]string{
"attrs.size": "agbecdfh",
"-attrs.size": "hfdcebga",
"attrs.seen": "aebcdfgh",
"-attrs.seen": "hgfdcbea",
"attrs.color": "gbacdefh",
"settings.level": "eabgcdfh",
"-settings.level": "hfdcgbae",
"attrs.price": "ebagcdfh",
"-attrs.price": "hfdcgabe",
}
PathOrders are the presentation orders path sorts give PathRecords: an absent member sorts as NULL (greatest), ties on id in the primary direction.
Functions ¶
func Lookups ¶
func Lookups() filter.MembershipLookup
Lookups resolves the cases' memberships over LookupTables with filter.MatchLookupRow: the in-memory answer to every lookup.
func Parser ¶
func Parser(t testing.TB) *filter.FilterParser
Parser returns the fixture's filter parser, clock pinned to Now.
func PathParser ¶
func PathParser(schema *filter.ResourceSchema) *filter.FilterParser
PathParser returns a filter parser over schema — PathSchema, or a copy declaring another storage — with its clock pinned to Now.
func PathSchema ¶
func PathSchema() (*filter.ResourceSchema, error)
PathSchema returns PathRecord's generated filter schema.
func RunMembership ¶
RunMembership evaluates every membership case on backend. The filter it passes still holds membership nodes: a SQL backend compiles them, a memory backend resolves them (filter.ResolveMemberships) first.
func RunPaths ¶
func RunPaths(t *testing.T, schema *filter.ResourceSchema, backend Backend)
RunPaths evaluates every path case, parsed against schema (PathSchema or a copy declaring the backend's storage), on backend, which evaluates against PathRecords.
func Schema ¶
func Schema() (*filter.ResourceSchema, error)
Schema returns Record's generated filter schema.
Types ¶
type Case ¶
type Case struct {
Name string
Filter string
Want []string
// ParseErr is the E-code the parser rejects Filter with; Want is unused.
ParseErr string
// Unsupported names the backends that cannot evaluate the filter and
// must fail instead ("sqlite", "memory"); a coded failure carries
// E2115.
Unsupported []string
}
Case is one filter and the IDs it matches, in ID order.
type LookupColumn ¶
LookupColumn is one lookup column and the type its values have: string, uuid (uuid.UUID values) or int (int64 values).
type LookupTable ¶
type LookupTable struct {
Name string
Columns []LookupColumn
Rows [][]any
}
LookupTable is a table membership cases select from. A backend creates it beside "records" with a column per LookupColumn and loads Rows; a nil value is NULL.
func LookupTables ¶
func LookupTables() []LookupTable
LookupTables are the shapes authorization resolves through: a reflexive closure over record ids, a pair relation with users, groups, tenants and ended pairs, grants of UUID references, and a nullable integer column.
type MembershipCase ¶
type MembershipCase struct {
Name string
Constraints *filter.PolicyConstraints
Want []string
}
MembershipCase applies Constraints to an empty filter over Records; Want is the matching IDs in ID order.
func MembershipCases ¶
func MembershipCases() []MembershipCase
MembershipCases are the membership semantics every backend shares: SQL's `x IN (subquery)`, three-valued under NOT when x or a projected value is NULL.
type PathRecord ¶
type PathRecord struct {
ID string `json:"id" db:"id" parse:"filter" filter_ops:"eq,in"`
Attrs json.RawMessage `` /* 213-byte string literal not displayed */
Settings *Settings `json:"settings" db:"settings" parse:"filter"`
}
PathRecord holds two documents: Attrs, a map with declared paths, and Settings, a struct whose members are paths. Its table is "path_records".
func PathRecords ¶
func PathRecords() []PathRecord
PathRecords is the path fixture. Rows c, d, f and h hold no typed member at any attrs path: c's members have other JSON kinds or shapes (its price a string in exponent notation), d's attrs is NULL, f's is empty and h's is an array; c's timestamp carries an offset. e's color is JSON null, its size is above 2^53 and its timestamp has a short fraction; g's size is a decimal, its color upper-case and its owner an upper-case UUID. a's timestamp is written as encoding/json writes UTC. Prices are JSON numbers (a, e) or strings in plain notation (b with a scale, g), as a decimal encodes.
type Record ¶
type Record struct {
ID string `json:"id" db:"id" parse:"filter" filter_ops:"eq,in"`
Name *string `json:"name" db:"name" parse:"filter" filter_ops:"eq,ne,gt,gte,lt,lte,in,nin,like,ilike,contains,null,not_null,exists"`
Count *int64 `json:"count" db:"count" parse:"filter" filter_ops:"eq,ne,gt,gte,lt,lte,in,nin,null,not_null,exists"`
Score *float64 `json:"score" db:"score" parse:"filter" filter_ops:"eq,ne,gt,gte,lt,lte,in,nin,null,not_null,exists"`
Amount *decimal.Decimal `json:"amount" db:"amount" parse:"filter" filter_ops:"eq,ne,gt,gte,lt,lte,in,nin,null,not_null,exists"`
Active *bool `json:"active" db:"active" parse:"filter" filter_ops:"eq,ne,in,nin,null,not_null,exists"`
At *time.Time `json:"at" db:"at" parse:"filter" filter_ops:"eq,ne,gt,gte,lt,lte,in,nin,null,not_null,exists"`
Ref *uuid.UUID `json:"ref" db:"ref" parse:"filter" filter_ops:"eq,ne,in,nin,null,not_null,exists"`
Doc json.RawMessage `json:"doc" db:"doc" parse:"filter" filter_ops:"eq,ne,contains,null,not_null,exists"`
Tags []string `json:"tags" db:"tags" parse:"filter" filter_ops:"contains,null,not_null,exists"`
Loc map[string]float64 `json:"loc" db:"loc" parse:"filter" filter_ops:"near,within,intersects,null,not_null,exists" geo:"jsonb"`
}
Record declares every operator its field type admits (filter.OperatorsFor), so the cases cover the full operator × type matrix. Its table is "records".
func Records ¶
func Records() []Record
Records is the fixture data. Row d is NULL in every column but id; g's document stores its integer as 1.0 with keys in a different order than the cases name them. The amounts order differently as numbers than as text (9.5 < 10 < 10.25), and h's is stored with a scale (10.00).
type Settings ¶
type Settings struct {
Mode string `json:"mode" parse:"filter,facet" filter_ops:"eq,ne,gt,lt,in,null,exists"`
Level int64 `json:"level" parse:"filter,sort,facet" facet:"range:0-5,5+"`
Window *Window `json:"window" parse:"filter"`
Note string `json:"note"`
}
Settings is a typed (struct) document; its tagged members are paths settings.mode, settings.level, settings.window.from.