chain_builder/query/
common.rs

1//! Common query functionality for WHERE clauses and other query parts
2
3use crate::query::QueryBuilder;
4use crate::types::Common;
5use serde_json::Value;
6
7fn build_placeholders(len: usize) -> String {
8    if len == 0 {
9        return String::new();
10    }
11    let mut s = String::with_capacity(len * 3 - 2);
12    s.push('?');
13    for _ in 1..len {
14        s.push_str(", ?");
15    }
16    s
17}
18
19/// Trait for common query operations
20pub trait QueryCommon {
21    /// Add a WITH clause
22    fn with(&mut self, alias: &str, chain_builder: crate::builder::ChainBuilder);
23
24    /// Add a recursive WITH clause
25    fn with_recursive(&mut self, alias: &str, chain_builder: crate::builder::ChainBuilder);
26
27    /// Add a UNION clause
28    fn union(&mut self, chain_builder: crate::builder::ChainBuilder);
29
30    /// Add a UNION ALL clause
31    fn union_all(&mut self, chain_builder: crate::builder::ChainBuilder);
32
33    /// Add a LIMIT clause
34    fn limit(&mut self, limit: usize);
35
36    /// Add an OFFSET clause
37    fn offset(&mut self, offset: usize);
38
39    /// Add a GROUP BY clause
40    fn group_by(&mut self, columns: Vec<String>);
41
42    /// Add a raw GROUP BY clause
43    fn group_by_raw(&mut self, sql: &str, binds: Option<Vec<Value>>);
44
45    /// Add an ORDER BY clause
46    fn order_by(&mut self, column: &str, order: &str);
47
48    /// Add a raw ORDER BY clause
49    fn order_by_raw(&mut self, sql: &str, binds: Option<Vec<Value>>);
50}
51
52impl QueryCommon for QueryBuilder {
53    fn with(&mut self, alias: &str, chain_builder: crate::builder::ChainBuilder) {
54        self.query_common
55            .push(Common::With(alias.to_string(), false, chain_builder));
56    }
57
58    fn with_recursive(&mut self, alias: &str, chain_builder: crate::builder::ChainBuilder) {
59        self.query_common
60            .push(Common::With(alias.to_string(), true, chain_builder));
61    }
62
63    fn union(&mut self, chain_builder: crate::builder::ChainBuilder) {
64        self.query_common.push(Common::Union(false, chain_builder));
65    }
66
67    fn union_all(&mut self, chain_builder: crate::builder::ChainBuilder) {
68        self.query_common.push(Common::Union(true, chain_builder));
69    }
70
71    fn limit(&mut self, limit: usize) {
72        self.query_common.push(Common::Limit(limit));
73    }
74
75    fn offset(&mut self, offset: usize) {
76        self.query_common.push(Common::Offset(offset));
77    }
78
79    fn group_by(&mut self, columns: Vec<String>) {
80        self.query_common.push(Common::GroupBy(columns));
81    }
82
83    fn group_by_raw(&mut self, sql: &str, binds: Option<Vec<Value>>) {
84        self.query_common
85            .push(Common::GroupByRaw(sql.to_string(), binds));
86    }
87
88    fn order_by(&mut self, column: &str, order: &str) {
89        self.query_common
90            .push(Common::OrderBy(column.to_string(), order.to_string()));
91    }
92
93    fn order_by_raw(&mut self, sql: &str, binds: Option<Vec<Value>>) {
94        self.query_common
95            .push(Common::OrderByRaw(sql.to_string(), binds));
96    }
97}
98
99/// Trait for HAVING clause operations
100pub trait HavingClauses {
101    /// Add a HAVING condition
102    fn having(&mut self, column: &str, operator: &str, value: Value);
103
104    /// Add a HAVING condition with raw SQL
105    fn having_raw(&mut self, sql: &str, binds: Option<Vec<Value>>);
106
107    /// Add a HAVING BETWEEN condition
108    fn having_between(&mut self, column: &str, values: [Value; 2]);
109
110    /// Add a HAVING IN condition
111    fn having_in(&mut self, column: &str, values: Vec<Value>);
112
113    /// Add a HAVING NOT IN condition
114    fn having_not_in(&mut self, column: &str, values: Vec<Value>);
115}
116
117impl HavingClauses for QueryBuilder {
118    fn having(&mut self, column: &str, operator: &str, value: Value) {
119        let sql = format!("{} {} ?", column, operator);
120        self.query_common
121            .push(Common::Having(sql, Some(vec![value])));
122    }
123
124    fn having_raw(&mut self, sql: &str, binds: Option<Vec<Value>>) {
125        self.query_common
126            .push(Common::Having(sql.to_string(), binds));
127    }
128
129    fn having_between(&mut self, column: &str, values: [Value; 2]) {
130        let sql = format!("{} BETWEEN ? AND ?", column);
131        self.query_common
132            .push(Common::Having(sql, Some(values.to_vec())));
133    }
134
135    fn having_in(&mut self, column: &str, values: Vec<Value>) {
136        if values.is_empty() {
137            self.query_common
138                .push(Common::Having("1 = 0".to_string(), None));
139            return;
140        }
141        let placeholders = build_placeholders(values.len());
142        let sql = format!("{} IN ({})", column, placeholders);
143        self.query_common.push(Common::Having(sql, Some(values)));
144    }
145
146    fn having_not_in(&mut self, column: &str, values: Vec<Value>) {
147        if values.is_empty() {
148            self.query_common
149                .push(Common::Having("1 = 1".to_string(), None));
150            return;
151        }
152        let placeholders = build_placeholders(values.len());
153        let sql = format!("{} NOT IN ({})", column, placeholders);
154        self.query_common.push(Common::Having(sql, Some(values)));
155    }
156}
157
158/// Trait for WHERE clause operations
159pub trait WhereClauses {
160    /// Add an equality condition
161    fn where_eq(&mut self, column: &str, value: Value);
162
163    /// Add a not equality condition
164    fn where_ne(&mut self, column: &str, value: Value);
165
166    /// Add an IN condition
167    fn where_in(&mut self, column: &str, values: Vec<Value>);
168
169    /// Add a NOT IN condition
170    fn where_not_in(&mut self, column: &str, values: Vec<Value>);
171
172    /// Add an IS NULL condition
173    fn where_null(&mut self, column: &str);
174
175    /// Add an IS NOT NULL condition
176    fn where_not_null(&mut self, column: &str);
177
178    /// Add a BETWEEN condition
179    fn where_between(&mut self, column: &str, values: [Value; 2]);
180
181    /// Add a NOT BETWEEN condition
182    fn where_not_between(&mut self, column: &str, values: [Value; 2]);
183
184    /// Add a LIKE condition
185    fn where_like(&mut self, column: &str, value: Value);
186
187    /// Add a NOT LIKE condition
188    fn where_not_like(&mut self, column: &str, value: Value);
189
190    /// Add a case-insensitive LIKE condition (ILIKE for Postgres, LOWER() for MySQL)
191    fn where_ilike(&mut self, column: &str, value: Value);
192
193    /// Add a greater than condition
194    fn where_gt(&mut self, column: &str, value: Value);
195
196    /// Add a greater than or equal condition
197    fn where_gte(&mut self, column: &str, value: Value);
198
199    /// Add a less than condition
200    fn where_lt(&mut self, column: &str, value: Value);
201
202    /// Add a less than or equal condition
203    fn where_lte(&mut self, column: &str, value: Value);
204
205    /// Add a column-to-column comparison
206    fn where_column(&mut self, lhs: &str, operator: &str, rhs: &str);
207
208    /// Add an EXISTS condition
209    fn where_exists(&mut self, query: impl FnOnce(&mut crate::builder::ChainBuilder));
210
211    /// Add a NOT EXISTS condition
212    fn where_not_exists(&mut self, query: impl FnOnce(&mut crate::builder::ChainBuilder));
213
214    /// Add a JSON contains condition (MySQL JSON_CONTAINS)
215    fn where_json_contains(&mut self, column: &str, value: Value);
216
217    /// Add a subquery condition
218    fn where_subquery(&mut self, query: impl FnOnce(&mut QueryBuilder));
219
220    /// Add an OR condition
221    fn or(&mut self) -> &mut QueryBuilder;
222
223    /// Add a raw WHERE condition
224    fn where_raw(&mut self, sql: &str, binds: Option<Vec<Value>>);
225}
226
227impl WhereClauses for QueryBuilder {
228    fn where_eq(&mut self, column: &str, value: Value) {
229        self.statement.push(crate::types::Statement::Value(
230            column.to_string(),
231            crate::query::Operator::Equal,
232            value,
233        ));
234    }
235
236    fn where_ne(&mut self, column: &str, value: Value) {
237        self.statement.push(crate::types::Statement::Value(
238            column.to_string(),
239            crate::query::Operator::NotEqual,
240            value,
241        ));
242    }
243
244    fn where_in(&mut self, column: &str, values: Vec<Value>) {
245        self.statement.push(crate::types::Statement::Value(
246            column.to_string(),
247            crate::query::Operator::In,
248            Value::Array(values),
249        ));
250    }
251
252    fn where_not_in(&mut self, column: &str, values: Vec<Value>) {
253        self.statement.push(crate::types::Statement::Value(
254            column.to_string(),
255            crate::query::Operator::NotIn,
256            Value::Array(values),
257        ));
258    }
259
260    fn where_null(&mut self, column: &str) {
261        self.statement.push(crate::types::Statement::Value(
262            column.to_string(),
263            crate::query::Operator::IsNull,
264            Value::Null,
265        ));
266    }
267
268    fn where_not_null(&mut self, column: &str) {
269        self.statement.push(crate::types::Statement::Value(
270            column.to_string(),
271            crate::query::Operator::IsNotNull,
272            Value::Null,
273        ));
274    }
275
276    fn where_between(&mut self, column: &str, values: [Value; 2]) {
277        self.statement.push(crate::types::Statement::Value(
278            column.to_string(),
279            crate::query::Operator::Between,
280            Value::Array(values.to_vec()),
281        ));
282    }
283
284    fn where_not_between(&mut self, column: &str, values: [Value; 2]) {
285        self.statement.push(crate::types::Statement::Value(
286            column.to_string(),
287            crate::query::Operator::NotBetween,
288            Value::Array(values.to_vec()),
289        ));
290    }
291
292    fn where_like(&mut self, column: &str, value: Value) {
293        self.statement.push(crate::types::Statement::Value(
294            column.to_string(),
295            crate::query::Operator::Like,
296            value,
297        ));
298    }
299
300    fn where_not_like(&mut self, column: &str, value: Value) {
301        self.statement.push(crate::types::Statement::Value(
302            column.to_string(),
303            crate::query::Operator::NotLike,
304            value,
305        ));
306    }
307
308    fn where_gt(&mut self, column: &str, value: Value) {
309        self.statement.push(crate::types::Statement::Value(
310            column.to_string(),
311            crate::query::Operator::GreaterThan,
312            value,
313        ));
314    }
315
316    fn where_gte(&mut self, column: &str, value: Value) {
317        self.statement.push(crate::types::Statement::Value(
318            column.to_string(),
319            crate::query::Operator::GreaterThanOrEqual,
320            value,
321        ));
322    }
323
324    fn where_lt(&mut self, column: &str, value: Value) {
325        self.statement.push(crate::types::Statement::Value(
326            column.to_string(),
327            crate::query::Operator::LessThan,
328            value,
329        ));
330    }
331
332    fn where_lte(&mut self, column: &str, value: Value) {
333        self.statement.push(crate::types::Statement::Value(
334            column.to_string(),
335            crate::query::Operator::LessThanOrEqual,
336            value,
337        ));
338    }
339
340    fn where_subquery(&mut self, query: impl FnOnce(&mut QueryBuilder)) {
341        let mut sub_query = QueryBuilder::new(self.client.clone());
342        query(&mut sub_query);
343        self.statement
344            .push(crate::types::Statement::SubChain(Box::new(sub_query)));
345    }
346
347    fn or(&mut self) -> &mut QueryBuilder {
348        let or_query = QueryBuilder::new(self.client.clone());
349        self.statement
350            .push(crate::types::Statement::OrChain(Box::new(or_query)));
351        self.statement.last_mut().unwrap().to_query_builder()
352    }
353
354    fn where_raw(&mut self, sql: &str, binds: Option<Vec<Value>>) {
355        self.statement
356            .push(crate::types::Statement::Raw((sql.to_string(), binds)));
357    }
358
359    fn where_ilike(&mut self, column: &str, value: Value) {
360        // For MySQL, use LOWER() function
361        let sql = format!("LOWER({}) LIKE LOWER(?)", column);
362        self.statement
363            .push(crate::types::Statement::Raw((sql, Some(vec![value]))));
364    }
365
366    fn where_column(&mut self, lhs: &str, operator: &str, rhs: &str) {
367        let sql = format!("{} {} {}", lhs, operator, rhs);
368        self.statement
369            .push(crate::types::Statement::Raw((sql, None)));
370    }
371
372    fn where_exists(&mut self, query: impl FnOnce(&mut crate::builder::ChainBuilder)) {
373        let mut sub_builder = crate::builder::ChainBuilder::new(self.client.clone());
374        query(&mut sub_builder);
375        let (sub_sql, sub_binds) = sub_builder.to_sql();
376        let sql = format!("EXISTS ({})", sub_sql);
377        self.statement
378            .push(crate::types::Statement::Raw((sql, Some(sub_binds))));
379    }
380
381    fn where_not_exists(&mut self, query: impl FnOnce(&mut crate::builder::ChainBuilder)) {
382        let mut sub_builder = crate::builder::ChainBuilder::new(self.client.clone());
383        query(&mut sub_builder);
384        let (sub_sql, sub_binds) = sub_builder.to_sql();
385        let sql = format!("NOT EXISTS ({})", sub_sql);
386        self.statement
387            .push(crate::types::Statement::Raw((sql, Some(sub_binds))));
388    }
389
390    fn where_json_contains(&mut self, column: &str, value: Value) {
391        let sql = format!("JSON_CONTAINS({}, ?)", column);
392        self.statement
393            .push(crate::types::Statement::Raw((sql, Some(vec![value]))));
394    }
395}