Skip to main content

ngb_sqlbuilder/
select.rs

1use crate::*;
2use tokio_postgres::types::ToSql;
3
4pub struct Where;
5pub struct Order;
6pub struct Group;
7pub struct SelectCondition<'q> {
8    pub(crate) sql: String,
9    pub(crate) params: Vec<&'q (dyn ToSql + Sync)>,
10}
11
12impl<'q, T> SqlClause<'q> for Clause<'q, T> {
13    fn unwrap(self) -> (String, Vec<&'q (dyn ToSql + Sync)>) {
14        (self.sql, self.params)
15    }
16}
17fn __group_by<'q, T1, T2, T3>(clause: Clause<'q, T1>, group: Clause<'_, T2>) -> Clause<'q, T3> {
18    let (mut sql, params) = clause.unwrap();
19    sql.push_str(" GROUP BY (");
20    let (cols, _) = group.unwrap();
21    sql.push_str(&cols);
22    sql.push(')');
23    Clause::new(sql, params)
24}
25impl<'q> Clause<'q, Where> {
26    pub fn group_by_cols(self, columns: &[&str]) -> Clause<'q, Group> {
27        __group_by(self, cols(columns))
28    }
29    pub fn limit(self, limit: &'q i64) -> Clause<'q, Paging> {
30        __limit(self, limit)
31    }
32    pub fn offset(self, offset: &'q i64) -> Clause<'q, Paging> {
33        __offset(self, offset)
34    }
35}
36
37impl<'q> Clause<'q, Paging> {
38    pub fn limit(self, limit: &'q i64) -> Clause<'q, ()> {
39        __limit(self, limit)
40    }
41    pub fn offset(self, offset: &'q i64) -> Clause<'q, ()> {
42        __offset(self, offset)
43    }
44}
45impl<'q> Clause<'q, Group> {
46    pub fn order_by_cols(self, columns: &[&str]) -> Clause<'q, Order> {
47        __order_by_cols(self, columns)
48    }
49    pub fn limit(self, limit: &'q i64) -> Clause<'q, Paging> {
50        __limit(self, limit)
51    }
52    pub fn offset(self, offset: &'q i64) -> Clause<'q, Paging> {
53        __offset(self, offset)
54    }
55}
56
57impl<'q> Clause<'q, Order> {
58    pub fn limit(self, limit: &'q i64) -> Clause<'q, Paging> {
59        __limit(self, limit)
60    }
61    pub fn offset(self, offset: &'q i64) -> Clause<'q, Paging> {
62        __offset(self, offset)
63    }
64}
65
66impl<'q> Clause<'q, Select> {
67    pub fn select<T>(self, clause: Clause<'q, T>) -> Clause<'q, Select> {
68        let mut sql = self.sql;
69        let mut params = self.params;
70        sql.push_str(", ");
71        sql.push_str(&clause.sql);
72        params.extend_from_slice(&clause.params);
73        Clause::new(sql, params)
74    }
75    pub fn from(self, table: &str) -> Clause<'q, From> {
76        let mut sql = self.sql;
77        sql.push_str(" FROM ");
78        sql.push_str(&format_prim(table));
79        Clause::new(sql, self.params)
80    }
81}
82
83fn __join<'q, T>(clause: Clause<'q, T>, join: &str, table: &str) -> Clause<'q, Join> {
84    let (mut sql, params) = clause.unwrap();
85    sql.push_str(&format!(" {join}JOIN "));
86    sql.push_str(&format_prim(table));
87    Clause::new(sql, params)
88}
89impl<'q> Clause<'q, From> {
90    pub fn join(self, table: &str) -> Clause<'q, Join> {
91        __join(self, "", table)
92    }
93    pub fn left_join(self, table: &str) -> Clause<'q, Join> {
94        __join(self, "LEFT ", table)
95    }
96
97    pub fn left_outer_join(self, table: &str) -> Clause<'q, Join> {
98        __join(self, "LEFT OUTER ", table)
99    }
100
101    pub fn right_join(self, table: &str) -> Clause<'q, Join> {
102        __join(self, "RIGHT ", table)
103    }
104
105    pub fn right_outer_join(self, table: &str) -> Clause<'q, Join> {
106        __join(self, "RIGHT OUTER ", table)
107    }
108
109    pub fn where_col(self, name: &str, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
110        __where(self, name, condition)
111    }
112    pub fn where_cond(self, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
113        let (mut sql, params) = self.unwrap();
114        sql.push_str(" WHERE ");
115        __condition(Clause::<From>::new(sql, params), condition)
116    }
117
118    pub fn limit(self, limit: &'q i64) -> Clause<'q, ()> {
119        __limit(self, limit)
120    }
121    pub fn offset(self, offset: &'q i64) -> Clause<'q, ()> {
122        __offset(self, offset)
123    }
124}
125fn __limit<'q, T, C>(clause: Clause<'q, T>, limit: &'q i64) -> Clause<'q, C> {
126    let (mut sql, mut params) = clause.unwrap();
127    sql.push_str(" LIMIT $");
128    params.push(limit);
129    Clause::new(sql, params)
130}
131fn __offset<'q, T, C>(clause: Clause<'q, T>, offset: &'q i64) -> Clause<'q, C> {
132    let (mut sql, mut params) = clause.unwrap();
133    sql.push_str(" OFFSET $");
134    params.push(offset);
135    Clause::new(sql, params)
136}
137
138impl<'q> Clause<'q, Join> {
139    pub fn using(self, cols: Clause<Column>) -> Clause<'q, From> {
140        let (mut sql, params) = self.unwrap();
141        let (col_sql, _) = cols.unwrap();
142        sql.push_str(" using(");
143        sql.push_str(&col_sql);
144        sql.push(')');
145        Clause::new(sql, params)
146    }
147    pub fn using_col(self, col_name: &str) -> Clause<'q, From> {
148        let (mut sql, params) = self.unwrap();
149        sql.push_str(" using(");
150        sql.push_str(&format_col(col_name));
151        sql.push(')');
152        Clause::new(sql, params)
153    }
154    pub fn using_cols(self, col_names: &[&str]) -> Clause<'q, From> {
155        let (mut sql, params) = self.unwrap();
156        sql.push_str(" using(");
157        __cols(&mut sql, col_names);
158        sql.push(')');
159        Clause::new(sql, params)
160    }
161    pub fn on(self, col1: &str, col2: &str) -> Clause<'q, From> {
162        let (mut sql, params) = self.unwrap();
163        sql.push_str(" on ");
164        sql.push_str(&format_col(col1));
165        sql.push_str(" = ");
166        sql.push_str(&format_col(col2));
167        Clause::new(sql, params)
168    }
169    pub fn on_wrap(self, condition: Clause<'q, Condition>) -> Clause<'q, From> {
170        let (mut sql, params) = self.unwrap();
171        let (cond_sql, _) = condition.unwrap();
172        sql.push_str(" on (");
173        sql.push_str(&cond_sql);
174        sql.push(')');
175        Clause::new(sql, params)
176    }
177}
178
179pub(crate) fn __where<'q, T, C>(
180    clause: Clause<'q, T>,
181    name: &str,
182    condition: Clause<'q, Condition>,
183) -> Clause<'q, C> {
184    let mut sql = clause.sql;
185    let mut params = clause.params;
186    sql.push_str(" where ");
187    sql.push_str(&format_col(name));
188    let (cond_sql, cond_params) = condition.unwrap();
189    sql.push_str(cond_sql.as_str());
190    params.extend(cond_params);
191    Clause::new(sql, params)
192}
193
194impl<'q> Clause<'q, Where> {
195    pub fn and(self, name: &str, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
196        __and_col(self, name, condition)
197    }
198    pub fn or(self, name: &str, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
199        __or_col(self, name, condition)
200    }
201
202    pub fn and_wrap(self, clause: Clause<'q, Where>) -> Clause<'q, Where> {
203        __and_wrap(self, clause)
204    }
205
206    pub fn or_wrap(self, clause: Clause<'q, Where>) -> Clause<'q, Where> {
207        __or_wrap(self, clause)
208    }
209
210    pub fn order_by_cols(self, columns: &[&str]) -> Clause<'q, Order> {
211        __order_by_cols(self, columns)
212        // let (mut sql, params) = self.unwrap();
213        // let mut not_first = false;
214        // sql.push_str(" order by ");
215        // for col in columns {
216        //     if not_first {
217        //         sql.push_str(", ");
218        //     } else {
219        //         not_first = true;
220        //     }
221        //     sql.push_str(&__order(col));
222        // }
223        // Clause::new(sql, params)
224    }
225}
226fn __order_by_cols<'q, T>(clause: Clause<'q, T>, columns: &[&str]) -> Clause<'q, Order> {
227    let (mut sql, params) = clause.unwrap();
228    let mut not_first = false;
229    sql.push_str(" order by ");
230    for col in columns {
231        if not_first {
232            sql.push_str(", ");
233        } else {
234            not_first = true;
235        }
236        sql.push_str(&__order(col));
237    }
238    Clause::new(sql, params)
239}
240fn __order(col: &str) -> String {
241    let (col_name, dir) = {
242        let mut split_as = col.split(" ");
243        let col_name = split_as.next().unwrap_or_default();
244        let alias = split_as.next();
245        (wrap(col_name), alias)
246    };
247    if let Some(dir) = dir
248        && dir.eq_ignore_ascii_case("desc")
249    {
250        format!("{} {}", col_name, dir)
251    } else {
252        format!("{}", col_name)
253    }
254}
255
256// pub trait FromClause {}
257
258pub fn select(clause: Clause<Column>) -> Clause<Select> {
259    Clause::new(format!("select {}", clause.sql), clause.params)
260}
261
262pub fn select_all<'q>() -> Clause<'q, Select> {
263    Clause::new("select *".to_string(), Vec::new())
264}
265
266pub fn col<'q>(name: &str) -> Clause<'q, Column> {
267    Clause::new(format_prim(name), vec![])
268}
269
270pub fn val<'q, T: ToSql + Sync + 'q, S>(value: &'q T) -> Clause<'q, S> {
271    Clause::new("$".to_string(), vec![value])
272}
273pub fn where_col<'q>(name: &str, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
274    let mut sql = String::new();
275    let (cond_sql, cond_params) = condition.unwrap();
276    sql.push(' ');
277    sql.push_str(&format_col(name));
278    sql.push_str(cond_sql.as_str());
279    Clause::new(sql, cond_params)
280}
281
282#[cfg(test)]
283mod tests {
284    use super::*;
285
286    #[test]
287    fn example() {
288        let user_id: i32 = 123;
289        let limit: i64 = 10;
290        let offset: i64 = 50;
291        let (sql, params) = select(cols(&[
292            "u.UserId as Id",
293            "u.Name",
294            "p.Title",
295            "p.Content::text as Body",
296        ]))
297        .from("User as u")
298        .left_join("Post as p")
299        .using_col("UserId")
300        .where_col("u.UserId", eq(&user_id).cast_raw("bigint"))
301        .order_by_cols(&["CreatedAt desc"])
302        .limit(&limit)
303        .offset(&offset)
304        .build();
305
306        println!("SQL: {}", sql);
307        println!("Params: {:?}", params);
308        // let rows = client.query(&sql, &params).await.unwrap();
309    }
310    #[test]
311    fn select_test() {
312        let user_id: i32 = 123;
313        let (sql, params) = select(cols(&["u.UserId", "u.Name", "p.Title", "p.Content"]))
314            .from("User as u")
315            .left_join("Post as p")
316            .using_col("UserId")
317            .where_col("u.UserId", eq(&user_id))
318            .and("t.Value", lt(&1000))
319            .and_wrap(where_col("t.Asd", eq(&true)).or("Xwe", eq(&false)))
320            .order_by_cols(&["CreatedAt desc"])
321            .limit(&10)
322            .offset(&100)
323            .build();
324        // let column = col("a.foo as dfg");
325        println!("{}", sql);
326        println!("{:?}", params);
327    }
328
329    #[test]
330    fn nested() {
331        let q = select(cols(&["u.UserId", "u.Name"]))
332            .select(avg_col("t.Score").alias("AvgScore"))
333            .from("User as u")
334            .where_cond(ands(&[
335                col("u.UserId").eq(&123),
336                ors(&[col("u.UserId").eq(&456), col_op("u.Id", ">=", &789)]),
337            ]))
338            .build();
339        println!("{}", q.0);
340    }
341
342    #[test]
343    fn branched() {
344        let opt1 = Some(1);
345        let mut query = select(cols(&["u.UserId", "u.Name", "p.Title", "p.Content"]))
346            .from("User as u")
347            .where_col("u.UserId", eq(&opt1));
348        if let Some(val) = &opt1 {
349            query = query.and("u.PostId", eq(val));
350        }
351        query.and("u.Title", eq(&1));
352    }
353}