Skip to content

test(query-db-collection): cover query invalidation behavior#1655

Merged
KyleAMathews merged 4 commits into
mainfrom
query-invalidation-matrix
Jul 9, 2026
Merged

test(query-db-collection): cover query invalidation behavior#1655
KyleAMathews merged 4 commits into
mainfrom
query-invalidation-matrix

Conversation

@KyleAMathews

@KyleAMathews KyleAMathews commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

🎯 Changes

Adds a focused invalidation behavior matrix for @tanstack/query-db-collection, covering eager and on-demand collections across exact, prefix, overlapping, inactive, removed, and failed-refetch scenarios.

This is test/spec coverage only for the adapter boundary: TanStack Query remains the invalidation authority, while the collection adapter is verified to rematerialize or preserve DB rows appropriately when Query invalidation changes observer state.

Reviewer Guidance

Root Cause

Issue #344 and RFC #1643 call out that the adapter sits between TanStack Query's document-cache model and TanStack DB's normalized row store. Without explicit matrix coverage, it is easy to regress where responsibility lives: Query should own invalidation and matching semantics, while the adapter should react correctly to successful or failed observer results.

Approach

  • Add a dedicated invalidation behavior suite in packages/query-db-collection/tests/query.test.ts.
  • Drive all invalidation scenarios through queryClient.invalidateQueries.
  • Cover eager collections with exact and prefix invalidation.
  • Cover active on-demand collections through live queries, including exact invalidation, root-prefix invalidation, and overlapping subsets.
  • Characterize lifecycle/error behavior:
    • failed refetches keep existing materialized rows;
    • inactive cached Query entries do not rematerialize DB rows;
    • removed Query entries do not refetch after invalidation.
  • Add a changeset for @tanstack/query-db-collection.

No runtime adapter code changes were needed.

Key Invariants

  • TanStack Query remains the only invalidation/matching authority.
  • The adapter does not add a parallel invalidation API or duplicate Query's matching logic.
  • Successful invalidation refetches rematerialize rows.
  • Failed invalidation refetches preserve the last successful materialized rows and expose error state.
  • DB rows are not recreated merely because an inactive Query cache entry exists.

Non-goals

  • No new public invalidation API.
  • No lifecycle or lease-manager refactor.
  • No changes to Query matching behavior.
  • No broad persistence fixture expansion for retained/persisted invalidation.

Trade-offs

The tests keep setup mostly explicit rather than extracting shared helpers. That makes each matrix row easier to review as a standalone characterization, at the cost of some repetition.

Retained/persisted invalidation is intentionally noted but not expanded into a broader fixture here; the existing unit coverage focuses this PR on active, inactive, removed, overlapping, and failed-refetch behavior.

✅ Checklist

  • I have tested this code locally with pnpm test.

Verification run locally:

pnpm --filter @tanstack/query-db-collection test tests/query.test.ts -t "invalidation"
pnpm --filter @tanstack/query-db-collection test tests/query.test.ts

Both commands pass locally. The test output includes expected stderr from existing error-path tests and the new failed-refetch characterization.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Files changed

  • .changeset/query-invalidation-matrix.md — adds a patch changeset for the new query collection invalidation coverage.
  • packages/query-db-collection/tests/query.test.ts — adds the invalidation behavior matrix.

Refs #344
Refs #1643

Summary by CodeRabbit

  • Tests
    • Added broader coverage for query invalidation behavior, including exact and prefix invalidations.
    • Verified eager and on-demand collections refresh correctly, preserve shared rows, and handle failed refetches without losing existing data.
    • Confirmed inactive or removed queries do not trigger unexpected rematerialization.
  • Chores
    • Added a release note entry for the @tanstack/query-db-collection package.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a Changesets patch entry for @tanstack/query-db-collection and expands query.test.ts with invalidation coverage for eager and on-demand collections, overlapping subsets, failed refetch handling, and inactive or removed query cases.

Changes

Invalidation behavior tests

Layer / File(s) Summary
Changeset entry
.changeset/query-invalidation-matrix.md
Adds a patch changeset for @tanstack/query-db-collection documenting new invalidation test coverage.
Eager query invalidation tests
packages/query-db-collection/tests/query.test.ts
Adds tests verifying active eager queries rematerialize after exact and prefix invalidation.
On-demand invalidation and overlapping subset tests
packages/query-db-collection/tests/query.test.ts
Adds tests for on-demand subset rematerialization after exact and root-prefix invalidation, and verifies overlapping subsets retain shared rows when only one subset is invalidated.
Failure and negative-path invalidation tests
packages/query-db-collection/tests/query.test.ts
Adds tests confirming rows are retained on failed refetch, inactive cached rows are not rematerialized, and removed queries are not refetched after invalidation.

Estimated code review effort: 2 (Simple) | ~12 minutes

Possibly related issues

Suggested reviewers: kevin-dp

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title is concise and accurately summarizes the main change: added query invalidation behavior coverage.
Description check ✅ Passed The description follows the template and includes changes, testing, and release impact details with a generated changeset.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch query-invalidation-matrix

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 Jul 7, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-db

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

@tanstack/browser-db-sqlite-persistence

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

@tanstack/capacitor-db-sqlite-persistence

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

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

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

@tanstack/db

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

@tanstack/db-ivm

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

@tanstack/db-sqlite-persistence-core

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

@tanstack/electric-db-collection

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

@tanstack/electron-db-sqlite-persistence

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

@tanstack/expo-db-sqlite-persistence

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

@tanstack/node-db-sqlite-persistence

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

@tanstack/offline-transactions

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

@tanstack/powersync-db-collection

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

@tanstack/query-db-collection

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

@tanstack/react-db

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

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

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

@tanstack/rxdb-db-collection

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

@tanstack/solid-db

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

@tanstack/svelte-db

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

@tanstack/tauri-db-sqlite-persistence

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

@tanstack/trailbase-db-collection

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

@tanstack/vue-db

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

commit: 23ae479

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 125 kB

ℹ️ View Unchanged
Filename Size
packages/db/dist/esm/collection/change-events.js 1.43 kB
packages/db/dist/esm/collection/changes.js 1.38 kB
packages/db/dist/esm/collection/cleanup-queue.js 810 B
packages/db/dist/esm/collection/events.js 434 B
packages/db/dist/esm/collection/index.js 3.62 kB
packages/db/dist/esm/collection/indexes.js 1.99 kB
packages/db/dist/esm/collection/lifecycle.js 1.69 kB
packages/db/dist/esm/collection/mutations.js 2.47 kB
packages/db/dist/esm/collection/state.js 5.4 kB
packages/db/dist/esm/collection/subscription.js 3.74 kB
packages/db/dist/esm/collection/sync.js 2.88 kB
packages/db/dist/esm/collection/transaction-metadata.js 144 B
packages/db/dist/esm/deferred.js 207 B
packages/db/dist/esm/errors.js 5.1 kB
packages/db/dist/esm/event-emitter.js 748 B
packages/db/dist/esm/index.js 3.1 kB
packages/db/dist/esm/indexes/auto-index.js 829 B
packages/db/dist/esm/indexes/base-index.js 767 B
packages/db/dist/esm/indexes/basic-index.js 2.06 kB
packages/db/dist/esm/indexes/btree-index.js 2.19 kB
packages/db/dist/esm/indexes/index-registry.js 820 B
packages/db/dist/esm/indexes/reverse-index.js 557 B
packages/db/dist/esm/local-only.js 916 B
packages/db/dist/esm/local-storage.js 2.12 kB
packages/db/dist/esm/optimistic-action.js 359 B
packages/db/dist/esm/paced-mutations.js 496 B
packages/db/dist/esm/proxy.js 3.75 kB
packages/db/dist/esm/query/builder/functions.js 1.47 kB
packages/db/dist/esm/query/builder/index.js 5.84 kB
packages/db/dist/esm/query/builder/ref-proxy.js 1.24 kB
packages/db/dist/esm/query/compiler/evaluators.js 1.89 kB
packages/db/dist/esm/query/compiler/expressions.js 430 B
packages/db/dist/esm/query/compiler/group-by.js 3.56 kB
packages/db/dist/esm/query/compiler/index.js 6.67 kB
packages/db/dist/esm/query/compiler/joins.js 2.5 kB
packages/db/dist/esm/query/compiler/lazy-targets.js 923 B
packages/db/dist/esm/query/compiler/order-by.js 1.74 kB
packages/db/dist/esm/query/compiler/select.js 1.53 kB
packages/db/dist/esm/query/effect.js 4.77 kB
packages/db/dist/esm/query/expression-helpers.js 1.43 kB
packages/db/dist/esm/query/ir.js 1.25 kB
packages/db/dist/esm/query/live-query-collection.js 360 B
packages/db/dist/esm/query/live/collection-config-builder.js 9.1 kB
packages/db/dist/esm/query/live/collection-registry.js 264 B
packages/db/dist/esm/query/live/collection-subscriber.js 1.93 kB
packages/db/dist/esm/query/live/internal.js 145 B
packages/db/dist/esm/query/live/utils.js 1.81 kB
packages/db/dist/esm/query/optimizer.js 2.92 kB
packages/db/dist/esm/query/predicate-utils.js 2.97 kB
packages/db/dist/esm/query/query-once.js 359 B
packages/db/dist/esm/query/subset-dedupe.js 960 B
packages/db/dist/esm/scheduler.js 1.3 kB
packages/db/dist/esm/SortedMap.js 1.3 kB
packages/db/dist/esm/strategies/debounceStrategy.js 247 B
packages/db/dist/esm/strategies/queueStrategy.js 428 B
packages/db/dist/esm/strategies/throttleStrategy.js 246 B
packages/db/dist/esm/transactions.js 3.04 kB
packages/db/dist/esm/utils.js 927 B
packages/db/dist/esm/utils/array-utils.js 273 B
packages/db/dist/esm/utils/browser-polyfills.js 304 B
packages/db/dist/esm/utils/btree.js 5.61 kB
packages/db/dist/esm/utils/comparison.js 1.11 kB
packages/db/dist/esm/utils/cursor.js 457 B
packages/db/dist/esm/utils/index-optimization.js 2.39 kB
packages/db/dist/esm/utils/type-guards.js 157 B
packages/db/dist/esm/utils/uuid.js 449 B
packages/db/dist/esm/virtual-props.js 360 B

compressed-size-action::db-package-size

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 4.26 kB

ℹ️ View Unchanged
Filename Size
packages/react-db/dist/esm/index.js 249 B
packages/react-db/dist/esm/useLiveInfiniteQuery.js 1.32 kB
packages/react-db/dist/esm/useLiveQuery.js 1.37 kB
packages/react-db/dist/esm/useLiveQueryEffect.js 355 B
packages/react-db/dist/esm/useLiveSuspenseQuery.js 567 B
packages/react-db/dist/esm/usePacedMutations.js 401 B

compressed-size-action::react-db-package-size

@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 (2)
packages/query-db-collection/tests/query.test.ts (2)

1610-1644: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Missing collection.cleanup() in these three tests.

Unlike the on-demand tests (which clean up via liveQuery.cleanup() in a finally block) and the inactive/removed-query tests (which call collection.cleanup() explicitly), these three eager tests leave the collection's observer/subscription active after the test ends. Since startSync: true creates a live QueryObserver against the shared queryClient, consider adding await collection.cleanup() for symmetry and to avoid lingering subscriptions across tests.

Also applies to: 1646-1681, 1881-1921

🤖 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/query-db-collection/tests/query.test.ts` around lines 1610 - 1644,
The eager invalidation tests leave the live observer from
createCollection/queryCollectionOptions active after completion because
startSync: true starts a QueryObserver subscription on the shared queryClient.
Add an explicit await collection.cleanup() at the end of these eager tests
(including the matching query.test cases mentioned in the comment) so they
mirror the existing cleanup patterns in the on-demand and inactive-query tests
and do not leak subscriptions across test cases.

1609-2002: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Repeated test boilerplate across all 8 cases.

Each test repeats the same pattern: build queryFn mock, createCollection, await vi.waitFor for initial materialization, mutate items, invalidate, then await vi.waitFor again. Extracting a small helper (e.g., createTestCollection(queryKey, options) and a waitForRow(collection, id, expected) assertion helper) would reduce duplication and make future invalidation tests easier to add.

As per coding guidelines, "Extract common logic into utility functions when identical or near-identical code blocks appear in multiple places" and "Prefer small, focused utility functions over large inline implementations."

🤖 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/query-db-collection/tests/query.test.ts` around lines 1609 - 2002,
The invalidation behavior tests repeat the same setup and assertion flow across
many cases, making the suite noisy and hard to extend. Extract the shared
materialization/invalidation pattern into small helpers near the existing
`invalidation behavior` describe block, such as a collection factory for
`createCollection`/`queryCollectionOptions` setup and a reusable row-wait
assertion for `vi.waitFor` checks. Keep the individual `it` cases focused on
their unique query key, invalidation type, and expected row state, while reusing
the helper logic for `queryFn`, `items`, and `stripVirtualProps` assertions.

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/query-db-collection/tests/query.test.ts`:
- Around line 1610-1644: The eager invalidation tests leave the live observer
from createCollection/queryCollectionOptions active after completion because
startSync: true starts a QueryObserver subscription on the shared queryClient.
Add an explicit await collection.cleanup() at the end of these eager tests
(including the matching query.test cases mentioned in the comment) so they
mirror the existing cleanup patterns in the on-demand and inactive-query tests
and do not leak subscriptions across test cases.
- Around line 1609-2002: The invalidation behavior tests repeat the same setup
and assertion flow across many cases, making the suite noisy and hard to extend.
Extract the shared materialization/invalidation pattern into small helpers near
the existing `invalidation behavior` describe block, such as a collection
factory for `createCollection`/`queryCollectionOptions` setup and a reusable
row-wait assertion for `vi.waitFor` checks. Keep the individual `it` cases
focused on their unique query key, invalidation type, and expected row state,
while reusing the helper logic for `queryFn`, `items`, and `stripVirtualProps`
assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6a8cdbc7-b96c-4460-b752-b6450b4b6f42

📥 Commits

Reviewing files that changed from the base of the PR and between 18ba740 and a09ecca.

📒 Files selected for processing (2)
  • .changeset/query-invalidation-matrix.md
  • packages/query-db-collection/tests/query.test.ts

@KyleAMathews KyleAMathews merged commit e147721 into main Jul 9, 2026
11 checks passed
@KyleAMathews KyleAMathews deleted the query-invalidation-matrix branch July 9, 2026 15:23
@github-actions github-actions Bot mentioned this pull request Jul 9, 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.

2 participants