SymbolTable.java

1
/*
2
 * Copyright OpenSearch Contributors
3
 * SPDX-License-Identifier: Apache-2.0
4
 */
5
6
7
package org.opensearch.sql.analysis.symbol;
8
9
import static java.util.Collections.emptyMap;
10
import static java.util.Collections.emptyNavigableMap;
11
12
import java.util.EnumMap;
13
import java.util.LinkedHashMap;
14
import java.util.Map;
15
import java.util.NavigableMap;
16
import java.util.Optional;
17
import java.util.TreeMap;
18
import org.opensearch.sql.data.type.ExprType;
19
20
/**
21
 * Symbol table for symbol definition and resolution.
22
 */
23
public class SymbolTable {
24
25
  /**
26
   * Two-dimension hash table to manage symbols with type in different namespace.
27
   */
28
  private Map<Namespace, NavigableMap<String, ExprType>> tableByNamespace =
29
      new EnumMap<>(Namespace.class);
30
31
  /**
32
   * Two-dimension hash table to manage symbols with type in different namespace.
33
   * Comparing with tableByNamespace, orderedTable use the LinkedHashMap to keep the order of
34
   * symbol.
35
   */
36
  private Map<Namespace, LinkedHashMap<String, ExprType>> orderedTable =
37
      new EnumMap<>(Namespace.class);
38
39
  /**
40
   * Store symbol with the type. Create new map for namespace for the first time.
41
   *
42
   * @param symbol symbol to define
43
   * @param type   symbol type
44
   */
45
  public void store(Symbol symbol, ExprType type) {
46
    tableByNamespace.computeIfAbsent(
47
        symbol.getNamespace(),
48 1 1. lambda$store$0 : replaced return value with null for org/opensearch/sql/analysis/symbol/SymbolTable::lambda$store$0 → KILLED
        ns -> new TreeMap<>()
49
    ).put(symbol.getName(), type);
50
51
    orderedTable.computeIfAbsent(
52
        symbol.getNamespace(),
53 1 1. lambda$store$1 : replaced return value with null for org/opensearch/sql/analysis/symbol/SymbolTable::lambda$store$1 → KILLED
        ns -> new LinkedHashMap<>()
54
    ).put(symbol.getName(), type);
55
  }
56
57
  /**
58
   * Remove a symbol from SymbolTable.
59
   */
60
  public void remove(Symbol symbol) {
61
    tableByNamespace.computeIfPresent(
62
        symbol.getNamespace(),
63
        (k, v) -> {
64
          v.remove(symbol.getName());
65 1 1. lambda$remove$2 : replaced return value with null for org/opensearch/sql/analysis/symbol/SymbolTable::lambda$remove$2 → SURVIVED
          return v;
66
        }
67
    );
68
    orderedTable.computeIfPresent(
69
        symbol.getNamespace(),
70
        (k, v) -> {
71
          v.remove(symbol.getName());
72 1 1. lambda$remove$3 : replaced return value with null for org/opensearch/sql/analysis/symbol/SymbolTable::lambda$remove$3 → KILLED
          return v;
73
        }
74
    );
75
  }
76
77
  /**
78
   * Look up symbol in the namespace map.
79
   *
80
   * @param symbol symbol to look up
81
   * @return symbol type which is optional
82
   */
83
  public Optional<ExprType> lookup(Symbol symbol) {
84
    Map<String, ExprType> table = tableByNamespace.get(symbol.getNamespace());
85
    ExprType type = null;
86 1 1. lookup : negated conditional → KILLED
    if (table != null) {
87
      type = table.get(symbol.getName());
88
    }
89 1 1. lookup : replaced return value with Optional.empty for org/opensearch/sql/analysis/symbol/SymbolTable::lookup → KILLED
    return Optional.ofNullable(type);
90
  }
91
92
  /**
93
   * Look up symbols by a prefix.
94
   *
95
   * @param prefix a symbol prefix
96
   * @return symbols starting with the prefix
97
   */
98
  public Map<String, ExprType> lookupByPrefix(Symbol prefix) {
99
    NavigableMap<String, ExprType> table = tableByNamespace.get(prefix.getNamespace());
100 1 1. lookupByPrefix : negated conditional → KILLED
    if (table != null) {
101 1 1. lookupByPrefix : replaced return value with Collections.emptyMap for org/opensearch/sql/analysis/symbol/SymbolTable::lookupByPrefix → KILLED
      return table.subMap(prefix.getName(), prefix.getName() + Character.MAX_VALUE);
102
    }
103
    return emptyMap();
104
  }
105
106
  /**
107
   * Look up all top level symbols in the namespace.
108
   * this function is mainly used by SELECT * use case to get the top level fields
109
   * Todo. currently, the top level fields is the field which doesn't include "." in the name or
110
   * the prefix doesn't exist in the symbol table.
111
   * e.g. The symbol table includes person, person.name, person/2.0.
112
   * person, is the top level field
113
   * person.name, isn't the top level field, because the prefix (person) in symbol table
114
   * person/2.0, is the top level field, because the prefix (person/2) isn't in symbol table
115
   *
116
   * @param namespace     a namespace
117
   * @return              all symbols in the namespace map
118
   */
119
  public Map<String, ExprType> lookupAllFields(Namespace namespace) {
120
    final LinkedHashMap<String, ExprType> allSymbols =
121
        orderedTable.getOrDefault(namespace, new LinkedHashMap<>());
122
    final LinkedHashMap<String, ExprType> results = new LinkedHashMap<>();
123
    allSymbols.entrySet().stream().filter(entry -> {
124
      String symbolName = entry.getKey();
125
      int lastDot = symbolName.lastIndexOf(".");
126 3 1. lambda$lookupAllFields$4 : negated conditional → KILLED
2. lambda$lookupAllFields$4 : negated conditional → KILLED
3. lambda$lookupAllFields$4 : replaced boolean return with true for org/opensearch/sql/analysis/symbol/SymbolTable::lambda$lookupAllFields$4 → KILLED
      return -1 == lastDot || !allSymbols.containsKey(symbolName.substring(0, lastDot));
127 1 1. lookupAllFields : removed call to java/util/stream/Stream::forEach → KILLED
    }).forEach(entry -> results.put(entry.getKey(), entry.getValue()));
128 1 1. lookupAllFields : replaced return value with Collections.emptyMap for org/opensearch/sql/analysis/symbol/SymbolTable::lookupAllFields → KILLED
    return results;
129
  }
130
131
  /**
132
   * Check if namespace map in empty (none definition).
133
   *
134
   * @param namespace a namespace
135
   * @return true for empty
136
   */
137
  public boolean isEmpty(Namespace namespace) {
138 2 1. isEmpty : replaced boolean return with true for org/opensearch/sql/analysis/symbol/SymbolTable::isEmpty → SURVIVED
2. isEmpty : replaced boolean return with false for org/opensearch/sql/analysis/symbol/SymbolTable::isEmpty → KILLED
    return tableByNamespace.getOrDefault(namespace, emptyNavigableMap()).isEmpty();
139
  }
140
}

Mutations

48

1.1
Location : lambda$store$0
Killed by : org.opensearch.sql.analysis.symbol.SymbolTableTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.symbol.SymbolTableTest]/[method:failedToResolveSymbolNoNamespaceMatched()]
replaced return value with null for org/opensearch/sql/analysis/symbol/SymbolTable::lambda$store$0 → KILLED

53

1.1
Location : lambda$store$1
Killed by : org.opensearch.sql.analysis.symbol.SymbolTableTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.symbol.SymbolTableTest]/[method:failedToResolveSymbolNoNamespaceMatched()]
replaced return value with null for org/opensearch/sql/analysis/symbol/SymbolTable::lambda$store$1 → KILLED

65

1.1
Location : lambda$remove$2
Killed by : none
replaced return value with null for org/opensearch/sql/analysis/symbol/SymbolTable::lambda$remove$2 → SURVIVED

72

1.1
Location : lambda$remove$3
Killed by : org.opensearch.sql.analysis.SelectAnalyzeTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.SelectAnalyzeTest]/[method:rename_and_project_all()]
replaced return value with null for org/opensearch/sql/analysis/symbol/SymbolTable::lambda$remove$3 → KILLED

86

1.1
Location : lookup
Killed by : org.opensearch.sql.analysis.symbol.SymbolTableTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.symbol.SymbolTableTest]/[method:failedToResolveSymbolNoNamespaceMatched()]
negated conditional → KILLED

89

1.1
Location : lookup
Killed by : org.opensearch.sql.analysis.symbol.SymbolTableTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.symbol.SymbolTableTest]/[method:defineFieldSymbolShouldBeAbleToResolve()]
replaced return value with Optional.empty for org/opensearch/sql/analysis/symbol/SymbolTable::lookup → KILLED

100

1.1
Location : lookupByPrefix
Killed by : org.opensearch.sql.analysis.symbol.SymbolTableTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.symbol.SymbolTableTest]/[method:failedToResolveSymbolNoNamespaceMatched()]
negated conditional → KILLED

101

1.1
Location : lookupByPrefix
Killed by : org.opensearch.sql.analysis.symbol.SymbolTableTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.symbol.SymbolTableTest]/[method:defineFieldSymbolShouldBeAbleToResolveByPrefix()]
replaced return value with Collections.emptyMap for org/opensearch/sql/analysis/symbol/SymbolTable::lookupByPrefix → KILLED

126

1.1
Location : lambda$lookupAllFields$4
Killed by : org.opensearch.sql.analysis.symbol.SymbolTableTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.symbol.SymbolTableTest]/[method:lookupAllFieldsReturnUnnestedFields()]
negated conditional → KILLED

2.2
Location : lambda$lookupAllFields$4
Killed by : org.opensearch.sql.analysis.symbol.SymbolTableTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.symbol.SymbolTableTest]/[method:lookupAllFieldsReturnUnnestedFields()]
negated conditional → KILLED

3.3
Location : lambda$lookupAllFields$4
Killed by : org.opensearch.sql.analysis.symbol.SymbolTableTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.symbol.SymbolTableTest]/[method:lookupAllFieldsReturnUnnestedFields()]
replaced boolean return with true for org/opensearch/sql/analysis/symbol/SymbolTable::lambda$lookupAllFields$4 → KILLED

127

1.1
Location : lookupAllFields
Killed by : org.opensearch.sql.analysis.symbol.SymbolTableTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.symbol.SymbolTableTest]/[method:lookupAllFieldsReturnUnnestedFields()]
removed call to java/util/stream/Stream::forEach → KILLED

128

1.1
Location : lookupAllFields
Killed by : org.opensearch.sql.analysis.symbol.SymbolTableTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.symbol.SymbolTableTest]/[method:lookupAllFieldsReturnUnnestedFields()]
replaced return value with Collections.emptyMap for org/opensearch/sql/analysis/symbol/SymbolTable::lookupAllFields → KILLED

138

1.1
Location : isEmpty
Killed by : org.opensearch.sql.analysis.symbol.SymbolTableTest.[engine:junit-jupiter]/[class:org.opensearch.sql.analysis.symbol.SymbolTableTest]/[method:isEmpty()]
replaced boolean return with false for org/opensearch/sql/analysis/symbol/SymbolTable::isEmpty → KILLED

2.2
Location : isEmpty
Killed by : none
replaced boolean return with true for org/opensearch/sql/analysis/symbol/SymbolTable::isEmpty → SURVIVED

Active mutators

Tests examined


Report generated by PIT 1.9.0