diff --git a/core/build.gradle b/core/build.gradle index 791d64df65..f5a4a4907a 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -52,7 +52,7 @@ dependencies { test { useJUnitPlatform() testLogging { - events "passed", "skipped", "failed" + events "skipped", "failed" exceptionFormat "full" } } diff --git a/core/src/main/java/org/opensearch/sql/analysis/Analyzer.java b/core/src/main/java/org/opensearch/sql/analysis/Analyzer.java index 6e87e5d663..533977197f 100644 --- a/core/src/main/java/org/opensearch/sql/analysis/Analyzer.java +++ b/core/src/main/java/org/opensearch/sql/analysis/Analyzer.java @@ -197,7 +197,9 @@ public LogicalPlan visitTableFunction(TableFunction node, AnalysisContext contex .collect(Collectors.toList()); TableFunctionImplementation tableFunctionImplementation = (TableFunctionImplementation) repository.compile(context.getFunctionProperties(), - dataSourceSchemaIdentifierNameResolver.getDataSourceName(), functionName, arguments); + dataSourceService + .getDataSource(dataSourceSchemaIdentifierNameResolver.getDataSourceName()) + .getStorageEngine().getFunctions(), functionName, arguments); context.push(); TypeEnvironment curEnv = context.peek(); Table table = tableFunctionImplementation.applyArguments(); diff --git a/core/src/main/java/org/opensearch/sql/datasource/model/DataSourceType.java b/core/src/main/java/org/opensearch/sql/datasource/model/DataSourceType.java index 1895b431c7..1d3ef6948d 100644 --- a/core/src/main/java/org/opensearch/sql/datasource/model/DataSourceType.java +++ b/core/src/main/java/org/opensearch/sql/datasource/model/DataSourceType.java @@ -8,5 +8,5 @@ public enum DataSourceType { PROMETHEUS, OPENSEARCH, - FILESYSTEM + JDBC } diff --git a/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionRepository.java b/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionRepository.java index 20f56a21cb..0eb11a9280 100644 --- a/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionRepository.java +++ b/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionRepository.java @@ -10,9 +10,12 @@ import com.google.common.annotations.VisibleForTesting; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.Pair; @@ -32,6 +35,7 @@ import org.opensearch.sql.expression.system.SystemFunctions; import org.opensearch.sql.expression.text.TextFunction; import org.opensearch.sql.expression.window.WindowFunctions; +import org.opensearch.sql.storage.StorageEngine; /** * Builtin Function Repository. @@ -40,9 +44,8 @@ * */ public class BuiltinFunctionRepository { - public static final String DEFAULT_NAMESPACE = "default"; - private final Map> namespaceFunctionResolverMap; + private final Map functionResolverMap; /** The singleton instance. */ private static BuiltinFunctionRepository instance; @@ -50,12 +53,11 @@ public class BuiltinFunctionRepository { /** * Construct a function repository with the given function registered. This is only used in test. * - * @param namespaceFunctionResolverMap function supported + * @param functionResolverMap function supported */ @VisibleForTesting - BuiltinFunctionRepository( - Map> namespaceFunctionResolverMap) { - this.namespaceFunctionResolverMap = namespaceFunctionResolverMap; + BuiltinFunctionRepository(Map functionResolverMap) { + this.functionResolverMap = functionResolverMap; } /** @@ -86,106 +88,86 @@ public static synchronized BuiltinFunctionRepository getInstance() { } /** - * Register {@link DefaultFunctionResolver} to the Builtin Function Repository - * under default namespace. + * Register {@link DefaultFunctionResolver} to the Builtin Function Repository. * * @param resolver {@link DefaultFunctionResolver} to be registered */ public void register(FunctionResolver resolver) { - register(DEFAULT_NAMESPACE, resolver); + functionResolverMap.put(resolver.getFunctionName(), resolver); } /** - * Register {@link DefaultFunctionResolver} to the Builtin Function Repository with - * specified namespace. - * - * @param resolver {@link DefaultFunctionResolver} to be registered - */ - public void register(String namespace, FunctionResolver resolver) { - Map functionResolverMap; - if (!namespaceFunctionResolverMap.containsKey(namespace)) { - functionResolverMap = new HashMap<>(); - namespaceFunctionResolverMap.put(namespace, functionResolverMap); - } - namespaceFunctionResolverMap.get(namespace).put(resolver.getFunctionName(), resolver); - } - - /** - * Compile FunctionExpression under default namespace. + * Compile FunctionExpression using core function resolver. * */ public FunctionImplementation compile(FunctionProperties functionProperties, FunctionName functionName, List expressions) { - return compile(functionProperties, DEFAULT_NAMESPACE, functionName, expressions); + return compile(functionProperties, Collections.emptyList(), functionName, expressions); } /** - * Compile FunctionExpression within given namespace. - * Checks for default namespace first and then tries to compile from given namespace. + * Compile FunctionExpression within {@link StorageEngine} provided {@link FunctionResolver}. */ public FunctionImplementation compile(FunctionProperties functionProperties, - String namespace, + Collection dataSourceFunctionResolver, FunctionName functionName, List expressions) { - List namespaceList = new ArrayList<>(List.of(DEFAULT_NAMESPACE)); - if (!namespace.equals(DEFAULT_NAMESPACE)) { - namespaceList.add(namespace); - } - FunctionBuilder resolvedFunctionBuilder = resolve( - namespaceList, new FunctionSignature(functionName, expressions - .stream().map(Expression::type).collect(Collectors.toList()))); + FunctionBuilder resolvedFunctionBuilder = + resolve( + dataSourceFunctionResolver, + new FunctionSignature( + functionName, + expressions.stream().map(Expression::type).collect(Collectors.toList()))); return resolvedFunctionBuilder.apply(functionProperties, expressions); } /** - * Resolve the {@link FunctionBuilder} in - * repository under a list of namespaces. - * Returns the First FunctionBuilder found. - * So list of namespaces is also the priority of namespaces. + * Resolve the {@link FunctionBuilder} in repository under a list of namespaces. Returns the First + * FunctionBuilder found. So list of namespaces is also the priority of namespaces. * * @param functionSignature {@link FunctionSignature} functionsignature. * @return Original function builder if it's a cast function or all arguments have expected types - * or otherwise wrap its arguments by cast function as needed. + * or otherwise wrap its arguments by cast function as needed. */ - public FunctionBuilder - resolve(List namespaces, - FunctionSignature functionSignature) { - FunctionName functionName = functionSignature.getFunctionName(); - FunctionBuilder result = null; - for (String namespace : namespaces) { - if (namespaceFunctionResolverMap.containsKey(namespace) - && namespaceFunctionResolverMap.get(namespace).containsKey(functionName)) { - result = getFunctionBuilder(functionSignature, functionName, - namespaceFunctionResolverMap.get(namespace)); - break; - } - } - if (result == null) { - throw new ExpressionEvaluationException( - String.format("unsupported function name: %s", functionName.getFunctionName())); - } else { - return result; - } + @VisibleForTesting + public FunctionBuilder resolve( + Collection dataSourceFunctionResolver, + FunctionSignature functionSignature) { + Map dataSourceFunctionMap = dataSourceFunctionResolver.stream() + .collect(Collectors.toMap(FunctionResolver::getFunctionName, t -> t)); + + // first, resolve in datasource provide function resolver. + // second, resolve in builtin function resolver. + return resolve(functionSignature, dataSourceFunctionMap) + .or(() -> resolve(functionSignature, functionResolverMap)) + .orElseThrow( + () -> + new ExpressionEvaluationException( + String.format( + "unsupported function name: %s", functionSignature.getFunctionName()))); } - private FunctionBuilder getFunctionBuilder( + private Optional resolve( FunctionSignature functionSignature, - FunctionName functionName, Map functionResolverMap) { - Pair resolvedSignature = - functionResolverMap.get(functionName).resolve(functionSignature); - - List sourceTypes = functionSignature.getParamTypeList(); - List targetTypes = resolvedSignature.getKey().getParamTypeList(); - FunctionBuilder funcBuilder = resolvedSignature.getValue(); - if (isCastFunction(functionName) - || FunctionSignature.isVarArgFunction(targetTypes) - || sourceTypes.equals(targetTypes)) { - return funcBuilder; + FunctionName functionName = functionSignature.getFunctionName(); + if (functionResolverMap.containsKey(functionName)) { + Pair resolvedSignature = + functionResolverMap.get(functionName).resolve(functionSignature); + + List sourceTypes = functionSignature.getParamTypeList(); + List targetTypes = resolvedSignature.getKey().getParamTypeList(); + FunctionBuilder funcBuilder = resolvedSignature.getValue(); + if (isCastFunction(functionName) + || FunctionSignature.isVarArgFunction(targetTypes) + || sourceTypes.equals(targetTypes)) { + return Optional.of(funcBuilder); + } + return Optional.of(castArguments(sourceTypes, targetTypes, funcBuilder)); + } else { + return Optional.empty(); } - return castArguments(sourceTypes, - targetTypes, funcBuilder); } /** diff --git a/core/src/test/java/org/opensearch/sql/analysis/AnalyzerTestBase.java b/core/src/test/java/org/opensearch/sql/analysis/AnalyzerTestBase.java index 85b8e6b068..1203232d33 100644 --- a/core/src/test/java/org/opensearch/sql/analysis/AnalyzerTestBase.java +++ b/core/src/test/java/org/opensearch/sql/analysis/AnalyzerTestBase.java @@ -7,16 +7,23 @@ package org.opensearch.sql.analysis; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opensearch.sql.analysis.DataSourceSchemaIdentifierNameResolver.DEFAULT_DATASOURCE_NAME; import static org.opensearch.sql.data.type.ExprCoreType.LONG; import static org.opensearch.sql.data.type.ExprCoreType.STRING; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import org.apache.commons.lang3.tuple.Pair; +import org.opensearch.sql.DataSourceSchemaName; import org.opensearch.sql.analysis.symbol.Namespace; import org.opensearch.sql.analysis.symbol.Symbol; import org.opensearch.sql.analysis.symbol.SymbolTable; @@ -53,6 +60,39 @@ protected StorageEngine storageEngine() { return (dataSourceSchemaName, tableName) -> table; } + protected StorageEngine prometheusStorageEngine() { + return new StorageEngine() { + @Override + public Collection getFunctions() { + return Collections.singletonList( + new FunctionResolver() { + + @Override + public Pair resolve( + FunctionSignature unresolvedSignature) { + FunctionName functionName = FunctionName.of("query_range"); + FunctionSignature functionSignature = + new FunctionSignature(functionName, List.of(STRING, LONG, LONG, LONG)); + return Pair.of( + functionSignature, + (functionProperties, args) -> + new TestTableFunctionImplementation(functionName, args, table)); + } + + @Override + public FunctionName getFunctionName() { + return FunctionName.of("query_range"); + } + }); + } + + @Override + public Table getTable(DataSourceSchemaName dataSourceSchemaName, String tableName) { + return table; + } + }; + } + protected Table table() { return Optional.ofNullable(table).orElseGet(() -> new Table() { @Override @@ -110,30 +150,11 @@ protected Environment typeEnv() { protected DataSourceService dataSourceService = dataSourceService(); - protected Analyzer analyzer = analyzer(expressionAnalyzer(), dataSourceService, table); + protected Analyzer analyzer = analyzer(expressionAnalyzer(), dataSourceService); protected Analyzer analyzer(ExpressionAnalyzer expressionAnalyzer, - DataSourceService dataSourceService, - Table table) { + DataSourceService dataSourceService) { BuiltinFunctionRepository functionRepository = BuiltinFunctionRepository.getInstance(); - functionRepository.register("prometheus", new FunctionResolver() { - - @Override - public Pair resolve( - FunctionSignature unresolvedSignature) { - FunctionName functionName = FunctionName.of("query_range"); - FunctionSignature functionSignature = - new FunctionSignature(functionName, List.of(STRING, LONG, LONG, LONG)); - return Pair.of(functionSignature, - (functionProperties, args) -> new TestTableFunctionImplementation(functionName, args, - table)); - } - - @Override - public FunctionName getFunctionName() { - return FunctionName.of("query_range"); - } - }); return new Analyzer(expressionAnalyzer, dataSourceService, functionRepository); } @@ -159,20 +180,26 @@ protected LogicalPlan analyze(UnresolvedPlan unresolvedPlan) { private class DefaultDataSourceService implements DataSourceService { - private StorageEngine storageEngine = storageEngine(); - private final DataSource dataSource - = new DataSource("prometheus", DataSourceType.PROMETHEUS, storageEngine); + private final DataSource opensearchDataSource = new DataSource(DEFAULT_DATASOURCE_NAME, + DataSourceType.OPENSEARCH, storageEngine()); + private final DataSource prometheusDataSource + = new DataSource("prometheus", DataSourceType.PROMETHEUS, prometheusStorageEngine()); @Override public Set getDataSourceMetadataSet() { - return ImmutableSet.of(new DataSourceMetadata(dataSource.getName(), - dataSource.getConnectorType(), ImmutableMap.of())); + return Stream.of(opensearchDataSource, prometheusDataSource) + .map(ds -> new DataSourceMetadata(ds.getName(), + ds.getConnectorType(), ImmutableMap.of())).collect(Collectors.toSet()); } @Override public DataSource getDataSource(String dataSourceName) { - return dataSource; + if ("prometheus".equals(dataSourceName)) { + return prometheusDataSource; + } else { + return opensearchDataSource; + } } @Override diff --git a/core/src/test/java/org/opensearch/sql/analysis/model/DataSourceSchemaIdentifierNameResolverTest.java b/core/src/test/java/org/opensearch/sql/analysis/model/DataSourceSchemaIdentifierNameResolverTest.java index 7d7c92f3ed..b36deb57f8 100644 --- a/core/src/test/java/org/opensearch/sql/analysis/model/DataSourceSchemaIdentifierNameResolverTest.java +++ b/core/src/test/java/org/opensearch/sql/analysis/model/DataSourceSchemaIdentifierNameResolverTest.java @@ -8,9 +8,15 @@ package org.opensearch.sql.analysis.model; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.opensearch.sql.analysis.DataSourceSchemaIdentifierNameResolver.DEFAULT_DATASOURCE_NAME; +import static org.opensearch.sql.analysis.DataSourceSchemaIdentifierNameResolver.DEFAULT_SCHEMA_NAME; +import static org.opensearch.sql.analysis.model.DataSourceSchemaIdentifierNameResolverTest.Identifier.identifierOf; + import java.util.Arrays; import java.util.Collections; -import org.junit.jupiter.api.Assertions; +import java.util.List; +import java.util.Set; import org.junit.jupiter.api.Test; import org.opensearch.sql.analysis.DataSourceSchemaIdentifierNameResolver; @@ -18,13 +24,57 @@ public class DataSourceSchemaIdentifierNameResolverTest { @Test void testFullyQualifiedName() { - DataSourceSchemaIdentifierNameResolver - dataSourceSchemaIdentifierNameResolver = new DataSourceSchemaIdentifierNameResolver( - Arrays.asList("prom", "information_schema", "tables"), Collections.singleton("prom")); - Assertions.assertEquals("information_schema", - dataSourceSchemaIdentifierNameResolver.getSchemaName()); - Assertions.assertEquals("prom", dataSourceSchemaIdentifierNameResolver.getDataSourceName()); - Assertions.assertEquals("tables", dataSourceSchemaIdentifierNameResolver.getIdentifierName()); + identifierOf( + Arrays.asList("prom", "information_schema", "tables"), Collections.singleton("prom")) + .datasource("prom") + .schema("information_schema") + .name("tables"); + } + + @Test + void defaultDataSourceNameResolve() { + identifierOf(Arrays.asList("tables"), Collections.emptySet()) + .datasource(DEFAULT_DATASOURCE_NAME) + .schema(DEFAULT_SCHEMA_NAME) + .name("tables"); + + identifierOf(Arrays.asList("information_schema", "tables"), Collections.emptySet()) + .datasource(DEFAULT_DATASOURCE_NAME) + .schema("information_schema") + .name("tables"); + + identifierOf( + Arrays.asList(DEFAULT_DATASOURCE_NAME, "information_schema", "tables"), + Collections.emptySet()) + .datasource(DEFAULT_DATASOURCE_NAME) + .schema("information_schema") + .name("tables"); } + static class Identifier { + private final DataSourceSchemaIdentifierNameResolver resolver; + + protected static Identifier identifierOf(List parts, Set allowedDataSources) { + return new Identifier(parts, allowedDataSources); + } + + Identifier(List parts, Set allowedDataSources) { + resolver = new DataSourceSchemaIdentifierNameResolver(parts, allowedDataSources); + } + + Identifier datasource(String expectedDatasource) { + assertEquals(expectedDatasource, resolver.getDataSourceName()); + return this; + } + + Identifier schema(String expectedSchema) { + assertEquals(expectedSchema, resolver.getSchemaName()); + return this; + } + + Identifier name(String expectedName) { + assertEquals(expectedName, resolver.getIdentifierName()); + return this; + } + } } diff --git a/core/src/test/java/org/opensearch/sql/expression/function/BuiltinFunctionRepositoryTest.java b/core/src/test/java/org/opensearch/sql/expression/function/BuiltinFunctionRepositoryTest.java index 8bba3bd9b9..98a4c32e2e 100644 --- a/core/src/test/java/org/opensearch/sql/expression/function/BuiltinFunctionRepositoryTest.java +++ b/core/src/test/java/org/opensearch/sql/expression/function/BuiltinFunctionRepositoryTest.java @@ -23,7 +23,6 @@ import static org.opensearch.sql.data.type.ExprCoreType.STRUCT; import static org.opensearch.sql.data.type.ExprCoreType.UNDEFINED; import static org.opensearch.sql.expression.function.BuiltinFunctionName.CAST_TO_BOOLEAN; -import static org.opensearch.sql.expression.function.BuiltinFunctionRepository.DEFAULT_NAMESPACE; import com.google.common.collect.ImmutableList; import java.util.Arrays; @@ -39,7 +38,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.opensearch.sql.data.model.ExprValue; -import org.opensearch.sql.data.type.ExprCoreType; import org.opensearch.sql.data.type.ExprType; import org.opensearch.sql.exception.ExpressionEvaluationException; import org.opensearch.sql.expression.Expression; @@ -49,13 +47,9 @@ @ExtendWith(MockitoExtension.class) class BuiltinFunctionRepositoryTest { - public static final String TEST_NAMESPACE = "TEST"; - @Mock private DefaultFunctionResolver mockfunctionResolver; @Mock - private Map> mockNamespaceMap; - @Mock private Map mockMap; @Mock FunctionProperties functionProperties; @@ -67,41 +61,23 @@ class BuiltinFunctionRepositoryTest { private FunctionSignature functionSignature; @Mock private Expression mockExpression; - @Mock - private Environment emptyEnv; private BuiltinFunctionRepository repo; @BeforeEach void setUp() { - repo = new BuiltinFunctionRepository(mockNamespaceMap); + repo = new BuiltinFunctionRepository(mockMap); } @Test void register() { - when(mockNamespaceMap.get(DEFAULT_NAMESPACE)).thenReturn(mockMap); - when(mockNamespaceMap.containsKey(DEFAULT_NAMESPACE)).thenReturn(true); when(mockfunctionResolver.getFunctionName()).thenReturn(mockFunctionName); - BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockNamespaceMap); + BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockMap); repo.register(mockfunctionResolver); verify(mockMap, times(1)).put(mockFunctionName, mockfunctionResolver); } - @Test - void register_under_datasource_namespace() { - when(mockNamespaceMap.containsKey(TEST_NAMESPACE)).thenReturn(false); - when(mockNamespaceMap.put(eq(TEST_NAMESPACE), any())).thenReturn(null); - when(mockNamespaceMap.get(TEST_NAMESPACE)).thenReturn(mockMap); - when(mockfunctionResolver.getFunctionName()).thenReturn(mockFunctionName); - BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockNamespaceMap); - repo.register(TEST_NAMESPACE, mockfunctionResolver); - - verify(mockNamespaceMap, times(1)).put(eq(TEST_NAMESPACE), any()); - verify(mockNamespaceMap, times(1)).get(TEST_NAMESPACE); - verify(mockMap, times(1)).put(mockFunctionName, mockfunctionResolver); - } - @Test void compile() { when(mockExpression.type()).thenReturn(UNDEFINED); @@ -109,11 +85,9 @@ void compile() { when(mockfunctionResolver.getFunctionName()).thenReturn(mockFunctionName); when(mockfunctionResolver.resolve(any())).thenReturn( Pair.of(functionSignature, functionExpressionBuilder)); - when(mockNamespaceMap.get(DEFAULT_NAMESPACE)).thenReturn(mockMap); - when(mockNamespaceMap.containsKey(DEFAULT_NAMESPACE)).thenReturn(true); when(mockMap.containsKey(mockFunctionName)).thenReturn(true); when(mockMap.get(mockFunctionName)).thenReturn(mockfunctionResolver); - BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockNamespaceMap); + BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockMap); repo.register(mockfunctionResolver); repo.compile(functionProperties, mockFunctionName, Arrays.asList(mockExpression)); @@ -121,22 +95,20 @@ void compile() { .apply(eq(functionProperties), any()); } - @Test - void compile_function_under_datasource_namespace() { + void compile_datasource_defined_function() { + DefaultFunctionResolver dataSourceFunctionResolver = mock(DefaultFunctionResolver.class); when(mockExpression.type()).thenReturn(UNDEFINED); when(functionSignature.getParamTypeList()).thenReturn(Arrays.asList(UNDEFINED)); - when(mockfunctionResolver.getFunctionName()).thenReturn(mockFunctionName); - when(mockfunctionResolver.resolve(any())).thenReturn( + when(dataSourceFunctionResolver.getFunctionName()).thenReturn(mockFunctionName); + when(dataSourceFunctionResolver.resolve(any())).thenReturn( Pair.of(functionSignature, functionExpressionBuilder)); - when(mockNamespaceMap.get(TEST_NAMESPACE)).thenReturn(mockMap); - when(mockNamespaceMap.containsKey(TEST_NAMESPACE)).thenReturn(true); - when(mockMap.containsKey(mockFunctionName)).thenReturn(true); - when(mockMap.get(mockFunctionName)).thenReturn(mockfunctionResolver); - BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockNamespaceMap); - repo.register(TEST_NAMESPACE, mockfunctionResolver); + BuiltinFunctionRepository repo = new BuiltinFunctionRepository(Map.of()); - repo.compile(functionProperties, TEST_NAMESPACE, mockFunctionName, + repo.compile( + functionProperties, + Collections.singletonList(dataSourceFunctionResolver), + mockFunctionName, Arrays.asList(mockExpression)); verify(functionExpressionBuilder, times(1)) .apply(eq(functionProperties), any()); @@ -149,23 +121,20 @@ void resolve() { when(mockfunctionResolver.getFunctionName()).thenReturn(mockFunctionName); when(mockfunctionResolver.resolve(functionSignature)).thenReturn( Pair.of(functionSignature, functionExpressionBuilder)); - when(mockNamespaceMap.get(DEFAULT_NAMESPACE)).thenReturn(mockMap); - when(mockNamespaceMap.containsKey(DEFAULT_NAMESPACE)).thenReturn(true); when(mockMap.containsKey(mockFunctionName)).thenReturn(true); when(mockMap.get(mockFunctionName)).thenReturn(mockfunctionResolver); - BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockNamespaceMap); + BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockMap); repo.register(mockfunctionResolver); assertEquals(functionExpressionBuilder, repo.resolve( - Collections.singletonList(DEFAULT_NAMESPACE), functionSignature)); + Collections.emptyList(), functionSignature)); } @Test void resolve_should_not_cast_arguments_in_cast_function() { when(mockExpression.toString()).thenReturn("string"); FunctionImplementation function = - repo.resolve( - Collections.singletonList(DEFAULT_NAMESPACE), + repo.resolve(Collections.emptyList(), registerFunctionResolver(CAST_TO_BOOLEAN.getName(), DATETIME, BOOLEAN)) .apply(functionProperties, ImmutableList.of(mockExpression)); assertEquals("cast_to_boolean(string)", function.toString()); @@ -176,8 +145,7 @@ void resolve_should_not_cast_arguments_if_same_type() { when(mockFunctionName.getFunctionName()).thenReturn("mock"); when(mockExpression.toString()).thenReturn("string"); FunctionImplementation function = - repo.resolve( - Collections.singletonList(DEFAULT_NAMESPACE), + repo.resolve(Collections.emptyList(), registerFunctionResolver(mockFunctionName, STRING, STRING)) .apply(functionProperties, ImmutableList.of(mockExpression)); assertEquals("mock(string)", function.toString()); @@ -188,8 +156,7 @@ void resolve_should_not_cast_arguments_if_both_numbers() { when(mockFunctionName.getFunctionName()).thenReturn("mock"); when(mockExpression.toString()).thenReturn("byte"); FunctionImplementation function = - repo.resolve( - Collections.singletonList(DEFAULT_NAMESPACE), + repo.resolve(Collections.emptyList(), registerFunctionResolver(mockFunctionName, BYTE, INTEGER)) .apply(functionProperties, ImmutableList.of(mockExpression)); assertEquals("mock(byte)", function.toString()); @@ -206,7 +173,7 @@ void resolve_should_cast_arguments() { registerFunctionResolver(CAST_TO_BOOLEAN.getName(), STRING, STRING); FunctionImplementation function = - repo.resolve(Collections.singletonList(DEFAULT_NAMESPACE), signature) + repo.resolve(Collections.emptyList(), signature) .apply(functionProperties, ImmutableList.of(mockExpression)); assertEquals("mock(cast_to_boolean(string))", function.toString()); } @@ -215,8 +182,7 @@ void resolve_should_cast_arguments() { void resolve_should_throw_exception_for_unsupported_conversion() { ExpressionEvaluationException error = assertThrows(ExpressionEvaluationException.class, () -> - repo.resolve( - Collections.singletonList(DEFAULT_NAMESPACE), + repo.resolve(Collections.emptyList(), registerFunctionResolver(mockFunctionName, BYTE, STRUCT)) .apply(functionProperties, ImmutableList.of(mockExpression))); assertEquals(error.getMessage(), "Type conversion to type STRUCT is not supported"); @@ -225,15 +191,12 @@ void resolve_should_throw_exception_for_unsupported_conversion() { @Test @DisplayName("resolve unregistered function should throw exception") void resolve_unregistered() { - when(mockNamespaceMap.get(DEFAULT_NAMESPACE)).thenReturn(mockMap); - when(mockNamespaceMap.containsKey(DEFAULT_NAMESPACE)).thenReturn(true); when(mockMap.containsKey(any())).thenReturn(false); - BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockNamespaceMap); + BuiltinFunctionRepository repo = new BuiltinFunctionRepository(mockMap); repo.register(mockfunctionResolver); ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class, - () -> repo.resolve( - Collections.singletonList(DEFAULT_NAMESPACE), + () -> repo.resolve(Collections.emptyList(), new FunctionSignature(FunctionName.of("unknown"), List.of()))); assertEquals("unsupported function name: unknown", exception.getMessage()); } @@ -249,8 +212,6 @@ private FunctionSignature registerFunctionResolver(FunctionName funcName, DefaultFunctionResolver funcResolver = mock(DefaultFunctionResolver.class); FunctionBuilder funcBuilder = mock(FunctionBuilder.class); - when(mockNamespaceMap.get(DEFAULT_NAMESPACE)).thenReturn(mockMap); - when(mockNamespaceMap.containsKey(DEFAULT_NAMESPACE)).thenReturn(true); when(mockMap.containsKey(eq(funcName))).thenReturn(true); when(mockMap.get(eq(funcName))).thenReturn(funcResolver); when(funcResolver.resolve(eq(unresolvedSignature))).thenReturn(