Skip to content

Commit c1f30e3

Browse files
committed
SQL: Refactor binary date time functions (#47786)
Refactor DateTrunc and DatePart to use separate Pipe classes which allows the removal of the BinaryDateOperation enum. (cherry picked from commit a6075e7)
1 parent 6a4bf5d commit c1f30e3

File tree

15 files changed

+375
-195
lines changed

15 files changed

+375
-195
lines changed

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/BinaryDateTimeFunction.java

+7-9
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,15 @@
2020
import static org.elasticsearch.common.logging.LoggerMessageFormat.format;
2121
import static org.elasticsearch.xpack.sql.expression.TypeResolutions.isDate;
2222
import static org.elasticsearch.xpack.sql.expression.TypeResolutions.isString;
23-
import static org.elasticsearch.xpack.sql.expression.function.scalar.datetime.BinaryDateTimeProcessor.BinaryDateOperation;
2423
import static org.elasticsearch.xpack.sql.expression.gen.script.ParamsBuilder.paramsBuilder;
2524

2625
public abstract class BinaryDateTimeFunction extends BinaryScalarFunction {
2726

2827
private final ZoneId zoneId;
29-
private final BinaryDateOperation operation;
3028

31-
public BinaryDateTimeFunction(Source source, Expression datePart, Expression timestamp, ZoneId zoneId,
32-
BinaryDateOperation operation) {
29+
public BinaryDateTimeFunction(Source source, Expression datePart, Expression timestamp, ZoneId zoneId) {
3330
super(source, datePart, timestamp);
3431
this.zoneId = zoneId;
35-
this.operation = operation;
3632
}
3733

3834
@Override
@@ -47,7 +43,7 @@ protected TypeResolution resolveType() {
4743
if (datePartValue != null && resolveDateTimeField(datePartValue) == false) {
4844
List<String> similar = findSimilarDateTimeFields(datePartValue);
4945
if (similar.isEmpty()) {
50-
return new TypeResolution(format(null, "first argument of [{}] must be one of {} or their aliases, found value [{}]",
46+
return new TypeResolution(format(null, "first argument of [{}] must be one of {} or their aliases; found value [{}]",
5147
sourceText(),
5248
validDateTimeFieldValues(),
5349
Expressions.name(left())));
@@ -78,9 +74,11 @@ public ZoneId zoneId() {
7874

7975
@Override
8076
protected Pipe makePipe() {
81-
return new BinaryDateTimePipe(source(), this, Expressions.pipe(left()), Expressions.pipe(right()), zoneId, operation);
77+
return createPipe(Expressions.pipe(left()), Expressions.pipe(right()), zoneId);
8278
}
8379

80+
protected abstract Pipe createPipe(Pipe left, Pipe right, ZoneId zoneId);
81+
8482
@Override
8583
public Nullability nullable() {
8684
return Nullability.TRUE;
@@ -101,7 +99,7 @@ protected ScriptTemplate asScriptFrom(ScriptTemplate leftScript, ScriptTemplate
10199

102100
@Override
103101
public int hashCode() {
104-
return Objects.hash(super.hashCode(), zoneId, operation);
102+
return Objects.hash(super.hashCode(), zoneId);
105103
}
106104

107105
@Override
@@ -116,6 +114,6 @@ public boolean equals(Object o) {
116114
return false;
117115
}
118116
BinaryDateTimeFunction that = (BinaryDateTimeFunction) o;
119-
return zoneId.equals(that.zoneId) && operation == that.operation;
117+
return zoneId.equals(that.zoneId);
120118
}
121119
}

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/BinaryDateTimePipe.java

+7-24
Original file line numberDiff line numberDiff line change
@@ -9,50 +9,34 @@
99
import org.elasticsearch.xpack.sql.expression.gen.pipeline.BinaryPipe;
1010
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
1111
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
12-
import org.elasticsearch.xpack.sql.tree.NodeInfo;
1312
import org.elasticsearch.xpack.sql.tree.Source;
1413

1514
import java.time.ZoneId;
1615
import java.util.Objects;
1716

18-
public class BinaryDateTimePipe extends BinaryPipe {
17+
public abstract class BinaryDateTimePipe extends BinaryPipe {
1918

2019
private final ZoneId zoneId;
21-
private final BinaryDateTimeProcessor.BinaryDateOperation operation;
2220

23-
public BinaryDateTimePipe(Source source, Expression expression, Pipe left, Pipe right, ZoneId zoneId,
24-
BinaryDateTimeProcessor.BinaryDateOperation operation) {
21+
public BinaryDateTimePipe(Source source, Expression expression, Pipe left, Pipe right, ZoneId zoneId) {
2522
super(source, expression, left, right);
2623
this.zoneId = zoneId;
27-
this.operation = operation;
2824
}
2925

3026
ZoneId zoneId() {
3127
return zoneId;
3228
}
3329

34-
BinaryDateTimeProcessor.BinaryDateOperation operation() {
35-
return operation;
36-
}
37-
38-
@Override
39-
protected NodeInfo<BinaryDateTimePipe> info() {
40-
return NodeInfo.create(this, BinaryDateTimePipe::new, expression(), left(), right(), zoneId, operation);
41-
}
42-
43-
@Override
44-
protected BinaryPipe replaceChildren(Pipe left, Pipe right) {
45-
return new BinaryDateTimePipe(source(), expression(), left, right, zoneId, operation);
46-
}
47-
4830
@Override
4931
public Processor asProcessor() {
50-
return BinaryDateTimeProcessor.asProcessor(operation, left().asProcessor(), right().asProcessor(), zoneId);
32+
return makeProcessor(left().asProcessor(), right().asProcessor(), zoneId);
5133
}
5234

35+
protected abstract Processor makeProcessor(Processor left, Processor right, ZoneId zoneId);
36+
5337
@Override
5438
public int hashCode() {
55-
return Objects.hash(super.hashCode(), zoneId, operation);
39+
return Objects.hash(super.hashCode(), zoneId);
5640
}
5741

5842
@Override
@@ -67,7 +51,6 @@ public boolean equals(Object o) {
6751
return false;
6852
}
6953
BinaryDateTimePipe that = (BinaryDateTimePipe) o;
70-
return Objects.equals(zoneId, that.zoneId) &&
71-
operation == that.operation;
54+
return Objects.equals(zoneId, that.zoneId);
7255
}
7356
}

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/BinaryDateTimeProcessor.java

+10-22
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,8 @@
1515
import java.time.ZoneId;
1616
import java.util.Objects;
1717

18-
import static org.elasticsearch.xpack.sql.expression.function.scalar.datetime.BinaryDateTimeProcessor.BinaryDateOperation.TRUNC;
19-
2018
public abstract class BinaryDateTimeProcessor extends BinaryProcessor {
2119

22-
// TODO: Remove and in favour of inheritance (subclasses which implement abstract methods)
23-
public enum BinaryDateOperation {
24-
TRUNC,
25-
PART;
26-
}
27-
2820
private final ZoneId zoneId;
2921

3022
public BinaryDateTimeProcessor(Processor source1, Processor source2, ZoneId zoneId) {
@@ -48,28 +40,24 @@ ZoneId zoneId() {
4840
@Override
4941
protected abstract Object doProcess(Object left, Object right);
5042

51-
public static BinaryDateTimeProcessor asProcessor(BinaryDateOperation operation, Processor left, Processor right, ZoneId zoneId) {
52-
if (operation == TRUNC) {
53-
return new DateTruncProcessor(left, right, zoneId);
54-
} else {
55-
return new DatePartProcessor(left, right, zoneId);
56-
}
57-
}
58-
5943
@Override
6044
public int hashCode() {
61-
return Objects.hash(zoneId);
45+
return Objects.hash(left(), right(), zoneId);
6246
}
6347

6448
@Override
65-
public boolean equals(Object o) {
66-
if (this == o) {
49+
public boolean equals(Object obj) {
50+
if (this == obj) {
6751
return true;
6852
}
69-
if (o == null || getClass() != o.getClass()) {
53+
54+
if (obj == null || getClass() != obj.getClass()) {
7055
return false;
7156
}
72-
BinaryDateTimeProcessor that = (BinaryDateTimeProcessor) o;
73-
return zoneId.equals(that.zoneId);
57+
58+
BinaryDateTimeProcessor other = (BinaryDateTimeProcessor) obj;
59+
return Objects.equals(left(), other.left())
60+
&& Objects.equals(right(), other.right())
61+
&& Objects.equals(zoneId(), other.zoneId());
7462
}
7563
}

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DatePart.java

+15-9
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.elasticsearch.xpack.sql.expression.Nullability;
1010
import org.elasticsearch.xpack.sql.expression.function.scalar.BinaryScalarFunction;
1111
import org.elasticsearch.xpack.sql.expression.function.scalar.datetime.DateTimeProcessor.DateTimeExtractor;
12+
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
1213
import org.elasticsearch.xpack.sql.tree.NodeInfo;
1314
import org.elasticsearch.xpack.sql.tree.Source;
1415
import org.elasticsearch.xpack.sql.type.DataType;
@@ -78,7 +79,7 @@ public Integer extract(ZonedDateTime dateTime) {
7879
}
7980

8081
public DatePart(Source source, Expression truncateTo, Expression timestamp, ZoneId zoneId) {
81-
super(source, truncateTo, timestamp, zoneId, BinaryDateTimeProcessor.BinaryDateOperation.PART);
82+
super(source, truncateTo, timestamp, zoneId);
8283
}
8384

8485
@Override
@@ -102,23 +103,28 @@ public Nullability nullable() {
102103
}
103104

104105
@Override
105-
protected boolean resolveDateTimeField(String dateTimeField) {
106-
return Part.resolve(dateTimeField) != null;
106+
protected String scriptMethodName() {
107+
return "datePart";
107108
}
108109

109110
@Override
110-
protected List<String> findSimilarDateTimeFields(String dateTimeField) {
111-
return Part.findSimilar(dateTimeField);
111+
public Object fold() {
112+
return DatePartProcessor.process(left().fold(), right().fold(), zoneId());
112113
}
113114

114115
@Override
115-
protected String scriptMethodName() {
116-
return "datePart";
116+
protected Pipe createPipe(Pipe left, Pipe right, ZoneId zoneId) {
117+
return new DatePartPipe(source(), this, left, right, zoneId);
117118
}
118119

119120
@Override
120-
public Object fold() {
121-
return DatePartProcessor.process(left().fold(), right().fold(), zoneId());
121+
protected boolean resolveDateTimeField(String dateTimeField) {
122+
return Part.resolve(dateTimeField) != null;
123+
}
124+
125+
@Override
126+
protected List<String> findSimilarDateTimeFields(String dateTimeField) {
127+
return Part.findSimilar(dateTimeField);
122128
}
123129

124130
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
package org.elasticsearch.xpack.sql.expression.function.scalar.datetime;
7+
8+
import org.elasticsearch.xpack.sql.expression.Expression;
9+
import org.elasticsearch.xpack.sql.expression.gen.pipeline.Pipe;
10+
import org.elasticsearch.xpack.sql.expression.gen.processor.Processor;
11+
import org.elasticsearch.xpack.sql.tree.NodeInfo;
12+
import org.elasticsearch.xpack.sql.tree.Source;
13+
14+
import java.time.ZoneId;
15+
16+
public class DatePartPipe extends BinaryDateTimePipe {
17+
18+
public DatePartPipe(Source source, Expression expression, Pipe left, Pipe right, ZoneId zoneId) {
19+
super(source, expression, left, right, zoneId);
20+
}
21+
22+
@Override
23+
protected NodeInfo<DatePartPipe> info() {
24+
return NodeInfo.create(this, DatePartPipe::new, expression(), left(), right(), zoneId());
25+
}
26+
27+
@Override
28+
protected DatePartPipe replaceChildren(Pipe left, Pipe right) {
29+
return new DatePartPipe(source(), expression(), left, right, zoneId());
30+
}
31+
32+
@Override
33+
protected Processor makeProcessor(Processor left, Processor right, ZoneId zoneId) {
34+
return new DatePartProcessor(left, right, zoneId);
35+
}
36+
}

x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/scalar/datetime/DatePartProcessor.java

+13-13
Original file line numberDiff line numberDiff line change
@@ -34,36 +34,36 @@ public String getWriteableName() {
3434
}
3535

3636
@Override
37-
protected Object doProcess(Object left, Object right) {
38-
return process(left, right, zoneId());
37+
protected Object doProcess(Object part, Object timestamp) {
38+
return process(part, timestamp, zoneId());
3939
}
4040

4141
/**
4242
* Used in Painless scripting
4343
*/
44-
public static Object process(Object source1, Object source2, ZoneId zoneId) {
45-
if (source1 == null || source2 == null) {
44+
public static Object process(Object part, Object timestamp, ZoneId zoneId) {
45+
if (part == null || timestamp == null) {
4646
return null;
4747
}
48-
if (source1 instanceof String == false) {
49-
throw new SqlIllegalArgumentException("A string is required; received [{}]", source1);
48+
if (part instanceof String == false) {
49+
throw new SqlIllegalArgumentException("A string is required; received [{}]", part);
5050
}
51-
Part datePartField = Part.resolve((String) source1);
51+
Part datePartField = Part.resolve((String) part);
5252
if (datePartField == null) {
53-
List<String> similar = Part.findSimilar((String) source1);
53+
List<String> similar = Part.findSimilar((String) part);
5454
if (similar.isEmpty()) {
5555
throw new SqlIllegalArgumentException("A value of {} or their aliases is required; received [{}]",
56-
Part.values(), source1);
56+
Part.values(), part);
5757
} else {
5858
throw new SqlIllegalArgumentException("Received value [{}] is not valid date part for extraction; " +
59-
"did you mean {}?", source1, similar);
59+
"did you mean {}?", part, similar);
6060
}
6161
}
6262

63-
if (source2 instanceof ZonedDateTime == false) {
64-
throw new SqlIllegalArgumentException("A date/datetime is required; received [{}]", source2);
63+
if (timestamp instanceof ZonedDateTime == false) {
64+
throw new SqlIllegalArgumentException("A date/datetime is required; received [{}]", timestamp);
6565
}
6666

67-
return datePartField.extract(((ZonedDateTime) source2).withZoneSameInstant(zoneId));
67+
return datePartField.extract(((ZonedDateTime) timestamp).withZoneSameInstant(zoneId));
6868
}
6969
}

0 commit comments

Comments
 (0)