Skip to main content

wae_database/orm/
builder.rs

1//! 查询构建器模块
2//!
3//! 提供 SELECT、INSERT、UPDATE、DELETE 查询构建器
4
5use 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
22/// JOIN 类型
23#[derive(Debug, Clone, Copy)]
24pub enum JoinType {
25    /// 内连接
26    Inner,
27    /// 左连接
28    Left,
29    /// 右连接
30    Right,
31    /// 全连接
32    Full,
33}
34
35/// JOIN 定义
36#[derive(Debug, Clone)]
37pub struct Join {
38    /// JOIN 类型
39    join_type: JoinType,
40    /// 表名
41    table: String,
42    /// ON 条件
43    on: Condition,
44}
45
46impl Join {
47    /// 创建新的 JOIN
48    pub fn new(join_type: JoinType, table: String, on: Condition) -> Self {
49        Self { join_type, table, on }
50    }
51}
52
53/// SELECT 查询构建器
54pub struct SelectBuilder<E: Entity> {
55    columns: Vec<String>,
56    joins: Vec<Join>,
57    conditions: Vec<Condition>,
58    group_by: Vec<String>,
59    having: Vec<Condition>,
60    order_by: Vec<(String, Order)>,
61    limit: Option<u64>,
62    offset: Option<u64>,
63    _marker: PhantomData<E>,
64}
65
66impl<E: Entity> SelectBuilder<E> {
67    pub(crate) fn new() -> Self {
68        Self {
69            columns: Vec::new(),
70            joins: Vec::new(),
71            conditions: Vec::new(),
72            group_by: Vec::new(),
73            having: Vec::new(),
74            order_by: Vec::new(),
75            limit: None,
76            offset: None,
77            _marker: PhantomData,
78        }
79    }
80
81    /// 选择指定列
82    pub fn columns(mut self, columns: &[&str]) -> Self {
83        self.columns = columns.iter().map(|s| s.to_string()).collect();
84        self
85    }
86
87    /// 添加 JOIN
88    pub fn join(mut self, join_type: JoinType, table: &str, on: Condition) -> Self {
89        self.joins.push(Join::new(join_type, table.to_string(), on));
90        self
91    }
92
93    /// 添加 INNER JOIN
94    pub fn inner_join(mut self, table: &str, on: Condition) -> Self {
95        self.joins.push(Join::new(JoinType::Inner, table.to_string(), on));
96        self
97    }
98
99    /// 添加 LEFT JOIN
100    pub fn left_join(mut self, table: &str, on: Condition) -> Self {
101        self.joins.push(Join::new(JoinType::Left, table.to_string(), on));
102        self
103    }
104
105    /// 添加 RIGHT JOIN
106    pub fn right_join(mut self, table: &str, on: Condition) -> Self {
107        self.joins.push(Join::new(JoinType::Right, table.to_string(), on));
108        self
109    }
110
111    /// 添加 FULL JOIN
112    pub fn full_join(mut self, table: &str, on: Condition) -> Self {
113        self.joins.push(Join::new(JoinType::Full, table.to_string(), on));
114        self
115    }
116
117    /// 添加 WHERE 条件
118    pub fn where_(mut self, condition: Condition) -> Self {
119        self.conditions.push(condition);
120        self
121    }
122
123    /// 添加多个 WHERE 条件 (AND 连接)
124    pub fn where_all(mut self, conditions: Vec<Condition>) -> Self {
125        self.conditions.extend(conditions);
126        self
127    }
128
129    /// 添加 GROUP BY
130    pub fn group_by(mut self, columns: &[&str]) -> Self {
131        self.group_by = columns.iter().map(|s| s.to_string()).collect();
132        self
133    }
134
135    /// 添加 HAVING 条件
136    pub fn having(mut self, condition: Condition) -> Self {
137        self.having.push(condition);
138        self
139    }
140
141    /// 添加多个 HAVING 条件 (AND 连接)
142    pub fn having_all(mut self, conditions: Vec<Condition>) -> Self {
143        self.having.extend(conditions);
144        self
145    }
146
147    /// 添加排序
148    pub fn order_by<C: Into<String>>(mut self, column: C, order: Order) -> Self {
149        self.order_by.push((column.into(), order));
150        self
151    }
152
153    /// 设置 LIMIT
154    pub fn limit(mut self, limit: u64) -> Self {
155        self.limit = Some(limit);
156        self
157    }
158
159    /// 设置 OFFSET
160    pub fn offset(mut self, offset: u64) -> Self {
161        self.offset = Some(offset);
162        self
163    }
164
165    #[cfg(feature = "turso")]
166    /// 构建 SQL 和参数 (内部使用)
167    pub(crate) fn build_turso(&self) -> (String, Vec<TursoValue>) {
168        let columns = if self.columns.is_empty() { "*".to_string() } else { self.columns.join(", ") };
169
170        let mut sql = format!("SELECT {} FROM {}", columns, E::table_name());
171        let mut params = Vec::new();
172
173        for join in &self.joins {
174            let (on_sql, on_params) = join.on.build_turso();
175            let join_type_str = match join.join_type {
176                JoinType::Inner => "INNER JOIN",
177                JoinType::Left => "LEFT JOIN",
178                JoinType::Right => "RIGHT JOIN",
179                JoinType::Full => "FULL JOIN",
180            };
181            sql.push_str(&format!(" {} {} ON {}", join_type_str, join.table, on_sql));
182            params.extend(on_params);
183        }
184
185        if !self.conditions.is_empty() {
186            let where_conditions = self.conditions.to_vec();
187            if where_conditions.len() == 1 {
188                let (cond_sql, cond_params) = where_conditions[0].build_turso();
189                sql.push_str(&format!(" WHERE {}", cond_sql));
190                params.extend(cond_params);
191            }
192            else {
193                let (cond_sql, cond_params) = Condition::and(where_conditions).build_turso();
194                sql.push_str(&format!(" WHERE {}", cond_sql));
195                params.extend(cond_params);
196            }
197        }
198
199        if !self.group_by.is_empty() {
200            sql.push_str(&format!(" GROUP BY {}", self.group_by.join(", ")));
201        }
202
203        if !self.having.is_empty() {
204            let having_conditions = self.having.to_vec();
205            if having_conditions.len() == 1 {
206                let (cond_sql, cond_params) = having_conditions[0].build_turso();
207                sql.push_str(&format!(" HAVING {}", cond_sql));
208                params.extend(cond_params);
209            }
210            else {
211                let (cond_sql, cond_params) = Condition::and(having_conditions).build_turso();
212                sql.push_str(&format!(" HAVING {}", cond_sql));
213                params.extend(cond_params);
214            }
215        }
216
217        if !self.order_by.is_empty() {
218            let order_parts: Vec<String> = self
219                .order_by
220                .iter()
221                .map(|(col, order)| {
222                    format!(
223                        "{} {}",
224                        col,
225                        match order {
226                            Order::Asc => "ASC",
227                            Order::Desc => "DESC",
228                        }
229                    )
230                })
231                .collect();
232            sql.push_str(&format!(" ORDER BY {}", order_parts.join(", ")));
233        }
234
235        if let Some(limit) = self.limit {
236            sql.push_str(&format!(" LIMIT {}", limit));
237        }
238
239        if let Some(offset) = self.offset {
240            sql.push_str(&format!(" OFFSET {}", offset));
241        }
242
243        (sql, params)
244    }
245
246    #[cfg(feature = "mysql")]
247    #[allow(dead_code)]
248    /// 构建 SQL 和参数 (内部使用 MySQL)
249    pub(crate) fn build_mysql(&self) -> (String, Vec<MySqlValue>) {
250        let columns = if self.columns.is_empty() { "*".to_string() } else { self.columns.join(", ") };
251
252        let mut sql = format!("SELECT {} FROM {}", columns, E::table_name());
253        let mut params = Vec::new();
254
255        for join in &self.joins {
256            let (on_sql, on_params) = join.on.build_mysql();
257            let join_type_str = match join.join_type {
258                JoinType::Inner => "INNER JOIN",
259                JoinType::Left => "LEFT JOIN",
260                JoinType::Right => "RIGHT JOIN",
261                JoinType::Full => "FULL JOIN",
262            };
263            sql.push_str(&format!(" {} {} ON {}", join_type_str, join.table, on_sql));
264            params.extend(on_params);
265        }
266
267        if !self.conditions.is_empty() {
268            let where_conditions = self.conditions.to_vec();
269            if where_conditions.len() == 1 {
270                let (cond_sql, cond_params) = where_conditions[0].build_mysql();
271                sql.push_str(&format!(" WHERE {}", cond_sql));
272                params.extend(cond_params);
273            }
274            else {
275                let (cond_sql, cond_params) = Condition::and(where_conditions).build_mysql();
276                sql.push_str(&format!(" WHERE {}", cond_sql));
277                params.extend(cond_params);
278            }
279        }
280
281        if !self.group_by.is_empty() {
282            sql.push_str(&format!(" GROUP BY {}", self.group_by.join(", ")));
283        }
284
285        if !self.having.is_empty() {
286            let having_conditions = self.having.to_vec();
287            if having_conditions.len() == 1 {
288                let (cond_sql, cond_params) = having_conditions[0].build_mysql();
289                sql.push_str(&format!(" HAVING {}", cond_sql));
290                params.extend(cond_params);
291            }
292            else {
293                let (cond_sql, cond_params) = Condition::and(having_conditions).build_mysql();
294                sql.push_str(&format!(" HAVING {}", cond_sql));
295                params.extend(cond_params);
296            }
297        }
298
299        if !self.order_by.is_empty() {
300            let order_parts: Vec<String> = self
301                .order_by
302                .iter()
303                .map(|(col, order)| {
304                    format!(
305                        "{} {}",
306                        col,
307                        match order {
308                            Order::Asc => "ASC",
309                            Order::Desc => "DESC",
310                        }
311                    )
312                })
313                .collect();
314            sql.push_str(&format!(" ORDER BY {}", order_parts.join(", ")));
315        }
316
317        if let Some(limit) = self.limit {
318            sql.push_str(&format!(" LIMIT {}", limit));
319        }
320
321        if let Some(offset) = self.offset {
322            sql.push_str(&format!(" OFFSET {}", offset));
323        }
324
325        (sql, params)
326    }
327
328    #[cfg(feature = "postgres")]
329    /// 构建 SQL 和参数 (内部使用 PostgreSQL)
330    pub(crate) fn build_postgres(&self) -> (String, Vec<crate::connection::postgres::PostgresParam>) {
331        let columns = if self.columns.is_empty() { "*".to_string() } else { self.columns.join(", ") };
332
333        let mut sql = format!("SELECT {} FROM {}", columns, E::table_name());
334        let mut params = Vec::new();
335        let mut param_offset = 0;
336
337        for join in &self.joins {
338            let (on_sql, on_params) = join.on.build_postgres();
339            let on_sql = replace_placeholders_for_query(&on_sql, param_offset + 1);
340            let join_type_str = match join.join_type {
341                JoinType::Inner => "INNER JOIN",
342                JoinType::Left => "LEFT JOIN",
343                JoinType::Right => "RIGHT JOIN",
344                JoinType::Full => "FULL JOIN",
345            };
346            sql.push_str(&format!(" {} {} ON {}", join_type_str, join.table, on_sql));
347            let on_params_len = on_params.len();
348            params.extend(on_params);
349            param_offset += on_params_len;
350        }
351
352        if !self.conditions.is_empty() {
353            let where_conditions = self.conditions.to_vec();
354            let (cond_sql, cond_params) = if where_conditions.len() == 1 {
355                where_conditions[0].build_postgres()
356            }
357            else {
358                Condition::and(where_conditions).build_postgres()
359            };
360            let cond_sql = replace_placeholders_for_query(&cond_sql, param_offset + 1);
361            sql.push_str(&format!(" WHERE {}", cond_sql));
362            let cond_params_len = cond_params.len();
363            params.extend(cond_params);
364            param_offset += cond_params_len;
365        }
366
367        if !self.group_by.is_empty() {
368            sql.push_str(&format!(" GROUP BY {}", self.group_by.join(", ")));
369        }
370
371        if !self.having.is_empty() {
372            let having_conditions = self.having.to_vec();
373            let (cond_sql, cond_params) = if having_conditions.len() == 1 {
374                having_conditions[0].build_postgres()
375            }
376            else {
377                Condition::and(having_conditions).build_postgres()
378            };
379            let cond_sql = replace_placeholders_for_query(&cond_sql, param_offset + 1);
380            sql.push_str(&format!(" HAVING {}", cond_sql));
381            params.extend(cond_params);
382        }
383
384        if !self.order_by.is_empty() {
385            let order_parts: Vec<String> = self
386                .order_by
387                .iter()
388                .map(|(col, order)| {
389                    format!(
390                        "{} {}",
391                        col,
392                        match order {
393                            Order::Asc => "ASC",
394                            Order::Desc => "DESC",
395                        }
396                    )
397                })
398                .collect();
399            sql.push_str(&format!(" ORDER BY {}", order_parts.join(", ")));
400        }
401
402        if let Some(limit) = self.limit {
403            sql.push_str(&format!(" LIMIT {}", limit));
404        }
405
406        if let Some(offset) = self.offset {
407            sql.push_str(&format!(" OFFSET {}", offset));
408        }
409
410        (sql, params)
411    }
412}
413
414#[cfg(feature = "postgres")]
415fn replace_placeholders_for_query(sql: &str, start_index: usize) -> String {
416    let mut result = String::new();
417    let mut chars = sql.chars().peekable();
418    while let Some(c) = chars.next() {
419        if c == '$' {
420            let mut num_str = String::new();
421            while let Some(&next_c) = chars.peek() {
422                if next_c.is_ascii_digit() {
423                    num_str.push(next_c);
424                    chars.next();
425                }
426                else {
427                    break;
428                }
429            }
430            if !num_str.is_empty() {
431                if let Ok(num) = num_str.parse::<usize>() {
432                    result.push_str(&format!("${}", num + start_index - 1));
433                }
434            }
435            else {
436                result.push(c);
437            }
438        }
439        else {
440            result.push(c);
441        }
442    }
443    result
444}
445
446/// INSERT 查询构建器
447pub struct InsertBuilder<E: Entity> {
448    data: Vec<(&'static str, Value)>,
449    _marker: PhantomData<E>,
450}
451
452impl<E: Entity> InsertBuilder<E> {
453    pub(crate) fn new() -> Self {
454        Self { data: Vec::new(), _marker: PhantomData }
455    }
456
457    /// 从实体创建
458    pub fn from_entity<T: ToRow>(entity: &T) -> Self {
459        Self { data: entity.to_row(), _marker: PhantomData }
460    }
461
462    /// 添加列值
463    pub fn value(mut self, column: &'static str, value: Value) -> Self {
464        self.data.push((column, value));
465        self
466    }
467
468    /// 批量添加列值
469    pub fn values(mut self, data: Vec<(&'static str, Value)>) -> Self {
470        self.data.extend(data);
471        self
472    }
473
474    #[cfg(feature = "turso")]
475    /// 构建 SQL 和参数 (内部使用)
476    pub(crate) fn build_turso(&self) -> (String, Vec<TursoValue>) {
477        let columns: Vec<&str> = self.data.iter().map(|(col, _)| *col).collect();
478        let placeholders: Vec<&str> = self.data.iter().map(|_| "?").collect();
479        let params: Vec<TursoValue> = self.data.iter().map(|(_, val)| from_wae_value(val.clone())).collect();
480
481        let sql = format!("INSERT INTO {} ({}) VALUES ({})", E::table_name(), columns.join(", "), placeholders.join(", "));
482
483        (sql, params)
484    }
485
486    #[cfg(feature = "mysql")]
487    /// 构建 SQL 和参数 (内部使用 MySQL)
488    pub(crate) fn build_mysql(&self) -> (String, Vec<MySqlValue>) {
489        let columns: Vec<&str> = self.data.iter().map(|(col, _)| *col).collect();
490        let placeholders: Vec<&str> = self.data.iter().map(|_| "?").collect();
491        let params: Vec<MySqlValue> = self.data.iter().map(|(_, val)| from_wae_to_mysql(val.clone())).collect();
492
493        let sql = format!("INSERT INTO {} ({}) VALUES ({})", E::table_name(), columns.join(", "), placeholders.join(", "));
494
495        (sql, params)
496    }
497}
498
499/// UPDATE 查询构建器
500pub struct UpdateBuilder<E: Entity> {
501    data: Vec<(&'static str, Value)>,
502    conditions: Vec<Condition>,
503    _marker: PhantomData<E>,
504}
505
506impl<E: Entity> UpdateBuilder<E> {
507    pub(crate) fn new() -> Self {
508        Self { data: Vec::new(), conditions: Vec::new(), _marker: PhantomData }
509    }
510
511    /// 设置列值
512    pub fn set(mut self, column: &'static str, value: Value) -> Self {
513        self.data.push((column, value));
514        self
515    }
516
517    /// 批量设置列值
518    pub fn set_all(mut self, data: Vec<(&'static str, Value)>) -> Self {
519        self.data.extend(data);
520        self
521    }
522
523    /// 从实体设置值 (排除主键)
524    pub fn from_entity<T: ToRow + Entity>(entity: &T) -> Self {
525        let id_col = T::id_column();
526        let data: Vec<(&'static str, Value)> = entity.to_row().into_iter().filter(|(col, _)| *col != id_col).collect();
527        Self { data, conditions: Vec::new(), _marker: PhantomData }
528    }
529
530    /// 添加 WHERE 条件
531    pub fn where_(mut self, condition: Condition) -> Self {
532        self.conditions.push(condition);
533        self
534    }
535
536    /// 按主键更新
537    pub fn where_id(mut self, id: E::Id) -> Self {
538        self.conditions.push(Condition::eq(E::id_column(), id));
539        self
540    }
541
542    #[cfg(feature = "turso")]
543    /// 构建 SQL 和参数 (内部使用)
544    pub(crate) fn build_turso(&self) -> (String, Vec<TursoValue>) {
545        let set_parts: Vec<String> = self.data.iter().map(|(col, _)| format!("{} = ?", col)).collect();
546        let mut params: Vec<TursoValue> = self.data.iter().map(|(_, val)| from_wae_value(val.clone())).collect();
547
548        let mut sql = format!("UPDATE {} SET {}", E::table_name(), set_parts.join(", "));
549
550        if !self.conditions.is_empty() {
551            let where_conditions = self.conditions.to_vec();
552            if where_conditions.len() == 1 {
553                let (cond_sql, cond_params) = where_conditions[0].build_turso();
554                sql.push_str(&format!(" WHERE {}", cond_sql));
555                params.extend(cond_params);
556            }
557            else {
558                let (cond_sql, cond_params) = Condition::and(where_conditions).build_turso();
559                sql.push_str(&format!(" WHERE {}", cond_sql));
560                params.extend(cond_params);
561            }
562        }
563
564        (sql, params)
565    }
566
567    #[cfg(feature = "mysql")]
568    /// 构建 SQL 和参数 (内部使用 MySQL)
569    pub(crate) fn build_mysql(&self) -> (String, Vec<MySqlValue>) {
570        let set_parts: Vec<String> = self.data.iter().map(|(col, _)| format!("{} = ?", col)).collect();
571        let mut params: Vec<MySqlValue> = self.data.iter().map(|(_, val)| from_wae_to_mysql(val.clone())).collect();
572
573        let mut sql = format!("UPDATE {} SET {}", E::table_name(), set_parts.join(", "));
574
575        if !self.conditions.is_empty() {
576            let where_conditions = self.conditions.to_vec();
577            if where_conditions.len() == 1 {
578                let (cond_sql, cond_params) = where_conditions[0].build_mysql();
579                sql.push_str(&format!(" WHERE {}", cond_sql));
580                params.extend(cond_params);
581            }
582            else {
583                let (cond_sql, cond_params) = Condition::and(where_conditions).build_mysql();
584                sql.push_str(&format!(" WHERE {}", cond_sql));
585                params.extend(cond_params);
586            }
587        }
588
589        (sql, params)
590    }
591}
592
593/// DELETE 查询构建器
594pub struct DeleteBuilder<E: Entity> {
595    conditions: Vec<Condition>,
596    _marker: PhantomData<E>,
597}
598
599impl<E: Entity> DeleteBuilder<E> {
600    pub(crate) fn new() -> Self {
601        Self { conditions: Vec::new(), _marker: PhantomData }
602    }
603
604    /// 添加 WHERE 条件
605    pub fn where_(mut self, condition: Condition) -> Self {
606        self.conditions.push(condition);
607        self
608    }
609
610    /// 按主键删除
611    pub fn where_id(mut self, id: E::Id) -> Self {
612        self.conditions.push(Condition::eq(E::id_column(), id));
613        self
614    }
615
616    #[cfg(feature = "turso")]
617    /// 构建 SQL 和参数 (内部使用)
618    pub(crate) fn build_turso(&self) -> (String, Vec<TursoValue>) {
619        let mut sql = format!("DELETE FROM {}", E::table_name());
620        let mut params = Vec::new();
621
622        if !self.conditions.is_empty() {
623            let where_conditions = self.conditions.to_vec();
624            if where_conditions.len() == 1 {
625                let (cond_sql, cond_params) = where_conditions[0].build_turso();
626                sql.push_str(&format!(" WHERE {}", cond_sql));
627                params.extend(cond_params);
628            }
629            else {
630                let (cond_sql, cond_params) = Condition::and(where_conditions).build_turso();
631                sql.push_str(&format!(" WHERE {}", cond_sql));
632                params.extend(cond_params);
633            }
634        }
635
636        (sql, params)
637    }
638
639    #[cfg(feature = "mysql")]
640    /// 构建 SQL 和参数 (内部使用 MySQL)
641    pub(crate) fn build_mysql(&self) -> (String, Vec<MySqlValue>) {
642        let mut sql = format!("DELETE FROM {}", E::table_name());
643        let mut params = Vec::new();
644
645        if !self.conditions.is_empty() {
646            let where_conditions = self.conditions.to_vec();
647            if where_conditions.len() == 1 {
648                let (cond_sql, cond_params) = where_conditions[0].build_mysql();
649                sql.push_str(&format!(" WHERE {}", cond_sql));
650                params.extend(cond_params);
651            }
652            else {
653                let (cond_sql, cond_params) = Condition::and(where_conditions).build_mysql();
654                sql.push_str(&format!(" WHERE {}", cond_sql));
655                params.extend(cond_params);
656            }
657        }
658
659        (sql, params)
660    }
661}
662
663/// 查询构建器入口
664pub struct QueryBuilder;
665
666impl QueryBuilder {
667    /// 创建 SELECT 构建器
668    pub fn select<E: Entity>() -> SelectBuilder<E> {
669        SelectBuilder::new()
670    }
671
672    /// 创建 INSERT 构建器
673    pub fn insert<E: Entity>() -> InsertBuilder<E> {
674        InsertBuilder::new()
675    }
676
677    /// 创建 UPDATE 构建器
678    pub fn update<E: Entity>() -> UpdateBuilder<E> {
679        UpdateBuilder::new()
680    }
681
682    /// 创建 DELETE 构建器
683    pub fn delete<E: Entity>() -> DeleteBuilder<E> {
684        DeleteBuilder::new()
685    }
686}