Skip to content

perf(db): preserve row references across metadata snapshots - #2328

Closed
benjavicente wants to merge 1 commit into
TanStack:mainfrom
benjavicente:observer-snapshot-caching
Closed

benjavicente wants to merge 1 commit into
TanStack:mainfrom
benjavicente:observer-snapshot-caching

Conversation

@benjavicente

@benjavicente benjavicente commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

🤖 Agent generated, human reviewed

🎯 Changes

Status-only and health-only observer updates currently rebuild row containers even when the rows have not changed. The new array and Map identities can trigger unnecessary work in consumers that use reference equality.

Cache row materialization separately from the full snapshot. Metadata changes still produce a fresh snapshot with current status and health, while reusing its data array and lazy state Map. Value, membership, and ordering changes remain visible, and retained snapshots keep their capture-time rows.

This complements the Angular fixes in #2327. Its snapshot-based signals follow the current query immediately, and its separate row-state projection can preserve the adapter's defensive Map copy when the observer keeps the same Map reference. Together, the changes avoid unnecessary row-signal value changes and downstream recomputation on metadata-only updates. They do not eliminate all notification or dirty-marking work.

The observer change is independent of the Angular adapter and can merge in either order.

🔬 Oracle Coverage

Owner: packages/db/tests/live-query-observer-snapshot-oracle.property.test.ts, extended with live-query-observer.row-container-sharing.

  • Law: metadata-only snapshots retain row-container references; row changes remain visible and retained snapshots stay point-in-time.
  • Reach: 52 fixed and 52 random histories cover both observer modes, attached/detached reads, zero through three rows, read order, readiness, health, and same-key value writes.
  • RED: from packages/db, ../../node_modules/.bin/vitest --run --coverage.enabled=false tests/live-query-observer-snapshot-oracle.property.test.ts -t 'metadata snapshots' fails on unchanged production because a metadata transition replaces the data array.
  • GREEN: 100 observer tests pass. The unchanged Angular adapter also passes 89 tests with one existing TODO against this branch.
  • Mutant: reusing containers based only on row count fails on a same-key value update, demonstrating that stable membership cannot hide changed values.
  • Limits: the new lane uses synchronous direct Collections with string keys. Existing ordered/findOne and hydration suites protect neighboring behavior; no new host scheduling or external-provider guarantee is claimed.

Detailed evidence and replay instructions.

✅ Checklist

  • I have tested this code locally with pnpm test.
  • The affected package tests and supporting checks listed below pass locally.

Affected tests, focused typecheck, ESLint, oracle lint, mangle validation, formatting, package build, and documentation snippet checks pass on Node 24.8.0. The full workspace pnpm test suite was not run locally.

🚀 Release Impact

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

Patch changeset for @tanstack/db.

Summary by CodeRabbit

  • Improvements
    • Live-query snapshots now retain the same data and state references when only status or health information changes, while still reflecting updated values and row ordering.
    • Snapshots with changed status or health remain distinct, and previously retained snapshots preserve their earlier rows.
  • Documentation
    • Added guidance and review evidence describing snapshot behavior and its verification.

Cache row materialization separately from full observer snapshots. Keep lazy
state Maps and data arrays stable across status/health changes while preserving
value-only updates, layout changes, and retained point-in-time reads.

Law: metadata-only snapshots retain their row containers (maintainer decision
2026-11-01; LiveQuerySnapshot contract).
Reach: 52 fixed and 52 random histories cross both observer modes, attached and
detached reads, empty/nonempty rows, read order, readiness, health, and writes.
RED: unchanged production fails metadata reference equality; seed 1101,
path 0:0:0:0, in live-query-observer.row-container-sharing.
GREEN: 100 observer tests, 89 existing Angular tests (one TODO), focused types,
ESLint, oracle lint, mangle validation, package build, and docs snippets pass on
Node 24.8.0. The patch Changeset releases this independently of Angular fixes.
Mutant: same-cardinality reuse fails a same-key value write; seed 1101,
path 0:0:1:2. The final implementation is restored.
Limits: the new lane uses synchronous direct Collections with 0..3 string keys;
existing ordered/findOne/hydration suites cover neighboring laws. No new host
scheduling or external-provider guarantee.
@changeset-bot

changeset-bot Bot commented Nov 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 62d15fa

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 24 packages
Name Type
@tanstack/db Patch
@tanstack/angular-db Patch
@tanstack/capacitor-db-sqlite-persistence-e2e-app Patch
@tanstack/convex-db-collection Patch
@tanstack/db-sqlite-persistence-core Patch
@tanstack/electric-db-collection Patch
@tanstack/expo-db-sqlite-persistence-e2e-app Patch
@tanstack/powersync-db-collection Patch
@tanstack/preact-db Patch
@tanstack/react-db Patch
@tanstack/rxdb-db-collection Patch
@tanstack/solid-db Patch
@tanstack/svelte-db Patch
@tanstack/tauri-db-sqlite-persistence-e2e-app Patch
@tanstack/trailbase-db-collection Patch
@tanstack/vue-db Patch
@tanstack/browser-db-sqlite-persistence Patch
@tanstack/capacitor-db-sqlite-persistence Patch
@tanstack/cloudflare-durable-objects-db-sqlite-persistence Patch
@tanstack/electron-db-sqlite-persistence Patch
@tanstack/expo-db-sqlite-persistence Patch
@tanstack/node-db-sqlite-persistence Patch
@tanstack/react-native-db-sqlite-persistence Patch
@tanstack/tauri-db-sqlite-persistence Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d1ffc24c-ecdf-486e-af97-c6be599de9c4
Commits

Reviewing files that changed from the base of the PR and between 15d2d2d and 62d15fa.

Files selected for processing: 7
  • .changeset/observer-row-container-sharing.md
  • docs/contributing/oracle-coverage.md
  • docs/contributing/oracle-reviews/2026-11-01-observer-row-containers.md
  • packages/db/mangle-cache.json
  • packages/db/src/live-query-observer.ts
  • packages/db/tests/live-query-observer-snapshot-oracle.property.test.ts
  • packages/db/tests/oracle-config.ts

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 6 remain after this review.

Walkthrough

The observer now reuses data arrays and state Maps across snapshots when entries remain unchanged. Property-based histories test reuse for metadata changes and replacement for writes.

Changes: Observer row-container sharing

Layer / File(s) Summary
Cache and reuse observer row containers
packages/db/src/live-query-observer.ts, packages/db/mangle-cache.json, .changeset/observer-row-container-sharing.md
The observer caches row containers by entries-array identity. Metadata-only snapshots reuse the data array and lazy state Map; changed entries produce new containers. Cache change detection compares entries even when a collection revision is available.
History validation and evidence
packages/db/tests/live-query-observer-snapshot-oracle.property.test.ts, packages/db/tests/oracle-config.ts, docs/contributing/oracle-coverage.md, docs/contributing/oracle-reviews/2026-11-01-observer-row-containers.md
Property histories check row values and container identity across metadata changes and writes. They cover granular and wholesale modes, attached and detached observers, and empty and populated collections. Oracle coverage and review evidence document the lane and its results.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Refactor

Possibly related issues

  • TanStack/db issue 2320: This change addresses observer reuse for metadata-only updates. The issue also covers collection-level reuse after equal selected values, which is outside this change.

Suggested reviewers: kyleamathews, kevin-dp

Merge Risk: Minimal · up to 62d15

No merge-blocking issue was established; the change is ready for normal merge checks.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: preserving row references across metadata snapshots.
Description check Passed The description includes the required Changes, Oracle Coverage, Checklist, and Release Impact sections. It explains the behavior change, test evidence, limits, and changeset. It also accurately states…
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.
Full details: Description check

Explanation

The description includes the required Changes, Oracle Coverage, Checklist, and Release Impact sections. It explains the behavior change, test evidence, limits, and changeset. It also accurately states that the full workspace pnpm test suite was not run.

Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 1 functions across 3 files. (4 skipped: 4 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@pkg-pr-new

pkg-pr-new Bot commented Nov 2, 2026

Copy link
Copy Markdown
More templates

@tanstack/angular-db

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

@tanstack/browser-db-sqlite-persistence

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

@tanstack/capacitor-db-sqlite-persistence

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

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

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

@tanstack/convex-db-collection

npm i https://pkg.pr.new/@tanstack/convex-db-collection@2328

@tanstack/db

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

@tanstack/db-ivm

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

@tanstack/db-sqlite-persistence-core

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

@tanstack/electric-db-collection

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

@tanstack/electron-db-sqlite-persistence

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

@tanstack/expo-db-sqlite-persistence

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

@tanstack/node-db-sqlite-persistence

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

@tanstack/offline-transactions

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

@tanstack/powersync-db-collection

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

@tanstack/preact-db

npm i https://pkg.pr.new/@tanstack/preact-db@2328

@tanstack/query-db-collection

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

@tanstack/react-db

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

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

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

@tanstack/react-router-with-db

npm i https://pkg.pr.new/@tanstack/react-router-with-db@2328

@tanstack/rxdb-db-collection

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

@tanstack/solid-db

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

@tanstack/svelte-db

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

@tanstack/tauri-db-sqlite-persistence

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

@tanstack/trailbase-db-collection

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

@tanstack/vue-db

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

commit: 62d15fa

@KyleAMathews

Copy link
Copy Markdown
Collaborator

Thanks for this fix, @benjavicente! I preserved your original commit in #2346 and added stronger oracle coverage and a smaller shared observer cache. Closing this PR in favor of that follow-up.

@benjavicente
benjavicente deleted the observer-snapshot-caching branch November 3, 2026 15:04
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