qail_core/ast/cmd/
advanced.rs

1//! Advanced query builder methods.
2//!
3//! DISTINCT ON, HAVING, row locks, table sampling, JOIN aliases, etc.
4
5use crate::ast::{
6    Cage, CageKind, Condition, Expr, Join, JoinKind, LockMode, LogicalOp, Operator,
7    OverridingKind, Qail, SampleMethod, SortOrder, Value, CTEDef,
8};
9
10impl Qail {
11    pub fn column_expr(mut self, expr: Expr) -> Self {
12        self.columns.push(expr);
13        self
14    }
15
16    pub fn columns_expr<I>(mut self, exprs: I) -> Self
17    where
18        I: IntoIterator<Item = Expr>,
19    {
20        self.columns.extend(exprs);
21        self
22    }
23
24    pub fn distinct_on<I, S>(mut self, cols: I) -> Self
25    where
26        I: IntoIterator<Item = S>,
27        S: AsRef<str>,
28    {
29        self.distinct_on = cols
30            .into_iter()
31            .map(|c| Expr::Named(c.as_ref().to_string()))
32            .collect();
33        self
34    }
35
36    pub fn distinct_on_expr<I>(mut self, exprs: I) -> Self
37    where
38        I: IntoIterator<Item = Expr>,
39    {
40        self.distinct_on = exprs.into_iter().collect();
41        self
42    }
43
44    pub fn filter_cond(mut self, condition: Condition) -> Self {
45        let filter_cage = self
46            .cages
47            .iter_mut()
48            .find(|c| matches!(c.kind, CageKind::Filter));
49
50        if let Some(cage) = filter_cage {
51            cage.conditions.push(condition);
52        } else {
53            self.cages.push(Cage {
54                kind: CageKind::Filter,
55                conditions: vec![condition],
56                logical_op: LogicalOp::And,
57            });
58        }
59        self
60    }
61
62    pub fn having_cond(mut self, condition: Condition) -> Self {
63        self.having.push(condition);
64        self
65    }
66
67    pub fn having_conds(mut self, conditions: impl IntoIterator<Item = Condition>) -> Self {
68        self.having.extend(conditions);
69        self
70    }
71
72    pub fn with_ctes(mut self, ctes: Vec<CTEDef>) -> Self {
73        self.ctes = ctes;
74        self
75    }
76
77    pub fn update_from<I, S>(mut self, tables: I) -> Self
78    where
79        I: IntoIterator<Item = S>,
80        S: AsRef<str>,
81    {
82        self.from_tables.extend(tables.into_iter().map(|s| s.as_ref().to_string()));
83        self
84    }
85
86    pub fn delete_using<I, S>(mut self, tables: I) -> Self
87    where
88        I: IntoIterator<Item = S>,
89        S: AsRef<str>,
90    {
91        self.using_tables.extend(tables.into_iter().map(|s| s.as_ref().to_string()));
92        self
93    }
94
95    pub fn for_update(mut self) -> Self {
96        self.lock_mode = Some(LockMode::Update);
97        self
98    }
99
100    pub fn for_no_key_update(mut self) -> Self {
101        self.lock_mode = Some(LockMode::NoKeyUpdate);
102        self
103    }
104
105    pub fn for_share(mut self) -> Self {
106        self.lock_mode = Some(LockMode::Share);
107        self
108    }
109
110    pub fn for_key_share(mut self) -> Self {
111        self.lock_mode = Some(LockMode::KeyShare);
112        self
113    }
114
115    pub fn fetch_first(mut self, count: u64) -> Self {
116        self.fetch = Some((count, false));
117        self
118    }
119
120    pub fn fetch_with_ties(mut self, count: u64) -> Self {
121        self.fetch = Some((count, true));
122        self
123    }
124
125    pub fn default_values(mut self) -> Self {
126        self.default_values = true;
127        self
128    }
129
130    pub fn overriding_system_value(mut self) -> Self {
131        self.overriding = Some(OverridingKind::SystemValue);
132        self
133    }
134
135    pub fn overriding_user_value(mut self) -> Self {
136        self.overriding = Some(OverridingKind::UserValue);
137        self
138    }
139
140    pub fn tablesample_bernoulli(mut self, percent: f64) -> Self {
141        self.sample = Some((SampleMethod::Bernoulli, percent, None));
142        self
143    }
144
145    pub fn tablesample_system(mut self, percent: f64) -> Self {
146        self.sample = Some((SampleMethod::System, percent, None));
147        self
148    }
149
150    pub fn repeatable(mut self, seed: u64) -> Self {
151        if let Some((method, percent, _)) = self.sample {
152            self.sample = Some((method, percent, Some(seed)));
153        }
154        self
155    }
156
157    pub fn only(mut self) -> Self {
158        self.only_table = true;
159        self
160    }
161
162    pub fn left_join_as(
163        mut self,
164        table: impl AsRef<str>,
165        alias: impl AsRef<str>,
166        left_col: impl AsRef<str>,
167        right_col: impl AsRef<str>,
168    ) -> Self {
169        self.joins.push(Join {
170            kind: JoinKind::Left,
171            table: format!("{} {}", table.as_ref(), alias.as_ref()),
172            on: Some(vec![Condition {
173                left: Expr::Named(left_col.as_ref().to_string()),
174                op: Operator::Eq,
175                value: Value::Column(right_col.as_ref().to_string()),
176                is_array_unnest: false,
177            }]),
178            on_true: false,
179        });
180        self
181    }
182
183    pub fn inner_join_as(
184        mut self,
185        table: impl AsRef<str>,
186        alias: impl AsRef<str>,
187        left_col: impl AsRef<str>,
188        right_col: impl AsRef<str>,
189    ) -> Self {
190        self.joins.push(Join {
191            kind: JoinKind::Inner,
192            table: format!("{} {}", table.as_ref(), alias.as_ref()),
193            on: Some(vec![Condition {
194                left: Expr::Named(left_col.as_ref().to_string()),
195                op: Operator::Eq,
196                value: Value::Column(right_col.as_ref().to_string()),
197                is_array_unnest: false,
198            }]),
199            on_true: false,
200        });
201        self
202    }
203
204    pub fn table_alias(mut self, alias: impl AsRef<str>) -> Self {
205        self.table = format!("{} {}", self.table, alias.as_ref());
206        self
207    }
208
209    pub fn order_by_expr(mut self, expr: Expr, order: SortOrder) -> Self {
210        self.cages.push(Cage {
211            kind: CageKind::Sort(order),
212            conditions: vec![Condition {
213                left: expr,
214                op: Operator::Eq,
215                value: Value::Null,
216                is_array_unnest: false,
217            }],
218            logical_op: LogicalOp::And,
219        });
220        self
221    }
222
223    pub fn group_by_expr<I>(mut self, exprs: I) -> Self
224    where
225        I: IntoIterator<Item = Expr>,
226    {
227        let conditions: Vec<Condition> = exprs
228            .into_iter()
229            .map(|e| Condition {
230                left: e,
231                op: Operator::Eq,
232                value: Value::Null,
233                is_array_unnest: false,
234            })
235            .collect();
236
237        self.cages.push(Cage {
238            kind: CageKind::Partition,
239            conditions,
240            logical_op: LogicalOp::And,
241        });
242        self
243    }
244}