gluesql_core/ast_builder/select/
order_by.rs

1use {
2    super::{Prebuild, ValuesNode},
3    crate::{
4        ast::Query,
5        ast_builder::{
6            ExprNode, FilterNode, GroupByNode, HashJoinNode, HavingNode, JoinConstraintNode,
7            JoinNode, LimitNode, OffsetNode, OrderByExprList, ProjectNode, QueryNode, SelectNode,
8            TableFactorNode,
9        },
10        result::Result,
11    },
12};
13
14#[derive(Clone, Debug)]
15pub enum PrevNode<'a> {
16    Select(SelectNode<'a>),
17    Having(HavingNode<'a>),
18    GroupBy(GroupByNode<'a>),
19    Filter(FilterNode<'a>),
20    JoinNode(JoinNode<'a>),
21    JoinConstraint(JoinConstraintNode<'a>),
22    HashJoin(Box<HashJoinNode<'a>>),
23    ProjectNode(Box<ProjectNode<'a>>),
24    Values(ValuesNode<'a>),
25}
26
27impl<'a> Prebuild<Query> for PrevNode<'a> {
28    fn prebuild(self) -> Result<Query> {
29        match self {
30            Self::Select(node) => node.prebuild(),
31            Self::Having(node) => node.prebuild(),
32            Self::GroupBy(node) => node.prebuild(),
33            Self::Filter(node) => node.prebuild(),
34            Self::JoinNode(node) => node.prebuild(),
35            Self::JoinConstraint(node) => node.prebuild(),
36            Self::HashJoin(node) => node.prebuild(),
37            Self::ProjectNode(node) => node.prebuild(),
38            Self::Values(node) => node.prebuild(),
39        }
40    }
41}
42
43impl<'a> From<SelectNode<'a>> for PrevNode<'a> {
44    fn from(node: SelectNode<'a>) -> Self {
45        PrevNode::Select(node)
46    }
47}
48
49impl<'a> From<HavingNode<'a>> for PrevNode<'a> {
50    fn from(node: HavingNode<'a>) -> Self {
51        PrevNode::Having(node)
52    }
53}
54
55impl<'a> From<GroupByNode<'a>> for PrevNode<'a> {
56    fn from(node: GroupByNode<'a>) -> Self {
57        PrevNode::GroupBy(node)
58    }
59}
60
61impl<'a> From<FilterNode<'a>> for PrevNode<'a> {
62    fn from(node: FilterNode<'a>) -> Self {
63        PrevNode::Filter(node)
64    }
65}
66
67impl<'a> From<JoinNode<'a>> for PrevNode<'a> {
68    fn from(node: JoinNode<'a>) -> Self {
69        PrevNode::JoinNode(node)
70    }
71}
72
73impl<'a> From<JoinConstraintNode<'a>> for PrevNode<'a> {
74    fn from(node: JoinConstraintNode<'a>) -> Self {
75        PrevNode::JoinConstraint(node)
76    }
77}
78
79impl<'a> From<HashJoinNode<'a>> for PrevNode<'a> {
80    fn from(node: HashJoinNode<'a>) -> Self {
81        PrevNode::HashJoin(Box::new(node))
82    }
83}
84
85impl<'a> From<ProjectNode<'a>> for PrevNode<'a> {
86    fn from(node: ProjectNode<'a>) -> Self {
87        PrevNode::ProjectNode(Box::new(node))
88    }
89}
90
91impl<'a> From<ValuesNode<'a>> for PrevNode<'a> {
92    fn from(node: ValuesNode<'a>) -> Self {
93        PrevNode::Values(node)
94    }
95}
96
97#[derive(Clone, Debug)]
98pub struct OrderByNode<'a> {
99    prev_node: PrevNode<'a>,
100    expr_list: OrderByExprList<'a>,
101}
102
103impl<'a> OrderByNode<'a> {
104    pub fn new<N: Into<PrevNode<'a>>, T: Into<OrderByExprList<'a>>>(
105        prev_node: N,
106        expr_list: T,
107    ) -> Self {
108        Self {
109            prev_node: prev_node.into(),
110            expr_list: expr_list.into(),
111        }
112    }
113
114    pub fn offset<T: Into<ExprNode<'a>>>(self, expr: T) -> OffsetNode<'a> {
115        OffsetNode::new(self, expr)
116    }
117
118    pub fn limit<T: Into<ExprNode<'a>>>(self, expr: T) -> LimitNode<'a> {
119        LimitNode::new(self, expr)
120    }
121
122    pub fn alias_as(self, table_alias: &'a str) -> TableFactorNode {
123        QueryNode::OrderByNode(self).alias_as(table_alias)
124    }
125}
126
127impl<'a> Prebuild<Query> for OrderByNode<'a> {
128    fn prebuild(self) -> Result<Query> {
129        let mut node_data = self.prev_node.prebuild()?;
130        node_data.order_by = self.expr_list.try_into()?;
131
132        Ok(node_data)
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    use {
139        crate::{
140            ast::{
141                Join, JoinConstraint, JoinExecutor, JoinOperator, Query, Select, SetExpr,
142                Statement, TableFactor, TableWithJoins,
143            },
144            ast_builder::{col, table, test, Build, ExprNode, OrderByExprList, SelectItemList},
145        },
146        pretty_assertions::assert_eq,
147    };
148
149    #[test]
150    fn order_by() {
151        // select node -> order by node(exprs vec) -> build
152        let actual = table("Foo").select().order_by(vec!["name desc"]).build();
153        let expected = "
154            SELECT * FROM Foo
155            ORDER BY name DESC
156        ";
157        test(actual, expected);
158
159        // select node -> order by node(exprs string) -> build
160        let actual = table("Bar")
161            .select()
162            .order_by("name asc, id desc, country")
163            .offset(10)
164            .build();
165        let expected = "
166                SELECT * FROM Bar 
167                ORDER BY name asc, id desc, country 
168                OFFSET 10
169            ";
170        test(actual, expected);
171
172        // group by node -> order by node -> build
173        let actual = table("Bar")
174            .select()
175            .group_by("name")
176            .order_by(vec!["id desc"])
177            .build();
178        let expected = "
179                SELECT * FROM Bar 
180                GROUP BY name 
181                ORDER BY id desc
182            ";
183        test(actual, expected);
184
185        // having node -> order by node -> build
186        let actual = table("Foo")
187            .select()
188            .group_by("city")
189            .having("COUNT(name) < 100")
190            .order_by(ExprNode::Identifier("name".into()))
191            .offset(2)
192            .limit(3)
193            .build();
194        let expected = "
195            SELECT * FROM Foo
196            GROUP BY city
197            HAVING COUNT(name) < 100
198            ORDER BY name
199            OFFSET 2
200            LIMIT 3
201        ";
202        test(actual, expected);
203
204        // filter node -> order by node -> build
205        let actual = table("Foo")
206            .select()
207            .filter("id > 10")
208            .filter("id < 20")
209            .order_by("id asc")
210            .build();
211        let expected = "
212            SELECT * FROM Foo
213            WHERE id > 10 AND id < 20
214            ORDER BY id ASC";
215        test(actual, expected);
216
217        // project node -> order by node -> build
218        let actual = table("Foo")
219            .select()
220            .project("id")
221            .order_by("id asc")
222            .build();
223        let expected = "SELECT id FROM Foo ORDER BY id asc";
224        test(actual, expected);
225
226        // join node -> order by node -> build
227        let actual = table("Foo")
228            .select()
229            .join("Bar")
230            .order_by("Foo.id desc")
231            .build();
232        let expected = "
233            SELECT * FROM Foo
234            JOIN Bar
235            ORDER BY Foo.id desc
236        ";
237        test(actual, expected);
238
239        // join constraint node -> order by node -> build
240        let actual = table("Foo")
241            .select()
242            .join("Bar")
243            .on("Foo.id = Bar.id")
244            .order_by("Foo.id desc")
245            .build();
246        let expected = "
247            SELECT * FROM Foo
248            JOIN Bar ON Foo.id = Bar.id
249            ORDER BY Foo.id desc
250        ";
251        test(actual, expected);
252
253        // hash join node -> order by node -> build
254        let actual = table("Player")
255            .select()
256            .join("PlayerItem")
257            .hash_executor("PlayerItem.user_id", "Player.id")
258            .order_by("Player.score DESC")
259            .build();
260        let expected = {
261            let join = Join {
262                relation: TableFactor::Table {
263                    name: "PlayerItem".to_owned(),
264                    alias: None,
265                    index: None,
266                },
267                join_operator: JoinOperator::Inner(JoinConstraint::None),
268                join_executor: JoinExecutor::Hash {
269                    key_expr: col("PlayerItem.user_id").try_into().unwrap(),
270                    value_expr: col("Player.id").try_into().unwrap(),
271                    where_clause: None,
272                },
273            };
274            let select = Select {
275                projection: SelectItemList::from("*").try_into().unwrap(),
276                from: TableWithJoins {
277                    relation: TableFactor::Table {
278                        name: "Player".to_owned(),
279                        alias: None,
280                        index: None,
281                    },
282                    joins: vec![join],
283                },
284                selection: None,
285                group_by: Vec::new(),
286                having: None,
287            };
288
289            Ok(Statement::Query(Query {
290                body: SetExpr::Select(Box::new(select)),
291                order_by: OrderByExprList::from("Player.score DESC")
292                    .try_into()
293                    .unwrap(),
294                limit: None,
295                offset: None,
296            }))
297        };
298        assert_eq!(actual, expected);
299
300        // select -> order by node -> derived subquery
301        let actual = table("Foo")
302            .select()
303            .order_by(vec!["name desc"])
304            .alias_as("Sub")
305            .select()
306            .build();
307        let expected = "
308            SELECT * FROM (
309                SELECT * FROM Foo
310                ORDER BY name DESC
311            ) Sub
312        ";
313        test(actual, expected);
314    }
315}