1 | /* | |
2 | * Copyright OpenSearch Contributors | |
3 | * SPDX-License-Identifier: Apache-2.0 | |
4 | */ | |
5 | ||
6 | ||
7 | package org.opensearch.sql.expression.aggregation; | |
8 | ||
9 | import java.util.List; | |
10 | import lombok.EqualsAndHashCode; | |
11 | import lombok.Getter; | |
12 | import lombok.RequiredArgsConstructor; | |
13 | import lombok.Setter; | |
14 | import lombok.experimental.Accessors; | |
15 | import org.opensearch.sql.analysis.ExpressionAnalyzer; | |
16 | import org.opensearch.sql.data.model.ExprValue; | |
17 | import org.opensearch.sql.data.model.ExprValueUtils; | |
18 | import org.opensearch.sql.data.type.ExprCoreType; | |
19 | import org.opensearch.sql.data.type.ExprType; | |
20 | import org.opensearch.sql.exception.ExpressionEvaluationException; | |
21 | import org.opensearch.sql.expression.Expression; | |
22 | import org.opensearch.sql.expression.ExpressionNodeVisitor; | |
23 | import org.opensearch.sql.expression.env.Environment; | |
24 | import org.opensearch.sql.expression.function.FunctionImplementation; | |
25 | import org.opensearch.sql.expression.function.FunctionName; | |
26 | import org.opensearch.sql.storage.bindingtuple.BindingTuple; | |
27 | ||
28 | /** | |
29 | * Aggregator which will iterate on the {@link BindingTuple}s to aggregate the result. | |
30 | * The Aggregator is not well fit into Expression, because it has side effect. | |
31 | * But we still want to make it implement {@link Expression} interface to make | |
32 | * {@link ExpressionAnalyzer} easier. | |
33 | */ | |
34 | @EqualsAndHashCode | |
35 | @RequiredArgsConstructor | |
36 | public abstract class Aggregator<S extends AggregationState> | |
37 | implements FunctionImplementation, Expression { | |
38 | @Getter | |
39 | private final FunctionName functionName; | |
40 | @Getter | |
41 | private final List<Expression> arguments; | |
42 | protected final ExprCoreType returnType; | |
43 | @Setter | |
44 | @Getter | |
45 | @Accessors(fluent = true) | |
46 | protected Expression condition; | |
47 | @Setter | |
48 | @Getter | |
49 | @Accessors(fluent = true) | |
50 | protected Boolean distinct = false; | |
51 | ||
52 | /** | |
53 | * Create an {@link AggregationState} which will be used for aggregation. | |
54 | */ | |
55 | public abstract S create(); | |
56 | ||
57 | /** | |
58 | * Iterate on {@link ExprValue}. | |
59 | * @param value {@link ExprValue} | |
60 | * @param state {@link AggregationState} | |
61 | * @return {@link AggregationState} | |
62 | */ | |
63 | protected abstract S iterate(ExprValue value, S state); | |
64 | ||
65 | /** | |
66 | * Let the aggregator iterate on the {@link BindingTuple} | |
67 | * To filter out ExprValues that are missing, null or cannot satisfy {@link #condition} | |
68 | * Before the specific aggregator iterating ExprValue in the tuple. | |
69 | * | |
70 | * @param tuple {@link BindingTuple} | |
71 | * @param state {@link AggregationState} | |
72 | * @return {@link AggregationState} | |
73 | */ | |
74 | public S iterate(BindingTuple tuple, S state) { | |
75 | ExprValue value = getArguments().get(0).valueOf(tuple); | |
76 |
3
1. iterate : negated conditional → KILLED 2. iterate : negated conditional → KILLED 3. iterate : negated conditional → KILLED |
if (value.isNull() || value.isMissing() || !conditionValue(tuple)) { |
77 |
1
1. iterate : replaced return value with null for org/opensearch/sql/expression/aggregation/Aggregator::iterate → SURVIVED |
return state; |
78 | } | |
79 |
1
1. iterate : replaced return value with null for org/opensearch/sql/expression/aggregation/Aggregator::iterate → KILLED |
return iterate(value, state); |
80 | } | |
81 | ||
82 | @Override | |
83 | public ExprValue valueOf(Environment<Expression, ExprValue> valueEnv) { | |
84 | throw new ExpressionEvaluationException( | |
85 | String.format("can't evaluate on aggregator: %s", functionName)); | |
86 | } | |
87 | ||
88 | @Override | |
89 | public ExprType type() { | |
90 |
1
1. type : replaced return value with null for org/opensearch/sql/expression/aggregation/Aggregator::type → KILLED |
return returnType; |
91 | } | |
92 | ||
93 | @Override | |
94 | public <T, C> T accept(ExpressionNodeVisitor<T, C> visitor, C context) { | |
95 |
1
1. accept : replaced return value with null for org/opensearch/sql/expression/aggregation/Aggregator::accept → KILLED |
return visitor.visitAggregator(this, context); |
96 | } | |
97 | ||
98 | /** | |
99 | * Util method to get value of condition in aggregation filter. | |
100 | */ | |
101 | public boolean conditionValue(BindingTuple tuple) { | |
102 |
1
1. conditionValue : negated conditional → KILLED |
if (condition == null) { |
103 |
1
1. conditionValue : replaced boolean return with false for org/opensearch/sql/expression/aggregation/Aggregator::conditionValue → KILLED |
return true; |
104 | } | |
105 |
2
1. conditionValue : replaced boolean return with false for org/opensearch/sql/expression/aggregation/Aggregator::conditionValue → KILLED 2. conditionValue : replaced boolean return with true for org/opensearch/sql/expression/aggregation/Aggregator::conditionValue → KILLED |
return ExprValueUtils.getBooleanValue(condition.valueOf(tuple)); |
106 | } | |
107 | ||
108 | } | |
Mutations | ||
76 |
1.1 2.2 3.3 |
|
77 |
1.1 |
|
79 |
1.1 |
|
90 |
1.1 |
|
95 |
1.1 |
|
102 |
1.1 |
|
103 |
1.1 |
|
105 |
1.1 2.2 |