filter

package
v3.0.0-...-104a1f6 Latest Latest
Warning

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

Go to latest
Published: Mar 18, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package filter compiles CEL filters into a dialect-agnostic condition tree.

The built-in SQL helpers such as Program.RenderSQL and RenderCondition are one renderer branch over that IR. Downstream integrations that target search engines, analyzers, or static checks should build on Program.Schema, Program.ConditionTree, WalkCondition, WalkValueExpr, and WalkPredicateExpr to implement their own renderer or analyzer without depending on SQL internals.

A custom renderer typically looks like:

prog, _ := engine.Compile(`title.contains(q) && visibility == "PUBLIC"`)
schema := prog.Schema()
cond := prog.ConditionTree()
_ = schema
_ = WalkCondition(cond, func(node Condition) error {
	// translate each IR node into your backend query representation
	return nil
})

Index

Constants

This section is empty.

Variables

View Source
var NowFunction = cel.Function("now",
	cel.Overload("now",
		[]*cel.Type{},
		cel.IntType,
		cel.FunctionBinding(func(_ ...ref.Val) ref.Val {
			return types.Int(time.Now().Unix())
		}),
	),
)

NowFunction exposes a CEL `now()` helper, returning unix seconds.

View Source
var SQLFunction = cel.Function("sql",
	cel.Overload("sql_string", []*cel.Type{cel.StringType}, cel.BoolType),
	cel.Overload("sql_string_list", []*cel.Type{cel.StringType, cel.ListType(cel.DynType)}, cel.BoolType),
)

SQLFunction declares the CEL function used to reference registered SQL predicates:

  • sql("predicate")
  • sql("predicate", [arg1, arg2, ...])

The function is only used for parsing and type-checking; runtime CEL evaluation is not used by this filter engine.

Functions

func EvaluateCondition

func EvaluateCondition(schema Schema, cond Condition, vars map[string]any, opts EvalOptions) (bool, error)

EvaluateCondition evaluates a compiled condition tree against the provided vars.

vars keys are CEL identifiers (schema field names) and any param variables (bindings).

func WalkCondition

func WalkCondition(cond Condition, fn func(Condition) error) error

WalkCondition visits cond and its descendants in pre-order depth-first order.

Nil inputs are ignored. If fn returns an error, traversal stops immediately and that error is returned.

func WalkPredicateExpr

func WalkPredicateExpr(expr PredicateExpr, fn func(PredicateExpr) error) error

WalkPredicateExpr visits expr and its descendants in pre-order depth-first order.

Nil inputs are ignored. If fn returns an error, traversal stops immediately and that error is returned.

func WalkValueExpr

func WalkValueExpr(expr ValueExpr, fn func(ValueExpr) error) error

WalkValueExpr visits expr and its descendants in pre-order depth-first order.

Nil inputs are ignored. If fn returns an error, traversal stops immediately and that error is returned.

Types

type Bindings

type Bindings map[string]any

Bindings provides runtime values for CEL variables which are not schema fields.

These values are used when rendering SQL placeholders and when evaluating compiled conditions in-memory.

type Column

type Column struct {
	Table string
	Name  string
}

Column identifies the backing table column.

type ComparisonCondition

type ComparisonCondition struct {
	Left     ValueExpr
	Operator ComparisonOperator
	Right    ValueExpr
}

ComparisonCondition represents a binary comparison.

type ComparisonOperator

type ComparisonOperator string

ComparisonOperator lists supported comparison operators.

const (
	CompareEq  ComparisonOperator = "="
	CompareNeq ComparisonOperator = "!="
	CompareLt  ComparisonOperator = "<"
	CompareLte ComparisonOperator = "<="
	CompareGt  ComparisonOperator = ">"
	CompareGte ComparisonOperator = ">="
)

type CompileHook

type CompileHook func(schema Schema, filter string, ast *cel.Ast, cond Condition) (Condition, error)

CompileHook can rewrite or replace the compiled condition tree.

Hooks run after CEL parsing/type-checking and IR building, but before the resulting Program is returned.

Returning (nil, nil) keeps the current condition unchanged.

type ComprehensionKind

type ComprehensionKind string

ComprehensionKind enumerates the supported comprehension macros.

const (
	ComprehensionExists ComprehensionKind = "exists"
)

type Condition

type Condition interface {
	// contains filtered or unexported methods
}

Condition represents a boolean expression derived from the CEL filter.

func CondAnd

func CondAnd(c ...Condition) Condition

And combines all conditions with logical AND.

func CondOr

func CondOr(c ...Condition) Condition

Or combines all conditions with logical OR.

type ConstantCondition

type ConstantCondition struct {
	Value bool
}

ConstantCondition captures a literal boolean outcome.

type ContainsCondition

type ContainsCondition struct {
	Field string
	Value ValueExpr
}

ContainsCondition models the <field>.contains(<value>) call.

type ContainsPredicate

type ContainsPredicate struct {
	Substring ValueExpr
}

ContainsPredicate represents t.contains(substring).

type DialectName

type DialectName string

DialectName enumerates supported SQL dialects.

const (
	DialectSQLite   DialectName = "sqlite"
	DialectMySQL    DialectName = "mysql"
	DialectPostgres DialectName = "postgres"
	// DialectPostgresNamedArgs renders Postgres SQL using named arguments (`@name`).
	//
	// The generated statement uses `Statement.NamedArgs` instead of positional `Statement.Args`.
	DialectPostgresNamedArgs DialectName = "postgres_pgx"
)

type DialectSQL

type DialectSQL struct {
	Default  string
	SQLite   string
	MySQL    string
	Postgres string
}

DialectSQL stores dialect-specific SQL templates.

Templates are SQL fragments used in a WHERE clause and must evaluate to a boolean expression in the target dialect.

Placeholders:

  • `{{field_name}}` is replaced with the schema column expression for that field.
  • `?` are replaced with dialect placeholders and populated from condition args.

type ElementInCondition

type ElementInCondition struct {
	Element ValueExpr
	Field   string
}

ElementInCondition represents the CEL syntax `"value" in field`.

This is primarily used for JSON list membership checks.

type EndsWithCondition

type EndsWithCondition struct {
	Field string
	Value ValueExpr
}

EndsWithCondition models the <field>.endsWith(<value>) call.

type EndsWithPredicate

type EndsWithPredicate struct {
	Suffix ValueExpr
}

EndsWithPredicate represents t.endsWith(suffix).

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine parses CEL filters into a dialect-agnostic condition tree.

func NewEngine

func NewEngine(schema Schema, opts ...EngineOption) (*Engine, error)

NewEngine builds a new Engine for the provided schema.

func (*Engine) Compile

func (e *Engine) Compile(filter string) (*Program, error)

Compile parses the filter string into an executable program.

func (*Engine) CompileToStatement

func (e *Engine) CompileToStatement(filter string, bindings Bindings, opts RenderOptions) (Statement, error)

CompileToStatement compiles and renders the filter in a single step.

func (*Engine) ExtraFilterCEL

func (e *Engine) ExtraFilterCEL() string

ExtraFilterCEL returns the Engine's configured extra CEL filter expression.

When unset, it returns an empty string.

func (*Engine) IsCondGranted

func (e *Engine) IsCondGranted(filter string, vars map[string]any) (bool, error)

IsCondGranted executes the filter as a CEL program and expects a boolean outcome.

The vars input is a `map[string]any` holding values for schema-defined fields.

type EngineOption

type EngineOption func(*engineConfig)

EngineOption customizes Engine construction.

func WithCompileHook

func WithCompileHook(hook CompileHook) EngineOption

WithCompileHook appends a post-compile hook which can rewrite the compiled condition tree.

func WithEnvOptions

func WithEnvOptions(opts ...cel.EnvOption) EngineOption

WithEnvOptions appends additional CEL environment options when creating the Engine.

This is the intended "extension hook" for callers to register custom CEL macros, functions, declarations, etc.

func WithExtraFilterCEL

func WithExtraFilterCEL(expr string) EngineOption

WithExtraFilterCEL registers an extra CEL boolean expression on the Engine.

This is consumed by `gorbac.NewFilterProgramFromCEL(...)` to AND an additional filter (e.g. a user query/search expression) onto the permission-derived scope.

func WithMacros

func WithMacros(macros ...cel.Macro) EngineOption

WithMacros is a convenience helper for registering custom CEL macros.

func WithSQLPredicate

func WithSQLPredicate(name string, pred SQLPredicate) EngineOption

WithSQLPredicate registers a custom SQL predicate.

The predicate is referenced from CEL via `sql("<name>")` or `sql("<name>", [...])`.

type EvalOptions

type EvalOptions struct {
}

EvalOptions configures in-memory evaluation.

Dialect is optional, but when set it will try to mirror renderer semantics for a few dialect-sensitive operations (e.g. Postgres ILIKE for contains()).

type Field

type Field struct {
	Name                 string
	Kind                 FieldKind
	Type                 FieldType
	Column               Column
	JSONPath             []string
	AliasFor             string
	SupportsContains     bool
	Expressions          map[DialectName]string
	AllowedComparisonOps map[ComparisonOperator]bool
}

Field captures the schema metadata for an exposed CEL identifier.

type FieldKind

type FieldKind string

FieldKind describes how a field is stored.

const (
	FieldKindScalar       FieldKind = "scalar"
	FieldKindBoolColumn   FieldKind = "bool_column"
	FieldKindJSONBool     FieldKind = "json_bool"
	FieldKindJSONList     FieldKind = "json_list"
	FieldKindVirtualAlias FieldKind = "virtual_alias"
)

type FieldPredicateCondition

type FieldPredicateCondition struct {
	Field string
}

FieldPredicateCondition asserts that a boolean field evaluates to true.

type FieldRef

type FieldRef struct {
	Name string
}

FieldRef references a named schema field.

type FieldType

type FieldType string

FieldType represents the logical type of a field.

const (
	FieldTypeString    FieldType = "string"
	FieldTypeInt       FieldType = "int"
	FieldTypeBool      FieldType = "bool"
	FieldTypeTimestamp FieldType = "timestamp"
)

type FunctionValue

type FunctionValue struct {
	Name string
	Args []ValueExpr
}

FunctionValue captures simple function calls like size(tags).

type InCondition

type InCondition struct {
	Left   ValueExpr
	Values []ValueExpr
}

InCondition represents an IN predicate.

Values can be:

  • individual literals/params (e.g. id in [1,2,3])
  • a single list param (e.g. id in project_ids)

type ListComprehensionCondition

type ListComprehensionCondition struct {
	Kind      ComprehensionKind
	Field     string
	IterVar   string
	Predicate PredicateExpr
}

ListComprehensionCondition represents CEL macros like exists().

type LiteralValue

type LiteralValue struct {
	Value any
}

LiteralValue holds a literal scalar.

type LogicalCondition

type LogicalCondition struct {
	Operator LogicalOperator
	Left     Condition
	Right    Condition
}

LogicalCondition composes two conditions with a logical operator.

type LogicalOperator

type LogicalOperator string

LogicalOperator enumerates the supported logical operators.

const (
	LogicalAnd LogicalOperator = "AND"
	LogicalOr  LogicalOperator = "OR"
)

type NotCondition

type NotCondition struct {
	Expr Condition
}

NotCondition negates a child condition.

type ParamRef

type ParamRef struct {
	Name string
}

ParamRef references a named CEL variable which is not a schema field.

Values are supplied at runtime via bindings (SQL rendering) or vars (in-memory evaluation).

type PredicateExpr

type PredicateExpr interface {
	// contains filtered or unexported methods
}

PredicateExpr represents predicates used in comprehensions.

type Program

type Program struct {
	// contains filtered or unexported fields
}

Program stores a compiled filter condition.

func NewProgramFromCondition

func NewProgramFromCondition(schema Schema, cond Condition) *Program

NewProgramFromCondition wraps an already-built condition tree as a Program.

This is useful when conditions are created programmatically (without CEL parsing), but you still want a single object capable of rendering SQL and evaluating objects.

func (*Program) ConditionTree

func (p *Program) ConditionTree() Condition

ConditionTree exposes the underlying condition tree.

Together with Schema and the Walk* helpers, this is the supported extension surface for downstream renderers, analyzers, and static checks.

func (*Program) IsCondGranted

func (p *Program) IsCondGranted(vars map[string]any, opts ...EvalOptions) (bool, error)

IsCondGranted evaluates the compiled condition tree against an object var map.

func (*Program) RenderSQL

func (p *Program) RenderSQL(bindings Bindings, opts RenderOptions) (Statement, error)

RenderSQL converts the program into a dialect-specific SQL fragment.

SQL rendering is one built-in renderer for the compiled IR. Non-SQL backends should build on Schema, ConditionTree, and the Walk* helpers instead of SQL renderer internals.

func (*Program) Schema

func (p *Program) Schema() Schema

Schema returns the schema bound when the program was compiled.

Together with ConditionTree and the Walk* helpers, this is the supported extension surface for downstream renderers, analyzers, and static checks.

type RenderOptions

type RenderOptions struct {
	Dialect           DialectName
	PlaceholderOffset int
	// TableAliases maps schema column table names to SQL qualifiers (usually aliases).
	//
	// This is useful when the schema was defined against a concrete table name but
	// the actual query uses a table alias:
	//
	//   schema column: {Table: "project", Name: "id"}
	//   query: FROM project p
	//   opts: TableAliases{"project": "p"} -> renders "p.id"
	//
	// A mapped empty string disables qualification for that table.
	TableAliases map[string]string
	// OmitTableQualifier disables table qualification for all columns, rendering
	// "id" instead of "t.id".
	//
	// This is useful when composing fragments into queries that use different
	// aliases (or no alias).
	OmitTableQualifier bool
}

RenderOptions configure SQL rendering.

type SQLPredicate

type SQLPredicate struct {
	SQL  DialectSQL
	Eval SQLPredicateEval
}

SQLPredicate defines a custom predicate which renders to dialect-specific SQL.

type SQLPredicateCondition

type SQLPredicateCondition struct {
	Name string
	SQL  DialectSQL
	Args []ValueExpr
	Eval SQLPredicateEval
}

SQLPredicateCondition represents a custom predicate rendered as SQL.

Instances are produced by `sql("<name>")` or `sql("<name>", [...])`. See SQLPredicate / WithSQLPredicate for registration.

type SQLPredicateEval

type SQLPredicateEval func(schema Schema, vars map[string]any, args []any, opts EvalOptions) (bool, error)

SQLPredicateEval evaluates a custom predicate in-memory.

The args slice contains resolved argument values (literals / param values). vars contains the full evaluation var map (schema fields and params).

Returning an error will fail evaluation.

type Schema

type Schema struct {
	Name       string
	Fields     map[string]*Field
	EnvOptions []cel.EnvOption
}

Schema collects CEL environment options and field metadata.

func SchemaFromStruct

func SchemaFromStruct(name, table string, model any) (Schema, error)

SchemaFromStruct builds a Schema from a Go struct type using reflection.

It is intended as a convenience helper to reduce boilerplate when the filter schema matches a DB model struct.

Supported Go field types:

  • string / *string -> FieldTypeString
  • bool / *bool -> FieldTypeBool
  • int/uint variants -> FieldTypeInt
  • time.Time / *time.Time -> FieldTypeTimestamp (represented as unix seconds in CEL)

Field name resolution precedence:

  1. `filter` tag (first segment, json-style)
  2. `json` tag
  3. `db` tag
  4. snake_case of Go field name

Column name resolution precedence:

  1. `filter` tag option `column=...`
  2. `db` tag
  3. `gorm` tag option `column:...`
  4. resolved field name

The `filter` tag supports:

  • "-" to skip the field
  • "contains" to enable <field>.contains(x)
  • "kind=..." to set FieldKind (scalar/json_bool/json_list/virtual_alias)
  • "json=..." to set JSONPath (dot or slash separated)
  • "alias=..." / "alias_for=..." to set AliasFor for virtual aliases
  • "ops=..." to set AllowedComparisonOps (pipe separated; eq|neq|lt|lte|gt|gte)

Returned EnvOptions only include CEL variables for schema fields; you can append extra variables (bindings) as needed.

func (Schema) Field

func (s Schema) Field(name string) (*Field, bool)

Field returns the field metadata if present.

func (Schema) ResolveAlias

func (s Schema) ResolveAlias(name string) (*Field, bool)

ResolveAlias resolves a virtual alias to its target field.

type StartsWithCondition

type StartsWithCondition struct {
	Field string
	Value ValueExpr
}

StartsWithCondition models the <field>.startsWith(<value>) call.

type StartsWithPredicate

type StartsWithPredicate struct {
	Prefix ValueExpr
}

StartsWithPredicate represents t.startsWith(prefix).

type Statement

type Statement struct {
	SQL  string
	Args []any
	// NamedArgs is populated when rendering with DialectPostgresNamedArgs.
	//
	// It is intended to be passed to pgx as `pgx.NamedArgs(stmt.NamedArgs)`:
	// `conn.Query(ctx, "SELECT ... WHERE "+stmt.SQL, pgx.NamedArgs(stmt.NamedArgs))`
	NamedArgs Bindings
}

Statement contains the rendered SQL fragment and its args.

func RenderCondition

func RenderCondition(schema Schema, cond Condition, bindings Bindings, opts RenderOptions) (Statement, error)

RenderCondition renders a pre-built condition tree into a SQL fragment.

This is useful when you need to compose multiple compiled filters together (e.g. OR across roles) before rendering once.

type ValueExpr

type ValueExpr interface {
	// contains filtered or unexported methods
}

ValueExpr models scalar expressions whose result feeds a comparison.

Jump to

Keyboard shortcuts

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