1use {
2 super::{
3 DistinctNode, ExprList, FilterNode, GroupByNode, HavingNode, InnerHashJoinNode,
4 InnerJoinConditionNode, InnerNestedLoopJoinNode, LeftOuterHashJoinNode,
5 LeftOuterJoinConditionNode, LeftOuterNestedLoopJoinNode, LimitNode, OffsetLimitNode,
6 OffsetNode, ProjectNode, SelectNode, SelectOrderByNode, SourceNode, ValuesOrderByNode,
7 select::{BuildQuery, BuildQueryPlan, ValuesNode},
8 },
9 crate::{
10 ast::{Query, SetExpr, Values},
11 parse_sql::parse_query,
12 plan::{QueryPlan, ValuesPlan},
13 result::Result,
14 translate::{NO_PARAMS, translate_query},
15 },
16};
17
18#[derive(Clone, Debug)]
19pub enum QueryNode<'a> {
20 Text(String),
21 Values(Vec<ExprList<'a>>),
22 SelectNode(SelectNode<'a>),
23 ValuesNode(ValuesNode<'a>),
24 InnerNestedLoopJoinNode(InnerNestedLoopJoinNode<'a>),
25 LeftOuterNestedLoopJoinNode(LeftOuterNestedLoopJoinNode<'a>),
26 InnerHashJoinNode(InnerHashJoinNode<'a>),
27 LeftOuterHashJoinNode(LeftOuterHashJoinNode<'a>),
28 InnerJoinConditionNode(InnerJoinConditionNode<'a>),
29 LeftOuterJoinConditionNode(LeftOuterJoinConditionNode<'a>),
30 GroupByNode(GroupByNode<'a>),
31 HavingNode(HavingNode<'a>),
32 LimitNode(LimitNode<'a>),
33 OffsetNode(OffsetNode<'a>),
34 OffsetLimitNode(OffsetLimitNode<'a>),
35 FilterNode(FilterNode<'a>),
36 ProjectNode(ProjectNode<'a>),
37 SelectOrderByNode(SelectOrderByNode<'a>),
38 ValuesOrderByNode(ValuesOrderByNode<'a>),
39 DistinctNode(DistinctNode<'a>),
40}
41
42impl<'a> QueryNode<'a> {
43 pub fn alias_as(self, table_alias: &'a str) -> SourceNode<'a> {
44 SourceNode::Derived {
45 query: Box::new(self),
46 alias: table_alias.to_owned(),
47 }
48 }
49
50 pub(super) fn build_query(self) -> Result<Query> {
51 match self {
52 QueryNode::Text(query_node) => {
53 parse_query(query_node).and_then(|item| translate_query(&item, NO_PARAMS))
54 }
55 QueryNode::Values(values) => {
56 let values = values
57 .into_iter()
58 .map(ExprList::build_exprs)
59 .collect::<Result<Vec<_>>>()?;
60
61 Ok(Query {
62 body: SetExpr::Values(Values(values)),
63 order_by: Vec::new(),
64 limit: None,
65 offset: None,
66 })
67 }
68 QueryNode::SelectNode(node) => node.build_query(),
69 QueryNode::ValuesNode(node) => node.build_query(),
70 QueryNode::InnerNestedLoopJoinNode(node) => node.build_query(),
71 QueryNode::LeftOuterNestedLoopJoinNode(node) => node.build_query(),
72 QueryNode::InnerHashJoinNode(node) => node.build_query(),
73 QueryNode::LeftOuterHashJoinNode(node) => node.build_query(),
74 QueryNode::InnerJoinConditionNode(node) => node.build_query(),
75 QueryNode::LeftOuterJoinConditionNode(node) => node.build_query(),
76 QueryNode::GroupByNode(node) => node.build_query(),
77 QueryNode::HavingNode(node) => node.build_query(),
78 QueryNode::FilterNode(node) => node.build_query(),
79 QueryNode::LimitNode(node) => node.build_query(),
80 QueryNode::OffsetNode(node) => node.build_query(),
81 QueryNode::OffsetLimitNode(node) => node.build_query(),
82 QueryNode::ProjectNode(node) => node.build_query(),
83 QueryNode::SelectOrderByNode(node) => node.build_query(),
84 QueryNode::ValuesOrderByNode(node) => node.build_query(),
85 QueryNode::DistinctNode(node) => node.build_query(),
86 }
87 }
88
89 pub(super) fn build_query_plan(self) -> Result<QueryPlan> {
90 match self {
91 QueryNode::Text(query_node) => parse_query(query_node)
92 .and_then(|item| translate_query(&item, NO_PARAMS).map(Into::into)),
93 QueryNode::Values(values) => {
94 let values = values
95 .into_iter()
96 .map(ExprList::build_exprs_plan)
97 .collect::<Result<Vec<_>>>()?;
98
99 Ok(QueryPlan::Values(ValuesPlan(values)))
100 }
101 QueryNode::SelectNode(node) => node.build_query_plan(),
102 QueryNode::ValuesNode(node) => node.build_query_plan(),
103 QueryNode::InnerNestedLoopJoinNode(node) => node.build_query_plan(),
104 QueryNode::LeftOuterNestedLoopJoinNode(node) => node.build_query_plan(),
105 QueryNode::InnerHashJoinNode(node) => node.build_query_plan(),
106 QueryNode::LeftOuterHashJoinNode(node) => node.build_query_plan(),
107 QueryNode::InnerJoinConditionNode(node) => node.build_query_plan(),
108 QueryNode::LeftOuterJoinConditionNode(node) => node.build_query_plan(),
109 QueryNode::GroupByNode(node) => node.build_query_plan(),
110 QueryNode::HavingNode(node) => node.build_query_plan(),
111 QueryNode::FilterNode(node) => node.build_query_plan(),
112 QueryNode::LimitNode(node) => node.build_query_plan(),
113 QueryNode::OffsetNode(node) => node.build_query_plan(),
114 QueryNode::OffsetLimitNode(node) => node.build_query_plan(),
115 QueryNode::ProjectNode(node) => node.build_query_plan(),
116 QueryNode::SelectOrderByNode(node) => node.build_query_plan(),
117 QueryNode::ValuesOrderByNode(node) => node.build_query_plan(),
118 QueryNode::DistinctNode(node) => node.build_query_plan(),
119 }
120 }
121}
122
123impl From<&str> for QueryNode<'_> {
124 fn from(query: &str) -> Self {
125 Self::Text(query.to_owned())
126 }
127}
128
129impl<'a> From<SelectNode<'a>> for QueryNode<'a> {
130 fn from(node: SelectNode<'a>) -> Self {
131 QueryNode::SelectNode(node)
132 }
133}
134
135macro_rules! impl_from_select_nodes {
136 ($type: ident) => {
137 impl<'a> From<$type<'a>> for QueryNode<'a> {
138 fn from(node: $type<'a>) -> Self {
139 QueryNode::$type(node)
140 }
141 }
142 };
143}
144
145impl_from_select_nodes!(InnerNestedLoopJoinNode);
146impl_from_select_nodes!(LeftOuterNestedLoopJoinNode);
147impl_from_select_nodes!(InnerHashJoinNode);
148impl_from_select_nodes!(LeftOuterHashJoinNode);
149impl_from_select_nodes!(InnerJoinConditionNode);
150impl_from_select_nodes!(LeftOuterJoinConditionNode);
151impl_from_select_nodes!(GroupByNode);
152impl_from_select_nodes!(HavingNode);
153impl_from_select_nodes!(FilterNode);
154impl_from_select_nodes!(LimitNode);
155impl_from_select_nodes!(OffsetNode);
156impl_from_select_nodes!(OffsetLimitNode);
157impl_from_select_nodes!(ProjectNode);
158impl_from_select_nodes!(SelectOrderByNode);
159impl_from_select_nodes!(ValuesOrderByNode);
160impl_from_select_nodes!(DistinctNode);
161
162#[cfg(test)]
163mod test {
164 use {
165 super::QueryNode,
166 crate::{
167 plan::{
168 HashJoinInputPlan, HashJoinPlan, InnerJoinInputPlan, InnerJoinPlan,
169 ProjectInputPlan, ProjectPlan, ProjectionPlan, QueryPlan, SourcePlan,
170 TableAccessPlan, TableSourcePlan,
171 },
172 query_builder::{
173 SelectItemList, col, glue_indexes, glue_objects, glue_table_columns, glue_tables,
174 series, table, test_query, test_query_builder, values,
175 },
176 },
177 pretty_assertions::assert_eq,
178 };
179
180 #[test]
181 fn query() {
182 let actual = QueryNode::Values(vec!["1, 'a'".into(), "2, 'b'".into()]);
183 let expected = "VALUES(1, 'a'), (2, 'b')";
184 test_query(actual, expected);
185
186 let actual = table("FOO").select().into();
187 let expected = "SELECT * FROM FOO";
188 test_query(actual, expected);
189
190 let actual = table("Bar").select().join("Foo").into();
191 let expected = "SELECT * FROM Bar JOIN Foo";
192 test_query(actual, expected);
193
194 let actual = table("Bar")
195 .select()
196 .join("Foo")
197 .on("Foo.id = Bar.foo_id")
198 .into();
199 let expected = "SELECT * FROM Bar JOIN Foo ON Foo.id = Bar.foo_id";
200 test_query(actual, expected);
201
202 let actual = QueryNode::from(
203 table("Player")
204 .select()
205 .join("PlayerItem")
206 .hash_executor("PlayerItem.user_id", "Player.id"),
207 )
208 .build_query_plan()
209 .unwrap();
210 let expected = {
211 let join = InnerJoinPlan {
212 input: InnerJoinInputPlan::Hash(HashJoinPlan {
213 input: HashJoinInputPlan::Source(SourcePlan::Table(TableSourcePlan {
214 name: "Player".to_owned(),
215 alias: None,
216 access: TableAccessPlan::FullScan,
217 })),
218 right: SourcePlan::Table(TableSourcePlan {
219 name: "PlayerItem".to_owned(),
220 alias: None,
221 access: TableAccessPlan::FullScan,
222 }),
223 input_key: col("Player.id").build_expr_plan().unwrap(),
224 right_key: col("PlayerItem.user_id").build_expr_plan().unwrap(),
225 right_filter: None,
226 }),
227 };
228 let project = ProjectPlan {
229 input: ProjectInputPlan::InnerJoin(Box::new(join)),
230 projection: ProjectionPlan::SelectItems(
231 SelectItemList::from("*").build_select_items_plan().unwrap(),
232 ),
233 };
234
235 QueryPlan::Project(project)
236 };
237 assert_eq!(actual, expected);
238
239 let actual = table("FOO").select().group_by("id").into();
240 let expected = "SELECT * FROM FOO GROUP BY id";
241 test_query(actual, expected);
242
243 let actual = table("FOO")
244 .select()
245 .group_by("id")
246 .having("COUNT(id) > 10")
247 .into();
248 let expected = "SELECT * FROM FOO GROUP BY id HAVING COUNT(id) > 10";
249 test_query(actual, expected);
250
251 let actual = table("FOO")
252 .select()
253 .group_by("city")
254 .having("COUNT(name) < 100")
255 .limit(3)
256 .into();
257 let expected = "SELECT * FROM FOO GROUP BY city HAVING COUNT(name) < 100 LIMIT 3";
258 test_query(actual, expected);
259
260 let actual = table("FOO").select().offset(10).into();
261 let expected = "SELECT * FROM FOO OFFSET 10";
262 test_query(actual, expected);
263
264 let actual = table("FOO")
265 .select()
266 .group_by("city")
267 .having("COUNT(name) < 100")
268 .offset(1)
269 .limit(3)
270 .into();
271 let expected = "SELECT * FROM FOO GROUP BY city HAVING COUNT(name) < 100 OFFSET 1 LIMIT 3";
272 test_query(actual, expected);
273
274 let actual = table("FOO").select().project("id, name").limit(10).into();
275 let expected = r"SELECT id, name FROM FOO LIMIT 10";
276 test_query(actual, expected);
277
278 let actual = table("Foo").select().order_by("score DESC").into();
279 let expected = "SELECT * FROM Foo ORDER BY score DESC";
280 test_query(actual, expected);
281
282 let actual = table("Foo")
283 .select()
284 .project("id")
285 .order_by("id")
286 .distinct()
287 .into();
288 let expected = "SELECT DISTINCT id FROM Foo ORDER BY id";
289 test_query(actual, expected);
290
291 let actual = glue_objects().select().into();
292 let expected = "SELECT * FROM GLUE_OBJECTS";
293 test_query(actual, expected);
294
295 let actual = glue_tables().select().into();
296 let expected = "SELECT * FROM GLUE_TABLES";
297 test_query(actual, expected);
298
299 let actual = glue_indexes().select().into();
300 let expected = "SELECT * FROM GLUE_INDEXES";
301 test_query(actual, expected);
302
303 let actual = glue_table_columns().select().into();
304 let expected = "SELECT * FROM GLUE_TABLE_COLUMNS";
305 test_query(actual, expected);
306
307 let actual = series("1 + 2").select().into();
308 let expected = "SELECT * FROM SERIES(1 + 2)";
309 test_query(actual, expected);
310
311 let actual = table("Items").select().alias_as("Sub").select().into();
312 let expected = "SELECT * FROM (SELECT * FROM Items) AS Sub";
313 test_query(actual, expected);
314 }
315
316 #[test]
317 fn select_distinct_builds_after_order_by() {
318 let actual = table("Item").select().distinct();
319 test_query_builder(actual, "SELECT DISTINCT * FROM Item");
320
321 let actual = table("Item").select().order_by("id").distinct();
322 test_query_builder(actual, "SELECT DISTINCT * FROM Item ORDER BY id");
323
324 let actual = table("Item").select().distinct().offset(2);
325 test_query_builder(actual, "SELECT DISTINCT * FROM Item OFFSET 2");
326
327 let actual = table("Item").select().order_by("id").distinct().offset(2);
328 test_query_builder(actual, "SELECT DISTINCT * FROM Item ORDER BY id OFFSET 2");
329
330 let actual = table("Item").select().distinct().limit(3);
331 test_query_builder(actual, "SELECT DISTINCT * FROM Item LIMIT 3");
332
333 let actual = table("Item").select().order_by("id").distinct().limit(3);
334 test_query_builder(actual, "SELECT DISTINCT * FROM Item ORDER BY id LIMIT 3");
335
336 let actual = table("Item").select().distinct().offset(2).limit(3);
337 test_query_builder(actual, "SELECT DISTINCT * FROM Item OFFSET 2 LIMIT 3");
338
339 let actual = table("Item")
340 .select()
341 .order_by("id")
342 .distinct()
343 .offset(2)
344 .limit(3);
345 test_query_builder(
346 actual,
347 "SELECT DISTINCT * FROM Item ORDER BY id OFFSET 2 LIMIT 3",
348 );
349 }
350
351 #[test]
352 fn query_builder_builds_only_valid_terminal_stage_relations() {
353 let actual = table("Foo").select();
354 test_query_builder(actual, "SELECT * FROM Foo");
355
356 let actual = table("Foo").select().order_by("id");
357 test_query_builder(actual, "SELECT * FROM Foo ORDER BY id");
358
359 let actual = table("Foo").select().offset(2);
360 test_query_builder(actual, "SELECT * FROM Foo OFFSET 2");
361
362 let actual = table("Foo").select().order_by("id").offset(2);
363 test_query_builder(actual, "SELECT * FROM Foo ORDER BY id OFFSET 2");
364
365 let actual = table("Foo").select().limit(3);
366 test_query_builder(actual, "SELECT * FROM Foo LIMIT 3");
367
368 let actual = table("Foo").select().order_by("id").limit(3);
369 test_query_builder(actual, "SELECT * FROM Foo ORDER BY id LIMIT 3");
370
371 let actual = table("Foo").select().offset(2).limit(3);
372 test_query_builder(actual, "SELECT * FROM Foo OFFSET 2 LIMIT 3");
373
374 let actual = table("Foo").select().order_by("id").offset(2).limit(3);
375 test_query_builder(actual, "SELECT * FROM Foo ORDER BY id OFFSET 2 LIMIT 3");
376 }
377
378 #[test]
379 fn query_builder_preserves_values_terminal_stage_relations() {
380 let actual = values(vec!["1"]);
381 test_query_builder(actual, "VALUES (1)");
382
383 let actual = values(vec!["1"]).order_by("column1");
384 test_query_builder(actual, "VALUES (1) ORDER BY column1");
385
386 let actual = values(vec!["1"]).offset(2);
387 test_query_builder(actual, "VALUES (1) OFFSET 2");
388
389 let actual = values(vec!["1"]).order_by("column1").offset(2);
390 test_query_builder(actual, "VALUES (1) ORDER BY column1 OFFSET 2");
391
392 let actual = values(vec!["1"]).limit(3);
393 test_query_builder(actual, "VALUES (1) LIMIT 3");
394
395 let actual = values(vec!["1"]).order_by("column1").limit(3);
396 test_query_builder(actual, "VALUES (1) ORDER BY column1 LIMIT 3");
397
398 let actual = values(vec!["1"]).offset(2).limit(3);
399 test_query_builder(actual, "VALUES (1) OFFSET 2 LIMIT 3");
400
401 let actual = values(vec!["1"]).order_by("column1").offset(2).limit(3);
402 test_query_builder(actual, "VALUES (1) ORDER BY column1 OFFSET 2 LIMIT 3");
403 }
404}