Skip to content

Commit 6bbf5b1

Browse files
committed
Merge branch 'main' of github.com:hypertrace/document-store into handle_array_exists_flat_collections
2 parents ce28574 + c7bb6ad commit 6bbf5b1

23 files changed

+1419
-392
lines changed

document-store/src/integrationTest/java/org/hypertrace/core/documentstore/DocStoreQueryV1Test.java

Lines changed: 248 additions & 29 deletions
Large diffs are not rendered by default.

document-store/src/main/java/org/hypertrace/core/documentstore/expression/impl/ArrayIdentifierExpression.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.hypertrace.core.documentstore.expression.impl;
22

3+
import java.util.Optional;
34
import lombok.EqualsAndHashCode;
5+
import org.hypertrace.core.documentstore.parser.SelectTypeExpressionVisitor;
46

57
/**
68
* Represents an identifier expression for array-typed fields. This allows parsers to apply
@@ -12,11 +14,36 @@
1214
@EqualsAndHashCode(callSuper = true)
1315
public class ArrayIdentifierExpression extends IdentifierExpression {
1416

17+
private final ArrayType arrayType;
18+
1519
public ArrayIdentifierExpression(String name) {
20+
this(name, null);
21+
}
22+
23+
public ArrayIdentifierExpression(String name, ArrayType arrayType) {
1624
super(name);
25+
this.arrayType = arrayType;
1726
}
1827

1928
public static ArrayIdentifierExpression of(String name) {
2029
return new ArrayIdentifierExpression(name);
2130
}
31+
32+
public static ArrayIdentifierExpression of(String name, ArrayType arrayType) {
33+
return new ArrayIdentifierExpression(name, arrayType);
34+
}
35+
36+
/** Returns the array type if specified, empty otherwise */
37+
public Optional<ArrayType> getArrayType() {
38+
return Optional.ofNullable(arrayType);
39+
}
40+
41+
/**
42+
* Accepts a SelectTypeExpressionVisitor and dispatches to the ArrayIdentifierExpression-specific
43+
* visit method.
44+
*/
45+
@Override
46+
public <T> T accept(final SelectTypeExpressionVisitor visitor) {
47+
return visitor.visit(this);
48+
}
2249
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.hypertrace.core.documentstore.expression.impl;
2+
3+
import lombok.Getter;
4+
5+
public enum ArrayType {
6+
TEXT("text[]"),
7+
INTEGER("integer[]"),
8+
BOOLEAN("boolean[]"),
9+
DOUBLE_PRECISION("double precision[]");
10+
11+
@Getter private final String postgresType;
12+
13+
ArrayType(String postgresType) {
14+
this.postgresType = postgresType;
15+
}
16+
}

document-store/src/main/java/org/hypertrace/core/documentstore/expression/impl/JsonArrayIdentifierExpression.java

Lines changed: 0 additions & 50 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.hypertrace.core.documentstore.expression.impl;
2+
3+
/** Represents the type of JSON fields in flat collections */
4+
public enum JsonFieldType {
5+
STRING,
6+
NUMBER,
7+
BOOLEAN,
8+
STRING_ARRAY,
9+
NUMBER_ARRAY,
10+
BOOLEAN_ARRAY,
11+
OBJECT_ARRAY,
12+
OBJECT
13+
}

document-store/src/main/java/org/hypertrace/core/documentstore/expression/impl/JsonIdentifierExpression.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
package org.hypertrace.core.documentstore.expression.impl;
22

33
import java.util.List;
4+
import java.util.Optional;
45
import lombok.EqualsAndHashCode;
56
import lombok.Getter;
67
import org.hypertrace.core.documentstore.parser.FieldTransformationVisitor;
8+
import org.hypertrace.core.documentstore.parser.SelectTypeExpressionVisitor;
79
import org.hypertrace.core.documentstore.postgres.utils.BasicPostgresSecurityValidator;
810

911
/**
@@ -19,6 +21,7 @@ public class JsonIdentifierExpression extends IdentifierExpression {
1921

2022
String columnName; // e.g., "customAttr" (the top-level JSONB column)
2123
List<String> jsonPath; // e.g., ["myAttribute", "nestedField"]
24+
JsonFieldType fieldType; // Optional: PRIMITIVE or ARRAY for optimization
2225

2326
public static JsonIdentifierExpression of(final String columnName) {
2427
throw new IllegalArgumentException(
@@ -33,7 +36,20 @@ public static JsonIdentifierExpression of(final String columnName, final String.
3336
return of(columnName, List.of(pathElements));
3437
}
3538

39+
public static JsonIdentifierExpression of(
40+
final String columnName, final JsonFieldType fieldType, final String... pathElements) {
41+
if (pathElements == null || pathElements.length == 0) {
42+
throw new IllegalArgumentException("JSON path cannot be null or empty");
43+
}
44+
return of(columnName, fieldType, List.of(pathElements));
45+
}
46+
3647
public static JsonIdentifierExpression of(final String columnName, final List<String> jsonPath) {
48+
return of(columnName, null, jsonPath);
49+
}
50+
51+
public static JsonIdentifierExpression of(
52+
final String columnName, final JsonFieldType fieldType, final List<String> jsonPath) {
3753
BasicPostgresSecurityValidator.getDefault().validateIdentifier(columnName);
3854

3955
if (jsonPath == null || jsonPath.isEmpty()) {
@@ -46,13 +62,20 @@ public static JsonIdentifierExpression of(final String columnName, final List<St
4662

4763
// Construct full name for compatibility: "customAttr.myAttribute"
4864
String fullName = columnName + "." + String.join(".", unmodifiablePath);
49-
return new JsonIdentifierExpression(fullName, columnName, unmodifiablePath);
65+
return new JsonIdentifierExpression(fullName, columnName, unmodifiablePath, fieldType);
5066
}
5167

52-
protected JsonIdentifierExpression(String name, String columnName, List<String> jsonPath) {
68+
protected JsonIdentifierExpression(
69+
String name, String columnName, List<String> jsonPath, JsonFieldType fieldType) {
5370
super(name);
5471
this.columnName = columnName;
5572
this.jsonPath = jsonPath;
73+
this.fieldType = fieldType;
74+
}
75+
76+
/** Returns the JSON field type if specified, empty otherwise */
77+
public Optional<JsonFieldType> getFieldType() {
78+
return Optional.ofNullable(fieldType);
5679
}
5780

5881
/**
@@ -68,6 +91,15 @@ public <T> T accept(final FieldTransformationVisitor<T> visitor) {
6891
return visitor.visit(this);
6992
}
7093

94+
/**
95+
* Accepts a SelectTypeExpressionVisitor and dispatches to the JsonIdentifierExpression-specific
96+
* visit method.
97+
*/
98+
@Override
99+
public <T> T accept(final SelectTypeExpressionVisitor visitor) {
100+
return visitor.visit(this);
101+
}
102+
71103
@Override
72104
public String toString() {
73105
return String.format(

document-store/src/main/java/org/hypertrace/core/documentstore/parser/SelectTypeExpressionVisitor.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
import org.hypertrace.core.documentstore.expression.impl.AggregateExpression;
44
import org.hypertrace.core.documentstore.expression.impl.AliasedIdentifierExpression;
5+
import org.hypertrace.core.documentstore.expression.impl.ArrayIdentifierExpression;
56
import org.hypertrace.core.documentstore.expression.impl.ConstantExpression;
67
import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DocumentConstantExpression;
78
import org.hypertrace.core.documentstore.expression.impl.FunctionExpression;
89
import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression;
10+
import org.hypertrace.core.documentstore.expression.impl.JsonIdentifierExpression;
911

1012
public interface SelectTypeExpressionVisitor {
1113
<T> T visit(final AggregateExpression expression);
@@ -19,4 +21,20 @@ public interface SelectTypeExpressionVisitor {
1921
<T> T visit(final IdentifierExpression expression);
2022

2123
<T> T visit(final AliasedIdentifierExpression expression);
24+
25+
/**
26+
* Visit an ArrayIdentifierExpression. Default implementation delegates to
27+
* visit(IdentifierExpression) since ArrayIdentifierExpression extends IdentifierExpression.
28+
*/
29+
default <T> T visit(final ArrayIdentifierExpression expression) {
30+
return visit((IdentifierExpression) expression);
31+
}
32+
33+
/**
34+
* Visit a JsonIdentifierExpression. Default implementation delegates to
35+
* visit(IdentifierExpression) since JsonIdentifierExpression extends IdentifierExpression.
36+
*/
37+
default <T> T visit(final JsonIdentifierExpression expression) {
38+
return visit((IdentifierExpression) expression);
39+
}
2240
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package org.hypertrace.core.documentstore.postgres.query.v1.parser.filter;
2+
3+
import org.hypertrace.core.documentstore.expression.impl.AggregateExpression;
4+
import org.hypertrace.core.documentstore.expression.impl.AliasedIdentifierExpression;
5+
import org.hypertrace.core.documentstore.expression.impl.ArrayIdentifierExpression;
6+
import org.hypertrace.core.documentstore.expression.impl.ConstantExpression;
7+
import org.hypertrace.core.documentstore.expression.impl.ConstantExpression.DocumentConstantExpression;
8+
import org.hypertrace.core.documentstore.expression.impl.FunctionExpression;
9+
import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression;
10+
import org.hypertrace.core.documentstore.expression.impl.JsonIdentifierExpression;
11+
import org.hypertrace.core.documentstore.parser.SelectTypeExpressionVisitor;
12+
import org.hypertrace.core.documentstore.postgres.query.v1.parser.filter.nonjson.field.PostgresContainsRelationalFilterParserNonJsonField;
13+
14+
class PostgresContainsParserSelector implements SelectTypeExpressionVisitor {
15+
16+
private static final PostgresContainsRelationalFilterParserInterface jsonFieldContainsParser =
17+
new PostgresContainsRelationalFilterParser();
18+
private static final PostgresContainsRelationalFilterParserInterface nonJsonFieldContainsParser =
19+
new PostgresContainsRelationalFilterParserNonJsonField();
20+
21+
private final boolean isFlatCollection;
22+
23+
PostgresContainsParserSelector(boolean isFlatCollection) {
24+
this.isFlatCollection = isFlatCollection;
25+
}
26+
27+
@Override
28+
public PostgresRelationalFilterParser visit(JsonIdentifierExpression expression) {
29+
return jsonFieldContainsParser;
30+
}
31+
32+
@Override
33+
public PostgresRelationalFilterParser visit(ArrayIdentifierExpression expression) {
34+
return isFlatCollection ? nonJsonFieldContainsParser : jsonFieldContainsParser;
35+
}
36+
37+
@Override
38+
public PostgresRelationalFilterParser visit(IdentifierExpression expression) {
39+
return isFlatCollection ? nonJsonFieldContainsParser : jsonFieldContainsParser;
40+
}
41+
42+
@Override
43+
public PostgresRelationalFilterParser visit(AggregateExpression expression) {
44+
return isFlatCollection ? nonJsonFieldContainsParser : jsonFieldContainsParser;
45+
}
46+
47+
@Override
48+
public PostgresRelationalFilterParser visit(ConstantExpression expression) {
49+
return isFlatCollection ? nonJsonFieldContainsParser : jsonFieldContainsParser;
50+
}
51+
52+
@Override
53+
public PostgresRelationalFilterParser visit(DocumentConstantExpression expression) {
54+
return isFlatCollection ? nonJsonFieldContainsParser : jsonFieldContainsParser;
55+
}
56+
57+
@Override
58+
public PostgresRelationalFilterParser visit(FunctionExpression expression) {
59+
return isFlatCollection ? nonJsonFieldContainsParser : jsonFieldContainsParser;
60+
}
61+
62+
@Override
63+
public PostgresRelationalFilterParser visit(AliasedIdentifierExpression expression) {
64+
return isFlatCollection ? nonJsonFieldContainsParser : jsonFieldContainsParser;
65+
}
66+
}

0 commit comments

Comments
 (0)