1#![allow(clippy::wrong_self_convention)]
2use crate::*;
3use tokio_postgres::types::ToSql;
4
5pub struct Where;
6pub struct Order;
7pub struct Group;
8pub struct SelectCondition<'q> {
9 pub(crate) sql: String,
10 pub(crate) params: Vec<&'q (dyn ToSql + Sync)>,
11}
12
13impl<'q, T> SqlClause<'q> for Clause<'q, T> {
14 fn unwrap(self) -> (String, Vec<&'q (dyn ToSql + Sync)>) {
15 (self.sql, self.params)
16 }
17
18 fn unwrap_ref(&self) -> (&str, &[&'q (dyn ToSql + Sync)]) {
19 (&self.sql, &self.params)
20 }
21}
22fn __group_by<'q, T1, T2, T3>(clause: Clause<'q, T1>, group: Clause<'_, T2>) -> Clause<'q, T3> {
23 let (mut sql, params) = clause.unwrap();
24 sql.push_str(" GROUP BY (");
25 let (cols, _) = group.unwrap();
26 sql.push_str(&cols);
27 sql.push(')');
28 Clause::new(sql, params)
29}
30impl<'q> Clause<'q, Where> {
31 pub fn group_by_cols(self, columns: &[&str]) -> Clause<'q, Group> {
32 __group_by(self, cols(columns))
33 }
34 pub fn group_by<C>(self, group: Clause<'_, C>) -> Clause<'q, Group> {
35 __group_by(self, group)
36 }
37 pub fn limit(self, limit: &'q i64) -> Clause<'q, Paging> {
38 __limit(self, limit)
39 }
40 pub fn offset(self, offset: &'q i64) -> Clause<'q, Paging> {
41 __offset(self, offset)
42 }
43}
44
45impl<'q> Clause<'q, Paging> {
46 pub fn limit(self, limit: &'q i64) -> Clause<'q, ()> {
47 __limit(self, limit)
48 }
49 pub fn offset(self, offset: &'q i64) -> Clause<'q, ()> {
50 __offset(self, offset)
51 }
52}
53impl<'q> Clause<'q, Group> {
54 pub fn order_by_cols(self, columns: &[&str]) -> Clause<'q, Order> {
55 __order_by_cols(self, columns)
56 }
57 pub fn limit(self, limit: &'q i64) -> Clause<'q, Paging> {
58 __limit(self, limit)
59 }
60 pub fn offset(self, offset: &'q i64) -> Clause<'q, Paging> {
61 __offset(self, offset)
62 }
63}
64
65impl<'q> Clause<'q, Order> {
66 pub fn limit(self, limit: &'q i64) -> Clause<'q, Paging> {
67 __limit(self, limit)
68 }
69 pub fn offset(self, offset: &'q i64) -> Clause<'q, Paging> {
70 __offset(self, offset)
71 }
72}
73
74impl<'q> Clause<'q, Select> {
75 pub fn select<T>(self, clause: Clause<'q, T>) -> Clause<'q, Select> {
94 let mut sql = self.sql;
95 let mut params = self.params;
96 sql.push_str(", ");
97 sql.push_str(&clause.sql);
98 params.extend_from_slice(&clause.params);
99 Clause::new(sql, params)
100 }
101 pub fn from(self, table: &str) -> Clause<'q, From> {
102 let mut sql = self.sql;
103 sql.push_str(" FROM ");
104 append_prim(&mut sql, table);
106 Clause::new(sql, self.params)
107 }
108 pub fn from_subquery<T>(self, sub: Clause<'q, T>, alias: &str) -> Clause<'q, From> {
109 let (mut sql, mut params) = self.unwrap();
110 let (sub_sql, sub_params) = sub.unwrap();
111 sql.push_str(" FROM (");
112 sql.push_str(&sub_sql);
113 params.extend_from_slice(&sub_params);
114 sql.push_str(") as ");
115 append_wrap(&mut sql, alias);
116 Clause::new(sql, params)
117 }
118}
119
120fn __join<'q, T>(
121 clause: Clause<'q, T>,
122 join: &str,
123 table: &str,
124 join_method: Clause<'q, Join>,
125) -> Clause<'q, From> {
126 let (mut sql, params) = clause.unwrap();
127 sql.push_str(&join);
129 sql.push_str(" JOIN ");
130 append_prim(&mut sql, table);
133 let (join_sql, _) = join_method.unwrap_ref();
134 sql.push_str(&join_sql);
135 Clause::new(sql, params)
136}
137impl<'q> Clause<'q, From> {
138 pub fn join(self, table: &str, join_method: Clause<'q, Join>) -> Clause<'q, From> {
139 __join(self, "", table, join_method)
140 }
141 pub fn left_join(self, table: &str, join_method: Clause<'q, Join>) -> Clause<'q, From> {
142 __join(self, " LEFT", table, join_method)
143 }
144
145 pub fn left_outer_join(self, table: &str, join_method: Clause<'q, Join>) -> Clause<'q, From> {
146 __join(self, " LEFT OUTER", table, join_method)
147 }
148
149 pub fn right_join(self, table: &str, join_method: Clause<'q, Join>) -> Clause<'q, From> {
150 __join(self, " RIGHT", table, join_method)
151 }
152
153 pub fn right_outer_join(self, table: &str, join_method: Clause<'q, Join>) -> Clause<'q, From> {
154 __join(self, " RIGHT OUTER", table, join_method)
155 }
156
157 pub fn where_col(self, name: &str, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
158 __where(self, name, condition)
159 }
160 pub fn where_cond(self, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
161 let (mut sql, params) = self.unwrap();
162 sql.push_str(" WHERE ");
163 __condition("", Clause::<From>::new(sql, params), condition)
164 }
165
166 pub fn limit(self, limit: &'q i64) -> Clause<'q, ()> {
167 __limit(self, limit)
168 }
169 pub fn offset(self, offset: &'q i64) -> Clause<'q, ()> {
170 __offset(self, offset)
171 }
172}
173fn __limit<'q, T, C>(clause: Clause<'q, T>, limit: &'q i64) -> Clause<'q, C> {
174 let (mut sql, mut params) = clause.unwrap();
175 sql.push_str(" LIMIT $");
176 params.push(limit);
177 Clause::new(sql, params)
178}
179fn __offset<'q, T, C>(clause: Clause<'q, T>, offset: &'q i64) -> Clause<'q, C> {
180 let (mut sql, mut params) = clause.unwrap();
181 sql.push_str(" OFFSET $");
182 params.push(offset);
183 Clause::new(sql, params)
184}
185
186impl<'q> Clause<'q, Join> {
187 }
226
227pub fn using<'q>(cols: Clause<Column>) -> Clause<'q, Join> {
228 let mut sql = String::new();
230 let (col_sql, _) = cols.unwrap();
231 sql.push_str(" USING (");
232 sql.push_str(&col_sql);
233 sql.push(')');
234 Clause::new(sql, vec![])
235}
236pub fn using_col<'q>(col_name: &str) -> Clause<'q, Join> {
252 let mut sql = String::new();
254 sql.push_str(" USING (");
255 append_col(&mut sql, col_name);
257 sql.push(')');
258 Clause::new(sql, vec![])
259}
260pub fn using_cols<'q>(col_names: &[&str]) -> Clause<'q, Join> {
277 let mut sql = String::new();
279 sql.push_str(" USING (");
280 __cols(&mut sql, col_names);
281 sql.push(')');
282 Clause::new(sql, vec![])
283}
284pub fn on_col_pair<'q>(col1: &str, col2: &str) -> Clause<'q, Join> {
302 let mut sql = String::new();
304 sql.push_str(" ON ");
305 append_col(&mut sql, col1);
307 sql.push('=');
309 append_col(&mut sql, col2);
311 Clause::new(sql, vec![])
312}
313pub fn on_col_pairs<'q>(col_pairs: &[(&str, &str)]) -> Clause<'q, Join> {
330 let mut sql = String::new();
331 sql.push_str(" ON (");
332 let mut not_first = false;
333 for (col1, col2) in col_pairs {
334 if not_first {
335 sql.push_str(" AND ");
336 } else {
337 not_first = true;
338 }
339 sql.push_str(&format_col(col1));
340 sql.push('=');
342 sql.push_str(&format_col(col2));
343 }
344 sql.push(')');
345 Clause::new(sql, vec![])
346}
347pub fn on_wrap(condition: Clause<Condition>) -> Clause<Join> {
348 let mut sql = String::new();
350 let (cond_sql, _) = condition.unwrap();
351 sql.push_str(" ON (");
352 sql.push_str(&cond_sql);
353 sql.push(')');
354 Clause::new(sql, vec![])
355}
356
357pub(crate) fn __where<'q, T, C>(
358 clause: Clause<'q, T>,
359 name: &str,
360 condition: Clause<'q, Condition>,
361) -> Clause<'q, C> {
362 let mut sql = clause.sql;
363 let mut params = clause.params;
364 sql.push_str(" WHERE ");
365 sql.push_str(&format_col(name));
366 let (cond_sql, cond_params) = condition.unwrap();
367 sql.push_str(cond_sql.as_str());
368 params.extend(cond_params);
369 Clause::new(sql, params)
370}
371
372impl<'q> Clause<'q, Where> {
373 pub fn and(self, name: &str, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
374 __and_col(self, name, condition)
375 }
376 pub fn or(self, name: &str, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
377 __or_col(self, name, condition)
378 }
379
380 pub fn and_nest(self, clause: Clause<'q, Condition>) -> Clause<'q, Where> {
381 __and_nest(self, clause)
382 }
383
384 pub fn or_nest(self, clause: Clause<'q, Condition>) -> Clause<'q, Where> {
385 __or_nest(self, clause)
386 }
387
388 pub fn order_by_cols(self, columns: &[&str]) -> Clause<'q, Order> {
389 __order_by_cols(self, columns)
390 }
403}
404fn __order_by_cols<'q, T>(clause: Clause<'q, T>, columns: &[&str]) -> Clause<'q, Order> {
405 let (mut sql, params) = clause.unwrap();
406 let mut not_first = false;
407 sql.push_str(" ORDER BY ");
408 for col in columns {
409 if not_first {
410 sql.push_str(", ");
411 } else {
412 not_first = true;
413 }
414 sql.push_str(&__order(col));
415 }
416 Clause::new(sql, params)
417}
418fn __order(col: &str) -> String {
419 let (col_name, dir) = {
420 let mut split_as = col.split(" ");
421 let col_name = split_as.next().unwrap_or_default();
422 let alias = split_as.next();
423 (wrap(col_name), alias)
424 };
425 if let Some(dir) = dir
426 && dir.eq_ignore_ascii_case("desc")
427 {
428 format!("{} {}", col_name, dir)
429 } else {
430 format!("{}", col_name)
431 }
432}
433
434pub fn select(clause: Clause<Column>) -> Clause<Select> {
453 Clause::new(format!("SELECT {}", clause.sql), clause.params)
454}
455
456pub fn select_all<'q>() -> Clause<'q, Select> {
457 Clause::new("SELECT *".to_string(), Vec::new())
458}
459
460pub fn col<'q>(expr: &str) -> Clause<'q, Column> {
494 Clause::new(format_prim(expr), vec![])
495}
496
497pub fn val<'q, T: ToSql + Sync + 'q, S>(value: &'q T) -> Clause<'q, S> {
515 Clause::new("$".to_string(), vec![value])
516}
517pub fn where_col<'q>(name: &str, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
518 let mut sql = String::new();
519 let (cond_sql, cond_params) = condition.unwrap();
520 sql.push(' ');
521 sql.push_str(&format_col(name));
522 sql.push_str(cond_sql.as_str());
523 Clause::new(sql, cond_params)
524}
525
526#[cfg(test)]
527mod tests {
528 use super::*;
529
530 #[test]
531 fn example() {
532 let user_id: i32 = 123;
533 let limit: i64 = 10;
534 let offset: i64 = 50;
535 let (sql, params) = select(cols(&[
536 "u.UserId as id",
537 "u.Name as name",
538 "p.Title as title",
539 "p.Content::text as body",
540 ]))
541 .from("User as u")
542 .left_join("Post as p", using_col("UserId"))
543 .where_col("u.UserId", eq(&user_id).cast("bigint"))
544 .order_by_cols(&["CreatedAt desc"])
545 .limit(&limit)
546 .offset(&offset)
547 .build();
548
549 println!("SQL: {}", sql);
550 println!("Params: {:?}", params);
551 }
553 #[test]
554 fn select_test() {
555 let user_id: i32 = 123;
556 let (sql, params) = select(cols(&["u.UserId as Id", "u.Name", "p.Title", "p.Content"]))
557 .from("User as u")
558 .left_join("Post as p", using_col("UserId"))
559 .left_join("Metadata as m", on_col_pair("p.Id", "m.PostId"))
560 .left_join(
561 "History as h",
562 on_col_pairs(&[("p.Id", "m.PostId"), ("p.Id", "h.PostId")]),
563 )
564 .where_col("u.UserId", eq(&user_id))
565 .and("t.Value", lt(&1000))
566 .and_nest(col("t.Asd").eq(&true).or_col("Xwe").eq(&false))
567 .order_by_cols(&["CreatedAt desc"])
568 .limit(&10)
569 .offset(&100)
570 .build();
571 println!("{}", sql);
573 println!("{:?}", params);
574 }
575
576 #[test]
577 fn nested() {
578 let q = select(cols(&["u.UserId", "u.Name"]))
579 .select(avg_col("t.Score").alias("AvgScore"))
580 .select(avg_col_f64("t.Rating").alias("AvgRating"))
581 .select(extract_col("epoch", "Timestamp").cast("int").alias("LogId"))
582 .from("User as u")
583 .where_cond(ands(&[
584 col("u.UserId").eq(&123),
585 ors(&[col("u.UserId").eq(&456), col_op("u.Id", ">=", &789)]),
586 ]))
587 .build();
588 println!("{}", q.0);
589 }
590
591 #[test]
592 fn branched() {
593 let opt1 = Some(1);
594 let mut query = select(cols(&["u.UserId", "u.Name", "p.Title", "p.Content"]))
595 .from("User as u")
596 .where_col("u.UserId", eq(&opt1))
597 .debug();
598 println!("Display: {}", query);
599 println!("Debug: {:?}", query);
600 if let Some(val) = &opt1 {
601 query = query.and("u.PostId", eq(val));
602 }
603 query.and("u.Title", eq(&1));
604 }
605
606 #[test]
607 fn subquery() {
608 let q = select(cols(&["sub.UserId", "sub.Name"]))
609 .from_subquery(
610 select(cols(&["u.UserId", "u.Name"])).from("Table as u"),
611 "sub",
612 )
613 .where_col("u.UserId", eq(&123));
614 println!("Display: {}", q);
615 println!("Debug: {:?}", q);
616 }
617
618 #[test]
619 fn union() {
620 let opt1 = Some(1);
621 let query = select(cols(&["u.UserId", "u.Name", "p.Title", "p.Content"]))
622 .from("User as u")
623 .where_col("u.UserId", eq(&opt1))
624 .union(
625 select(cols(&["u.UserId", "u.Name", "p.Title", "p.Content"]))
626 .from("User as u")
627 .where_col("u.UserId", eq(&opt1)),
628 )
629 .union_all(
630 select(cols(&["u.UserId", "u.Name", "p.Title", "p.Content"]))
631 .from("User as u")
632 .where_col("u.UserId", eq(&opt1)),
633 );
634 println!("Display: {}", query);
635 println!("Debug: {:?}", query);
636 }
637}