Skip to content

Commit f7b7c3d

Browse files
authored
feat: google.protobuf.Any handling (#135)
* refactor: mark visitation method as overriden for consistency * refactor: extract newFileOrFiles * feat: support Advanced Extensions from RelCommon * feat: support Leaf/Single/Multi Rel extensions * feat: support ExtensionTable * feat: support Advanced Extensions from Rels * refactor: extension -> commonExtension * feat: allow extension rels to derive their own record types * refactor: make rel extension details non-optional * feat: allow extension table to derive its schema * test: verify roundtripping of google.protobuf.Any fields * test: verify default ProtoRelConvert behaviour when Any data is present * feat: allow users to provide custom ProtoRelConverter implementations * refactor: make extension table details non-optional * fix: handle Detail data in StringHolderHandlingProtoRelConverter * docs: document google.protobuf.Any handling code * feat: allow for easier extension of ProtoRelConverter * docs: difference between Optimization and Enhancement * docs: correct optimization docs * refactor: getRelExtension -> getExtension * refactor: extract ToProto interface * refactor: split out extension from Rel * refactor: generalExtension -> relExtension BREAKING CHANGE: Use commonExtension to indicate that these extensions are associated with the RelCommon message BREAKING CHANGE: Use relExtension to indicate that these extensions are associated directly with Rels
1 parent dd069f6 commit f7b7c3d

31 files changed

+1243
-182
lines changed
Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,24 @@
11
package io.substrait.io.substrait.extension;
22

3-
public interface AdvancedExtension {
3+
import io.substrait.relation.Extension;
4+
import java.util.Optional;
5+
import org.immutables.value.Value;
46

5-
io.substrait.proto.AdvancedExtension toProto();
7+
@Value.Immutable
8+
public abstract class AdvancedExtension {
9+
10+
public abstract Optional<Extension.Optimization> getOptimization();
11+
12+
public abstract Optional<Extension.Enhancement> getEnhancement();
13+
14+
public io.substrait.proto.AdvancedExtension toProto() {
15+
var builder = io.substrait.proto.AdvancedExtension.newBuilder();
16+
getEnhancement().ifPresent(e -> builder.setEnhancement(e.toProto()));
17+
getOptimization().ifPresent(e -> builder.setOptimization(e.toProto()));
18+
return builder.build();
19+
}
20+
21+
public static ImmutableAdvancedExtension.Builder builder() {
22+
return ImmutableAdvancedExtension.builder();
23+
}
624
}

core/src/main/java/io/substrait/plan/ProtoPlanConverter.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class ProtoPlanConverter {
1515
static final org.slf4j.Logger logger =
1616
org.slf4j.LoggerFactory.getLogger(io.substrait.plan.ProtoPlanConverter.class);
1717

18-
private final SimpleExtension.ExtensionCollection extensionCollection;
18+
protected final SimpleExtension.ExtensionCollection extensionCollection;
1919

2020
public ProtoPlanConverter() throws IOException {
2121
this(SimpleExtension.loadDefaults());
@@ -25,9 +25,14 @@ public ProtoPlanConverter(SimpleExtension.ExtensionCollection extensionCollectio
2525
this.extensionCollection = extensionCollection;
2626
}
2727

28+
/** Override hook for providing custom {@link ProtoRelConverter} implementations */
29+
protected ProtoRelConverter getProtoRelConverter(FunctionLookup functionLookup) {
30+
return new ProtoRelConverter(functionLookup, this.extensionCollection);
31+
}
32+
2833
public Plan from(io.substrait.proto.Plan plan) {
2934
FunctionLookup functionLookup = ImmutableFunctionLookup.builder().from(plan).build();
30-
ProtoRelConverter relConverter = new ProtoRelConverter(functionLookup, extensionCollection);
35+
ProtoRelConverter relConverter = getProtoRelConverter(functionLookup);
3136
List<Plan.Root> roots = new ArrayList<>();
3237
for (PlanRel planRel : plan.getRelationsList()) {
3338
io.substrait.proto.RelRoot root = planRel.getRoot();

core/src/main/java/io/substrait/relation/AbstractReadRel.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
package io.substrait.relation;
22

33
import io.substrait.expression.Expression;
4-
import io.substrait.io.substrait.extension.AdvancedExtension;
54
import io.substrait.type.NamedStruct;
65
import io.substrait.type.Type;
76
import java.util.Optional;
87

9-
public abstract class AbstractReadRel extends ZeroInputRel {
8+
public abstract class AbstractReadRel extends ZeroInputRel implements HasExtension {
109

1110
public abstract NamedStruct getInitialSchema();
1211

@@ -15,8 +14,6 @@ public abstract class AbstractReadRel extends ZeroInputRel {
1514
// TODO:
1615
// public abstract Optional<MaskExpression>
1716

18-
public abstract Optional<AdvancedExtension> getGeneralExtension();
19-
2017
@Override
2118
protected final Type.Struct deriveRecordType() {
2219
return getInitialSchema().struct();

core/src/main/java/io/substrait/relation/AbstractRelVisitor.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,28 @@ public OUTPUT visit(VirtualTableScan virtualTableScan) throws EXCEPTION {
5959
return visitFallback(virtualTableScan);
6060
}
6161

62+
@Override
6263
public OUTPUT visit(Cross cross) throws EXCEPTION {
6364
return visitFallback(cross);
6465
}
66+
67+
@Override
68+
public OUTPUT visit(ExtensionLeaf extensionLeaf) throws EXCEPTION {
69+
return visitFallback(extensionLeaf);
70+
}
71+
72+
@Override
73+
public OUTPUT visit(ExtensionSingle extensionSingle) throws EXCEPTION {
74+
return visitFallback(extensionSingle);
75+
}
76+
77+
@Override
78+
public OUTPUT visit(ExtensionMulti extensionMulti) throws EXCEPTION {
79+
return visitFallback(extensionMulti);
80+
}
81+
82+
@Override
83+
public OUTPUT visit(ExtensionTable extensionTable) throws EXCEPTION {
84+
return visitFallback(extensionTable);
85+
}
6586
}

core/src/main/java/io/substrait/relation/Aggregate.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import org.immutables.value.Value;
1313

1414
@Value.Immutable
15-
public abstract class Aggregate extends SingleInputRel {
15+
public abstract class Aggregate extends SingleInputRel implements HasExtension {
1616
static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(Aggregate.class);
1717

1818
public abstract List<Grouping> getGroupings();

core/src/main/java/io/substrait/relation/Cross.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import org.immutables.value.Value;
77

88
@Value.Immutable
9-
public abstract class Cross extends BiRel {
9+
public abstract class Cross extends BiRel implements HasExtension {
1010

1111
@Override
1212
protected Type.Struct deriveRecordType() {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package io.substrait.relation;
2+
3+
import io.substrait.type.NamedStruct;
4+
import io.substrait.type.Type;
5+
import java.util.List;
6+
7+
/** Contains tag interfaces for handling {@link com.google.protobuf.Any} types within Substrait. */
8+
public class Extension {
9+
10+
/**
11+
* Optimization associated with an {@link io.substrait.proto.AdvancedExtension}
12+
*
13+
* <p>An optimization is helpful information that don't influence semantics. May be ignored by a
14+
* consumer.
15+
*/
16+
public interface Optimization extends ToProto<com.google.protobuf.Any> {}
17+
18+
/**
19+
* Enhancement associated with an {@link io.substrait.proto.AdvancedExtension}
20+
*
21+
* <p>An enhancement alter semantics. Cannot be ignored by a consumer.
22+
*/
23+
public interface Enhancement extends ToProto<com.google.protobuf.Any> {}
24+
25+
public interface LeafRelDetail extends ToProto<com.google.protobuf.Any> {
26+
/**
27+
* @return the record layout for the associated {@link ExtensionLeaf} relation
28+
*/
29+
Type.Struct deriveRecordType();
30+
}
31+
32+
public interface SingleRelDetail extends ToProto<com.google.protobuf.Any> {
33+
/**
34+
* @param input to the associated {@link ExtensionSingle} relation
35+
* @return the record layout for the associated {@link ExtensionSingle} relation
36+
*/
37+
Type.Struct deriveRecordType(Rel input);
38+
}
39+
40+
public interface MultiRelDetail extends ToProto<com.google.protobuf.Any> {
41+
/**
42+
* @param inputs to the associated {@link ExtensionMulti} relation
43+
* @return the record layout for the associated {@link ExtensionMulti} relation
44+
*/
45+
Type.Struct deriveRecordType(List<Rel> inputs);
46+
}
47+
48+
public interface ExtensionTableDetail extends ToProto<com.google.protobuf.Any> {
49+
/**
50+
* @return the table schema for the associated {@link ExtensionTable} relation
51+
*/
52+
NamedStruct deriveSchema();
53+
}
54+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.substrait.relation;
2+
3+
import org.immutables.value.Value;
4+
5+
@Value.Immutable
6+
public abstract class ExtensionLeaf extends ZeroInputRel {
7+
8+
public abstract Extension.LeafRelDetail getDetail();
9+
10+
@Override
11+
public <O, E extends Exception> O accept(RelVisitor<O, E> visitor) throws E {
12+
return visitor.visit(this);
13+
}
14+
15+
public static ImmutableExtensionLeaf.Builder from(Extension.LeafRelDetail detail) {
16+
return ImmutableExtensionLeaf.builder()
17+
.detail(detail)
18+
.deriveRecordType(detail.deriveRecordType());
19+
}
20+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package io.substrait.relation;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
import java.util.stream.Collectors;
6+
import org.immutables.value.Value;
7+
8+
@Value.Immutable
9+
public abstract class ExtensionMulti extends AbstractRel {
10+
11+
public abstract Extension.MultiRelDetail getDetail();
12+
13+
@Override
14+
public <O, E extends Exception> O accept(RelVisitor<O, E> visitor) throws E {
15+
return visitor.visit(this);
16+
}
17+
18+
public static ImmutableExtensionMulti.Builder from(
19+
Extension.MultiRelDetail detail, Rel... inputs) {
20+
return from(detail, Arrays.stream(inputs).collect(Collectors.toList()));
21+
}
22+
23+
public static ImmutableExtensionMulti.Builder from(
24+
Extension.MultiRelDetail detail, List<Rel> inputs) {
25+
return ImmutableExtensionMulti.builder()
26+
.addAllInputs(inputs)
27+
.detail(detail)
28+
.deriveRecordType(detail.deriveRecordType(inputs));
29+
}
30+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package io.substrait.relation;
2+
3+
import org.immutables.value.Value;
4+
5+
@Value.Immutable
6+
public abstract class ExtensionSingle extends SingleInputRel {
7+
8+
public abstract Extension.SingleRelDetail getDetail();
9+
10+
@Override
11+
public <O, E extends Exception> O accept(RelVisitor<O, E> visitor) throws E {
12+
return visitor.visit(this);
13+
}
14+
15+
public static ImmutableExtensionSingle.Builder from(Extension.SingleRelDetail detail, Rel input) {
16+
return ImmutableExtensionSingle.builder()
17+
.input(input)
18+
.detail(detail)
19+
.deriveRecordType(detail.deriveRecordType(input));
20+
}
21+
}

0 commit comments

Comments
 (0)