fix: resolve materialize(findOne()) to undefined when the correlation key is null - #1707
fix: resolve materialize(findOne()) to undefined when the correlation key is null#1707Mohith26 wants to merge 2 commits into
Conversation
… key is null A null correlation key never reaches materializeIncludedValue: the Phase 1 includes flush only handled 'correlationKey != null', so the compiler's null select placeholder leaked into the parent result, violating the typed 'T | undefined' contract of findOne() (and 'Array<T>' for array materializations). Null correlation keys can never match a child row and never receive child pipeline output, so the field is now resolved eagerly to its empty materialized value: undefined for findOne(), [] for arrays, an empty string for concat. Rows that do not participate in the include at all (conditional-select guards failed, or no routing info found) are tagged 'skipped' by the compiler's routing functions so values owned by other conditional-select branches are left untouched. Bare (non-materialized) subquery includes are unchanged; their null-key behavior is tracked separately by the RFC 1658 cluster. Fixes TanStack#1706
Covers the three paths from the TanStack#1706 repro: findOne() with a matching FK, an FK that matches no child, and a null FK, plus the array materialization shape and a live update transitioning the FK to null.
📝 WalkthroughWalkthroughThis change distinguishes skipped include routing from null correlation keys, emits empty materialized values for inline includes with null correlations, synchronizes stored parent rows, and adds regression coverage for ChangesNull correlation materialization
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related issues
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 |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/db/tests/query/includes.test.ts (1)
6583-6597: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winKeep the regression fixtures type-safe.
The helper has no return annotation and the assertions use
as any, so result-shape regressions are not type-checked. Use a precise helper return type and inferred/narrowed query results instead.As per coding guidelines, avoid
anyand provide the most precise TypeScript return type annotations.Also applies to: 6620-6682
🤖 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/query/includes.test.ts` around lines 6583 - 6597, The createAuthorAndPostCollections helper should declare a precise return type for both collection instances, and the related query assertions should remove as any casts. Use inferred or properly narrowed result types so regressions in the query result shape are caught by TypeScript.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.
Inline comments:
In @.changeset/shiny-donkeys-repeat.md:
- Line 5: Update the changeset description to replace the invalid-looking
`materialize(q…findOne())` expression with valid API syntax such as
`materialize(q.from(...).findOne())`, or describe the behavior in prose while
preserving the existing null-correlation-key details.
---
Nitpick comments:
In `@packages/db/tests/query/includes.test.ts`:
- Around line 6583-6597: The createAuthorAndPostCollections helper should
declare a precise return type for both collection instances, and the related
query assertions should remove as any casts. Use inferred or properly narrowed
result types so regressions in the query result shape are caught by TypeScript.
🪄 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 Plus
Run ID: a3f855fd-290c-4076-8ce6-410bcea0f9aa
📒 Files selected for processing (4)
.changeset/shiny-donkeys-repeat.mdpackages/db/src/query/compiler/index.tspackages/db/src/query/live/collection-config-builder.tspackages/db/tests/query/includes.test.ts
| '@tanstack/db': patch | ||
| --- | ||
|
|
||
| Fix: `materialize(q…findOne())` resolved to `null` instead of `undefined` when the correlation key itself was null. A null correlation key never reached the includes materialization step, so the compiler's `null` select placeholder leaked into the result, violating the typed `T | undefined` contract. Null correlation keys now resolve to the empty materialized value (`undefined` for `findOne()`, `[]` for arrays, `` for `concat`). |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Use a valid-looking query expression.
materialize(q…findOne()) is unclear and reads like invalid API syntax. Use materialize(q.from(...).findOne()) or prose instead.
Proposed fix
-Fix: `materialize(q…findOne())` resolved to `null` instead of `undefined`
+Fix: `materialize(q.from(...).findOne())` resolved to `null` instead of `undefined`📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| Fix: `materialize(q…findOne())` resolved to `null` instead of `undefined` when the correlation key itself was null. A null correlation key never reached the includes materialization step, so the compiler's `null` select placeholder leaked into the result, violating the typed `T | undefined` contract. Null correlation keys now resolve to the empty materialized value (`undefined` for `findOne()`, `[]` for arrays, `` for `concat`). | |
| Fix: `materialize(q.from(...).findOne())` resolved to `null` instead of `undefined` when the correlation key itself was null. A null correlation key never reached the includes materialization step, so the compiler's `null` select placeholder leaked into the result, violating the typed `T | undefined` contract. Null correlation keys now resolve to the empty materialized value (`undefined` for `findOne()`, `[]` for arrays, `` for `concat`). |
🤖 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 @.changeset/shiny-donkeys-repeat.md at line 5, Update the changeset
description to replace the invalid-looking `materialize(q…findOne())` expression
with valid API syntax such as `materialize(q.from(...).findOne())`, or describe
the behavior in prose while preserving the existing null-correlation-key
details.
Fixes #1706, reported by @Jaime02.
materialize(q...findOne())returnednullinstead of the typedundefinedwhenever the correlated FK column was itself null: the compiler replaces the include in select with a literalnullplaceholder, and Phase 1 of the includes flush only handledcorrelationKey != null, so null-FK parents never reachedmaterializeIncludedValueand the raw placeholder leaked out, violating theT | undefinedcontract in the types.The fix resolves null-correlation-key fields eagerly to their empty materialized value at parent-insert time (
undefinedfor findOne,[]for arrays,""for concat), with askippedrouting flag so conditional-select branches that do not own the field are untouched. Bare non-materialized includes with null FK intentionally keep the placeholder pending RFC #1658.Independent of #1705 (different region of the compiler plus the live-collection routing; reproduced on plain main; no overlapping hunks). Patch changeset included. Three regression tests (the issue's three-post repro with an FK-set-but-unmatched control, array shape, live FK-update-to-null transition) fail without the fix; full suite 2486 passed, zero new failures; eslint/prettier/typecheck clean.
Summary by CodeRabbit
null.findOne()now consistently returnsundefined, array queries return[], and concatenated results return an empty value.null.