Skip to main content

vantage_sql/primitives/
union.rs

1use 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/// Compound query: combines multiple SELECT statements with UNION / UNION ALL / EXCEPT / INTERSECT.
25///
26/// # Examples
27///
28/// ```ignore
29/// Union::new(first_select)
30///     .union_all(second_select)
31///     .except(third_select)
32/// ```
33#[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}