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