EvalOperator.java

1
/*
2
 * Copyright OpenSearch Contributors
3
 * SPDX-License-Identifier: Apache-2.0
4
 */
5
6
7
package org.opensearch.sql.planner.physical;
8
9
import static org.opensearch.sql.data.type.ExprCoreType.STRUCT;
10
import static org.opensearch.sql.expression.env.Environment.extendEnv;
11
12
import com.google.common.collect.ImmutableMap;
13
import com.google.common.collect.ImmutableMap.Builder;
14
import java.util.Collections;
15
import java.util.LinkedHashMap;
16
import java.util.List;
17
import java.util.Map;
18
import java.util.Map.Entry;
19
import lombok.EqualsAndHashCode;
20
import lombok.Getter;
21
import lombok.RequiredArgsConstructor;
22
import lombok.ToString;
23
import org.apache.commons.lang3.tuple.Pair;
24
import org.opensearch.sql.data.model.ExprTupleValue;
25
import org.opensearch.sql.data.model.ExprValue;
26
import org.opensearch.sql.data.model.ExprValueUtils;
27
import org.opensearch.sql.expression.Expression;
28
import org.opensearch.sql.expression.ReferenceExpression;
29
import org.opensearch.sql.expression.env.Environment;
30
31
/**
32
 * The eval operator evaluate the {@link EvalOperator#expressionList} and put the result into to
33
 * output. If the field name doesn't exist in the input, a new field will be append to the output.
34
 * If the field name exist in the input, a new value will be put into to output.
35
 *
36
 * <p>The {@link EvalOperator#expressionList} are evaluated from left to right. It means you can
37
 * reference previous evaluated field.
38
 * e.g. fields velocity = distance/time, doubleVelocity = 2 * velocity
39
 */
40
@ToString
41
@EqualsAndHashCode(callSuper = false)
42
@RequiredArgsConstructor
43
public class EvalOperator extends PhysicalPlan {
44
  @Getter
45
  private final PhysicalPlan input;
46
  @Getter
47
  private final List<Pair<ReferenceExpression, Expression>> expressionList;
48
49
  @Override
50
  public <R, C> R accept(PhysicalPlanNodeVisitor<R, C> visitor, C context) {
51 1 1. accept : replaced return value with null for org/opensearch/sql/planner/physical/EvalOperator::accept → KILLED
    return visitor.visitEval(this, context);
52
  }
53
54
  @Override
55
  public List<PhysicalPlan> getChild() {
56 1 1. getChild : replaced return value with Collections.emptyList for org/opensearch/sql/planner/physical/EvalOperator::getChild → KILLED
    return Collections.singletonList(input);
57
  }
58
59
  @Override
60
  public boolean hasNext() {
61 2 1. hasNext : replaced boolean return with true for org/opensearch/sql/planner/physical/EvalOperator::hasNext → TIMED_OUT
2. hasNext : replaced boolean return with false for org/opensearch/sql/planner/physical/EvalOperator::hasNext → KILLED
    return input.hasNext();
62
  }
63
64
  @Override
65
  public ExprValue next() {
66
    ExprValue inputValue = input.next();
67
    Map<String, ExprValue> evalMap = eval(inputValue.bindingTuples());
68
69 1 1. next : negated conditional → KILLED
    if (STRUCT == inputValue.type()) {
70
      ImmutableMap.Builder<String, ExprValue> resultBuilder = new Builder<>();
71
      Map<String, ExprValue> tupleValue = ExprValueUtils.getTupleValue(inputValue);
72
      for (Entry<String, ExprValue> valueEntry : tupleValue.entrySet()) {
73 1 1. next : negated conditional → KILLED
        if (evalMap.containsKey(valueEntry.getKey())) {
74
          resultBuilder.put(valueEntry.getKey(), evalMap.get(valueEntry.getKey()));
75
          evalMap.remove(valueEntry.getKey());
76
        } else {
77
          resultBuilder.put(valueEntry);
78
        }
79
      }
80
      resultBuilder.putAll(evalMap);
81 1 1. next : replaced return value with null for org/opensearch/sql/planner/physical/EvalOperator::next → KILLED
      return ExprTupleValue.fromExprValueMap(resultBuilder.build());
82
    } else {
83 1 1. next : replaced return value with null for org/opensearch/sql/planner/physical/EvalOperator::next → KILLED
      return inputValue;
84
    }
85
  }
86
87
  /**
88
   * Evaluate the expression in the {@link EvalOperator#expressionList} with {@link Environment}.
89
   * @param env {@link Environment}
90
   * @return The mapping of reference and {@link ExprValue} for each expression.
91
   */
92
  private Map<String, ExprValue> eval(Environment<Expression, ExprValue> env) {
93
    Map<String, ExprValue> evalResultMap = new LinkedHashMap<>();
94
    for (Pair<ReferenceExpression, Expression> pair : expressionList) {
95
      ReferenceExpression var = pair.getKey();
96
      ExprValue value = pair.getValue().valueOf(env);
97
      env = extendEnv(env, var, value);
98
      evalResultMap.put(var.toString(), value);
99
    }
100 1 1. eval : replaced return value with Collections.emptyMap for org/opensearch/sql/planner/physical/EvalOperator::eval → KILLED
    return evalResultMap;
101
  }
102
}

Mutations

51

1.1
Location : accept
Killed by : org.opensearch.sql.executor.ExplainTest.[engine:junit-jupiter]/[class:org.opensearch.sql.executor.ExplainTest]/[method:can_explain_other_operators()]
replaced return value with null for org/opensearch/sql/planner/physical/EvalOperator::accept → KILLED

56

1.1
Location : getChild
Killed by : org.opensearch.sql.executor.ExplainTest.[engine:junit-jupiter]/[class:org.opensearch.sql.executor.ExplainTest]/[method:can_explain_other_operators()]
replaced return value with Collections.emptyList for org/opensearch/sql/planner/physical/EvalOperator::getChild → KILLED

61

1.1
Location : hasNext
Killed by : org.opensearch.sql.planner.physical.EvalOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.EvalOperatorTest]/[method:do_nothing_with_none_tuple_value()]
replaced boolean return with false for org/opensearch/sql/planner/physical/EvalOperator::hasNext → KILLED

2.2
Location : hasNext
Killed by : none
replaced boolean return with true for org/opensearch/sql/planner/physical/EvalOperator::hasNext → TIMED_OUT

69

1.1
Location : next
Killed by : org.opensearch.sql.planner.physical.EvalOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.EvalOperatorTest]/[method:do_nothing_with_none_tuple_value()]
negated conditional → KILLED

73

1.1
Location : next
Killed by : org.opensearch.sql.planner.physical.EvalOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.EvalOperatorTest]/[method:create_new_field_that_contain_the_result_of_a_calculation()]
negated conditional → KILLED

81

1.1
Location : next
Killed by : org.opensearch.sql.planner.physical.EvalOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.EvalOperatorTest]/[method:create_new_field_that_contain_the_result_of_a_calculation()]
replaced return value with null for org/opensearch/sql/planner/physical/EvalOperator::next → KILLED

83

1.1
Location : next
Killed by : org.opensearch.sql.planner.physical.EvalOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.EvalOperatorTest]/[method:do_nothing_with_none_tuple_value()]
replaced return value with null for org/opensearch/sql/planner/physical/EvalOperator::next → KILLED

100

1.1
Location : eval
Killed by : org.opensearch.sql.planner.physical.EvalOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.EvalOperatorTest]/[method:create_new_field_that_contain_the_result_of_a_calculation()]
replaced return value with Collections.emptyMap for org/opensearch/sql/planner/physical/EvalOperator::eval → KILLED

Active mutators

Tests examined


Report generated by PIT 1.9.0