Skip to content

Commit

Permalink
Add Day_Of_Week Function As An Alias Of DayOfWeek (#190) (#1228)
Browse files Browse the repository at this point in the history
Added Implementation And Testing For Day_Of_Week Function

Signed-off-by: GabeFernandez310 <[email protected]>

Signed-off-by: GabeFernandez310 <[email protected]>
  • Loading branch information
GabeFernandez310 authored Jan 6, 2023
1 parent 61e2374 commit bac9c37
Show file tree
Hide file tree
Showing 8 changed files with 226 additions and 36 deletions.
10 changes: 8 additions & 2 deletions core/src/main/java/org/opensearch/sql/expression/DSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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));
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
}
Expand Down
15 changes: 8 additions & 7 deletions docs/user/dql/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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'))");
Expand Down
1 change: 1 addition & 0 deletions sql/src/main/antlr/OpenSearchSQLParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,7 @@ dateTimeFunctionName
| DAYOFMONTH
| DAYOFWEEK
| DAYOFYEAR
| DAY_OF_WEEK
| FROM_DAYS
| FROM_UNIXTIME
| HOUR
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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')"));
Expand Down

0 comments on commit bac9c37

Please sign in to comment.