Skip to content

feat: implement window functions - #188

Open
gord02 wants to merge 2 commits into
mainfrom
gordon.hamilton/implement-window-functions
Open

feat: implement window functions#188
gord02 wants to merge 2 commits into
mainfrom
gordon.hamilton/implement-window-functions

Conversation

@gord02

@gord02 gord02 commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR implements window function building on the refactoring PRs.

Type of Change

  • New feature

Testing

  • Added tests for new functionality
  • All existing tests pass

Related Issues

Closes #158

@gord02
gord02 requested review from a team and wackywendell as code owners July 21, 2026 21:57

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 02163d48b7

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/parser/expressions.rs
if is_list_of_fields {
items
.into_iter()
.map(|item| sort_field_from_tuple(extensions, unwrap_single_pair(item)))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Return an error for mixed order tuples

If a window order= list starts with a valid sort tuple but contains a later non-tuple item, e.g. order=(($0,&AscNullsLast), $1), is_list_of_fields is true and this call passes a reference pair into sort_field_from_tuple, whose assert_eq!(tuple.as_rule(), Rule::tuple) panics instead of returning a MessageParseError. This is syntactically parseable bad input, so the parser should validate every item and report the contextual error rather than aborting the caller.

AGENTS.md reference: AGENTS.md:L54-L56

Useful? React with 👍 / 👎.

Comment thread src/parser/expressions.rs
)
})?;

let expr = window_expression_from_value(extensions, expr_pair)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject non-reference window order keys

Using window_expression_from_value here lets order=(add($0):i64, &AscNullsLast) parse into a SortField with a scalar-function expression, but the shared formatter for SortField only renders selection references and emits !{SortField} for any other expression. Since the documented window syntax describes the sort key as a reference, this accepted input cannot be formatted back into parseable text; either reject non-reference order keys here or teach the formatter to render them.

AGENTS.md reference: AGENTS.md:L80-L83

Useful? React with 👍 / 👎.

@gord02
gord02 force-pushed the gordon.hamilton/implement-window-functions branch from 02163d4 to 53eea56 Compare July 21, 2026 22:08
@gord02
gord02 requested a review from Copilot July 22, 2026 19:17

Copilot AI 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.

Pull request overview

This PR adds end-to-end support for Substrait Expression.WindowFunction in substrait-explain, extending the text format, parser, and textifier so window functions can be round-tripped through parse -> textify -> parse.

Changes:

  • Adds parsing for window_function_call expressions with an over(...) clause (partition/order/phase/invocation + optional rows/range frame) and the necessary semantic validations.
  • Adds textification for WindowFunction, including canonical rendering of over(...) named arguments and frame bounds.
  • Updates the Pest grammar and GRAMMAR.md, and adds roundtrip + rejection tests for window function behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/plan_roundtrip.rs Adds roundtrip cases and plan-level rejection cases for window function syntax/semantics.
src/textify/expressions.rs Implements Textify for WindowFunction and supporting helpers for over(...) arguments and frame rendering.
src/parser/extensions.rs Explicitly rejects _ as an extension-relation argument value now that _ is syntactically allowed as an argument token.
src/parser/expressions.rs Implements window function parsing (window_function_call) and over(...) clause decoding/validation.
src/parser/expression_grammar.pest Introduces window_function_call grammar and allows _ (empty) as an extension_argument for frame bounds.
GRAMMAR.md Documents the new window function syntax and clarifies _ as a syntactic argument value with limited semantic meaning.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/parser/expressions.rs
Comment on lines +800 to +820
let phase_pair = phase_pair.ok_or_else(|| {
MessageParseError::invalid(
"WindowFunction",
span,
"Missing required phase= argument in over(...)",
)
})?;
let phase = match window_enum_str(phase_pair, "phase")?.as_str() {
"Unspecified" => AggregationPhase::Unspecified as i32,
"InitialToIntermediate" => AggregationPhase::InitialToIntermediate as i32,
"IntermediateToIntermediate" => AggregationPhase::IntermediateToIntermediate as i32,
"InitialToResult" => AggregationPhase::InitialToResult as i32,
"IntermediateToResult" => AggregationPhase::IntermediateToResult as i32,
other => {
return Err(MessageParseError::invalid(
"AggregationPhase",
span,
format!("Unknown AggregationPhase: {other}"),
));
}
};
Comment thread src/parser/expressions.rs
Comment on lines +822 to +836
let invocation = match invocation_pair {
None => AggregationInvocation::Unspecified as i32,
Some(p) => match window_enum_str(p, "invocation")?.as_str() {
"Unspecified" => AggregationInvocation::Unspecified as i32,
"All" => AggregationInvocation::All as i32,
"Distinct" => AggregationInvocation::Distinct as i32,
other => {
return Err(MessageParseError::invalid(
"AggregationInvocation",
span,
format!("Unknown AggregationInvocation: {other}"),
));
}
},
};
@gord02
gord02 force-pushed the gordon.hamilton/function-reference-refactor branch from e0b8d95 to c297ab1 Compare July 29, 2026 16:47
@gord02 gord02 changed the title Gordon.hamilton/implement window functions feat: implement window functions Jul 29, 2026
@gord02
gord02 force-pushed the gordon.hamilton/implement-window-functions branch from 6836dd4 to 8b9bac6 Compare July 29, 2026 17:21
Base automatically changed from gordon.hamilton/function-reference-refactor to main August 12, 2026 18:36
gord02 and others added 2 commits August 13, 2026 14:35
Add parsing and textifying of window functions (Expression.WindowFunction):
an `over(...)` clause with partition=, order=, phase=, invocation=, and
rows=/range= frame bounds.

Reuses the generic argument/tuple/named-argument grammar (adding '_' to
extension_argument for unbounded bounds, rejected as an extension-relation
argument), composes the shared FunctionReference and FunctionArguments parser
components into WindowFunctionInvocation/OverClause/Bound, and textifies via
the shared value primitives.

Includes GRAMMAR.md docs and parser + roundtrip tests.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gord02
gord02 force-pushed the gordon.hamilton/implement-window-functions branch from 8b9bac6 to acfc254 Compare August 13, 2026 18:36
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.

2 participants