forked from opensearch-project/sql
-
Notifications
You must be signed in to change notification settings - Fork 0
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
Update TIMESTAMP
function
#139
Merged
Merged
Changes from 13 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
939539f
Add functions `ADDTIME` and `SUBTIME`.
Yury-Fridlyand 3b01e6b
Update docs - rework on examples.
Yury-Fridlyand fbabe78
Update `ExprTimeValue` by `datetimeValue` and other interfaces. Add c…
Yury-Fridlyand 533281c
Update `TIMESTAMP` function implementation and signatures.
Yury-Fridlyand 80affb7
Modify function to accept strings.
Yury-Fridlyand e7db970
Return `NULL` on invalid string input.
Yury-Fridlyand df0b27c
Add unit tests.
Yury-Fridlyand 5e6423b
Update docs.
Yury-Fridlyand e257d5c
Minor checkstyle fixes.
Yury-Fridlyand 5e86202
Make function to throw an exception on incorrect input.
Yury-Fridlyand 86524aa
Fix rebasing errors.
Yury-Fridlyand 84a1d4d
Rework to use `FunctionProperties`.
Yury-Fridlyand 95ee90d
Typo fix.
Yury-Fridlyand f938ea8
Apply suggestions from code review
Yury-Fridlyand File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
186 changes: 186 additions & 0 deletions
186
core/src/test/java/org/opensearch/sql/expression/datetime/TimestampTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,186 @@ | ||
/* | ||
* Copyright OpenSearch Contributors | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
package org.opensearch.sql.expression.datetime; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertThrows; | ||
import static org.opensearch.sql.data.type.ExprCoreType.TIMESTAMP; | ||
|
||
import java.time.Instant; | ||
import java.time.LocalDate; | ||
import java.time.LocalDateTime; | ||
import java.time.LocalTime; | ||
import java.util.stream.Stream; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.params.ParameterizedTest; | ||
import org.junit.jupiter.params.provider.Arguments; | ||
import org.junit.jupiter.params.provider.CsvSource; | ||
import org.junit.jupiter.params.provider.MethodSource; | ||
import org.opensearch.sql.data.model.ExprTimestampValue; | ||
import org.opensearch.sql.data.model.ExprValueUtils; | ||
import org.opensearch.sql.exception.SemanticCheckException; | ||
import org.opensearch.sql.expression.DSL; | ||
import org.opensearch.sql.expression.ExpressionTestBase; | ||
|
||
public class TimestampTest extends ExpressionTestBase { | ||
|
||
@Test | ||
public void timestamp_one_arg_string() { | ||
var expr = DSL.timestamp(functionProperties, DSL.literal("1961-04-12 09:07:00")); | ||
assertEquals(TIMESTAMP, expr.type()); | ||
assertEquals(new ExprTimestampValue("1961-04-12 09:07:00"), expr.valueOf()); | ||
|
||
expr = DSL.timestamp(functionProperties, DSL.literal("1961-04-12 09:07:00.123456")); | ||
assertEquals(TIMESTAMP, expr.type()); | ||
assertEquals(LocalDateTime.of(1961, 4, 12, 9, 7, 0, 123456000), | ||
expr.valueOf().datetimeValue()); | ||
} | ||
|
||
/** | ||
* Check that `TIMESTAMP` function throws an exception on incorrect string input. | ||
* @param value A value. | ||
* @param testName A test name. | ||
*/ | ||
@ParameterizedTest(name = "{1}") | ||
@CsvSource({ | ||
"1984-02-30 12:20:42, Feb 30th", | ||
"1984-02-10 24:00:00, 24:00:00", | ||
"84-02-10 12:20:42, 2 digit year" | ||
}) | ||
public void timestamp_one_arg_string_invalid_format(String value, String testName) { | ||
// exception thrown from ExprTimestampValue(String) CTOR | ||
var exception = assertThrows(SemanticCheckException.class, | ||
() -> DSL.timestamp(functionProperties, DSL.literal(value)).valueOf()); | ||
assertEquals(String.format("timestamp:%s in unsupported format, please " | ||
+ "use yyyy-MM-dd HH:mm:ss[.SSSSSSSSS]", value), exception.getMessage()); | ||
} | ||
|
||
@Test | ||
public void timestamp_one_arg_time() { | ||
var expr = DSL.timestamp(functionProperties, DSL.time(DSL.literal("22:33:44"))); | ||
assertEquals(TIMESTAMP, expr.type()); | ||
var refValue = LocalDate.now().atTime(LocalTime.of(22, 33, 44)) | ||
.atZone(ExprTimestampValue.ZONE).toInstant(); | ||
assertEquals(new ExprTimestampValue(refValue), expr.valueOf()); | ||
} | ||
|
||
@Test | ||
public void timestamp_one_arg_date() { | ||
var expr = DSL.timestamp(functionProperties, DSL.date(DSL.literal("2077-12-15"))); | ||
assertEquals(TIMESTAMP, expr.type()); | ||
var refValue = LocalDate.of(2077, 12, 15).atStartOfDay() | ||
.atZone(ExprTimestampValue.ZONE).toInstant(); | ||
assertEquals(new ExprTimestampValue(refValue), expr.valueOf()); | ||
} | ||
|
||
@Test | ||
public void timestamp_one_arg_datetime() { | ||
var expr = DSL.timestamp(functionProperties, DSL.datetime(DSL.literal("1961-04-12 09:07:00"))); | ||
assertEquals(TIMESTAMP, expr.type()); | ||
assertEquals(LocalDateTime.of(1961, 4, 12, 9, 7, 0), expr.valueOf().datetimeValue()); | ||
} | ||
|
||
@Test | ||
public void timestamp_one_arg_timestamp() { | ||
var refValue = new ExprTimestampValue(Instant.ofEpochSecond(10050042)); | ||
var expr = DSL.timestamp(functionProperties, | ||
DSL.timestamp(functionProperties, DSL.literal(refValue))); | ||
assertEquals(TIMESTAMP, expr.type()); | ||
assertEquals(refValue, expr.valueOf()); | ||
} | ||
|
||
private static Instant dateTime2Instant(LocalDateTime dt) { | ||
return dt.atZone(ExprTimestampValue.ZONE).toInstant(); | ||
} | ||
|
||
private static ExprTimestampValue dateTime2ExprTs(LocalDateTime dt) { | ||
return new ExprTimestampValue(dateTime2Instant(dt)); | ||
} | ||
|
||
private static Stream<Arguments> getTestData() { | ||
var today = LocalDate.now(); | ||
// First argument of `TIMESTAMP` function, second argument and expected result value | ||
return Stream.of( | ||
// STRING and STRING/DATE/TIME/DATETIME/TIMESTAMP | ||
Arguments.of("1961-04-12 09:07:00", "2077-12-15 01:48:00", | ||
dateTime2ExprTs(LocalDateTime.of(1961, 4, 12, 10, 55, 0))), | ||
Arguments.of("1984-02-10 12:20:42", LocalDate.of(2077, 12, 21), | ||
dateTime2ExprTs(LocalDateTime.of(1984, 2, 10, 12, 20, 42))), | ||
Arguments.of("1961-04-12 09:07:00", LocalTime.of(1, 48), | ||
dateTime2ExprTs(LocalDateTime.of(1961, 4, 12, 10, 55, 0))), | ||
Arguments.of("2020-12-31 17:30:00", LocalDateTime.of(2077, 12, 21, 12, 20, 42), | ||
dateTime2ExprTs(LocalDateTime.of(2021, 1, 1, 5, 50, 42))), | ||
Arguments.of("2020-12-31 17:30:00", Instant.ofEpochSecond(42), | ||
dateTime2ExprTs(LocalDateTime.of(2020, 12, 31, 17, 30, 42))), | ||
// DATE and STRING/DATE/TIME/DATETIME/TIMESTAMP | ||
Arguments.of(LocalDate.of(2077, 12, 21), "2077-12-15 01:48:00", | ||
dateTime2ExprTs(LocalDateTime.of(2077, 12, 21, 1, 48, 0))), | ||
Arguments.of(LocalDate.of(2077, 12, 21), LocalDate.of(1984, 2, 3), | ||
dateTime2ExprTs(LocalDateTime.of(2077, 12, 21, 0, 0, 0))), | ||
Arguments.of(LocalDate.of(2077, 12, 21), LocalTime.of(22, 33, 44), | ||
dateTime2ExprTs(LocalDateTime.of(2077, 12, 21, 22, 33, 44))), | ||
Arguments.of(LocalDate.of(2077, 12, 21), LocalDateTime.of(1999, 9, 9, 22, 33, 44), | ||
dateTime2ExprTs(LocalDateTime.of(2077, 12, 21, 22, 33, 44))), | ||
Arguments.of(LocalDate.of(2077, 12, 21), Instant.ofEpochSecond(42), | ||
dateTime2ExprTs(LocalDateTime.of(2077, 12, 21, 0, 0, 42))), | ||
// TIME and STRING/DATE/TIME/DATETIME/TIMESTAMP | ||
Arguments.of(LocalTime.of(9, 7, 0), "2077-12-15 01:48:00", | ||
dateTime2ExprTs(today.atTime(LocalTime.of(10, 55, 0)))), | ||
Arguments.of(LocalTime.of(12, 20, 42), LocalDate.of(2077, 12, 21), | ||
dateTime2ExprTs(today.atTime(LocalTime.of(12, 20, 42)))), | ||
Arguments.of(LocalTime.of(9, 7, 0), LocalTime.of(1, 48), | ||
dateTime2ExprTs(today.atTime(LocalTime.of(10, 55, 0)))), | ||
Arguments.of(LocalTime.of(17, 30, 0), LocalDateTime.of(2077, 12, 21, 12, 20, 42), | ||
dateTime2ExprTs(today.plusDays(1).atTime(LocalTime.of(5, 50, 42)))), | ||
Arguments.of(LocalTime.of(17, 30, 0), Instant.ofEpochSecond(42), | ||
dateTime2ExprTs(today.atTime(LocalTime.of(17, 30, 42)))), | ||
// DATETIME and STRING/DATE/TIME/DATETIME/TIMESTAMP | ||
Arguments.of(LocalDateTime.of(1961, 4, 12, 9, 7, 0), "2077-12-15 01:48:00", | ||
dateTime2ExprTs(LocalDateTime.of(1961, 4, 12, 10, 55, 0))), | ||
Arguments.of(LocalDateTime.of(1984, 2, 10, 12, 20, 42), LocalDate.of(2077, 12, 21), | ||
dateTime2ExprTs(LocalDateTime.of(1984, 2, 10, 12, 20, 42))), | ||
Arguments.of(LocalDateTime.of(1961, 4, 12, 9, 7, 0), LocalTime.of(1, 48), | ||
dateTime2ExprTs(LocalDateTime.of(1961, 4, 12, 10, 55, 0))), | ||
Arguments.of(LocalDateTime.of(2020, 12, 31, 17, 30, 0), | ||
LocalDateTime.of(2077, 12, 21, 12, 20, 42), | ||
dateTime2ExprTs(LocalDateTime.of(2021, 1, 1, 5, 50, 42))), | ||
Arguments.of(LocalDateTime.of(2020, 12, 31, 17, 30, 0), Instant.ofEpochSecond(42), | ||
dateTime2ExprTs(LocalDateTime.of(2020, 12, 31, 17, 30, 42))), | ||
// TIMESTAMP and STRING/DATE/TIME/DATETIME/TIMESTAMP | ||
Arguments.of(dateTime2Instant(LocalDateTime.of(1961, 4, 12, 9, 7, 0)), | ||
"2077-12-15 01:48:00", | ||
dateTime2ExprTs(LocalDateTime.of(1961, 4, 12, 10, 55, 0))), | ||
Arguments.of(dateTime2Instant(LocalDateTime.of(1984, 2, 10, 12, 20, 42)), | ||
LocalDate.of(2077, 12, 21), | ||
dateTime2ExprTs(LocalDateTime.of(1984, 2, 10, 12, 20, 42))), | ||
Arguments.of(dateTime2Instant(LocalDateTime.of(1961, 4, 12, 9, 7, 0)), | ||
LocalTime.of(1, 48), | ||
dateTime2ExprTs(LocalDateTime.of(1961, 4, 12, 10, 55, 0))), | ||
Arguments.of(dateTime2Instant(LocalDateTime.of(2020, 12, 31, 17, 30, 0)), | ||
LocalDateTime.of(2077, 12, 21, 12, 20, 42), | ||
dateTime2ExprTs(LocalDateTime.of(2021, 1, 1, 5, 50, 42))), | ||
Arguments.of(dateTime2Instant(LocalDateTime.of(2020, 12, 31, 17, 30, 0)), | ||
Instant.ofEpochSecond(42), | ||
dateTime2ExprTs(LocalDateTime.of(2020, 12, 31, 17, 30, 42))) | ||
); | ||
} | ||
|
||
/** | ||
* Test `TIMESTAMP` function which takes 2 arguments with input of different types. | ||
* @param arg1 First argument to be passed to `TIMESTAMP` function. | ||
* @param arg2 Second argument to be passed to `TIMESTAMP` function. | ||
* @param expected The expected result. | ||
*/ | ||
@ParameterizedTest | ||
@MethodSource("getTestData") | ||
public void timestamp_with_two_args(Object arg1, Object arg2, ExprTimestampValue expected) { | ||
var expr = DSL.timestamp(functionProperties, | ||
DSL.literal(ExprValueUtils.fromObjectValue(arg1)), | ||
DSL.literal(ExprValueUtils.fromObjectValue(arg2))); | ||
assertEquals(TIMESTAMP, expr.type()); | ||
assertEquals(expected, expr.valueOf()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oooh. I do not like this logic is required here.
It would be better if the logic was in Expr*Value classes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you give an example, please?