filtertest

package
v0.8.0 Latest Latest
Warning

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

Go to latest
Published: Nov 2, 2026 License: MIT Imports: 12 Imported by: 0

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

Constants

This section is empty.

Variables

View Source
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.

View Source
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.

View Source
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 Run

func Run(t *testing.T, name string, backend Backend)

Run evaluates every case on backend, named as Case.Unsupported names it.

func RunMembership

func RunMembership(t *testing.T, backend Backend)

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 Backend

type Backend func(t *testing.T, f *filter.ParsedFilter) ([]string, error)

Backend evaluates a parsed filter over Records and returns the matching IDs.

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.

func Cases

func Cases() []Case

Cases is the operator × type matrix over Records. Every predicate but the NULL tests is NULL on a NULL field, so negation never matches row d.

func PathCases

func PathCases() []Case

PathCases are the path filters and the rows each matches. An absent member is NULL: no comparison but the NULL tests matches it.

type LookupColumn

type LookupColumn struct {
	Name string
	Type core.FieldType
}

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.

type Window

type Window struct {
	From time.Time `json:"from" parse:"filter"`
}

Window is a nested struct member of Settings.

Jump to

Keyboard shortcuts

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