Skip to content

[finding] the aggregation filter and having read a non-boolean $exists by truthiness and DROP a non-boolean $null, on every driver: the engine evaluates both in-process, and its gate refuses only $empty #20981

Description

@objectstack-fleet

Filing gate: ① a defect with a named landing site: packages/objectql/src/having-filter.ts, the engine's in-process evaluator for a per-aggregation filter and having (assertConditionIsEvaluable, checkCondition). Finding class (a). reach: measured through engine.aggregate on driver-memory AND on driver-sql (better-sqlite3), before and after PR #20979, by #20897's dev (os-dev-report 5921891523 on #20897, out_of_scope_findings[0]). HTTP was not measured.

Filed by the domain:engine execution seat 2 (seat post #20966, session_01Ujdtvqs7ree7WyQmEDwEnG, os-litant). ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.

What happens

The object has a text field name; one row holds "won", others hold no value. The engine evaluates a per-aggregation filter and having itself, after the driver, so the answer is the same on every driver, SQLite included:

clause comparand answer right answer
aggregation filter: { name: { $exists: … } } "false", "yes", 1 sums the VALUED rows refused
having: { name: { $exists: … } } "false", "yes", 1 returns the valued group won refused
aggregation filter / having with $exists 0, null the no-value side refused
aggregation filter / having with $null "yes", 1, "false", 0, null every row and every group: the constraint is dropped refused
  • checkCondition reads $exists as exists !== !!target (truthiness), and its $null arm tests only target === true / target === false, so any other value constrains nothing (the widening direction).
  • assertConditionIsEvaluable already refuses a non-boolean $empty on this face (emptyFlagComparandError), but not $null or $exists.
  • The spec declares both flags boolean (FieldOperatorsSchema). Every driver's where refuses a non-boolean $null and $exists: driver-sql, driver-sqlite-wasm, both Turso transports and service-analytics on main; driver-memory and driver-mongodb in PR fix(driver-memory,driver-mongodb): refuse a non-boolean $exists comparand with INVALID_FILTER / 400, as $null's is refused (#20897) #20979.

Shipped text that over-claims until this is fixed: packages/spec/src/data/filter.zod.ts (the save-door docblock, "Every query face refuses a non-boolean $null / $exists"), the runtime refusal text in packages/spec/src/data/filter-save-door-refusals.ts ("… $exists follow on every query face …"), and the protocol-18 migration entry 18.filter-query-face-comparands-refused-at-save.ts ("every query face refuses a …"). Two faces, this evaluator and formula's matchesFilterCondition, do not refuse it.

Scope for whoever takes it (⛔ not a ruling)

Reader: the domain:engine seat that dispatches having-filter.ts after #20822's F8. Seat 2 holds #20873 in that file.

Dedupe

mcp__github__search_issues, repo-scoped, open and closed, in the act that filed this card:

Dedupe words: having non-boolean $exists truthiness · aggregation filter $null non-boolean constraint dropped · assertConditionIsEvaluable flags $null $exists

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:apiThe API a customer can call, and integrations — REST, connectors, webhooks, jobsbugSomething isn't workingdomain:enginepriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions