Skip to content

Commit e1a3671

Browse files
committed
Add UTs for coverage
1 parent 6911569 commit e1a3671

File tree

2 files changed

+318
-0
lines changed

2 files changed

+318
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package org.hypertrace.core.documentstore.postgres.query.v1.parser.filter;
2+
3+
import static org.hypertrace.core.documentstore.expression.operators.RelationalOperator.EXISTS;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
import static org.mockito.ArgumentMatchers.any;
6+
import static org.mockito.Mockito.mock;
7+
import static org.mockito.Mockito.when;
8+
9+
import org.hypertrace.core.documentstore.expression.impl.ArrayIdentifierExpression;
10+
import org.hypertrace.core.documentstore.expression.impl.ArrayType;
11+
import org.hypertrace.core.documentstore.expression.impl.ConstantExpression;
12+
import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression;
13+
import org.hypertrace.core.documentstore.expression.impl.JsonFieldType;
14+
import org.hypertrace.core.documentstore.expression.impl.JsonIdentifierExpression;
15+
import org.hypertrace.core.documentstore.expression.impl.RelationalExpression;
16+
import org.hypertrace.core.documentstore.postgres.query.v1.parser.filter.PostgresRelationalFilterParser.PostgresRelationalFilterContext;
17+
import org.hypertrace.core.documentstore.postgres.query.v1.vistors.PostgresSelectTypeExpressionVisitor;
18+
import org.junit.jupiter.api.BeforeEach;
19+
import org.junit.jupiter.api.Test;
20+
21+
class PostgresExistsRelationalFilterParserTest {
22+
23+
private PostgresExistsRelationalFilterParser parser;
24+
private PostgresRelationalFilterContext context;
25+
private PostgresSelectTypeExpressionVisitor lhsParser;
26+
27+
@BeforeEach
28+
void setUp() {
29+
parser = new PostgresExistsRelationalFilterParser();
30+
context = mock(PostgresRelationalFilterContext.class);
31+
lhsParser = mock(PostgresSelectTypeExpressionVisitor.class);
32+
when(context.lhsParser()).thenReturn(lhsParser);
33+
}
34+
35+
@Test
36+
void testParse_arrayField_rhsTrue() {
37+
// Test EXISTS on array with RHS = true
38+
ArrayIdentifierExpression lhs = ArrayIdentifierExpression.of("tags", ArrayType.TEXT);
39+
ConstantExpression rhs = ConstantExpression.of("null"); // Any non-false value
40+
RelationalExpression expression = RelationalExpression.of(lhs, EXISTS, rhs);
41+
42+
when(lhsParser.visit(any(ArrayIdentifierExpression.class))).thenReturn("\"tags\"");
43+
44+
String result = parser.parse(expression, context);
45+
46+
assertEquals(
47+
"(\"tags\" IS NOT NULL AND cardinality(\"tags\") > 0)",
48+
result,
49+
"EXISTS with RHS=true on ARRAY should check IS NOT NULL AND cardinality > 0");
50+
}
51+
52+
@Test
53+
void testParse_arrayField_rhsFalse() {
54+
// Test EXISTS on array with RHS = false
55+
ArrayIdentifierExpression lhs = ArrayIdentifierExpression.of("tags", ArrayType.TEXT);
56+
ConstantExpression rhs = ConstantExpression.of(false);
57+
RelationalExpression expression = RelationalExpression.of(lhs, EXISTS, rhs);
58+
59+
when(lhsParser.visit(any(ArrayIdentifierExpression.class))).thenReturn("\"tags\"");
60+
61+
String result = parser.parse(expression, context);
62+
63+
assertEquals(
64+
"(\"tags\" IS NULL OR cardinality(\"tags\") = 0)",
65+
result,
66+
"EXISTS with RHS=false on ARRAY should check IS NULL OR cardinality = 0");
67+
}
68+
69+
@Test
70+
void testParse_jsonbArrayField_rhsTrue() {
71+
// Test EXISTS on JSONB array with RHS = true
72+
JsonIdentifierExpression lhs =
73+
JsonIdentifierExpression.of("props", JsonFieldType.STRING_ARRAY, "colors");
74+
ConstantExpression rhs = ConstantExpression.of("null");
75+
RelationalExpression expression = RelationalExpression.of(lhs, EXISTS, rhs);
76+
77+
when(lhsParser.visit(any(JsonIdentifierExpression.class)))
78+
.thenReturn("document->'props'->'colors'");
79+
80+
String result = parser.parse(expression, context);
81+
82+
assertEquals(
83+
"(document->'props'->'colors' IS NOT NULL AND jsonb_typeof(document->'props'->'colors') = 'array' AND jsonb_array_length(document->'props'->'colors') > 0)",
84+
result,
85+
"EXISTS with RHS=true on JSONB_ARRAY should check IS NOT NULL AND typeof = 'array' AND length > 0");
86+
}
87+
88+
@Test
89+
void testParse_jsonbArrayField_rhsFalse() {
90+
// Test EXISTS on JSONB array with RHS = false
91+
JsonIdentifierExpression lhs =
92+
JsonIdentifierExpression.of("props", JsonFieldType.NUMBER_ARRAY, "scores");
93+
ConstantExpression rhs = ConstantExpression.of(false);
94+
RelationalExpression expression = RelationalExpression.of(lhs, EXISTS, rhs);
95+
96+
when(lhsParser.visit(any(JsonIdentifierExpression.class)))
97+
.thenReturn("document->'props'->'scores'");
98+
99+
String result = parser.parse(expression, context);
100+
101+
assertEquals(
102+
"(document->'props'->'scores' IS NULL OR (jsonb_typeof(document->'props'->'scores') = 'array' AND jsonb_array_length(document->'props'->'scores') = 0))",
103+
result,
104+
"EXISTS with RHS=false on JSONB_ARRAY should check IS NULL OR (typeof = 'array' AND length = 0)");
105+
}
106+
107+
@Test
108+
void testParse_scalarField_rhsTrue() {
109+
// Test EXISTS on scalar field with RHS = true
110+
IdentifierExpression lhs = IdentifierExpression.of("item");
111+
ConstantExpression rhs = ConstantExpression.of("null");
112+
RelationalExpression expression = RelationalExpression.of(lhs, EXISTS, rhs);
113+
114+
when(lhsParser.visit(any(IdentifierExpression.class))).thenReturn("document->>'item'");
115+
116+
String result = parser.parse(expression, context);
117+
118+
assertEquals(
119+
"document->>'item' IS NOT NULL",
120+
result,
121+
"EXISTS with RHS=true on SCALAR should check IS NOT NULL");
122+
}
123+
124+
@Test
125+
void testParse_scalarField_rhsFalse() {
126+
// Test EXISTS on scalar field with RHS = false
127+
IdentifierExpression lhs = IdentifierExpression.of("item");
128+
ConstantExpression rhs = ConstantExpression.of(false);
129+
RelationalExpression expression = RelationalExpression.of(lhs, EXISTS, rhs);
130+
131+
when(lhsParser.visit(any(IdentifierExpression.class))).thenReturn("document->>'item'");
132+
133+
String result = parser.parse(expression, context);
134+
135+
assertEquals(
136+
"document->>'item' IS NULL",
137+
result,
138+
"EXISTS with RHS=false on SCALAR should check IS NULL");
139+
}
140+
141+
@Test
142+
void testParse_jsonScalarField_rhsTrue() {
143+
// Test EXISTS on JSON scalar (non-array) field with RHS = true
144+
JsonIdentifierExpression lhs =
145+
JsonIdentifierExpression.of("props", JsonFieldType.STRING, "brand");
146+
ConstantExpression rhs = ConstantExpression.of("null");
147+
RelationalExpression expression = RelationalExpression.of(lhs, EXISTS, rhs);
148+
149+
when(lhsParser.visit(any(JsonIdentifierExpression.class)))
150+
.thenReturn("document->'props'->>'brand'");
151+
152+
String result = parser.parse(expression, context);
153+
154+
assertEquals(
155+
"document->'props'->>'brand' IS NOT NULL",
156+
result,
157+
"EXISTS with RHS=true on JSON scalar should check IS NOT NULL");
158+
}
159+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package org.hypertrace.core.documentstore.postgres.query.v1.parser.filter;
2+
3+
import static org.hypertrace.core.documentstore.expression.operators.RelationalOperator.NOT_EXISTS;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
import static org.mockito.ArgumentMatchers.any;
6+
import static org.mockito.Mockito.mock;
7+
import static org.mockito.Mockito.when;
8+
9+
import org.hypertrace.core.documentstore.expression.impl.ArrayIdentifierExpression;
10+
import org.hypertrace.core.documentstore.expression.impl.ArrayType;
11+
import org.hypertrace.core.documentstore.expression.impl.ConstantExpression;
12+
import org.hypertrace.core.documentstore.expression.impl.IdentifierExpression;
13+
import org.hypertrace.core.documentstore.expression.impl.JsonFieldType;
14+
import org.hypertrace.core.documentstore.expression.impl.JsonIdentifierExpression;
15+
import org.hypertrace.core.documentstore.expression.impl.RelationalExpression;
16+
import org.hypertrace.core.documentstore.postgres.query.v1.parser.filter.PostgresRelationalFilterParser.PostgresRelationalFilterContext;
17+
import org.hypertrace.core.documentstore.postgres.query.v1.vistors.PostgresSelectTypeExpressionVisitor;
18+
import org.junit.jupiter.api.BeforeEach;
19+
import org.junit.jupiter.api.Test;
20+
21+
class PostgresNotExistsRelationalFilterParserTest {
22+
23+
private PostgresNotExistsRelationalFilterParser parser;
24+
private PostgresRelationalFilterContext context;
25+
private PostgresSelectTypeExpressionVisitor lhsParser;
26+
27+
@BeforeEach
28+
void setUp() {
29+
parser = new PostgresNotExistsRelationalFilterParser();
30+
context = mock(PostgresRelationalFilterContext.class);
31+
lhsParser = mock(PostgresSelectTypeExpressionVisitor.class);
32+
when(context.lhsParser()).thenReturn(lhsParser);
33+
}
34+
35+
@Test
36+
void testParse_arrayField_rhsFalse() {
37+
// Test NOT_EXISTS on array with RHS = false (means NOT_EXISTS should be true)
38+
ArrayIdentifierExpression lhs = ArrayIdentifierExpression.of("tags", ArrayType.TEXT);
39+
ConstantExpression rhs = ConstantExpression.of(false);
40+
RelationalExpression expression = RelationalExpression.of(lhs, NOT_EXISTS, rhs);
41+
42+
when(lhsParser.visit(any(ArrayIdentifierExpression.class))).thenReturn("\"tags\"");
43+
44+
String result = parser.parse(expression, context);
45+
46+
assertEquals(
47+
"(\"tags\" IS NOT NULL AND cardinality(\"tags\") > 0)",
48+
result,
49+
"NOT_EXISTS with RHS=false on ARRAY should check IS NOT NULL AND cardinality > 0");
50+
}
51+
52+
@Test
53+
void testParse_arrayField_rhsTrue() {
54+
// Test NOT_EXISTS on array with RHS = true (means NOT_EXISTS should be false)
55+
ArrayIdentifierExpression lhs = ArrayIdentifierExpression.of("tags", ArrayType.TEXT);
56+
ConstantExpression rhs = ConstantExpression.of("null"); // Any non-false value
57+
RelationalExpression expression = RelationalExpression.of(lhs, NOT_EXISTS, rhs);
58+
59+
when(lhsParser.visit(any(ArrayIdentifierExpression.class))).thenReturn("\"tags\"");
60+
61+
String result = parser.parse(expression, context);
62+
63+
assertEquals(
64+
"(\"tags\" IS NULL OR cardinality(\"tags\") = 0)",
65+
result,
66+
"NOT_EXISTS with RHS=true on ARRAY should check IS NULL OR cardinality = 0");
67+
}
68+
69+
@Test
70+
void testParse_jsonbArrayField_rhsFalse() {
71+
// Test NOT_EXISTS on JSONB array with RHS = false
72+
JsonIdentifierExpression lhs =
73+
JsonIdentifierExpression.of("props", JsonFieldType.STRING_ARRAY, "colors");
74+
ConstantExpression rhs = ConstantExpression.of(false);
75+
RelationalExpression expression = RelationalExpression.of(lhs, NOT_EXISTS, rhs);
76+
77+
when(lhsParser.visit(any(JsonIdentifierExpression.class)))
78+
.thenReturn("document->'props'->'colors'");
79+
80+
String result = parser.parse(expression, context);
81+
82+
assertEquals(
83+
"(document->'props'->'colors' IS NOT NULL AND jsonb_typeof(document->'props'->'colors') = 'array' AND jsonb_array_length(document->'props'->'colors') > 0)",
84+
result,
85+
"NOT_EXISTS with RHS=false on JSONB_ARRAY should check IS NOT NULL AND typeof = 'array' AND length > 0");
86+
}
87+
88+
@Test
89+
void testParse_jsonbArrayField_rhsTrue() {
90+
// Test NOT_EXISTS on JSONB array with RHS = true
91+
JsonIdentifierExpression lhs =
92+
JsonIdentifierExpression.of("props", JsonFieldType.BOOLEAN_ARRAY, "flags");
93+
ConstantExpression rhs = ConstantExpression.of("null");
94+
RelationalExpression expression = RelationalExpression.of(lhs, NOT_EXISTS, rhs);
95+
96+
when(lhsParser.visit(any(JsonIdentifierExpression.class)))
97+
.thenReturn("document->'props'->'flags'");
98+
99+
String result = parser.parse(expression, context);
100+
101+
assertEquals(
102+
"(document->'props'->'flags' IS NULL OR (jsonb_typeof(document->'props'->'flags') = 'array' AND jsonb_array_length(document->'props'->'flags') = 0))",
103+
result,
104+
"NOT_EXISTS with RHS=true on JSONB_ARRAY should check IS NULL OR (typeof = 'array' AND length = 0)");
105+
}
106+
107+
@Test
108+
void testParse_scalarField_rhsFalse() {
109+
// Test NOT_EXISTS on scalar field with RHS = false
110+
IdentifierExpression lhs = IdentifierExpression.of("item");
111+
ConstantExpression rhs = ConstantExpression.of(false);
112+
RelationalExpression expression = RelationalExpression.of(lhs, NOT_EXISTS, rhs);
113+
114+
when(lhsParser.visit(any(IdentifierExpression.class))).thenReturn("document->>'item'");
115+
116+
String result = parser.parse(expression, context);
117+
118+
assertEquals(
119+
"document->>'item' IS NOT NULL",
120+
result,
121+
"NOT_EXISTS with RHS=false on SCALAR should check IS NOT NULL");
122+
}
123+
124+
@Test
125+
void testParse_scalarField_rhsTrue() {
126+
// Test NOT_EXISTS on scalar field with RHS = true
127+
IdentifierExpression lhs = IdentifierExpression.of("item");
128+
ConstantExpression rhs = ConstantExpression.of("null");
129+
RelationalExpression expression = RelationalExpression.of(lhs, NOT_EXISTS, rhs);
130+
131+
when(lhsParser.visit(any(IdentifierExpression.class))).thenReturn("document->>'item'");
132+
133+
String result = parser.parse(expression, context);
134+
135+
assertEquals(
136+
"document->>'item' IS NULL",
137+
result,
138+
"NOT_EXISTS with RHS=true on SCALAR should check IS NULL");
139+
}
140+
141+
@Test
142+
void testParse_jsonScalarField_rhsFalse() {
143+
// Test NOT_EXISTS on JSON scalar (non-array) field with RHS = false
144+
JsonIdentifierExpression lhs =
145+
JsonIdentifierExpression.of("props", JsonFieldType.STRING, "brand");
146+
ConstantExpression rhs = ConstantExpression.of(false);
147+
RelationalExpression expression = RelationalExpression.of(lhs, NOT_EXISTS, rhs);
148+
149+
when(lhsParser.visit(any(JsonIdentifierExpression.class)))
150+
.thenReturn("document->'props'->>'brand'");
151+
152+
String result = parser.parse(expression, context);
153+
154+
assertEquals(
155+
"document->'props'->>'brand' IS NOT NULL",
156+
result,
157+
"NOT_EXISTS with RHS=false on JSON scalar should check IS NOT NULL");
158+
}
159+
}

0 commit comments

Comments
 (0)