fix: invalidate stale predicate-scoped cache entries on manual-sync writes#1497
fix: invalidate stale predicate-scoped cache entries on manual-sync writes#1497marbemac wants to merge 4 commits into
Conversation
More templates
@tanstack/angular-db
@tanstack/browser-db-sqlite-persistence
@tanstack/capacitor-db-sqlite-persistence
@tanstack/cloudflare-durable-objects-db-sqlite-persistence
@tanstack/db
@tanstack/db-ivm
@tanstack/db-sqlite-persistence-core
@tanstack/electric-db-collection
@tanstack/electron-db-sqlite-persistence
@tanstack/expo-db-sqlite-persistence
@tanstack/node-db-sqlite-persistence
@tanstack/offline-transactions
@tanstack/powersync-db-collection
@tanstack/query-db-collection
@tanstack/react-db
@tanstack/react-native-db-sqlite-persistence
@tanstack/rxdb-db-collection
@tanstack/solid-db
@tanstack/svelte-db
@tanstack/tauri-db-sqlite-persistence
@tanstack/trailbase-db-collection
@tanstack/vue-db
commit: |
|
any news on this? we hit the same bug :( — for now we are avoiding the |
📝 WalkthroughWalkthroughDirect writes now patch eager caches but revalidate active scoped on-demand queries and remove inactive or disabled entries. Query observer tracking prevents duplicate reconciliation, while tests cover query-key variants, predicates, pagination, deferred refreshes, and preload behavior. ChangesManual-write cache invalidation
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant DirectWrite
participant updateCacheData
participant QueryObserver
participant queryFn
DirectWrite->>updateCacheData: update cache after synced-store write
updateCacheData->>QueryObserver: refetch active scoped observers
QueryObserver->>queryFn: request scoped results
queryFn-->>QueryObserver: return refreshed data
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
|
@marbemac @andyfelder16 could you test this against my latest pushes? I merged in origin/main & did a few fixes |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/query-db-collection/tests/query.test.ts (1)
8676-8677: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueClarify the double
setQueryDatawith an identity updater.Two back-to-back identity
setQueryDatacalls are non-obvious; they appear intended to advancedataUpdateCountso the laterresetQueriesexercises the stale-count path. A one-line comment explaining why the count is bumped twice would help future readers.🤖 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 8676 - 8677, Add a concise comment immediately before the duplicate customQueryClient.setQueryData calls explaining that the identity updates intentionally increment dataUpdateCount twice so the subsequent resetQueries test covers the stale-count path; leave both calls unchanged.
🤖 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 8676-8677: Add a concise comment immediately before the duplicate
customQueryClient.setQueryData calls explaining that the identity updates
intentionally increment dataUpdateCount twice so the subsequent resetQueries
test covers the stale-count path; leave both calls unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: abffe3a9-0247-453a-9e5c-a6a3fe9b8dcc
📒 Files selected for processing (5)
.changeset/fix-cache-poisoning-on-manual-writes.mddocs/collections/query-collection.mddocs/reference/query-db-collection/interfaces/QueryCollectionUtils.mdpackages/query-db-collection/src/query.tspackages/query-db-collection/tests/query.test.ts
Manual-sync writes in on-demand Query Collections now preserve predicate-, order-, and pagination-scoped Query cache results. Active queries revalidate from their source, while inactive or disabled entries are removed so later subscriptions fetch fresh data.
Root cause
Each on-demand Query cache entry belongs to one
queryFnresult and may encode a distinctwhere,orderBy,limit, oroffset. Manual writes replaced every entry under the collection's base key with the full normalized collection snapshot. That changed the shape and membership of scoped cache entries.An inactive poisoned entry could later be treated as a valid cache hit. Its rows would be reconciled through the wrong query ownership scope, which surfaced in production as “not found” results for rows that still existed in Postgres. Active limited or ordered queries had the same flaw: patching them from the normalized snapshot could widen the cache or fail to replenish a deleted row.
Approach
staleTime: 'static'.queryFn.dataUpdateCount, then accept the next authoritative result.Key invariants
queryFn.Non-goals and trade-offs
This does not change eager cache updates or the direct-write API. Active on-demand queries now incur a network refetch after a manual write; that cost is required because a normalized collection snapshot cannot reconstruct ordered, limited, paginated, or predicate-scoped results.
Verification
The package suite passes all 146 tests. New regressions cover inactive cache hits, overlapping scopes, active limited and static queries, disabled entries, in-flight initial loads, Query resets, and rejected deferred-refresh barriers.
Files changed
packages/query-db-collection/src/query.ts: revalidate or remove on-demand cache entries and guard stale notifications.packages/query-db-collection/tests/query.test.ts: add red/green coverage for scoped-cache and lifecycle cases.docs/collections/query-collection.md: document eager and on-demand direct-write behavior.docs/reference/query-db-collection/interfaces/QueryCollectionUtils.md: update generated API reference text..changeset/fix-cache-poisoning-on-manual-writes.md: add the patch release note.Release impact
Summary by CodeRabbit
Bug Fixes
Documentation