1use super::{
6 condition::{Condition, Order},
7 entity::{Entity, ToRow},
8};
9use std::marker::PhantomData;
10use wae_types::Value;
11
12#[cfg(feature = "turso")]
13use crate::types::from_wae_value;
14#[cfg(feature = "turso")]
15use turso::Value as TursoValue;
16
17#[cfg(feature = "mysql")]
18use crate::types::from_wae_to_mysql;
19#[cfg(feature = "mysql")]
20use mysql_async::Value as MySqlValue;
21
22pub struct SelectBuilder<E: Entity> {
24 columns: Vec<String>,
25 conditions: Vec<Condition>,
26 order_by: Vec<(String, Order)>,
27 limit: Option<u64>,
28 offset: Option<u64>,
29 _marker: PhantomData<E>,
30}
31
32impl<E: Entity> SelectBuilder<E> {
33 pub(crate) fn new() -> Self {
34 Self {
35 columns: Vec::new(),
36 conditions: Vec::new(),
37 order_by: Vec::new(),
38 limit: None,
39 offset: None,
40 _marker: PhantomData,
41 }
42 }
43
44 pub fn columns(mut self, columns: &[&str]) -> Self {
46 self.columns = columns.iter().map(|s| s.to_string()).collect();
47 self
48 }
49
50 pub fn where_(mut self, condition: Condition) -> Self {
52 self.conditions.push(condition);
53 self
54 }
55
56 pub fn where_all(mut self, conditions: Vec<Condition>) -> Self {
58 self.conditions.extend(conditions);
59 self
60 }
61
62 pub fn order_by<C: Into<String>>(mut self, column: C, order: Order) -> Self {
64 self.order_by.push((column.into(), order));
65 self
66 }
67
68 pub fn limit(mut self, limit: u64) -> Self {
70 self.limit = Some(limit);
71 self
72 }
73
74 pub fn offset(mut self, offset: u64) -> Self {
76 self.offset = Some(offset);
77 self
78 }
79
80 #[cfg(feature = "turso")]
81 pub(crate) fn build_turso(&self) -> (String, Vec<TursoValue>) {
83 let columns = if self.columns.is_empty() { "*".to_string() } else { self.columns.join(", ") };
84
85 let mut sql = format!("SELECT {} FROM {}", columns, E::table_name());
86 let mut params = Vec::new();
87
88 if !self.conditions.is_empty() {
89 let where_conditions = self.conditions.to_vec();
90 if where_conditions.len() == 1 {
91 let (cond_sql, cond_params) = where_conditions[0].build_turso();
92 sql.push_str(&format!(" WHERE {}", cond_sql));
93 params.extend(cond_params);
94 }
95 else {
96 let (cond_sql, cond_params) = Condition::and(where_conditions).build_turso();
97 sql.push_str(&format!(" WHERE {}", cond_sql));
98 params.extend(cond_params);
99 }
100 }
101
102 if !self.order_by.is_empty() {
103 let order_parts: Vec<String> = self
104 .order_by
105 .iter()
106 .map(|(col, order)| {
107 format!(
108 "{} {}",
109 col,
110 match order {
111 Order::Asc => "ASC",
112 Order::Desc => "DESC",
113 }
114 )
115 })
116 .collect();
117 sql.push_str(&format!(" ORDER BY {}", order_parts.join(", ")));
118 }
119
120 if let Some(limit) = self.limit {
121 sql.push_str(&format!(" LIMIT {}", limit));
122 }
123
124 if let Some(offset) = self.offset {
125 sql.push_str(&format!(" OFFSET {}", offset));
126 }
127
128 (sql, params)
129 }
130
131 #[cfg(feature = "mysql")]
132 #[allow(dead_code)]
133 pub(crate) fn build_mysql(&self) -> (String, Vec<MySqlValue>) {
135 let columns = if self.columns.is_empty() { "*".to_string() } else { self.columns.join(", ") };
136
137 let mut sql = format!("SELECT {} FROM {}", columns, E::table_name());
138 let mut params = Vec::new();
139
140 if !self.conditions.is_empty() {
141 let where_conditions = self.conditions.to_vec();
142 if where_conditions.len() == 1 {
143 let (cond_sql, cond_params) = where_conditions[0].build_mysql();
144 sql.push_str(&format!(" WHERE {}", cond_sql));
145 params.extend(cond_params);
146 }
147 else {
148 let (cond_sql, cond_params) = Condition::and(where_conditions).build_mysql();
149 sql.push_str(&format!(" WHERE {}", cond_sql));
150 params.extend(cond_params);
151 }
152 }
153
154 if !self.order_by.is_empty() {
155 let order_parts: Vec<String> = self
156 .order_by
157 .iter()
158 .map(|(col, order)| {
159 format!(
160 "{} {}",
161 col,
162 match order {
163 Order::Asc => "ASC",
164 Order::Desc => "DESC",
165 }
166 )
167 })
168 .collect();
169 sql.push_str(&format!(" ORDER BY {}", order_parts.join(", ")));
170 }
171
172 if let Some(limit) = self.limit {
173 sql.push_str(&format!(" LIMIT {}", limit));
174 }
175
176 if let Some(offset) = self.offset {
177 sql.push_str(&format!(" OFFSET {}", offset));
178 }
179
180 (sql, params)
181 }
182}
183
184pub struct InsertBuilder<E: Entity> {
186 data: Vec<(&'static str, Value)>,
187 _marker: PhantomData<E>,
188}
189
190impl<E: Entity> InsertBuilder<E> {
191 pub(crate) fn new() -> Self {
192 Self { data: Vec::new(), _marker: PhantomData }
193 }
194
195 pub fn from_entity<T: ToRow>(entity: &T) -> Self {
197 Self { data: entity.to_row(), _marker: PhantomData }
198 }
199
200 pub fn value(mut self, column: &'static str, value: Value) -> Self {
202 self.data.push((column, value));
203 self
204 }
205
206 pub fn values(mut self, data: Vec<(&'static str, Value)>) -> Self {
208 self.data.extend(data);
209 self
210 }
211
212 #[cfg(feature = "turso")]
213 pub(crate) fn build_turso(&self) -> (String, Vec<TursoValue>) {
215 let columns: Vec<&str> = self.data.iter().map(|(col, _)| *col).collect();
216 let placeholders: Vec<&str> = self.data.iter().map(|_| "?").collect();
217 let params: Vec<TursoValue> = self.data.iter().map(|(_, val)| from_wae_value(val.clone())).collect();
218
219 let sql = format!("INSERT INTO {} ({}) VALUES ({})", E::table_name(), columns.join(", "), placeholders.join(", "));
220
221 (sql, params)
222 }
223
224 #[cfg(feature = "mysql")]
225 pub(crate) fn build_mysql(&self) -> (String, Vec<MySqlValue>) {
227 let columns: Vec<&str> = self.data.iter().map(|(col, _)| *col).collect();
228 let placeholders: Vec<&str> = self.data.iter().map(|_| "?").collect();
229 let params: Vec<MySqlValue> = self.data.iter().map(|(_, val)| from_wae_to_mysql(val.clone())).collect();
230
231 let sql = format!("INSERT INTO {} ({}) VALUES ({})", E::table_name(), columns.join(", "), placeholders.join(", "));
232
233 (sql, params)
234 }
235}
236
237pub struct UpdateBuilder<E: Entity> {
239 data: Vec<(&'static str, Value)>,
240 conditions: Vec<Condition>,
241 _marker: PhantomData<E>,
242}
243
244impl<E: Entity> UpdateBuilder<E> {
245 pub(crate) fn new() -> Self {
246 Self { data: Vec::new(), conditions: Vec::new(), _marker: PhantomData }
247 }
248
249 pub fn set(mut self, column: &'static str, value: Value) -> Self {
251 self.data.push((column, value));
252 self
253 }
254
255 pub fn set_all(mut self, data: Vec<(&'static str, Value)>) -> Self {
257 self.data.extend(data);
258 self
259 }
260
261 pub fn from_entity<T: ToRow + Entity>(entity: &T) -> Self {
263 let id_col = T::id_column();
264 let data: Vec<(&'static str, Value)> = entity.to_row().into_iter().filter(|(col, _)| *col != id_col).collect();
265 Self { data, conditions: Vec::new(), _marker: PhantomData }
266 }
267
268 pub fn where_(mut self, condition: Condition) -> Self {
270 self.conditions.push(condition);
271 self
272 }
273
274 pub fn where_id(mut self, id: E::Id) -> Self {
276 self.conditions.push(Condition::eq(E::id_column(), id));
277 self
278 }
279
280 #[cfg(feature = "turso")]
281 pub(crate) fn build_turso(&self) -> (String, Vec<TursoValue>) {
283 let set_parts: Vec<String> = self.data.iter().map(|(col, _)| format!("{} = ?", col)).collect();
284 let mut params: Vec<TursoValue> = self.data.iter().map(|(_, val)| from_wae_value(val.clone())).collect();
285
286 let mut sql = format!("UPDATE {} SET {}", E::table_name(), set_parts.join(", "));
287
288 if !self.conditions.is_empty() {
289 let where_conditions = self.conditions.to_vec();
290 if where_conditions.len() == 1 {
291 let (cond_sql, cond_params) = where_conditions[0].build_turso();
292 sql.push_str(&format!(" WHERE {}", cond_sql));
293 params.extend(cond_params);
294 }
295 else {
296 let (cond_sql, cond_params) = Condition::and(where_conditions).build_turso();
297 sql.push_str(&format!(" WHERE {}", cond_sql));
298 params.extend(cond_params);
299 }
300 }
301
302 (sql, params)
303 }
304
305 #[cfg(feature = "mysql")]
306 pub(crate) fn build_mysql(&self) -> (String, Vec<MySqlValue>) {
308 let set_parts: Vec<String> = self.data.iter().map(|(col, _)| format!("{} = ?", col)).collect();
309 let mut params: Vec<MySqlValue> = self.data.iter().map(|(_, val)| from_wae_to_mysql(val.clone())).collect();
310
311 let mut sql = format!("UPDATE {} SET {}", E::table_name(), set_parts.join(", "));
312
313 if !self.conditions.is_empty() {
314 let where_conditions = self.conditions.to_vec();
315 if where_conditions.len() == 1 {
316 let (cond_sql, cond_params) = where_conditions[0].build_mysql();
317 sql.push_str(&format!(" WHERE {}", cond_sql));
318 params.extend(cond_params);
319 }
320 else {
321 let (cond_sql, cond_params) = Condition::and(where_conditions).build_mysql();
322 sql.push_str(&format!(" WHERE {}", cond_sql));
323 params.extend(cond_params);
324 }
325 }
326
327 (sql, params)
328 }
329}
330
331pub struct DeleteBuilder<E: Entity> {
333 conditions: Vec<Condition>,
334 _marker: PhantomData<E>,
335}
336
337impl<E: Entity> DeleteBuilder<E> {
338 pub(crate) fn new() -> Self {
339 Self { conditions: Vec::new(), _marker: PhantomData }
340 }
341
342 pub fn where_(mut self, condition: Condition) -> Self {
344 self.conditions.push(condition);
345 self
346 }
347
348 pub fn where_id(mut self, id: E::Id) -> Self {
350 self.conditions.push(Condition::eq(E::id_column(), id));
351 self
352 }
353
354 #[cfg(feature = "turso")]
355 pub(crate) fn build_turso(&self) -> (String, Vec<TursoValue>) {
357 let mut sql = format!("DELETE FROM {}", E::table_name());
358 let mut params = Vec::new();
359
360 if !self.conditions.is_empty() {
361 let where_conditions = self.conditions.to_vec();
362 if where_conditions.len() == 1 {
363 let (cond_sql, cond_params) = where_conditions[0].build_turso();
364 sql.push_str(&format!(" WHERE {}", cond_sql));
365 params.extend(cond_params);
366 }
367 else {
368 let (cond_sql, cond_params) = Condition::and(where_conditions).build_turso();
369 sql.push_str(&format!(" WHERE {}", cond_sql));
370 params.extend(cond_params);
371 }
372 }
373
374 (sql, params)
375 }
376
377 #[cfg(feature = "mysql")]
378 pub(crate) fn build_mysql(&self) -> (String, Vec<MySqlValue>) {
380 let mut sql = format!("DELETE FROM {}", E::table_name());
381 let mut params = Vec::new();
382
383 if !self.conditions.is_empty() {
384 let where_conditions = self.conditions.to_vec();
385 if where_conditions.len() == 1 {
386 let (cond_sql, cond_params) = where_conditions[0].build_mysql();
387 sql.push_str(&format!(" WHERE {}", cond_sql));
388 params.extend(cond_params);
389 }
390 else {
391 let (cond_sql, cond_params) = Condition::and(where_conditions).build_mysql();
392 sql.push_str(&format!(" WHERE {}", cond_sql));
393 params.extend(cond_params);
394 }
395 }
396
397 (sql, params)
398 }
399}
400
401pub struct QueryBuilder;
403
404impl QueryBuilder {
405 pub fn select<E: Entity>() -> SelectBuilder<E> {
407 SelectBuilder::new()
408 }
409
410 pub fn insert<E: Entity>() -> InsertBuilder<E> {
412 InsertBuilder::new()
413 }
414
415 pub fn update<E: Entity>() -> UpdateBuilder<E> {
417 UpdateBuilder::new()
418 }
419
420 pub fn delete<E: Entity>() -> DeleteBuilder<E> {
422 DeleteBuilder::new()
423 }
424}