feat(ir): name mixed-aggregate group-by keys by source text (#599) — corpus 570→574#910
Conversation
Walkthrough
ChangesExplicit group-key aliasing in aggregate plans
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
crates/gf-rel/src/lowerer.rs (1)
2371-2374: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd a non-empty
group_aliaseslowering test.This test only covers
group_aliases: vec![], so the new aliasing branch inlower_aggregateis still unpinned at unit level. A small grouped-aggregate case that asserts the output header uses the supplied alias would make this contract much harder to regress.🤖 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 `@crates/gf-rel/src/lowerer.rs` around lines 2371 - 2374, Add a grouped-aggregate lowering test that exercises a non-empty group_aliases path in lower_aggregate, since the current coverage only uses vec![] and leaves the aliasing branch unverified. Create a small aggregate case in the lowerer.rs test area that passes a group alias through GraphOp::Aggregate and assert the lowered output header/column name uses that alias, so the behavior is pinned at unit level.
🤖 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 `@crates/gf-ir/src/binder.rs`:
- Around line 1089-1095: The group-by lowering in binder.rs still uses
lower_expr for RETURN items, which leaves whole-node keys like n or startNode(r)
as bare VarRef values instead of the _node_struct form. Update the
Aggregate/group_by path in the relevant binder logic to reuse the same
whole-node materialization used by lower_return_item_expr, so mixed queries like
RETURN n, count(*) bind against the rewritten node structure rather than an
unbound column. Keep the existing alias handling via
group_aliases.push(item.alias.clone().or_else(|| item.display.clone()))
unchanged.
---
Nitpick comments:
In `@crates/gf-rel/src/lowerer.rs`:
- Around line 2371-2374: Add a grouped-aggregate lowering test that exercises a
non-empty group_aliases path in lower_aggregate, since the current coverage only
uses vec![] and leaves the aliasing branch unverified. Create a small aggregate
case in the lowerer.rs test area that passes a group alias through
GraphOp::Aggregate and assert the lowered output header/column name uses that
alias, so the behavior is pinned at unit level.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 0aef24f7-f2e1-4758-a67e-be6c93af906d
⛔ Files ignored due to path filters (2)
CHANGELOG.mdis excluded by!**/*.mddocs/reference/tck-compliance.mdis excluded by!**/*.md,!**/docs/**
📒 Files selected for processing (5)
crates/gf-ir/src/binder.rscrates/gf-ir/src/plan.rscrates/gf-rel/src/lowerer.rstests/tck/coverage_matrix.jsontests/tck/passing_baseline.txt
Completes source-text naming for the aggregate path (un-aliased aggregates landed in #909) and fixes whole-node group keys. In a mixed aggregate query like `RETURN n.name, count(*)`, the `n.name` group-by column was named by its lowered expression (`var_0.name`), failing the TCK header-exact comparison. The `Aggregate` IR op now carries an optional per-key output alias — `group_aliases`, parallel to `group_by` and `#[serde(skip_serializing_if = "Vec::is_empty")]` so existing plans/goldens are unchanged — filled by the binder from each RETURN item's `AS` alias or verbatim source text and applied by `lower_aggregate` via `.alias()`. Group keys are also now materialized through the same path as terminal RETURN items: a whole-node group key (`RETURN n, count(*)`) rewrites to `_node_struct` rather than a bare `var_N` (which is not a real column and lowered against an unbound reference). (Thanks CodeRabbit.) Corpus passing 570 → 575 (+5, 0 regressions); baseline re-blessed. No golden churn (the IR aggregation golden has an empty group-by). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
033be1d to
29a85e4
Compare
What
Completes source-text naming for the aggregate path (un-aliased aggregates landed in #909). In a mixed aggregate query like
RETURN n.name, count(*), then.namegroup-by column was named by its lowered expression (var_0.name), failing the TCK header-exact comparison.The
AggregateIR op now carries an optional per-key output alias —group_aliases, parallel togroup_byand#[serde(skip_serializing_if = "Vec::is_empty")]so existing plans/goldens are unchanged. The binder fills it from each RETURN item'sASalias or verbatim source text;lower_aggregateapplies it via.alias()on the group expression.Impact
Corpus passing 570 → 574 (+4, 0 regressions); baseline re-blessed. Modest yield (mixed aggregate queries are uncommon) but it closes the aggregate-naming gap. No golden churn (the IR aggregation golden has an empty group-by).
Verification
Refs #599 (does not close). Next aggregation slice: nested aggregates (
count(*)+1) via Aggregate→Project decomposition.🤖 Generated with Claude Code
Note
Name mixed-aggregate group-by keys by source text in the IR aggregate op
group_aliases: Vec<Option<String>>toGraphOp::Aggregatein plan.rs, carrying per-key output aliases alongsidegroup_bykeysASclauses or display text for each group-by key, and materializes bare node variables to node structs using terminal RETURN item semanticsMacroscope summarized 29a85e4.
Summary by CodeRabbit
New Features
Bug Fixes
Tests