1use sqlx::Arguments;
2
3use super::{Db, DbArguments, placeholder};
4use crate::error::AppResult;
5
6pub struct InsertBuilder {
14 table: String,
15 columns: Vec<String>,
16 args: DbArguments,
17}
18
19impl InsertBuilder {
20 pub fn into(table: &str) -> Self {
21 Self {
22 table: table.to_string(),
23 columns: Vec::new(),
24 args: DbArguments::default(),
25 }
26 }
27
28 pub fn set<T>(mut self, column: &str, value: T) -> Self
30 where
31 T: sqlx::Type<Db> + sqlx::Encode<'static, Db> + Send + 'static,
32 {
33 self.columns.push(column.to_string());
34 self.args.add(value).unwrap();
35 self
36 }
37
38 pub fn set_optional<T>(mut self, column: &str, value: Option<T>) -> Self
40 where
41 T: sqlx::Type<Db> + sqlx::Encode<'static, Db> + Send + 'static,
42 {
43 self.columns.push(column.to_string());
44 self.args.add(value).unwrap();
45 self
46 }
47
48 pub async fn execute<'e, E>(self, executor: E) -> AppResult<u64>
50 where
51 E: sqlx::Executor<'e, Database = Db>,
52 {
53 let placeholders: Vec<String> = (1..=self.columns.len())
54 .map(placeholder)
55 .collect();
56
57 #[cfg(feature = "mysql")]
58 let sql = format!(
59 "INSERT INTO {} ({}) VALUES ({})",
60 self.table,
61 self.columns.join(", "),
62 placeholders.join(", ")
63 );
64
65 #[cfg(feature = "postgres")]
66 let sql = format!(
67 "INSERT INTO {} ({}) VALUES ({}) RETURNING id",
68 self.table,
69 self.columns.join(", "),
70 placeholders.join(", ")
71 );
72
73 #[cfg(feature = "mysql")]
74 {
75 let result = sqlx::query_with(&sql, self.args)
76 .execute(executor)
77 .await?;
78 Ok(result.last_insert_id())
79 }
80
81 #[cfg(feature = "postgres")]
82 {
83 use sqlx::Row;
84 let row = sqlx::query_with(&sql, self.args)
85 .fetch_one(executor)
86 .await?;
87 let id: i64 = row.get(0);
88 Ok(id as u64)
89 }
90 }
91}
92
93pub struct UpdateBuilder {
101 table: String,
102 set_clauses: Vec<String>,
103 where_clauses: Vec<String>,
104 args: DbArguments,
105 param_count: usize,
106}
107
108impl UpdateBuilder {
109 pub fn table(table: &str) -> Self {
110 Self {
111 table: table.to_string(),
112 set_clauses: Vec::new(),
113 where_clauses: Vec::new(),
114 args: DbArguments::default(),
115 param_count: 0,
116 }
117 }
118
119 pub fn set<T>(mut self, column: &str, value: T) -> Self
121 where
122 T: sqlx::Type<Db> + sqlx::Encode<'static, Db> + Send + 'static,
123 {
124 self.param_count += 1;
125 self.set_clauses.push(format!("{} = {}", column, placeholder(self.param_count)));
126 self.args.add(value).unwrap();
127 self
128 }
129
130 pub fn set_raw(mut self, column: &str, expr: &str) -> Self {
132 self.set_clauses.push(format!("{} = {}", column, expr));
133 self
134 }
135
136 pub fn set_if<T>(mut self, column: &str, value: Option<T>) -> Self
138 where
139 T: sqlx::Type<Db> + sqlx::Encode<'static, Db> + Send + 'static,
140 {
141 if let Some(v) = value {
142 self.param_count += 1;
143 self.set_clauses.push(format!("{} = {}", column, placeholder(self.param_count)));
144 self.args.add(v).unwrap();
145 }
146 self
147 }
148
149 pub fn where_eq<T>(mut self, column: &str, value: T) -> Self
151 where
152 T: sqlx::Type<Db> + sqlx::Encode<'static, Db> + Send + 'static,
153 {
154 self.param_count += 1;
155 self.where_clauses.push(format!("{} = {}", column, placeholder(self.param_count)));
156 self.args.add(value).unwrap();
157 self
158 }
159
160 pub fn where_raw(mut self, condition: &str) -> Self {
162 self.where_clauses.push(condition.to_string());
163 self
164 }
165
166 pub fn where_ne<T>(mut self, column: &str, value: T) -> Self
168 where
169 T: sqlx::Type<Db> + sqlx::Encode<'static, Db> + Send + 'static,
170 {
171 self.param_count += 1;
172 self.where_clauses.push(format!("{} != {}", column, placeholder(self.param_count)));
173 self.args.add(value).unwrap();
174 self
175 }
176
177 pub async fn execute<'e, E>(self, executor: E) -> AppResult<u64>
179 where
180 E: sqlx::Executor<'e, Database = Db>,
181 {
182 if self.set_clauses.is_empty() {
183 return Ok(0);
184 }
185
186 let where_clause = if self.where_clauses.is_empty() {
187 String::new()
188 } else {
189 format!(" WHERE {}", self.where_clauses.join(" AND "))
190 };
191
192 let sql = format!(
193 "UPDATE {} SET {}{}",
194 self.table,
195 self.set_clauses.join(", "),
196 where_clause,
197 );
198
199 let result = sqlx::query_with(&sql, self.args)
200 .execute(executor)
201 .await?;
202
203 Ok(result.rows_affected())
204 }
205}
206
207pub struct DeleteBuilder {
215 table: String,
216 where_clauses: Vec<String>,
217 args: DbArguments,
218 param_count: usize,
219}
220
221impl DeleteBuilder {
222 pub fn from(table: &str) -> Self {
223 Self {
224 table: table.to_string(),
225 where_clauses: Vec::new(),
226 args: DbArguments::default(),
227 param_count: 0,
228 }
229 }
230
231 pub fn where_eq<T>(mut self, column: &str, value: T) -> Self
233 where
234 T: sqlx::Type<Db> + sqlx::Encode<'static, Db> + Send + 'static,
235 {
236 self.param_count += 1;
237 self.where_clauses.push(format!("{} = {}", column, placeholder(self.param_count)));
238 self.args.add(value).unwrap();
239 self
240 }
241
242 pub fn where_raw(mut self, condition: &str) -> Self {
244 self.where_clauses.push(condition.to_string());
245 self
246 }
247
248 pub async fn execute<'e, E>(self, executor: E) -> AppResult<u64>
250 where
251 E: sqlx::Executor<'e, Database = Db>,
252 {
253 let where_clause = if self.where_clauses.is_empty() {
254 String::new()
255 } else {
256 format!(" WHERE {}", self.where_clauses.join(" AND "))
257 };
258
259 let sql = format!("DELETE FROM {}{}", self.table, where_clause);
260
261 let result = sqlx::query_with(&sql, self.args)
262 .execute(executor)
263 .await?;
264
265 Ok(result.rows_affected())
266 }
267}
268
269pub struct CountBuilder {
277 table: String,
278 where_clauses: Vec<String>,
279 args: DbArguments,
280 param_count: usize,
281}
282
283impl CountBuilder {
284 pub fn from(table: &str) -> Self {
285 Self {
286 table: table.to_string(),
287 where_clauses: Vec::new(),
288 args: DbArguments::default(),
289 param_count: 0,
290 }
291 }
292
293 pub fn where_eq<T>(mut self, column: &str, value: T) -> Self
295 where
296 T: sqlx::Type<Db> + sqlx::Encode<'static, Db> + Send + 'static,
297 {
298 self.param_count += 1;
299 self.where_clauses.push(format!("{} = {}", column, placeholder(self.param_count)));
300 self.args.add(value).unwrap();
301 self
302 }
303
304 pub fn where_ne<T>(mut self, column: &str, value: T) -> Self
306 where
307 T: sqlx::Type<Db> + sqlx::Encode<'static, Db> + Send + 'static,
308 {
309 self.param_count += 1;
310 self.where_clauses.push(format!("{} != {}", column, placeholder(self.param_count)));
311 self.args.add(value).unwrap();
312 self
313 }
314
315 pub fn where_raw(mut self, condition: &str) -> Self {
317 self.where_clauses.push(condition.to_string());
318 self
319 }
320
321 pub async fn execute<'e, E>(self, executor: E) -> AppResult<i64>
323 where
324 E: sqlx::Executor<'e, Database = Db>,
325 {
326 let where_clause = if self.where_clauses.is_empty() {
327 String::new()
328 } else {
329 format!(" WHERE {}", self.where_clauses.join(" AND "))
330 };
331
332 let sql = format!("SELECT COUNT(*) FROM {}{}", self.table, where_clause);
333
334 let (count,): (i64,) = sqlx::query_as_with(&sql, self.args)
335 .fetch_one(executor)
336 .await?;
337
338 Ok(count)
339 }
340}