-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add POJOs for ConsistentPartitionWindowRel and WindowRelFunction #231
Conversation
t -> t.accept(getExpressionCopyOnWriteVisitor())); | ||
var sorts = transformList(consistentPartitionWindow.getSorts(), this::visitSortField); | ||
|
||
return Optional.of( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To follow the pattern of the other copy on write visitors, this should return empty unless any of the Optionals windowFunctions
, partitionExpressions
and sorts
is non-empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing a couple field conversions, but overall this looks good.
I wasn't sure about the organization/place of some parts since it's not physically under Expression, but there's a lot in common, even highlighted in the proto:
I can't a think of a alternate organization at this point either. Grouping the WindowRelFunctionInvocation
conversion code alongside the equivalent WindowFunctionInvocation
conversion code makes sense to me, and at least keeps it together. There might be some nicer abstraction we could use to unify these somehow, but I think that would be a bigger refactor and should be left for another time.
core/src/main/java/io/substrait/relation/RelCopyOnWriteVisitor.java
Outdated
Show resolved
Hide resolved
ConsistentPartitionWindow.WindowRelFunctionInvocation.builder() | ||
.arguments( | ||
visitFunctionArguments(windowRelFunctionInvocation.arguments()) | ||
.orElse(windowRelFunctionInvocation.arguments())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should return empty if visitFunctionArguments
returns an empty optional to keep the copy on write behaviour.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done, thanks!
@@ -250,6 +219,80 @@ public Expression from(io.substrait.proto.Expression expr) { | |||
}; | |||
} | |||
|
|||
public ImmutableExpression.WindowFunctionInvocation fromWindowFunction( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: We should return Expression.WindowFunctionInvocation
here. We generally avoid using the Immutable generate classes in signatures.
Good call extracting this out. It's much easier to look at alongside fromWindowRelFunction
like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Overlook when using extract method on IntelliJ
core/src/main/java/io/substrait/expression/proto/ProtoExpressionConverter.java
Show resolved
Hide resolved
.collect(Collectors.toList()); | ||
} | ||
|
||
public ImmutableExpression.SortField fromSortField(SortField s) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
minor: This should return Expression.SortField
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto
core/src/main/java/io/substrait/relation/RelProtoConverter.java
Outdated
Show resolved
Hide resolved
core/src/main/java/io/substrait/relation/RelProtoConverter.java
Outdated
Show resolved
Hide resolved
} | ||
|
||
@Value.Immutable | ||
public abstract static class WindowRelFunctionInvocation { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not for this PR. It might make sense in the future to define an interface of common types that we can share between WindowRelFunctionInvocation
and WindowFunctionInvocation
.
Constructing a WindowRelFunctionInvocation
from that interface would be straightforward (as it would have all the fields), and then construction a WindowRelFunctionInvocation
would just required providing the partitions and sorts.
We might also be able to have WindowFunctionInvocation
extend from WindowRelFunctionInvocation
, but I vaguely recall trying something like that in the past and the Immutable library not liking it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I agree -- it's subtly different and can be annoying to have concise builders and everything.
core/src/test/java/io/substrait/type/proto/WindowFunctionRoundtripTest.java
Outdated
Show resolved
Hide resolved
@@ -377,14 +377,8 @@ protected Optional<ConsistentPartitionWindow.WindowRelFunctionInvocation> visitW | |||
|
|||
return Optional.of( | |||
ConsistentPartitionWindow.WindowRelFunctionInvocation.builder() | |||
.from(windowRelFunctionInvocation) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using from here both:
- saves use some lines of code
- prevents issues if we ever add fields to the
ConsistentPartitionWindow
(as we would then need to make sure we updated this code to manually copy over those fields)
import java.util.Collections; | ||
import org.junit.jupiter.api.Test; | ||
|
||
public class WindowFunctionRoundtripTest extends TestBase { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to ConsistentPartitionWindowRelRoundtripTest
as we're testing the roundtripability of the rel as a whole.
var windowFunctionDeclaration = | ||
defaultExtensionCollection.getWindowFunction( | ||
SimpleExtension.FunctionAnchor.of( | ||
DefaultExtensionCatalog.FUNCTIONS_ARITHMETIC, "lead:any")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a specific function (in this case lead:any
) instead of a random one from defaultExtensionCollection.windowFunctions().get(0)
. There's no guarantee that a function chosen at random will be valid with the arguments that we choose to pass.
b.namedScan( | ||
Arrays.asList("test"), | ||
Arrays.asList("a", "b", "c"), | ||
Arrays.asList(R.I64, R.I16, R.I32)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the builder to setup the input as it's more readable (IMO)
ConsistentPartitionWindow.WindowRelFunctionInvocation.builder() | ||
.declaration(windowFunctionDeclaration) | ||
// lead(a) | ||
.arguments(Arrays.asList(b.fieldReference(input, 0))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specify at least one argument to make sure argument conversions are wired in.
|
||
io.substrait.proto.Rel protoRel = relProtoConverter.toProto(rel1); | ||
io.substrait.relation.Rel rel2 = protoRelConverter.from(protoRel); | ||
assertEquals(rel1, rel2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the relProtoConverter
and protoRelConverter
defined in TestBase
to avoid having to set them up ourselves.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding the POJO for ConsistentPartitionWindowRel and WindowRelFunction: https://github.com/substrait-io/substrait/blob/main/proto/substrait/algebra.proto#L233-L267
I wasn't sure about the organization/place of some parts since it's not physically under
Expression
, but there's a lot in common, even highlighted in the proto:So I tried to keep it as a new base class, but tried to keep the converters as close as they were to make it more concise + simplifying reuse.
--
I'll have an Isthmus change following (this is essentially a cleanup / split of #228), and @vbarua rightfully suggested breaking it down.