PeerRowsWindowFrame.java

1
/*
2
 * Copyright OpenSearch Contributors
3
 * SPDX-License-Identifier: Apache-2.0
4
 */
5
6
7
package org.opensearch.sql.expression.window.frame;
8
9
import com.google.common.collect.PeekingIterator;
10
import java.util.ArrayList;
11
import java.util.Collections;
12
import java.util.List;
13
import java.util.stream.Collectors;
14
import lombok.RequiredArgsConstructor;
15
import org.apache.commons.lang3.tuple.Pair;
16
import org.opensearch.sql.data.model.ExprValue;
17
import org.opensearch.sql.expression.Expression;
18
import org.opensearch.sql.expression.env.Environment;
19
import org.opensearch.sql.expression.window.WindowDefinition;
20
21
/**
22
 * Window frame that only keep peers (tuples with same value of fields specified in sort list
23
 * in window definition). See PeerWindowFrameTest for details about how this window frame
24
 * interacts with window operator and window function.
25
 */
26
@RequiredArgsConstructor
27
public class PeerRowsWindowFrame implements WindowFrame {
28
29
  private final WindowDefinition windowDefinition;
30
31
  /**
32
   * All peer rows (peer means rows in a partition that share same sort key
33
   * based on sort list in window definition.
34
   */
35
  private final List<ExprValue> peers = new ArrayList<>();
36
37
  /**
38
   * Which row in the peer is currently being enriched by window function.
39
   */
40
  private int position;
41
42
  /**
43
   * Does row at current position represents a new partition.
44
   */
45
  private boolean isNewPartition = true;
46
47
  /**
48
   * If any more pre-fetched rows not returned to window operator yet.
49
   */
50
  @Override
51
  public boolean hasNext() {
52 3 1. hasNext : changed conditional boundary → KILLED
2. hasNext : negated conditional → KILLED
3. hasNext : replaced boolean return with true for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::hasNext → KILLED
    return position < peers.size();
53
  }
54
55
  /**
56
   * Move position and clear new partition flag.
57
   * Note that because all peer rows have same result from window function,
58
   * this is only returned at first time to change window function state.
59
   * Afterwards, empty list is returned to avoid changes until next peer loaded.
60
   *
61
   * @return all rows for the peer
62
   */
63
  @Override
64
  public List<ExprValue> next() {
65
    isNewPartition = false;
66 2 1. next : Replaced integer addition with subtraction → KILLED
2. next : negated conditional → KILLED
    if (position++ == 0) {
67 1 1. next : replaced return value with Collections.emptyList for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::next → KILLED
      return peers;
68
    }
69
    return Collections.emptyList();
70
  }
71
72
  /**
73
   * Current row at the position. Because rows are pre-fetched here,
74
   * window operator needs to get them from here too.
75
   * @return row at current position that being enriched by window function
76
   */
77
  @Override
78
  public ExprValue current() {
79 1 1. current : replaced return value with null for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::current → KILLED
    return peers.get(position);
80
  }
81
82
  /**
83
   * Preload all peer rows if last peer rows done. Note that when no more data in peeking iterator,
84
   * there must be rows in frame (hasNext()=true), so no need to check it.hasNext() in this method.
85
   * Load until:
86
   *  1. Different peer found (row with different sort key)
87
   *  2. Or new partition (row with different partition key)
88
   *  3. Or no more rows
89
   * @param it  rows iterator
90
   */
91
  @Override
92
  public void load(PeekingIterator<ExprValue> it) {
93 1 1. load : negated conditional → KILLED
    if (hasNext()) {
94
      return;
95
    }
96
97
    // Reset state: reset new partition before clearing peers
98 1 1. load : negated conditional → KILLED
    isNewPartition = !isSamePartition(it.peek());
99
    position = 0;
100 1 1. load : removed call to java/util/List::clear → KILLED
    peers.clear();
101
102 1 1. load : negated conditional → KILLED
    while (it.hasNext()) {
103
      ExprValue next = it.peek();
104 1 1. load : negated conditional → KILLED
      if (peers.isEmpty()) {
105
        peers.add(it.next());
106 2 1. load : negated conditional → KILLED
2. load : negated conditional → KILLED
      } else if (isSamePartition(next) && isPeer(next)) {
107
        peers.add(it.next());
108
      } else {
109
        break;
110
      }
111
    }
112
  }
113
114
  @Override
115
  public boolean isNewPartition() {
116 2 1. isNewPartition : replaced boolean return with false for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isNewPartition → KILLED
2. isNewPartition : replaced boolean return with true for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isNewPartition → KILLED
    return isNewPartition;
117
  }
118
119
  private boolean isPeer(ExprValue next) {
120
    List<Expression> sortFields =
121
        windowDefinition.getSortList()
122
                        .stream()
123
                        .map(Pair::getRight)
124
                        .collect(Collectors.toList());
125
126 1 1. isPeer : Replaced integer subtraction with addition → KILLED
    ExprValue last = peers.get(peers.size() - 1);
127 2 1. isPeer : replaced boolean return with false for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isPeer → KILLED
2. isPeer : replaced boolean return with true for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isPeer → KILLED
    return resolve(sortFields, last).equals(resolve(sortFields, next));
128
  }
129
130
  private boolean isSamePartition(ExprValue next) {
131 1 1. isSamePartition : negated conditional → KILLED
    if (peers.isEmpty()) {
132 1 1. isSamePartition : replaced boolean return with true for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isSamePartition → KILLED
      return false;
133
    }
134
135
    List<Expression> partitionByList = windowDefinition.getPartitionByList();
136 1 1. isSamePartition : Replaced integer subtraction with addition → KILLED
    ExprValue last = peers.get(peers.size() - 1);
137 2 1. isSamePartition : replaced boolean return with false for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isSamePartition → KILLED
2. isSamePartition : replaced boolean return with true for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isSamePartition → KILLED
    return resolve(partitionByList, last).equals(resolve(partitionByList, next));
138
  }
139
140
  private List<ExprValue> resolve(List<Expression> expressions, ExprValue row) {
141
    Environment<Expression, ExprValue> valueEnv = row.bindingTuples();
142 1 1. resolve : replaced return value with Collections.emptyList for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::resolve → KILLED
    return expressions.stream()
143 1 1. lambda$resolve$0 : replaced return value with null for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::lambda$resolve$0 → KILLED
                      .map(expr -> expr.valueOf(valueEnv))
144
                      .collect(Collectors.toList());
145
  }
146
147
}

Mutations

52

1.1
Location : hasNext
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_row()]
changed conditional boundary → KILLED

2.2
Location : hasNext
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_row()]
negated conditional → KILLED

3.3
Location : hasNext
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_row()]
replaced boolean return with true for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::hasNext → KILLED

66

1.1
Location : next
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_window_definition_with_no_order_by()]
Replaced integer addition with subtraction → KILLED

2.2
Location : next
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_row()]
negated conditional → KILLED

67

1.1
Location : next
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_row()]
replaced return value with Collections.emptyList for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::next → KILLED

79

1.1
Location : current
Killed by : org.opensearch.sql.planner.physical.WindowOperatorTest.[engine:junit-jupiter]/[class:org.opensearch.sql.planner.physical.WindowOperatorTest]/[method:test_aggregate_window_function_without_sort_key()]
replaced return value with null for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::current → KILLED

93

1.1
Location : load
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_row()]
negated conditional → KILLED

98

1.1
Location : load
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_row()]
negated conditional → KILLED

100

1.1
Location : load
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_window_definition_with_no_order_by()]
removed call to java/util/List::clear → KILLED

102

1.1
Location : load
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_row()]
negated conditional → KILLED

104

1.1
Location : load
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_row()]
negated conditional → KILLED

106

1.1
Location : load
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_window_definition_with_no_order_by()]
negated conditional → KILLED

2.2
Location : load
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_window_definition_with_no_partition_by_and_order_by()]
negated conditional → KILLED

116

1.1
Location : isNewPartition
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_row()]
replaced boolean return with false for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isNewPartition → KILLED

2.2
Location : isNewPartition
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_window_definition_with_no_partition_by_and_order_by()]
replaced boolean return with true for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isNewPartition → KILLED

126

1.1
Location : isPeer
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_window_definition_with_no_partition_by_and_order_by()]
Replaced integer subtraction with addition → KILLED

127

1.1
Location : isPeer
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_window_definition_with_no_partition_by_and_order_by()]
replaced boolean return with false for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isPeer → KILLED

2.2
Location : isPeer
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_partition_with_no_more_rows_after_peers()]
replaced boolean return with true for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isPeer → KILLED

131

1.1
Location : isSamePartition
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_row()]
negated conditional → KILLED

132

1.1
Location : isSamePartition
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_single_row()]
replaced boolean return with true for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isSamePartition → KILLED

136

1.1
Location : isSamePartition
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_window_definition_with_no_order_by()]
Replaced integer subtraction with addition → KILLED

137

1.1
Location : isSamePartition
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_window_definition_with_no_partition_by_and_order_by()]
replaced boolean return with false for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isSamePartition → KILLED

2.2
Location : isSamePartition
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_window_definition_with_no_order_by()]
replaced boolean return with true for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::isSamePartition → KILLED

142

1.1
Location : resolve
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_window_definition_with_no_order_by()]
replaced return value with Collections.emptyList for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::resolve → KILLED

143

1.1
Location : lambda$resolve$0
Killed by : org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.window.frame.PeerRowsWindowFrameTest]/[method:test_window_definition_with_no_order_by()]
replaced return value with null for org/opensearch/sql/expression/window/frame/PeerRowsWindowFrame::lambda$resolve$0 → KILLED

Active mutators

Tests examined


Report generated by PIT 1.9.0