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 5745372bb5..616f431283 100644 --- a/core/src/main/java/org/opensearch/sql/expression/DSL.java +++ b/core/src/main/java/org/opensearch/sql/expression/DSL.java @@ -439,6 +439,11 @@ public static FunctionExpression week( return compile(functionProperties, BuiltinFunctionName.WEEK, expressions); } + public static FunctionExpression weekofyear( + FunctionProperties functionProperties, Expression... expressions) { + return compile(functionProperties, BuiltinFunctionName.WEEKOFYEAR, expressions); + } + public static FunctionExpression week_of_year( FunctionProperties functionProperties, Expression... expressions) { return compile(functionProperties, BuiltinFunctionName.WEEK_OF_YEAR, 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 61555480e3..fc8cdc93ef 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 @@ -193,6 +193,7 @@ public void register(BuiltinFunctionRepository repository) { repository.register(to_days()); repository.register(unix_timestamp()); repository.register(week(BuiltinFunctionName.WEEK)); + repository.register(week(BuiltinFunctionName.WEEKOFYEAR)); repository.register(week(BuiltinFunctionName.WEEK_OF_YEAR)); repository.register(year()); } 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 54c74294f0..ec4a7bc140 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 @@ -109,6 +109,7 @@ public enum BuiltinFunctionName { UTC_TIMESTAMP(FunctionName.of("utc_timestamp")), UNIX_TIMESTAMP(FunctionName.of("unix_timestamp")), WEEK(FunctionName.of("week")), + WEEKOFYEAR(FunctionName.of("weekofyear")), WEEK_OF_YEAR(FunctionName.of("week_of_year")), YEAR(FunctionName.of("year")), // `now`-like functions 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 3ad3fd608b..fdb029ca90 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 @@ -1498,7 +1498,7 @@ private void weekQuery(String date, int mode, int expectedResult) { assertEquals(integerValue(expectedResult), eval(expression)); } - private void weekOfYearQuery(String date, int mode, int expectedResult) { + private void weekOfYearUnderscoresQuery(String date, int mode, int expectedResult) { FunctionExpression expression = DSL .week_of_year( functionProperties, @@ -1508,6 +1508,16 @@ private void weekOfYearQuery(String date, int mode, int expectedResult) { assertEquals(integerValue(expectedResult), eval(expression)); } + private void weekOfYearQuery(String date, int mode, int expectedResult) { + FunctionExpression expression = DSL + .weekofyear( + functionProperties, + DSL.literal(new ExprDateValue(date)), DSL.literal(mode)); + assertEquals(INTEGER, expression.type()); + assertEquals(String.format("weekofyear(DATE '%s', %d)", date, mode), expression.toString()); + assertEquals(integerValue(expectedResult), eval(expression)); + } + private void nullMissingWeekQuery(ExprCoreType date) { when(nullRef.type()).thenReturn(date); when(missingRef.type()).thenReturn(date); @@ -1581,6 +1591,7 @@ public void testWeek(String date, int mode, int expected) { lenient().when(missingRef.valueOf(env)).thenReturn(missingValue()); weekQuery(date, mode, expected); weekOfYearQuery(date, mode, expected); + weekOfYearUnderscoresQuery(date, mode, expected); } private void validateStringFormat( @@ -1630,6 +1641,9 @@ public void testWeekFormats( validateStringFormat( DSL.week_of_year(functionProperties, arg), String.format("week_of_year(%s)", expectedString), expectedInteger); + validateStringFormat( + DSL.weekofyear(functionProperties, arg), + String.format("weekofyear(%s)", expectedString), expectedInteger); } @Test @@ -1649,6 +1663,11 @@ public void testWeekOfYearWithTimeType() { () -> validateStringFormat( DSL.week_of_year(functionProperties, DSL.literal(new ExprTimeValue("12:23:34"))), "week_of_year(TIME '12:23:34')", + LocalDate.now(functionProperties.getQueryStartClock()).get(ALIGNED_WEEK_OF_YEAR)), + + () -> validateStringFormat( + DSL.weekofyear(functionProperties, DSL.literal(new ExprTimeValue("12:23:34"))), + "weekofyear(TIME '12:23:34')", LocalDate.now(functionProperties.getQueryStartClock()).get(ALIGNED_WEEK_OF_YEAR)) ); } @@ -1705,6 +1724,7 @@ public void testInvalidWeekOfYear() { nullRef, missingRef))); assertAll( + //Test for WeekOfYear //test invalid month () -> assertThrows( SemanticCheckException.class, @@ -1716,7 +1736,21 @@ public void testInvalidWeekOfYear() { //test invalid leap year () -> assertThrows( SemanticCheckException.class, - () -> weekOfYearQuery("2019-02-29 01:02:03", 0, 0)) + () -> weekOfYearQuery("2019-02-29 01:02:03", 0, 0)), + + //Test for Week_Of_Year + //test invalid month + () -> assertThrows( + SemanticCheckException.class, + () -> weekOfYearUnderscoresQuery("2019-13-05 01:02:03", 0, 0)), + //test invalid day + () -> assertThrows( + SemanticCheckException.class, + () -> weekOfYearUnderscoresQuery("2019-01-50 01:02:03", 0, 0)), + //test invalid leap year + () -> assertThrows( + SemanticCheckException.class, + () -> weekOfYearUnderscoresQuery("2019-02-29 01:02:03", 0, 0)) ); } diff --git a/docs/user/dql/functions.rst b/docs/user/dql/functions.rst index c015b0e0d2..5d5a3e1f96 100644 --- a/docs/user/dql/functions.rst +++ b/docs/user/dql/functions.rst @@ -2570,7 +2570,7 @@ Description Usage: week(date[, mode]) returns the week number for date. If the mode argument is omitted, the default mode 0 is used. If an argument of type `TIME` is given, the function will use the current date. -The function `week_of_year` is also provided as an alias. +The functions `weekofyear` and `week_of_year` is also provided as an alias. .. list-table:: The following table describes how the mode argument works. :widths: 25 50 25 75 @@ -2628,7 +2628,7 @@ Example:: +----------------------------+-------------------------------+ WEEK_OF_YEAR ----- +------------ Description >>>>>>>>>>> @@ -2651,6 +2651,30 @@ Example:: +------------------------------------+---------------------------------------+ +WEEKOFYEAR +---------- + +Description +>>>>>>>>>>> + +The weekofyear function is a synonym for the `week`_ function. +If an argument of type `TIME` is given, the function will use the current date. + +Argument type: DATE/DATETIME/TIME/TIMESTAMP/STRING + +Return type: INTEGER + +Example:: + + os> SELECT WEEKOFYEAR(DATE('2008-02-20')), WEEKOFYEAR(DATE('2008-02-20'), 1) + fetched rows / total rows = 1/1 + +----------------------------------+-------------------------------------+ + | WEEKOFYEAR(DATE('2008-02-20')) | WEEKOFYEAR(DATE('2008-02-20'), 1) | + |----------------------------------+-------------------------------------| + | 7 | 8 | + +----------------------------------+-------------------------------------+ + + YEAR ---- 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 19ca270d33..4254641524 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 @@ -933,7 +933,7 @@ public void testWeek() throws IOException { } @Test - public void testWeekOfYear() throws IOException { + public void testWeekOfYearUnderscores() throws IOException { JSONObject result = executeQuery("select week_of_year(date('2008-02-20'))"); verifySchema(result, schema("week_of_year(date('2008-02-20'))", null, "integer")); verifyDataRows(result, rows(7)); @@ -946,35 +946,43 @@ public void testWeekOfYear() throws IOException { } @Test - public void testWeekAlternateSyntaxesReturnTheSameResults() throws IOException { - JSONObject result1 = executeQuery("SELECT week(date('2022-11-22'))"); - JSONObject result2 = executeQuery("SELECT week_of_year(date('2022-11-22'))"); - verifyDataRows(result1, rows(47)); - result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + public void testWeekOfYear() throws IOException { + JSONObject result = executeQuery("select weekofyear(date('2008-02-20'))"); + verifySchema(result, schema("weekofyear(date('2008-02-20'))", null, "integer")); + verifyDataRows(result, rows(7)); - result1 = executeQuery(String.format( - "SELECT week(CAST(date0 AS date)) FROM %s", TEST_INDEX_CALCS)); - result2 = executeQuery(String.format( - "SELECT week_of_year(CAST(date0 AS date)) FROM %s", TEST_INDEX_CALCS)); - result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + week("2008-02-20", 0, 7, "weekofyear"); + week("2008-02-20", 1, 8, "weekofyear"); + week("2008-12-31", 1, 53, "weekofyear"); + week("2000-01-01", 0, 0, "weekofyear"); + week("2000-01-01", 2, 52, "week_of_year"); + } - result1 = executeQuery(String.format( - "SELECT week(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS)); - result2 = executeQuery(String.format( - "SELECT week_of_year(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS)); - result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + private void compareWeekResults(String arg, String table) throws IOException { + JSONObject result1 = executeQuery(String.format( + "SELECT week(%s) FROM %s", arg, table)); + JSONObject result2 = executeQuery(String.format( + "SELECT week_of_year(%s) FROM %s", arg, table)); + JSONObject result3 = executeQuery(String.format( + "SELECT weekofyear(%s) FROM %s", arg, table)); - result1 = executeQuery(String.format( - "SELECT week(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS)); - result2 = executeQuery(String.format( - "SELECT week_of_year(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS)); result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + result1.getJSONArray("datarows").similar(result3.getJSONArray("datarows")); + } - result1 = executeQuery(String.format( - "SELECT week(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS)); - result2 = executeQuery(String.format( - "SELECT week_of_year(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS)); + @Test + public void testWeekAlternateSyntaxesReturnTheSameResults() throws IOException { + JSONObject result1 = executeQuery("SELECT week(date('2022-11-22'))"); + JSONObject result2 = executeQuery("SELECT week_of_year(date('2022-11-22'))"); + JSONObject result3 = executeQuery("SELECT weekofyear(date('2022-11-22'))"); + verifyDataRows(result1, rows(47)); result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows")); + result1.getJSONArray("datarows").similar(result3.getJSONArray("datarows")); + + compareWeekResults("CAST(date0 AS date)", TEST_INDEX_CALCS); + compareWeekResults("datetime(CAST(time0 AS STRING))", TEST_INDEX_CALCS); + compareWeekResults("CAST(time0 AS STRING)", TEST_INDEX_CALCS); + compareWeekResults("CAST(datetime0 AS timestamp)", TEST_INDEX_CALCS); } void verifyDateFormat(String date, String type, String format, String formatted) throws IOException { diff --git a/sql/src/main/antlr/OpenSearchSQLLexer.g4 b/sql/src/main/antlr/OpenSearchSQLLexer.g4 index 018f19110d..25f23a7bd6 100644 --- a/sql/src/main/antlr/OpenSearchSQLLexer.g4 +++ b/sql/src/main/antlr/OpenSearchSQLLexer.g4 @@ -330,6 +330,7 @@ TERMS: 'TERMS'; TOPHITS: 'TOPHITS'; TYPEOF: 'TYPEOF'; WEEK_OF_YEAR: 'WEEK_OF_YEAR'; +WEEKOFYEAR: 'WEEKOFYEAR'; WILDCARDQUERY: 'WILDCARDQUERY'; WILDCARD_QUERY: 'WILDCARD_QUERY'; diff --git a/sql/src/main/antlr/OpenSearchSQLParser.g4 b/sql/src/main/antlr/OpenSearchSQLParser.g4 index d26c789b0a..e5efeabba0 100644 --- a/sql/src/main/antlr/OpenSearchSQLParser.g4 +++ b/sql/src/main/antlr/OpenSearchSQLParser.g4 @@ -480,6 +480,7 @@ dateTimeFunctionName | UNIX_TIMESTAMP | WEEK | WEEK_OF_YEAR + | WEEKOFYEAR | YEAR ;