1use {
2 super::{Expr, ToSqlUnquoted},
3 crate::ast::ToSql,
4 itertools::Itertools,
5 serde::{Deserialize, Serialize},
6 strum_macros::Display,
7};
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub struct Query {
11 pub body: SetExpr,
12 pub order_by: Vec<OrderByExpr>,
13 pub limit: Option<Expr>,
14 pub offset: Option<Expr>,
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
18pub enum SetExpr {
19 Select(Box<Select>),
20 Values(Values),
21}
22
23#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
24pub enum Projection {
25 SelectItems(Vec<SelectItem>),
26}
27
28#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
29pub struct Select {
30 pub distinct: bool,
31 pub projection: Projection,
32 pub from: TableWithJoins,
33 pub selection: Option<Expr>,
35 pub group_by: Vec<Expr>,
36 pub having: Option<Expr>,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
40pub enum SelectItem {
41 Expr { expr: Expr, label: String },
43 QualifiedWildcard(String),
45 Wildcard,
47}
48
49#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
50pub struct TableWithJoins {
51 pub relation: TableFactor,
52 pub joins: Vec<Join>,
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
56pub enum TableFactor {
57 Table {
58 name: String,
59 alias: Option<TableAlias>,
60 },
61 Derived {
62 subquery: Query,
63 alias: TableAlias,
64 },
65 Series {
66 alias: TableAlias,
67 size: Expr,
68 },
69 Dictionary {
70 dict: Dictionary,
71 alias: TableAlias,
72 },
73}
74
75#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Display)]
76#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
77pub enum Dictionary {
78 GlueTables,
79 GlueTableColumns,
80 GlueIndexes,
81 GlueObjects,
82}
83
84#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
85pub struct TableAlias {
86 pub name: String,
87 pub columns: Vec<String>,
88}
89
90#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
91pub struct Join {
92 pub relation: TableFactor,
93 pub join_operator: JoinOperator,
94}
95
96#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
97pub enum JoinOperator {
98 Inner(JoinConstraint),
99 LeftOuter(JoinConstraint),
100}
101
102#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
103pub enum JoinConstraint {
104 On(Expr),
105 None,
106}
107
108#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
109pub struct OrderByExpr {
110 pub expr: Expr,
111 pub asc: Option<bool>,
112}
113
114#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
115pub struct Values(pub Vec<Vec<Expr>>);
116
117impl ToSql for Query {
118 fn to_sql(&self) -> String {
119 self.to_sql_with(true)
120 }
121}
122
123impl ToSqlUnquoted for Query {
124 fn to_sql_unquoted(&self) -> String {
125 self.to_sql_with(false)
126 }
127}
128
129impl Query {
130 fn to_sql_with(&self, quoted: bool) -> String {
131 let to_sql = |expr: &Expr| {
132 if quoted {
133 expr.to_sql()
134 } else {
135 expr.to_sql_unquoted()
136 }
137 };
138
139 let Query {
140 body,
141 order_by,
142 limit,
143 offset,
144 } = self;
145
146 let order_by = if order_by.is_empty() {
147 String::new()
148 } else {
149 format!(
150 "ORDER BY {}",
151 order_by
152 .iter()
153 .map(|expr| expr.to_sql_with(quoted))
154 .join(" ")
155 )
156 };
157
158 let limit = match limit {
159 Some(expr) => format!("LIMIT {}", to_sql(expr)),
160 _ => String::new(),
161 };
162
163 let offset = match offset {
164 Some(expr) => format!("OFFSET {}", to_sql(expr)),
165 _ => String::new(),
166 };
167
168 let string = [order_by, limit, offset]
169 .iter()
170 .filter(|sql| !sql.is_empty())
171 .join(" ");
172
173 if string.is_empty() {
174 body.to_sql_with(quoted)
175 } else {
176 format!("{} {}", body.to_sql_with(quoted), string)
177 }
178 }
179}
180
181impl ToSql for SetExpr {
182 fn to_sql(&self) -> String {
183 self.to_sql_with(true)
184 }
185}
186
187impl ToSqlUnquoted for SetExpr {
188 fn to_sql_unquoted(&self) -> String {
189 self.to_sql_with(false)
190 }
191}
192
193impl SetExpr {
194 fn to_sql_with(&self, quoted: bool) -> String {
195 match (self, quoted) {
196 (SetExpr::Select(select), true) => select.to_sql(),
197 (SetExpr::Select(select), false) => select.to_sql_unquoted(),
198 (SetExpr::Values(values), true) => format!("VALUES {}", values.to_sql()),
199 (SetExpr::Values(values), false) => format!("VALUES {}", values.to_sql_unquoted()),
200 }
201 }
202}
203
204impl ToSql for Select {
205 fn to_sql(&self) -> String {
206 self.to_sql_with(true)
207 }
208}
209
210impl ToSqlUnquoted for Select {
211 fn to_sql_unquoted(&self) -> String {
212 self.to_sql_with(false)
213 }
214}
215
216impl Select {
217 fn to_sql_with(&self, quoted: bool) -> String {
218 let to_sql = |expr: &Expr| {
219 if quoted {
220 expr.to_sql()
221 } else {
222 expr.to_sql_unquoted()
223 }
224 };
225
226 let Select {
227 distinct,
228 projection,
229 from,
230 selection,
231 group_by,
232 having,
233 } = self;
234 let projection = match projection {
235 Projection::SelectItems(items) => {
236 items.iter().map(|item| item.to_sql_with(quoted)).join(", ")
237 }
238 };
239
240 let selection = match selection {
241 Some(expr) => format!("WHERE {}", to_sql(expr)),
242 None => String::new(),
243 };
244
245 let group_by = if group_by.is_empty() {
246 String::new()
247 } else {
248 format!("GROUP BY {}", group_by.iter().map(to_sql).join(", "))
249 };
250
251 let having = match having {
252 Some(having) => format!("HAVING {}", to_sql(having)),
253 None => String::new(),
254 };
255
256 let condition = [selection, group_by, having]
257 .iter()
258 .filter(|sql| !sql.is_empty())
259 .join(" ");
260
261 let distinct = if *distinct { "DISTINCT " } else { "" };
262
263 if condition.is_empty() {
264 format!(
265 "SELECT {}{projection} FROM {}",
266 distinct,
267 from.to_sql_with(quoted)
268 )
269 } else {
270 format!(
271 "SELECT {}{projection} FROM {} {condition}",
272 distinct,
273 from.to_sql_with(quoted)
274 )
275 }
276 }
277}
278
279impl ToSql for SelectItem {
280 fn to_sql(&self) -> String {
281 self.to_sql_with(true)
282 }
283}
284
285impl ToSqlUnquoted for SelectItem {
286 fn to_sql_unquoted(&self) -> String {
287 self.to_sql_with(false)
288 }
289}
290
291impl SelectItem {
292 fn to_sql_with(&self, quoted: bool) -> String {
293 let to_sql = |expr: &Expr| {
294 if quoted {
295 expr.to_sql()
296 } else {
297 expr.to_sql_unquoted()
298 }
299 };
300
301 match self {
302 SelectItem::Expr { expr, label } => {
303 let expr = to_sql(expr);
304 match (label.is_empty(), quoted) {
305 (true, _) => expr,
306 (false, true) => format!(r#"{expr} AS "{label}""#),
307 (false, false) => format!("{expr} AS {label}"),
308 }
309 }
310 SelectItem::QualifiedWildcard(obj) => {
311 if quoted {
312 format!(r#""{obj}".*"#)
313 } else {
314 format!("{obj}.*")
315 }
316 }
317 SelectItem::Wildcard => "*".to_owned(),
318 }
319 }
320}
321
322impl ToSql for TableWithJoins {
323 fn to_sql(&self) -> String {
324 self.to_sql_with(true)
325 }
326}
327
328impl ToSqlUnquoted for TableWithJoins {
329 fn to_sql_unquoted(&self) -> String {
330 self.to_sql_with(false)
331 }
332}
333
334impl TableWithJoins {
335 fn to_sql_with(&self, quoted: bool) -> String {
336 let TableWithJoins { relation, joins } = self;
337
338 if joins.is_empty() {
339 relation.to_sql_with(quoted)
340 } else {
341 format!(
342 "{} {}",
343 relation.to_sql_with(quoted),
344 joins.iter().map(|join| join.to_sql_with(quoted)).join(" ")
345 )
346 }
347 }
348}
349
350impl ToSql for TableFactor {
351 fn to_sql(&self) -> String {
352 self.to_sql_with(true)
353 }
354}
355
356impl ToSqlUnquoted for TableFactor {
357 fn to_sql_unquoted(&self) -> String {
358 self.to_sql_with(false)
359 }
360}
361
362impl TableFactor {
363 fn to_sql_with(&self, quoted: bool) -> String {
364 let to_sql = |expr: &Expr| {
365 if quoted {
366 expr.to_sql()
367 } else {
368 expr.to_sql_unquoted()
369 }
370 };
371
372 match (self, quoted) {
373 (TableFactor::Table { name, alias }, true) => match alias {
374 Some(alias) => format!(r#""{}" {}"#, name, alias.to_sql_with(quoted)),
375 None => format!(r#""{name}""#),
376 },
377 (TableFactor::Table { name, alias }, false) => match alias {
378 Some(alias) => format!("{} {}", name, alias.to_sql_with(quoted)),
379 None => name.to_owned(),
380 },
381 (TableFactor::Derived { subquery, alias }, _) => {
382 format!(
383 "({}) {}",
384 subquery.to_sql_with(quoted),
385 alias.to_sql_with(quoted)
386 )
387 }
388 (TableFactor::Series { alias, size }, _) => {
389 format!("SERIES({}) {}", to_sql(size), alias.to_sql_with(quoted))
390 }
391 (TableFactor::Dictionary { dict, alias }, true) => {
392 format!(r#""{dict}" {}"#, alias.to_sql_with(quoted))
393 }
394 (TableFactor::Dictionary { dict, alias }, false) => {
395 format!("{dict} {}", alias.to_sql_with(quoted))
396 }
397 }
398 }
399}
400
401impl ToSql for TableAlias {
402 fn to_sql(&self) -> String {
403 self.to_sql_with(true)
404 }
405}
406
407impl ToSqlUnquoted for TableAlias {
408 fn to_sql_unquoted(&self) -> String {
409 self.to_sql_with(false)
410 }
411}
412
413impl TableAlias {
414 fn to_sql_with(&self, quoted: bool) -> String {
415 let TableAlias { name, .. } = self;
416
417 if quoted {
418 format!(r#"AS "{name}""#)
419 } else {
420 format!("AS {name}")
421 }
422 }
423}
424
425impl ToSql for Join {
426 fn to_sql(&self) -> String {
427 self.to_sql_with(true)
428 }
429}
430
431impl ToSqlUnquoted for Join {
432 fn to_sql_unquoted(&self) -> String {
433 self.to_sql_with(false)
434 }
435}
436
437impl Join {
438 fn to_sql_with(&self, quoted: bool) -> String {
439 let Join {
440 relation,
441 join_operator,
442 } = self;
443
444 let (join_operator, join_constraint) = match join_operator {
445 JoinOperator::Inner(join_constraint) => ("INNER JOIN", join_constraint),
446 JoinOperator::LeftOuter(join_constraint) => ("LEFT OUTER JOIN", join_constraint),
447 };
448
449 let join_constraint = if quoted {
450 join_constraint.to_sql()
451 } else {
452 join_constraint.to_sql_unquoted()
453 };
454
455 if join_constraint.is_empty() {
456 format!("{join_operator} {}", relation.to_sql_with(quoted))
457 } else {
458 format!(
459 "{join_operator} {} ON {join_constraint}",
460 relation.to_sql_with(quoted)
461 )
462 }
463 }
464}
465
466impl ToSql for JoinConstraint {
467 fn to_sql(&self) -> String {
468 self.to_sql_with(true)
469 }
470}
471
472impl ToSqlUnquoted for JoinConstraint {
473 fn to_sql_unquoted(&self) -> String {
474 self.to_sql_with(false)
475 }
476}
477
478impl JoinConstraint {
479 fn to_sql_with(&self, quoted: bool) -> String {
480 match (self, quoted) {
481 (JoinConstraint::On(expr), true) => expr.to_sql(),
482 (JoinConstraint::On(expr), false) => expr.to_sql_unquoted(),
483 (JoinConstraint::None, _) => String::new(),
484 }
485 }
486}
487
488impl ToSql for OrderByExpr {
489 fn to_sql(&self) -> String {
490 self.to_sql_with(true)
491 }
492}
493
494impl ToSqlUnquoted for OrderByExpr {
495 fn to_sql_unquoted(&self) -> String {
496 self.to_sql_with(false)
497 }
498}
499
500impl OrderByExpr {
501 fn to_sql_with(&self, quoted: bool) -> String {
502 let OrderByExpr { expr, asc } = self;
503 let expr = if quoted {
504 expr.to_sql()
505 } else {
506 expr.to_sql_unquoted()
507 };
508
509 match asc {
510 Some(true) => format!("{expr} ASC"),
511 Some(false) => format!("{expr} DESC"),
512 None => expr,
513 }
514 }
515}
516
517impl ToSql for Values {
518 fn to_sql(&self) -> String {
519 self.to_sql_with(true)
520 }
521}
522
523impl ToSqlUnquoted for Values {
524 fn to_sql_unquoted(&self) -> String {
525 self.to_sql_with(false)
526 }
527}
528
529impl Values {
530 fn to_sql_with(&self, quoted: bool) -> String {
531 let Values(expr) = self;
532
533 expr.iter()
534 .map(|value| {
535 format!(
536 "({})",
537 value
538 .iter()
539 .map(|expr| if quoted {
540 expr.to_sql()
541 } else {
542 expr.to_sql_unquoted()
543 })
544 .join(", ")
545 )
546 })
547 .join(", ")
548 }
549}
550
551#[cfg(test)]
552mod tests {
553 use {
554 crate::{
555 ast::{
556 BinaryOperator, Dictionary, Expr, Join, JoinConstraint, JoinOperator, Literal,
557 OrderByExpr, Projection, Query, Select, SelectItem, SetExpr, TableAlias,
558 TableFactor, TableWithJoins, ToSql, ToSqlUnquoted, Values,
559 },
560 parse_sql::parse_expr,
561 translate::{NO_PARAMS, translate_expr},
562 },
563 bigdecimal::BigDecimal,
564 std::str::FromStr,
565 };
566
567 fn expr(sql: &str) -> Expr {
568 let parsed = parse_expr(sql).expect(sql);
569
570 translate_expr(&parsed, NO_PARAMS).expect(sql)
571 }
572
573 #[test]
574 fn to_sql_query() {
575 let order_by = vec![OrderByExpr {
576 expr: Expr::Identifier("name".to_owned()),
577 asc: Some(true),
578 }];
579 let actual =
580 r#"SELECT * FROM "FOO" AS "F" ORDER BY "name" ASC LIMIT 10 OFFSET 3"#.to_owned();
581 let expected = Query {
582 body: SetExpr::Select(Box::new(Select {
583 distinct: false,
584 projection: Projection::SelectItems(vec![SelectItem::Wildcard]),
585 from: TableWithJoins {
586 relation: TableFactor::Table {
587 name: "FOO".to_owned(),
588 alias: Some(TableAlias {
589 name: "F".to_owned(),
590 columns: Vec::new(),
591 }),
592 },
593 joins: Vec::new(),
594 },
595 selection: None,
596 group_by: Vec::new(),
597 having: None,
598 })),
599 order_by,
600 limit: Some(Expr::Literal(Literal::Number(
601 BigDecimal::from_str("10").unwrap(),
602 ))),
603 offset: Some(Expr::Literal(Literal::Number(
604 BigDecimal::from_str("3").unwrap(),
605 ))),
606 }
607 .to_sql();
608 assert_eq!(actual, expected);
609 }
610
611 #[test]
612 fn to_sql_unquoted_query() {
613 let order_by = vec![OrderByExpr {
614 expr: Expr::Identifier("name".to_owned()),
615 asc: Some(true),
616 }];
617 let actual = "SELECT * FROM FOO AS F ORDER BY name ASC LIMIT 10 OFFSET 3".to_owned();
618 let expected = Query {
619 body: SetExpr::Select(Box::new(Select {
620 distinct: false,
621 projection: Projection::SelectItems(vec![SelectItem::Wildcard]),
622 from: TableWithJoins {
623 relation: TableFactor::Table {
624 name: "FOO".to_owned(),
625 alias: Some(TableAlias {
626 name: "F".to_owned(),
627 columns: Vec::new(),
628 }),
629 },
630 joins: Vec::new(),
631 },
632 selection: None,
633 group_by: Vec::new(),
634 having: None,
635 })),
636 order_by,
637 limit: Some(Expr::Literal(Literal::Number(
638 BigDecimal::from_str("10").unwrap(),
639 ))),
640 offset: Some(Expr::Literal(Literal::Number(
641 BigDecimal::from_str("3").unwrap(),
642 ))),
643 }
644 .to_sql_unquoted();
645 assert_eq!(actual, expected);
646 }
647
648 #[test]
649 fn to_sql_set_expr() {
650 let actual = r#"SELECT * FROM "FOO" AS "F" INNER JOIN "PlayerItem""#.to_owned();
651 let expected = SetExpr::Select(Box::new(Select {
652 distinct: false,
653 projection: Projection::SelectItems(vec![SelectItem::Wildcard]),
654 from: TableWithJoins {
655 relation: TableFactor::Table {
656 name: "FOO".to_owned(),
657 alias: Some(TableAlias {
658 name: "F".to_owned(),
659 columns: Vec::new(),
660 }),
661 },
662 joins: vec![Join {
663 relation: TableFactor::Table {
664 name: "PlayerItem".to_owned(),
665 alias: None,
666 },
667 join_operator: JoinOperator::Inner(JoinConstraint::None),
668 }],
669 },
670 selection: None,
671 group_by: Vec::new(),
672 having: None,
673 }))
674 .to_sql();
675 assert_eq!(actual, expected);
676
677 let actual = "VALUES (1, 'glue', 3), (2, 'sql', 2)".to_owned();
678 let expected = SetExpr::Values(Values(vec![
679 vec![
680 Expr::Literal(Literal::Number(BigDecimal::from_str("1").unwrap())),
681 Expr::Literal(Literal::QuotedString("glue".to_owned())),
682 Expr::Literal(Literal::Number(BigDecimal::from_str("3").unwrap())),
683 ],
684 vec![
685 Expr::Literal(Literal::Number(BigDecimal::from_str("2").unwrap())),
686 Expr::Literal(Literal::QuotedString("sql".to_owned())),
687 Expr::Literal(Literal::Number(BigDecimal::from_str("2").unwrap())),
688 ],
689 ]))
690 .to_sql();
691 assert_eq!(actual, expected);
692 }
693
694 #[test]
695 fn to_sql_unquoted_set_expr() {
696 let actual = "SELECT * FROM FOO AS F INNER JOIN PlayerItem".to_owned();
697 let expected = SetExpr::Select(Box::new(Select {
698 distinct: false,
699 projection: Projection::SelectItems(vec![SelectItem::Wildcard]),
700 from: TableWithJoins {
701 relation: TableFactor::Table {
702 name: "FOO".to_owned(),
703 alias: Some(TableAlias {
704 name: "F".to_owned(),
705 columns: Vec::new(),
706 }),
707 },
708 joins: vec![Join {
709 relation: TableFactor::Table {
710 name: "PlayerItem".to_owned(),
711 alias: None,
712 },
713 join_operator: JoinOperator::Inner(JoinConstraint::None),
714 }],
715 },
716 selection: None,
717 group_by: Vec::new(),
718 having: None,
719 }))
720 .to_sql_unquoted();
721 assert_eq!(actual, expected);
722
723 let actual = "VALUES (1 + 1, 'glue'), (3 - 2, 'sql')".to_owned();
724 let expected = SetExpr::Values(Values(vec![
725 vec![
726 Expr::BinaryOp {
727 left: Box::new(Expr::Literal(Literal::Number(
728 BigDecimal::from_str("1").unwrap(),
729 ))),
730 op: BinaryOperator::Plus,
731 right: Box::new(Expr::Literal(Literal::Number(
732 BigDecimal::from_str("1").unwrap(),
733 ))),
734 },
735 Expr::Literal(Literal::QuotedString("glue".to_owned())),
736 ],
737 vec![
738 Expr::BinaryOp {
739 left: Box::new(Expr::Literal(Literal::Number(
740 BigDecimal::from_str("3").unwrap(),
741 ))),
742 op: BinaryOperator::Minus,
743 right: Box::new(Expr::Literal(Literal::Number(
744 BigDecimal::from_str("2").unwrap(),
745 ))),
746 },
747 Expr::Literal(Literal::QuotedString("sql".to_owned())),
748 ],
749 ]))
750 .to_sql_unquoted();
751 assert_eq!(actual, expected);
752 }
753
754 #[test]
755 fn to_sql_select() {
756 let actual =
757 r#"SELECT * FROM "FOO" AS "F" GROUP BY "name" HAVING "name" = 'glue'"#.to_owned();
758 let expected = Select {
759 distinct: false,
760 projection: Projection::SelectItems(vec![SelectItem::Wildcard]),
761 from: TableWithJoins {
762 relation: TableFactor::Table {
763 name: "FOO".to_owned(),
764 alias: Some(TableAlias {
765 name: "F".to_owned(),
766 columns: Vec::new(),
767 }),
768 },
769 joins: Vec::new(),
770 },
771 selection: None,
772 group_by: vec![Expr::Identifier("name".to_owned())],
773 having: Some(Expr::BinaryOp {
774 left: Box::new(Expr::Identifier("name".to_owned())),
775 op: BinaryOperator::Eq,
776 right: Box::new(Expr::Literal(Literal::QuotedString("glue".to_owned()))),
777 }),
778 }
779 .to_sql();
780 assert_eq!(actual, expected);
781
782 let actual = r#"SELECT * FROM "FOO" WHERE "name" = 'glue'"#.to_owned();
783 let expected = Select {
784 distinct: false,
785 projection: Projection::SelectItems(vec![SelectItem::Wildcard]),
786 from: TableWithJoins {
787 relation: TableFactor::Table {
788 name: "FOO".to_owned(),
789 alias: None,
790 },
791 joins: Vec::new(),
792 },
793 selection: Some(Expr::BinaryOp {
794 left: Box::new(Expr::Identifier("name".to_owned())),
795 op: BinaryOperator::Eq,
796 right: Box::new(Expr::Literal(Literal::QuotedString("glue".to_owned()))),
797 }),
798 group_by: Vec::new(),
799 having: None,
800 }
801 .to_sql();
802 assert_eq!(actual, expected);
803 }
804
805 #[test]
806 fn to_sql_unquoted_select() {
807 let actual = "SELECT * FROM FOO AS F GROUP BY name HAVING name = 'glue'".to_owned();
808 let expected = Select {
809 distinct: false,
810 projection: Projection::SelectItems(vec![SelectItem::Wildcard]),
811 from: TableWithJoins {
812 relation: TableFactor::Table {
813 name: "FOO".to_owned(),
814 alias: Some(TableAlias {
815 name: "F".to_owned(),
816 columns: Vec::new(),
817 }),
818 },
819 joins: Vec::new(),
820 },
821 selection: None,
822 group_by: vec![Expr::Identifier("name".to_owned())],
823 having: Some(Expr::BinaryOp {
824 left: Box::new(Expr::Identifier("name".to_owned())),
825 op: BinaryOperator::Eq,
826 right: Box::new(Expr::Literal(Literal::QuotedString("glue".to_owned()))),
827 }),
828 }
829 .to_sql_unquoted();
830 assert_eq!(actual, expected);
831
832 let actual = "SELECT * FROM FOO WHERE name = 'glue'".to_owned();
833 let expected = Select {
834 distinct: false,
835 projection: Projection::SelectItems(vec![SelectItem::Wildcard]),
836 from: TableWithJoins {
837 relation: TableFactor::Table {
838 name: "FOO".to_owned(),
839 alias: None,
840 },
841 joins: Vec::new(),
842 },
843 selection: Some(Expr::BinaryOp {
844 left: Box::new(Expr::Identifier("name".to_owned())),
845 op: BinaryOperator::Eq,
846 right: Box::new(Expr::Literal(Literal::QuotedString("glue".to_owned()))),
847 }),
848 group_by: Vec::new(),
849 having: None,
850 }
851 .to_sql_unquoted();
852 assert_eq!(actual, expected);
853 }
854
855 #[test]
856 fn to_sql_select_item() {
857 let actual = r#""name" AS "n""#.to_owned();
858 let expected = SelectItem::Expr {
859 expr: Expr::Identifier("name".to_owned()),
860 label: "n".to_owned(),
861 }
862 .to_sql();
863 assert_eq!(actual, expected);
864
865 let actual = r#""foo".*"#.to_owned();
866 let expected = SelectItem::QualifiedWildcard("foo".to_owned()).to_sql();
867 assert_eq!(actual, expected);
868
869 let actual = "*".to_owned();
870 let expected = SelectItem::Wildcard.to_sql();
871 assert_eq!(actual, expected);
872 }
873
874 #[test]
875 fn to_sql_unquoted_select_item() {
876 let actual = "name AS n".to_owned();
877 let expected = SelectItem::Expr {
878 expr: Expr::Identifier("name".to_owned()),
879 label: "n".to_owned(),
880 }
881 .to_sql_unquoted();
882 assert_eq!(actual, expected);
883
884 let actual = "foo.*".to_owned();
885 let expected = SelectItem::QualifiedWildcard("foo".to_owned()).to_sql_unquoted();
886 assert_eq!(actual, expected);
887 }
888
889 #[test]
890 fn to_sql_table_with_joins() {
891 let actual = r#""FOO" AS "F""#;
892 let expected = TableWithJoins {
893 relation: TableFactor::Table {
894 name: "FOO".to_owned(),
895 alias: Some(TableAlias {
896 name: "F".to_owned(),
897 columns: Vec::new(),
898 }),
899 },
900 joins: Vec::new(),
901 }
902 .to_sql();
903 assert_eq!(actual, expected);
904 }
905
906 #[test]
907 fn to_sql_unquoted_table_with_joins() {
908 let actual = "FOO AS F";
909 let expected = TableWithJoins {
910 relation: TableFactor::Table {
911 name: "FOO".to_owned(),
912 alias: Some(TableAlias {
913 name: "F".to_owned(),
914 columns: Vec::new(),
915 }),
916 },
917 joins: Vec::new(),
918 }
919 .to_sql_unquoted();
920 assert_eq!(actual, expected);
921 }
922
923 #[test]
924 fn to_sql_table_factor() {
925 let actual = r#""FOO" AS "F""#;
926 let expected = TableFactor::Table {
927 name: "FOO".to_owned(),
928 alias: Some(TableAlias {
929 name: "F".to_owned(),
930 columns: Vec::new(),
931 }),
932 }
933 .to_sql();
934 assert_eq!(actual, expected);
935
936 let actual = r#"(SELECT * FROM "FOO") AS "F""#;
937 let expected = TableFactor::Derived {
938 subquery: Query {
939 body: SetExpr::Select(Box::new(Select {
940 distinct: false,
941 projection: Projection::SelectItems(vec![SelectItem::Wildcard]),
942 from: TableWithJoins {
943 relation: TableFactor::Table {
944 name: "FOO".to_owned(),
945 alias: None,
946 },
947 joins: Vec::new(),
948 },
949 selection: None,
950 group_by: Vec::new(),
951 having: None,
952 })),
953 order_by: Vec::new(),
954 limit: None,
955 offset: None,
956 },
957 alias: TableAlias {
958 name: "F".to_owned(),
959 columns: Vec::new(),
960 },
961 }
962 .to_sql();
963 assert_eq!(actual, expected);
964
965 let actual = r#"SERIES(3) AS "S""#;
966 let expected = TableFactor::Series {
967 alias: TableAlias {
968 name: "S".to_owned(),
969 columns: Vec::new(),
970 },
971 size: Expr::Literal(Literal::Number(BigDecimal::from_str("3").unwrap())),
972 }
973 .to_sql();
974 assert_eq!(actual, expected);
975
976 let actual = r#""GLUE_TABLES" AS "glue""#;
977 let expected = TableFactor::Dictionary {
978 dict: Dictionary::GlueTables,
979 alias: TableAlias {
980 name: "glue".to_owned(),
981 columns: Vec::new(),
982 },
983 }
984 .to_sql();
985 assert_eq!(actual, expected);
986 }
987
988 #[test]
989 fn to_sql_unquoted_table_factor() {
990 let actual = "FOO AS F";
991 let expected = TableFactor::Table {
992 name: "FOO".to_owned(),
993 alias: Some(TableAlias {
994 name: "F".to_owned(),
995 columns: Vec::new(),
996 }),
997 }
998 .to_sql_unquoted();
999 assert_eq!(actual, expected);
1000
1001 let actual = "(SELECT * FROM FOO) AS F";
1002 let expected = TableFactor::Derived {
1003 subquery: Query {
1004 body: SetExpr::Select(Box::new(Select {
1005 distinct: false,
1006 projection: Projection::SelectItems(vec![SelectItem::Wildcard]),
1007 from: TableWithJoins {
1008 relation: TableFactor::Table {
1009 name: "FOO".to_owned(),
1010 alias: None,
1011 },
1012 joins: Vec::new(),
1013 },
1014 selection: None,
1015 group_by: Vec::new(),
1016 having: None,
1017 })),
1018 order_by: Vec::new(),
1019 limit: None,
1020 offset: None,
1021 },
1022 alias: TableAlias {
1023 name: "F".to_owned(),
1024 columns: Vec::new(),
1025 },
1026 }
1027 .to_sql_unquoted();
1028 assert_eq!(actual, expected);
1029
1030 let actual = "SERIES(3) AS S";
1031 let expected = TableFactor::Series {
1032 alias: TableAlias {
1033 name: "S".to_owned(),
1034 columns: Vec::new(),
1035 },
1036 size: Expr::Literal(Literal::Number(BigDecimal::from_str("3").unwrap())),
1037 }
1038 .to_sql_unquoted();
1039 assert_eq!(actual, expected);
1040
1041 let actual = "GLUE_TABLES AS glue";
1042 let expected = TableFactor::Dictionary {
1043 dict: Dictionary::GlueTables,
1044 alias: TableAlias {
1045 name: "glue".to_owned(),
1046 columns: Vec::new(),
1047 },
1048 }
1049 .to_sql_unquoted();
1050 assert_eq!(actual, expected);
1051 }
1052
1053 #[test]
1054 fn to_sql_table_alias() {
1055 let actual = r#"AS "F""#;
1056 let expected = TableAlias {
1057 name: "F".to_owned(),
1058 columns: Vec::new(),
1059 }
1060 .to_sql();
1061 assert_eq!(actual, expected);
1062 }
1063
1064 #[test]
1065 fn to_sql_unquoted_table_alias() {
1066 let actual = "AS F";
1067 let expected = TableAlias {
1068 name: "F".to_owned(),
1069 columns: Vec::new(),
1070 }
1071 .to_sql_unquoted();
1072 assert_eq!(actual, expected);
1073 }
1074
1075 #[test]
1076 fn to_sql_join() {
1077 let actual = r#"INNER JOIN "PlayerItem""#;
1078 let expected = Join {
1079 relation: TableFactor::Table {
1080 name: "PlayerItem".to_owned(),
1081 alias: None,
1082 },
1083 join_operator: JoinOperator::Inner(JoinConstraint::None),
1084 }
1085 .to_sql();
1086 assert_eq!(actual, expected);
1087
1088 let actual = r#"INNER JOIN "PlayerItem" ON "PlayerItem"."user_id" = "Player"."id""#;
1089 let expected = Join {
1090 relation: TableFactor::Table {
1091 name: "PlayerItem".to_owned(),
1092 alias: None,
1093 },
1094 join_operator: JoinOperator::Inner(JoinConstraint::On(expr(
1095 r#""PlayerItem"."user_id" = "Player"."id""#,
1096 ))),
1097 }
1098 .to_sql();
1099 assert_eq!(actual, expected);
1100
1101 let actual = r#"LEFT OUTER JOIN "PlayerItem""#;
1102 let expected = Join {
1103 relation: TableFactor::Table {
1104 name: "PlayerItem".to_owned(),
1105 alias: None,
1106 },
1107 join_operator: JoinOperator::LeftOuter(JoinConstraint::None),
1108 }
1109 .to_sql();
1110 assert_eq!(actual, expected);
1111
1112 let actual = r#"LEFT OUTER JOIN "PlayerItem" ON "PlayerItem"."user_id" = "Player"."id""#;
1113 let expected = Join {
1114 relation: TableFactor::Table {
1115 name: "PlayerItem".to_owned(),
1116 alias: None,
1117 },
1118 join_operator: JoinOperator::LeftOuter(JoinConstraint::On(expr(
1119 r#""PlayerItem"."user_id" = "Player"."id""#,
1120 ))),
1121 }
1122 .to_sql();
1123 assert_eq!(actual, expected);
1124
1125 let actual = r#"LEFT OUTER JOIN "PlayerItem" ON "PlayerItem"."age" > "Player"."age" AND "PlayerItem"."user_id" = "Player"."id" AND "PlayerItem"."amount" > 10 AND "PlayerItem"."amount" * 3 <= 2"#;
1126 let expected = Join {
1127 relation: TableFactor::Table {
1128 name: "PlayerItem".to_owned(),
1129 alias: None,
1130 },
1131 join_operator: JoinOperator::LeftOuter(JoinConstraint::On(expr(
1132 r#""PlayerItem"."age" > "Player"."age" AND "PlayerItem"."user_id" = "Player"."id" AND "PlayerItem"."amount" > 10 AND "PlayerItem"."amount" * 3 <= 2"#,
1133 ))),
1134 }
1135 .to_sql();
1136 assert_eq!(actual, expected);
1137 }
1138
1139 #[test]
1140 fn to_sql_unquoted_join() {
1141 let actual = "INNER JOIN PlayerItem";
1142 let expected = Join {
1143 relation: TableFactor::Table {
1144 name: "PlayerItem".to_owned(),
1145 alias: None,
1146 },
1147 join_operator: JoinOperator::Inner(JoinConstraint::None),
1148 }
1149 .to_sql_unquoted();
1150 assert_eq!(actual, expected);
1151
1152 let actual = "INNER JOIN PlayerItem ON PlayerItem.user_id = Player.id AND PlayerItem.group_id = Player.group_id";
1153 let expected = Join {
1154 relation: TableFactor::Table {
1155 name: "PlayerItem".to_owned(),
1156 alias: None,
1157 },
1158 join_operator: JoinOperator::Inner(JoinConstraint::On(expr(
1159 "PlayerItem.user_id = Player.id AND PlayerItem.group_id = Player.group_id",
1160 ))),
1161 }
1162 .to_sql_unquoted();
1163 assert_eq!(actual, expected);
1164
1165 let actual = "LEFT OUTER JOIN PlayerItem";
1166 let expected = Join {
1167 relation: TableFactor::Table {
1168 name: "PlayerItem".to_owned(),
1169 alias: None,
1170 },
1171 join_operator: JoinOperator::LeftOuter(JoinConstraint::None),
1172 }
1173 .to_sql_unquoted();
1174 assert_eq!(actual, expected);
1175
1176 let actual = "LEFT OUTER JOIN PlayerItem ON PlayerItem.user_id = Player.id";
1177 let expected = Join {
1178 relation: TableFactor::Table {
1179 name: "PlayerItem".to_owned(),
1180 alias: None,
1181 },
1182 join_operator: JoinOperator::LeftOuter(JoinConstraint::On(expr(
1183 "PlayerItem.user_id = Player.id",
1184 ))),
1185 }
1186 .to_sql_unquoted();
1187 assert_eq!(actual, expected);
1188
1189 let actual = "LEFT OUTER JOIN PlayerItem ON PlayerItem.age > Player.age AND PlayerItem.user_id = Player.id AND PlayerItem.amount > 10 AND PlayerItem.amount * 3 <= 2";
1190 let expected = Join {
1191 relation: TableFactor::Table {
1192 name: "PlayerItem".to_owned(),
1193 alias: None,
1194 },
1195 join_operator: JoinOperator::LeftOuter(JoinConstraint::On(expr(
1196 "PlayerItem.age > Player.age AND PlayerItem.user_id = Player.id AND PlayerItem.amount > 10 AND PlayerItem.amount * 3 <= 2",
1197 ))),
1198 }
1199 .to_sql_unquoted();
1200 assert_eq!(actual, expected);
1201 }
1202
1203 #[test]
1204 fn to_sql_order_by_expr() {
1205 let actual = r#""foo" ASC"#;
1206 let expected = OrderByExpr {
1207 expr: Expr::Identifier("foo".to_owned()),
1208 asc: Some(true),
1209 }
1210 .to_sql();
1211 assert_eq!(actual, expected);
1212
1213 let actual = r#""foo" DESC"#;
1214 let expected = OrderByExpr {
1215 expr: Expr::Identifier("foo".to_owned()),
1216 asc: Some(false),
1217 }
1218 .to_sql();
1219 assert_eq!(actual, expected);
1220
1221 let actual = r#""foo""#;
1222 let expected = OrderByExpr {
1223 expr: Expr::Identifier("foo".to_owned()),
1224 asc: None,
1225 }
1226 .to_sql();
1227 assert_eq!(actual, expected);
1228 }
1229
1230 #[test]
1231 fn to_sql_unquoted_order_by_expr() {
1232 let actual = "foo ASC";
1233 let expected = OrderByExpr {
1234 expr: Expr::Identifier("foo".to_owned()),
1235 asc: Some(true),
1236 }
1237 .to_sql_unquoted();
1238 assert_eq!(actual, expected);
1239
1240 let actual = "foo DESC";
1241 let expected = OrderByExpr {
1242 expr: Expr::Identifier("foo".to_owned()),
1243 asc: Some(false),
1244 }
1245 .to_sql_unquoted();
1246 assert_eq!(actual, expected);
1247
1248 let actual = "foo";
1249 let expected = OrderByExpr {
1250 expr: Expr::Identifier("foo".to_owned()),
1251 asc: None,
1252 }
1253 .to_sql_unquoted();
1254 assert_eq!(actual, expected);
1255 }
1256}