Skip to content

test: failing tests for AND/OR queries mixing indexed and non-indexed conditions#1581

Closed
kevin-dp wants to merge 7 commits into
TanStack:mainfrom
kevin-dp:test/showcase-index-optimization-or-and-bugs
Closed

test: failing tests for AND/OR queries mixing indexed and non-indexed conditions#1581
kevin-dp wants to merge 7 commits into
TanStack:mainfrom
kevin-dp:test/showcase-index-optimization-or-and-bugs

Conversation

@kevin-dp

@kevin-dp kevin-dp commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds seven unit tests to collection-indexes.test.ts that assert the expected results of currentStateAsChanges for where clauses that the index optimizer currently gets wrong. All tests are written purely in terms of expected behaviour.

Mixing indexed and non-indexed conditions (e.g. length(name) > 6):

  1. OR — the result must be the union of rows matching either condition. Currently rows matched only by the non-indexed condition are missing.
  2. AND — every condition must be enforced. Currently rows failing the non-indexed condition are included.
  3. Compound range + condition on another (indexed) field — all conditions must be enforced. Currently only the range is applied.

Range boundary handling:
4. Strictest lower boundgte(age, 25) AND gt(age, 25) must reduce to age > 25 regardless of argument order. Currently the inclusive bound wins.
5. Strictest upper boundlte(age, 30) AND lt(age, 30) must reduce to age < 30. Currently the inclusive bound wins.
6. Date bounds at the same value — distinct Date instances representing the same time must be treated as equal when picking the strictest bound. (Also exercises one-sided compound ranges, which currently return an empty result.)
7. Strict comparisons on date fieldsgt(createdAt, date) must exclude the boundary row. Currently the BTree index includes it because it compares the normalized indexed value against the raw Date.

⚠️ These tests fail on main by design — they pin down the expected behaviour. The follow-up PR #1582 provides the fixes that make them pass.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
    • Added new coverage to ensure strict boundary behavior for date range queries (values equal to the boundary are excluded).
    • Expanded assertions for complex query optimization, validating correct and/or behavior when mixing indexed and computed predicates, including “strictest bound wins” logic.
    • Added edge-case and parity tests for full-scan consistency, including handling of undefined values and NaN semantics in equality and IN queries.

…d non-indexed conditions

These tests assert the expected results of currentStateAsChanges for
AND/OR where clauses that combine conditions on indexed fields with
conditions that cannot be served by an index. They currently fail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds tests for strict date gt behavior, mixed indexed/computed boolean query semantics, overlapping range-bound handling, undefined-value edge cases, and string and NaN comparison parity.

Changes

Complex Query Optimization & Date-bound Tests

Layer / File(s) Summary
Date gt strictness on createdAt
packages/db/tests/collection-indexes.test.ts
Verifies gt on a createdAt date field is strict and excludes rows equal to the boundary timestamp.
Mixed indexed vs computed predicate boolean ops
packages/db/tests/collection-indexes.test.ts
or(...) returns the union when one branch is index-backed and the other is a non-indexed computed predicate; and(...) enforces conjunction when mixing indexed and computed predicates.
String ordering and NaN equality
packages/db/tests/collection-indexes.test.ts
Confirms string range results match JavaScript relational ordering, and eq(NaN) plus inArray(..., [NaN, ...]) follow JavaScript equality behavior.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 I hopped through ranges, bright and neat,
Dates stood firm on boundaryీట్,
And/or danced in tidy rows,
Strings and NaNs in testy prose,
All matched the rules the rabbit knows.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description summarizes the change but doesn't follow the repository template or include the checklist and release impact sections. Rewrite the PR description using the template: add ## 🎯 Changes, ## ✅ Checklist with test confirmation, and ## 🚀 Release Impact with the correct choice.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main change: tests for AND/OR queries mixing indexed and non-indexed conditions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jun 10, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-db

npm i https://pkg.pr.new/@tanstack/angular-db@1581

@tanstack/browser-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/browser-db-sqlite-persistence@1581

@tanstack/capacitor-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/capacitor-db-sqlite-persistence@1581

@tanstack/cloudflare-durable-objects-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/cloudflare-durable-objects-db-sqlite-persistence@1581

@tanstack/db

npm i https://pkg.pr.new/@tanstack/db@1581

@tanstack/db-ivm

npm i https://pkg.pr.new/@tanstack/db-ivm@1581

@tanstack/db-sqlite-persistence-core

npm i https://pkg.pr.new/@tanstack/db-sqlite-persistence-core@1581

@tanstack/electric-db-collection

npm i https://pkg.pr.new/@tanstack/electric-db-collection@1581

@tanstack/electron-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/electron-db-sqlite-persistence@1581

@tanstack/expo-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/expo-db-sqlite-persistence@1581

@tanstack/node-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/node-db-sqlite-persistence@1581

@tanstack/offline-transactions

npm i https://pkg.pr.new/@tanstack/offline-transactions@1581

@tanstack/powersync-db-collection

npm i https://pkg.pr.new/@tanstack/powersync-db-collection@1581

@tanstack/query-db-collection

npm i https://pkg.pr.new/@tanstack/query-db-collection@1581

@tanstack/react-db

npm i https://pkg.pr.new/@tanstack/react-db@1581

@tanstack/react-native-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/react-native-db-sqlite-persistence@1581

@tanstack/rxdb-db-collection

npm i https://pkg.pr.new/@tanstack/rxdb-db-collection@1581

@tanstack/solid-db

npm i https://pkg.pr.new/@tanstack/solid-db@1581

@tanstack/svelte-db

npm i https://pkg.pr.new/@tanstack/svelte-db@1581

@tanstack/tauri-db-sqlite-persistence

npm i https://pkg.pr.new/@tanstack/tauri-db-sqlite-persistence@1581

@tanstack/trailbase-db-collection

npm i https://pkg.pr.new/@tanstack/trailbase-db-collection@1581

@tanstack/vue-db

npm i https://pkg.pr.new/@tanstack/vue-db@1581

commit: 13f7ead

kevin-dp and others added 4 commits June 10, 2026 14:31
Adds expected-behaviour tests for range conditions:
- compound ranges sharing a boundary value must apply the strictest
  bound regardless of argument order, including for date values
- one-sided compound ranges must return the matching rows
- strict comparisons (gt) on date fields must exclude the boundary row

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A compound range condition where one bound is undefined (e.g.
gt(score, undefined) AND lt(score, 90)) must match nothing, since a
comparison against undefined is never true. The index-optimized path
must agree with a full scan. This test currently fails.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ries

A comparison against null/undefined is never true, but BTree indexes
store and return rows with nullish indexed values (they sort as the
smallest key). These tests assert that the index-optimized snapshot
matches a full predicate scan for:
- eq against undefined
- IN with an undefined member
- a range comparison over a field that has rows with undefined values
- an upper-bounded compound range over such a field

They currently fail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two more cases where an index-optimized snapshot must match a full
predicate scan:
- a string range predicate (e.g. name > 'z') must return a row whose
  value satisfies the JS relational comparison ('ö' > 'z'), even though
  a locale-collated index orders that value differently
- eq and IN against NaN must not match a NaN-valued row, since NaN is
  never equal to itself

They currently fail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/db/tests/collection-indexes.test.ts (1)

1377-1394: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Consider extracting the repeated collection-setup boilerplate into a helper.

The createCollection({ getKey, startSync, autoIndex, defaultIndexType, sync: { sync: ({begin,write,commit,markReady}) => {...} } }) block is duplicated near-identically across these three tests (and appears to follow the same shape used earlier in the file). A small helper such as createSeededCollection(rows) taking the seed rows would cut the noise and keep each test focused on its predicate/assertion.

As per coding guidelines: "Extract common logic into utility functions when identical or near-identical code blocks appear in multiple places."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/db/tests/collection-indexes.test.ts` around lines 1377 - 1394, The
test setup for creating seeded collections is duplicated across multiple cases,
so extract the repeated
createCollection/getKey/startSync/autoIndex/defaultIndexType/sync boilerplate
into a helper. Add a small helper near the existing collection-index tests, such
as a seeded collection factory that accepts the row seed data and performs the
begin/write/commit/markReady sequence, then update the affected tests (including
the stringCollection setup) to use it so each test only states its specific rows
and assertion.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/db/tests/collection-indexes.test.ts`:
- Around line 1377-1394: The test setup for creating seeded collections is
duplicated across multiple cases, so extract the repeated
createCollection/getKey/startSync/autoIndex/defaultIndexType/sync boilerplate
into a helper. Add a small helper near the existing collection-index tests, such
as a seeded collection factory that accepts the row seed data and performs the
begin/write/commit/markReady sequence, then update the affected tests (including
the stringCollection setup) to use it so each test only states its specific rows
and assertion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5acff077-b247-41ef-aa93-9ec98cfb0ee9

📥 Commits

Reviewing files that changed from the base of the PR and between 029e759 and fc07196.

📒 Files selected for processing (1)
  • packages/db/tests/collection-indexes.test.ts

kevin-dp and others added 2 commits June 25, 2026 10:16
… domains

Three more cases where an index-optimized range query must match a
full predicate scan:
- an array-valued field (the evaluator compares with standard relational
  operators, which differ from the index's recursive array ordering)
- a field indexed with a custom comparator
- a numeric field that also contains a NaN value

They currently fail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
NaN and invalid Dates have no natural order. They should still get a
consistent, well-defined position (alongside nulls) so that:
- the comparator produces a stable total order;
- ordering a collection by such a field is deterministic;
- a range query on a field that contains such a value can still be
  served by the index rather than falling back to a full scan.

These tests currently fail.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kevin-dp

Copy link
Copy Markdown
Contributor Author

Superseded by #1582.

These failing tests were split out purely to show the red → green progression. They're now included directly in #1582 (passing) alongside the fixes that make them pass, plus the PostgreSQL NaN-semantics work that superseded #1617. #1582 is retargeted to main and is self-contained, so this PR is no longer needed.

Closing in favor of #1582.

@kevin-dp kevin-dp closed this Jun 26, 2026
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.

1 participant