diff --git a/document-store/src/integrationTest/java/org/hypertrace/core/documentstore/DocStoreQueryV1Test.java b/document-store/src/integrationTest/java/org/hypertrace/core/documentstore/DocStoreQueryV1Test.java index a482c1ec..1024f0e2 100644 --- a/document-store/src/integrationTest/java/org/hypertrace/core/documentstore/DocStoreQueryV1Test.java +++ b/document-store/src/integrationTest/java/org/hypertrace/core/documentstore/DocStoreQueryV1Test.java @@ -69,6 +69,7 @@ import com.typesafe.config.ConfigFactory; import java.io.IOException; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -6546,6 +6547,58 @@ SELECT itemDetails.item, MAX(itemDetails.date) AS latest_date dataStoreName, iterator, "query/sub_query_join_response_with_nested_fields.json", 3); } + @ParameterizedTest + @ArgumentsSource(MongoProvider.class) + void testDateConstantExpressionInFilterForMongo(String dataStoreName) throws IOException { + Collection collection = getCollection(dataStoreName); + Date currentDate = new Date(System.currentTimeMillis()); + + // Test that DateConstantExpression works in a filter for Mongo + Query query = + Query.builder() + .setFilter( + RelationalExpression.of( + IdentifierExpression.of("_lastUpdateTime"), + LTE, + ConstantExpression.of(currentDate))) + .addSelection(IdentifierExpression.of("item")) + .addSelection(IdentifierExpression.of("price")) + .addSelection(IdentifierExpression.of("quantity")) + .addSort(IdentifierExpression.of("price"), ASC) + .addSort(IdentifierExpression.of("quantity"), DESC) + .build(); + + // Verify results + Iterator iterator = collection.aggregate(query); + assertDocsAndSizeEqual( + dataStoreName, iterator, "query/filter_contains_date_constant_expression.json", 8); + } + + @ParameterizedTest + @ArgumentsSource(PostgresProvider.class) + void testDateConstantExpressionInFilterForPostgresThrowsException(String dataStoreName) { + Collection collection = getCollection(dataStoreName); + Date currentDate = new Date(System.currentTimeMillis()); + + // Test that DateConstantExpression throws UnsupportedOperationException in a filter for + // Postgres + Query query = + Query.builder() + .setFilter( + RelationalExpression.of( + IdentifierExpression.of("_lastUpdateTime"), + LTE, + ConstantExpression.of(currentDate))) + .addSelection(IdentifierExpression.of("item")) + .build(); + + // This should throw UnsupportedOperationException for Postgres + assertThrows( + UnsupportedOperationException.class, + () -> collection.aggregate(query), + "DateConstantExpression should throw UnsupportedOperationException for Postgres"); + } + private static Collection getCollection(final String dataStoreName) { return getCollection(dataStoreName, COLLECTION_NAME); } diff --git a/document-store/src/integrationTest/resources/query/filter_contains_date_constant_expression.json b/document-store/src/integrationTest/resources/query/filter_contains_date_constant_expression.json new file mode 100644 index 00000000..8dc828bb --- /dev/null +++ b/document-store/src/integrationTest/resources/query/filter_contains_date_constant_expression.json @@ -0,0 +1,42 @@ +[ + { + "item":"Shampoo", + "price":5, + "quantity":20 + }, + { + "item":"Shampoo", + "price":5, + "quantity":10 + }, + { + "item":"Comb", + "price":7.5, + "quantity":10 + }, + { + "item":"Comb", + "price":7.5, + "quantity":5 + }, + { + "item":"Soap", + "price":10, + "quantity":5 + }, + { + "item":"Soap", + "price":10, + "quantity":2 + }, + { + "item":"Soap", + "price":20, + "quantity":5 + }, + { + "item":"Mirror", + "price":20, + "quantity":1 + } +] \ No newline at end of file diff --git a/document-store/src/main/java/org/hypertrace/core/documentstore/expression/impl/ConstantExpression.java b/document-store/src/main/java/org/hypertrace/core/documentstore/expression/impl/ConstantExpression.java index 03bbbfc8..6cdef3d3 100644 --- a/document-store/src/main/java/org/hypertrace/core/documentstore/expression/impl/ConstantExpression.java +++ b/document-store/src/main/java/org/hypertrace/core/documentstore/expression/impl/ConstantExpression.java @@ -1,5 +1,6 @@ package org.hypertrace.core.documentstore.expression.impl; +import java.util.Date; import java.util.List; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -43,6 +44,10 @@ public static ConstantExpression of(final Document value) { return new DocumentConstantExpression(value); } + public static ConstantExpression of(final Date value) { + return new DateConstantExpression(value); + } + public static ConstantExpression ofStrings(final List values) { return validateAndReturn(values); } @@ -96,4 +101,25 @@ public String toString() { return "JSON(" + StringUtils.wrap(getValue().toJson(), "'") + ")"; } } + + public static class DateConstantExpression extends ConstantExpression { + private DateConstantExpression(final Date value) { + super(value); + } + + @Override + public T accept(final SelectTypeExpressionVisitor visitor) { + return visitor.visit(this); + } + + @Override + public Date getValue() { + return (Date) value; + } + + @Override + public String toString() { + return "DATE(" + StringUtils.wrap(getValue().toString(), "'") + ")"; + } + } } diff --git a/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/parser/MongoConstantExpressionParser.java b/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/parser/MongoConstantExpressionParser.java index 04dbdac1..8c63e808 100644 --- a/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/parser/MongoConstantExpressionParser.java +++ b/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/parser/MongoConstantExpressionParser.java @@ -6,6 +6,7 @@ import com.mongodb.BasicDBObject; import lombok.NoArgsConstructor; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression; +import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DateConstantExpression; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DocumentConstantExpression; @NoArgsConstructor @@ -30,6 +31,12 @@ public Object visit(final DocumentConstantExpression expression) { } } + @SuppressWarnings("unchecked") + @Override + public Object visit(final DateConstantExpression expression) { + return expression.getValue(); + } + Object parse(final ConstantExpression expression) { return expression.getValue(); } diff --git a/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/parser/MongoNonProjectedSortTypeExpressionParser.java b/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/parser/MongoNonProjectedSortTypeExpressionParser.java index bd9b8949..582bf9f9 100644 --- a/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/parser/MongoNonProjectedSortTypeExpressionParser.java +++ b/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/parser/MongoNonProjectedSortTypeExpressionParser.java @@ -15,6 +15,7 @@ import org.hypertrace.core.documentstore.expression.impl.AggregateExpression; import org.hypertrace.core.documentstore.expression.impl.AliasedIdentifierExpression; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression; +import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DateConstantExpression; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DocumentConstantExpression; import org.hypertrace.core.documentstore.expression.impl.FunctionExpression; import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression; @@ -94,6 +95,16 @@ public Map visit(DocumentConstantExpression expression) { expression.getValue().toString())); } + @SuppressWarnings("unchecked") + @Override + public Map visit(DateConstantExpression expression) { + throw new UnsupportedOperationException( + String.format( + "Cannot sort a constant expression ($%s) in MongoDB." + + "Set alias in selection and sort by the alias as identifier", + expression.getValue().toString())); + } + @SuppressWarnings("unchecked") @Override public Map visit(final AliasedIdentifierExpression expression) { diff --git a/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/parser/MongoProjectingParser.java b/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/parser/MongoProjectingParser.java index caffd5f8..e2a0d138 100644 --- a/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/parser/MongoProjectingParser.java +++ b/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/parser/MongoProjectingParser.java @@ -8,6 +8,7 @@ import org.apache.commons.lang3.StringUtils; import org.hypertrace.core.documentstore.expression.impl.AggregateExpression; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression; +import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DateConstantExpression; import org.hypertrace.core.documentstore.expression.impl.FunctionExpression; import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression; import org.hypertrace.core.documentstore.expression.type.SelectTypeExpression; @@ -51,6 +52,21 @@ public Map visit(final ConstantExpression expression) { return convertToMap(key, parsed); } + @SuppressWarnings("unchecked") + @Override + public Map visit(final DateConstantExpression expression) { + final Object parsed; + + try { + parsed = baseParser.visit(expression); + } catch (UnsupportedOperationException e) { + return Map.of(); + } + + final String key = getAlias(expression); + return convertToMap(key, parsed); + } + @SuppressWarnings("unchecked") @Override public Map visit(final FunctionExpression expression) { diff --git a/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/transformer/MongoSelectionsAddingTransformation.java b/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/transformer/MongoSelectionsAddingTransformation.java index 2fb4ca0c..cd6fcc7f 100644 --- a/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/transformer/MongoSelectionsAddingTransformation.java +++ b/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/transformer/MongoSelectionsAddingTransformation.java @@ -10,6 +10,7 @@ import org.hypertrace.core.documentstore.expression.impl.AggregateExpression; import org.hypertrace.core.documentstore.expression.impl.AliasedIdentifierExpression; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression; +import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DateConstantExpression; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DocumentConstantExpression; import org.hypertrace.core.documentstore.expression.impl.FunctionExpression; import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression; @@ -113,6 +114,12 @@ public Optional visit(final DocumentConstantExpression expression return Optional.empty(); } + @SuppressWarnings("unchecked") + @Override + public Optional visit(final DateConstantExpression expression) { + return Optional.empty(); + } + @SuppressWarnings("unchecked") @Override public Optional visit(final FunctionExpression expression) { diff --git a/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/transformer/MongoSelectionsUpdatingTransformation.java b/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/transformer/MongoSelectionsUpdatingTransformation.java index ea38a3a1..de87e266 100644 --- a/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/transformer/MongoSelectionsUpdatingTransformation.java +++ b/document-store/src/main/java/org/hypertrace/core/documentstore/mongo/query/transformer/MongoSelectionsUpdatingTransformation.java @@ -17,6 +17,7 @@ import org.hypertrace.core.documentstore.expression.impl.AggregateExpression; import org.hypertrace.core.documentstore.expression.impl.AliasedIdentifierExpression; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression; +import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DateConstantExpression; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DocumentConstantExpression; import org.hypertrace.core.documentstore.expression.impl.FunctionExpression; import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression; @@ -113,6 +114,12 @@ public SelectionSpec visit(final DocumentConstantExpression expression) { return source; } + @SuppressWarnings("unchecked") + @Override + public SelectionSpec visit(final DateConstantExpression expression) { + return source; + } + @SuppressWarnings("unchecked") @Override public SelectionSpec visit(final FunctionExpression expression) { diff --git a/document-store/src/main/java/org/hypertrace/core/documentstore/parser/SelectTypeExpressionVisitor.java b/document-store/src/main/java/org/hypertrace/core/documentstore/parser/SelectTypeExpressionVisitor.java index d90fc64b..701b5d70 100644 --- a/document-store/src/main/java/org/hypertrace/core/documentstore/parser/SelectTypeExpressionVisitor.java +++ b/document-store/src/main/java/org/hypertrace/core/documentstore/parser/SelectTypeExpressionVisitor.java @@ -4,6 +4,7 @@ import org.hypertrace.core.documentstore.expression.impl.AliasedIdentifierExpression; import org.hypertrace.core.documentstore.expression.impl.ArrayIdentifierExpression; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression; +import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DateConstantExpression; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DocumentConstantExpression; import org.hypertrace.core.documentstore.expression.impl.FunctionExpression; import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression; @@ -37,4 +38,12 @@ default T visit(final ArrayIdentifierExpression expression) { default T visit(final JsonIdentifierExpression expression) { return visit((IdentifierExpression) expression); } + + /** + * Visit a DateConstantExpression. Default implementation throws UnsupportedOperationException. + * Override this method in implementations that support DateConstantExpression. + */ + default T visit(final DateConstantExpression expression) { + throw new UnsupportedOperationException("DateConstantExpression is not supported"); + } } diff --git a/document-store/src/main/java/org/hypertrace/core/documentstore/postgres/query/v1/vistors/PostgresConstantExpressionVisitor.java b/document-store/src/main/java/org/hypertrace/core/documentstore/postgres/query/v1/vistors/PostgresConstantExpressionVisitor.java index 71e8faad..319b12e0 100644 --- a/document-store/src/main/java/org/hypertrace/core/documentstore/postgres/query/v1/vistors/PostgresConstantExpressionVisitor.java +++ b/document-store/src/main/java/org/hypertrace/core/documentstore/postgres/query/v1/vistors/PostgresConstantExpressionVisitor.java @@ -2,6 +2,7 @@ import lombok.NoArgsConstructor; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression; +import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DateConstantExpression; import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DocumentConstantExpression; import org.hypertrace.core.documentstore.postgres.query.v1.PostgresQueryParser; @@ -30,4 +31,9 @@ public Object visit(final ConstantExpression expression) { public Object visit(final DocumentConstantExpression expression) { return expression.getValue(); } + + @Override + public Object visit(final DateConstantExpression expression) { + throw new UnsupportedOperationException("DateConstantExpression is not supported for Postgres"); + } }