Skip to content

fix(search-typesense)!: compile a where clause that can match nothing to a term matching nothing - #753

Merged
ddeboer merged 1 commit into
mainfrom
worktree-issue-752-empty-clause-widens
Aug 20, 2026
Merged

fix(search-typesense)!: compile a where clause that can match nothing to a term matching nothing#753
ddeboer merged 1 commit into
mainfrom
worktree-issue-752-empty-clause-widens

Conversation

@ddeboer

@ddeboer ddeboer commented Aug 20, 2026

Copy link
Copy Markdown
Member

A where clause whose every criterion compiles to nothing was left out of filter_by – and a
conjunct missing from a conjunction constrains nothing. So a clause the compiler read as false
was emitted as true: one misspelled field name turned a filtered search into the whole
collection.

where: [
  { or: [{ field: 'status', in: ['valid'] }] },
  { or: [{ field: 'nonexistent', in: ['x'] }] },
]
// filter_by: "status:[`valid`]"   ← the false conjunct is simply gone

The term for “nothing”

A clause with criteria but no terms now compiles to id:=[] – an empty identity membership,
“the document is one of no documents”. Not a sentinel: it is the same reading isUnsatisfiable
gives an empty id membership in the IR, and the one shape a filter language can spell when it
has no keyword for false.

It had to be a term the engine applies rather than ignores, so I checked the candidates against
a real Typesense 30.2 instance: id:=``` is rejected outright (“Filter value cannot be empty”), while id:=[]returns 0 against a baseline of 2. A new integration test insearch-engine.test.ts`
pins that down – the fix is worthless if the engine ever starts ignoring the term.

A clause carrying no criteria at all ({ or: [] }) states nothing rather than stating false,
so it stays the vacuous no-op it reads as. That distinction is now the one thing compileFilter
decides, and its JSDoc says so.

onIgnoredFilter keeps firing for both kinds, since neither compiled as the caller wrote it –
its doc now describes the two cases instead of implying every reported clause was skipped.

Reachability

Not reachable through search(): assertValidQuery rejects an unknown field, a non-filterable
one and an operator mismatch before compiling, and isUnsatisfiable answers the empty id
membership without a round-trip. The exposure was, and the fix is for, direct callers of the
exported buildSearchParams.

Fix #752

… to a term matching nothing

A clause whose every criterion was false compiled to no term, and a clause
with no term was left out of filter_by. An absent conjunct constrains
nothing, so false was compiled as true: a single misspelled field name in
where turned a filtered search into the whole collection.

- a clause with criteria but no terms now compiles to id:=[] – an empty
  identity membership, the same reading isUnsatisfiable gives one in the IR,
  and a term Typesense applies rather than ignores
- a clause carrying no criteria at all still states nothing, not false, so it
  stays the vacuous no-op it reads as
- onIgnoredFilter keeps reporting both, since neither compiles as written

Not reachable through search(): assertValidQuery rejects an unknown field,
a non-filterable one and an operator mismatch first, and isUnsatisfiable
answers the empty id membership without a round-trip. It is reachable for
every direct caller of buildSearchParams.

BREAKING CHANGE: buildSearchParams compiles a where clause it cannot compile
to “id:=[]” instead of omitting it, so a query that used to come back with
every document now comes back empty. onIgnoredFilter still fires for it.
@ddeboer
ddeboer force-pushed the worktree-issue-752-empty-clause-widens branch from 73e4fc7 to 936a5b5 Compare August 20, 2026 15:36
@ddeboer
ddeboer merged commit 3a9959b into main Aug 20, 2026
4 checks passed
@ddeboer
ddeboer deleted the worktree-issue-752-empty-clause-widens branch August 20, 2026 17:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A where clause that compiles to nothing is dropped, so a false criterion widens the search

1 participant