Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Minute_Of_Day Function To SQL Plugin #1207

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions core/src/main/java/org/opensearch/sql/expression/DSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,10 @@ public static FunctionExpression minute(Expression... expressions) {
return compile(FunctionProperties.None, BuiltinFunctionName.MINUTE, expressions);
}

public static FunctionExpression minute_of_day(Expression... expressions) {
return compile(FunctionProperties.None, BuiltinFunctionName.MINUTE_OF_DAY, expressions);
}

public static FunctionExpression month(Expression... expressions) {
return compile(FunctionProperties.None, BuiltinFunctionName.MONTH, expressions);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

package org.opensearch.sql.expression.datetime;

import static java.time.temporal.ChronoUnit.MINUTES;
import static java.time.temporal.ChronoUnit.MONTHS;
import static org.opensearch.sql.data.type.ExprCoreType.DATE;
import static org.opensearch.sql.data.type.ExprCoreType.DATETIME;
Expand Down Expand Up @@ -113,6 +114,7 @@ public void register(BuiltinFunctionRepository repository) {
repository.register(maketime());
repository.register(microsecond());
repository.register(minute());
repository.register(minute_of_day());
repository.register(month(BuiltinFunctionName.MONTH));
repository.register(month(BuiltinFunctionName.MONTH_OF_YEAR));
repository.register(monthName());
Expand Down Expand Up @@ -432,6 +434,19 @@ private DefaultFunctionResolver minute() {
);
}

/**
* MINUTE(STRING/TIME/DATETIME/TIMESTAMP). return the minute value for time.
*/
private DefaultFunctionResolver minute_of_day() {
return define(BuiltinFunctionName.MINUTE_OF_DAY.getName(),
impl(nullMissingHandling(DateTimeFunction::exprMinuteOfDay), INTEGER, STRING),
impl(nullMissingHandling(DateTimeFunction::exprMinuteOfDay), INTEGER, TIME),
impl(nullMissingHandling(DateTimeFunction::exprMinuteOfDay), INTEGER, DATE),
impl(nullMissingHandling(DateTimeFunction::exprMinuteOfDay), INTEGER, DATETIME),
impl(nullMissingHandling(DateTimeFunction::exprMinuteOfDay), INTEGER, TIMESTAMP)
);
}

/**
* MONTH(STRING/DATE/DATETIME/TIMESTAMP). return the month for date (1-12).
*/
Expand Down Expand Up @@ -902,6 +917,17 @@ private ExprValue exprMinute(ExprValue time) {
return new ExprIntegerValue(time.timeValue().getMinute());
}

/**
* Minute_of_day implementation for ExprValue.
*
* @param time ExprValue of Time/String type.
* @return ExprValue.
*/
private ExprValue exprMinuteOfDay(ExprValue time) {
return new ExprIntegerValue(
MINUTES.between(LocalTime.MIN, time.timeValue()));
}

/**
* Month for date implementation for ExprValue.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public enum BuiltinFunctionName {
MAKETIME(FunctionName.of("maketime")),
MICROSECOND(FunctionName.of("microsecond")),
MINUTE(FunctionName.of("minute")),
MINUTE_OF_DAY(FunctionName.of("minute_of_day")),
MONTH(FunctionName.of("month")),
MONTH_OF_YEAR(FunctionName.of("month_of_year")),
MONTHNAME(FunctionName.of("monthname")),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,37 @@ public void hour() {
assertEquals("hour(\"2020-08-17 01:02:03\")", expression.toString());
}

private void testInvalidMinuteOfDay(String date) {
FunctionExpression expression = DSL.minute_of_day(DSL.literal(new ExprDateValue(date)));
eval(expression);
}

@Test
public void invalidMinuteOfDay() {
lenient().when(nullRef.valueOf(env)).thenReturn(nullValue());
lenient().when(missingRef.valueOf(env)).thenReturn(missingValue());

assertThrows(SemanticCheckException.class,
() -> testInvalidMinuteOfDay("2022-12-14 12:23:3400"));
assertThrows(SemanticCheckException.class,
() -> testInvalidMinuteOfDay("2022-12-14 12:2300:34"));
assertThrows(SemanticCheckException.class,
() -> testInvalidMinuteOfDay("2022-12-14 1200:23:34"));
assertThrows(SemanticCheckException.class,
() -> testInvalidMinuteOfDay("2022-12-1400 12:23:34"));
assertThrows(SemanticCheckException.class,
() -> testInvalidMinuteOfDay("2022-1200-14 12:23:34"));
assertThrows(SemanticCheckException.class,
() -> testInvalidMinuteOfDay("12:23:3400"));
assertThrows(SemanticCheckException.class,
() -> testInvalidMinuteOfDay("12:2300:34"));
assertThrows(SemanticCheckException.class,
() -> testInvalidMinuteOfDay("1200:23:34"));
assertThrows(SemanticCheckException.class,
() -> testInvalidMinuteOfDay("asdfasdfasdf"));

}

@Test
public void microsecond() {
when(nullRef.type()).thenReturn(TIME);
Expand Down Expand Up @@ -691,6 +722,48 @@ public void minute() {
assertEquals("minute(\"2020-08-17 01:02:03\")", expression.toString());
}

private void testMinuteOfDay(String date, int value) {
FunctionExpression expression = DSL.minute_of_day(DSL.literal(new ExprTimeValue(date)));
assertEquals(INTEGER, expression.type());
assertEquals(integerValue(value), eval(expression));
}

@Test
public void minuteOfDay() {
when(nullRef.type()).thenReturn(TIME);
when(missingRef.type()).thenReturn(TIME);
assertEquals(nullValue(), eval(DSL.minute_of_day(nullRef)));
assertEquals(missingValue(), eval(DSL.minute_of_day(missingRef)));

FunctionExpression expression = DSL.minute_of_day(DSL.literal(new ExprTimeValue("01:02:03")));
assertEquals(INTEGER, expression.type());
assertEquals(integerValue(62), eval(expression));
assertEquals("minute_of_day(TIME '01:02:03')", expression.toString());

expression = DSL.minute_of_day(DSL.literal("01:02:03"));
assertEquals(INTEGER, expression.type());
assertEquals(integerValue(62), eval(expression));
assertEquals("minute_of_day(\"01:02:03\")", expression.toString());

expression = DSL.minute_of_day(DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03")));
assertEquals(INTEGER, expression.type());
assertEquals(integerValue(62), expression.valueOf(env));
assertEquals("minute_of_day(TIMESTAMP '2020-08-17 01:02:03')", expression.toString());

expression = DSL.minute_of_day(DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03")));
assertEquals(INTEGER, expression.type());
assertEquals(integerValue(62), expression.valueOf(env));
assertEquals("minute_of_day(DATETIME '2020-08-17 01:02:03')", expression.toString());

expression = DSL.minute_of_day(DSL.literal("2020-08-17 01:02:03"));
assertEquals(INTEGER, expression.type());
assertEquals(integerValue(62), expression.valueOf(env));
assertEquals("minute_of_day(\"2020-08-17 01:02:03\")", expression.toString());

testMinuteOfDay("2020-08-17 23:59:59", 1439);
testMinuteOfDay("2020-08-17 00:00:01", 0);
}

@Test
public void month() {
when(nullRef.type()).thenReturn(DATE);
Expand Down
22 changes: 22 additions & 0 deletions docs/user/dql/functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1762,6 +1762,28 @@ Example::
| 2 |
+-----------------------------+

MINUTE_OF_DAY
------

Description
>>>>>>>>>>>

Usage: minute_of_day(time) returns the minute value for time within a 24 hour day, in the range 0 to 1439.

Argument type: STRING/TIME/DATETIME/TIMESTAMP

Return type: INTEGER

Example::

os> SELECT MINUTE_OF_DAY((TIME '01:02:03'))
fetched rows / total rows = 1/1
+------------------------------------+
| MINUTE_OF_DAY((TIME '01:02:03')) |
|------------------------------------|
| 62 |
+------------------------------------+


MONTH
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,30 @@ public void testMinute() throws IOException {
verifyDataRows(result, rows(30));
}


@Test
public void testMinuteOfDay() throws IOException {
JSONObject result = executeQuery("select minute_of_day(timestamp('2020-09-16 17:30:00'))");
verifySchema(result, schema("minute_of_day(timestamp('2020-09-16 17:30:00'))", null, "integer"));
verifyDataRows(result, rows(1050));

result = executeQuery("select minute_of_day(datetime('2020-09-16 17:30:00'))");
verifySchema(result, schema("minute_of_day(datetime('2020-09-16 17:30:00'))", null, "integer"));
verifyDataRows(result, rows(1050));

result = executeQuery("select minute_of_day(time('17:30:00'))");
verifySchema(result, schema("minute_of_day(time('17:30:00'))", null, "integer"));
verifyDataRows(result, rows(1050));

result = executeQuery("select minute_of_day('2020-09-16 17:30:00')");
verifySchema(result, schema("minute_of_day('2020-09-16 17:30:00')", null, "integer"));
verifyDataRows(result, rows(1050));

result = executeQuery("select minute_of_day('17:30:00')");
verifySchema(result, schema("minute_of_day('17:30:00')", null, "integer"));
verifyDataRows(result, rows(1050));
}

@Test
public void testMonth() throws IOException {
JSONObject result = executeQuery("select month(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 @@ -433,6 +433,7 @@ dateTimeFunctionName
| MAKETIME
| MICROSECOND
| MINUTE
| MINUTE_OF_DAY
| MONTH
| MONTHNAME
| NOW
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,14 @@ public void can_parse_match_phrase_relevance_function() {
assertNotNull(parser.parse("SELECT * FROM test WHERE match_phrase(column, 100500)"));
}

@Test
public void can_parse_minute_of_day_function() {
assertNotNull(parser.parse("SELECT minute_of_day(\"12:23:34\");"));
assertNotNull(parser.parse("SELECT minute_of_day('12:23:34');"));;
assertNotNull(parser.parse("SELECT minute_of_day(\"2022-12-14 12:23:34\");"));;
assertNotNull(parser.parse("SELECT minute_of_day('2022-12-14 12:23:34');"));;
}

@Test
public void can_parse_wildcard_query_relevance_function() {
assertNotNull(
Expand Down