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

Extend comparison methods to accept different datetime types. (#129) #1196

Merged
merged 10 commits into from
Jan 26, 2023
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 Datetime value.
*
* @return true: is a datetime value, otherwise false
*/
default boolean isDateTime() {
return false;
}

/**
* Get the {@link BindingTuple}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,11 @@ public enum ExprCoreType implements ExprType {

/**
* Date.
* Todo. compatible relationship.
*/
TIMESTAMP(STRING),
DATE(STRING),
TIME(STRING),
DATETIME(STRING),
DATETIME(STRING, DATE, TIME),
TIMESTAMP(STRING, DATETIME),
INTERVAL(UNDEFINED),

/**
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 @@ -19,7 +19,9 @@
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 java.util.Arrays;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -176,12 +178,18 @@ private static DefaultFunctionResolver castToTime() {
);
}

// `DATE`/`TIME`/`DATETIME` -> `DATETIME`/TIMESTAMP` cast tested in BinaryPredicateOperatorTest
private static DefaultFunctionResolver castToTimestamp() {
return FunctionDSL.define(BuiltinFunctionName.CAST_TO_TIMESTAMP.getName(),
impl(nullMissingHandling(
(v) -> new ExprTimestampValue(v.stringValue())), TIMESTAMP, STRING),
impl(nullMissingHandling(
(v) -> new ExprTimestampValue(v.timestampValue())), TIMESTAMP, DATETIME),
impl(nullMissingHandling(
(v) -> new ExprTimestampValue(v.timestampValue())), TIMESTAMP, DATE),
implWithProperties(nullMissingHandlingWithProperties(
(fp, v) -> new ExprTimestampValue(((ExprTimeValue)v).timestampValue(fp))),
TIMESTAMP, TIME),
impl(nullMissingHandling((v) -> v), TIMESTAMP, TIMESTAMP)
);
}
Expand All @@ -193,7 +201,11 @@ private static DefaultFunctionResolver castToDatetime() {
impl(nullMissingHandling(
(v) -> new ExprDatetimeValue(v.datetimeValue())), DATETIME, TIMESTAMP),
impl(nullMissingHandling(
(v) -> new ExprDatetimeValue(v.datetimeValue())), DATETIME, DATE)
(v) -> new ExprDatetimeValue(v.datetimeValue())), DATETIME, DATE),
implWithProperties(nullMissingHandlingWithProperties(
(fp, v) -> new ExprDatetimeValue(((ExprTimeValue)v).datetimeValue(fp))),
DATETIME, TIME),
impl(nullMissingHandling((v) -> v), DATETIME, DATETIME)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,55 @@

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.opensearch.sql.utils.ComparisonUtil.compare;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.opensearch.sql.data.type.ExprCoreType.BOOLEAN;

import org.junit.jupiter.api.Test;
import org.opensearch.sql.exception.ExpressionEvaluationException;

public class ExprBooleanValueTest {

@Test
public void comparabilityTest() {
ExprValue booleanValue = ExprValueUtils.booleanValue(false);
ExpressionEvaluationException exception = assertThrows(ExpressionEvaluationException.class,
() -> compare(booleanValue, booleanValue));
assertEquals("ExprBooleanValue instances are not comparable", exception.getMessage());
public void equals_to_self() {
ExprValue value = ExprValueUtils.booleanValue(false);
assertEquals(value.booleanValue(), false);
assertTrue(value.equals(value));
}

@Test
public void equal() {
ExprValue v1 = ExprBooleanValue.of(true);
ExprValue v2 = ExprBooleanValue.of(true);
assertTrue(v1.equals(v2));
assertTrue(v2.equals(v1));
assertEquals(0, ((ExprBooleanValue)v1).compare((ExprBooleanValue)v2));
assertEquals(0, ((ExprBooleanValue)v2).compare((ExprBooleanValue)v1));
}

@Test
public void compare() {
var v1 = ExprBooleanValue.of(true);
var v2 = ExprBooleanValue.of(false);
assertEquals(1, v1.compare(v2));
assertEquals(-1, v2.compare(v1));
}

@Test
public void invalid_get_value() {
ExprDateValue value = new ExprDateValue("2020-08-20");
assertThrows(ExpressionEvaluationException.class, value::booleanValue,
String.format("invalid to get booleanValue from value of type %s", value.type()));
}

@Test
public void value() {
ExprValue value = ExprBooleanValue.of(true);
assertEquals(true, value.value());
}

@Test
public void type() {
ExprValue value = ExprBooleanValue.of(false);
assertEquals(BOOLEAN, value.type());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

package org.opensearch.sql.data.model;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.opensearch.sql.data.type.ExprCoreType.STRING;

import org.junit.jupiter.api.Test;
import org.opensearch.sql.exception.ExpressionEvaluationException;

public class ExprStringValueTest {
@Test
public void equals_to_self() {
ExprValue string = ExprValueUtils.stringValue("str");
assertEquals(string.stringValue(), "str");
assertTrue(string.equals(string));
}

@Test
public void equal() {
ExprValue v1 = new ExprStringValue("str");
ExprValue v2 = ExprValueUtils.stringValue("str");
assertTrue(v1.equals(v2));
assertTrue(v2.equals(v1));
assertEquals(0, ((ExprStringValue)v1).compare((ExprStringValue)v2));
assertEquals(0, ((ExprStringValue)v2).compare((ExprStringValue)v1));
}

@Test
public void compare() {
ExprStringValue v1 = new ExprStringValue("str1");
ExprStringValue v2 = new ExprStringValue("str2");
assertEquals(-1, v1.compare(v2));
assertEquals(1, v2.compare(v1));
}

@Test
public void invalid_get_value() {
ExprDateValue value = new ExprDateValue("2020-08-20");
assertThrows(ExpressionEvaluationException.class, value::stringValue,
String.format("invalid to get intervalValue from value of type %s", value.type()));
}

@Test
public void value() {
ExprValue value = new ExprStringValue("string");
assertEquals("string", value.value());
}

@Test
public void type() {
ExprValue value = new ExprStringValue("string");
assertEquals(STRING, value.type());
}
}
Loading