Skip to content

Commit 15439de

Browse files
Refactoring - Remove FunctionUtils.java and move all functionality to Foldables.java
1 parent 88edfdf commit 15439de

File tree

29 files changed

+128
-137
lines changed

29 files changed

+128
-137
lines changed

x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/expression/Foldables.java

Lines changed: 0 additions & 41 deletions
This file was deleted.

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichPolicyResolver.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
import java.util.Set;
6060
import java.util.stream.Collectors;
6161

62-
import static org.elasticsearch.xpack.esql.core.expression.Foldables.stringLiteralValueOf;
62+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.stringLiteralValueOf;
6363
import static org.elasticsearch.xpack.esql.session.EsqlCCSUtils.markClusterWithFinalStateAndNoShards;
6464

6565
/**
Lines changed: 71 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,63 +6,49 @@
66
*/
77
package org.elasticsearch.xpack.esql.expression.function;
88

9+
import org.apache.lucene.util.BytesRef;
910
import org.elasticsearch.common.lucene.BytesRefs;
1011
import org.elasticsearch.core.Nullable;
1112
import org.elasticsearch.core.Strings;
1213
import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException;
1314
import org.elasticsearch.xpack.esql.common.Failure;
1415
import org.elasticsearch.xpack.esql.common.Failures;
16+
import org.elasticsearch.xpack.esql.core.QlIllegalArgumentException;
1517
import org.elasticsearch.xpack.esql.core.expression.Expression;
18+
import org.elasticsearch.xpack.esql.core.expression.FoldContext;
1619
import org.elasticsearch.xpack.esql.core.expression.Literal;
1720

1821
import static org.elasticsearch.common.logging.LoggerMessageFormat.format;
1922
import static org.elasticsearch.xpack.esql.common.Failure.fail;
2023

21-
public class FunctionUtils {
22-
/**
23-
* A utility class to validate the type resolution of expressions before and after logical planning.
24-
* If null is passed for Failures to the constructor, it means we are only type resolution.
25-
* This is usually called when doing pre-logical planning validation.
26-
* If a {@link Failures} instance is passed, it means we are doing post-logical planning validation as well.
27-
* This is usually called after folding is done, during
28-
* {@link org.elasticsearch.xpack.esql.capabilities.PostOptimizationVerificationAware} verification
29-
*/
30-
public static class TypeResolutionValidator {
31-
32-
Expression.TypeResolution typeResolution = Expression.TypeResolution.TYPE_RESOLVED;
33-
@Nullable
34-
private final Failures postValidationFailures; // null means we are doing pre-folding validation only
35-
private final Expression field;
36-
37-
public static TypeResolutionValidator forPreOptimizationValidation(Expression field) {
38-
return new TypeResolutionValidator(field, null);
39-
}
40-
41-
public static TypeResolutionValidator forPostOptimizationValidation(Expression field, Failures failures) {
42-
return new TypeResolutionValidator(field, failures);
43-
}
24+
public abstract class Foldables {
4425

45-
private TypeResolutionValidator(Expression field, Failures failures) {
46-
this.field = field;
47-
this.postValidationFailures = failures;
26+
public static Object valueOf(FoldContext ctx, Expression e) {
27+
if (e.foldable()) {
28+
return e.fold(ctx);
4829
}
30+
throw new QlIllegalArgumentException("Cannot determine value for {}", e);
31+
}
4932

50-
public void invalidIfPostValidation(Failure failure) {
51-
if (postValidationFailures != null) {
52-
postValidationFailures.add(failure);
53-
}
33+
public static String stringLiteralValueOf(Expression expression, String message) {
34+
if (expression instanceof Literal literal && literal.value() instanceof BytesRef bytesRef) {
35+
return bytesRef.utf8ToString();
5436
}
37+
throw new QlIllegalArgumentException(message);
38+
}
5539

56-
public void invalid(Expression.TypeResolution message) {
57-
typeResolution = message;
58-
if (postValidationFailures != null) {
59-
postValidationFailures.add(fail(field, message.message()));
60-
}
40+
public static Object literalValueOf(Expression e) {
41+
if (e instanceof Literal literal) {
42+
return literal.value();
6143
}
44+
throw new QlIllegalArgumentException("Expected literal, but got {}", e);
45+
}
6246

63-
public Expression.TypeResolution getResolvedType() {
64-
return typeResolution;
47+
public static Object extractLiteralOrReturnSelf(Expression e) {
48+
if (e instanceof Literal literal) {
49+
return literal.value();
6550
}
51+
return e;
6652
}
6753

6854
public static Integer limitValue(Expression limitField, String sourceText) {
@@ -151,11 +137,57 @@ public static String queryAsString(Expression queryField, String sourceText) {
151137
}
152138

153139
public static int intValueOf(Expression field, String sourceText, String fieldName) {
154-
if (field instanceof Literal literal) {
155-
return ((Number) literal.value()).intValue();
140+
if (field instanceof Literal literal && literal.value() instanceof Number n) {
141+
return n.intValue();
156142
}
157143
throw new EsqlIllegalArgumentException(
158144
Strings.format(null, "[{}] value must be a constant number in [{}], found [{}]", fieldName, sourceText, field)
159145
);
160146
}
147+
148+
/**
149+
* A utility class to validate the type resolution of expressions before and after logical planning.
150+
* If null is passed for Failures to the constructor, it means we are only type resolution.
151+
* This is usually called when doing pre-logical planning validation.
152+
* If a {@link Failures} instance is passed, it means we are doing post-logical planning validation as well.
153+
* This is usually called after folding is done, during
154+
* {@link org.elasticsearch.xpack.esql.capabilities.PostOptimizationVerificationAware} verification
155+
*/
156+
public static class TypeResolutionValidator {
157+
158+
Expression.TypeResolution typeResolution = Expression.TypeResolution.TYPE_RESOLVED;
159+
@Nullable
160+
private final Failures postValidationFailures; // null means we are doing pre-folding validation only
161+
private final Expression field;
162+
163+
public static TypeResolutionValidator forPreOptimizationValidation(Expression field) {
164+
return new TypeResolutionValidator(field, null);
165+
}
166+
167+
public static TypeResolutionValidator forPostOptimizationValidation(Expression field, Failures failures) {
168+
return new TypeResolutionValidator(field, failures);
169+
}
170+
171+
private TypeResolutionValidator(Expression field, Failures failures) {
172+
this.field = field;
173+
this.postValidationFailures = failures;
174+
}
175+
176+
public void invalidIfPostValidation(Failure failure) {
177+
if (postValidationFailures != null) {
178+
postValidationFailures.add(failure);
179+
}
180+
}
181+
182+
public void invalid(Expression.TypeResolution message) {
183+
typeResolution = message;
184+
if (postValidationFailures != null) {
185+
postValidationFailures.add(fail(field, message.message()));
186+
}
187+
}
188+
189+
public Expression.TypeResolution getResolvedType() {
190+
return typeResolution;
191+
}
192+
}
161193
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/CountDistinct.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType;
4949
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isWholeNumber;
5050
import static org.elasticsearch.xpack.esql.core.util.CollectionUtils.nullSafeList;
51-
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.intValueOf;
51+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.intValueOf;
5252

5353
public class CountDistinct extends AggregateFunction implements OptionalArgument, ToAggregator, SurrogateExpression {
5454
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Percentile.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.SECOND;
3838
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isFoldable;
3939
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType;
40-
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.intValueOf;
40+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.intValueOf;
4141

4242
public class Percentile extends NumericAggregate implements SurrogateExpression {
4343
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Sample.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@
2525
import org.elasticsearch.xpack.esql.core.tree.Source;
2626
import org.elasticsearch.xpack.esql.core.type.DataType;
2727
import org.elasticsearch.xpack.esql.expression.function.Example;
28+
import org.elasticsearch.xpack.esql.expression.function.Foldables;
2829
import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo;
2930
import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle;
3031
import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
3132
import org.elasticsearch.xpack.esql.expression.function.FunctionType;
32-
import org.elasticsearch.xpack.esql.expression.function.FunctionUtils;
3333
import org.elasticsearch.xpack.esql.expression.function.Param;
3434
import org.elasticsearch.xpack.esql.planner.PlannerUtils;
3535
import org.elasticsearch.xpack.esql.planner.ToAggregator;
@@ -42,9 +42,9 @@
4242
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNotNull;
4343
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isRepresentableExceptCounters;
4444
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType;
45-
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.TypeResolutionValidator.forPostOptimizationValidation;
46-
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.TypeResolutionValidator.forPreOptimizationValidation;
47-
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.resolveTypeLimit;
45+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.TypeResolutionValidator.forPostOptimizationValidation;
46+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.TypeResolutionValidator.forPreOptimizationValidation;
47+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.resolveTypeLimit;
4848

4949
public class Sample extends AggregateFunction implements ToAggregator, PostOptimizationVerificationAware {
5050
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "Sample", Sample::new);
@@ -174,7 +174,7 @@ Expression limitField() {
174174
}
175175

176176
private int limitValue() {
177-
return FunctionUtils.limitValue(limitField(), sourceText());
177+
return Foldables.limitValue(limitField(), sourceText());
178178
}
179179

180180
Expression uuid() {
@@ -183,6 +183,6 @@ Expression uuid() {
183183

184184
@Override
185185
public void postOptimizationVerification(Failures failures) {
186-
FunctionUtils.resolveTypeLimit(limitField(), sourceText(), forPostOptimizationValidation(limitField(), failures));
186+
Foldables.resolveTypeLimit(limitField(), sourceText(), forPostOptimizationValidation(limitField(), failures));
187187
}
188188
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/aggregate/Top.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,10 @@
2929
import org.elasticsearch.xpack.esql.core.type.DataType;
3030
import org.elasticsearch.xpack.esql.expression.SurrogateExpression;
3131
import org.elasticsearch.xpack.esql.expression.function.Example;
32+
import org.elasticsearch.xpack.esql.expression.function.Foldables;
33+
import org.elasticsearch.xpack.esql.expression.function.Foldables.TypeResolutionValidator;
3234
import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
3335
import org.elasticsearch.xpack.esql.expression.function.FunctionType;
34-
import org.elasticsearch.xpack.esql.expression.function.FunctionUtils;
35-
import org.elasticsearch.xpack.esql.expression.function.FunctionUtils.TypeResolutionValidator;
3636
import org.elasticsearch.xpack.esql.expression.function.Param;
3737
import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput;
3838
import org.elasticsearch.xpack.esql.planner.ToAggregator;
@@ -49,8 +49,8 @@
4949
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNotNull;
5050
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString;
5151
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isType;
52-
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.TypeResolutionValidator.forPostOptimizationValidation;
53-
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.TypeResolutionValidator.forPreOptimizationValidation;
52+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.TypeResolutionValidator.forPostOptimizationValidation;
53+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.TypeResolutionValidator.forPreOptimizationValidation;
5454

5555
public class Top extends AggregateFunction implements ToAggregator, SurrogateExpression, PostOptimizationVerificationAware {
5656
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "Top", Top::new);
@@ -123,7 +123,7 @@ Expression orderField() {
123123
}
124124

125125
private Integer limitValue() {
126-
return FunctionUtils.limitValue(limitField(), sourceText());
126+
return Foldables.limitValue(limitField(), sourceText());
127127
}
128128

129129
private boolean orderValue() {
@@ -181,7 +181,7 @@ protected TypeResolution resolveType() {
181181
* During postOptimizationVerification folding is already done, so we also verify that it is definitively a literal
182182
*/
183183
private TypeResolution resolveTypeLimit() {
184-
return FunctionUtils.resolveTypeLimit(limitField(), sourceText(), forPreOptimizationValidation(limitField()));
184+
return Foldables.resolveTypeLimit(limitField(), sourceText(), forPreOptimizationValidation(limitField()));
185185
}
186186

187187
/**
@@ -238,7 +238,7 @@ public void postOptimizationVerification(Failures failures) {
238238
}
239239

240240
private void postOptimizationVerificationLimit(Failures failures) {
241-
FunctionUtils.resolveTypeLimit(limitField(), sourceText(), forPostOptimizationValidation(limitField(), failures));
241+
Foldables.resolveTypeLimit(limitField(), sourceText(), forPostOptimizationValidation(limitField(), failures));
242242
}
243243

244244
private void postOptimizationVerificationOrder(Failures failures) {

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/FullTextFunction.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@
5656
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.ParamOrdinal.DEFAULT;
5757
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isNotNull;
5858
import static org.elasticsearch.xpack.esql.core.expression.TypeResolutions.isString;
59-
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.TypeResolutionValidator.forPostOptimizationValidation;
60-
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.TypeResolutionValidator.forPreOptimizationValidation;
61-
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.resolveTypeQuery;
59+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.TypeResolutionValidator.forPostOptimizationValidation;
60+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.TypeResolutionValidator.forPreOptimizationValidation;
61+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.resolveTypeQuery;
6262

6363
/**
6464
* Base class for full-text functions that use ES queries to match documents.

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Kql.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@
1717
import org.elasticsearch.xpack.esql.core.tree.NodeInfo;
1818
import org.elasticsearch.xpack.esql.core.tree.Source;
1919
import org.elasticsearch.xpack.esql.expression.function.Example;
20+
import org.elasticsearch.xpack.esql.expression.function.Foldables;
2021
import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo;
2122
import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle;
2223
import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
23-
import org.elasticsearch.xpack.esql.expression.function.FunctionUtils;
2424
import org.elasticsearch.xpack.esql.expression.function.Param;
2525
import org.elasticsearch.xpack.esql.io.stream.PlanStreamInput;
2626
import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
@@ -95,7 +95,7 @@ protected NodeInfo<? extends Expression> info() {
9595

9696
@Override
9797
protected Query translate(LucenePushdownPredicates pushdownPredicates, TranslatorHandler handler) {
98-
return new KqlQuery(source(), FunctionUtils.queryAsString(query(), sourceText()));
98+
return new KqlQuery(source(), Foldables.queryAsString(query(), sourceText()));
9999
}
100100

101101
@Override

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/Match.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727
import org.elasticsearch.xpack.esql.core.util.Check;
2828
import org.elasticsearch.xpack.esql.core.util.NumericUtils;
2929
import org.elasticsearch.xpack.esql.expression.function.Example;
30+
import org.elasticsearch.xpack.esql.expression.function.Foldables;
3031
import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesTo;
3132
import org.elasticsearch.xpack.esql.expression.function.FunctionAppliesToLifecycle;
3233
import org.elasticsearch.xpack.esql.expression.function.FunctionInfo;
33-
import org.elasticsearch.xpack.esql.expression.function.FunctionUtils;
3434
import org.elasticsearch.xpack.esql.expression.function.MapParam;
3535
import org.elasticsearch.xpack.esql.expression.function.OptionalArgument;
3636
import org.elasticsearch.xpack.esql.expression.function.Options;
@@ -79,8 +79,8 @@
7979
import static org.elasticsearch.xpack.esql.core.type.DataType.TEXT;
8080
import static org.elasticsearch.xpack.esql.core.type.DataType.UNSIGNED_LONG;
8181
import static org.elasticsearch.xpack.esql.core.type.DataType.VERSION;
82-
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.TypeResolutionValidator.forPreOptimizationValidation;
83-
import static org.elasticsearch.xpack.esql.expression.function.FunctionUtils.resolveTypeQuery;
82+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.TypeResolutionValidator.forPreOptimizationValidation;
83+
import static org.elasticsearch.xpack.esql.expression.function.Foldables.resolveTypeQuery;
8484
import static org.elasticsearch.xpack.esql.expression.predicate.operator.comparison.EsqlBinaryComparison.formatIncompatibleTypesMessage;
8585

8686
/**
@@ -405,7 +405,7 @@ public BiConsumer<LogicalPlan, Failures> postAnalysisPlanVerification() {
405405
}
406406

407407
public Object queryAsObject() {
408-
Object queryAsObject = FunctionUtils.queryAsObject(query(), sourceText());
408+
Object queryAsObject = Foldables.queryAsObject(query(), sourceText());
409409

410410
// Convert BytesRef to string for string-based values
411411
if (queryAsObject instanceof BytesRef bytesRef) {

0 commit comments

Comments
 (0)