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