Skip to main content
Related: Observability, Troubleshooting → Presets

Overview

Presets are server-side bundles of query options that you can attach to a relation to enforce consistent filters, sorts, or selections. They provide a global config (optional namespace and enablement), per‑collection defaults, and a per‑relation preset(name, mode:) DSL.
  • Why: enforce consistent defaults, reuse across surfaces, and keep chains concise.
  • Where: global config under SearchEngine.config.presets; model-level default_preset; relation-level Relation#preset.

Config & Default preset

Presets are namespaced when enabled. The effective name is computed as ”#_# when both enabled and namespace are set; otherwise the bare token is used.
  • Global config: enabled, namespace, and locked_domains (used by :lock mode)
  • Model default: declare default_preset :token on a SearchEngine::Base subclass
  • Reader: YourModel.default_preset_name returns the effective name (or nil if none)
Notes:
  • Namespacing is ignored when enabled is false; tokens remain usable as declared.
  • locked_domains is normalized to Symbols and used by the compiler to prune keys in :lock mode.

Relation DSL

Apply a preset with copy‑on‑write semantics, validate inputs, and keep chaining ergonomics:
  • Relation#preset(name, mode: :merge) validates the name and mode
  • Readers: rel.preset_name and rel.preset_mode (defaults to :merge)
  • inspect/explain show the preset and, for :lock, any dropped keys
  • Presets affect the compiler stage only; no global config is mutated

Strategies (:merge, :only, :lock)

  • merge: Send preset and all compiled params. When Typesense sees overlapping knobs, the later param wins; here the chain wins. No conflicts are recorded.
  • only: Keep only essentials from the chain (q, page, per_page) and send the preset. Use for strict server‑defined queries with local pagination.
  • lock: Drop chain keys that belong to SearchEngine.config.presets.locked_domains (default: filter_by, sort_by, include_fields, exclude_fields), record dropped keys, and include them in explain.

Mermaid — Strategy flow

Compiler mapping & pruning

The compiler injects preset: <effective_name> into the params and prunes keys according to the chosen strategy.
  • only: keep q, page, per_page; drop the rest
  • lock: drop keys in SearchEngine.config.presets.locked_domains and record them
  • merge: no pruning
Compact mapping:

Mermaid — State → params mapping

Example (reused):

Conflicts

Conflicts are detected only in mode: :lock and occur when a compiled chain key belongs to SearchEngine.config.presets.locked_domains. Such keys are dropped from the final params and recorded.
  • Accessor: Relation#preset_conflicts[{ key: :filter_by, reason: :locked_by_preset }, ...] (deterministic, frozen)
  • Explain: lists the effective preset and a line per dropped key with a humanized reason
  • Inspect: appends a compact token: preset=prod_brand_curated(mode=lock; conflicts=filter_by,sort_by)
  • Redaction: keys only; no raw values
Example snippet:

Mermaid — Conflict resolution

Multi‑search

Presets are applied per search entry. Each searches[] item carries its own preset and respects that relation’s mode.
  • :merge: pass through compiled params (includes preset)
  • :only: keep only collection, q, page, per_page, and preset
  • :lock: drop keys listed in SearchEngine.config.presets.locked_domains
Example (reused):

Observability & troubleshooting

Events (keys and counts only; values redacted elsewhere):
  • search_engine.preset.apply — emitted once per compile when a preset is present
    • Payload: preset_name, mode, locked_domains, pruned_keys
  • search_engine.preset.conflict — emitted once per compile in :lock mode when keys were dropped
    • Payload: keys, count, mode, preset_name
Logging subscriber (compact):
  • Text: appends pz=<name>|m=<mode>|pk=<count>|ld=<count>; when pruned_keys.size <= 3, includes pk=[k1,k2]
  • JSON: adds preset_name, preset_mode, preset_pruned_keys_count, preset_locked_domains_count, and optionally preset_pruned_keys

FAQ

  • How does namespacing interact with enabled: false? Namespacing is ignored when disabled; tokens are used as declared.
  • Can I customize locked_domains? Yes: SearchEngine.config.presets.locked_domains = %i[filter_by sort_by include_fields exclude_fields] (Array/Set/single value accepted; normalized to Symbols).
  • What happens if a preset is missing on the server? Typesense returns an error at request time; handle it like any search error. The client surfaces it via SearchEngine::Errors.
  • How do presets interact with field selection? In :lock, selection keys (include_fields, exclude_fields) belong to locked_domains by default and are dropped from the chain; the preset governs them.
  • How does multi‑search resolve conflicting modes across entries? Modes are per entry. Each relation’s preset_mode is applied independently when compiling searches[].
Backlinks: Index · Relation · Compiler · Multi‑search · Observability