Skip to content

Commit

Permalink
Extend comparison methods to accept different datetime types. (#129)
Browse files Browse the repository at this point in the history
* Extend comparison methods to accept different datetime types.

Signed-off-by: Yury-Fridlyand <yuryf@bitquilltech.com>
Signed-off-by: Yury-Fridlyand <yury.fridlyand@improving.com>
  • Loading branch information
Yury-Fridlyand committed Jan 10, 2023
1 parent 1108379 commit 9af22f9
Show file tree
Hide file tree
Showing 17 changed files with 1,788 additions and 170 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ public abstract class AbstractExprValue implements ExprValue {
public int compareTo(ExprValue other) {
if (this.isNull() || this.isMissing() || other.isNull() || other.isMissing()) {
throw new IllegalStateException(
String.format("[BUG] Unreachable, Comparing with NULL or MISSING is undefined"));
"[BUG] Unreachable, Comparing with NULL or MISSING is undefined");
}
if ((this.isNumber() && other.isNumber()) || this.type() == other.type()) {
if ((this.isNumber() && other.isNumber())
|| (this.isDateTime() && other.isDateTime())
|| this.type() == other.type()) {
return compare(other);
} else {
throw new ExpressionEvaluationException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ public Instant timestampValue() {
return ZonedDateTime.of(date, timeValue(), ExprTimestampValue.ZONE).toInstant();
}

@Override
public boolean isDateTime() {
return true;
}

@Override
public String toString() {
return String.format("DATE '%s'", value());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ public Instant timestampValue() {
return ZonedDateTime.of(datetime, ExprTimestampValue.ZONE).toInstant();
}

@Override
public boolean isDateTime() {
return true;
}

@Override
public int compare(ExprValue other) {
return datetime.compareTo(other.datetimeValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ public Instant timestampValue(FunctionProperties functionProperties) {
.toInstant();
}

@Override
public boolean isDateTime() {
return true;
}

@Override
public String toString() {
return String.format("TIME '%s'", value());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ public LocalDateTime datetimeValue() {
return timestamp.atZone(ZONE).toLocalDateTime();
}

@Override
public boolean isDateTime() {
return true;
}

@Override
public String toString() {
return String.format("TIMESTAMP '%s'", value());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ default boolean isNumber() {
return false;
}

/**
* Is Number value.
*
* @return true: is a datetime value, otherwise false
*/
default boolean isDateTime() {
return false;
}

/**
* Get the {@link BindingTuple}.
*/
Expand Down
36 changes: 30 additions & 6 deletions core/src/main/java/org/opensearch/sql/expression/DSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -536,28 +536,52 @@ public static FunctionExpression not(Expression... expressions) {
return compile(FunctionProperties.None, BuiltinFunctionName.NOT, expressions);
}

public static FunctionExpression equal(FunctionProperties fp, Expression... expressions) {
return compile(fp, BuiltinFunctionName.EQUAL, expressions);
}

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

public static FunctionExpression notequal(FunctionProperties fp, Expression... expressions) {
return compile(fp, BuiltinFunctionName.NOTEQUAL, expressions);
}

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

public static FunctionExpression less(FunctionProperties fp, Expression... expressions) {
return compile(fp, BuiltinFunctionName.LESS, expressions);
}

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

public static FunctionExpression lte(FunctionProperties fp, Expression... expressions) {
return compile(fp, BuiltinFunctionName.LTE, expressions);
}

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

public static FunctionExpression greater(FunctionProperties fp, Expression... expressions) {
return compile(fp, BuiltinFunctionName.GREATER, expressions);
}

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

public static FunctionExpression gte(FunctionProperties fp, Expression... expressions) {
return compile(fp, BuiltinFunctionName.GTE, expressions);
}

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

public static FunctionExpression like(Expression... expressions) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,34 @@
import static org.opensearch.sql.data.model.ExprValueUtils.LITERAL_NULL;
import static org.opensearch.sql.data.model.ExprValueUtils.LITERAL_TRUE;
import static org.opensearch.sql.data.type.ExprCoreType.BOOLEAN;
import static org.opensearch.sql.data.type.ExprCoreType.DATE;
import static org.opensearch.sql.data.type.ExprCoreType.DATETIME;
import static org.opensearch.sql.data.type.ExprCoreType.INTEGER;
import static org.opensearch.sql.data.type.ExprCoreType.STRING;
import static org.opensearch.sql.data.type.ExprCoreType.TIME;
import static org.opensearch.sql.data.type.ExprCoreType.TIMESTAMP;
import static org.opensearch.sql.expression.function.FunctionDSL.impl;
import static org.opensearch.sql.expression.function.FunctionDSL.implWithProperties;
import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandling;
import static org.opensearch.sql.expression.function.FunctionDSL.nullMissingHandlingWithProperties;
import static org.opensearch.sql.utils.DateTimeUtils.extractDateTime;

import com.google.common.collect.ImmutableTable;
import com.google.common.collect.Table;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.tuple.Pair;
import org.opensearch.sql.data.model.ExprBooleanValue;
import org.opensearch.sql.data.model.ExprValue;
import org.opensearch.sql.data.type.ExprCoreType;
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.FunctionDSL;
import org.opensearch.sql.expression.function.FunctionName;
import org.opensearch.sql.expression.function.SerializableBiFunction;
import org.opensearch.sql.utils.OperatorUtils;

/**
Expand Down Expand Up @@ -141,116 +155,80 @@ public static void register(BuiltinFunctionRepository repository) {
.build();

private static DefaultFunctionResolver and() {
return FunctionDSL.define(BuiltinFunctionName.AND.getName(), FunctionDSL
.impl((v1, v2) -> lookupTableFunction(v1, v2, andTable), BOOLEAN, BOOLEAN,
BOOLEAN));
return FunctionDSL.define(BuiltinFunctionName.AND.getName(),
impl((v1, v2) -> lookupTableFunction(v1, v2, andTable), BOOLEAN, BOOLEAN, BOOLEAN));
}

private static DefaultFunctionResolver or() {
return FunctionDSL.define(BuiltinFunctionName.OR.getName(), FunctionDSL
.impl((v1, v2) -> lookupTableFunction(v1, v2, orTable), BOOLEAN, BOOLEAN,
BOOLEAN));
return FunctionDSL.define(BuiltinFunctionName.OR.getName(),
impl((v1, v2) -> lookupTableFunction(v1, v2, orTable), BOOLEAN, BOOLEAN, BOOLEAN));
}

private static DefaultFunctionResolver xor() {
return FunctionDSL.define(BuiltinFunctionName.XOR.getName(), FunctionDSL
.impl((v1, v2) -> lookupTableFunction(v1, v2, xorTable), BOOLEAN, BOOLEAN,
BOOLEAN));
return FunctionDSL.define(BuiltinFunctionName.XOR.getName(),
impl((v1, v2) -> lookupTableFunction(v1, v2, xorTable), BOOLEAN, BOOLEAN, BOOLEAN));
}

private static DefaultFunctionResolver equal() {
return FunctionDSL.define(BuiltinFunctionName.EQUAL.getName(),
ExprCoreType.coreTypes().stream()
.map(type -> FunctionDSL.impl(
FunctionDSL.nullMissingHandling((v1, v2) -> ExprBooleanValue.of(v1.equals(v2))),
BOOLEAN, type, type))
.collect(
Collectors.toList()));
return compareImpl(BuiltinFunctionName.EQUAL.getName(),
(Comparable v1, Comparable v2) -> v1.equals(v2));
}

private static DefaultFunctionResolver notEqual() {
return FunctionDSL
.define(BuiltinFunctionName.NOTEQUAL.getName(), ExprCoreType.coreTypes().stream()
.map(type -> FunctionDSL
.impl(
FunctionDSL
.nullMissingHandling((v1, v2) -> ExprBooleanValue.of(!v1.equals(v2))),
BOOLEAN,
type,
type))
.collect(
Collectors.toList()));
return compareImpl(BuiltinFunctionName.NOTEQUAL.getName(),
(Comparable v1, Comparable v2) -> !v1.equals(v2));
}

private static DefaultFunctionResolver less() {
return FunctionDSL
.define(BuiltinFunctionName.LESS.getName(), ExprCoreType.coreTypes().stream()
.map(type -> FunctionDSL
.impl(FunctionDSL
.nullMissingHandling((v1, v2) -> ExprBooleanValue.of(v1.compareTo(v2) < 0)),
BOOLEAN,
type, type))
.collect(
Collectors.toList()));
return compareImpl(BuiltinFunctionName.LESS.getName(),
(Comparable v1, Comparable v2) -> v1.compareTo(v2) < 0);
}

private static DefaultFunctionResolver lte() {
return FunctionDSL
.define(BuiltinFunctionName.LTE.getName(), ExprCoreType.coreTypes().stream()
.map(type -> FunctionDSL
.impl(
FunctionDSL
.nullMissingHandling(
(v1, v2) -> ExprBooleanValue.of(v1.compareTo(v2) <= 0)),
BOOLEAN,
type, type))
.collect(
Collectors.toList()));
return compareImpl(BuiltinFunctionName.LTE.getName(),
(Comparable v1, Comparable v2) -> v1.compareTo(v2) <= 0);
}

private static DefaultFunctionResolver greater() {
return FunctionDSL
.define(BuiltinFunctionName.GREATER.getName(), ExprCoreType.coreTypes().stream()
.map(type -> FunctionDSL
.impl(FunctionDSL
.nullMissingHandling((v1, v2) -> ExprBooleanValue.of(v1.compareTo(v2) > 0)),
BOOLEAN, type, type))
.collect(
Collectors.toList()));
return compareImpl(BuiltinFunctionName.GREATER.getName(),
(Comparable v1, Comparable v2) -> v1.compareTo(v2) > 0);
}

private static DefaultFunctionResolver gte() {
return FunctionDSL
.define(BuiltinFunctionName.GTE.getName(), ExprCoreType.coreTypes().stream()
.map(type -> FunctionDSL
.impl(
FunctionDSL.nullMissingHandling(
(v1, v2) -> ExprBooleanValue.of(v1.compareTo(v2) >= 0)),
BOOLEAN,
type, type))
.collect(
Collectors.toList()));
return compareImpl(BuiltinFunctionName.GTE.getName(),
(Comparable v1, Comparable v2) -> v1.compareTo(v2) >= 0);
}

private static DefaultFunctionResolver compareImpl(
FunctionName function, SerializableBiFunction<Comparable, Comparable, Boolean> comparator) {
return FunctionDSL.define(function,
Stream.concat(
ExprCoreType.coreTypes().stream()
.map(type -> impl(nullMissingHandling(
(v1, v2) -> ExprBooleanValue.of(comparator.apply(v1, v2))),
BOOLEAN, type, type)),
permuteTemporalTypesByPairs().stream()
.map(pair -> implWithProperties(nullMissingHandlingWithProperties(
(fp, v1, v2) -> ExprBooleanValue.of(comparator.apply(
extractDateTime(v1, fp), extractDateTime(v2, fp)))),
BOOLEAN, pair.getLeft(), pair.getRight())))
.collect(Collectors.toList()));
}

private static DefaultFunctionResolver like() {
return FunctionDSL.define(BuiltinFunctionName.LIKE.getName(), FunctionDSL
.impl(FunctionDSL.nullMissingHandling(OperatorUtils::matches), BOOLEAN, STRING,
STRING));
return FunctionDSL.define(BuiltinFunctionName.LIKE.getName(),
impl(nullMissingHandling(OperatorUtils::matches), BOOLEAN, STRING, STRING));
}

private static DefaultFunctionResolver regexp() {
return FunctionDSL.define(BuiltinFunctionName.REGEXP.getName(), FunctionDSL
.impl(FunctionDSL.nullMissingHandling(OperatorUtils::matchesRegexp),
INTEGER, STRING, STRING));
return FunctionDSL.define(BuiltinFunctionName.REGEXP.getName(),
impl(nullMissingHandling(OperatorUtils::matchesRegexp), INTEGER, STRING, STRING));
}

private static DefaultFunctionResolver notLike() {
return FunctionDSL.define(BuiltinFunctionName.NOT_LIKE.getName(), FunctionDSL
.impl(FunctionDSL.nullMissingHandling(
return FunctionDSL.define(BuiltinFunctionName.NOT_LIKE.getName(), impl(nullMissingHandling(
(v1, v2) -> UnaryPredicateOperator.not(OperatorUtils.matches(v1, v2))),
BOOLEAN,
STRING,
STRING));
BOOLEAN, STRING, STRING));
}

private static ExprValue lookupTableFunction(ExprValue arg1, ExprValue arg2,
Expand All @@ -261,4 +239,13 @@ private static ExprValue lookupTableFunction(ExprValue arg1, ExprValue arg2,
return table.get(arg2, arg1);
}
}

private static List<Pair<ExprCoreType, ExprCoreType>> permuteTemporalTypesByPairs() {
return List.of(
Pair.of(DATE, TIME), Pair.of(DATE, DATETIME), Pair.of(DATE, TIMESTAMP),
Pair.of(TIME, DATE), Pair.of(TIME, DATETIME), Pair.of(TIME, TIMESTAMP),
Pair.of(DATETIME, TIME), Pair.of(DATETIME, DATE), Pair.of(DATETIME, TIMESTAMP),
Pair.of(TIMESTAMP, TIME), Pair.of(TIMESTAMP, DATE), Pair.of(TIMESTAMP, DATETIME)
);
}
}
Loading

0 comments on commit 9af22f9

Please sign in to comment.