From dce7d0e73e9df173e7afdabd8c7d8a6e65a8a4d3 Mon Sep 17 00:00:00 2001 From: GabeFernandez310 Date: Fri, 6 Jan 2023 10:59:22 -0800 Subject: [PATCH 1/6] Add Second_Of_Minute Function As An Alias Of The Second Function (#1231) Added Testing And Implementation For Second_Of_Minute Function Signed-off-by: GabeFernandez310 Signed-off-by: GabeFernandez310 --- .../org/opensearch/sql/expression/DSL.java | 4 + .../expression/datetime/DateTimeFunction.java | 12 ++- .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 76 +++++++++++++++++++ docs/user/dql/functions.rst | 9 +++ .../sql/sql/DateTimeFunctionIT.java | 45 +++++++++++ sql/src/main/antlr/OpenSearchSQLParser.g4 | 1 + .../sql/sql/antlr/SQLSyntaxParserTest.java | 8 ++ 8 files changed, 152 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/opensearch/sql/expression/DSL.java b/core/src/main/java/org/opensearch/sql/expression/DSL.java index dfe380b507..7899e47a71 100644 --- a/core/src/main/java/org/opensearch/sql/expression/DSL.java +++ b/core/src/main/java/org/opensearch/sql/expression/DSL.java @@ -378,6 +378,10 @@ public static FunctionExpression second(Expression... expressions) { return compile(FunctionProperties.None, BuiltinFunctionName.SECOND, expressions); } + public static FunctionExpression second_of_minute(Expression... expressions) { + return compile(FunctionProperties.None, BuiltinFunctionName.SECOND_OF_MINUTE, expressions); + } + public static FunctionExpression subdate(Expression... expressions) { return compile(FunctionProperties.None, BuiltinFunctionName.SUBDATE, expressions); } diff --git a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java index 6ee5a79172..a29429fc04 100644 --- a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java @@ -9,6 +9,7 @@ import static java.time.temporal.ChronoUnit.DAYS; import static java.time.temporal.ChronoUnit.MINUTES; import static java.time.temporal.ChronoUnit.MONTHS; +import static java.time.temporal.ChronoUnit.SECONDS; import static org.opensearch.sql.data.type.ExprCoreType.DATE; import static org.opensearch.sql.data.type.ExprCoreType.DATETIME; import static org.opensearch.sql.data.type.ExprCoreType.DOUBLE; @@ -128,7 +129,8 @@ public void register(BuiltinFunctionRepository repository) { repository.register(period_add()); repository.register(period_diff()); repository.register(quarter()); - repository.register(second()); + repository.register(second(BuiltinFunctionName.SECOND)); + repository.register(second(BuiltinFunctionName.SECOND_OF_MINUTE)); repository.register(subdate()); repository.register(sysdate()); repository.register(time()); @@ -557,10 +559,11 @@ private DefaultFunctionResolver quarter() { /** * SECOND(STRING/TIME/DATETIME/TIMESTAMP). return the second value for time. */ - private DefaultFunctionResolver second() { - return define(BuiltinFunctionName.SECOND.getName(), + private DefaultFunctionResolver second(BuiltinFunctionName name) { + return define(name.getName(), impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, STRING), impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, TIME), + impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, DATE), impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, DATETIME), impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, TIMESTAMP) ); @@ -1131,7 +1134,8 @@ private ExprValue exprQuarter(ExprValue date) { * @return ExprValue. */ private ExprValue exprSecond(ExprValue time) { - return new ExprIntegerValue(time.timeValue().getSecond()); + return new ExprIntegerValue( + (SECONDS.between(LocalTime.MIN, time.timeValue()) % 60)); } /** diff --git a/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java index 50c8682c62..06b46b6888 100644 --- a/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java @@ -86,6 +86,7 @@ public enum BuiltinFunctionName { PERIOD_DIFF(FunctionName.of("period_diff")), QUARTER(FunctionName.of("quarter")), SECOND(FunctionName.of("second")), + SECOND_OF_MINUTE(FunctionName.of("second_of_minute")), SUBDATE(FunctionName.of("subdate")), TIME(FunctionName.of("time")), TIMEDIFF(FunctionName.of("timediff")), diff --git a/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java index 29a0843287..7a486fc8d4 100644 --- a/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -28,10 +28,14 @@ import com.google.common.collect.ImmutableList; import java.time.LocalDate; import java.util.List; +import java.util.stream.Stream; import lombok.AllArgsConstructor; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.opensearch.sql.data.model.ExprDateValue; @@ -46,6 +50,7 @@ import org.opensearch.sql.expression.Expression; import org.opensearch.sql.expression.ExpressionTestBase; import org.opensearch.sql.expression.FunctionExpression; +import org.opensearch.sql.expression.LiteralExpression; import org.opensearch.sql.expression.env.Environment; @ExtendWith(MockitoExtension.class) @@ -904,6 +909,77 @@ public void second() { assertEquals("second(DATETIME '2020-08-17 01:02:03')", expression.toString()); } + private void secondOfMinuteQuery(FunctionExpression dateExpression, int second, String testExpr) { + assertEquals(INTEGER, dateExpression.type()); + assertEquals(integerValue(second), eval(dateExpression)); + assertEquals(testExpr, dateExpression.toString()); + } + + private static Stream getTestDataForSecondOfMinute() { + return Stream.of( + Arguments.of( + DSL.literal(new ExprTimeValue("01:02:03")), + 3, + "second_of_minute(TIME '01:02:03')"), + Arguments.of( + DSL.literal("01:02:03"), + 3, + "second_of_minute(\"01:02:03\")"), + Arguments.of( + DSL.literal("2020-08-17 01:02:03"), + 3, + "second_of_minute(\"2020-08-17 01:02:03\")"), + Arguments.of( + + DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03")), + 3, + "second_of_minute(TIMESTAMP '2020-08-17 01:02:03')"), + Arguments.of( + + DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03")), + 3, + "second_of_minute(DATETIME '2020-08-17 01:02:03')") + ); + } + + @ParameterizedTest(name = "{2}") + @MethodSource("getTestDataForSecondOfMinute") + public void secondOfMinute(LiteralExpression arg, int expectedResult, String expectedString) { + lenient().when(nullRef.valueOf(env)).thenReturn(nullValue()); + lenient().when(missingRef.valueOf(env)).thenReturn(missingValue()); + + secondOfMinuteQuery(DSL.second_of_minute(arg), expectedResult, expectedString); + } + + private void invalidSecondOfMinuteQuery(String time) { + FunctionExpression expression = DSL.second_of_minute(DSL.literal(new ExprTimeValue(time))); + eval(expression); + } + + @Test + public void secondOfMinuteInvalidArguments() { + when(nullRef.type()).thenReturn(TIME); + when(missingRef.type()).thenReturn(TIME); + + assertAll( + () -> assertEquals(nullValue(), eval(DSL.second_of_minute(nullRef))), + () -> assertEquals(missingValue(), eval(DSL.second_of_minute(missingRef))), + //Invalid Seconds + () -> assertThrows(SemanticCheckException.class, + () -> invalidSecondOfMinuteQuery("12:23:61")), + //Invalid Minutes + () -> assertThrows(SemanticCheckException.class, + () -> invalidSecondOfMinuteQuery("12:61:34")), + //Invalid Hours + () -> assertThrows(SemanticCheckException.class, + () -> invalidSecondOfMinuteQuery("25:23:34")), + //incorrect format + () -> assertThrows(SemanticCheckException.class, + () -> invalidSecondOfMinuteQuery("asdfasdf")) + ); + } + + @Test public void subdate() { FunctionExpression expr = DSL.subdate(DSL.date(DSL.literal("2020-08-26")), DSL.literal(7)); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 1726c92054..f95947a7b5 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -1961,6 +1961,7 @@ Description >>>>>>>>>>> Usage: second(time) returns the second for time, in the range 0 to 59. +The function `second_of_minute`_ is provided as an alias Argument type: STRING/TIME/DATETIME/TIMESTAMP @@ -1976,6 +1977,14 @@ Example:: | 3 | +-----------------------------+ + os> SELECT SECOND_OF_MINUTE(time('01:02:03')) + fetched rows / total rows = 1/1 + +--------------------------------------+ + | SECOND_OF_MINUTE(time('01:02:03')) | + |--------------------------------------| + | 3 | + +--------------------------------------+ + SUBDATE ------- diff --git a/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java b/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java index e135f15523..62bb033af3 100644 --- a/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java @@ -493,6 +493,51 @@ public void testSecond() throws IOException { verifyDataRows(result, rows(0)); } + @Test + public void testSecondOfMinute() throws IOException { + JSONObject result = executeQuery("select second_of_minute(timestamp('2020-09-16 17:30:00'))"); + verifySchema(result, schema("second_of_minute(timestamp('2020-09-16 17:30:00'))", null, "integer")); + verifyDataRows(result, rows(0)); + + result = executeQuery("select second_of_minute(time('17:30:00'))"); + verifySchema(result, schema("second_of_minute(time('17:30:00'))", null, "integer")); + verifyDataRows(result, rows(0)); + + result = executeQuery("select second_of_minute('2020-09-16 17:30:00')"); + verifySchema(result, schema("second_of_minute('2020-09-16 17:30:00')", null, "integer")); + verifyDataRows(result, rows(0)); + + result = executeQuery("select second_of_minute('17:30:00')"); + verifySchema(result, schema("second_of_minute('17:30:00')", null, "integer")); + verifyDataRows(result, rows(0)); + } + + @Test + public void testSecondFunctionAliasesReturnTheSameResults() throws IOException { + JSONObject result1 = executeQuery("SELECT second('2022-11-22 12:23:34')"); + JSONObject result2 = executeQuery("SELECT second_of_minute('2022-11-22 12:23:34')"); + verifyDataRows(result1, rows(34)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + + result1 = executeQuery(String.format( + "SELECT second(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS)); + result2 = executeQuery(String.format( + "SELECT second_of_minute(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + + result1 = executeQuery(String.format( + "SELECT second(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS)); + result2 = executeQuery(String.format( + "SELECT second_of_minute(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + + result1 = executeQuery(String.format( + "SELECT second(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS)); + result2 = executeQuery(String.format( + "SELECT second_of_minute(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + } + @Test public void testSubDate() throws IOException { JSONObject result = diff --git a/sql/src/main/antlr/OpenSearchSQLParser.g4 b/sql/src/main/antlr/OpenSearchSQLParser.g4 index 6d9f7b9f8b..9e827d03f8 100644 --- a/sql/src/main/antlr/OpenSearchSQLParser.g4 +++ b/sql/src/main/antlr/OpenSearchSQLParser.g4 @@ -450,6 +450,7 @@ dateTimeFunctionName | PERIOD_DIFF | QUARTER | SECOND + | SECOND_OF_MINUTE | SUBDATE | SYSDATE | TIME diff --git a/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java b/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java index 82e1b0b848..130534af10 100644 --- a/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java +++ b/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java @@ -269,6 +269,14 @@ public void can_parse_multi_match_relevance_function() { + "operator='AND', tie_breaker=0.3, type = \"most_fields\", fuzziness = \"AUTO\")")); } + @Test + public void can_parse_second_functions() { + assertNotNull(parser.parse("SELECT second('12:23:34')")); + assertNotNull(parser.parse("SELECT second_of_minute('2022-11-18')")); + assertNotNull(parser.parse("SELECT second('2022-11-18 12:23:34')")); + assertNotNull(parser.parse("SELECT second_of_minute('2022-11-18 12:23:34')")); + } + @Test public void can_parse_simple_query_string_relevance_function() { assertNotNull(parser.parse( From 61e2374eace01945bb8b083c8b19859e5042e228 Mon Sep 17 00:00:00 2001 From: GabeFernandez310 Date: Fri, 6 Jan 2023 11:00:13 -0800 Subject: [PATCH 2/6] Add Minute_Of_Hour Function As An Alias Of Minute Function (#196) (#1230) Added Testing And Implementation For Minute_Of_Hour Function Signed-off-by: GabeFernandez310 Signed-off-by: GabeFernandez310 --- .../org/opensearch/sql/expression/DSL.java | 4 + .../expression/datetime/DateTimeFunction.java | 11 ++- .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 81 ++++++++++++++++++- docs/user/dql/functions.rst | 13 +-- .../sql/sql/DateTimeFunctionIT.java | 46 +++++++++++ sql/src/main/antlr/OpenSearchSQLParser.g4 | 1 + .../sql/sql/antlr/SQLSyntaxParserTest.java | 9 +++ 8 files changed, 155 insertions(+), 11 deletions(-) diff --git a/core/src/main/java/org/opensearch/sql/expression/DSL.java b/core/src/main/java/org/opensearch/sql/expression/DSL.java index 7899e47a71..b3972af86d 100644 --- a/core/src/main/java/org/opensearch/sql/expression/DSL.java +++ b/core/src/main/java/org/opensearch/sql/expression/DSL.java @@ -358,6 +358,10 @@ public static FunctionExpression minute_of_day(Expression... expressions) { return compile(FunctionProperties.None, BuiltinFunctionName.MINUTE_OF_DAY, expressions); } + public static FunctionExpression minute_of_hour(Expression... expressions) { + return compile(FunctionProperties.None, BuiltinFunctionName.MINUTE_OF_HOUR, expressions); + } + public static FunctionExpression month(Expression... expressions) { return compile(FunctionProperties.None, BuiltinFunctionName.MONTH, expressions); } diff --git a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java index a29429fc04..4ad395537f 100644 --- a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java @@ -120,8 +120,9 @@ public void register(BuiltinFunctionRepository repository) { repository.register(makedate()); repository.register(maketime()); repository.register(microsecond()); - repository.register(minute()); + repository.register(minute(BuiltinFunctionName.MINUTE)); repository.register(minute_of_day()); + repository.register(minute(BuiltinFunctionName.MINUTE_OF_HOUR)); repository.register(month(BuiltinFunctionName.MONTH)); repository.register(month(BuiltinFunctionName.MONTH_OF_YEAR)); repository.register(monthName()); @@ -477,11 +478,12 @@ private DefaultFunctionResolver microsecond() { /** * MINUTE(STRING/TIME/DATETIME/TIMESTAMP). return the minute value for time. */ - private DefaultFunctionResolver minute() { - return define(BuiltinFunctionName.MINUTE.getName(), + private DefaultFunctionResolver minute(BuiltinFunctionName name) { + return define(name.getName(), impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, STRING), impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, TIME), impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, DATETIME), + impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, DATE), impl(nullMissingHandling(DateTimeFunction::exprMinute), INTEGER, TIMESTAMP) ); } @@ -1026,7 +1028,8 @@ private ExprValue exprMicrosecond(ExprValue time) { * @return ExprValue. */ private ExprValue exprMinute(ExprValue time) { - return new ExprIntegerValue(time.timeValue().getMinute()); + return new ExprIntegerValue( + (MINUTES.between(LocalTime.MIN, time.timeValue()) % 60)); } /** diff --git a/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java index 06b46b6888..eff36c9f64 100644 --- a/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java @@ -79,6 +79,7 @@ public enum BuiltinFunctionName { MICROSECOND(FunctionName.of("microsecond")), MINUTE(FunctionName.of("minute")), MINUTE_OF_DAY(FunctionName.of("minute_of_day")), + MINUTE_OF_HOUR(FunctionName.of("minute_of_hour")), MONTH(FunctionName.of("month")), MONTH_OF_YEAR(FunctionName.of("month_of_year")), MONTHNAME(FunctionName.of("monthname")), diff --git a/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java index 7a486fc8d4..617f3f7d3e 100644 --- a/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -732,7 +732,7 @@ private void testMinuteOfDay(String date, int value) { assertEquals(INTEGER, expression.type()); assertEquals(integerValue(value), eval(expression)); } - + @Test public void minuteOfDay() { when(nullRef.type()).thenReturn(TIME); @@ -769,6 +769,85 @@ public void minuteOfDay() { testMinuteOfDay("2020-08-17 00:00:01", 0); } + private void minuteOfHourQuery(FunctionExpression dateExpression, int minute, String testExpr) { + assertAll( + () -> assertEquals(INTEGER, dateExpression.type()), + () -> assertEquals(integerValue(minute), eval(dateExpression)), + () -> assertEquals(testExpr, dateExpression.toString()) + ); + } + + private static Stream getTestDataForMinuteOfHour() { + return Stream.of( + Arguments.of( + DSL.literal(new ExprTimeValue("01:02:03")), + 2, + "minute_of_hour(TIME '01:02:03')"), + Arguments.of( + DSL.literal("01:02:03"), + 2, + "minute_of_hour(\"01:02:03\")"), + Arguments.of( + DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03")), + 2, + "minute_of_hour(TIMESTAMP '2020-08-17 01:02:03')"), + Arguments.of( + DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03")), + 2, + "minute_of_hour(DATETIME '2020-08-17 01:02:03')"), + Arguments.of( + DSL.literal("2020-08-17 01:02:03"), + 2, + "minute_of_hour(\"2020-08-17 01:02:03\")") + ); + } + + @ParameterizedTest(name = "{2}") + @MethodSource("getTestDataForMinuteOfHour") + public void minuteOfHour(LiteralExpression arg, int expectedResult, String expectedString) { + lenient().when(nullRef.valueOf(env)).thenReturn(nullValue()); + lenient().when(missingRef.valueOf(env)).thenReturn(missingValue()); + + minuteOfHourQuery(DSL.minute_of_hour(arg), expectedResult, expectedString); + } + + private void invalidMinuteOfHourQuery(String time) { + FunctionExpression expression = DSL.minute_of_hour(DSL.literal(new ExprTimeValue(time))); + eval(expression); + } + + @Test + public void minuteOfHourInvalidArguments() { + when(nullRef.type()).thenReturn(TIME); + when(missingRef.type()).thenReturn(TIME); + + assertAll( + () -> assertEquals(nullValue(), eval(DSL.minute_of_hour(nullRef))), + () -> assertEquals(missingValue(), eval(DSL.minute_of_hour(missingRef))), + + //Invalid Seconds + () -> assertThrows( + SemanticCheckException.class, + () -> invalidMinuteOfHourQuery("12:23:61")), + + //Invalid Minutes + () -> assertThrows( + SemanticCheckException.class, + () -> invalidMinuteOfHourQuery("12:61:34")), + + //Invalid Hours + () -> assertThrows( + SemanticCheckException.class, + () -> invalidMinuteOfHourQuery("25:23:34")), + + //incorrect format + () -> assertThrows( + SemanticCheckException.class, + () -> invalidMinuteOfHourQuery("asdfasdf")) + ); + } + + @Test public void month() { when(nullRef.type()).thenReturn(DATE); diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index f95947a7b5..0ca2a6bad4 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -1767,6 +1767,7 @@ Description >>>>>>>>>>> Usage: minute(time) returns the minute for time, in the range 0 to 59. +The `minute_of_hour` function is provided as an alias. Argument type: STRING/TIME/DATETIME/TIMESTAMP @@ -1774,13 +1775,13 @@ Return type: INTEGER Example:: - os> SELECT MINUTE((TIME '01:02:03')) + os> SELECT MINUTE(time('01:02:03')), MINUTE_OF_HOUR(time('01:02:03')) fetched rows / total rows = 1/1 - +-----------------------------+ - | MINUTE((TIME '01:02:03')) | - |-----------------------------| - | 2 | - +-----------------------------+ + +----------------------------+------------------------------------+ + | MINUTE(time('01:02:03')) | MINUTE_OF_HOUR(time('01:02:03')) | + |----------------------------+------------------------------------| + | 2 | 2 | + +----------------------------+------------------------------------+ MINUTE_OF_DAY ------ diff --git a/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java b/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java index 62bb033af3..6255ccf010 100644 --- a/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java @@ -390,6 +390,52 @@ public void testMinuteOfDay() throws IOException { verifyDataRows(result, rows(1050)); } + @Test + public void testMinuteOfHour() throws IOException { + JSONObject result = executeQuery("select minute_of_hour(timestamp('2020-09-16 17:30:00'))"); + verifySchema(result, schema( + "minute_of_hour(timestamp('2020-09-16 17:30:00'))", null, "integer")); + verifyDataRows(result, rows(30)); + + result = executeQuery("select minute_of_hour(time('17:30:00'))"); + verifySchema(result, schema("minute_of_hour(time('17:30:00'))", null, "integer")); + verifyDataRows(result, rows(30)); + + result = executeQuery("select minute_of_hour('2020-09-16 17:30:00')"); + verifySchema(result, schema("minute_of_hour('2020-09-16 17:30:00')", null, "integer")); + verifyDataRows(result, rows(30)); + + result = executeQuery("select minute_of_hour('17:30:00')"); + verifySchema(result, schema("minute_of_hour('17:30:00')", null, "integer")); + verifyDataRows(result, rows(30)); + } + + @Test + public void testMinuteFunctionAliasesReturnTheSameResults() throws IOException { + JSONObject result1 = executeQuery("SELECT minute('11:30:00')"); + JSONObject result2 = executeQuery("SELECT minute_of_hour('11:30:00')"); + verifyDataRows(result1, rows(30)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + + result1 = executeQuery(String.format( + "SELECT minute(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS)); + result2 = executeQuery(String.format( + "SELECT minute_of_hour(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + + result1 = executeQuery(String.format( + "SELECT minute(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS)); + result2 = executeQuery(String.format( + "SELECT minute_of_hour(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + + result1 = executeQuery(String.format( + "SELECT minute(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS)); + result2 = executeQuery(String.format( + "SELECT minute_of_hour(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + } + @Test public void testMonth() throws IOException { JSONObject result = executeQuery("select month(date('2020-09-16'))"); diff --git a/sql/src/main/antlr/OpenSearchSQLParser.g4 b/sql/src/main/antlr/OpenSearchSQLParser.g4 index 9e827d03f8..0ef7e21b42 100644 --- a/sql/src/main/antlr/OpenSearchSQLParser.g4 +++ b/sql/src/main/antlr/OpenSearchSQLParser.g4 @@ -443,6 +443,7 @@ dateTimeFunctionName | MICROSECOND | MINUTE | MINUTE_OF_DAY + | MINUTE_OF_HOUR | MONTH | MONTHNAME | NOW diff --git a/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java b/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java index 130534af10..eee476a56a 100644 --- a/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java +++ b/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java @@ -207,6 +207,15 @@ public void can_parse_dayofyear_functions() { assertNotNull(parser.parse("SELECT day_of_year('2022-11-18')")); } + @Test + public void can_parse_minute_functions() { + assertNotNull(parser.parse("SELECT minute('12:23:34')")); + assertNotNull(parser.parse("SELECT minute_of_hour('12:23:34')")); + + assertNotNull(parser.parse("SELECT minute('2022-12-20 12:23:34')")); + assertNotNull(parser.parse("SELECT minute_of_hour('2022-12-20 12:23:34')")); + } + @Test public void can_parse_month_of_year_function() { assertNotNull(parser.parse("SELECT month('2022-11-18')")); From bac9c37f3020ea04b581c12c7a492d17ffe9636b Mon Sep 17 00:00:00 2001 From: GabeFernandez310 Date: Fri, 6 Jan 2023 11:06:20 -0800 Subject: [PATCH 3/6] Add Day_Of_Week Function As An Alias Of DayOfWeek (#190) (#1228) Added Implementation And Testing For Day_Of_Week Function Signed-off-by: GabeFernandez310 Signed-off-by: GabeFernandez310 --- .../org/opensearch/sql/expression/DSL.java | 10 +- .../expression/datetime/DateTimeFunction.java | 24 ++- .../function/BuiltinFunctionName.java | 1 + .../datetime/DateTimeFunctionTest.java | 162 +++++++++++++++--- docs/user/dql/functions.rst | 15 +- .../sql/sql/DateTimeFunctionIT.java | 43 +++++ sql/src/main/antlr/OpenSearchSQLParser.g4 | 1 + .../sql/sql/antlr/SQLSyntaxParserTest.java | 6 + 8 files changed, 226 insertions(+), 36 deletions(-) diff --git a/core/src/main/java/org/opensearch/sql/expression/DSL.java b/core/src/main/java/org/opensearch/sql/expression/DSL.java index b3972af86d..bb343cd5f9 100644 --- a/core/src/main/java/org/opensearch/sql/expression/DSL.java +++ b/core/src/main/java/org/opensearch/sql/expression/DSL.java @@ -326,8 +326,9 @@ public static FunctionExpression dayofmonth(Expression... expressions) { return compile(FunctionProperties.None, BuiltinFunctionName.DAYOFMONTH, expressions); } - public static FunctionExpression dayofweek(Expression... expressions) { - return compile(FunctionProperties.None, BuiltinFunctionName.DAYOFWEEK, expressions); + public static FunctionExpression dayofweek( + FunctionProperties functionProperties, Expression... expressions) { + return compile(functionProperties, BuiltinFunctionName.DAYOFWEEK, expressions); } public static FunctionExpression dayofyear(Expression... expressions) { @@ -338,6 +339,11 @@ public static FunctionExpression day_of_year(Expression... expressions) { return compile(FunctionProperties.None, BuiltinFunctionName.DAY_OF_YEAR, expressions); } + public static FunctionExpression day_of_week( + FunctionProperties functionProperties, Expression... expressions) { + return compile(functionProperties, BuiltinFunctionName.DAY_OF_WEEK, expressions); + } + public static FunctionExpression from_days(Expression... expressions) { return compile(FunctionProperties.None, BuiltinFunctionName.FROM_DAYS, expressions); } diff --git a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java index 4ad395537f..37f5babe89 100644 --- a/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java +++ b/core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java @@ -109,7 +109,8 @@ public void register(BuiltinFunctionRepository repository) { repository.register(day()); repository.register(dayName()); repository.register(dayOfMonth()); - repository.register(dayOfWeek()); + repository.register(dayOfWeek(BuiltinFunctionName.DAYOFWEEK.getName())); + repository.register(dayOfWeek(BuiltinFunctionName.DAY_OF_WEEK.getName())); repository.register(dayOfYear(BuiltinFunctionName.DAYOFYEAR)); repository.register(dayOfYear(BuiltinFunctionName.DAY_OF_YEAR)); repository.register(from_days()); @@ -401,11 +402,14 @@ private DefaultFunctionResolver dayOfMonth() { } /** - * DAYOFWEEK(STRING/DATE/DATETIME/TIMESTAMP). + * DAYOFWEEK(STRING/DATE/DATETIME/TIME/TIMESTAMP). * return the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday). */ - private DefaultFunctionResolver dayOfWeek() { - return define(BuiltinFunctionName.DAYOFWEEK.getName(), + private DefaultFunctionResolver dayOfWeek(FunctionName name) { + return define(name, + implWithProperties(nullMissingHandlingWithProperties( + (functionProperties, arg) -> DateTimeFunction.dayOfWeekToday( + functionProperties.getQueryStartClock())), INTEGER, TIME), impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), INTEGER, DATE), impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), INTEGER, DATETIME), impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), INTEGER, TIMESTAMP), @@ -728,6 +732,16 @@ private DefaultFunctionResolver date_format() { ); } + /** + * Day of Week implementation for ExprValue when passing in an arguemt of type TIME. + * + * @param clock Current clock taken from function properties + * @return ExprValue. + */ + private ExprValue dayOfWeekToday(Clock clock) { + return new ExprIntegerValue((formatNow(clock).getDayOfWeek().getValue() % 7) + 1); + } + /** * ADDDATE function implementation for ExprValue. * @@ -900,7 +914,7 @@ private ExprValue exprDayOfMonth(ExprValue date) { /** * Day of Week implementation for ExprValue. * - * @param date ExprValue of Date/String type. + * @param date ExprValue of Date/Datetime/String/Timstamp type. * @return ExprValue. */ private ExprValue exprDayOfWeek(ExprValue date) { diff --git a/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java b/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java index eff36c9f64..3fca0a6fc8 100644 --- a/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java +++ b/core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java @@ -70,6 +70,7 @@ public enum BuiltinFunctionName { DAYOFMONTH(FunctionName.of("dayofmonth")), DAYOFWEEK(FunctionName.of("dayofweek")), DAYOFYEAR(FunctionName.of("dayofyear")), + DAY_OF_WEEK(FunctionName.of("day_of_week")), DAY_OF_YEAR(FunctionName.of("day_of_year")), FROM_DAYS(FunctionName.of("from_days")), FROM_UNIXTIME(FunctionName.of("from_unixtime")), diff --git a/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java b/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java index 617f3f7d3e..7761c1e94c 100644 --- a/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java +++ b/core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java @@ -435,32 +435,150 @@ public void dayOfMonth() { assertEquals(integerValue(8), eval(expression)); } + private void dayOfWeekQuery( + FunctionExpression dateExpression, + int dayOfWeek, + String testExpr) { + assertEquals(INTEGER, dateExpression.type()); + assertEquals(integerValue(dayOfWeek), eval(dateExpression)); + assertEquals(testExpr, dateExpression.toString()); + } + @Test public void dayOfWeek() { + lenient().when(nullRef.valueOf(env)).thenReturn(nullValue()); + lenient().when(missingRef.valueOf(env)).thenReturn(missingValue()); + + FunctionExpression expression1 = DSL.dayofweek( + functionProperties, + DSL.literal(new ExprDateValue("2020-08-07"))); + FunctionExpression expression2 = DSL.dayofweek( + functionProperties, + DSL.literal(new ExprDateValue("2020-08-09"))); + FunctionExpression expression3 = DSL.dayofweek( + functionProperties, + DSL.literal("2020-08-09")); + FunctionExpression expression4 = DSL.dayofweek( + functionProperties, + DSL.literal("2020-08-09 01:02:03")); + + assertAll( + () -> dayOfWeekQuery(expression1, 6, "dayofweek(DATE '2020-08-07')"), + + () -> dayOfWeekQuery(expression2, 1, "dayofweek(DATE '2020-08-09')"), + + () -> dayOfWeekQuery(expression3, 1, "dayofweek(\"2020-08-09\")"), + + () -> dayOfWeekQuery(expression4, 1, "dayofweek(\"2020-08-09 01:02:03\")") + ); + } + + private void dayOfWeekWithUnderscoresQuery( + FunctionExpression dateExpression, + int dayOfWeek, + String testExpr) { + assertEquals(INTEGER, dateExpression.type()); + assertEquals(integerValue(dayOfWeek), eval(dateExpression)); + assertEquals(testExpr, dateExpression.toString()); + } + + @Test + public void dayOfWeekWithUnderscores() { + lenient().when(nullRef.valueOf(env)).thenReturn(nullValue()); + lenient().when(missingRef.valueOf(env)).thenReturn(missingValue()); + + FunctionExpression expression1 = DSL.day_of_week( + functionProperties, + DSL.literal(new ExprDateValue("2020-08-07"))); + FunctionExpression expression2 = DSL.day_of_week( + functionProperties, + DSL.literal(new ExprDateValue("2020-08-09"))); + FunctionExpression expression3 = DSL.day_of_week( + functionProperties, + DSL.literal("2020-08-09")); + FunctionExpression expression4 = DSL.day_of_week( + functionProperties, + DSL.literal("2020-08-09 01:02:03")); + + assertAll( + () -> dayOfWeekWithUnderscoresQuery(expression1, 6, "day_of_week(DATE '2020-08-07')"), + + () -> dayOfWeekWithUnderscoresQuery(expression2, 1, "day_of_week(DATE '2020-08-09')"), + + () -> dayOfWeekWithUnderscoresQuery(expression3, 1, "day_of_week(\"2020-08-09\")"), + + () -> dayOfWeekWithUnderscoresQuery( + expression4, 1, "day_of_week(\"2020-08-09 01:02:03\")") + ); + } + + @Test + public void testDayOfWeekWithTimeType() { + lenient().when(nullRef.valueOf(env)).thenReturn(nullValue()); + lenient().when(missingRef.valueOf(env)).thenReturn(missingValue()); + FunctionExpression expression = DSL.day_of_week( + functionProperties, DSL.literal(new ExprTimeValue("12:23:34"))); + + assertAll( + () -> assertEquals(INTEGER, eval(expression).type()), + () -> assertEquals(( + LocalDate.now( + functionProperties.getQueryStartClock()).getDayOfWeek().getValue() % 7) + 1, + eval(expression).integerValue()), + () -> assertEquals("day_of_week(TIME '12:23:34')", expression.toString()) + ); + } + + private void testInvalidDayOfWeek(String date) { + FunctionExpression expression = DSL.day_of_week( + functionProperties, DSL.literal(new ExprDateValue(date))); + eval(expression); + } + + @Test + public void dayOfWeekWithUnderscoresLeapYear() { + lenient().when(nullRef.valueOf(env)).thenReturn(nullValue()); + lenient().when(missingRef.valueOf(env)).thenReturn(missingValue()); + + assertAll( + //Feb. 29 of a leap year + () -> dayOfWeekWithUnderscoresQuery(DSL.day_of_week( + functionProperties, + DSL.literal("2020-02-29")), 7, "day_of_week(\"2020-02-29\")"), + //day after Feb. 29 of a leap year + () -> dayOfWeekWithUnderscoresQuery(DSL.day_of_week( + functionProperties, + DSL.literal("2020-03-01")), 1, "day_of_week(\"2020-03-01\")"), + //Feb. 28 of a non-leap year + () -> dayOfWeekWithUnderscoresQuery(DSL.day_of_week( + functionProperties, + DSL.literal("2021-02-28")), 1, "day_of_week(\"2021-02-28\")"), + //Feb. 29 of a non-leap year + () -> assertThrows( + SemanticCheckException.class, () -> testInvalidDayOfWeek("2021-02-29")) + ); + } + + @Test + public void dayOfWeekWithUnderscoresInvalidArgument() { when(nullRef.type()).thenReturn(DATE); when(missingRef.type()).thenReturn(DATE); - assertEquals(nullValue(), eval(DSL.dayofweek(nullRef))); - assertEquals(missingValue(), eval(DSL.dayofweek(missingRef))); - - FunctionExpression expression = DSL.dayofweek(DSL.literal(new ExprDateValue("2020-08-07"))); - assertEquals(INTEGER, expression.type()); - assertEquals("dayofweek(DATE '2020-08-07')", expression.toString()); - assertEquals(integerValue(6), eval(expression)); + assertEquals(nullValue(), eval(DSL.day_of_week(functionProperties, nullRef))); + assertEquals(missingValue(), eval(DSL.day_of_week(functionProperties, missingRef))); - expression = DSL.dayofweek(DSL.literal(new ExprDateValue("2020-08-09"))); - assertEquals(INTEGER, expression.type()); - assertEquals("dayofweek(DATE '2020-08-09')", expression.toString()); - assertEquals(integerValue(1), eval(expression)); + assertAll( + //40th day of the month + () -> assertThrows(SemanticCheckException.class, + () -> testInvalidDayOfWeek("2021-02-40")), - expression = DSL.dayofweek(DSL.literal("2020-08-09")); - assertEquals(INTEGER, expression.type()); - assertEquals("dayofweek(\"2020-08-09\")", expression.toString()); - assertEquals(integerValue(1), eval(expression)); + //13th month of the year + () -> assertThrows(SemanticCheckException.class, + () -> testInvalidDayOfWeek("2021-13-29")), - expression = DSL.dayofweek(DSL.literal("2020-08-09 01:02:03")); - assertEquals(INTEGER, expression.type()); - assertEquals("dayofweek(\"2020-08-09 01:02:03\")", expression.toString()); - assertEquals(integerValue(1), eval(expression)); + //incorrect format + () -> assertThrows(SemanticCheckException.class, + () -> testInvalidDayOfWeek("asdfasdf")) + ); } @Test @@ -486,7 +604,7 @@ public void dayOfYear() { assertEquals(integerValue(220), eval(expression)); } - public void testDayOfYearWithUnderscores(String date, int dayOfYear) { + private void testDayOfYearWithUnderscores(String date, int dayOfYear) { FunctionExpression expression = DSL.day_of_year(DSL.literal(new ExprDateValue(date))); assertEquals(INTEGER, expression.type()); assertEquals(integerValue(dayOfYear), eval(expression)); @@ -553,7 +671,7 @@ public void dayOfYearWithUnderscoresLeapYear() { ); } - public void testInvalidDayOfYear(String date) { + private void testInvalidDayOfYear(String date) { FunctionExpression expression = DSL.day_of_year(DSL.literal(new ExprDateValue(date))); eval(expression); } @@ -871,7 +989,7 @@ public void month() { assertEquals(integerValue(8), eval(expression)); } - public void testInvalidDates(String date) throws SemanticCheckException { + private void testInvalidDates(String date) throws SemanticCheckException { FunctionExpression expression = DSL.month_of_year(DSL.literal(new ExprDateValue(date))); eval(expression); } diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index 0ca2a6bad4..be5e788ca6 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -1454,20 +1454,21 @@ Description Usage: dayofweek(date) returns the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday). +The `day_of_week` function is also provided as an alias. + Argument type: STRING/DATE/DATETIME/TIMESTAMP Return type: INTEGER Example:: - os> SELECT DAYOFWEEK(DATE('2020-08-26')) + os> SELECT DAYOFWEEK('2020-08-26'), DAY_OF_WEEK('2020-08-26') fetched rows / total rows = 1/1 - +---------------------------------+ - | DAYOFWEEK(DATE('2020-08-26')) | - |---------------------------------| - | 4 | - +---------------------------------+ - + +---------------------------+-----------------------------+ + | DAYOFWEEK('2020-08-26') | DAY_OF_WEEK('2020-08-26') | + |---------------------------+-----------------------------| + | 4 | 4 | + +---------------------------+-----------------------------+ DAYOFYEAR diff --git a/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java b/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java index 6255ccf010..95e232ab21 100644 --- a/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java +++ b/integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java @@ -219,6 +219,49 @@ public void testDayOfWeek() throws IOException { verifyDataRows(result, rows(4)); } + @Test + public void testDayOfWeekWithUnderscores() throws IOException { + JSONObject result = executeQuery("select day_of_week(date('2020-09-16'))"); + verifySchema(result, schema("day_of_week(date('2020-09-16'))", null, "integer")); + verifyDataRows(result, rows(4)); + + result = executeQuery("select day_of_week('2020-09-16')"); + verifySchema(result, schema("day_of_week('2020-09-16')", null, "integer")); + verifyDataRows(result, rows(4)); + } + + @Test + public void testDayOfWeekAliasesReturnTheSameResults() throws IOException { + JSONObject result1 = executeQuery("SELECT dayofweek(date('2022-11-22'))"); + JSONObject result2 = executeQuery("SELECT day_of_week(date('2022-11-22'))"); + verifyDataRows(result1, rows(3)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + + result1 = executeQuery(String.format( + "SELECT dayofweek(CAST(date0 AS date)) FROM %s", TEST_INDEX_CALCS)); + result2 = executeQuery(String.format( + "SELECT day_of_week(CAST(date0 AS date)) FROM %s", TEST_INDEX_CALCS)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + + result1 = executeQuery(String.format( + "SELECT dayofweek(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS)); + result2 = executeQuery(String.format( + "SELECT day_of_week(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + + result1 = executeQuery(String.format( + "SELECT dayofweek(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS)); + result2 = executeQuery(String.format( + "SELECT day_of_week(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + + result1 = executeQuery(String.format( + "SELECT dayofweek(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS)); + result2 = executeQuery(String.format( + "SELECT day_of_week(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS)); + result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + } + @Test public void testDayOfYear() throws IOException { JSONObject result = executeQuery("select dayofyear(date('2020-09-16'))"); diff --git a/sql/src/main/antlr/OpenSearchSQLParser.g4 b/sql/src/main/antlr/OpenSearchSQLParser.g4 index 0ef7e21b42..e8db0de53b 100644 --- a/sql/src/main/antlr/OpenSearchSQLParser.g4 +++ b/sql/src/main/antlr/OpenSearchSQLParser.g4 @@ -435,6 +435,7 @@ dateTimeFunctionName | DAYOFMONTH | DAYOFWEEK | DAYOFYEAR + | DAY_OF_WEEK | FROM_DAYS | FROM_UNIXTIME | HOUR diff --git a/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java b/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java index eee476a56a..32715a64e1 100644 --- a/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java +++ b/sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java @@ -201,6 +201,12 @@ public void can_parse_week_of_year_functions() { assertNotNull(parser.parse("SELECT week_of_year('2022-11-18')")); } + @Test + public void can_parse_day_of_week_functions() { + assertNotNull(parser.parse("SELECT dayofweek('2022-11-18')")); + assertNotNull(parser.parse("SELECT day_of_week('2022-11-18')")); + } + @Test public void can_parse_dayofyear_functions() { assertNotNull(parser.parse("SELECT dayofyear('2022-11-18')")); From 57e3250c143949b061f6d7b1ed8f171a2fd7d8a9 Mon Sep 17 00:00:00 2001 From: GabeFernandez310 Date: Fri, 6 Jan 2023 12:06:22 -0800 Subject: [PATCH 4/6] Fixed Imports Signed-off-by: GabeFernandez310 --- .../sql/sql/parser/AstExpressionBuilder.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java b/sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java index 1c01f8aaf7..14044cbb30 100644 --- a/sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java +++ b/sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java @@ -16,8 +16,9 @@ import static org.opensearch.sql.expression.function.BuiltinFunctionName.NOT_LIKE; import static org.opensearch.sql.expression.function.BuiltinFunctionName.POSITION; import static org.opensearch.sql.expression.function.BuiltinFunctionName.REGEXP; +import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AltMultiFieldRelevanceFunctionContext; +import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AltSingleFieldRelevanceFunctionContext; import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AlternateMultiMatchFieldContext; -import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AlternateMultiMatchQueryContext; import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.BetweenPredicateContext; import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.BinaryComparisonPredicateContext; import static org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.BooleanContext; @@ -96,6 +97,7 @@ import org.opensearch.sql.ast.tree.Sort.SortOption; import org.opensearch.sql.common.utils.StringUtils; import org.opensearch.sql.expression.function.BuiltinFunctionName; +import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AlternateMultiMatchQueryContext; import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.AndExpressionContext; import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.ColumnNameContext; import org.opensearch.sql.sql.antlr.parser.OpenSearchSQLParser.IdentContext; @@ -431,7 +433,7 @@ public UnresolvedExpression visitSingleFieldRelevanceFunction( @Override public UnresolvedExpression visitAltSingleFieldRelevanceFunction( - OpenSearchSQLParser.AltSingleFieldRelevanceFunctionContext ctx) { + AltSingleFieldRelevanceFunctionContext ctx) { return new Function( ctx.altSyntaxFunctionName.getText().toLowerCase(), altSingleFieldRelevanceFunctionArguments(ctx)); @@ -460,7 +462,7 @@ public UnresolvedExpression visitMultiFieldRelevanceFunction( @Override public UnresolvedExpression visitAltMultiFieldRelevanceFunction( - OpenSearchSQLParser.AltMultiFieldRelevanceFunctionContext ctx) { + AltMultiFieldRelevanceFunctionContext ctx) { return new Function( ctx.altSyntaxFunctionName.getText().toLowerCase(), altMultiFieldRelevanceFunctionArguments(ctx)); @@ -523,7 +525,7 @@ private List singleFieldRelevanceArguments( private List altSingleFieldRelevanceFunctionArguments( - OpenSearchSQLParser.AltSingleFieldRelevanceFunctionContext ctx) { + AltSingleFieldRelevanceFunctionContext ctx) { // all the arguments are defaulted to string values // to skip environment resolving and function signature resolving ImmutableList.Builder builder = ImmutableList.builder(); @@ -591,7 +593,7 @@ private List alternateMultiMatchArguments( } private List altMultiFieldRelevanceFunctionArguments( - OpenSearchSQLParser.AltMultiFieldRelevanceFunctionContext ctx) { + AltMultiFieldRelevanceFunctionContext ctx) { // all the arguments are defaulted to string values // to skip environment resolving and function signature resolving var map = new HashMap(); From 864099c7ac7c0055c2d7abd2d42c793637ff6937 Mon Sep 17 00:00:00 2001 From: GabeFernandez310 Date: Fri, 6 Jan 2023 14:27:20 -0800 Subject: [PATCH 5/6] Fixed Casting Issue Signed-off-by: GabeFernandez310 --- .../org/opensearch/sql/sql/parser/AstExpressionBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java b/sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java index 14044cbb30..e40f2edb03 100644 --- a/sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java +++ b/sql/src/main/java/org/opensearch/sql/sql/parser/AstExpressionBuilder.java @@ -530,7 +530,7 @@ private List altSingleFieldRelevanceFunctionArguments( // to skip environment resolving and function signature resolving ImmutableList.Builder builder = ImmutableList.builder(); builder.add(new UnresolvedArgument("field", - new Literal(StringUtils.unquoteText(ctx.field.getText()), DataType.STRING))); + new QualifiedName(StringUtils.unquoteText(ctx.field.getText())))); builder.add(new UnresolvedArgument("query", new Literal(StringUtils.unquoteText(ctx.query.getText()), DataType.STRING))); fillRelevanceArgs(ctx.relevanceArg(), builder); From a707e3f3a5e5df7f809ef89836cbb97275a70d94 Mon Sep 17 00:00:00 2001 From: GabeFernandez310 Date: Fri, 6 Jan 2023 14:57:14 -0800 Subject: [PATCH 6/6] Fixed Unit Tests Signed-off-by: GabeFernandez310 --- .../sql/parser/AstExpressionBuilderTest.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/sql/src/test/java/org/opensearch/sql/sql/parser/AstExpressionBuilderTest.java b/sql/src/test/java/org/opensearch/sql/sql/parser/AstExpressionBuilderTest.java index 0bc44cdffd..23d3ddbc49 100644 --- a/sql/src/test/java/org/opensearch/sql/sql/parser/AstExpressionBuilderTest.java +++ b/sql/src/test/java/org/opensearch/sql/sql/parser/AstExpressionBuilderTest.java @@ -576,26 +576,26 @@ public void relevanceMatch_Query() { public void relevanceMatchQueryAltSyntax() { assertEquals(AstDSL.function("match_query", unresolvedArg("field", stringLiteral("message")), - unresolvedArg("query", stringLiteral("search query"))), - buildExprAst("message = match_query('search query')") + unresolvedArg("query", stringLiteral("search query"))).toString(), + buildExprAst("message = match_query('search query')").toString() ); assertEquals(AstDSL.function("match_query", unresolvedArg("field", stringLiteral("message")), - unresolvedArg("query", stringLiteral("search query"))), - buildExprAst("message = match_query(\"search query\")") + unresolvedArg("query", stringLiteral("search query"))).toString(), + buildExprAst("message = match_query(\"search query\")").toString() ); assertEquals(AstDSL.function("matchquery", unresolvedArg("field", stringLiteral("message")), - unresolvedArg("query", stringLiteral("search query"))), - buildExprAst("message = matchquery('search query')") + unresolvedArg("query", stringLiteral("search query"))).toString(), + buildExprAst("message = matchquery('search query')").toString() ); assertEquals(AstDSL.function("matchquery", unresolvedArg("field", stringLiteral("message")), - unresolvedArg("query", stringLiteral("search query"))), - buildExprAst("message = matchquery(\"search query\")") + unresolvedArg("query", stringLiteral("search query"))).toString(), + buildExprAst("message = matchquery(\"search query\")").toString() ); } @@ -603,26 +603,26 @@ public void relevanceMatchQueryAltSyntax() { public void relevanceMatchPhraseAltSyntax() { assertEquals(AstDSL.function("match_phrase", unresolvedArg("field", stringLiteral("message")), - unresolvedArg("query", stringLiteral("search query"))), - buildExprAst("message = match_phrase('search query')") + unresolvedArg("query", stringLiteral("search query"))).toString(), + buildExprAst("message = match_phrase('search query')").toString() ); assertEquals(AstDSL.function("match_phrase", unresolvedArg("field", stringLiteral("message")), - unresolvedArg("query", stringLiteral("search query"))), - buildExprAst("message = match_phrase(\"search query\")") + unresolvedArg("query", stringLiteral("search query"))).toString(), + buildExprAst("message = match_phrase(\"search query\")").toString() ); assertEquals(AstDSL.function("matchphrase", unresolvedArg("field", stringLiteral("message")), - unresolvedArg("query", stringLiteral("search query"))), - buildExprAst("message = matchphrase('search query')") + unresolvedArg("query", stringLiteral("search query"))).toString(), + buildExprAst("message = matchphrase('search query')").toString() ); assertEquals(AstDSL.function("matchphrase", unresolvedArg("field", stringLiteral("message")), - unresolvedArg("query", stringLiteral("search query"))), - buildExprAst("message = matchphrase(\"search query\")") + unresolvedArg("query", stringLiteral("search query"))).toString(), + buildExprAst("message = matchphrase(\"search query\")").toString() ); }