1use super::error::ParseError;
4use super::Parser;
5use crate::ast::{
6 FieldRef, GraphQuery, JoinCondition, JoinQuery, JoinType, Projection, QueryExpr, SelectItem,
7 TableQuery,
8};
9use crate::lexer::Token;
10use crate::sql_lowering::{filter_to_expr, projection_to_select_item};
11impl<'a> Parser<'a> {
12 pub fn parse_from_query(&mut self) -> Result<QueryExpr, ParseError> {
14 self.expect(Token::From)?;
15
16 let mut table_query = if self.check(&Token::LParen) {
25 self.advance()?; if !self.check(&Token::Select) {
29 return Err(ParseError::new(
30 "subquery in FROM must start with SELECT".to_string(),
31 self.position(),
32 ));
33 }
34 let inner = self.parse_select_query()?;
35 self.expect(Token::RParen)?;
36 let alias = if self.consume(&Token::As)?
37 || (self.check(&Token::Ident("".into())) && !self.is_join_keyword())
38 {
39 Some(self.expect_ident()?)
40 } else {
41 None
42 };
43 TableQuery::from_subquery(inner, alias)
44 } else {
45 let table = self.parse_table_source()?;
47 let alias = if self.consume(&Token::As)?
48 || (self.check(&Token::Ident("".into())) && !self.is_join_keyword())
49 {
50 Some(self.expect_ident()?)
51 } else {
52 None
53 };
54 TableQuery {
55 table,
56 source: None,
57 alias,
58 select_items: Vec::new(),
59 columns: Vec::new(),
60 where_expr: None,
61 filter: None,
62 group_by_exprs: Vec::new(),
63 group_by: Vec::new(),
64 having_expr: None,
65 having: None,
66 order_by: Vec::new(),
67 limit: None,
68 limit_param: None,
69 offset: None,
70 offset_param: None,
71 expand: None,
72 as_of: None,
73 sessionize: None,
74 distinct: false,
75 }
76 };
77
78 if self.is_join_keyword() {
80 return self.parse_join_query(QueryExpr::Table(table_query));
81 }
82
83 if self.consume(&Token::Where)? {
85 let filter = self.parse_filter()?;
86 table_query.where_expr = Some(filter_to_expr(&filter));
87 table_query.filter = Some(filter);
88 }
89
90 if self.consume(&Token::Order)? {
92 self.expect(Token::By)?;
93 table_query.order_by = self.parse_order_by_list()?;
94 }
95
96 if self.consume(&Token::Limit)? {
98 table_query.limit = Some(self.parse_integer()? as u64);
99 }
100 if self.consume(&Token::Offset)? {
101 table_query.offset = Some(self.parse_integer()? as u64);
102 }
103
104 if self.consume(&Token::Return)? {
106 let (select_items, columns) = self.parse_select_items_and_projections()?;
107 table_query.select_items = select_items;
108 table_query.columns = columns;
109 }
110
111 Ok(QueryExpr::Table(table_query))
112 }
113
114 pub fn is_join_keyword(&self) -> bool {
116 matches!(
117 self.peek(),
118 Token::Join | Token::Inner | Token::Left | Token::Right | Token::Full | Token::Cross
119 )
120 }
121
122 pub(crate) fn parse_join_query(&mut self, left: QueryExpr) -> Result<QueryExpr, ParseError> {
124 let join_type = if self.consume(&Token::Inner)? {
126 self.expect(Token::Join)?;
127 JoinType::Inner
128 } else if self.consume(&Token::Left)? {
129 self.consume(&Token::Outer)?;
130 self.expect(Token::Join)?;
131 JoinType::LeftOuter
132 } else if self.consume(&Token::Right)? {
133 self.consume(&Token::Outer)?;
134 self.expect(Token::Join)?;
135 JoinType::RightOuter
136 } else if self.consume(&Token::Full)? {
137 self.consume(&Token::Outer)?;
139 self.expect(Token::Join)?;
140 JoinType::FullOuter
141 } else if self.consume(&Token::Cross)? {
142 self.expect(Token::Join)?;
143 JoinType::Cross
144 } else {
145 self.expect(Token::Join)?;
146 JoinType::Inner
147 };
148
149 if self.consume(&Token::Graph)? {
150 return self.parse_graph_join_query(left, join_type);
151 }
152 if self.check(&Token::Path) {
153 return self.parse_path_join_query(left, join_type);
154 }
155 if self.check(&Token::Vector) {
156 return self.parse_vector_join_query(left, join_type);
157 }
158 if self.check(&Token::Hybrid) {
159 return self.parse_hybrid_join_query(left, join_type);
160 }
161
162 self.parse_table_join_query(left, join_type)
163 }
164
165 fn parse_graph_join_query(
166 &mut self,
167 left: QueryExpr,
168 join_type: JoinType,
169 ) -> Result<QueryExpr, ParseError> {
170 let pattern = self.parse_graph_pattern()?;
172 let alias = self.parse_join_rhs_alias()?;
173
174 self.expect(Token::On)?;
176 let on = self.parse_graph_join_condition()?;
177 let (filter, order_by, limit, offset, return_items, return_) =
178 self.parse_join_post_clauses()?;
179 let graph_query = GraphQuery {
180 alias,
181 pattern,
182 filter: None,
183 return_: Vec::new(),
184 limit: None,
185 };
186
187 Ok(QueryExpr::Join(JoinQuery {
188 left: Box::new(left),
189 right: Box::new(QueryExpr::Graph(graph_query)),
190 join_type,
191 on,
192 filter,
193 order_by,
194 limit,
195 offset,
196 return_items,
197 return_,
198 }))
199 }
200
201 fn parse_table_join_query(
202 &mut self,
203 left: QueryExpr,
204 join_type: JoinType,
205 ) -> Result<QueryExpr, ParseError> {
206 let table = self.parse_table_source()?;
207 let alias = if self.consume(&Token::As)?
208 || (self.check(&Token::Ident("".into())) && !self.is_clause_keyword())
209 {
210 Some(self.expect_ident()?)
211 } else {
212 None
213 };
214
215 let on = if matches!(join_type, JoinType::Cross) {
218 cross_join_sentinel()
219 } else {
220 self.expect(Token::On)?;
221 self.parse_table_join_condition()?
222 };
223 let table_query = TableQuery {
224 table,
225 source: None,
226 alias,
227 select_items: Vec::new(),
228 columns: Vec::new(),
229 where_expr: None,
230 filter: None,
231 group_by_exprs: Vec::new(),
232 group_by: Vec::new(),
233 having_expr: None,
234 having: None,
235 order_by: Vec::new(),
236 limit: None,
237 limit_param: None,
238 offset: None,
239 offset_param: None,
240 expand: None,
241 as_of: None,
242 sessionize: None,
243 distinct: false,
244 };
245
246 let mut expr = QueryExpr::Join(JoinQuery {
247 left: Box::new(left),
248 right: Box::new(QueryExpr::Table(table_query)),
249 join_type,
250 on,
251 filter: None,
252 order_by: Vec::new(),
253 limit: None,
254 offset: None,
255 return_items: Vec::new(),
256 return_: Vec::new(),
257 });
258
259 if self.is_join_keyword() {
260 return self.parse_join_query(expr);
261 }
262
263 let (filter, order_by, limit, offset, _, return_) = self.parse_join_post_clauses()?;
264 let return_ = normalize_table_join_return_projections(return_);
265 let return_items = return_
266 .iter()
267 .filter_map(projection_to_select_item)
268 .collect();
269 if let QueryExpr::Join(join) = &mut expr {
270 join.filter = filter;
271 join.order_by = order_by;
272 join.limit = limit;
273 join.offset = offset;
274 join.return_items = return_items;
275 join.return_ = return_;
276 }
277 Ok(expr)
278 }
279
280 fn parse_vector_join_query(
281 &mut self,
282 left: QueryExpr,
283 join_type: JoinType,
284 ) -> Result<QueryExpr, ParseError> {
285 let mut right = match self.parse_vector_query()? {
286 QueryExpr::Vector(query) => query,
287 _ => unreachable!("vector parser must return QueryExpr::Vector"),
288 };
289 right.alias = self.parse_join_rhs_alias()?;
290 self.expect(Token::On)?;
291 let on = self.parse_table_join_condition()?;
292 let (filter, order_by, limit, offset, return_items, return_) =
293 self.parse_join_post_clauses()?;
294
295 Ok(QueryExpr::Join(JoinQuery {
296 left: Box::new(left),
297 right: Box::new(QueryExpr::Vector(right)),
298 join_type,
299 on,
300 filter,
301 order_by,
302 limit,
303 offset,
304 return_items,
305 return_,
306 }))
307 }
308
309 fn parse_path_join_query(
310 &mut self,
311 left: QueryExpr,
312 join_type: JoinType,
313 ) -> Result<QueryExpr, ParseError> {
314 let mut right = match self.parse_path_query()? {
315 QueryExpr::Path(query) => query,
316 _ => unreachable!("path parser must return QueryExpr::Path"),
317 };
318 right.alias = self.parse_join_rhs_alias()?;
319 self.expect(Token::On)?;
320 let on = self.parse_table_join_condition()?;
321 let (filter, order_by, limit, offset, return_items, return_) =
322 self.parse_join_post_clauses()?;
323
324 Ok(QueryExpr::Join(JoinQuery {
325 left: Box::new(left),
326 right: Box::new(QueryExpr::Path(right)),
327 join_type,
328 on,
329 filter,
330 order_by,
331 limit,
332 offset,
333 return_items,
334 return_,
335 }))
336 }
337
338 fn parse_hybrid_join_query(
339 &mut self,
340 left: QueryExpr,
341 join_type: JoinType,
342 ) -> Result<QueryExpr, ParseError> {
343 let mut right = match self.parse_hybrid_query()? {
344 QueryExpr::Hybrid(query) => query,
345 _ => unreachable!("hybrid parser must return QueryExpr::Hybrid"),
346 };
347 right.alias = self.parse_join_rhs_alias()?;
348 self.expect(Token::On)?;
349 let on = self.parse_table_join_condition()?;
350 let (filter, order_by, limit, offset, return_items, return_) =
351 self.parse_join_post_clauses()?;
352
353 Ok(QueryExpr::Join(JoinQuery {
354 left: Box::new(left),
355 right: Box::new(QueryExpr::Hybrid(right)),
356 join_type,
357 on,
358 filter,
359 order_by,
360 limit,
361 offset,
362 return_items,
363 return_,
364 }))
365 }
366
367 fn parse_join_post_clauses(
368 &mut self,
369 ) -> Result<
370 (
371 Option<crate::ast::Filter>,
372 Vec<crate::ast::OrderByClause>,
373 Option<u64>,
374 Option<u64>,
375 Vec<SelectItem>,
376 Vec<crate::ast::Projection>,
377 ),
378 ParseError,
379 > {
380 let mut filter = None;
381 let mut order_by = Vec::new();
382 let mut limit = None;
383 let mut offset = None;
384 let mut return_items = Vec::new();
385 let mut return_ = Vec::new();
386
387 loop {
388 if self.consume(&Token::Where)? {
389 filter = Some(self.parse_filter()?);
390 } else if self.consume(&Token::Order)? {
391 self.expect(Token::By)?;
392 order_by = self.parse_order_by_list()?;
393 } else if self.consume(&Token::Limit)? {
394 limit = Some(self.parse_integer()? as u64);
395 } else if self.consume(&Token::Offset)? {
396 offset = Some(self.parse_integer()? as u64);
397 } else if self.consume(&Token::Return)? {
398 return_ = self.parse_return_list()?;
399 return_items = return_
400 .iter()
401 .filter_map(projection_to_select_item)
402 .collect();
403 } else {
404 break;
405 }
406 }
407
408 Ok((filter, order_by, limit, offset, return_items, return_))
409 }
410
411 fn parse_join_rhs_alias(&mut self) -> Result<Option<String>, ParseError> {
412 if self.consume(&Token::As)?
413 || (self.check(&Token::Ident("".into())) && !self.is_join_rhs_clause_keyword())
414 {
415 Ok(Some(self.expect_ident()?))
416 } else {
417 Ok(None)
418 }
419 }
420
421 fn is_join_rhs_clause_keyword(&self) -> bool {
422 matches!(
423 self.peek(),
424 Token::On
425 | Token::Where
426 | Token::Order
427 | Token::Limit
428 | Token::Offset
429 | Token::Return
430 | Token::Join
431 | Token::Inner
432 | Token::Left
433 | Token::Right
434 )
435 }
436
437 fn parse_table_source(&mut self) -> Result<String, ParseError> {
438 if self.consume(&Token::Star)? {
439 Ok("*".to_string())
440 } else if self.consume(&Token::All)? {
441 Ok("all".to_string())
442 } else {
443 self.expect_ident()
444 }
445 }
446
447 fn parse_graph_join_condition(&mut self) -> Result<JoinCondition, ParseError> {
449 let left_field = self.parse_field_ref()?;
450 self.expect(Token::Eq)?;
451 let right_first = self.expect_ident()?;
452 self.expect(Token::Dot)?;
453 let right_second = self.expect_ident()?;
454
455 let right_field = if right_second == "id" {
457 FieldRef::NodeId { alias: right_first }
458 } else {
459 FieldRef::NodeProperty {
460 alias: right_first,
461 property: right_second,
462 }
463 };
464
465 Ok(JoinCondition {
466 left_field,
467 right_field,
468 })
469 }
470
471 fn parse_table_join_condition(&mut self) -> Result<JoinCondition, ParseError> {
472 let left_field = self.parse_field_ref()?;
473 self.expect(Token::Eq)?;
474 let right_field = self.parse_field_ref()?;
475
476 Ok(JoinCondition {
477 left_field,
478 right_field,
479 })
480 }
481}
482
483fn normalize_table_join_return_projections(projections: Vec<Projection>) -> Vec<Projection> {
484 projections
485 .into_iter()
486 .map(|projection| match projection {
487 Projection::Field(FieldRef::NodeProperty { alias, property }, output_alias) => {
488 let output_alias = output_alias.or_else(|| Some(property.clone()));
489 Projection::Field(
490 FieldRef::TableColumn {
491 table: alias,
492 column: property,
493 },
494 output_alias,
495 )
496 }
497 other => other,
498 })
499 .collect()
500}
501
502fn cross_join_sentinel() -> JoinCondition {
507 JoinCondition {
508 left_field: FieldRef::TableColumn {
509 table: String::new(),
510 column: String::new(),
511 },
512 right_field: FieldRef::TableColumn {
513 table: String::new(),
514 column: String::new(),
515 },
516 }
517}