Skip to content

Commit cdeff0c

Browse files
committed
test(api): Add SQL planner tests and refactor test base for multi-language support
- Refactor UnifiedQueryTestBase with queryType() hook for subclass override - Add UnifiedSqlQueryPlannerTest covering SELECT, WHERE, GROUP BY, JOIN, ORDER BY, subquery, case sensitivity, namespaces, and error handling - Update UnifiedQueryContextTest to verify SQL context creation Signed-off-by: Chen Dai <daichen@amazon.com>
1 parent e7f97d6 commit cdeff0c

3 files changed

Lines changed: 152 additions & 9 deletions

File tree

api/src/test/java/org/opensearch/sql/api/UnifiedQueryContextTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,15 @@ public void testMissingQueryType() {
6363
UnifiedQueryContext.builder().catalog("opensearch", testSchema).build();
6464
}
6565

66-
@Test(expected = IllegalArgumentException.class)
67-
public void testUnsupportedQueryType() {
66+
@Test
67+
public void testSqlQueryType() {
6868
UnifiedQueryContext context =
6969
UnifiedQueryContext.builder()
70-
.language(QueryType.SQL) // only PPL is supported for now
70+
.language(QueryType.SQL)
7171
.catalog("opensearch", testSchema)
7272
.build();
73-
new UnifiedQueryPlanner(context);
73+
UnifiedQueryPlanner planner = new UnifiedQueryPlanner(context);
74+
assertNotNull("SQL planner should be created", planner);
7475
}
7576

7677
@Test(expected = IllegalArgumentException.class)
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.opensearch.sql.api;
7+
8+
import static org.junit.Assert.assertNotNull;
9+
import static org.junit.Assert.assertThrows;
10+
11+
import java.util.Map;
12+
import org.apache.calcite.rel.RelNode;
13+
import org.apache.calcite.schema.Schema;
14+
import org.apache.calcite.schema.impl.AbstractSchema;
15+
import org.junit.Test;
16+
import org.opensearch.sql.executor.QueryType;
17+
18+
public class UnifiedSqlQueryPlannerTest extends UnifiedQueryTestBase {
19+
20+
@Override
21+
protected QueryType queryType() {
22+
return QueryType.SQL;
23+
}
24+
25+
@Test
26+
public void testSelectAll() {
27+
RelNode plan = planner.plan("SELECT * FROM catalog.employees");
28+
assertNotNull("Plan should be created", plan);
29+
}
30+
31+
@Test
32+
public void testSelectWithFilter() {
33+
RelNode plan = planner.plan("SELECT * FROM catalog.employees WHERE age > 30");
34+
assertNotNull("Plan should be created", plan);
35+
}
36+
37+
@Test
38+
public void testSelectWithAggregation() {
39+
RelNode plan =
40+
planner.plan("SELECT department, count(*) FROM catalog.employees GROUP BY department");
41+
assertNotNull("Plan should be created", plan);
42+
}
43+
44+
@Test
45+
public void testSelectWithJoin() {
46+
RelNode plan =
47+
planner.plan(
48+
"SELECT a.id, b.name FROM catalog.employees a"
49+
+ " JOIN catalog.employees b ON a.id = b.age");
50+
assertNotNull("Plan should be created", plan);
51+
}
52+
53+
@Test
54+
public void testSelectWithOrderBy() {
55+
RelNode plan = planner.plan("SELECT * FROM catalog.employees ORDER BY age DESC");
56+
assertNotNull("Plan should be created", plan);
57+
}
58+
59+
@Test
60+
public void testSelectWithSubquery() {
61+
RelNode plan =
62+
planner.plan(
63+
"SELECT * FROM catalog.employees WHERE age > (SELECT avg(age) FROM catalog.employees)");
64+
assertNotNull("Plan should be created", plan);
65+
}
66+
67+
@Test
68+
public void testCaseInsensitiveIdentifiers() {
69+
// Verify Casing.UNCHANGED: lowercase table/column names resolve correctly
70+
RelNode plan = planner.plan("SELECT id, name FROM catalog.employees WHERE age > 30");
71+
assertNotNull("Plan should be created with lowercase identifiers", plan);
72+
}
73+
74+
@Test
75+
public void testDefaultNamespace() {
76+
UnifiedQueryContext sqlContext =
77+
UnifiedQueryContext.builder()
78+
.language(QueryType.SQL)
79+
.catalog("catalog", testSchema)
80+
.defaultNamespace("catalog")
81+
.build();
82+
UnifiedQueryPlanner sqlPlanner = new UnifiedQueryPlanner(sqlContext);
83+
84+
assertNotNull(
85+
"Plan should resolve unqualified table", sqlPlanner.plan("SELECT * FROM employees"));
86+
}
87+
88+
@Test
89+
public void testMultipleCatalogs() {
90+
UnifiedQueryContext sqlContext =
91+
UnifiedQueryContext.builder()
92+
.language(QueryType.SQL)
93+
.catalog("catalog1", testSchema)
94+
.catalog("catalog2", testSchema)
95+
.build();
96+
UnifiedQueryPlanner sqlPlanner = new UnifiedQueryPlanner(sqlContext);
97+
98+
RelNode plan =
99+
sqlPlanner.plan(
100+
"SELECT a.id FROM catalog1.employees a" + " JOIN catalog2.employees b ON a.id = b.id");
101+
assertNotNull("Plan should be created with multiple catalogs", plan);
102+
}
103+
104+
@Test
105+
public void testDefaultNamespaceMultiLevel() {
106+
AbstractSchema deepSchema =
107+
new AbstractSchema() {
108+
@Override
109+
protected Map<String, Schema> getSubSchemaMap() {
110+
return Map.of("opensearch", testSchema);
111+
}
112+
};
113+
UnifiedQueryContext sqlContext =
114+
UnifiedQueryContext.builder()
115+
.language(QueryType.SQL)
116+
.catalog("catalog", deepSchema)
117+
.defaultNamespace("catalog.opensearch")
118+
.build();
119+
UnifiedQueryPlanner sqlPlanner = new UnifiedQueryPlanner(sqlContext);
120+
121+
assertNotNull(
122+
"Plan should resolve with multi-level default namespace",
123+
sqlPlanner.plan("SELECT * FROM employees"));
124+
}
125+
126+
@Test
127+
public void testInvalidSqlThrowsException() {
128+
assertThrows(IllegalStateException.class, () -> planner.plan("SELECT FROM"));
129+
}
130+
}

api/src/testFixtures/java/org/opensearch/sql/api/UnifiedQueryTestBase.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,26 @@ protected Map<String, Table> getTableMap() {
5555
}
5656
};
5757

58-
context =
59-
UnifiedQueryContext.builder()
60-
.language(QueryType.PPL)
61-
.catalog(DEFAULT_CATALOG, testSchema)
62-
.build();
58+
context = buildContext(queryType());
6359
planner = new UnifiedQueryPlanner(context);
6460
}
6561

62+
/**
63+
* Returns the query type for this test class. Subclasses override to test different languages.
64+
* Defaults to PPL for backward compatibility.
65+
*/
66+
protected QueryType queryType() {
67+
return QueryType.PPL;
68+
}
69+
70+
/** Builds a UnifiedQueryContext with the test schema for the given query type. */
71+
protected UnifiedQueryContext buildContext(QueryType queryType) {
72+
return UnifiedQueryContext.builder()
73+
.language(queryType)
74+
.catalog(DEFAULT_CATALOG, testSchema)
75+
.build();
76+
}
77+
6678
@After
6779
public void tearDown() throws Exception {
6880
if (context != null) {

0 commit comments

Comments
 (0)