BuiltinFunctionRepository.java

1
/*
2
 * Copyright OpenSearch Contributors
3
 * SPDX-License-Identifier: Apache-2.0
4
 */
5
6
package org.opensearch.sql.expression.function;
7
8
import static org.opensearch.sql.ast.expression.Cast.getCastFunctionName;
9
import static org.opensearch.sql.ast.expression.Cast.isCastFunction;
10
11
import com.google.common.collect.ImmutableList;
12
import java.util.ArrayList;
13
import java.util.Arrays;
14
import java.util.Collection;
15
import java.util.Collections;
16
import java.util.HashMap;
17
import java.util.LinkedHashSet;
18
import java.util.List;
19
import java.util.Map;
20
import java.util.Set;
21
import java.util.TreeSet;
22
import java.util.stream.Collectors;
23
import lombok.RequiredArgsConstructor;
24
import org.apache.commons.lang3.tuple.Pair;
25
import org.opensearch.sql.common.utils.StringUtils;
26
import org.opensearch.sql.data.type.ExprCoreType;
27
import org.opensearch.sql.data.type.ExprType;
28
import org.opensearch.sql.exception.ExpressionEvaluationException;
29
import org.opensearch.sql.expression.Expression;
30
31
/**
32
 * Builtin Function Repository.
33
 * Repository registers catalog specific functions under catalog specific namespace and
34
 * universal functions under default namespace. Catalog Specific Namespace carries their own
35
 * namespace.
36
 *
37
 */
38
@RequiredArgsConstructor
39
public class BuiltinFunctionRepository {
40
41
  public static final String DEFAULT_NAMESPACE = "default";
42
43
  private final Map<String, Map<FunctionName, FunctionResolver>> namespaceFunctionResolverMap;
44
45
46
  /**
47
   * Register {@link DefaultFunctionResolver} to the Builtin Function Repository
48
   * under default namespace.
49
   *
50
   * @param resolver {@link DefaultFunctionResolver} to be registered
51
   */
52
  public void register(FunctionResolver resolver) {
53 1 1. register : removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → KILLED
    register(DEFAULT_NAMESPACE, resolver);
54
  }
55
56
  /**
57
   * Register {@link DefaultFunctionResolver} to the Builtin Function Repository with
58
   * specified namespace.
59
   *
60
   * @param resolver {@link DefaultFunctionResolver} to be registered
61
   */
62
  public void register(String namespace, FunctionResolver resolver) {
63
    Map<FunctionName, FunctionResolver> functionResolverMap;
64 1 1. register : negated conditional → KILLED
    if (!namespaceFunctionResolverMap.containsKey(namespace)) {
65
      functionResolverMap = new HashMap<>();
66
      namespaceFunctionResolverMap.put(namespace, functionResolverMap);
67
    }
68
    namespaceFunctionResolverMap.get(namespace).put(resolver.getFunctionName(), resolver);
69
  }
70
71
72
  /**
73
   * Compile FunctionExpression under default namespace.
74
   *
75
   */
76
  public FunctionImplementation compile(FunctionName functionName, List<Expression> expressions) {
77 1 1. compile : replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::compile → KILLED
    return compile(DEFAULT_NAMESPACE, functionName, expressions);
78
  }
79
80
81
  /**
82
   * Compile FunctionExpression within given namespace.
83
   * Checks for default namespace first and then tries to compile from given namespace.
84
   */
85
  public FunctionImplementation compile(String namespace, FunctionName functionName,
86
                                        List<Expression> expressions) {
87
    List<String> namespaceList = new ArrayList<>(List.of(DEFAULT_NAMESPACE));
88 1 1. compile : negated conditional → KILLED
    if (!namespace.equals(DEFAULT_NAMESPACE)) {
89
      namespaceList.add(namespace);
90
    }
91
    FunctionBuilder resolvedFunctionBuilder = resolve(namespaceList,
92
        new FunctionSignature(functionName, expressions
93 1 1. lambda$compile$0 : replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::lambda$compile$0 → KILLED
            .stream().map(expression -> expression.type()).collect(Collectors.toList())));
94 1 1. compile : replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::compile → KILLED
    return resolvedFunctionBuilder.apply(expressions);
95
  }
96
97
  /**
98
   * Resolve the {@link FunctionBuilder} in
99
   * repository under a list of namespaces.
100
   * Returns the First FunctionBuilder found.
101
   * So list of namespaces is also the priority of namespaces.
102
   *
103
   * @param functionSignature {@link FunctionSignature} functionsignature.
104
   *
105
   * @return Original function builder if it's a cast function or all arguments have expected types
106
   *         or other wise wrap its arguments by cast function as needed.
107
   */
108
  public FunctionBuilder resolve(List<String> namespaces, FunctionSignature functionSignature) {
109
    FunctionName functionName = functionSignature.getFunctionName();
110
    FunctionBuilder result = null;
111
    for (String namespace : namespaces) {
112 1 1. resolve : negated conditional → KILLED
      if (namespaceFunctionResolverMap.containsKey(namespace)
113 1 1. resolve : negated conditional → KILLED
          && namespaceFunctionResolverMap.get(namespace).containsKey(functionName)) {
114
        result = getFunctionBuilder(functionSignature, functionName,
115
            namespaceFunctionResolverMap.get(namespace));
116
        break;
117
      }
118
    }
119 1 1. resolve : negated conditional → KILLED
    if (result == null) {
120
      throw new ExpressionEvaluationException(
121
          String.format("unsupported function name: %s", functionName.getFunctionName()));
122
    } else {
123 1 1. resolve : replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::resolve → KILLED
      return result;
124
    }
125
  }
126
127
  private FunctionBuilder getFunctionBuilder(FunctionSignature functionSignature,
128
                       FunctionName functionName,
129
                       Map<FunctionName, FunctionResolver> functionResolverMap) {
130
    Pair<FunctionSignature, FunctionBuilder> resolvedSignature =
131
        functionResolverMap.get(functionName).resolve(functionSignature);
132
133
    List<ExprType> sourceTypes = functionSignature.getParamTypeList();
134
    List<ExprType> targetTypes = resolvedSignature.getKey().getParamTypeList();
135
    FunctionBuilder funcBuilder = resolvedSignature.getValue();
136 2 1. getFunctionBuilder : negated conditional → KILLED
2. getFunctionBuilder : negated conditional → KILLED
    if (isCastFunction(functionName) || sourceTypes.equals(targetTypes)) {
137 1 1. getFunctionBuilder : replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::getFunctionBuilder → KILLED
      return funcBuilder;
138
    }
139 1 1. getFunctionBuilder : replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::getFunctionBuilder → KILLED
    return castArguments(sourceTypes, targetTypes, funcBuilder);
140
  }
141
142
  /**
143
   * Wrap resolved function builder's arguments by cast function to cast input expression value
144
   * to value of target type at runtime. For example, suppose unresolved signature is
145
   * equal(BOOL,STRING) and its resolved function builder is F with signature equal(BOOL,BOOL).
146
   * In this case, wrap F and return equal(BOOL, cast_to_bool(STRING)).
147
   */
148
  private FunctionBuilder castArguments(List<ExprType> sourceTypes,
149
                                        List<ExprType> targetTypes,
150
                                        FunctionBuilder funcBuilder) {
151 1 1. castArguments : replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::castArguments → KILLED
    return arguments -> {
152
      List<Expression> argsCasted = new ArrayList<>();
153 2 1. lambda$castArguments$1 : changed conditional boundary → KILLED
2. lambda$castArguments$1 : negated conditional → KILLED
      for (int i = 0; i < arguments.size(); i++) {
154
        Expression arg = arguments.get(i);
155
        ExprType sourceType = sourceTypes.get(i);
156
        ExprType targetType = targetTypes.get(i);
157
158 1 1. lambda$castArguments$1 : negated conditional → KILLED
        if (isCastRequired(sourceType, targetType)) {
159
          argsCasted.add(cast(arg, targetType));
160
        } else {
161
          argsCasted.add(arg);
162
        }
163
      }
164 1 1. lambda$castArguments$1 : replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::lambda$castArguments$1 → KILLED
      return funcBuilder.apply(argsCasted);
165
    };
166
  }
167
168
  private boolean isCastRequired(ExprType sourceType, ExprType targetType) {
169
    // TODO: Remove this special case after fixing all failed UTs
170 1 1. isCastRequired : negated conditional → KILLED
    if (ExprCoreType.numberTypes().contains(sourceType)
171 1 1. isCastRequired : negated conditional → KILLED
        && ExprCoreType.numberTypes().contains(targetType)) {
172 1 1. isCastRequired : replaced boolean return with true for org/opensearch/sql/expression/function/BuiltinFunctionRepository::isCastRequired → KILLED
      return false;
173
    }
174 2 1. isCastRequired : replaced boolean return with false for org/opensearch/sql/expression/function/BuiltinFunctionRepository::isCastRequired → KILLED
2. isCastRequired : replaced boolean return with true for org/opensearch/sql/expression/function/BuiltinFunctionRepository::isCastRequired → KILLED
    return sourceType.shouldCast(targetType);
175
  }
176
177
  private Expression cast(Expression arg, ExprType targetType) {
178
    FunctionName castFunctionName = getCastFunctionName(targetType);
179 1 1. cast : negated conditional → KILLED
    if (castFunctionName == null) {
180
      throw new ExpressionEvaluationException(StringUtils.format(
181
          "Type conversion to type %s is not supported", targetType));
182
    }
183 1 1. cast : replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::cast → KILLED
    return (Expression) compile(castFunctionName, ImmutableList.of(arg));
184
  }
185
186
}

Mutations

53

1.1
Location : register
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:register()]
removed call to org/opensearch/sql/expression/function/BuiltinFunctionRepository::register → KILLED

64

1.1
Location : register
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:register_under_catalog_namespace()]
negated conditional → KILLED

77

1.1
Location : compile
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_cast_arguments()]
replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::compile → KILLED

88

1.1
Location : compile
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:compile_function_under_catalog_namespace()]
negated conditional → KILLED

93

1.1
Location : lambda$compile$0
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:compile_function_under_catalog_namespace()]
replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::lambda$compile$0 → KILLED

94

1.1
Location : compile
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_cast_arguments()]
replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::compile → KILLED

112

1.1
Location : resolve
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_unregistered()]
negated conditional → KILLED

113

1.1
Location : resolve
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_unregistered()]
negated conditional → KILLED

119

1.1
Location : resolve
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_unregistered()]
negated conditional → KILLED

123

1.1
Location : resolve
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve()]
replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::resolve → KILLED

136

1.1
Location : getFunctionBuilder
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_not_cast_arguments_in_cast_function()]
negated conditional → KILLED

2.2
Location : getFunctionBuilder
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve()]
negated conditional → KILLED

137

1.1
Location : getFunctionBuilder
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve()]
replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::getFunctionBuilder → KILLED

139

1.1
Location : getFunctionBuilder
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_throw_exception_for_unsupported_conversion()]
replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::getFunctionBuilder → KILLED

151

1.1
Location : castArguments
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_throw_exception_for_unsupported_conversion()]
replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::castArguments → KILLED

153

1.1
Location : lambda$castArguments$1
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_not_cast_arguments_if_both_numbers()]
changed conditional boundary → KILLED

2.2
Location : lambda$castArguments$1
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_throw_exception_for_unsupported_conversion()]
negated conditional → KILLED

158

1.1
Location : lambda$castArguments$1
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_throw_exception_for_unsupported_conversion()]
negated conditional → KILLED

164

1.1
Location : lambda$castArguments$1
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_not_cast_arguments_if_both_numbers()]
replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::lambda$castArguments$1 → KILLED

170

1.1
Location : isCastRequired
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_not_cast_arguments_if_both_numbers()]
negated conditional → KILLED

171

1.1
Location : isCastRequired
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_throw_exception_for_unsupported_conversion()]
negated conditional → KILLED

172

1.1
Location : isCastRequired
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_not_cast_arguments_if_both_numbers()]
replaced boolean return with true for org/opensearch/sql/expression/function/BuiltinFunctionRepository::isCastRequired → KILLED

174

1.1
Location : isCastRequired
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_throw_exception_for_unsupported_conversion()]
replaced boolean return with false for org/opensearch/sql/expression/function/BuiltinFunctionRepository::isCastRequired → KILLED

2.2
Location : isCastRequired
Killed by : org.opensearch.sql.expression.datetime.DateTimeFunctionTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.datetime.DateTimeFunctionTest]/[method:date_add()]
replaced boolean return with true for org/opensearch/sql/expression/function/BuiltinFunctionRepository::isCastRequired → KILLED

179

1.1
Location : cast
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_throw_exception_for_unsupported_conversion()]
negated conditional → KILLED

183

1.1
Location : cast
Killed by : org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest.[engine:junit-jupiter]/[class:org.opensearch.sql.expression.function.BuiltinFunctionRepositoryTest]/[method:resolve_should_cast_arguments()]
replaced return value with null for org/opensearch/sql/expression/function/BuiltinFunctionRepository::cast → KILLED

Active mutators

Tests examined


Report generated by PIT 1.9.0