Skip to content

Commit bac9c37

Browse files
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 <[email protected]> Signed-off-by: GabeFernandez310 <[email protected]>
1 parent 61e2374 commit bac9c37

File tree

8 files changed

+226
-36
lines changed

8 files changed

+226
-36
lines changed

core/src/main/java/org/opensearch/sql/expression/DSL.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,8 +326,9 @@ public static FunctionExpression dayofmonth(Expression... expressions) {
326326
return compile(FunctionProperties.None, BuiltinFunctionName.DAYOFMONTH, expressions);
327327
}
328328

329-
public static FunctionExpression dayofweek(Expression... expressions) {
330-
return compile(FunctionProperties.None, BuiltinFunctionName.DAYOFWEEK, expressions);
329+
public static FunctionExpression dayofweek(
330+
FunctionProperties functionProperties, Expression... expressions) {
331+
return compile(functionProperties, BuiltinFunctionName.DAYOFWEEK, expressions);
331332
}
332333

333334
public static FunctionExpression dayofyear(Expression... expressions) {
@@ -338,6 +339,11 @@ public static FunctionExpression day_of_year(Expression... expressions) {
338339
return compile(FunctionProperties.None, BuiltinFunctionName.DAY_OF_YEAR, expressions);
339340
}
340341

342+
public static FunctionExpression day_of_week(
343+
FunctionProperties functionProperties, Expression... expressions) {
344+
return compile(functionProperties, BuiltinFunctionName.DAY_OF_WEEK, expressions);
345+
}
346+
341347
public static FunctionExpression from_days(Expression... expressions) {
342348
return compile(FunctionProperties.None, BuiltinFunctionName.FROM_DAYS, expressions);
343349
}

core/src/main/java/org/opensearch/sql/expression/datetime/DateTimeFunction.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ public void register(BuiltinFunctionRepository repository) {
109109
repository.register(day());
110110
repository.register(dayName());
111111
repository.register(dayOfMonth());
112-
repository.register(dayOfWeek());
112+
repository.register(dayOfWeek(BuiltinFunctionName.DAYOFWEEK.getName()));
113+
repository.register(dayOfWeek(BuiltinFunctionName.DAY_OF_WEEK.getName()));
113114
repository.register(dayOfYear(BuiltinFunctionName.DAYOFYEAR));
114115
repository.register(dayOfYear(BuiltinFunctionName.DAY_OF_YEAR));
115116
repository.register(from_days());
@@ -401,11 +402,14 @@ private DefaultFunctionResolver dayOfMonth() {
401402
}
402403

403404
/**
404-
* DAYOFWEEK(STRING/DATE/DATETIME/TIMESTAMP).
405+
* DAYOFWEEK(STRING/DATE/DATETIME/TIME/TIMESTAMP).
405406
* return the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday).
406407
*/
407-
private DefaultFunctionResolver dayOfWeek() {
408-
return define(BuiltinFunctionName.DAYOFWEEK.getName(),
408+
private DefaultFunctionResolver dayOfWeek(FunctionName name) {
409+
return define(name,
410+
implWithProperties(nullMissingHandlingWithProperties(
411+
(functionProperties, arg) -> DateTimeFunction.dayOfWeekToday(
412+
functionProperties.getQueryStartClock())), INTEGER, TIME),
409413
impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), INTEGER, DATE),
410414
impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), INTEGER, DATETIME),
411415
impl(nullMissingHandling(DateTimeFunction::exprDayOfWeek), INTEGER, TIMESTAMP),
@@ -728,6 +732,16 @@ private DefaultFunctionResolver date_format() {
728732
);
729733
}
730734

735+
/**
736+
* Day of Week implementation for ExprValue when passing in an arguemt of type TIME.
737+
*
738+
* @param clock Current clock taken from function properties
739+
* @return ExprValue.
740+
*/
741+
private ExprValue dayOfWeekToday(Clock clock) {
742+
return new ExprIntegerValue((formatNow(clock).getDayOfWeek().getValue() % 7) + 1);
743+
}
744+
731745
/**
732746
* ADDDATE function implementation for ExprValue.
733747
*
@@ -900,7 +914,7 @@ private ExprValue exprDayOfMonth(ExprValue date) {
900914
/**
901915
* Day of Week implementation for ExprValue.
902916
*
903-
* @param date ExprValue of Date/String type.
917+
* @param date ExprValue of Date/Datetime/String/Timstamp type.
904918
* @return ExprValue.
905919
*/
906920
private ExprValue exprDayOfWeek(ExprValue date) {

core/src/main/java/org/opensearch/sql/expression/function/BuiltinFunctionName.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ public enum BuiltinFunctionName {
7070
DAYOFMONTH(FunctionName.of("dayofmonth")),
7171
DAYOFWEEK(FunctionName.of("dayofweek")),
7272
DAYOFYEAR(FunctionName.of("dayofyear")),
73+
DAY_OF_WEEK(FunctionName.of("day_of_week")),
7374
DAY_OF_YEAR(FunctionName.of("day_of_year")),
7475
FROM_DAYS(FunctionName.of("from_days")),
7576
FROM_UNIXTIME(FunctionName.of("from_unixtime")),

core/src/test/java/org/opensearch/sql/expression/datetime/DateTimeFunctionTest.java

Lines changed: 140 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -435,32 +435,150 @@ public void dayOfMonth() {
435435
assertEquals(integerValue(8), eval(expression));
436436
}
437437

438+
private void dayOfWeekQuery(
439+
FunctionExpression dateExpression,
440+
int dayOfWeek,
441+
String testExpr) {
442+
assertEquals(INTEGER, dateExpression.type());
443+
assertEquals(integerValue(dayOfWeek), eval(dateExpression));
444+
assertEquals(testExpr, dateExpression.toString());
445+
}
446+
438447
@Test
439448
public void dayOfWeek() {
449+
lenient().when(nullRef.valueOf(env)).thenReturn(nullValue());
450+
lenient().when(missingRef.valueOf(env)).thenReturn(missingValue());
451+
452+
FunctionExpression expression1 = DSL.dayofweek(
453+
functionProperties,
454+
DSL.literal(new ExprDateValue("2020-08-07")));
455+
FunctionExpression expression2 = DSL.dayofweek(
456+
functionProperties,
457+
DSL.literal(new ExprDateValue("2020-08-09")));
458+
FunctionExpression expression3 = DSL.dayofweek(
459+
functionProperties,
460+
DSL.literal("2020-08-09"));
461+
FunctionExpression expression4 = DSL.dayofweek(
462+
functionProperties,
463+
DSL.literal("2020-08-09 01:02:03"));
464+
465+
assertAll(
466+
() -> dayOfWeekQuery(expression1, 6, "dayofweek(DATE '2020-08-07')"),
467+
468+
() -> dayOfWeekQuery(expression2, 1, "dayofweek(DATE '2020-08-09')"),
469+
470+
() -> dayOfWeekQuery(expression3, 1, "dayofweek(\"2020-08-09\")"),
471+
472+
() -> dayOfWeekQuery(expression4, 1, "dayofweek(\"2020-08-09 01:02:03\")")
473+
);
474+
}
475+
476+
private void dayOfWeekWithUnderscoresQuery(
477+
FunctionExpression dateExpression,
478+
int dayOfWeek,
479+
String testExpr) {
480+
assertEquals(INTEGER, dateExpression.type());
481+
assertEquals(integerValue(dayOfWeek), eval(dateExpression));
482+
assertEquals(testExpr, dateExpression.toString());
483+
}
484+
485+
@Test
486+
public void dayOfWeekWithUnderscores() {
487+
lenient().when(nullRef.valueOf(env)).thenReturn(nullValue());
488+
lenient().when(missingRef.valueOf(env)).thenReturn(missingValue());
489+
490+
FunctionExpression expression1 = DSL.day_of_week(
491+
functionProperties,
492+
DSL.literal(new ExprDateValue("2020-08-07")));
493+
FunctionExpression expression2 = DSL.day_of_week(
494+
functionProperties,
495+
DSL.literal(new ExprDateValue("2020-08-09")));
496+
FunctionExpression expression3 = DSL.day_of_week(
497+
functionProperties,
498+
DSL.literal("2020-08-09"));
499+
FunctionExpression expression4 = DSL.day_of_week(
500+
functionProperties,
501+
DSL.literal("2020-08-09 01:02:03"));
502+
503+
assertAll(
504+
() -> dayOfWeekWithUnderscoresQuery(expression1, 6, "day_of_week(DATE '2020-08-07')"),
505+
506+
() -> dayOfWeekWithUnderscoresQuery(expression2, 1, "day_of_week(DATE '2020-08-09')"),
507+
508+
() -> dayOfWeekWithUnderscoresQuery(expression3, 1, "day_of_week(\"2020-08-09\")"),
509+
510+
() -> dayOfWeekWithUnderscoresQuery(
511+
expression4, 1, "day_of_week(\"2020-08-09 01:02:03\")")
512+
);
513+
}
514+
515+
@Test
516+
public void testDayOfWeekWithTimeType() {
517+
lenient().when(nullRef.valueOf(env)).thenReturn(nullValue());
518+
lenient().when(missingRef.valueOf(env)).thenReturn(missingValue());
519+
FunctionExpression expression = DSL.day_of_week(
520+
functionProperties, DSL.literal(new ExprTimeValue("12:23:34")));
521+
522+
assertAll(
523+
() -> assertEquals(INTEGER, eval(expression).type()),
524+
() -> assertEquals((
525+
LocalDate.now(
526+
functionProperties.getQueryStartClock()).getDayOfWeek().getValue() % 7) + 1,
527+
eval(expression).integerValue()),
528+
() -> assertEquals("day_of_week(TIME '12:23:34')", expression.toString())
529+
);
530+
}
531+
532+
private void testInvalidDayOfWeek(String date) {
533+
FunctionExpression expression = DSL.day_of_week(
534+
functionProperties, DSL.literal(new ExprDateValue(date)));
535+
eval(expression);
536+
}
537+
538+
@Test
539+
public void dayOfWeekWithUnderscoresLeapYear() {
540+
lenient().when(nullRef.valueOf(env)).thenReturn(nullValue());
541+
lenient().when(missingRef.valueOf(env)).thenReturn(missingValue());
542+
543+
assertAll(
544+
//Feb. 29 of a leap year
545+
() -> dayOfWeekWithUnderscoresQuery(DSL.day_of_week(
546+
functionProperties,
547+
DSL.literal("2020-02-29")), 7, "day_of_week(\"2020-02-29\")"),
548+
//day after Feb. 29 of a leap year
549+
() -> dayOfWeekWithUnderscoresQuery(DSL.day_of_week(
550+
functionProperties,
551+
DSL.literal("2020-03-01")), 1, "day_of_week(\"2020-03-01\")"),
552+
//Feb. 28 of a non-leap year
553+
() -> dayOfWeekWithUnderscoresQuery(DSL.day_of_week(
554+
functionProperties,
555+
DSL.literal("2021-02-28")), 1, "day_of_week(\"2021-02-28\")"),
556+
//Feb. 29 of a non-leap year
557+
() -> assertThrows(
558+
SemanticCheckException.class, () -> testInvalidDayOfWeek("2021-02-29"))
559+
);
560+
}
561+
562+
@Test
563+
public void dayOfWeekWithUnderscoresInvalidArgument() {
440564
when(nullRef.type()).thenReturn(DATE);
441565
when(missingRef.type()).thenReturn(DATE);
442-
assertEquals(nullValue(), eval(DSL.dayofweek(nullRef)));
443-
assertEquals(missingValue(), eval(DSL.dayofweek(missingRef)));
444-
445-
FunctionExpression expression = DSL.dayofweek(DSL.literal(new ExprDateValue("2020-08-07")));
446-
assertEquals(INTEGER, expression.type());
447-
assertEquals("dayofweek(DATE '2020-08-07')", expression.toString());
448-
assertEquals(integerValue(6), eval(expression));
566+
assertEquals(nullValue(), eval(DSL.day_of_week(functionProperties, nullRef)));
567+
assertEquals(missingValue(), eval(DSL.day_of_week(functionProperties, missingRef)));
449568

450-
expression = DSL.dayofweek(DSL.literal(new ExprDateValue("2020-08-09")));
451-
assertEquals(INTEGER, expression.type());
452-
assertEquals("dayofweek(DATE '2020-08-09')", expression.toString());
453-
assertEquals(integerValue(1), eval(expression));
569+
assertAll(
570+
//40th day of the month
571+
() -> assertThrows(SemanticCheckException.class,
572+
() -> testInvalidDayOfWeek("2021-02-40")),
454573

455-
expression = DSL.dayofweek(DSL.literal("2020-08-09"));
456-
assertEquals(INTEGER, expression.type());
457-
assertEquals("dayofweek(\"2020-08-09\")", expression.toString());
458-
assertEquals(integerValue(1), eval(expression));
574+
//13th month of the year
575+
() -> assertThrows(SemanticCheckException.class,
576+
() -> testInvalidDayOfWeek("2021-13-29")),
459577

460-
expression = DSL.dayofweek(DSL.literal("2020-08-09 01:02:03"));
461-
assertEquals(INTEGER, expression.type());
462-
assertEquals("dayofweek(\"2020-08-09 01:02:03\")", expression.toString());
463-
assertEquals(integerValue(1), eval(expression));
578+
//incorrect format
579+
() -> assertThrows(SemanticCheckException.class,
580+
() -> testInvalidDayOfWeek("asdfasdf"))
581+
);
464582
}
465583

466584
@Test
@@ -486,7 +604,7 @@ public void dayOfYear() {
486604
assertEquals(integerValue(220), eval(expression));
487605
}
488606

489-
public void testDayOfYearWithUnderscores(String date, int dayOfYear) {
607+
private void testDayOfYearWithUnderscores(String date, int dayOfYear) {
490608
FunctionExpression expression = DSL.day_of_year(DSL.literal(new ExprDateValue(date)));
491609
assertEquals(INTEGER, expression.type());
492610
assertEquals(integerValue(dayOfYear), eval(expression));
@@ -553,7 +671,7 @@ public void dayOfYearWithUnderscoresLeapYear() {
553671
);
554672
}
555673

556-
public void testInvalidDayOfYear(String date) {
674+
private void testInvalidDayOfYear(String date) {
557675
FunctionExpression expression = DSL.day_of_year(DSL.literal(new ExprDateValue(date)));
558676
eval(expression);
559677
}
@@ -871,7 +989,7 @@ public void month() {
871989
assertEquals(integerValue(8), eval(expression));
872990
}
873991

874-
public void testInvalidDates(String date) throws SemanticCheckException {
992+
private void testInvalidDates(String date) throws SemanticCheckException {
875993
FunctionExpression expression = DSL.month_of_year(DSL.literal(new ExprDateValue(date)));
876994
eval(expression);
877995
}

docs/user/dql/functions.rst

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,20 +1454,21 @@ Description
14541454

14551455
Usage: dayofweek(date) returns the weekday index for date (1 = Sunday, 2 = Monday, …, 7 = Saturday).
14561456

1457+
The `day_of_week` function is also provided as an alias.
1458+
14571459
Argument type: STRING/DATE/DATETIME/TIMESTAMP
14581460

14591461
Return type: INTEGER
14601462

14611463
Example::
14621464

1463-
os> SELECT DAYOFWEEK(DATE('2020-08-26'))
1465+
os> SELECT DAYOFWEEK('2020-08-26'), DAY_OF_WEEK('2020-08-26')
14641466
fetched rows / total rows = 1/1
1465-
+---------------------------------+
1466-
| DAYOFWEEK(DATE('2020-08-26')) |
1467-
|---------------------------------|
1468-
| 4 |
1469-
+---------------------------------+
1470-
1467+
+---------------------------+-----------------------------+
1468+
| DAYOFWEEK('2020-08-26') | DAY_OF_WEEK('2020-08-26') |
1469+
|---------------------------+-----------------------------|
1470+
| 4 | 4 |
1471+
+---------------------------+-----------------------------+
14711472

14721473

14731474
DAYOFYEAR

integ-test/src/test/java/org/opensearch/sql/sql/DateTimeFunctionIT.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,49 @@ public void testDayOfWeek() throws IOException {
219219
verifyDataRows(result, rows(4));
220220
}
221221

222+
@Test
223+
public void testDayOfWeekWithUnderscores() throws IOException {
224+
JSONObject result = executeQuery("select day_of_week(date('2020-09-16'))");
225+
verifySchema(result, schema("day_of_week(date('2020-09-16'))", null, "integer"));
226+
verifyDataRows(result, rows(4));
227+
228+
result = executeQuery("select day_of_week('2020-09-16')");
229+
verifySchema(result, schema("day_of_week('2020-09-16')", null, "integer"));
230+
verifyDataRows(result, rows(4));
231+
}
232+
233+
@Test
234+
public void testDayOfWeekAliasesReturnTheSameResults() throws IOException {
235+
JSONObject result1 = executeQuery("SELECT dayofweek(date('2022-11-22'))");
236+
JSONObject result2 = executeQuery("SELECT day_of_week(date('2022-11-22'))");
237+
verifyDataRows(result1, rows(3));
238+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
239+
240+
result1 = executeQuery(String.format(
241+
"SELECT dayofweek(CAST(date0 AS date)) FROM %s", TEST_INDEX_CALCS));
242+
result2 = executeQuery(String.format(
243+
"SELECT day_of_week(CAST(date0 AS date)) FROM %s", TEST_INDEX_CALCS));
244+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
245+
246+
result1 = executeQuery(String.format(
247+
"SELECT dayofweek(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS));
248+
result2 = executeQuery(String.format(
249+
"SELECT day_of_week(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS));
250+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
251+
252+
result1 = executeQuery(String.format(
253+
"SELECT dayofweek(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS));
254+
result2 = executeQuery(String.format(
255+
"SELECT day_of_week(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS));
256+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
257+
258+
result1 = executeQuery(String.format(
259+
"SELECT dayofweek(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS));
260+
result2 = executeQuery(String.format(
261+
"SELECT day_of_week(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS));
262+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
263+
}
264+
222265
@Test
223266
public void testDayOfYear() throws IOException {
224267
JSONObject result = executeQuery("select dayofyear(date('2020-09-16'))");

sql/src/main/antlr/OpenSearchSQLParser.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,7 @@ dateTimeFunctionName
435435
| DAYOFMONTH
436436
| DAYOFWEEK
437437
| DAYOFYEAR
438+
| DAY_OF_WEEK
438439
| FROM_DAYS
439440
| FROM_UNIXTIME
440441
| HOUR

sql/src/test/java/org/opensearch/sql/sql/antlr/SQLSyntaxParserTest.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,12 @@ public void can_parse_week_of_year_functions() {
201201
assertNotNull(parser.parse("SELECT week_of_year('2022-11-18')"));
202202
}
203203

204+
@Test
205+
public void can_parse_day_of_week_functions() {
206+
assertNotNull(parser.parse("SELECT dayofweek('2022-11-18')"));
207+
assertNotNull(parser.parse("SELECT day_of_week('2022-11-18')"));
208+
}
209+
204210
@Test
205211
public void can_parse_dayofyear_functions() {
206212
assertNotNull(parser.parse("SELECT dayofyear('2022-11-18')"));

0 commit comments

Comments
 (0)