Skip to content

fix(mock): exclude null field values from != queries like Firestore - #118

Merged
fwal merged 2 commits into
mainfrom
detail/bug-fix/fix-mock-exclude-null-field-values-from-queries-li-681072
Sep 19, 2026
Merged

fwal merged 2 commits into
mainfrom
detail/bug-fix/fix-mock-exclude-null-field-values-from-queries-li-681072

Conversation

@detail-app

@detail-app detail-app Bot commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

Detail bug report: View on Detail

Closes #99

Bug

The mock's != query operator in matchesWhere included documents whose field value was explicitly null, whereas real Firestore excludes them. The branch only guarded against missing fields (value !== undefined), so where(field, '!=', V) returned a strict superset of production whenever a field was null. This is a real, reachable shape: Firestore.Optional/Firestore.OptionalNull encode Option.none() as a literal null field on write, so any != query over such a field diverged between the mock and Firestore. A test asserting on the result set (a length, or "all results have a present status") could pass against the mock and fail in production (or vice-versa).

Fix

packages/mock/src/lib/firestore/query-filter.ts — the != branch now excludes both null and undefined field values, matching Firestore's documented semantics ("null field values do not match != clauses, because x != null evaluates to undefined"):

case '!=':
  if (value === null || value === undefined) return false;
  return !equals(value, where.value);

The adjacent == branch is unchanged — it already handles null correctly (equals(null, nonNull) is false, equals(null, null) is true). Also updated packages/mock/README.md to drop != from the list of "simplified" null semantics (only not-in remains listed; its analogous null gap is out of scope for this change).

Note: the bug report suggested a where.value === null guard so != null matches no documents. Emulator cross-validation disproved this — real Firestore returns the present, non-null-field documents for != null, not the empty set — so that guard is intentionally omitted (see Testing).

Testing

  • Unit tests (query-filter.spec.ts): added a fixture mixing present, explicit-null, and missing status values; the bug case where('status','!=','active') now returns only the non-null non-matching doc, plus regression guards for == null (includes explicit-null) and == 'active' (excludes null/missing). The existing all-non-null != spec still returns ['1','4'] (no regression).
  • E2e (layer.spec.ts): through Firestore.makeRepository with an Firestore.Optional(Schema.String) field, where('status','!=','active') returns ['B'] (not ['B','C']); the Option.none() doc round-trips as Option.none(), proving the store holds an explicit null field.
  • Bug-catching check: reverting the one-line fix makes the new unit test fail with Expected ['b'] Received ['b','c']; restoring it passes.
  • Full mock suite, typecheck, lint, and build all pass.
  • End-to-end against the real backend: ran the scenarios against the Firebase Firestore emulator via a temporary Admin-layer spec (not committed). where('status','!=','active') returned ['B'] on Firestore, matching the mock. It also confirmed where('status','!=',null) returns the non-null-field documents ['A','B'] (not []), which is why the where.value === null guard was not added.

Automatic Fixes PRs can be configured here.

Firestore's `!=` operator excludes documents where the filtered field is
`null` (or missing): a null field never matches `!=`, because `x != null`
is undefined. The mock's `!=` branch only guarded against missing fields
(`value !== undefined`), so a document whose field was explicitly `null`
— the exact shape written by `Firestore.Optional`/`OptionalNull` for
`Option.none()` — wrongly matched any `!=` clause. The mock thus returned
a strict superset of production for `!=` queries over such fields.

Exclude null (and missing) field values from the `!=` branch, matching
Firestore. Also drop the README note listing `!=` null semantics as
simplified.

Closes #99
@detail-app
detail-app Bot requested a review from fwal as a code owner September 19, 2026 03:40
@github-actions github-actions Bot added 📖 docs Improvements or additions to documentation 🐛 fix Something is broken or doesn't work properly 📦 mock labels Sep 19, 2026
@greptile-apps

greptile-apps Bot commented Sep 19, 2026

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

The PR appears safe to merge; the previous documentation concern is resolved and no actionable new defects remain.

Summary

This PR aligns the mock Firestore != operator with Firestore by excluding explicit null and missing field values.

  • Updates the query predicate while preserving != null behavior for present, non-null values.
  • Adds focused predicate and repository-level regression coverage.
  • Updates the mock limitations documentation.
  • Corrects the prior misleading emulator-test reference by describing the validation as manual.

Reviews (2) · Last reviewed commit: "fix(mock): correct misleading emulator t..."

Comment thread packages/mock/src/lib/firestore/query-filter.spec.ts Outdated
@fwal fwal added this to the 1.0 milestone Sep 19, 2026
@fwal
fwal merged commit d3b5820 into main Sep 19, 2026
6 checks passed
@fwal
fwal deleted the detail/bug-fix/fix-mock-exclude-null-field-values-from-queries-li-681072 branch September 19, 2026 14:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

📖 docs Improvements or additions to documentation 🐛 fix Something is broken or doesn't work properly 📦 mock

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Detail Bug] Mock Firestore != queries incorrectly include documents with explicit null field values

1 participant