Skip to content

Commit c2b7ef2

Browse files
Add Day_Of_Month Function As An Alias Of DayOfMonth (#194)
Added Implementation And Testing For Day_Of_Month Function Signed-off-by: GabeFernandez310 <[email protected]>
1 parent 1b58f7d commit c2b7ef2

File tree

8 files changed

+190
-19
lines changed

8 files changed

+190
-19
lines changed

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,8 +322,10 @@ public static FunctionExpression dayname(Expression... expressions) {
322322
return compile(FunctionProperties.None, BuiltinFunctionName.DAYNAME, expressions);
323323
}
324324

325-
public static FunctionExpression dayofmonth(Expression... expressions) {
326-
return compile(FunctionProperties.None, BuiltinFunctionName.DAYOFMONTH, expressions);
325+
public static FunctionExpression dayofmonth(
326+
FunctionProperties functionProperties,
327+
Expression... expressions) {
328+
return compile(functionProperties, BuiltinFunctionName.DAYOFMONTH, expressions);
327329
}
328330

329331
public static FunctionExpression dayofweek(Expression... expressions) {
@@ -334,6 +336,12 @@ public static FunctionExpression dayofyear(Expression... expressions) {
334336
return compile(FunctionProperties.None, BuiltinFunctionName.DAYOFYEAR, expressions);
335337
}
336338

339+
public static FunctionExpression day_of_month(
340+
FunctionProperties functionProperties,
341+
Expression... expressions) {
342+
return compile(functionProperties, BuiltinFunctionName.DAY_OF_MONTH, expressions);
343+
}
344+
337345
public static FunctionExpression day_of_year(Expression... expressions) {
338346
return compile(FunctionProperties.None, BuiltinFunctionName.DAY_OF_YEAR, expressions);
339347
}

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

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
package org.opensearch.sql.expression.datetime;
88

9+
import static java.time.temporal.ChronoUnit.DAYS;
910
import static java.time.temporal.ChronoUnit.MINUTES;
1011
import static java.time.temporal.ChronoUnit.MONTHS;
1112
import static org.opensearch.sql.data.type.ExprCoreType.DATE;
@@ -21,6 +22,7 @@
2122
import static org.opensearch.sql.expression.function.FunctionDSL.impl;
2223
import static org.opensearch.sql.expression.function.FunctionDSL.implWithProperties;
2324
import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandling;
25+
import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandlingWithProperties;
2426
import static org.opensearch.sql.utils.DateTimeFormatters.DATE_FORMATTER_LONG_YEAR;
2527
import static org.opensearch.sql.utils.DateTimeFormatters.DATE_FORMATTER_SHORT_YEAR;
2628
import static org.opensearch.sql.utils.DateTimeFormatters.DATE_TIME_FORMATTER_LONG_YEAR;
@@ -58,7 +60,6 @@
5860
import org.opensearch.sql.data.model.ExprValue;
5961
import org.opensearch.sql.data.type.ExprCoreType;
6062
import org.opensearch.sql.exception.ExpressionEvaluationException;
61-
import org.opensearch.sql.exception.SemanticCheckException;
6263
import org.opensearch.sql.expression.function.BuiltinFunctionName;
6364
import org.opensearch.sql.expression.function.BuiltinFunctionRepository;
6465
import org.opensearch.sql.expression.function.DefaultFunctionResolver;
@@ -102,7 +103,8 @@ public void register(BuiltinFunctionRepository repository) {
102103
repository.register(date_sub());
103104
repository.register(day());
104105
repository.register(dayName());
105-
repository.register(dayOfMonth());
106+
repository.register(dayOfMonth(BuiltinFunctionName.DAYOFMONTH));
107+
repository.register(dayOfMonth(BuiltinFunctionName.DAY_OF_MONTH));
106108
repository.register(dayOfWeek());
107109
repository.register(dayOfYear(BuiltinFunctionName.DAYOFYEAR));
108110
repository.register(dayOfYear(BuiltinFunctionName.DAY_OF_YEAR));
@@ -342,12 +344,15 @@ private DefaultFunctionResolver dayName() {
342344
/**
343345
* DAYOFMONTH(STRING/DATE/DATETIME/TIMESTAMP). return the day of the month (1-31).
344346
*/
345-
private DefaultFunctionResolver dayOfMonth() {
346-
return define(BuiltinFunctionName.DAYOFMONTH.getName(),
347+
private DefaultFunctionResolver dayOfMonth(BuiltinFunctionName name) {
348+
return define(name.getName(),
349+
implWithProperties(nullMissingHandlingWithProperties(
350+
(functionProperties, arg) -> DateTimeFunction.dayOfMonthToday(
351+
functionProperties.getQueryStartClock())), INTEGER, TIME),
347352
impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, DATE),
348353
impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, DATETIME),
349-
impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, TIMESTAMP),
350-
impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, STRING)
354+
impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, STRING),
355+
impl(nullMissingHandling(DateTimeFunction::exprDayOfMonth), INTEGER, TIMESTAMP)
351356
);
352357
}
353358

@@ -661,6 +666,10 @@ private DefaultFunctionResolver date_format() {
661666
);
662667
}
663668

669+
private ExprValue dayOfMonthToday(Clock clock) {
670+
return new ExprIntegerValue(LocalDateTime.now(clock).getDayOfMonth());
671+
}
672+
664673
/**
665674
* ADDDATE function implementation for ExprValue.
666675
*
@@ -807,7 +816,7 @@ private ExprValue exprDayName(ExprValue date) {
807816
/**
808817
* Day of Month implementation for ExprValue.
809818
*
810-
* @param date ExprValue of Date/String type.
819+
* @param date ExprValue of Date/Datetime/String/Time/Timestamp type.
811820
* @return ExprValue.
812821
*/
813822
private ExprValue exprDayOfMonth(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
@@ -67,6 +67,7 @@ public enum BuiltinFunctionName {
6767
DAY(FunctionName.of("day")),
6868
DAYNAME(FunctionName.of("dayname")),
6969
DAYOFMONTH(FunctionName.of("dayofmonth")),
70+
DAY_OF_MONTH(FunctionName.of("day_of_month")),
7071
DAYOFWEEK(FunctionName.of("dayofweek")),
7172
DAYOFYEAR(FunctionName.of("dayofyear")),
7273
DAY_OF_YEAR(FunctionName.of("day_of_year")),

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

Lines changed: 85 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -416,20 +416,101 @@ public void dayName() {
416416
public void dayOfMonth() {
417417
when(nullRef.type()).thenReturn(DATE);
418418
when(missingRef.type()).thenReturn(DATE);
419-
assertEquals(nullValue(), eval(DSL.dayofmonth(nullRef)));
420-
assertEquals(missingValue(), eval(DSL.dayofmonth(missingRef)));
419+
assertEquals(nullValue(), eval(DSL.dayofmonth(functionProperties, nullRef)));
420+
assertEquals(missingValue(), eval(DSL.dayofmonth(functionProperties, missingRef)));
421421

422-
FunctionExpression expression = DSL.dayofmonth(DSL.literal(new ExprDateValue("2020-08-07")));
422+
FunctionExpression expression = DSL.dayofmonth(
423+
functionProperties, DSL.literal(new ExprDateValue("2020-08-07")));
423424
assertEquals(INTEGER, expression.type());
424425
assertEquals("dayofmonth(DATE '2020-08-07')", expression.toString());
425426
assertEquals(integerValue(7), eval(expression));
426427

427-
expression = DSL.dayofmonth(DSL.literal("2020-07-08"));
428+
expression = DSL.dayofmonth(functionProperties, DSL.literal("2020-07-08"));
428429
assertEquals(INTEGER, expression.type());
429430
assertEquals("dayofmonth(\"2020-07-08\")", expression.toString());
430431
assertEquals(integerValue(8), eval(expression));
431432
}
432433

434+
private void testDayOfMonthWithUnderscores(FunctionExpression dateExpression, int dayOfMonth) {
435+
assertEquals(INTEGER, dateExpression.type());
436+
assertEquals(integerValue(dayOfMonth), eval(dateExpression));
437+
}
438+
439+
@Test
440+
public void dayOfMonthWithUnderscores() {
441+
lenient().when(nullRef.valueOf(env)).thenReturn(nullValue());
442+
lenient().when(missingRef.valueOf(env)).thenReturn(missingValue());
443+
444+
445+
FunctionExpression expression1 = DSL.dayofmonth(
446+
functionProperties, DSL.literal(new ExprDateValue("2020-08-07")));
447+
FunctionExpression expression2 = DSL.dayofmonth(functionProperties, DSL.literal("2020-07-08"));
448+
449+
assertAll(
450+
() -> testDayOfMonthWithUnderscores(expression1, 7),
451+
() -> assertEquals("dayofmonth(DATE '2020-08-07')", expression1.toString()),
452+
453+
() -> testDayOfMonthWithUnderscores(expression2, 8),
454+
() -> assertEquals("dayofmonth(\"2020-07-08\")", expression2.toString())
455+
456+
);
457+
}
458+
459+
@Test
460+
public void testDayOfMonthWithTimeType() {
461+
lenient().when(nullRef.valueOf(env)).thenReturn(nullValue());
462+
lenient().when(missingRef.valueOf(env)).thenReturn(missingValue());
463+
FunctionExpression expression = DSL.day_of_month(
464+
functionProperties, DSL.literal(new ExprTimeValue("12:23:34")));
465+
466+
assertEquals(INTEGER, eval(expression).type());
467+
assertEquals(
468+
LocalDate.now(functionProperties.getQueryStartClock()).getDayOfMonth(),
469+
eval(expression).integerValue());
470+
assertEquals("day_of_month(TIME '12:23:34')", expression.toString());
471+
}
472+
473+
private void testInvalidDayOfMonth(String date) {
474+
FunctionExpression expression = DSL.day_of_month(
475+
functionProperties, DSL.literal(new ExprDateValue(date)));
476+
eval(expression);
477+
}
478+
479+
@Test
480+
public void dayOfMonthWithUnderscoresLeapYear() {
481+
lenient().when(nullRef.valueOf(env)).thenReturn(nullValue());
482+
lenient().when(missingRef.valueOf(env)).thenReturn(missingValue());
483+
484+
//Feb. 29 of a leap year
485+
testDayOfMonthWithUnderscores(DSL.day_of_month(
486+
functionProperties, DSL.literal("2020-02-29")), 29);
487+
488+
//Feb. 29 of a non-leap year
489+
assertThrows(SemanticCheckException.class, () -> testInvalidDayOfMonth("2021-02-29"));
490+
}
491+
492+
@Test
493+
public void dayOfMonthWithUnderscoresInvalidArguments() {
494+
lenient().when(nullRef.type()).thenReturn(DATE);
495+
lenient().when(missingRef.type()).thenReturn(DATE);
496+
497+
assertAll(
498+
() -> assertEquals(nullValue(), eval(DSL.day_of_month(functionProperties, nullRef))),
499+
() -> assertEquals(
500+
missingValue(), eval(DSL.day_of_month(functionProperties, missingRef))),
501+
502+
//40th day of the month
503+
() -> assertThrows(
504+
SemanticCheckException.class, () -> testInvalidDayOfMonth("2021-02-40")),
505+
//13th month of the year
506+
() -> assertThrows(
507+
SemanticCheckException.class, () -> testInvalidDayOfMonth("2021-13-40")),
508+
//incorrect format
509+
() -> assertThrows(
510+
SemanticCheckException.class, () -> testInvalidDayOfMonth("asdfasdfasdf"))
511+
);
512+
}
513+
433514
@Test
434515
public void dayOfWeek() {
435516
when(nullRef.type()).thenReturn(DATE);

docs/user/dql/functions.rst

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,13 +1359,13 @@ DAY
13591359
Description
13601360
>>>>>>>>>>>
13611361

1362-
Usage: day(date) extracts the day of the month for date, in the range 1 to 31. The dates with value 0 such as '0000-00-00' or '2008-00-00' are invalid.
1362+
Usage: day(date) extracts the day of the month for date, in the range 1 to 31.
13631363

1364-
Argument type: STRING/DATE/DATETIME/TIMESTAMP
1364+
Argument type: STRING/DATE/DATETIME/TIME/TIMESTAMP
13651365

13661366
Return type: INTEGER
13671367

1368-
Synonyms: DAYOFMONTH
1368+
Synonyms: `DAYOFMONTH`_, `DAY_OF_MONTH`_
13691369

13701370
Example::
13711371

@@ -1407,13 +1407,13 @@ DAYOFMONTH
14071407
Description
14081408
>>>>>>>>>>>
14091409

1410-
Usage: dayofmonth(date) extracts the day of the month for date, in the range 1 to 31. The dates with value 0 such as '0000-00-00' or '2008-00-00' are invalid.
1410+
Usage: dayofmonth(date) extracts the day of the month for date, in the range 1 to 31.
14111411

1412-
Argument type: STRING/DATE/DATETIME/TIMESTAMP
1412+
Argument type: STRING/DATE/DATETIME/TIME/TIMESTAMP
14131413

14141414
Return type: INTEGER
14151415

1416-
Synonyms: DAY
1416+
Synonyms: `DAY`_, `DAY_OF_MONTH`_
14171417

14181418
Example::
14191419

@@ -1425,6 +1425,29 @@ Example::
14251425
| 26 |
14261426
+----------------------------------+
14271427

1428+
DAY_OF_MONTH
1429+
------------
1430+
1431+
Description
1432+
>>>>>>>>>>>
1433+
1434+
Usage: day_of_month(date) extracts the day of the month for date, in the range 1 to 31.
1435+
1436+
Argument type: STRING/DATE/TIME/DATETIME/TIMESTAMP
1437+
1438+
Return type: INTEGER
1439+
1440+
Synonyms: `DAY`_, `DAYOFMONTH`_
1441+
1442+
Example::
1443+
1444+
os> SELECT DAY_OF_MONTH('2020-08-26')
1445+
fetched rows / total rows = 1/1
1446+
+------------------------------+
1447+
| DAY_OF_MONTH('2020-08-26') |
1448+
|------------------------------|
1449+
| 26 |
1450+
+------------------------------+
14281451

14291452
DAYOFWEEK
14301453
---------

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,48 @@ public void testDayOfMonth() throws IOException {
208208
verifyDataRows(result, rows(16));
209209
}
210210

211+
@Test
212+
public void testDayOfMonthWithUnderscores() throws IOException {
213+
JSONObject result = executeQuery("select day_of_month(date('2020-09-16'))");
214+
verifySchema(result, schema("day_of_month(date('2020-09-16'))", null, "integer"));
215+
verifyDataRows(result, rows(16));
216+
217+
result = executeQuery("select day_of_month('2020-09-16')");
218+
verifySchema(result, schema("day_of_month('2020-09-16')", null, "integer"));
219+
verifyDataRows(result, rows(16));
220+
}
221+
222+
@Test
223+
public void testDayOfMonthAliasesReturnTheSameResults() throws IOException {
224+
JSONObject result1 = executeQuery("SELECT dayofmonth(date('2022-11-22'))");
225+
JSONObject result2 = executeQuery("SELECT day_of_month(date('2022-11-22'))");
226+
verifyDataRows(result1, rows(22));
227+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
228+
229+
result1 = executeQuery(String.format(
230+
"SELECT dayofmonth(CAST(date0 AS date)) FROM %s", TEST_INDEX_CALCS));
231+
result2 = executeQuery(String.format(
232+
"SELECT day_of_month(CAST(date0 AS date)) FROM %s", TEST_INDEX_CALCS));
233+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
234+
235+
result1 = executeQuery(String.format(
236+
"SELECT dayofmonth(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS));
237+
result2 = executeQuery(String.format(
238+
"SELECT day_of_month(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS));
239+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
240+
241+
result1 = executeQuery(String.format(
242+
"SELECT dayofmonth(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS));
243+
result2 = executeQuery(String.format(
244+
"SELECT day_of_month(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS));
245+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
246+
247+
result1 = executeQuery(String.format(
248+
"SELECT dayofmonth(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS));
249+
result2 = executeQuery(String.format(
250+
"SELECT day_of_month(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS));
251+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
252+
}
211253
@Test
212254
public void testDayOfWeek() throws IOException {
213255
JSONObject result = executeQuery("select dayofweek(date('2020-09-16'))");

sql/src/main/antlr/OpenSearchSQLParser.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,7 @@ dateTimeFunctionName
419419
| DAY
420420
| DAYNAME
421421
| DAYOFMONTH
422+
| DAY_OF_MONTH
422423
| DAYOFWEEK
423424
| DAYOFYEAR
424425
| FROM_DAYS

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_dayofmonth_functions() {
206+
assertNotNull(parser.parse("SELECT dayofmonth('2022-11-18')"));
207+
assertNotNull(parser.parse("SELECT day_of_month('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)