Skip to content

fix: correlated subquery resolves empty when correlation targets a joined alias - #1705

Open
Mohith26 wants to merge 2 commits into
TanStack:mainfrom
Mohith26:fix/materialize-subquery-correlation
Open

fix: correlated subquery resolves empty when correlation targets a joined alias#1705
Mohith26 wants to merge 2 commits into
TanStack:mainfrom
Mohith26:fix/materialize-subquery-correlation

Conversation

@Mohith26

@Mohith26 Mohith26 commented Jul 29, 2026

Copy link
Copy Markdown

Fixes #1704, reported by @Jaime02.

In compileQuery, the includes-child path re-keys the raw main-source input by childCorrelationField.path.slice(1), assuming the correlation ref lives on the subquery's own from alias. When it references a joined alias instead (eq(order.partId, part.id) with from(production).innerJoin(order)), the nested lookup returns undefined, so the inner join with parent keys drops every row: the subquery resolves to [] permanently, with no error.

The fix defers the parent-key filter when the correlation alias is not the main source: the identical inner join is applied after processJoins against the namespaced pipeline using the compiled correlation expression, tagging __correlationKey on the main-source namespace and merging parent context so group-by, order-by, and output routing consume it unchanged. Lazy loading needed no change (followRef already resolves joined aliases). Patch changeset included.

Two regression tests cover initial resolution, incremental insert/delete propagation, the issue's exact spread-select shape, and a from-alias-with-join control; both fail without the fix. Package suite: 2485 passed, zero new failures; eslint, build, and vitest typecheck clean.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed materialize() returning empty results when correlation conditions referenced fields from joined data.
    • Ensured correlated results remain accurate after incremental inserts and deletes.
    • Improved support for queries that select fields from joined sources while preserving parent-child relationships.

Mohith26 added 2 commits July 29, 2026 14:27
…ined alias

The includes-child compilation re-keyed the raw main-source input by
childCorrelationField.path.slice(1), silently assuming the correlation
ref lives on the subquery's own from alias. When it references a joined
alias instead, every correlation value evaluated to undefined and the
inner join with parent keys dropped all rows, so materialize() resolved
to a permanently empty array.

Defer the parent-key filter until after joins in that case: re-key the
namespaced pipeline by the compiled correlation expression, inner-join
with the parent key stream, and tag __correlationKey on the main source
namespace (with parent context merged) so downstream routing, group-by,
order-by and output extraction keep working unchanged.

Fixes TanStack#1704
Covers the initial resolve, incremental insert/delete propagation, the
issue's exact spread-select shape, and a control asserting from-alias
correlation still works when the subquery contains a join.
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

materialize() now defers parent-key filtering when correlation references a joined alias, applies the correlation after joins, and preserves parent context. Regression tests cover initial and incremental results, spread selections, and parent-side alias controls.

Changes

Materialize correlation handling

Layer / File(s) Summary
Deferred joined-alias correlation and regression coverage
packages/db/src/query/compiler/index.ts, packages/db/tests/query/includes.test.ts, .changeset/plenty-hoops-shake.md
The compiler detects joined-alias correlations, defers parent-key filtering until after joins, applies correlation keys and parent context, and tests initial, insert, delete, spread-selection, and control-query behavior. The package receives a patch changeset.

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

Suggested reviewers: kevin-dp, kyleamathews

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the change well, but it does not follow the required template headings or checkbox sections. Add the template sections: 🎯 Changes, ✅ Checklist with pnpm test status, and 🚀 Release Impact with the correct checkbox.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the fix for correlated subqueries failing when the correlation predicate uses a joined alias.
Linked Issues check ✅ Passed The fix, deferred correlation filtering, and regression tests all match the requirements of issue #1704.
Out of Scope Changes check ✅ Passed The changes are limited to the fix, its tests, and a changeset, with no unrelated scope added.
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.

🧹 Nitpick comments (4)
packages/db/tests/query/includes.test.ts (2)

6794-6818: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Exercise incremental changes to the joined correlation source.

These assertions only insert and delete comments. Also update or delete an issues row so its projectId changes, then verify the comment is removed from one project and routed to the other. That directly protects the new post-join correlation path.

🤖 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 6794 - 6818, Extend
the incremental joined-correlation test around collection.get(1) to update or
delete an issues row and change its projectId, then verify the associated
comment is removed from the original project and appears under the destination
project. Keep the existing comment insert/delete assertions and exercise the
post-join routing path through an issues-source change.

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

Keep the regression assertions type-checked.

Replace these as any casts with non-null assertions or explicit expected result types so schema/result inference regressions remain visible to TypeScript.

As per coding guidelines: “Avoid using any types; use unknown instead when the type is truly unknown.” <coding_guidelines>

Also applies to: 6786-6786, 6791-6792, 6802-6802, 6815-6815, 6837-6837, 6857-6857

🤖 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` at line 6780, Remove the as any
casts from the regression assertions around collection.get calls, including the
related lines, and preserve type checking by using non-null assertions or
explicit expected result types. Keep the existing assertions and test behavior
unchanged while ensuring schema/result inference errors remain visible to
TypeScript.

Source: Coding guidelines

packages/db/src/query/compiler/index.ts (2)

326-373: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared correlation filtering pipeline.

This duplicates the pre-join rekey/join/filter/effective-key flow at Lines 262-293. Extract the common mechanics with callbacks for reading and tagging each row shape so both paths cannot drift.

As per coding guidelines: “Extract common logic into utility functions when identical or near-identical code blocks appear in multiple places.” <coding_guidelines>

🤖 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/src/query/compiler/index.ts` around lines 326 - 373, Extract the
shared rekey, inner-join, filtering, correlation tagging, parent-context merge,
and effective-key generation from this block and the corresponding pre-join flow
into a reusable helper. Parameterize the helper with callbacks for reading
correlation values and tagging each row shape, then update both paths around
compileExpression(childCorrelationField!) to use it while preserving their
existing outputs.

Source: Coding guidelines


330-371: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace the new any annotations with typed stream tuples.

Define types for the namespaced row and joined values, then annotate the callbacks and returned key-value tuples precisely. This preserves compiler checks around childSide, parentSide, and namespacedRow[mainSource].

As per coding guidelines: “Avoid using any types; use unknown instead when the type is truly unknown, and provide proper type annotations for return values.” <coding_guidelines>

🤖 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/src/query/compiler/index.ts` around lines 330 - 371, Replace the
any annotations in the rekeying, filtering, and mapping callbacks with explicit
types for namespaced rows, child tuples, parent context, and joined stream
values. Define reusable tuple/object types near this join logic, type
namespacedRow[mainSource] safely, and annotate the returned effective
key/tagged-row tuple without weakening checks around childSide or parentSide.

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/db/src/query/compiler/index.ts`:
- Around line 326-373: Extract the shared rekey, inner-join, filtering,
correlation tagging, parent-context merge, and effective-key generation from
this block and the corresponding pre-join flow into a reusable helper.
Parameterize the helper with callbacks for reading correlation values and
tagging each row shape, then update both paths around
compileExpression(childCorrelationField!) to use it while preserving their
existing outputs.
- Around line 330-371: Replace the any annotations in the rekeying, filtering,
and mapping callbacks with explicit types for namespaced rows, child tuples,
parent context, and joined stream values. Define reusable tuple/object types
near this join logic, type namespacedRow[mainSource] safely, and annotate the
returned effective key/tagged-row tuple without weakening checks around
childSide or parentSide.

In `@packages/db/tests/query/includes.test.ts`:
- Around line 6794-6818: Extend the incremental joined-correlation test around
collection.get(1) to update or delete an issues row and change its projectId,
then verify the associated comment is removed from the original project and
appears under the destination project. Keep the existing comment insert/delete
assertions and exercise the post-join routing path through an issues-source
change.
- Line 6780: Remove the as any casts from the regression assertions around
collection.get calls, including the related lines, and preserve type checking by
using non-null assertions or explicit expected result types. Keep the existing
assertions and test behavior unchanged while ensuring schema/result inference
errors remain visible to TypeScript.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1b89689c-402c-4419-b219-aebf98edaed2

📥 Commits

Reviewing files that changed from the base of the PR and between 67c840f and c7033a8.

📒 Files selected for processing (3)
  • .changeset/plenty-hoops-shake.md
  • packages/db/src/query/compiler/index.ts
  • packages/db/tests/query/includes.test.ts

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.

materialize() subquery resolves to [] when its correlation predicate targets a joined alias

1 participant