gluesql_core/ast_builder/select/
root.rs1use {
2 super::{Prebuild, join::JoinOperatorType},
3 crate::{
4 ast::{Expr, Literal, Query, Select, SelectItem, TableAlias, TableFactor, TableWithJoins},
5 ast_builder::{
6 ExprList, ExprNode, FilterNode, GroupByNode, JoinNode, LimitNode, OffsetNode,
7 OrderByExprList, OrderByNode, ProjectNode, QueryNode, SelectItemList, TableFactorNode,
8 table_factor::TableType,
9 },
10 result::Result,
11 translate::alias_or_name,
12 },
13};
14
15#[derive(Clone, Debug)]
16pub struct SelectNode<'a> {
17 table_node: TableFactorNode<'a>,
18 distinct: bool,
19}
20
21impl<'a> SelectNode<'a> {
22 pub fn new(table_node: TableFactorNode<'a>) -> Self {
23 Self {
24 table_node,
25 distinct: false,
26 }
27 }
28
29 #[must_use]
30 pub fn distinct(mut self) -> Self {
31 self.distinct = true;
32 self
33 }
34
35 pub fn filter<T: Into<ExprNode<'a>>>(self, expr: T) -> FilterNode<'a> {
36 FilterNode::new(self, expr)
37 }
38
39 pub fn group_by<T: Into<ExprList<'a>>>(self, expr_list: T) -> GroupByNode<'a> {
40 GroupByNode::new(self, expr_list)
41 }
42
43 pub fn offset<T: Into<ExprNode<'a>>>(self, expr: T) -> OffsetNode<'a> {
44 OffsetNode::new(self, expr)
45 }
46
47 pub fn limit<T: Into<ExprNode<'a>>>(self, expr: T) -> LimitNode<'a> {
48 LimitNode::new(self, expr)
49 }
50
51 pub fn project<T: Into<SelectItemList<'a>>>(self, select_items: T) -> ProjectNode<'a> {
52 ProjectNode::new(self, select_items)
53 }
54
55 pub fn order_by<T: Into<OrderByExprList<'a>>>(self, order_by_exprs: T) -> OrderByNode<'a> {
56 OrderByNode::new(self, order_by_exprs)
57 }
58
59 pub fn join(self, table_name: &str) -> JoinNode<'a> {
60 JoinNode::new(self, table_name.to_owned(), None, JoinOperatorType::Inner)
61 }
62
63 pub fn join_as(self, table_name: &str, alias: &str) -> JoinNode<'a> {
64 JoinNode::new(
65 self,
66 table_name.to_owned(),
67 Some(alias.to_owned()),
68 JoinOperatorType::Inner,
69 )
70 }
71
72 pub fn left_join(self, table_name: &str) -> JoinNode<'a> {
73 JoinNode::new(self, table_name.to_owned(), None, JoinOperatorType::Left)
74 }
75
76 pub fn left_join_as(self, table_name: &str, alias: &str) -> JoinNode<'a> {
77 JoinNode::new(
78 self,
79 table_name.to_owned(),
80 Some(alias.to_owned()),
81 JoinOperatorType::Left,
82 )
83 }
84
85 pub fn alias_as(self, table_alias: &'a str) -> TableFactorNode<'a> {
86 QueryNode::SelectNode(self).alias_as(table_alias)
87 }
88}
89
90impl Prebuild<Select> for SelectNode<'_> {
91 fn prebuild(self) -> Result<Select> {
92 let alias = self.table_node.table_alias.map(|name| TableAlias {
93 name,
94 columns: Vec::new(),
95 });
96
97 let index = match self.table_node.index {
98 Some(index) => Some(index.prebuild()?),
99 None => None,
100 };
101
102 let relation = match self.table_node.table_type {
103 TableType::Table => TableFactor::Table {
104 name: self.table_node.table_name,
105 alias,
106 index,
107 },
108 TableType::Dictionary(dict) => TableFactor::Dictionary {
109 dict,
110 alias: alias_or_name(alias, self.table_node.table_name),
111 },
112 TableType::Series(args) => TableFactor::Series {
113 alias: alias_or_name(alias, self.table_node.table_name),
114 size: args.try_into()?,
115 },
116 TableType::Derived { subquery, alias } => TableFactor::Derived {
117 subquery: Query::try_from(*subquery)?,
118 alias: TableAlias {
119 name: alias,
120 columns: Vec::new(),
121 },
122 },
123 };
124
125 let from = TableWithJoins {
126 relation,
127 joins: Vec::new(),
128 };
129
130 Ok(Select {
131 distinct: self.distinct,
132 projection: vec![SelectItem::Wildcard],
133 from,
134 selection: None,
135 group_by: Vec::new(),
136 having: None,
137 })
138 }
139}
140
141pub fn select<'a>() -> SelectNode<'a> {
142 SelectNode {
143 distinct: false,
144 table_node: TableFactorNode {
145 table_name: "Series".to_owned(),
146 table_type: TableType::Series(Expr::Literal(Literal::Number(1.into())).into()),
147 table_alias: None,
148 index: None,
149 },
150 }
151}
152
153#[cfg(test)]
154mod tests {
155 use crate::ast_builder::{Build, select, table, test};
156
157 #[test]
158 fn select_root() {
159 let actual = table("App").select().build();
161 let expected = "SELECT * FROM App";
162 test(&actual, expected);
163
164 let actual = table("Item").alias_as("i").select().build();
165 let expected = "SELECT * FROM Item i";
166 test(&actual, expected);
167
168 let actual = table("App").select().alias_as("Sub").select().build();
170 let expected = "SELECT * FROM (SELECT * FROM App) Sub";
171 test(&actual, expected);
172
173 let actual = select().project("1 + 1").build();
175 let expected = "SELECT 1 + 1";
176 test(&actual, expected);
177
178 let actual = table("User").select().distinct().build();
180 let expected = "SELECT DISTINCT * FROM User";
181 test(&actual, expected);
182
183 let actual = table("Item").select().distinct().project("name").build();
185 let expected = "SELECT DISTINCT name FROM Item";
186 test(&actual, expected);
187 }
188}