diff --git a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java index 33c1fb4aac3..fb63266885e 100644 --- a/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java +++ b/x-pack/plugin/sql/src/main/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistry.java @@ -94,18 +94,16 @@ import org.elasticsearch.xpack.sql.parser.ParsingException; import org.elasticsearch.xpack.sql.session.Configuration; import org.elasticsearch.xpack.sql.tree.Location; import org.elasticsearch.xpack.sql.type.DataType; -import org.elasticsearch.xpack.sql.util.StringUtils; +import org.elasticsearch.xpack.sql.util.Check; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; -import java.util.Set; import java.util.TimeZone; import java.util.function.BiFunction; import java.util.regex.Pattern; @@ -117,14 +115,6 @@ import static java.util.stream.Collectors.toList; public class FunctionRegistry { - private static final Set EXCLUDE_FROM_NAME_NORMALIZATION = new HashSet<>(); - - static { - EXCLUDE_FROM_NAME_NORMALIZATION.add(IfNull.class.getSimpleName()); - EXCLUDE_FROM_NAME_NORMALIZATION.add(NullIf.class.getSimpleName()); - } - - // list of functions grouped by type of functions (aggregate, statistics, math etc) and ordered alphabetically inside each group // a single function will have one entry for itself with its name associated to its instance and, also, one entry for each alias // it has with the alias name associated to the FunctionDefinition instance @@ -147,99 +137,99 @@ public class FunctionRegistry { private void defineDefaultFunctions() { // Aggregate functions - addToMap(def(Avg.class, Avg::new), - def(Count.class, Count::new), - def(Max.class, Max::new), - def(Min.class, Min::new), - def(Sum.class, Sum::new)); + addToMap(def(Avg.class, Avg::new, "AVG"), + def(Count.class, Count::new, "COUNT"), + def(Max.class, Max::new, "MAX"), + def(Min.class, Min::new, "MIN"), + def(Sum.class, Sum::new, "SUM")); // Statistics - addToMap(def(StddevPop.class, StddevPop::new), - def(VarPop.class, VarPop::new), - def(Percentile.class, Percentile::new), - def(PercentileRank.class, PercentileRank::new), - def(SumOfSquares.class, SumOfSquares::new), - def(Skewness.class, Skewness::new), - def(Kurtosis.class, Kurtosis::new)); + addToMap(def(StddevPop.class, StddevPop::new, "STDDEV_POP"), + def(VarPop.class, VarPop::new,"VAR_POP"), + def(Percentile.class, Percentile::new, "PERCENTILE"), + def(PercentileRank.class, PercentileRank::new, "PERCENTILE_RANK"), + def(SumOfSquares.class, SumOfSquares::new, "SUM_OF_SQUARES"), + def(Skewness.class, Skewness::new, "SKEWNESS"), + def(Kurtosis.class, Kurtosis::new, "KURTOSIS")); // Scalar functions // conditional - addToMap(def(Coalesce.class, Coalesce::new), - def(IfNull.class, IfNull::new, "ISNULL", "NVL"), - def(NullIf.class, NullIf::new), - def(Greatest.class, Greatest::new), - def(Least.class, Least::new)); + addToMap(def(Coalesce.class, Coalesce::new, "COALESCE"), + def(IfNull.class, IfNull::new, "IFNULL", "ISNULL", "NVL"), + def(NullIf.class, NullIf::new, "NULLIF"), + def(Greatest.class, Greatest::new, "GREATEST"), + def(Least.class, Least::new, "LEAST")); // Date - addToMap(def(DayName.class, DayName::new, "DAYNAME"), - def(DayOfMonth.class, DayOfMonth::new, "DAYOFMONTH", "DAY", "DOM"), - def(DayOfWeek.class, DayOfWeek::new, "DAYOFWEEK", "DOW"), - def(DayOfYear.class, DayOfYear::new, "DAYOFYEAR", "DOY"), - def(HourOfDay.class, HourOfDay::new, "HOUR"), - def(MinuteOfDay.class, MinuteOfDay::new), - def(MinuteOfHour.class, MinuteOfHour::new, "MINUTE"), - def(MonthName.class, MonthName::new, "MONTHNAME"), - def(MonthOfYear.class, MonthOfYear::new, "MONTH"), - def(SecondOfMinute.class, SecondOfMinute::new, "SECOND"), - def(Quarter.class, Quarter::new), - def(Year.class, Year::new), - def(WeekOfYear.class, WeekOfYear::new, "WEEK")); + addToMap(def(DayName.class, DayName::new, "DAY_NAME", "DAYNAME"), + def(DayOfMonth.class, DayOfMonth::new, "DAY_OF_MONTH", "DAYOFMONTH", "DAY", "DOM"), + def(DayOfWeek.class, DayOfWeek::new, "DAY_OF_WEEK", "DAYOFWEEK", "DOW"), + def(DayOfYear.class, DayOfYear::new, "DAY_OF_YEAR", "DAYOFYEAR", "DOY"), + def(HourOfDay.class, HourOfDay::new, "HOUR_OF_DAY", "HOUR"), + def(MinuteOfDay.class, MinuteOfDay::new, "MINUTE_OF_DAY"), + def(MinuteOfHour.class, MinuteOfHour::new, "MINUTE_OF_HOUR", "MINUTE"), + def(MonthName.class, MonthName::new, "MONTH_NAME", "MONTHNAME"), + def(MonthOfYear.class, MonthOfYear::new, "MONTH_OF_YEAR", "MONTH"), + def(SecondOfMinute.class, SecondOfMinute::new, "SECOND_OF_MINUTE", "SECOND"), + def(Quarter.class, Quarter::new, "QUARTER"), + def(Year.class, Year::new, "YEAR"), + def(WeekOfYear.class, WeekOfYear::new, "WEEK_OF_YEAR", "WEEK")); // Math - addToMap(def(Abs.class, Abs::new), - def(ACos.class, ACos::new), - def(ASin.class, ASin::new), - def(ATan.class, ATan::new), - def(ATan2.class, ATan2::new), - def(Cbrt.class, Cbrt::new), - def(Ceil.class, Ceil::new, "CEILING"), - def(Cos.class, Cos::new), - def(Cosh.class, Cosh::new), - def(Cot.class, Cot::new), - def(Degrees.class, Degrees::new), - def(E.class, E::new), - def(Exp.class, Exp::new), - def(Expm1.class, Expm1::new), - def(Floor.class, Floor::new), - def(Log.class, Log::new), - def(Log10.class, Log10::new), + addToMap(def(Abs.class, Abs::new, "ABS"), + def(ACos.class, ACos::new, "ACOS"), + def(ASin.class, ASin::new, "ASIN"), + def(ATan.class, ATan::new, "ATAN"), + def(ATan2.class, ATan2::new, "ATAN2"), + def(Cbrt.class, Cbrt::new, "CBRT"), + def(Ceil.class, Ceil::new, "CEIL", "CEILING"), + def(Cos.class, Cos::new, "COS"), + def(Cosh.class, Cosh::new, "COSH"), + def(Cot.class, Cot::new, "COT"), + def(Degrees.class, Degrees::new, "DEGREES"), + def(E.class, E::new, "E"), + def(Exp.class, Exp::new, "EXP"), + def(Expm1.class, Expm1::new, "EXPM1"), + def(Floor.class, Floor::new, "FLOOR"), + def(Log.class, Log::new, "LOG"), + def(Log10.class, Log10::new, "LOG10"), // SQL and ODBC require MOD as a _function_ - def(Mod.class, Mod::new), - def(Pi.class, Pi::new), - def(Power.class, Power::new), - def(Radians.class, Radians::new), - def(Random.class, Random::new, "RAND"), - def(Round.class, Round::new), - def(Sign.class, Sign::new, "SIGNUM"), - def(Sin.class, Sin::new), - def(Sinh.class, Sinh::new), - def(Sqrt.class, Sqrt::new), - def(Tan.class, Tan::new), - def(Truncate.class, Truncate::new)); + def(Mod.class, Mod::new, "MOD"), + def(Pi.class, Pi::new, "PI"), + def(Power.class, Power::new, "POWER"), + def(Radians.class, Radians::new, "RADIANS"), + def(Random.class, Random::new, "RANDOM", "RAND"), + def(Round.class, Round::new, "ROUND"), + def(Sign.class, Sign::new, "SIGN", "SIGNUM"), + def(Sin.class, Sin::new, "SIN"), + def(Sinh.class, Sinh::new, "SINH"), + def(Sqrt.class, Sqrt::new, "SQRT"), + def(Tan.class, Tan::new, "TAN"), + def(Truncate.class, Truncate::new, "TRUNCATE")); // String - addToMap(def(Ascii.class, Ascii::new), - def(BitLength.class, BitLength::new), - def(Char.class, Char::new), - def(CharLength.class, CharLength::new, "CHARACTER_LENGTH"), - def(Concat.class, Concat::new), - def(Insert.class, Insert::new), - def(LCase.class, LCase::new), - def(Left.class, Left::new), - def(Length.class, Length::new), - def(Locate.class, Locate::new), - def(LTrim.class, LTrim::new), - def(OctetLength.class, OctetLength::new), - def(Position.class, Position::new), - def(Repeat.class, Repeat::new), - def(Replace.class, Replace::new), - def(Right.class, Right::new), - def(RTrim.class, RTrim::new), - def(Space.class, Space::new), - def(Substring.class, Substring::new), - def(UCase.class, UCase::new)); + addToMap(def(Ascii.class, Ascii::new, "ASCII"), + def(BitLength.class, BitLength::new, "BIT_LENGTH"), + def(Char.class, Char::new, "CHAR"), + def(CharLength.class, CharLength::new, "CHAR_LENGTH", "CHARACTER_LENGTH"), + def(Concat.class, Concat::new, "CONCAT"), + def(Insert.class, Insert::new, "INSERT"), + def(LCase.class, LCase::new, "LCASE"), + def(Left.class, Left::new, "LEFT"), + def(Length.class, Length::new, "LENGTH"), + def(Locate.class, Locate::new, "LOCATE"), + def(LTrim.class, LTrim::new, "LTRIM"), + def(OctetLength.class, OctetLength::new, "OCTET_LENGTH"), + def(Position.class, Position::new, "POSITION"), + def(Repeat.class, Repeat::new, "REPEAT"), + def(Replace.class, Replace::new, "REPLACE"), + def(Right.class, Right::new, "RIGHT"), + def(RTrim.class, RTrim::new, "RTRIM"), + def(Space.class, Space::new, "SPACE"), + def(Substring.class, Substring::new, "SUBSTRING"), + def(UCase.class, UCase::new, "UCASE")); // DataType conversion - addToMap(def(Cast.class, Cast::new, "CONVERT")); + addToMap(def(Cast.class, Cast::new, "CAST", "CONVERT")); // Scalar "meta" functions - addToMap(def(Database.class, Database::new), - def(User.class, User::new)); + addToMap(def(Database.class, Database::new, "DATABASE"), + def(User.class, User::new, "USER")); // Special - addToMap(def(Score.class, Score::new)); + addToMap(def(Score.class, Score::new, "SCORE")); } void addToMap(FunctionDefinition...functions) { @@ -293,7 +283,7 @@ public class FunctionRegistry { public Collection listFunctions(String pattern) { // It is worth double checking if we need this copy. These are immutable anyway. - Pattern p = Strings.hasText(pattern) ? Pattern.compile(normalize(pattern)) : null; + Pattern p = Strings.hasText(pattern) ? Pattern.compile(pattern.toUpperCase(Locale.ROOT)) : null; return defs.entrySet().stream() .filter(e -> p == null || p.matcher(e.getKey()).matches()) .map(e -> new FunctionDefinition(e.getKey(), emptyList(), @@ -306,7 +296,7 @@ public class FunctionRegistry { * is not aware of time zone and does not support {@code DISTINCT}. */ static FunctionDefinition def(Class function, - java.util.function.Function ctorRef, String... aliases) { + java.util.function.Function ctorRef, String... names) { FunctionBuilder builder = (location, children, distinct, cfg) -> { if (false == children.isEmpty()) { throw new IllegalArgumentException("expects no arguments"); @@ -316,7 +306,7 @@ public class FunctionRegistry { } return ctorRef.apply(location); }; - return def(function, builder, false, aliases); + return def(function, builder, false, names); } /** @@ -326,7 +316,7 @@ public class FunctionRegistry { */ @SuppressWarnings("overloads") static FunctionDefinition def(Class function, - ConfigurationAwareFunctionBuilder ctorRef, String... aliases) { + ConfigurationAwareFunctionBuilder ctorRef, String... names) { FunctionBuilder builder = (location, children, distinct, cfg) -> { if (false == children.isEmpty()) { throw new IllegalArgumentException("expects no arguments"); @@ -336,7 +326,7 @@ public class FunctionRegistry { } return ctorRef.build(location, cfg); }; - return def(function, builder, false, aliases); + return def(function, builder, false, names); } interface ConfigurationAwareFunctionBuilder { @@ -349,7 +339,7 @@ public class FunctionRegistry { */ @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do static FunctionDefinition def(Class function, - BiFunction ctorRef, String... aliases) { + BiFunction ctorRef, String... names) { FunctionBuilder builder = (location, children, distinct, cfg) -> { if (children.size() != 1) { throw new IllegalArgumentException("expects exactly one argument"); @@ -359,7 +349,7 @@ public class FunctionRegistry { } return ctorRef.apply(location, children.get(0)); }; - return def(function, builder, false, aliases); + return def(function, builder, false, names); } /** @@ -368,14 +358,14 @@ public class FunctionRegistry { */ @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do static FunctionDefinition def(Class function, - MultiFunctionBuilder ctorRef, String... aliases) { + MultiFunctionBuilder ctorRef, String... names) { FunctionBuilder builder = (location, children, distinct, cfg) -> { if (distinct) { throw new IllegalArgumentException("does not support DISTINCT yet it was specified"); } return ctorRef.build(location, children); }; - return def(function, builder, false, aliases); + return def(function, builder, false, names); } interface MultiFunctionBuilder { @@ -388,14 +378,14 @@ public class FunctionRegistry { */ @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do static FunctionDefinition def(Class function, - DistinctAwareUnaryFunctionBuilder ctorRef, String... aliases) { + DistinctAwareUnaryFunctionBuilder ctorRef, String... names) { FunctionBuilder builder = (location, children, distinct, cfg) -> { if (children.size() != 1) { throw new IllegalArgumentException("expects exactly one argument"); } return ctorRef.build(location, children.get(0), distinct); }; - return def(function, builder, false, aliases); + return def(function, builder, false, names); } interface DistinctAwareUnaryFunctionBuilder { @@ -408,7 +398,7 @@ public class FunctionRegistry { */ @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do static FunctionDefinition def(Class function, - DatetimeUnaryFunctionBuilder ctorRef, String... aliases) { + DatetimeUnaryFunctionBuilder ctorRef, String... names) { FunctionBuilder builder = (location, children, distinct, cfg) -> { if (children.size() != 1) { throw new IllegalArgumentException("expects exactly one argument"); @@ -418,7 +408,7 @@ public class FunctionRegistry { } return ctorRef.build(location, children.get(0), cfg.timeZone()); }; - return def(function, builder, true, aliases); + return def(function, builder, true, names); } interface DatetimeUnaryFunctionBuilder { @@ -431,7 +421,7 @@ public class FunctionRegistry { */ @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do static FunctionDefinition def(Class function, - BinaryFunctionBuilder ctorRef, String... aliases) { + BinaryFunctionBuilder ctorRef, String... names) { FunctionBuilder builder = (location, children, distinct, cfg) -> { boolean isBinaryOptionalParamFunction = function.isAssignableFrom(Round.class) || function.isAssignableFrom(Truncate.class); if (isBinaryOptionalParamFunction && (children.size() > 2 || children.size() < 1)) { @@ -445,17 +435,24 @@ public class FunctionRegistry { } return ctorRef.build(location, children.get(0), children.size() == 2 ? children.get(1) : null); }; - return def(function, builder, false, aliases); + return def(function, builder, false, names); } interface BinaryFunctionBuilder { T build(Location location, Expression lhs, Expression rhs); } + /** + * Main method to register a function/ + * @param names Must always have at least one entry which is the method's primary name + * + */ @SuppressWarnings("overloads") private static FunctionDefinition def(Class function, FunctionBuilder builder, - boolean datetime, String... aliases) { - String primaryName = normalize(function.getSimpleName()); + boolean datetime, String... names) { + Check.isTrue(names.length > 0, "At least one name must be provided for the function"); + String primaryName = names[0]; + List aliases = Arrays.asList(names).subList(1, names.length); FunctionDefinition.Builder realBuilder = (uf, distinct, cfg) -> { try { return builder.build(uf.location(), uf.children(), distinct, cfg); @@ -464,7 +461,7 @@ public class FunctionRegistry { uf.location().getLineNumber(), uf.location().getColumnNumber()); } }; - return new FunctionDefinition(primaryName, unmodifiableList(Arrays.asList(aliases)), function, datetime, realBuilder); + return new FunctionDefinition(primaryName, unmodifiableList(aliases), function, datetime, realBuilder); } private interface FunctionBuilder { @@ -473,7 +470,7 @@ public class FunctionRegistry { @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do static FunctionDefinition def(Class function, - ThreeParametersFunctionBuilder ctorRef, String... aliases) { + ThreeParametersFunctionBuilder ctorRef, String... names) { FunctionBuilder builder = (location, children, distinct, cfg) -> { boolean isLocateFunction = function.isAssignableFrom(Locate.class); if (isLocateFunction && (children.size() > 3 || children.size() < 2)) { @@ -486,7 +483,7 @@ public class FunctionRegistry { } return ctorRef.build(location, children.get(0), children.get(1), children.size() == 3 ? children.get(2) : null); }; - return def(function, builder, false, aliases); + return def(function, builder, false, names); } interface ThreeParametersFunctionBuilder { @@ -495,7 +492,7 @@ public class FunctionRegistry { @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do static FunctionDefinition def(Class function, - FourParametersFunctionBuilder ctorRef, String... aliases) { + FourParametersFunctionBuilder ctorRef, String... names) { FunctionBuilder builder = (location, children, distinct, cfg) -> { if (children.size() != 4) { throw new IllegalArgumentException("expects exactly four arguments"); @@ -505,7 +502,7 @@ public class FunctionRegistry { } return ctorRef.build(location, children.get(0), children.get(1), children.get(2), children.get(3)); }; - return def(function, builder, false, aliases); + return def(function, builder, false, names); } interface FourParametersFunctionBuilder { @@ -521,22 +518,13 @@ public class FunctionRegistry { @SuppressWarnings("overloads") // These are ambiguous if you aren't using ctor references but we always do private static FunctionDefinition def(Class function, CastFunctionBuilder ctorRef, - String... aliases) { + String... names) { FunctionBuilder builder = (location, children, distinct, cfg) -> ctorRef.build(location, children.get(0), children.get(0).dataType()); - return def(function, builder, false, aliases); + return def(function, builder, false, names); } private interface CastFunctionBuilder { T build(Location location, Expression expression, DataType dataType); } - - private static String normalize(String name) { - if (EXCLUDE_FROM_NAME_NORMALIZATION.contains(name)) { - return name.toUpperCase(Locale.ROOT); - } - - // translate CamelCase to CAMEL_CASE - return StringUtils.camelCaseToUnderscore(name); - } } diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistryTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistryTests.java index 63b0b193493..63008e8f27f 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistryTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/expression/function/FunctionRegistryTests.java @@ -34,9 +34,10 @@ import static org.hamcrest.Matchers.is; import static org.mockito.Mockito.mock; public class FunctionRegistryTests extends ESTestCase { + public void testNoArgFunction() { UnresolvedFunction ur = uf(STANDARD); - FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new)); + FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "DUMMY_FUNCTION")); FunctionDefinition def = r.resolveFunction(ur.name()); assertEquals(ur.location(), ur.buildResolved(randomConfiguration(), def).location()); @@ -56,7 +57,7 @@ public class FunctionRegistryTests extends ESTestCase { FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, (Location l, Expression e) -> { assertSame(e, ur.children().get(0)); return new DummyFunction(l); - })); + }, "DUMMY_FUNCTION")); FunctionDefinition def = r.resolveFunction(ur.name()); assertFalse(def.datetime()); assertEquals(ur.location(), ur.buildResolved(randomConfiguration(), def).location()); @@ -84,7 +85,7 @@ public class FunctionRegistryTests extends ESTestCase { assertEquals(urIsDistinct, distinct); assertSame(e, ur.children().get(0)); return new DummyFunction(l); - })); + }, "DUMMY_FUNCTION")); FunctionDefinition def = r.resolveFunction(ur.name()); assertEquals(ur.location(), ur.buildResolved(randomConfiguration(), def).location()); assertFalse(def.datetime()); @@ -109,7 +110,7 @@ public class FunctionRegistryTests extends ESTestCase { assertEquals(providedTimeZone, tz); assertSame(e, ur.children().get(0)); return new DummyFunction(l); - })); + }, "DUMMY_FUNCTION")); FunctionDefinition def = r.resolveFunction(ur.name()); assertEquals(ur.location(), ur.buildResolved(providedConfiguration, def).location()); assertTrue(def.datetime()); @@ -136,7 +137,7 @@ public class FunctionRegistryTests extends ESTestCase { assertSame(lhs, ur.children().get(0)); assertSame(rhs, ur.children().get(1)); return new DummyFunction(l); - })); + }, "DUMMY_FUNCTION")); FunctionDefinition def = r.resolveFunction(ur.name()); assertEquals(ur.location(), ur.buildResolved(randomConfiguration(), def).location()); assertFalse(def.datetime()); @@ -164,24 +165,24 @@ public class FunctionRegistryTests extends ESTestCase { } public void testAliasNameIsTheSameAsAFunctionName() { - FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "ALIAS")); + FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "DUMMY_FUNCTION", "ALIAS")); IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> - r.addToMap(def(DummyFunction2.class, DummyFunction2::new, "DUMMY_FUNCTION"))); - assertEquals(iae.getMessage(), "alias [DUMMY_FUNCTION] is used by [DUMMY_FUNCTION] and [DUMMY_FUNCTION2]"); + r.addToMap(def(DummyFunction2.class, DummyFunction2::new, "DUMMY_FUNCTION2", "DUMMY_FUNCTION"))); + assertEquals("alias [DUMMY_FUNCTION] is used by [DUMMY_FUNCTION] and [DUMMY_FUNCTION2]", iae.getMessage()); } public void testDuplicateAliasInTwoDifferentFunctionsFromTheSameBatch() { IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> - new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "ALIAS"), - def(DummyFunction2.class, DummyFunction2::new, "ALIAS"))); - assertEquals(iae.getMessage(), "alias [ALIAS] is used by [DUMMY_FUNCTION(ALIAS)] and [DUMMY_FUNCTION2]"); + new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "DUMMY_FUNCTION", "ALIAS"), + def(DummyFunction2.class, DummyFunction2::new, "DUMMY_FUNCTION2", "ALIAS"))); + assertEquals("alias [ALIAS] is used by [DUMMY_FUNCTION(ALIAS)] and [DUMMY_FUNCTION2]", iae.getMessage()); } public void testDuplicateAliasInTwoDifferentFunctionsFromTwoDifferentBatches() { - FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "ALIAS")); + FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, DummyFunction::new, "DUMMY_FUNCTION", "ALIAS")); IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, () -> - r.addToMap(def(DummyFunction2.class, DummyFunction2::new, "ALIAS"))); - assertEquals(iae.getMessage(), "alias [ALIAS] is used by [DUMMY_FUNCTION] and [DUMMY_FUNCTION2]"); + r.addToMap(def(DummyFunction2.class, DummyFunction2::new, "DUMMY_FUNCTION2", "ALIAS"))); + assertEquals("alias [ALIAS] is used by [DUMMY_FUNCTION] and [DUMMY_FUNCTION2]", iae.getMessage()); } public void testFunctionResolving() { @@ -189,7 +190,7 @@ public class FunctionRegistryTests extends ESTestCase { FunctionRegistry r = new FunctionRegistry(def(DummyFunction.class, (Location l, Expression e) -> { assertSame(e, ur.children().get(0)); return new DummyFunction(l); - }, "DUMMY_FUNC")); + }, "DUMMY_FUNCTION", "DUMMY_FUNC")); // Resolve by primary name FunctionDefinition def = r.resolveFunction(r.resolveAlias("DuMMy_FuncTIon"));