Skip to content

Commit 2351e39

Browse files
committed
Add comparison folding for literals
Parser now performs comparison folding for literals. Paranthesized expressions are now allowed. In the process refactored the folding code to make it more compact.
1 parent 5aca3d7 commit 2351e39

File tree

5 files changed

+221
-169
lines changed

5 files changed

+221
-169
lines changed

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/promql/ArithmeticOperation.java

Lines changed: 0 additions & 51 deletions
This file was deleted.
Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
import org.elasticsearch.xpack.esql.core.expression.predicate.operator.arithmetic.Arithmetics;
1111
import org.elasticsearch.xpack.esql.core.tree.Source;
12+
import org.elasticsearch.xpack.esql.expression.promql.predicate.operator.arithmetic.VectorBinaryArithmetic.ArithmeticOp;
13+
import org.elasticsearch.xpack.esql.expression.promql.predicate.operator.comparison.VectorBinaryComparison.ComparisonOp;
1214
import org.elasticsearch.xpack.esql.parser.ParsingException;
1315

1416
import java.time.Duration;
@@ -20,7 +22,7 @@
2022
* - Durations and numbers (converts to seconds, computes, converts back)
2123
* - Durations and durations (only for ADD/SUB)
2224
*/
23-
public class PromqlArithmeticUtils {
25+
public class PromqlFoldingUtils {
2426

2527
/**
2628
* Evaluate arithmetic operation between two scalar values at parse time.
@@ -31,7 +33,7 @@ public class PromqlArithmeticUtils {
3133
* @param operation The arithmetic operation
3234
* @return Result value (Number or Duration)
3335
*/
34-
public static Object evaluate(Source source, Object left, Object right, ArithmeticOperation operation) {
36+
public static Object evaluate(Source source, Object left, Object right, ArithmeticOp operation) {
3537
// Dispatch to appropriate handler based on operand types
3638
if (left instanceof Duration leftDuration) {
3739
if (right instanceof Duration rightDuration) {
@@ -58,14 +60,14 @@ public static Object evaluate(Source source, Object left, Object right, Arithmet
5860
/**
5961
* Duration op Duration (only ADD and SUB supported).
6062
*/
61-
private static Duration arithmetics(Source source, Duration left, Duration right, ArithmeticOperation op) {
63+
private static Duration arithmetics(Source source, Duration left, Duration right, ArithmeticOp op) {
6264
Duration result = switch (op) {
6365
case ADD -> left.plus(right);
6466
case SUB -> left.minus(right);
6567
default -> throw new ParsingException(
6668
source,
6769
"Operation [{}] not supported between two durations",
68-
op.symbol()
70+
op
6971
);
7072
};
7173

@@ -77,7 +79,7 @@ private static Duration arithmetics(Source source, Duration left, Duration right
7779
* For ADD/SUB: Number interpreted as seconds (PromQL convention).
7880
* For MUL/DIV/MOD/POW: Number is a dimensionless scalar.
7981
*/
80-
private static Duration arithmetics(Source source, Duration duration, Number scalar, ArithmeticOperation op) {
82+
private static Duration arithmetics(Source source, Duration duration, Number scalar, ArithmeticOp op) {
8183
long durationSeconds = duration.getSeconds();
8284
long scalarValue = scalar.longValue();
8385

@@ -113,15 +115,15 @@ private static Duration arithmetics(Source source, Duration duration, Number sca
113115
return Duration.ofSeconds(resultSeconds);
114116
}
115117

116-
private static Duration arithmetics(Source source, Number scalar, Duration duration, ArithmeticOperation op) {
118+
private static Duration arithmetics(Source source, Number scalar, Duration duration, ArithmeticOp op) {
117119
return switch (op) {
118-
case ADD -> arithmetics(source, duration, scalar, ArithmeticOperation.ADD);
119-
case SUB -> arithmetics(source, Duration.ofSeconds(scalar.longValue()), duration, ArithmeticOperation.SUB);
120-
case MUL -> arithmetics(source, duration, scalar, ArithmeticOperation.MUL);
120+
case ADD -> arithmetics(source, duration, scalar, ArithmeticOp.ADD);
121+
case SUB -> arithmetics(source, Duration.ofSeconds(scalar.longValue()), duration, ArithmeticOp.SUB);
122+
case MUL -> arithmetics(source, duration, scalar, ArithmeticOp.MUL);
121123
default -> throw new ParsingException(
122124
source,
123125
"Operation [{}] not supported with scalar on left and duration on right",
124-
op.symbol()
126+
op
125127
);
126128
};
127129
}
@@ -130,7 +132,7 @@ private static Duration arithmetics(Source source, Number scalar, Duration durat
130132
* Number op Number (pure numeric operations).
131133
* Delegates to Arithmetics for consistent numeric handling.
132134
*/
133-
private static Number numericArithmetics(Source source, Number left, Number right, ArithmeticOperation op) {
135+
private static Number numericArithmetics(Source source, Number left, Number right, ArithmeticOp op) {
134136
try {
135137
return switch (op) {
136138
case ADD -> Arithmetics.add(left, right);
@@ -158,6 +160,37 @@ private static Number numericArithmetics(Source source, Number left, Number righ
158160
}
159161
}
160162

163+
/**
164+
* Evaluate comparison operation between two numbers at parse time.
165+
*
166+
* @param left Left operand (Number)
167+
* @param right Right operand (Number)
168+
* @param operation The comparison operation
169+
* @return true if comparison holds, false otherwise
170+
*/
171+
public static boolean evaluate(Source source, Object left, Object right, ComparisonOp operation) {
172+
if (left instanceof Number ln && right instanceof Number rn) {
173+
// Get double values once, reuse for comparison - avoids extra allocation
174+
double l = ln.doubleValue();
175+
double r = rn.doubleValue();
176+
177+
return switch (operation) {
178+
case EQ -> l == r;
179+
case NEQ -> l != r;
180+
case GT -> l > r;
181+
case GTE -> l >= r;
182+
case LT -> l < r;
183+
case LTE -> l <= r;
184+
};
185+
}
186+
throw new ParsingException(
187+
source,
188+
"Cannot perform comparison between [{}] and [{}]",
189+
left.getClass().getSimpleName(),
190+
right.getClass().getSimpleName()
191+
);
192+
}
193+
161194
/**
162195
* Validate that duration is positive (PromQL requirement).
163196
*/

0 commit comments

Comments
 (0)