Skip to content

Commit dce7d0e

Browse files
Add Second_Of_Minute Function As An Alias Of The Second Function (opensearch-project#1231)
Added Testing And Implementation For Second_Of_Minute Function Signed-off-by: GabeFernandez310 <[email protected]> Signed-off-by: GabeFernandez310 <[email protected]>
1 parent b919ba0 commit dce7d0e

File tree

8 files changed

+152
-4
lines changed

8 files changed

+152
-4
lines changed

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,10 @@ public static FunctionExpression second(Expression... expressions) {
378378
return compile(FunctionProperties.None, BuiltinFunctionName.SECOND, expressions);
379379
}
380380

381+
public static FunctionExpression second_of_minute(Expression... expressions) {
382+
return compile(FunctionProperties.None, BuiltinFunctionName.SECOND_OF_MINUTE, expressions);
383+
}
384+
381385
public static FunctionExpression subdate(Expression... expressions) {
382386
return compile(FunctionProperties.None, BuiltinFunctionName.SUBDATE, expressions);
383387
}

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

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import static java.time.temporal.ChronoUnit.DAYS;
1010
import static java.time.temporal.ChronoUnit.MINUTES;
1111
import static java.time.temporal.ChronoUnit.MONTHS;
12+
import static java.time.temporal.ChronoUnit.SECONDS;
1213
import static org.opensearch.sql.data.type.ExprCoreType.DATE;
1314
import static org.opensearch.sql.data.type.ExprCoreType.DATETIME;
1415
import static org.opensearch.sql.data.type.ExprCoreType.DOUBLE;
@@ -128,7 +129,8 @@ public void register(BuiltinFunctionRepository repository) {
128129
repository.register(period_add());
129130
repository.register(period_diff());
130131
repository.register(quarter());
131-
repository.register(second());
132+
repository.register(second(BuiltinFunctionName.SECOND));
133+
repository.register(second(BuiltinFunctionName.SECOND_OF_MINUTE));
132134
repository.register(subdate());
133135
repository.register(sysdate());
134136
repository.register(time());
@@ -557,10 +559,11 @@ private DefaultFunctionResolver quarter() {
557559
/**
558560
* SECOND(STRING/TIME/DATETIME/TIMESTAMP). return the second value for time.
559561
*/
560-
private DefaultFunctionResolver second() {
561-
return define(BuiltinFunctionName.SECOND.getName(),
562+
private DefaultFunctionResolver second(BuiltinFunctionName name) {
563+
return define(name.getName(),
562564
impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, STRING),
563565
impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, TIME),
566+
impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, DATE),
564567
impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, DATETIME),
565568
impl(nullMissingHandling(DateTimeFunction::exprSecond), INTEGER, TIMESTAMP)
566569
);
@@ -1131,7 +1134,8 @@ private ExprValue exprQuarter(ExprValue date) {
11311134
* @return ExprValue.
11321135
*/
11331136
private ExprValue exprSecond(ExprValue time) {
1134-
return new ExprIntegerValue(time.timeValue().getSecond());
1137+
return new ExprIntegerValue(
1138+
(SECONDS.between(LocalTime.MIN, time.timeValue()) % 60));
11351139
}
11361140

11371141
/**

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
@@ -86,6 +86,7 @@ public enum BuiltinFunctionName {
8686
PERIOD_DIFF(FunctionName.of("period_diff")),
8787
QUARTER(FunctionName.of("quarter")),
8888
SECOND(FunctionName.of("second")),
89+
SECOND_OF_MINUTE(FunctionName.of("second_of_minute")),
8990
SUBDATE(FunctionName.of("subdate")),
9091
TIME(FunctionName.of("time")),
9192
TIMEDIFF(FunctionName.of("timediff")),

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

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,14 @@
2828
import com.google.common.collect.ImmutableList;
2929
import java.time.LocalDate;
3030
import java.util.List;
31+
import java.util.stream.Stream;
3132
import lombok.AllArgsConstructor;
3233
import org.junit.jupiter.api.BeforeEach;
3334
import org.junit.jupiter.api.Test;
3435
import org.junit.jupiter.api.extension.ExtendWith;
36+
import org.junit.jupiter.params.ParameterizedTest;
37+
import org.junit.jupiter.params.provider.Arguments;
38+
import org.junit.jupiter.params.provider.MethodSource;
3539
import org.mockito.Mock;
3640
import org.mockito.junit.jupiter.MockitoExtension;
3741
import org.opensearch.sql.data.model.ExprDateValue;
@@ -46,6 +50,7 @@
4650
import org.opensearch.sql.expression.Expression;
4751
import org.opensearch.sql.expression.ExpressionTestBase;
4852
import org.opensearch.sql.expression.FunctionExpression;
53+
import org.opensearch.sql.expression.LiteralExpression;
4954
import org.opensearch.sql.expression.env.Environment;
5055

5156
@ExtendWith(MockitoExtension.class)
@@ -904,6 +909,77 @@ public void second() {
904909
assertEquals("second(DATETIME '2020-08-17 01:02:03')", expression.toString());
905910
}
906911

912+
private void secondOfMinuteQuery(FunctionExpression dateExpression, int second, String testExpr) {
913+
assertEquals(INTEGER, dateExpression.type());
914+
assertEquals(integerValue(second), eval(dateExpression));
915+
assertEquals(testExpr, dateExpression.toString());
916+
}
917+
918+
private static Stream<Arguments> getTestDataForSecondOfMinute() {
919+
return Stream.of(
920+
Arguments.of(
921+
DSL.literal(new ExprTimeValue("01:02:03")),
922+
3,
923+
"second_of_minute(TIME '01:02:03')"),
924+
Arguments.of(
925+
DSL.literal("01:02:03"),
926+
3,
927+
"second_of_minute(\"01:02:03\")"),
928+
Arguments.of(
929+
DSL.literal("2020-08-17 01:02:03"),
930+
3,
931+
"second_of_minute(\"2020-08-17 01:02:03\")"),
932+
Arguments.of(
933+
934+
DSL.literal(new ExprTimestampValue("2020-08-17 01:02:03")),
935+
3,
936+
"second_of_minute(TIMESTAMP '2020-08-17 01:02:03')"),
937+
Arguments.of(
938+
939+
DSL.literal(new ExprDatetimeValue("2020-08-17 01:02:03")),
940+
3,
941+
"second_of_minute(DATETIME '2020-08-17 01:02:03')")
942+
);
943+
}
944+
945+
@ParameterizedTest(name = "{2}")
946+
@MethodSource("getTestDataForSecondOfMinute")
947+
public void secondOfMinute(LiteralExpression arg, int expectedResult, String expectedString) {
948+
lenient().when(nullRef.valueOf(env)).thenReturn(nullValue());
949+
lenient().when(missingRef.valueOf(env)).thenReturn(missingValue());
950+
951+
secondOfMinuteQuery(DSL.second_of_minute(arg), expectedResult, expectedString);
952+
}
953+
954+
private void invalidSecondOfMinuteQuery(String time) {
955+
FunctionExpression expression = DSL.second_of_minute(DSL.literal(new ExprTimeValue(time)));
956+
eval(expression);
957+
}
958+
959+
@Test
960+
public void secondOfMinuteInvalidArguments() {
961+
when(nullRef.type()).thenReturn(TIME);
962+
when(missingRef.type()).thenReturn(TIME);
963+
964+
assertAll(
965+
() -> assertEquals(nullValue(), eval(DSL.second_of_minute(nullRef))),
966+
() -> assertEquals(missingValue(), eval(DSL.second_of_minute(missingRef))),
967+
//Invalid Seconds
968+
() -> assertThrows(SemanticCheckException.class,
969+
() -> invalidSecondOfMinuteQuery("12:23:61")),
970+
//Invalid Minutes
971+
() -> assertThrows(SemanticCheckException.class,
972+
() -> invalidSecondOfMinuteQuery("12:61:34")),
973+
//Invalid Hours
974+
() -> assertThrows(SemanticCheckException.class,
975+
() -> invalidSecondOfMinuteQuery("25:23:34")),
976+
//incorrect format
977+
() -> assertThrows(SemanticCheckException.class,
978+
() -> invalidSecondOfMinuteQuery("asdfasdf"))
979+
);
980+
}
981+
982+
907983
@Test
908984
public void subdate() {
909985
FunctionExpression expr = DSL.subdate(DSL.date(DSL.literal("2020-08-26")), DSL.literal(7));

docs/user/dql/functions.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,6 +1961,7 @@ Description
19611961
>>>>>>>>>>>
19621962

19631963
Usage: second(time) returns the second for time, in the range 0 to 59.
1964+
The function `second_of_minute`_ is provided as an alias
19641965

19651966
Argument type: STRING/TIME/DATETIME/TIMESTAMP
19661967

@@ -1976,6 +1977,14 @@ Example::
19761977
| 3 |
19771978
+-----------------------------+
19781979

1980+
os> SELECT SECOND_OF_MINUTE(time('01:02:03'))
1981+
fetched rows / total rows = 1/1
1982+
+--------------------------------------+
1983+
| SECOND_OF_MINUTE(time('01:02:03')) |
1984+
|--------------------------------------|
1985+
| 3 |
1986+
+--------------------------------------+
1987+
19791988

19801989
SUBDATE
19811990
-------

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,51 @@ public void testSecond() throws IOException {
493493
verifyDataRows(result, rows(0));
494494
}
495495

496+
@Test
497+
public void testSecondOfMinute() throws IOException {
498+
JSONObject result = executeQuery("select second_of_minute(timestamp('2020-09-16 17:30:00'))");
499+
verifySchema(result, schema("second_of_minute(timestamp('2020-09-16 17:30:00'))", null, "integer"));
500+
verifyDataRows(result, rows(0));
501+
502+
result = executeQuery("select second_of_minute(time('17:30:00'))");
503+
verifySchema(result, schema("second_of_minute(time('17:30:00'))", null, "integer"));
504+
verifyDataRows(result, rows(0));
505+
506+
result = executeQuery("select second_of_minute('2020-09-16 17:30:00')");
507+
verifySchema(result, schema("second_of_minute('2020-09-16 17:30:00')", null, "integer"));
508+
verifyDataRows(result, rows(0));
509+
510+
result = executeQuery("select second_of_minute('17:30:00')");
511+
verifySchema(result, schema("second_of_minute('17:30:00')", null, "integer"));
512+
verifyDataRows(result, rows(0));
513+
}
514+
515+
@Test
516+
public void testSecondFunctionAliasesReturnTheSameResults() throws IOException {
517+
JSONObject result1 = executeQuery("SELECT second('2022-11-22 12:23:34')");
518+
JSONObject result2 = executeQuery("SELECT second_of_minute('2022-11-22 12:23:34')");
519+
verifyDataRows(result1, rows(34));
520+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
521+
522+
result1 = executeQuery(String.format(
523+
"SELECT second(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS));
524+
result2 = executeQuery(String.format(
525+
"SELECT second_of_minute(datetime(CAST(time0 AS STRING))) FROM %s", TEST_INDEX_CALCS));
526+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
527+
528+
result1 = executeQuery(String.format(
529+
"SELECT second(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS));
530+
result2 = executeQuery(String.format(
531+
"SELECT second_of_minute(CAST(time0 AS STRING)) FROM %s", TEST_INDEX_CALCS));
532+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
533+
534+
result1 = executeQuery(String.format(
535+
"SELECT second(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS));
536+
result2 = executeQuery(String.format(
537+
"SELECT second_of_minute(CAST(datetime0 AS timestamp)) FROM %s", TEST_INDEX_CALCS));
538+
result1.getJSONArray("datarows").similar(result2.getJSONArray("datarows"));
539+
}
540+
496541
@Test
497542
public void testSubDate() throws IOException {
498543
JSONObject result =

sql/src/main/antlr/OpenSearchSQLParser.g4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ dateTimeFunctionName
450450
| PERIOD_DIFF
451451
| QUARTER
452452
| SECOND
453+
| SECOND_OF_MINUTE
453454
| SUBDATE
454455
| SYSDATE
455456
| TIME

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,14 @@ public void can_parse_multi_match_relevance_function() {
269269
+ "operator='AND', tie_breaker=0.3, type = \"most_fields\", fuzziness = \"AUTO\")"));
270270
}
271271

272+
@Test
273+
public void can_parse_second_functions() {
274+
assertNotNull(parser.parse("SELECT second('12:23:34')"));
275+
assertNotNull(parser.parse("SELECT second_of_minute('2022-11-18')"));
276+
assertNotNull(parser.parse("SELECT second('2022-11-18 12:23:34')"));
277+
assertNotNull(parser.parse("SELECT second_of_minute('2022-11-18 12:23:34')"));
278+
}
279+
272280
@Test
273281
public void can_parse_simple_query_string_relevance_function() {
274282
assertNotNull(parser.parse(

0 commit comments

Comments
 (0)