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 ¶
- Variables
- func EvaluateCondition(schema Schema, cond Condition, vars map[string]any, opts EvalOptions) (bool, error)
- func WalkCondition(cond Condition, fn func(Condition) error) error
- func WalkPredicateExpr(expr PredicateExpr, fn func(PredicateExpr) error) error
- func WalkValueExpr(expr ValueExpr, fn func(ValueExpr) error) error
- type Bindings
- type Column
- type ComparisonCondition
- type ComparisonOperator
- type CompileHook
- type ComprehensionKind
- type Condition
- type ConstantCondition
- type ContainsCondition
- type ContainsPredicate
- type DialectName
- type DialectSQL
- type ElementInCondition
- type EndsWithCondition
- type EndsWithPredicate
- type Engine
- type EngineOption
- type EvalOptions
- type Field
- type FieldKind
- type FieldPredicateCondition
- type FieldRef
- type FieldType
- type FunctionValue
- type InCondition
- type ListComprehensionCondition
- type LiteralValue
- type LogicalCondition
- type LogicalOperator
- type NotCondition
- type ParamRef
- type PredicateExpr
- type Program
- type RenderOptions
- type SQLPredicate
- type SQLPredicateCondition
- type SQLPredicateEval
- type Schema
- type StartsWithCondition
- type StartsWithPredicate
- type Statement
- type ValueExpr
Constants ¶
This section is empty.
Variables ¶
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.
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 ¶
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.
Types ¶
type Bindings ¶
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 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.
type ConstantCondition ¶
type ConstantCondition struct {
Value bool
}
ConstantCondition captures a literal boolean outcome.
type ContainsCondition ¶
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 ¶
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 ¶
ElementInCondition represents the CEL syntax `"value" in field`.
This is primarily used for JSON list membership checks.
type EndsWithCondition ¶
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) 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 ¶
ExtraFilterCEL returns the Engine's configured extra CEL filter expression.
When unset, it returns an empty string.
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 FieldPredicateCondition ¶
type FieldPredicateCondition struct {
Field string
}
FieldPredicateCondition asserts that a boolean field evaluates to true.
type FunctionValue ¶
FunctionValue captures simple function calls like size(tags).
type InCondition ¶
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 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 ¶
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 ¶
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 ¶
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.
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 ¶
Schema collects CEL environment options and field metadata.
func SchemaFromStruct ¶
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:
- `filter` tag (first segment, json-style)
- `json` tag
- `db` tag
- snake_case of Go field name
Column name resolution precedence:
- `filter` tag option `column=...`
- `db` tag
- `gorm` tag option `column:...`
- 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.
type StartsWithCondition ¶
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.