Skip to content

fix(mock): order NaN below -Infinity and exclude it from range and in filters - #127

Merged
fwal merged 2 commits into
mainfrom
detail/bug-fix/fix-mock-order-nan-below-infinity-and-exclude-it-f-bc9cad
Sep 21, 2026
Merged

fwal merged 2 commits into
mainfrom
detail/bug-fix/fix-mock-order-nan-below-infinity-and-exclude-it-f-bc9cad

Conversation

@detail-app

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

Copy link
Copy Markdown
Contributor

Detail bug report: View on Detail

Closes #108

Bug

compareNumbers in the mock (packages/mock/src/lib/firestore/value.ts) used a < b ? -1 : a > b ? 1 : 0. For NaN both NaN < x and NaN > x are false, so it returned 0 for every operand. Since equals is compare(a,b) === 0, a stored NaN field became equal to every number — matching any numeric ==, !=, <=, >=, and in [..] query, tying with every number in orderBy, dedup-ing every number in arrayUnion/arrayRemove, and skipping NaN↔number transitions in live-stream change detection. Firestore actually normalizes NaN, orders it below -Infinity (equal only to NaN), and excludes NaN field values from range and in filters.

Fix

  • value.tscompareNumbers special-cases NaN (equal only to NaN, ordered before every other number, below -Infinity). One change fixes every consumer of the primitive: equals, orderBy, arrayUnion/arrayRemove dedup, snapshotEquals stream change-detection, and Timestamp/GeoPoint sub-field ordering.
  • query-filter.ts — a stored NaN field value is excluded from range filters (<,<=,>,>=) and in, and always included in not-in. This matches the Firestore emulator's actual scan semantics and corrects the bug report's impact table, which assumed range/in filters follow the total order — they don't; only orderBy does. Without this, the report's suggested compareNumbers-only fix would still diverge from Firestore for <, <=, in, and not-in.

==/!= (via equals) and orderBy (via compare) need no extra cases.

Testing

  • Added regression tests for compare/equals NaN ordering, arrayUnion/arrayRemove dedup, query filters across all operators plus orderBy, and a live-stream NaN→number change-detection case. None existed before, so the bug was silent.
  • Unit tests, typecheck, lint, and build all pass.
  • End-to-end fidelity: started the Firestore emulator (installed a JRE; used the repo-local Firebase CLI), wrote docs with a NaN numeric field via firebase-admin, and ran the same 22 queries — every result set matched the mock, including NaN exclusion from range/in and first-ascending orderBy ordering.
  • Out of scope: Firestore rejects a NaN query operand (e.g. where v < NaN) with invalid-argument; the mock returns an empty/ordered result instead because it has no query-operand validation path today. Happy-path queries (non-NaN operands, the bug's scenario) are faithful.

Automatic Fixes PRs can be configured here.

@detail-app
detail-app Bot requested a review from fwal as a code owner September 19, 2026 03:42
@github-actions github-actions Bot added 🐛 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; no actionable correctness, security, or repository-rule violations remain.

Fix All in Claude CodeFindings

  1. P2 Mock semantics undocumented
Summary

This PR aligns the in-memory Firestore mock’s NaN behavior with Firestore.

  • Orders NaN below negative infinity while treating it as equal only to NaN.
  • Excludes stored NaN values from range and in filters and includes them in not-in.
  • Adds coverage for comparisons, queries, array sentinels, ordering, and reactive snapshot updates.
  • Documents the new semantics and the remaining NaN query-operand validation limitation.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[Stored Firestore value] --> B[NaN-aware comparator]
    B --> C[Equality and ordering]
    C --> D[orderBy]
    C --> E[arrayUnion / arrayRemove]
    C --> F[Snapshot change detection]
    A --> G[Query filter handling]
    G --> H[Range: exclude NaN]
    G --> I[in: exclude NaN]
    G --> J[not-in: include NaN]
Loading

Reviews (4) · Last reviewed commit: "docs(mock): document NaN field-value sem..."

Comment on lines +34 to 39
if (typeof value === 'number' && Number.isNaN(value)) {
return false;
}
const diff = compare(value, where.value);
switch (where.op) {
case '<':

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Mock semantics undocumented

This change adds special NaN behavior for range, in, and not-in filters, while the related comparator change also alters NaN equality and ordering. The repository guide requires changes to mock semantics to be documented in packages/mock/README.md. That requirement must be satisfied before merging, including the relevant query-validation limitations.

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 2945857.

@github-actions github-actions Bot added the 📖 docs Improvements or additions to documentation label Sep 19, 2026
@fwal fwal added this to the 1.0 milestone Sep 19, 2026
@detail-app
detail-app Bot force-pushed the detail/bug-fix/fix-mock-order-nan-below-infinity-and-exclude-it-f-bc9cad branch from 2945857 to 6ed4c50 Compare September 20, 2026 20:08
@fwal
fwal merged commit dd36482 into main Sep 21, 2026
6 checks passed
@fwal
fwal deleted the detail/bug-fix/fix-mock-order-nan-below-infinity-and-exclude-it-f-bc9cad branch September 21, 2026 06:33
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 treats NaN as equal to all numbers, breaking query filters and ordering

1 participant