gluesql_core/query_builder/select/
offset_limit.rs1use {
2 super::{BuildQuery, BuildQueryPlan},
3 crate::{
4 ast::Query,
5 plan::{LimitInputPlan, LimitPlan, OffsetPlan, QueryPlan},
6 query_builder::{ExprNode, OffsetNode, QueryNode, SourceNode},
7 result::Result,
8 },
9};
10
11#[derive(Clone, Debug)]
12pub(super) enum PrevNode<'a> {
13 Offset(OffsetNode<'a>),
14}
15
16impl PrevNode<'_> {
17 fn build_offset_plan(self) -> Result<OffsetPlan> {
18 match self {
19 Self::Offset(node) => node.build_offset_plan(),
20 }
21 }
22}
23
24impl BuildQuery for PrevNode<'_> {
25 fn build_query(self) -> Result<Query> {
26 match self {
27 Self::Offset(node) => node.build_query(),
28 }
29 }
30}
31
32impl<'a> From<OffsetNode<'a>> for PrevNode<'a> {
33 fn from(node: OffsetNode<'a>) -> Self {
34 PrevNode::Offset(node)
35 }
36}
37
38#[derive(Clone, Debug)]
39pub struct OffsetLimitNode<'a> {
40 prev_node: PrevNode<'a>,
41 expr: ExprNode<'a>,
42}
43
44impl<'a> OffsetLimitNode<'a> {
45 pub(super) fn new<N: Into<PrevNode<'a>>, T: Into<ExprNode<'a>>>(prev_node: N, expr: T) -> Self {
46 Self {
47 prev_node: prev_node.into(),
48 expr: expr.into(),
49 }
50 }
51
52 pub fn alias_as(self, table_alias: &'a str) -> SourceNode<'a> {
53 QueryNode::OffsetLimitNode(self).alias_as(table_alias)
54 }
55}
56
57impl BuildQueryPlan for OffsetLimitNode<'_> {
58 fn build_query_plan(self) -> Result<QueryPlan> {
59 let count = self.expr.build_expr_plan()?;
60 self.prev_node.build_offset_plan().map(|offset| {
61 QueryPlan::Limit(LimitPlan {
62 input: LimitInputPlan::Offset(offset),
63 count,
64 })
65 })
66 }
67}
68
69impl BuildQuery for OffsetLimitNode<'_> {
70 fn build_query(self) -> Result<Query> {
71 let mut node_data = self.prev_node.build_query()?;
72 node_data.limit = Some(self.expr.build_expr()?);
73
74 Ok(node_data)
75 }
76}
77
78#[cfg(test)]
79mod tests {
80 use crate::query_builder::{table, test_query_builder};
81
82 #[test]
83 fn offset_limit() {
84 let actual = table("Bar")
86 .select()
87 .group_by("city")
88 .having("COUNT(name) < 100")
89 .offset(1)
90 .limit(3);
91 let expected = "
92 SELECT * FROM Bar
93 GROUP BY city
94 HAVING COUNT(name) < 100
95 OFFSET 1
96 LIMIT 3;
97 ";
98 test_query_builder(actual, expected);
99
100 let actual = table("Bar")
102 .select()
103 .group_by("city")
104 .having("COUNT(name) < 100")
105 .project("city")
106 .offset(1)
107 .limit(3);
108 let expected = "
109 SELECT city FROM Bar
110 GROUP BY city
111 HAVING COUNT(name) < 100
112 OFFSET 1
113 LIMIT 3;
114 ";
115 test_query_builder(actual, expected);
116
117 let actual = table("Bar")
119 .select()
120 .group_by("city")
121 .having("COUNT(name) < 100")
122 .offset(1)
123 .limit(3)
124 .alias_as("Sub")
125 .select();
126 let expected = "
127 SELECT * FROM (
128 SELECT * FROM Bar
129 GROUP BY city
130 HAVING COUNT(name) < 100
131 OFFSET 1
132 LIMIT 3
133 ) Sub
134 ";
135 test_query_builder(actual, expected);
136 }
137}