internal/filter/README.md
This package houses the memo-only filter engine that turns standard CEL syntax into SQL fragments for the subset of expressions supported by the memo schema. The engine follows a three phase pipeline inspired by systems such as Calcite or Prisma:
cel-go and validated against
the memo-specific environment declared in schema.go. Only fields that
exist in the schema can surface in the filter, and non-standard legacy
coercions are rejected.ir.go. The IR is a dialect-agnostic tree of
conditions (logical operators, comparisons, list membership, etc.). This
step enforces schema rules (e.g. operator compatibility, type checks).render.go walks the IR and produces a SQL
fragment plus placeholder arguments tailored to a target dialect
(sqlite, mysql, or postgres). Dialect differences such as JSON access,
boolean semantics, placeholders, and LIKE vs ILIKE are encapsulated in
renderer helpers.The entry point is filter.DefaultEngine() from engine.go. It lazily constructs
an Engine configured with the memo schema and exposes:
engine, _ := filter.DefaultEngine()
stmt, _ := engine.CompileToStatement(ctx, `has_task_list && visibility == "PUBLIC"`, filter.RenderOptions{
Dialect: filter.DialectPostgres,
})
// stmt.SQL -> "((memo.payload->'property'->>'hasTaskList')::boolean IS TRUE AND memo.visibility = $1)"
// stmt.Args -> ["PUBLIC"]
| File | Responsibility |
|---|---|
schema.go | Declares memo fields, their types, backing columns, CEL environment options |
ir.go | IR node definitions used across the pipeline |
parser.go | Converts CEL Expr into IR while applying schema validation |
render.go | Translates IR into SQL, handling dialect-specific behavior |
engine.go | Glue between the phases; exposes Compile, CompileToStatement, and DefaultEngine |
helpers.go | Convenience helpers for store integration (appending conditions) |
? is used for SQLite/MySQL, $n for Postgres. The renderer
tracks offsets to compose queries with pre-existing arguments.memo.payload. The renderer handles
JSON_EXTRACT/json_extract/->/->> variations and boolean coercion.tag in [...] and "tag" in tags become JSON array
predicates. SQLite uses LIKE patterns, MySQL uses JSON_CONTAINS, and
Postgres uses @>.has_task_list render as IS TRUE equality
checks, or comparisons against CAST('true' AS JSON) depending on the dialect.filter.DefaultEngine().CompileToStatement using the appropriate dialect enum.WHERE clause.The helpers.AppendConditions helper encapsulates steps 2–3 when a driver needs
to process an array of filters.