Skip to content

Commit

Permalink
Rework on DATE_ADD/ADDDATE functions.
Browse files Browse the repository at this point in the history
Signed-off-by: Yury-Fridlyand <[email protected]>
  • Loading branch information
Yury-Fridlyand committed Sep 19, 2022
1 parent 929ebfe commit a4bca4f
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,20 @@
import static org.opensearch.sql.expression.function.FunctionDSL.impl;
import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandling;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.Arrays;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.tuple.Pair;
import org.opensearch.sql.data.model.ExprDateValue;
import org.opensearch.sql.data.model.ExprDatetimeValue;
import org.opensearch.sql.data.model.ExprIntegerValue;
Expand All @@ -38,8 +45,11 @@
import org.opensearch.sql.expression.function.BuiltinFunctionName;
import org.opensearch.sql.expression.function.BuiltinFunctionRepository;
import org.opensearch.sql.expression.function.DefaultFunctionResolver;
import org.opensearch.sql.expression.function.FunctionBuilder;
import org.opensearch.sql.expression.function.FunctionName;
import org.opensearch.sql.expression.function.FunctionResolver;
import org.opensearch.sql.expression.function.FunctionSignature;
import org.opensearch.sql.expression.function.SerializableFunction;

/**
* The definition of date and time functions.
Expand Down Expand Up @@ -90,29 +100,45 @@ public void register(BuiltinFunctionRepository repository) {
/**
* Specify a start date and add a temporal amount to the date.
* The return type depends on the date type and the interval unit. Detailed supported signatures:
* (STRING/DATE/DATETIME/TIMESTAMP, INTERVAL) -> DATETIME
* (DATE, LONG) -> DATE
* (STRING/DATETIME/TIMESTAMP, LONG) -> DATETIME
* (DATE/DATETIME/TIMESTAMP/TIME, INTERVAL) -> DATETIME
* (DATE, INTERVAL) -> DATE // when interval has no time part
* (TIME, INTERVAL) -> TIME // when interval has no date part
*/

private DefaultFunctionResolver add_date(FunctionName functionName) {
return define(functionName,
impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval),
DATETIME, STRING, INTERVAL),
private SerializableFunction<?, ?>[] get_date_add_signatures() {
return new SerializableFunction[]{
impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATETIME, DATE, INTERVAL),
impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval), DATE, DATE, INTERVAL),
impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval),
DATETIME, DATETIME, INTERVAL),
DATETIME, DATETIME, INTERVAL),
impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval),
DATETIME, TIMESTAMP, INTERVAL),
DATETIME, TIMESTAMP, INTERVAL),
impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval),
DATETIME, TIME, INTERVAL),
impl(nullMissingHandling(DateTimeFunction::exprAddDateInterval),
TIME, TIME, INTERVAL)
};
}

/**
* Adds an integer number of days to the first argument
* (DATE, LONG) -> DATE
* (TIME/DATETIME/TIMESTAMP, LONG) -> DATETIME
*/
private SerializableFunction<?, ?>[] get_adddate_signatures() {
return new SerializableFunction[]{
impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATE, DATE, LONG),
impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, DATETIME, LONG),
impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, TIMESTAMP, LONG),
impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, STRING, LONG)
);
impl(nullMissingHandling(DateTimeFunction::exprAddDateDays), DATETIME, TIME, LONG)
};
}

@SuppressWarnings("unchecked")
private DefaultFunctionResolver adddate() {
return add_date(BuiltinFunctionName.ADDDATE.getName());
return define(BuiltinFunctionName.ADDDATE.getName(),
(SerializableFunction<FunctionName, Pair<FunctionSignature, FunctionBuilder>>[])
(Stream.concat(Arrays.stream(get_date_add_signatures()), Arrays.stream(get_adddate_signatures()))
.toArray(SerializableFunction<?, ?>[]::new)));
}

/**
Expand All @@ -128,8 +154,11 @@ private DefaultFunctionResolver date() {
impl(nullMissingHandling(DateTimeFunction::exprDate), DATE, TIMESTAMP));
}

@SuppressWarnings("unchecked")
private DefaultFunctionResolver date_add() {
return add_date(BuiltinFunctionName.DATE_ADD.getName());
return define(BuiltinFunctionName.DATE_ADD.getName(),
(SerializableFunction<FunctionName, Pair<FunctionSignature, FunctionBuilder>>[])
get_date_add_signatures());
}

/**
Expand Down Expand Up @@ -429,16 +458,28 @@ private DefaultFunctionResolver date_format() {
}

/**
* ADDDATE function implementation for ExprValue.
* DATE_ADD function implementation for ExprValue.
*
* @param date ExprValue of String/Date/Datetime/Timestamp type.
* @param expr ExprValue of Interval type, the temporal amount to add.
* @return Datetime resulted from expr added to date.
*/
private ExprValue exprAddDateInterval(ExprValue date, ExprValue expr) {
ExprValue exprValue = new ExprDatetimeValue(date.datetimeValue().plus(expr.intervalValue()));
return (exprValue.timeValue().toSecondOfDay() == 0 ? new ExprDateValue(exprValue.dateValue())
: exprValue);
var dt = LocalDateTime.MIN;
if (date.type() == TIME) {
if (expr.intervalValue() instanceof Duration) {
return new ExprTimeValue(date.timeValue().plus(expr.intervalValue()));
} else {
dt = LocalDateTime.of(LocalDate.now(), date.timeValue());
}
} else {
dt = date.datetimeValue();
}
dt = dt.plus(expr.intervalValue());
if (date.type() == DATE && expr.intervalValue() instanceof Period) {
return new ExprDateValue(dt.toLocalDate());
}
return new ExprDatetimeValue(dt);
}

/**
Expand All @@ -449,9 +490,16 @@ private ExprValue exprAddDateInterval(ExprValue date, ExprValue expr) {
* @return Date/Datetime resulted from days added to date.
*/
private ExprValue exprAddDateDays(ExprValue date, ExprValue days) {
ExprValue exprValue = new ExprDatetimeValue(date.datetimeValue().plusDays(days.longValue()));
return (exprValue.timeValue().toSecondOfDay() == 0 ? new ExprDateValue(exprValue.dateValue())
: exprValue);
if (date.type() == DATE) {
return new ExprDateValue(date.dateValue().plusDays(days.longValue()));
}
var dt = LocalDateTime.MIN;
if (date.type() == TIME) {
dt = LocalDateTime.of(LocalDate.now(), date.timeValue());
} else {
dt = date.datetimeValue();
}
return new ExprDatetimeValue(dt.plusDays(days.longValue()));
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private ExprValue hour(ExprValue value) {
}

private ExprValue day(ExprValue value) {
return new ExprIntervalValue(Duration.ofDays(getIntegerValue(value)));
return new ExprIntervalValue(Period.ofDays(getIntegerValue(value)));
}

private ExprValue week(ExprValue value) {
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 @@ -341,6 +341,7 @@ multiFieldRelevanceFunction

convertedDataType
: typeName=DATE
| typeName=DATETIME
| typeName=TIME
| typeName=TIMESTAMP
| typeName=INT
Expand Down

0 comments on commit a4bca4f

Please sign in to comment.