Skip to content

fix(db): materialize includes into parent rows before commit#1684

Closed
juliuslipp wants to merge 2 commits into
TanStack:mainfrom
juliuslipp:fix/includes-parent-only-updates
Closed

fix(db): materialize includes into parent rows before commit#1684
juliuslipp wants to merge 2 commits into
TanStack:mainfrom
juliuslipp:fix/includes-parent-only-updates

Conversation

@juliuslipp

@juliuslipp juliuslipp commented Jul 17, 2026

Copy link
Copy Markdown

🎯 Changes

Fixes #1635.

Live query includes are materialized into parent rows only after the parent collection commits: flushIncludesState patches the stored row in place (setIncludedValue) without emitting an event, and the follow-up re-emit (inlineReEmitKeys) only fires for correlation keys with pending child changes.

Any consumer that copies rows at emit time never observes that patch. The most common shape is another live query layered on the collection — which is what every framework adapter produces for component-level queries (useLiveQuery((q) => q.from({ row: myLiveQuery }))). For those consumers, a parent-only update (e.g. a status column change synced from the server, no child rows touched) re-emits the parent row with every included field unset, and since no child change follows, they keep the empty includes until an unrelated child change recomputes the row. This is the "nested includes are undefined on next render after collection.update, a forced re-render brings them back" behavior reported in #1635.

The fix: materialize the current includes state into the new parent change values before begin()/commit(), so the emitted events already carry the included values. The post-commit flush then re-applies the same values idempotently (it still owns child-collection bookkeeping and registry maintenance), and the child-change re-emit path is unchanged. Only inline materializations (array/singleton/concat) are patched pre-commit; collection materialization still attaches in the post-commit flush.

New regression test: includes subqueries > parent-only updates > keeps materialized includes on rows observed through a layered live query — fails on main, passes with this change.

✅ Checklist

  • I have tested this code locally with pnpm test.

🚀 Release Impact

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

Summary by CodeRabbit

  • Bug Fixes
    • Fixed Materialize behavior so included child fields are populated on parent rows before change events are emitted.
    • Ensured included values remain correct after parent-only updates, including when used in layered live queries.
    • Prevented included fields from temporarily appearing empty until a subsequent child change occurs.

The includes flush patched parent rows in place only after the live
query collection committed, without emitting an event. Consumers that
copy rows at emit time (e.g. a live query layered on the collection,
the shape framework adapters produce for component-level queries)
captured the pre-patch row with its included fields unset, and a
parent-only update never triggered the follow-up re-emit, so those
consumers kept empty includes until an unrelated child change
recomputed the row.

Materialize the current includes state into the new parent change
values before begin/commit; the post-commit flush re-applies the same
values idempotently and the child-change re-emit path is unchanged.

Fixes TanStack#1635
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4c03308a-8d39-481b-87c0-bedd0db3d783

📥 Commits

Reviewing files that changed from the base of the PR and between a976137 and c8d03e4.

📒 Files selected for processing (2)
  • packages/db/src/query/live/collection-config-builder.ts
  • packages/db/tests/query/includes.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/db/tests/query/includes.test.ts
  • packages/db/src/query/live/collection-config-builder.ts

📝 Walkthrough

Walkthrough

The live query flush now materializes inline includes into parent changes before commit and emission. A regression test verifies layered queries retain included child rows after parent-only updates, and the changeset documents the fix for issue 1635.

Changes

Live query include materialization

Layer / File(s) Summary
Pre-commit parent include patching
packages/db/src/query/live/collection-config-builder.ts, .changeset/heavy-pandas-tell.md
Pending parent inserts are patched with inline materialized include values before transaction commit; the changeset records the patch release and behavior fix.
Parent-only update regression test
packages/db/tests/query/includes.test.ts
A layered live query test verifies materialized child includes remain populated after updating only the parent row.

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

Possibly related issues

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly describes the main change: materializing includes into parent rows before commit.
Description check ✅ Passed The description follows the template and includes the change summary, checklist, and release-impact notes.
Linked Issues check ✅ Passed The PR addresses #1635 by fixing nested includes after parent-only updates and adding a regression test.
Out of Scope Changes check ✅ Passed The changes stay focused on the bug fix, regression test, and required changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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.

@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.

Actionable comments posted: 2

🤖 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.

Inline comments:
In `@packages/db/src/query/live/collection-config-builder.ts`:
- Around line 1257-1260: Update patchParentChangesFromIncludes to use a generic
result type and type parentChanges as Map<unknown, Changes<TResult>> instead of
any. Preserve the caller’s Changes<TResult> type through the function contract,
using narrowly scoped internal casts only where symbol-based indexing or
setIncludedValue requires them.

In `@packages/db/tests/query/includes.test.ts`:
- Around line 755-757: In the test flow around layered.get(1), replace the fixed
10ms timeout with a deterministic synchronization mechanism, such as awaiting
the collection’s change event or using the project’s retry-polling helper, so
the assertion runs only after the async update completes. Replace the any cast
on renamed with the appropriate concrete type inferred from the collection or
existing test types.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6ec1e02b-c316-4ea5-9673-dc1fae95c75e

📥 Commits

Reviewing files that changed from the base of the PR and between 7f0fa36 and a976137.

📒 Files selected for processing (3)
  • .changeset/heavy-pandas-tell.md
  • packages/db/src/query/live/collection-config-builder.ts
  • packages/db/tests/query/includes.test.ts

Comment thread packages/db/src/query/live/collection-config-builder.ts Outdated
Comment thread packages/db/tests/query/includes.test.ts Outdated
- Type patchParentChangesFromIncludes over the caller's Changes<TResult>
  instead of Changes<any>, with one narrow cast for symbol-indexed routing
- Replace the fixed test sleep with vi.waitFor and drop the as-any casts
  (the layered query's inferred row type carries name/issues)
- Trim comments to the function contract

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juliuslipp juliuslipp closed this Jul 17, 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.

Nested includes are undefined on next render after collection.update

1 participant