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}
11impl<'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 }
45 pub fn offset(self, offset: &'q i64) -> Clause<'q, Final> {
46 __offset(self, offset)
47 }
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 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 clause: Clause<'q, Where>,
216 ) -> Clause<'q, Where> {
217 let mut sql = self.sql;
218 sql.push_str(" and (");
219 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
269pub 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 println!("{}", sql);
316 println!("{:?}", params);
317 }
318 #[tokio::test]
319 async fn it_works() {
320 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, ¶ms).await.unwrap();
341 println!("{:?}", result);
349 }
350}