Skip to content

feat(ir): WITH forwards a whole node (#814 slice 2)#896

Merged
DecisionNerd merged 1 commit into
mainfrom
feature/814-with-node-forwarding
Jun 23, 2026
Merged

feat(ir): WITH forwards a whole node (#814 slice 2)#896
DecisionNerd merged 1 commit into
mainfrom
feature/814-with-node-forwarding

Conversation

@DecisionNerd

@DecisionNerd DecisionNerd commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Part of #814 (slice 2 — whole-node forwarding through WITH; does not close it).

Summary

MATCH (n) WITH n … now carries a node through the WITH scope reset instead of erroring (the slice-1 deferral). This was the most-cited deferral and a prerequisite for WITH-then-RETURN n.

How

A node variable spans multiple columns (var_<n>.node_uuid + each property), so a single aliased projection can't represent it:

  • Lowerer (lower_with_op): a WITH item that is a bare VarRef to a node var (one with a NodeScan shape) now forwards all input columns under that var's qualifier, unchanged — instead of col(expr).alias(name). The scope reset maps the var to its column prefix.
  • Binder (lower_with): a no-rename node item (WITH n / WITH n AS n) reuses the node's var (no fresh mint) and re-registers it in node_vars after the reset, so a later RETURN n materializes a whole node value (rust: node-value materialization — return a whole node value (identity+labels+props) from an expression #785) and n.x resolves.

Deferred (clear errors, not silently wrong)

  • Renaming a node through WITH (WITH n AS m) — needs column re-qualification.
  • Forwarding a relationship / path variable.

Validation

  • New e2e: with_forwards_whole_node_then_property (WITH n WHERE n.age>28 RETURN n.name → Alice+Carol), with_forwards_whole_node_then_node_value (WITH n RETURN n → node Struct) — 84 pass.
  • IR / rel goldens unchanged (with_pipeline uses scalar WITH); cargo clippy --workspace -- -D warnings + fmt clean.

🤖 Generated with Claude Code

Note

Support forwarding a whole node through WITH in graph IR

  • The binder in crates/gf-ir/src/binder.rs now allows WITH n (bare node variable, no rename) to pass through the scope reset, reusing the existing VarId and re-registering it as a node var so downstream RETURN n and n.x resolve correctly.
  • The lowerer in crates/gf-rel/src/lowerer.rs detects node-shaped VarRef items and projects all columns under the variable's qualifier prefix instead of a single scalar column.
  • Renaming a node via WITH n AS m and forwarding a relationship or path through WITH remain rejected with explicit errors.
  • E2E tests in crates/gf-api/tests/e2e_baseline.rs are updated to assert correct row results and node-value struct access after WITH n.

Macroscope summarized b2f4e33.

Summary by CodeRabbit

  • New Features
    • The WITH clause now supports forwarding whole node variables through queries, enabling full node variables to retain all their properties and structure through subsequent query operations. This allows queries like WITH n WHERE n.age > 28 RETURN n.name and WITH n RETURN n to succeed as expected.

`MATCH (n) WITH n …` now carries a node through the WITH scope reset
instead of erroring (the prior #814 deferral). A node variable spans
multiple columns (var_<n>.node_uuid + properties), so:

- Lowerer (lower_with_op): a WITH item that is a bare VarRef to a node
  var (one with a NodeScan shape) forwards ALL input columns under that
  var's qualifier unchanged, rather than projecting a single column. The
  scope reset then maps the var to its column prefix.
- Binder (lower_with): a no-rename node item (`WITH n` / `WITH n AS n`)
  reuses the node's var (no fresh mint) and re-registers it in node_vars
  after the reset, so a later `RETURN n` materializes a whole node value
  (#785) and `n.x` resolves.

Still deferred (clear errors): renaming a node (`WITH n AS m`, needs
column re-qualification) and forwarding a relationship/path.

Validated: new e2e `with_forwards_whole_node_then_property` and
`with_forwards_whole_node_then_node_value` (84 pass); IR/rel goldens
unchanged (with_pipeline uses scalar WITH); clippy --workspace -D
warnings + fmt clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The PR implements whole-node variable forwarding through WITH clauses. The IR binder (lower_with) gains classification logic to detect bare node passthroughs, preserve label metadata across scope resets, and reuse existing VarIds. The relational lowerer (lower_with_op) projects all columns under a node's var prefix and installs prefix-aware scope mappings. E2E tests are updated from error expectations to success assertions.

Changes

WITH Whole-Node Forwarding

Layer / File(s) Summary
Binder: classify and register forwarded node vars
crates/gf-ir/src/binder.rs
Adds forwarded_nodes accumulator; replaces blanket rejection of WITH n with classification that accepts bare passthrough (reusing existing VarId), rejects path forwarding and node rename; re-registers node_vars entries from forwarded_nodes after scope reset.
Relational lowerer: forward all node columns through WITH
crates/gf-rel/src/lowerer.rs
In lower_with_op, detects VarRef items present in node_shapes, selects every column qualified under that node's var prefix, records the prefix in new_scope; clears VarMap and repopulates it with prefix-aware mappings; releases node_shapes borrow before mutation.
E2E tests: whole-node WITH forwarding
crates/gf-api/tests/e2e_baseline.rs
Replaces the prior error-expecting test with a success assertion for WITH n + WHERE + property RETURN; adds a second test confirming RETURN n after WITH n materializes a full node-value struct with correct property values.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • DecisionNerd/graphforge#890: Directly related — introduces node_shapes and whole-node materialization in RETURN n that this PR's WITH forwarding relies on.
  • DecisionNerd/graphforge#894: Directly related — introduced the deferred/rejection behavior for WITH n whole-node passthrough that this PR replaces with actual support.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title concisely and accurately describes the main feature: implementing whole-node forwarding through the WITH clause in the IR layer.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering summary, implementation details, deferred work, and validation results.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/814-with-node-forwarding

Comment @coderabbitai help to get the list of available commands.

@DecisionNerd DecisionNerd merged commit b98b9ba into main Jun 23, 2026
41 checks passed
@DecisionNerd DecisionNerd deleted the feature/814-with-node-forwarding branch June 23, 2026 21:44
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.

1 participant