Skip to main content
Related: Query DSL, Relation, Debugging
Instrumentation: search_engine.compile is emitted by the compiler. See Debugging.

Compiled Params boundary

  • Public output type: SearchEngine::CompiledParams — immutable, read-only wrapper around compiled Typesense params.
  • Determinism: to_h returns a symbol-keyed, lexicographically ordered Hash; to_json is stable across runs.
  • Usage: callers may treat it like a Hash for read methods ([], key?, keys, each) or call to_h.
  • Construction: internal to the relation/compiler; user code does not instantiate it directly.
The compiler turns a Predicate AST under SearchEngine::AST into a deterministic Typesense filter_by string. It is pure (no I/O), safe (centralized quoting/escaping), and consistent with the where DSL.

Overview

  • Deterministic: same AST → same string; no globals.
  • Safe quoting: uses SearchEngine::Filters::Sanitizer for all values.
  • Parentheses & precedence: explicit, predictable rules (And > Or).
  • Escape hatch: AST::Raw is passed through as-is.

Node mapping

  • Matches / Prefix: Typesense filter_by does not support these forms; compilation raises UnsupportedNode. Use AST::Raw for adapter-specific fragments if needed.

Quoting & types

Values are rendered via Filters::Sanitizer.quote:
  • String: double-quoted, with minimal escaping for \ and ".
  • Boolean: true/false.
  • Nil: null.
  • Numeric: as-is (epoch seconds recommended for :time / :datetime).
  • Time/Date/DateTime: ISO8601 string (quoted). Upstream parsing coerces Date/DateTime to Time.utc. When the field type is numeric (:time/:datetime), prefer passing epoch seconds.
  • Array: one-level flatten; each element quoted; wrapped as [a, b].

Precedence & parentheses

  • Precedence: And = 20, Or = 10. Leaves bind tighter.
  • Group always inserts parentheses.
  • Parentheses are added when a child has lower precedence than its parent.
  • Whitespace: single spaces around && and ||.

Examples

Integration

  • Relation#to_typesense_params prefers compiling ast when present, falling back to legacy string filters for backward compatibility.
  • Raw fragments are preserved through the pipeline.
  • When joins are applied, joined fields render as assoc.field</code>in<code>filterby</code>andas<code>assoc.field</code> in <code>filter_by</code> and as <code>assoc.field:dir in sort_by. Nested include_fields compile to $assoc(field1,field2,…) segments emitted before base fields. The final include_fields reflects precedence: effective include set = include − exclude (per path); exclude always wins. Empty groups are omitted.
  • Curation state maps to body params: pinned_hits, hidden_hits, curation_tags, filter_curated_hits (omitted when empty/nil). See Curation.

Example with joins

The :_join section is an internal context map for downstream components and may be removed by the HTTP layer before sending the request. See Joins for details.
See also: DX for Relation#to_params_json — it uses SearchEngine::CompiledParams to ensure stable ordering. See also: Relation · Query DSL · Joins

Troubleshooting

  • Unsupported node: Use AST::Raw for adapter‑specific fragments not supported by filter_by.
  • Unexpected quoting: All quoting is centralized in the sanitizer; ensure values are passed as plain Ruby objects.
  • Complex precedence: Wrap with AST.group to force explicit parentheses.
Backlinks: README, Query DSL