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