vantage_sql/primitives/
union.rs1use std::fmt::{Debug, Display};
2
3use vantage_expressions::{Expression, Expressive, ExpressiveEnum};
4
5#[derive(Debug, Clone)]
6enum CompoundOp {
7 Union,
8 UnionAll,
9 Except,
10 Intersect,
11}
12
13impl CompoundOp {
14 fn as_str(&self) -> &'static str {
15 match self {
16 CompoundOp::Union => " UNION ",
17 CompoundOp::UnionAll => " UNION ALL ",
18 CompoundOp::Except => " EXCEPT ",
19 CompoundOp::Intersect => " INTERSECT ",
20 }
21 }
22}
23
24#[derive(Debug, Clone)]
34pub struct Union<T: Debug + Display + Clone> {
35 first: Expression<T>,
36 rest: Vec<(CompoundOp, Expression<T>)>,
37}
38
39impl<T: Debug + Display + Clone> Union<T> {
40 pub fn new(first: impl Expressive<T>) -> Self {
41 Self {
42 first: first.expr(),
43 rest: Vec::new(),
44 }
45 }
46
47 pub fn union(mut self, query: impl Expressive<T>) -> Self {
48 self.rest.push((CompoundOp::Union, query.expr()));
49 self
50 }
51
52 pub fn union_all(mut self, query: impl Expressive<T>) -> Self {
53 self.rest.push((CompoundOp::UnionAll, query.expr()));
54 self
55 }
56
57 pub fn except(mut self, query: impl Expressive<T>) -> Self {
58 self.rest.push((CompoundOp::Except, query.expr()));
59 self
60 }
61
62 pub fn intersect(mut self, query: impl Expressive<T>) -> Self {
63 self.rest.push((CompoundOp::Intersect, query.expr()));
64 self
65 }
66}
67
68impl<T: Debug + Display + Clone> Expressive<T> for Union<T> {
69 fn expr(&self) -> Expression<T> {
70 let mut params = vec![ExpressiveEnum::Nested(self.first.clone())];
71 let mut template = String::from("{}");
72
73 for (op, query) in &self.rest {
74 template.push_str(op.as_str());
75 template.push_str("{}");
76 params.push(ExpressiveEnum::Nested(query.clone()));
77 }
78
79 Expression::new(template, params)
80 }
81}