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
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}
17
18impl<'q> Clause<'q, Where> {
19 pub fn limit(self, limit: &'q i64) -> Clause<'q, Paging> {
20 __limit(self, limit)
21 }
22 pub fn offset(self, offset: &'q i64) -> Clause<'q, Paging> {
23 __offset(self, offset)
24 }
25}
26
27impl<'q> Clause<'q, Paging> {
28 pub fn limit(self, limit: &'q i64) -> Clause<'q, ()> {
29 __limit(self, limit)
30 }
31 pub fn offset(self, offset: &'q i64) -> Clause<'q, ()> {
32 __offset(self, offset)
33 }
34}
35
36impl<'q> Clause<'q, Order> {
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, Select> {
46 pub fn select<T>(self, clause: Clause<'q, T>) -> Clause<'q, Select> {
47 let mut sql = self.sql;
48 let mut params = self.params;
49 sql.push_str(", ");
50 sql.push_str(&clause.sql);
51 params.extend_from_slice(&clause.params);
52 Clause::new(sql, params)
53 }
54 pub fn from(self, table: &str) -> Clause<'q, From> {
55 let mut sql = self.sql;
56 sql.push_str(" FROM ");
57 sql.push_str(&format_prim(table));
58 Clause::new(sql, self.params)
59 }
60}
61
62fn __join<'q, T>(clause: Clause<'q, T>, join: &str, table: &str) -> Clause<'q, Join> {
63 let (mut sql, params) = clause.unwrap();
64 sql.push_str(&format!(" {join}JOIN "));
65 sql.push_str(&format_prim(table));
66 Clause::new(sql, params)
67}
68impl<'q> Clause<'q, From> {
69 pub fn join(self, table: &str) -> Clause<'q, Join> {
70 __join(self, "", table)
71 }
72 pub fn left_join(self, table: &str) -> Clause<'q, Join> {
73 __join(self, "LEFT ", table)
74 }
75
76 pub fn left_outer_join(self, table: &str) -> Clause<'q, Join> {
77 __join(self, "LEFT OUTER ", table)
78 }
79
80 pub fn right_join(self, table: &str) -> Clause<'q, Join> {
81 __join(self, "RIGHT ", table)
82 }
83
84 pub fn right_outer_join(self, table: &str) -> Clause<'q, Join> {
85 __join(self, "RIGHT OUTER ", table)
86 }
87
88 pub fn where_col(self, name: &str, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
89 __where(self, name, condition)
90 }
91 pub fn where_cond(self, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
92 let (mut sql, params) = self.unwrap();
93 sql.push_str(" WHERE ");
94 __condition(Clause::<From>::new(sql, params), condition)
95 }
96
97 pub fn limit(self, limit: &'q i64) -> Clause<'q, ()> {
98 __limit(self, limit)
99 }
100 pub fn offset(self, offset: &'q i64) -> Clause<'q, ()> {
101 __offset(self, offset)
102 }
103}
104fn __limit<'q, T, C>(clause: Clause<'q, T>, limit: &'q i64) -> Clause<'q, C> {
105 let (mut sql, mut params) = clause.unwrap();
106 sql.push_str(" LIMIT $");
107 params.push(limit);
108 Clause::new(sql, params)
109}
110fn __offset<'q, T, C>(clause: Clause<'q, T>, offset: &'q i64) -> Clause<'q, C> {
111 let (mut sql, mut params) = clause.unwrap();
112 sql.push_str(" OFFSET $");
113 params.push(offset);
114 Clause::new(sql, params)
115}
116
117impl<'q> Clause<'q, Join> {
118 pub fn using(self, cols: Clause<Column>) -> Clause<'q, From> {
119 let (mut sql, params) = self.unwrap();
120 let (col_sql, _) = cols.unwrap();
121 sql.push_str(" using(");
122 sql.push_str(&col_sql);
123 sql.push(')');
124 Clause::new(sql, params)
125 }
126 pub fn using_col(self, col_name: &str) -> Clause<'q, From> {
127 let (mut sql, params) = self.unwrap();
128 sql.push_str(" using(");
129 sql.push_str(&format_col(col_name));
130 sql.push(')');
131 Clause::new(sql, params)
132 }
133 pub fn using_cols(self, col_names: &[&str]) -> Clause<'q, From> {
134 let (mut sql, params) = self.unwrap();
135 sql.push_str(" using(");
136 __cols(&mut sql, col_names);
137 sql.push(')');
138 Clause::new(sql, params)
139 }
140 pub fn on(self, col1: &str, col2: &str) -> Clause<'q, From> {
141 let (mut sql, params) = self.unwrap();
142 sql.push_str(" on ");
143 sql.push_str(&format_col(col1));
144 sql.push_str(" = ");
145 sql.push_str(&format_col(col2));
146 Clause::new(sql, params)
147 }
148 pub fn on_wrap(self, condition: Clause<'q, Condition>) -> Clause<'q, From> {
149 let (mut sql, params) = self.unwrap();
150 let (cond_sql, _) = condition.unwrap();
151 sql.push_str(" on (");
152 sql.push_str(&cond_sql);
153 sql.push(')');
154 Clause::new(sql, params)
155 }
156}
157
158pub(crate) fn __where<'q, T, C>(
159 clause: Clause<'q, T>,
160 name: &str,
161 condition: Clause<'q, Condition>,
162) -> Clause<'q, C> {
163 let mut sql = clause.sql;
164 let mut params = clause.params;
165 sql.push_str(" where ");
166 sql.push_str(&format_col(name));
167 let (cond_sql, cond_params) = condition.unwrap();
168 sql.push_str(cond_sql.as_str());
169 params.extend(cond_params);
170 Clause::new(sql, params)
171}
172
173impl<'q> Clause<'q, Where> {
174 pub fn and(self, name: &str, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
175 __and_col(self, name, condition)
176 }
177 pub fn or(self, name: &str, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
178 __or_col(self, name, condition)
179 }
180
181 pub fn and_wrap(self, clause: Clause<'q, Where>) -> Clause<'q, Where> {
182 __and_wrap(self, clause)
183 }
184
185 pub fn or_wrap(self, clause: Clause<'q, Where>) -> Clause<'q, Where> {
186 __or_wrap(self, clause)
187 }
188
189 pub fn order_by_cols(self, columns: &[&str]) -> Clause<'q, Order> {
190 let (mut sql, params) = self.unwrap();
191 let mut not_first = false;
192 sql.push_str(" order by ");
193 for col in columns {
194 if not_first {
195 sql.push_str(", ");
196 } else {
197 not_first = true;
198 }
199 sql.push_str(&__order(col));
200 }
201 Clause::new(sql, params)
202 }
203}
204fn __order(col: &str) -> String {
205 let (col_name, dir) = {
206 let mut split_as = col.split(" ");
207 let col_name = split_as.next().unwrap_or_default();
208 let alias = split_as.next();
209 (wrap(col_name), alias)
210 };
211 if let Some(dir) = dir
212 && dir.eq_ignore_ascii_case("desc")
213 {
214 format!("{} {}", col_name, dir)
215 } else {
216 format!("{}", col_name)
217 }
218}
219
220pub fn select(clause: Clause<Column>) -> Clause<Select> {
223 Clause::new(format!("select {}", clause.sql), clause.params)
224}
225
226pub fn select_all<'q>() -> Clause<'q, Select> {
227 Clause::new("select *".to_string(), Vec::new())
228}
229
230pub fn col<'q>(name: &str) -> Clause<'q, Column> {
231 Clause::new(format_prim(name), vec![])
232}
233
234pub fn val<'q, T: ToSql + Sync + 'q, S>(value: &'q T) -> Clause<'q, S> {
235 Clause::new("$".to_string(), vec![value])
236}
237pub fn where_col<'q>(name: &str, condition: Clause<'q, Condition>) -> Clause<'q, Where> {
238 let mut sql = String::new();
239 let (cond_sql, cond_params) = condition.unwrap();
240 sql.push(' ');
241 sql.push_str(&format_col(name));
242 sql.push_str(cond_sql.as_str());
243 Clause::new(sql, cond_params)
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 #[test]
251 fn example() {
252 let user_id: i32 = 123;
253 let limit: i64 = 10;
254 let offset: i64 = 50;
255 let (sql, params) = select(cols(&[
256 "u.UserId as Id",
257 "u.Name",
258 "p.Title",
259 "p.Content::text as Body",
260 ]))
261 .from("User as u")
262 .left_join("Post as p")
263 .using_col("UserId")
264 .where_col("u.UserId", eq(&user_id).cast_raw("bigint"))
265 .order_by_cols(&["CreatedAt desc"])
266 .limit(&limit)
267 .offset(&offset)
268 .build();
269
270 println!("SQL: {}", sql);
271 println!("Params: {:?}", params);
272 }
274 #[test]
275 fn select_test() {
276 let user_id: i32 = 123;
277 let (sql, params) = select(cols(&["u.UserId", "u.Name", "p.Title", "p.Content"]))
278 .from("User as u")
279 .left_join("Post as p")
280 .using_col("UserId")
281 .where_col("u.UserId", eq(&user_id))
282 .and("t.Value", lt(&1000))
283 .and_wrap(where_col("t.Asd", eq(&true)).or("Xwe", eq(&false)))
284 .order_by_cols(&["CreatedAt desc"])
285 .limit(&10)
286 .offset(&100)
287 .build();
288 println!("{}", sql);
290 println!("{:?}", params);
291 }
292
293 #[test]
294 fn nested() {
295 let q = select(cols(&["u.UserId", "u.Name"]))
296 .from("User as u")
297 .where_cond(ands(&[
298 col("u.UserId").eq(&123),
299 ors(&[col("u.UserId").eq(&456), col_op("u.Id", ">=", &789)]),
300 ]))
301 .build();
302 println!("{}", q.0);
303 }
304
305 #[test]
306 fn branched() {
307 let opt1 = Some(1);
308 let mut query = select(cols(&["u.UserId", "u.Name", "p.Title", "p.Content"]))
309 .from("User as u")
310 .where_col("u.UserId", eq(&opt1));
311 if let Some(val) = &opt1 {
312 query = query.and("u.PostId", eq(val));
313 }
314 query.and("u.Title", eq(&1));
315 }
316}