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