Conversation
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
|
fwal
approved these changes
Sep 19, 2026
fwal
deleted the
detail/bug-fix/fix-mock-exclude-null-field-values-from-queries-li-681072
branch
September 19, 2026 14:08
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Detail bug report: View on Detail
Closes #99
Bug
The mock's
!=query operator inmatchesWhereincluded documents whose field value was explicitlynull, whereas real Firestore excludes them. The branch only guarded against missing fields (value !== undefined), sowhere(field, '!=', V)returned a strict superset of production whenever a field wasnull. This is a real, reachable shape:Firestore.Optional/Firestore.OptionalNullencodeOption.none()as a literalnullfield 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 bothnullandundefinedfield values, matching Firestore's documented semantics ("null field values do not match!=clauses, becausex != nullevaluates to undefined"):The adjacent
==branch is unchanged — it already handles null correctly (equals(null, nonNull)is false,equals(null, null)is true). Also updatedpackages/mock/README.mdto drop!=from the list of "simplified" null semantics (onlynot-inremains listed; its analogous null gap is out of scope for this change).Note: the bug report suggested a
where.value === nullguard so!= nullmatches 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
query-filter.spec.ts): added a fixture mixing present, explicit-null, and missingstatusvalues; the bug casewhere('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).layer.spec.ts): throughFirestore.makeRepositorywith anFirestore.Optional(Schema.String)field,where('status','!=','active')returns['B'](not['B','C']); theOption.none()doc round-trips asOption.none(), proving the store holds an explicitnullfield.Expected ['b'] Received ['b','c']; restoring it passes.where('status','!=','active')returned['B']on Firestore, matching the mock. It also confirmedwhere('status','!=',null)returns the non-null-field documents['A','B'](not[]), which is why thewhere.value === nullguard was not added.Automatic Fixes PRs can be configured here.