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 }
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
256pub 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 }
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 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}