Skip to main content

ngb_sqlbuilder/
select.rs

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