Skip to main content

yang_db/mysql/
query_builder.rs

1use crate::mysql::condition::{Condition, SqlValue};
2use crate::mysql::field::{FieldType, JoinClause, OrderClause};
3use sqlx::mysql::MySqlPool;
4use std::collections::HashMap;
5
6/// 将 SqlValue 绑定到 sqlx 查询的内部宏
7///
8/// 封装 SqlValue 各变体到 `.bind()` 调用的映射逻辑,消除 4 个 bind_param
9/// 函数中完全相同的 match 分支重复代码。未来新增 SqlValue 变体时,
10/// 只需在此宏中添加一个分支即可完成所有函数的更新。
11///
12/// # 参数
13/// - `$query`: sqlx 查询对象(支持 `.bind()` 方法的任意类型)
14/// - `$param`: `&SqlValue` 引用
15///
16/// # 返回
17/// 绑定参数后的查询对象(与 `$query` 类型相同)
18macro_rules! bind_value_match {
19    ($query:expr, $param:expr) => {
20        match $param {
21            // NULL 值:绑定为 Option<i32>::None
22            SqlValue::Null => $query.bind(Option::<i32>::None),
23            // 布尔值
24            SqlValue::Bool(b) => $query.bind(*b),
25            // 整数
26            SqlValue::Int(i) => $query.bind(*i),
27            // 浮点数
28            SqlValue::Float(f) => $query.bind(*f),
29            // 字符串(需要 clone 以满足 sqlx 的所有权要求)
30            SqlValue::String(s) => $query.bind(s.clone()),
31            // 字节数组(需要 clone)
32            SqlValue::Bytes(b) => $query.bind(b.clone()),
33            // JSON 值:序列化为字符串后绑定
34            SqlValue::Json(j) => $query.bind(j.to_string()),
35            // 日期时间
36            SqlValue::DateTime(dt) => $query.bind(*dt),
37            // 时间戳(整数)
38            SqlValue::Timestamp(ts) => $query.bind(*ts),
39        }
40    };
41}
42
43/// 批量插入的默认批次大小
44///
45/// 为了避免单次插入过多数据导致 SQL 语句过大或超时,
46/// 批量插入操作会自动将数据分批处理,每批最多插入 INSERT_BATCH_SIZE 条记录。
47const INSERT_BATCH_SIZE: usize = 500;
48
49/// 批量更新的默认批次大小
50const UPDATE_BATCH_SIZE: usize = 1000;
51
52/// SQL 生成器(内部使用)
53#[allow(dead_code)]
54pub(crate) struct SqlGenerator {
55    /// 生成的 SQL 语句
56    sql: String,
57    /// SQL 参数列表
58    params: Vec<SqlValue>,
59}
60
61#[allow(dead_code)]
62impl SqlGenerator {
63    /// 创建新的 SQL 生成器
64    ///
65    /// 预分配合理的缓冲区容量,减少 SQL 字符串构建过程中的重新分配次数:
66    /// - `sql` 预分配 256 字节,适合大多数 SQL 语句
67    /// - `params` 预分配 8 个槽位,适合大多数查询参数数量
68    pub(crate) fn new() -> Self {
69        Self {
70            // 预分配 256 字节,减少字符串扩容次数
71            sql: String::with_capacity(256),
72            // 预分配 8 个参数槽位,减少 Vec 扩容次数
73            params: Vec::with_capacity(8),
74        }
75    }
76
77    /// 获取生成的 SQL 语句
78    pub(crate) fn get_sql(&self) -> &str {
79        &self.sql
80    }
81
82    /// 获取参数列表
83    pub(crate) fn get_params(&self) -> &[SqlValue] {
84        &self.params
85    }
86
87    /// 添加 SQL 片段
88    fn append(&mut self, fragment: &str) {
89        self.sql.push_str(fragment);
90    }
91
92    /// 添加参数
93    fn add_param(&mut self, param: SqlValue) {
94        self.params.push(param);
95    }
96
97    /// 清空生成器(保留已分配容量,避免重复分配)
98    fn clear(&mut self) {
99        self.sql.clear();
100        self.params.clear();
101    }
102
103    /// 测试专用:暴露 clear 方法供测试模块调用
104    #[cfg(test)]
105    pub(crate) fn clear_for_test(&mut self) {
106        self.clear();
107    }
108
109    /// 测试专用:获取 sql 字段的当前容量
110    #[cfg(test)]
111    pub(crate) fn sql_capacity(&self) -> usize {
112        self.sql.capacity()
113    }
114
115    /// 测试专用:获取 params 字段的当前容量
116    #[cfg(test)]
117    pub(crate) fn params_capacity(&self) -> usize {
118        self.params.capacity()
119    }
120
121    /// 生成 SELECT 语句
122    ///
123    /// # 参数
124    /// - builder: QueryBuilder 引用
125    ///
126    /// # 返回
127    /// - Ok(()): 成功生成 SQL
128    /// - Err(DbError): 生成失败
129    fn build_select(&mut self, builder: &QueryBuilder) -> Result<(), crate::error::DbError> {
130        // 清空之前的内容
131        self.clear();
132
133        // SELECT 子句
134        self.append("SELECT ");
135
136        // DISTINCT 关键字
137        if builder.distinct {
138            self.append("DISTINCT ");
139        }
140
141        // 字段列表
142        if builder.fields.is_empty() {
143            self.append("*");
144        } else {
145            self.append(&builder.fields.join(", "));
146        }
147
148        // FROM 子句
149        self.append(" FROM ");
150        self.append(&builder.table);
151
152        // JOIN 子句
153        if !builder.joins.is_empty() {
154            self.build_joins(&builder.joins);
155        }
156
157        // WHERE 子句
158        if !builder.conditions.is_empty() {
159            self.build_where(&builder.conditions)?;
160        }
161
162        // GROUP BY 子句
163        if !builder.group_by.is_empty() {
164            self.build_group_by(&builder.group_by);
165        }
166
167        // HAVING 子句
168        if !builder.having_clause.is_empty() {
169            if builder.group_by.is_empty() {
170                return Err(crate::error::DbError::MissingGroupByClause);
171            }
172            self.build_having(&builder.having_clause)?;
173        }
174
175        // ORDER BY 子句
176        if !builder.order_by.is_empty() {
177            self.build_order_by(&builder.order_by);
178        }
179
180        // LIMIT 子句
181        if let Some(limit) = builder.limit {
182            self.append(&format!(" LIMIT {}", limit));
183        }
184
185        // OFFSET 子句
186        if let Some(offset) = builder.offset {
187            self.append(&format!(" OFFSET {}", offset));
188        }
189
190        Ok(())
191    }
192
193    /// 生成 WHERE 子句
194    ///
195    /// # 参数
196    /// - conditions: 条件列表
197    ///
198    /// # 返回
199    /// - Ok(()): 成功生成 WHERE 子句
200    /// - Err(DbError): 生成失败
201    fn build_where(&mut self, conditions: &[Condition]) -> Result<(), crate::error::DbError> {
202        if conditions.is_empty() {
203            return Ok(());
204        }
205
206        self.append(" WHERE ");
207
208        // 如果有多个条件,用 AND 连接
209        if conditions.len() == 1 {
210            let sql = crate::mysql::condition::condition_to_sql(&conditions[0], &mut self.params);
211            self.append(&sql);
212        } else {
213            // 多个条件用 AND 连接
214            let combined = Condition::And(conditions.to_vec());
215            let sql = crate::mysql::condition::condition_to_sql(&combined, &mut self.params);
216            self.append(&sql);
217        }
218
219        Ok(())
220    }
221
222    /// 生成 JOIN 子句
223    ///
224    /// # 参数
225    /// - joins: JOIN 子句列表
226    fn build_joins(&mut self, joins: &[JoinClause]) {
227        use crate::mysql::field::JoinType;
228
229        for join in joins {
230            let join_type_str = match join.join_type {
231                JoinType::Inner => " INNER JOIN ",
232                JoinType::Left => " LEFT JOIN ",
233                JoinType::Right => " RIGHT JOIN ",
234            };
235
236            self.append(join_type_str);
237            self.append(&join.table);
238            self.append(" ON ");
239            self.append(&join.on);
240        }
241    }
242
243    /// 生成 ORDER BY 子句
244    ///
245    /// # 参数
246    /// - orders: 排序子句列表
247    fn build_order_by(&mut self, orders: &[OrderClause]) {
248        if orders.is_empty() {
249            return;
250        }
251
252        self.append(" ORDER BY ");
253
254        let order_parts: Vec<String> = orders
255            .iter()
256            .map(|order| {
257                let direction = if order.asc { "ASC" } else { "DESC" };
258                format!("{} {}", order.field, direction)
259            })
260            .collect();
261
262        self.append(&order_parts.join(", "));
263    }
264
265    /// 生成 GROUP BY 子句
266    ///
267    /// # 参数
268    /// - groups: 分组字段列表
269    fn build_group_by(&mut self, groups: &[String]) {
270        if groups.is_empty() {
271            return;
272        }
273
274        self.append(" GROUP BY ");
275        self.append(&groups.join(", "));
276    }
277
278    /// 生成 HAVING 子句
279    fn build_having(&mut self, conditions: &[Condition]) -> Result<(), crate::error::DbError> {
280        self.append(" HAVING ");
281        if conditions.len() == 1 {
282            let sql = crate::mysql::condition::condition_to_sql(&conditions[0], &mut self.params);
283            self.append(&sql);
284        } else {
285            let parts: Vec<String> = conditions
286                .iter()
287                .map(|c| crate::mysql::condition::condition_to_sql(c, &mut self.params))
288                .collect();
289            self.append(&parts.join(" AND "));
290        }
291        Ok(())
292    }
293
294    /// 生成 INSERT 语句
295    ///
296    /// # 参数
297    /// - table: 表名
298    /// - data: 要插入的数据(JSON 格式)
299    /// - field_types: 字段类型映射
300    ///
301    /// # 返回
302    /// - Ok(()): 成功生成 SQL
303    /// - Err(DbError): 生成失败
304    pub(crate) fn build_insert(
305        &mut self,
306        table: &str,
307        data: &serde_json::Value,
308        field_types: &HashMap<String, FieldType>,
309    ) -> Result<(), crate::error::DbError> {
310        // 清空之前的内容
311        self.clear();
312
313        // 确保 data 是一个对象
314        let obj = data.as_object().ok_or_else(|| {
315            crate::error::DbError::SerializationError("插入数据必须是 JSON 对象".to_string())
316        })?;
317
318        if obj.is_empty() {
319            return Err(crate::error::DbError::SerializationError(
320                "插入数据不能为空".to_string(),
321            ));
322        }
323
324        // 提取字段名和值
325        let mut fields = Vec::new();
326        let mut placeholders = Vec::new();
327
328        for (key, value) in obj.iter() {
329            fields.push(key.clone());
330            placeholders.push("?".to_string());
331
332            // 根据字段类型转换值
333            let sql_value = self.json_value_to_sql_value(value, field_types.get(key))?;
334            self.add_param(sql_value);
335        }
336
337        // 构建 INSERT 语句
338        self.append("INSERT INTO ");
339        self.append(table);
340        self.append(" (");
341        self.append(&fields.join(", "));
342        self.append(") VALUES (");
343        self.append(&placeholders.join(", "));
344        self.append(")");
345
346        Ok(())
347    }
348
349    /// 生成批量 INSERT 语句
350    ///
351    /// # 参数
352    /// - table: 表名
353    /// - data_list: 要插入的数据列表(JSON 格式)
354    /// - field_types: 字段类型映射
355    ///
356    /// # 返回
357    /// - Ok(()): 成功生成 SQL
358    /// - Err(DbError): 生成失败
359    pub(crate) fn build_insert_batch(
360        &mut self,
361        table: &str,
362        data_list: &[serde_json::Value],
363        field_types: &HashMap<String, FieldType>,
364    ) -> Result<(), crate::error::DbError> {
365        // 清空之前的内容
366        self.clear();
367
368        if data_list.is_empty() {
369            return Err(crate::error::DbError::SerializationError(
370                "批量插入数据不能为空".to_string(),
371            ));
372        }
373
374        // 从第一条数据中提取字段名
375        let first_obj = data_list[0].as_object().ok_or_else(|| {
376            crate::error::DbError::SerializationError("插入数据必须是 JSON 对象".to_string())
377        })?;
378
379        if first_obj.is_empty() {
380            return Err(crate::error::DbError::SerializationError(
381                "插入数据不能为空".to_string(),
382            ));
383        }
384
385        // 提取字段名(从第一条记录)
386        let fields: Vec<String> = first_obj.keys().cloned().collect();
387
388        // 构建 INSERT 语句头部
389        self.append("INSERT INTO ");
390        self.append(table);
391        self.append(" (");
392        self.append(&fields.join(", "));
393        self.append(") VALUES ");
394
395        // 直接将每条记录的 VALUES 子句写入 self.sql,避免中间 Vec<String> 分配
396        for (record_idx, data) in data_list.iter().enumerate() {
397            // 记录之间用 ", " 分隔,直接追加到 sql,替代最终的 join 调用
398            if record_idx > 0 {
399                self.sql.push_str(", ");
400            }
401
402            let obj = data.as_object().ok_or_else(|| {
403                crate::error::DbError::SerializationError("插入数据必须是 JSON 对象".to_string())
404            })?;
405
406            // 直接写入 '(' 开始当前记录的占位符列表
407            self.sql.push('(');
408
409            // 逐字段追加 '?' 占位符,替代 format!("({})", placeholders.join(", ")) 模式
410            for (field_idx, field) in fields.iter().enumerate() {
411                // 字段之间用 ", " 分隔
412                if field_idx > 0 {
413                    self.sql.push_str(", ");
414                }
415                self.sql.push('?');
416
417                // 获取字段值,如果不存在则使用 NULL
418                let value = obj.get(field).unwrap_or(&serde_json::Value::Null);
419
420                // 根据字段类型转换值并绑定参数
421                let sql_value = self.json_value_to_sql_value(value, field_types.get(field))?;
422                self.add_param(sql_value);
423            }
424
425            // 直接写入 ')' 结束当前记录的占位符列表
426            self.sql.push(')');
427        }
428
429        Ok(())
430    }
431
432    /// 生成 UPDATE 语句
433    ///
434    /// # 参数
435    /// - table: 表名
436    /// - data: 要更新的数据(JSON 格式)
437    /// - field_types: 字段类型映射
438    /// - conditions: WHERE 条件列表
439    ///
440    /// # 返回
441    /// - Ok(()): 成功生成 SQL
442    /// - Err(DbError): 生成失败
443    pub(crate) fn build_update(
444        &mut self,
445        table: &str,
446        data: &serde_json::Value,
447        field_types: &HashMap<String, FieldType>,
448        conditions: &[Condition],
449    ) -> Result<(), crate::error::DbError> {
450        // 清空之前的内容
451        self.clear();
452
453        // 检查是否有 WHERE 条件
454        if conditions.is_empty() {
455            return Err(crate::error::DbError::MissingWhereClause);
456        }
457
458        // 确保 data 是一个对象
459        let obj = data.as_object().ok_or_else(|| {
460            crate::error::DbError::SerializationError("更新数据必须是 JSON 对象".to_string())
461        })?;
462
463        if obj.is_empty() {
464            return Err(crate::error::DbError::SerializationError(
465                "更新数据不能为空".to_string(),
466            ));
467        }
468
469        // 构建 UPDATE 语句
470        self.append("UPDATE ");
471        self.append(table);
472        self.append(" SET ");
473
474        // 构建 SET 子句
475        let mut set_clauses = Vec::new();
476
477        for (key, value) in obj.iter() {
478            set_clauses.push(format!("{} = ?", key));
479
480            // 根据字段类型转换值
481            let sql_value = self.json_value_to_sql_value(value, field_types.get(key))?;
482            self.add_param(sql_value);
483        }
484
485        self.append(&set_clauses.join(", "));
486
487        // 添加 WHERE 子句
488        self.build_where(conditions)?;
489
490        Ok(())
491    }
492
493    /// 生成 DELETE 语句
494    ///
495    /// # 参数
496    /// - table: 表名
497    /// - conditions: WHERE 条件列表
498    ///
499    /// # 返回
500    /// - Ok(()): 成功生成 SQL
501    /// - Err(DbError): 生成失败
502    pub(crate) fn build_delete(
503        &mut self,
504        table: &str,
505        conditions: &[Condition],
506    ) -> Result<(), crate::error::DbError> {
507        // 清空之前的内容
508        self.clear();
509
510        // 检查是否有 WHERE 条件
511        if conditions.is_empty() {
512            return Err(crate::error::DbError::MissingWhereClause);
513        }
514
515        // 构建 DELETE 语句
516        self.append("DELETE FROM ");
517        self.append(table);
518
519        // 添加 WHERE 子句
520        self.build_where(conditions)?;
521
522        Ok(())
523    }
524
525    /// 生成批量 UPDATE 语句(CASE WHEN 策略)
526    ///
527    /// 优化:直接将 CASE WHEN 子句写入 self.sql,消除 O(M×N) 的中间字符串分配。
528    /// 每个字段只需一次 push_str 操作序列,中间分配次数降至 O(M) 级别。
529    pub(crate) fn build_update_batch(
530        &mut self,
531        table: &str,
532        records: &[serde_json::Value],
533        id_field: &str,
534        field_types: &std::collections::HashMap<String, FieldType>,
535    ) -> Result<(), crate::error::DbError> {
536        self.clear();
537
538        if records.is_empty() {
539            return Err(crate::error::DbError::SerializationError(
540                "批量更新数据不能为空".to_string(),
541            ));
542        }
543
544        let first = records[0].as_object().ok_or_else(|| {
545            crate::error::DbError::SerializationError("更新数据必须是 JSON 对象".to_string())
546        })?;
547
548        // 收集需要更新的字段名(排除主键字段),O(M) 次分配
549        let update_fields: Vec<String> = first
550            .keys()
551            .filter(|k| k.as_str() != id_field)
552            .cloned()
553            .collect();
554
555        if update_fields.is_empty() {
556            return Err(crate::error::DbError::SerializationError(
557                "没有可更新的字段".to_string(),
558            ));
559        }
560
561        // 写入 UPDATE ... SET 头部
562        self.sql.push_str("UPDATE ");
563        self.sql.push_str(table);
564        self.sql.push_str(" SET ");
565
566        // 为每个字段生成 CASE WHEN 子句,直接追加到 self.sql
567        // 消除了原来的 Vec<String> set_parts 和 Vec<String> when_parts 中间分配
568        for (field_idx, field) in update_fields.iter().enumerate() {
569            // 字段之间用 ", " 分隔
570            if field_idx > 0 {
571                self.sql.push_str(", ");
572            }
573
574            // 写入 "字段名 = CASE "
575            self.sql.push_str(field);
576            self.sql.push_str(" = CASE ");
577
578            // 为每条记录生成 WHEN id=? THEN ? 子句,直接追加,替代 format! 收集再 join 的模式
579            for record in records {
580                let id_val = record.get(id_field).unwrap_or(&serde_json::Value::Null);
581                let field_val = record.get(field.as_str()).unwrap_or(&serde_json::Value::Null);
582
583                // 先转换参数值(避免借用冲突),再追加 SQL 片段和参数
584                let id_sql_val = self.json_value_to_sql_value(id_val, field_types.get(id_field))?;
585                let field_sql_val =
586                    self.json_value_to_sql_value(field_val, field_types.get(field.as_str()))?;
587
588                // 直接追加 WHEN id=? THEN ? 片段,替代 format!("WHEN {}=? THEN ?", id_field)
589                self.sql.push_str("WHEN ");
590                self.sql.push_str(id_field);
591                self.sql.push_str("=? THEN ? ");
592
593                // 绑定 id 参数和字段值参数
594                self.params.push(id_sql_val);
595                self.params.push(field_sql_val);
596            }
597
598            // 写入 CASE 结束标记
599            self.sql.push_str("END");
600        }
601
602        // 生成 WHERE id IN (?, ?, ...) 子句
603        self.sql.push_str(" WHERE ");
604        self.sql.push_str(id_field);
605        self.sql.push_str(" IN (");
606
607        // 直接追加占位符,替代 Vec<&str> 收集再 join 的模式
608        for (idx, record) in records.iter().enumerate() {
609            if idx > 0 {
610                self.sql.push(',');
611            }
612            self.sql.push('?');
613
614            // 绑定 WHERE IN 子句中的 id 参数
615            let id_val = record.get(id_field).unwrap_or(&serde_json::Value::Null);
616            let id_sql_val = self.json_value_to_sql_value(id_val, field_types.get(id_field))?;
617            self.params.push(id_sql_val);
618        }
619
620        self.sql.push(')');
621
622        Ok(())
623    }
624
625    /// 生成 UPSERT (INSERT ... ON DUPLICATE KEY UPDATE) 语句
626    pub(crate) fn build_upsert(
627        &mut self,
628        table: &str,
629        data: &serde_json::Value,
630        field_types: &std::collections::HashMap<String, FieldType>,
631    ) -> Result<(), crate::error::DbError> {
632        self.clear();
633
634        let obj = data.as_object().ok_or_else(|| {
635            crate::error::DbError::SerializationError("插入数据必须是 JSON 对象".to_string())
636        })?;
637
638        if obj.is_empty() {
639            return Err(crate::error::DbError::SerializationError(
640                "插入数据不能为空".to_string(),
641            ));
642        }
643
644        let fields: Vec<String> = obj.keys().cloned().collect();
645        let placeholders: Vec<&str> = fields.iter().map(|_| "?").collect();
646
647        self.append(&format!(
648            "INSERT INTO {} ({}) VALUES ({})",
649            table,
650            fields.join(", "),
651            placeholders.join(", ")
652        ));
653
654        for field in &fields {
655            let val = obj.get(field.as_str()).unwrap_or(&serde_json::Value::Null);
656            self.add_param(self.json_value_to_sql_value(val, field_types.get(field.as_str()))?);
657        }
658
659        let update_parts: Vec<String> = fields
660            .iter()
661            .map(|f| format!("{}=VALUES({})", f, f))
662            .collect();
663
664        self.append(&format!(
665            " ON DUPLICATE KEY UPDATE {}",
666            update_parts.join(", ")
667        ));
668
669        Ok(())
670    }
671
672    ///
673    /// # 参数
674    /// - value: JSON 值
675    /// - field_type: 字段类型(可选)
676    ///
677    /// # 返回
678    /// - Ok(SqlValue): 转换后的 SQL 值
679    /// - Err(DbError): 转换失败
680    fn json_value_to_sql_value(
681        &self,
682        value: &serde_json::Value,
683        field_type: Option<&FieldType>,
684    ) -> Result<SqlValue, crate::error::DbError> {
685        use serde_json::Value;
686
687        // 如果有字段类型标记,优先使用
688        if let Some(ft) = field_type {
689            match ft {
690                FieldType::Json => {
691                    // JSON 类型:直接存储为 JSON
692                    return Ok(SqlValue::Json(value.clone()));
693                }
694                FieldType::DateTime => {
695                    // DATETIME 类型:期望字符串格式
696                    if let Some(s) = value.as_str() {
697                        let dt = chrono::NaiveDateTime::parse_from_str(s, "%Y-%m-%d %H:%M:%S")
698                            .map_err(|e| {
699                                crate::error::DbError::TypeConversionError(format!(
700                                    "无法解析 DATETIME 字符串: {}",
701                                    e
702                                ))
703                            })?;
704                        return Ok(SqlValue::DateTime(dt));
705                    }
706                }
707                FieldType::Timestamp => {
708                    // TIMESTAMP 类型:期望整数
709                    if let Some(i) = value.as_i64() {
710                        return Ok(SqlValue::Timestamp(i));
711                    }
712                }
713                FieldType::Decimal => {
714                    // DECIMAL 类型:转换为浮点数
715                    if let Some(f) = value.as_f64() {
716                        return Ok(SqlValue::Float(f));
717                    } else if let Some(i) = value.as_i64() {
718                        return Ok(SqlValue::Float(i as f64));
719                    }
720                }
721                FieldType::Blob => {
722                    // BLOB 类型:期望字节数组或 base64 字符串
723                    if let Some(s) = value.as_str() {
724                        // 尝试解析为 base64
725                        use base64::Engine;
726                        if let Ok(bytes) = base64::engine::general_purpose::STANDARD.decode(s) {
727                            return Ok(SqlValue::Bytes(bytes));
728                        }
729                        // 否则直接转换为字节
730                        return Ok(SqlValue::Bytes(s.as_bytes().to_vec()));
731                    }
732                }
733                FieldType::Text => {
734                    // TEXT 类型:转换为字符串
735                    if let Some(s) = value.as_str() {
736                        return Ok(SqlValue::String(s.to_string()));
737                    }
738                }
739                FieldType::Standard => {
740                    // 标准类型:按照默认规则处理
741                }
742            }
743        }
744
745        // 默认转换规则
746        match value {
747            Value::Null => Ok(SqlValue::Null),
748            Value::Bool(b) => Ok(SqlValue::Bool(*b)),
749            Value::Number(n) => {
750                if let Some(i) = n.as_i64() {
751                    Ok(SqlValue::Int(i))
752                } else if let Some(f) = n.as_f64() {
753                    Ok(SqlValue::Float(f))
754                } else {
755                    Err(crate::error::DbError::TypeConversionError(
756                        "无法转换数字类型".to_string(),
757                    ))
758                }
759            }
760            Value::String(s) => Ok(SqlValue::String(s.clone())),
761            Value::Array(_) | Value::Object(_) => {
762                // 数组和对象默认序列化为 JSON
763                Ok(SqlValue::Json(value.clone()))
764            }
765        }
766    }
767}
768
769/// 查询构建器
770pub struct QueryBuilder<'a> {
771    #[allow(dead_code)]
772    pool: &'a MySqlPool,
773    table: String,
774    fields: Vec<String>,
775    #[allow(dead_code)]
776    conditions: Vec<Condition>,
777    #[allow(dead_code)]
778    joins: Vec<JoinClause>,
779    #[allow(dead_code)]
780    order_by: Vec<OrderClause>,
781    #[allow(dead_code)]
782    group_by: Vec<String>,
783    #[allow(dead_code)]
784    having_clause: Vec<Condition>,
785    limit: Option<u64>,
786    offset: Option<u64>,
787    distinct: bool,
788    field_types: HashMap<String, FieldType>,
789    #[allow(dead_code)]
790    enable_logging: bool,
791}
792
793impl<'a> QueryBuilder<'a> {
794    /// 创建新的查询构建器
795    pub(crate) fn new(pool: &'a MySqlPool, table_name: &str, enable_logging: bool) -> Self {
796        Self {
797            pool,
798            table: table_name.to_string(),
799            fields: Vec::new(),
800            conditions: Vec::new(),
801            joins: Vec::new(),
802            order_by: Vec::new(),
803            group_by: Vec::new(),
804            having_clause: Vec::new(),
805            limit: None,
806            offset: None,
807            distinct: false,
808            field_types: HashMap::new(),
809            enable_logging,
810        }
811    }
812
813    /// 选择字段
814    pub fn field(mut self, field: &str) -> Self {
815        self.fields.push(field.to_string());
816        self
817    }
818
819    /// 选择多个字段
820    pub fn fields(mut self, fields: &[&str]) -> Self {
821        for field in fields {
822            self.fields.push(field.to_string());
823        }
824        self
825    }
826
827    /// 标记字段为 JSON 类型
828    pub fn json(mut self, field: &str) -> Self {
829        self.field_types.insert(field.to_string(), FieldType::Json);
830        self
831    }
832
833    /// 标记字段为 DATETIME 类型
834    pub fn datetime(mut self, field: &str) -> Self {
835        self.field_types
836            .insert(field.to_string(), FieldType::DateTime);
837        self
838    }
839
840    /// 标记字段为 TIMESTAMP 类型
841    pub fn timestamp(mut self, field: &str) -> Self {
842        self.field_types
843            .insert(field.to_string(), FieldType::Timestamp);
844        self
845    }
846
847    /// 标记字段为 DECIMAL 类型
848    pub fn decimal(mut self, field: &str) -> Self {
849        self.field_types
850            .insert(field.to_string(), FieldType::Decimal);
851        self
852    }
853
854    /// 标记字段为 BLOB 类型
855    pub fn blob(mut self, field: &str) -> Self {
856        self.field_types.insert(field.to_string(), FieldType::Blob);
857        self
858    }
859
860    /// 标记字段为 TEXT 类型
861    pub fn text(mut self, field: &str) -> Self {
862        self.field_types.insert(field.to_string(), FieldType::Text);
863        self
864    }
865
866    /// 去重
867    pub fn distinct(mut self) -> Self {
868        self.distinct = true;
869        self
870    }
871
872    /// 添加 AND 条件
873    ///
874    /// 遇到不支持的操作符时返回 `Err(DbError::UnsupportedOperator)`。
875    /// 支持的操作符:`=`、`!=`、`>`、`<`、`>=`、`<=`、`like`、`LIKE`。
876    ///
877    /// # 参数
878    /// - `field`: 字段名
879    /// - `op`: 比较操作符
880    /// - `value`: 比较值
881    ///
882    /// # 返回
883    /// - `Ok(Self)`: 操作符合法,条件已添加
884    /// - `Err(DbError::UnsupportedOperator)`: 操作符不在支持集合中
885    pub fn where_and<V>(mut self, field: &str, op: &str, value: V) -> Result<Self, crate::error::DbError>
886    where
887        V: Into<crate::mysql::condition::SqlValue>,
888    {
889        use crate::mysql::condition::{Condition, SqlValue};
890
891        let sql_value = value.into();
892        let condition = match op {
893            "=" => Condition::Eq(field.to_string(), sql_value),
894            "!=" => Condition::Ne(field.to_string(), sql_value),
895            ">" => Condition::Gt(field.to_string(), sql_value),
896            "<" => Condition::Lt(field.to_string(), sql_value),
897            ">=" => Condition::Gte(field.to_string(), sql_value),
898            "<=" => Condition::Lte(field.to_string(), sql_value),
899            "like" | "LIKE" => {
900                if let SqlValue::String(s) = sql_value {
901                    Condition::Like(field.to_string(), s)
902                } else {
903                    // 如果不是字符串,转换为字符串
904                    Condition::Like(field.to_string(), format!("{:?}", sql_value))
905                }
906            }
907            // 不支持的操作符:返回错误而非 panic
908            _ => return Err(crate::error::DbError::UnsupportedOperator(op.to_string())),
909        };
910
911        self.conditions.push(condition);
912        Ok(self)
913    }
914
915    /// 添加 AND 条件(不检查操作符,保持向后兼容)
916    ///
917    /// 与 `where_and` 相同,但遇到不支持的操作符时直接 panic,
918    /// 保持原有行为,供需要链式调用且确定操作符合法的场景使用。
919    ///
920    /// # 参数
921    /// - `field`: 字段名
922    /// - `op`: 比较操作符(必须是支持的操作符,否则 panic)
923    /// - `value`: 比较值
924    pub fn where_and_unchecked<V>(self, field: &str, op: &str, value: V) -> Self
925    where
926        V: Into<crate::mysql::condition::SqlValue>,
927    {
928        // 调用 where_and 并在出错时 panic,保持原有行为
929        self.where_and(field, op, value)
930            .unwrap_or_else(|e| panic!("{}", e))
931    }
932
933    /// 添加 OR 条件
934    ///
935    /// 遇到不支持的操作符时返回 `Err(DbError::UnsupportedOperator)`。
936    /// 支持的操作符:`=`、`!=`、`>`、`<`、`>=`、`<=`、`like`、`LIKE`。
937    ///
938    /// # 参数
939    /// - `field`: 字段名
940    /// - `op`: 比较操作符
941    /// - `value`: 比较值
942    ///
943    /// # 返回
944    /// - `Ok(Self)`: 操作符合法,条件已添加
945    /// - `Err(DbError::UnsupportedOperator)`: 操作符不在支持集合中
946    pub fn where_or<V>(mut self, field: &str, op: &str, value: V) -> Result<Self, crate::error::DbError>
947    where
948        V: Into<crate::mysql::condition::SqlValue>,
949    {
950        use crate::mysql::condition::{Condition, SqlValue};
951
952        let sql_value = value.into();
953        let condition = match op {
954            "=" => Condition::Eq(field.to_string(), sql_value),
955            "!=" => Condition::Ne(field.to_string(), sql_value),
956            ">" => Condition::Gt(field.to_string(), sql_value),
957            "<" => Condition::Lt(field.to_string(), sql_value),
958            ">=" => Condition::Gte(field.to_string(), sql_value),
959            "<=" => Condition::Lte(field.to_string(), sql_value),
960            "like" | "LIKE" => {
961                if let SqlValue::String(s) = sql_value {
962                    Condition::Like(field.to_string(), s)
963                } else {
964                    Condition::Like(field.to_string(), format!("{:?}", sql_value))
965                }
966            }
967            // 不支持的操作符:返回错误而非 panic
968            _ => return Err(crate::error::DbError::UnsupportedOperator(op.to_string())),
969        };
970
971        // 如果已有条件,将新条件与现有条件用 OR 组合
972        if !self.conditions.is_empty() {
973            let existing = std::mem::take(&mut self.conditions);
974            self.conditions.push(Condition::Or(vec![
975                if existing.len() == 1 {
976                    existing.into_iter().next().unwrap()
977                } else {
978                    Condition::And(existing)
979                },
980                condition,
981            ]));
982        } else {
983            self.conditions.push(condition);
984        }
985
986        Ok(self)
987    }
988
989    /// 添加 OR 条件(不检查操作符,保持向后兼容)
990    ///
991    /// 与 `where_or` 相同,但遇到不支持的操作符时直接 panic,
992    /// 保持原有行为,供需要链式调用且确定操作符合法的场景使用。
993    ///
994    /// # 参数
995    /// - `field`: 字段名
996    /// - `op`: 比较操作符(必须是支持的操作符,否则 panic)
997    /// - `value`: 比较值
998    pub fn where_or_unchecked<V>(self, field: &str, op: &str, value: V) -> Self
999    where
1000        V: Into<crate::mysql::condition::SqlValue>,
1001    {
1002        // 调用 where_or 并在出错时 panic,保持原有行为
1003        self.where_or(field, op, value)
1004            .unwrap_or_else(|e| panic!("{}", e))
1005    }
1006
1007    /// 添加 IN 条件
1008    pub fn where_in<V>(mut self, field: &str, values: Vec<V>) -> Self
1009    where
1010        V: Into<crate::mysql::condition::SqlValue>,
1011    {
1012        use crate::mysql::condition::Condition;
1013
1014        let sql_values: Vec<_> = values.into_iter().map(|v| v.into()).collect();
1015        self.conditions
1016            .push(Condition::In(field.to_string(), sql_values));
1017        self
1018    }
1019
1020    /// 添加 BETWEEN 条件
1021    pub fn where_between<V>(mut self, field: &str, start: V, end: V) -> Self
1022    where
1023        V: Into<crate::mysql::condition::SqlValue>,
1024    {
1025        use crate::mysql::condition::Condition;
1026
1027        self.conditions.push(Condition::Between(
1028            field.to_string(),
1029            start.into(),
1030            end.into(),
1031        ));
1032        self
1033    }
1034
1035    /// 添加 IS NULL 条件
1036    ///
1037    /// 生成 `field IS NULL` 子句,用于查询字段值为 NULL 的记录。
1038    ///
1039    /// # 参数
1040    /// - `field`: 字段名
1041    ///
1042    /// # 示例
1043    /// ```no_run
1044    /// # use yang_db::Database;
1045    /// # async fn example() -> Result<(), yang_db::DbError> {
1046    /// # let db = Database::connect("mysql://root:password@localhost/test").await?;
1047    /// # #[derive(serde::Deserialize, sqlx::FromRow)] struct User;
1048    /// let users = db.table("users")
1049    ///     .where_null("deleted_at")
1050    ///     .select::<User>()
1051    ///     .await?;
1052    /// # Ok(())
1053    /// # }
1054    /// ```
1055    pub fn where_null(mut self, field: &str) -> Self {
1056        self.conditions.push(Condition::IsNull(field.to_string()));
1057        self
1058    }
1059
1060    /// 添加 IS NOT NULL 条件
1061    ///
1062    /// 生成 `field IS NOT NULL` 子句,用于查询字段值不为 NULL 的记录。
1063    ///
1064    /// # 参数
1065    /// - `field`: 字段名
1066    pub fn where_not_null(mut self, field: &str) -> Self {
1067        self.conditions
1068            .push(Condition::IsNotNull(field.to_string()));
1069        self
1070    }
1071
1072    /// 添加 HAVING 条件
1073    ///
1074    /// 对 GROUP BY 分组后的结果进行过滤。必须与 `group()` 方法配合使用,
1075    /// 否则查询执行时返回 `MissingGroupByClause` 错误。
1076    /// 多次调用将以 AND 连接所有条件。
1077    ///
1078    /// # 参数
1079    /// - `field`: 聚合字段或聚合表达式(如 `"cnt"`)
1080    /// - `op`: 比较运算符("="、"!="、">"、"<"、">="、"<=")
1081    /// - `value`: 比较值(参数化,防 SQL 注入)
1082    ///
1083    /// # 示例
1084    /// ```no_run
1085    /// # use yang_db::Database;
1086    /// # async fn example() -> Result<(), yang_db::DbError> {
1087    /// # let db = Database::connect("mysql://root:password@localhost/test").await?;
1088    /// # #[derive(serde::Deserialize, sqlx::FromRow)] struct OrderSummary;
1089    /// let result = db.table("orders")
1090    ///     .field("user_id")
1091    ///     .field("COUNT(*) as cnt")
1092    ///     .group("user_id")
1093    ///     .having_cond("cnt", ">", 5i64)
1094    ///     .select::<OrderSummary>()
1095    ///     .await?;
1096    /// # Ok(())
1097    /// # }
1098    /// ```
1099    pub fn having_cond<V>(mut self, field: &str, op: &str, value: V) -> Result<Self, crate::error::DbError>
1100    where
1101        V: Into<crate::mysql::condition::SqlValue>,
1102    {
1103        let sql_value = value.into();
1104        let condition = match op {
1105            "=" => Condition::Eq(field.to_string(), sql_value),
1106            "!=" => Condition::Ne(field.to_string(), sql_value),
1107            ">" => Condition::Gt(field.to_string(), sql_value),
1108            "<" => Condition::Lt(field.to_string(), sql_value),
1109            ">=" => Condition::Gte(field.to_string(), sql_value),
1110            "<=" => Condition::Lte(field.to_string(), sql_value),
1111            // 不支持的操作符:返回错误而非 panic
1112            _ => return Err(crate::error::DbError::UnsupportedOperator(op.to_string())),
1113        };
1114        self.having_clause.push(condition);
1115        Ok(self)
1116    }
1117
1118    /// 添加 HAVING 条件(不检查操作符,保持向后兼容)
1119    ///
1120    /// 与 `having_cond` 相同,但遇到不支持的操作符时直接 panic,
1121    /// 保持原有行为,供需要链式调用且确定操作符合法的场景使用。
1122    ///
1123    /// # 参数
1124    /// - `field`: 聚合字段或聚合表达式
1125    /// - `op`: 比较运算符(必须是支持的操作符,否则 panic)
1126    /// - `value`: 比较值
1127    pub fn having_cond_unchecked<V>(self, field: &str, op: &str, value: V) -> Self
1128    where
1129        V: Into<crate::mysql::condition::SqlValue>,
1130    {
1131        // 调用 having_cond 并在出错时 panic,保持原有行为
1132        self.having_cond(field, op, value)
1133            .unwrap_or_else(|e| panic!("{}", e))
1134    }
1135
1136    /// INNER JOIN
1137    pub fn join(mut self, table: &str, on: &str) -> Self {
1138        use crate::mysql::field::{JoinClause, JoinType};
1139
1140        self.joins.push(JoinClause {
1141            join_type: JoinType::Inner,
1142            table: table.to_string(),
1143            on: on.to_string(),
1144        });
1145        self
1146    }
1147
1148    /// LEFT JOIN
1149    pub fn left_join(mut self, table: &str, on: &str) -> Self {
1150        use crate::mysql::field::{JoinClause, JoinType};
1151
1152        self.joins.push(JoinClause {
1153            join_type: JoinType::Left,
1154            table: table.to_string(),
1155            on: on.to_string(),
1156        });
1157        self
1158    }
1159
1160    /// RIGHT JOIN
1161    pub fn right_join(mut self, table: &str, on: &str) -> Self {
1162        use crate::mysql::field::{JoinClause, JoinType};
1163
1164        self.joins.push(JoinClause {
1165            join_type: JoinType::Right,
1166            table: table.to_string(),
1167            on: on.to_string(),
1168        });
1169        self
1170    }
1171
1172    /// 排序
1173    pub fn order(mut self, field: &str, asc: bool) -> Self {
1174        use crate::mysql::field::OrderClause;
1175
1176        self.order_by.push(OrderClause {
1177            field: field.to_string(),
1178            asc,
1179        });
1180        self
1181    }
1182
1183    /// 分组
1184    pub fn group(mut self, field: &str) -> Self {
1185        self.group_by.push(field.to_string());
1186        self
1187    }
1188
1189    /// 限制返回数量
1190    pub fn limit(mut self, limit: u64) -> Self {
1191        self.limit = Some(limit);
1192        self
1193    }
1194
1195    /// 偏移量
1196    pub fn offset(mut self, offset: u64) -> Self {
1197        self.offset = Some(offset);
1198        self
1199    }
1200
1201    /// 获取生成的 SQL(用于调试)
1202    ///
1203    /// # 返回
1204    /// - 生成的完整 SQL 语句字符串
1205    pub fn to_sql(&self) -> String {
1206        let mut generator = SqlGenerator::new();
1207
1208        // 使用 build_select 生成完整的 SQL
1209        match generator.build_select(self) {
1210            Ok(_) => generator.get_sql().to_string(),
1211            Err(_) => {
1212                // 如果生成失败,返回简化版本
1213                let fields_str = if self.fields.is_empty() {
1214                    "*".to_string()
1215                } else {
1216                    self.fields.join(", ")
1217                };
1218
1219                let distinct_str = if self.distinct { "DISTINCT " } else { "" };
1220
1221                format!("SELECT {}{} FROM {}", distinct_str, fields_str, self.table)
1222            }
1223        }
1224    }
1225
1226    /// 查询单条记录
1227    ///
1228    /// 自动添加 LIMIT 1 到查询,返回单条记录或 None
1229    ///
1230    /// # 类型参数
1231    /// - T: 结果类型,必须实现 FromRow trait
1232    ///
1233    /// # 返回
1234    /// - Ok(Some(T)): 查询成功,返回单条记录
1235    /// - Ok(None): 查询成功,但没有匹配的记录
1236    /// - Err(DbError): 查询执行失败
1237    ///
1238    /// # 示例
1239    /// ```no_run
1240    /// use yang_db::Database;
1241    /// use serde::{Deserialize, Serialize};
1242    ///
1243    /// #[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
1244    /// struct User {
1245    ///     id: i32,
1246    ///     name: String,
1247    /// }
1248    ///
1249    /// # async fn example() -> Result<(), yang_db::DbError> {
1250    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
1251    /// let user: Option<User> = db.table("users")
1252    ///     .where_and("id", "=", 1)
1253    ///     .find()
1254    ///     .await?;
1255    ///
1256    /// match user {
1257    ///     Some(u) => println!("找到用户: {:?}", u),
1258    ///     None => println!("用户不存在"),
1259    /// }
1260    /// # Ok(())
1261    /// # }
1262    /// ```
1263    pub async fn find<T>(mut self) -> Result<Option<T>, crate::error::DbError>
1264    where
1265        T: for<'r> sqlx::FromRow<'r, sqlx::mysql::MySqlRow> + Send + Unpin,
1266    {
1267        // 自动添加 LIMIT 1
1268        self.limit = Some(1);
1269
1270        // 生成 SQL 语句
1271        let mut generator = SqlGenerator::new();
1272        generator.build_select(&self)?;
1273
1274        let sql = generator.get_sql();
1275        let params = generator.get_params();
1276
1277        // 记录日志
1278        if self.enable_logging {
1279            log::debug!("执行 find() 查询: {}", sql);
1280            log::debug!("参数: {:?}", params);
1281        }
1282
1283        // 构建查询
1284        let mut query = sqlx::query_as::<_, T>(sql);
1285
1286        // 绑定参数
1287        for param in params {
1288            query = bind_param(query, param);
1289        }
1290
1291        // 执行查询
1292        let result = query.fetch_optional(self.pool).await;
1293
1294        match result {
1295            Ok(row) => {
1296                if self.enable_logging {
1297                    if row.is_some() {
1298                        log::debug!("find() 查询成功,返回 1 条记录");
1299                    } else {
1300                        log::debug!("find() 查询成功,未找到匹配记录");
1301                    }
1302                }
1303                Ok(row)
1304            }
1305            Err(e) => {
1306                log::error!("find() 查询失败: {}", e);
1307                Err(crate::error::DbError::from(e))
1308            }
1309        }
1310    }
1311
1312    /// 查询多条记录
1313    ///
1314    /// 执行 SELECT 查询并返回所有匹配的记录
1315    ///
1316    /// # 类型参数
1317    /// - T: 结果类型,必须实现 FromRow trait
1318    ///
1319    /// # 返回
1320    /// - Ok(Vec<T>): 查询成功,返回匹配的记录列表(可能为空)
1321    /// - Err(DbError): 查询执行失败
1322    ///
1323    /// # 示例
1324    /// ```no_run
1325    /// use yang_db::Database;
1326    /// use serde::{Deserialize, Serialize};
1327    ///
1328    /// #[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
1329    /// struct User {
1330    ///     id: i32,
1331    ///     name: String,
1332    /// }
1333    ///
1334    /// # async fn example() -> Result<(), yang_db::DbError> {
1335    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
1336    /// let users: Vec<User> = db.table("users")
1337    ///     .where_and("status", "=", 1)
1338    ///     .order("name", true)
1339    ///     .select()
1340    ///     .await?;
1341    ///
1342    /// println!("找到 {} 个用户", users.len());
1343    /// for user in users {
1344    ///     println!("用户: {:?}", user);
1345    /// }
1346    /// # Ok(())
1347    /// # }
1348    /// ```
1349    pub async fn select<T>(self) -> Result<Vec<T>, crate::error::DbError>
1350    where
1351        T: for<'r> sqlx::FromRow<'r, sqlx::mysql::MySqlRow> + Send + Unpin,
1352    {
1353        // 生成 SQL 语句
1354        let mut generator = SqlGenerator::new();
1355        generator.build_select(&self)?;
1356
1357        let sql = generator.get_sql();
1358        let params = generator.get_params();
1359
1360        // 记录日志
1361        if self.enable_logging {
1362            log::debug!("执行 select() 查询: {}", sql);
1363            log::debug!("参数: {:?}", params);
1364        }
1365
1366        // 构建查询
1367        let mut query = sqlx::query_as::<_, T>(sql);
1368
1369        // 绑定参数
1370        for param in params {
1371            query = bind_param(query, param);
1372        }
1373
1374        // 执行查询
1375        let result = query.fetch_all(self.pool).await;
1376
1377        match result {
1378            Ok(rows) => {
1379                if self.enable_logging {
1380                    log::debug!("select() 查询成功,返回 {} 条记录", rows.len());
1381                }
1382                Ok(rows)
1383            }
1384            Err(e) => {
1385                log::error!("select() 查询失败: {}", e);
1386                Err(crate::error::DbError::from(e))
1387            }
1388        }
1389    }
1390
1391    /// 查询单个字段值
1392    ///
1393    /// 执行 SELECT 查询并返回指定字段的单个值。自动添加 LIMIT 1 到查询。
1394    ///
1395    /// # 参数
1396    /// - field: 要查询的字段名
1397    ///
1398    /// # 类型参数
1399    /// - T: 字段值类型,必须实现 sqlx::Decode 和 sqlx::Type trait
1400    ///
1401    /// # 返回
1402    /// - Ok(Some(T)): 查询成功,返回字段值
1403    /// - Ok(None): 查询成功,但没有匹配的记录
1404    /// - Err(DbError): 查询执行失败
1405    ///
1406    /// # 示例
1407    /// ```no_run
1408    /// use yang_db::Database;
1409    ///
1410    /// # async fn example() -> Result<(), yang_db::DbError> {
1411    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
1412    ///
1413    /// // 查询用户名
1414    /// let name: Option<String> = db.table("users")
1415    ///     .where_and("id", "=", 1)
1416    ///     .value("name")
1417    ///     .await?;
1418    ///
1419    /// match name {
1420    ///     Some(n) => println!("用户名: {}", n),
1421    ///     None => println!("用户不存在"),
1422    /// }
1423    ///
1424    /// // 查询用户数量
1425    /// let count: Option<i64> = db.table("users")
1426    ///     .where_and("status", "=", 1)
1427    ///     .value("COUNT(*)")
1428    ///     .await?;
1429    ///
1430    /// println!("活跃用户数: {}", count.unwrap_or(0));
1431    /// # Ok(())
1432    /// # }
1433    /// ```
1434    pub async fn value<T>(mut self, field: &str) -> Result<Option<T>, crate::error::DbError>
1435    where
1436        T: for<'r> sqlx::Decode<'r, sqlx::MySql> + sqlx::Type<sqlx::MySql> + Send + Unpin,
1437    {
1438        // 清空现有字段选择,只选择指定字段
1439        self.fields.clear();
1440        self.fields.push(field.to_string());
1441
1442        // 自动添加 LIMIT 1
1443        self.limit = Some(1);
1444
1445        // 生成 SQL 语句
1446        let mut generator = SqlGenerator::new();
1447        generator.build_select(&self)?;
1448
1449        let sql = generator.get_sql();
1450        let params = generator.get_params();
1451
1452        // 记录日志
1453        if self.enable_logging {
1454            log::debug!("执行 value() 查询: {}", sql);
1455            log::debug!("参数: {:?}", params);
1456        }
1457
1458        // 构建查询 - 使用 query_scalar 直接获取单个值
1459        let mut query = sqlx::query_scalar::<_, T>(sql);
1460
1461        // 绑定参数
1462        for param in params {
1463            query = bind_scalar_param(query, param);
1464        }
1465
1466        // 执行查询
1467        let result = query.fetch_optional(self.pool).await;
1468
1469        match result {
1470            Ok(value) => {
1471                if self.enable_logging {
1472                    if value.is_some() {
1473                        log::debug!("value() 查询成功,返回字段值");
1474                    } else {
1475                        log::debug!("value() 查询成功,未找到匹配记录");
1476                    }
1477                }
1478                Ok(value)
1479            }
1480            Err(e) => {
1481                log::error!("value() 查询失败: {}", e);
1482                Err(crate::error::DbError::from(e))
1483            }
1484        }
1485    }
1486
1487    /// 统计记录数量
1488    ///
1489    /// 执行 COUNT(*) 查询并返回匹配条件的记录数量。
1490    ///
1491    /// # 返回
1492    /// - Ok(i64): 查询成功,返回记录数量
1493    /// - Err(DbError): 查询执行失败
1494    ///
1495    /// # 示例
1496    /// ```no_run
1497    /// use yang_db::Database;
1498    ///
1499    /// # async fn example() -> Result<(), yang_db::DbError> {
1500    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
1501    ///
1502    /// // 统计所有用户数量
1503    /// let total_users = db.table("users")
1504    ///     .count()
1505    ///     .await?;
1506    /// println!("总用户数: {}", total_users);
1507    ///
1508    /// // 统计活跃用户数量
1509    /// let active_users = db.table("users")
1510    ///     .where_and("status", "=", 1)
1511    ///     .count()
1512    ///     .await?;
1513    /// println!("活跃用户数: {}", active_users);
1514    /// # Ok(())
1515    /// # }
1516    /// ```
1517    pub async fn count(self) -> Result<i64, crate::error::DbError> {
1518        // 记录日志
1519        if self.enable_logging {
1520            log::debug!("执行 count() 查询");
1521        }
1522
1523        // 使用 value() 方法查询 COUNT(*)
1524        let result = self.value::<i64>("COUNT(*)").await?;
1525
1526        // COUNT(*) 总是返回一个值(至少是 0),所以这里 unwrap_or(0) 是安全的
1527        Ok(result.unwrap_or(0))
1528    }
1529
1530    /// 计算字段总和
1531    ///
1532    /// 执行 SUM(field) 查询并返回指定字段的总和。
1533    ///
1534    /// # 参数
1535    /// - field: 要求和的字段名
1536    ///
1537    /// # 返回
1538    /// - Ok(Some(f64)): 查询成功,返回字段总和
1539    /// - Ok(None): 查询成功,但没有匹配的记录或字段值全为 NULL
1540    /// - Err(DbError): 查询执行失败
1541    ///
1542    /// # 注意
1543    /// MySQL 的 SUM() 函数对于整数字段返回 DECIMAL 类型,对于浮点数字段返回 DOUBLE 类型。
1544    /// 本方法使用 CAST 将结果转换为 DOUBLE,以统一返回类型。
1545    ///
1546    /// # 示例
1547    /// ```no_run
1548    /// use yang_db::Database;
1549    ///
1550    /// # async fn example() -> Result<(), yang_db::DbError> {
1551    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
1552    ///
1553    /// // 计算所有订单总金额
1554    /// let total_amount = db.table("orders")
1555    ///     .sum("amount")
1556    ///     .await?;
1557    ///
1558    /// match total_amount {
1559    ///     Some(sum) => println!("订单总金额: {:.2}", sum),
1560    ///     None => println!("没有订单或金额全为 NULL"),
1561    /// }
1562    ///
1563    /// // 计算已完成订单的总金额
1564    /// let completed_amount = db.table("orders")
1565    ///     .where_and("status", "=", "completed")
1566    ///     .sum("amount")
1567    ///     .await?;
1568    ///
1569    /// println!("已完成订单总金额: {:.2}", completed_amount.unwrap_or(0.0));
1570    /// # Ok(())
1571    /// # }
1572    /// ```
1573    pub async fn sum(self, field: &str) -> Result<Option<f64>, crate::error::DbError> {
1574        // 记录日志
1575        if self.enable_logging {
1576            log::debug!("执行 sum() 查询,字段: {}", field);
1577        }
1578
1579        // 构建 SUM(field) 表达式,并使用 CAST 转换为 DOUBLE
1580        // 这样可以统一处理整数和浮点数字段的求和结果
1581        let sum_expr = format!("CAST(SUM({}) AS DOUBLE)", field);
1582
1583        // 清空现有字段选择,只选择 SUM 表达式
1584        let mut builder = self;
1585        builder.fields.clear();
1586        builder.fields.push(sum_expr.clone());
1587
1588        // 自动添加 LIMIT 1(虽然聚合函数只返回一行,但保持一致性)
1589        builder.limit = Some(1);
1590
1591        // 生成 SQL 语句
1592        let mut generator = SqlGenerator::new();
1593        generator.build_select(&builder)?;
1594
1595        let sql = generator.get_sql();
1596        let params = generator.get_params();
1597
1598        // 记录日志
1599        if builder.enable_logging {
1600            log::debug!("执行 sum() 查询: {}", sql);
1601            log::debug!("参数: {:?}", params);
1602        }
1603
1604        // 构建查询 - 使用 Option<f64> 来处理 NULL 值
1605        let mut query = sqlx::query_scalar::<_, Option<f64>>(sql);
1606
1607        // 绑定参数
1608        for param in params {
1609            query = bind_scalar_param_option(query, param);
1610        }
1611
1612        // 执行查询
1613        let result = query.fetch_optional(builder.pool).await;
1614
1615        match result {
1616            Ok(Some(value)) => {
1617                // 查询成功,返回值(可能是 Some(f64) 或 None)
1618                if builder.enable_logging {
1619                    if value.is_some() {
1620                        log::debug!("sum() 查询成功,返回总和");
1621                    } else {
1622                        log::debug!("sum() 查询成功,返回 None(没有匹配记录或所有值为 NULL)");
1623                    }
1624                }
1625                Ok(value)
1626            }
1627            Ok(None) => {
1628                // 没有记录(理论上不应该发生,因为聚合函数总是返回一行)
1629                if builder.enable_logging {
1630                    log::debug!("sum() 查询成功,未找到匹配记录");
1631                }
1632                Ok(None)
1633            }
1634            Err(e) => {
1635                log::error!("sum() 查询失败: {}", e);
1636                Err(crate::error::DbError::from(e))
1637            }
1638        }
1639    }
1640
1641    /// 计算字段平均值
1642    ///
1643    /// 执行 AVG 聚合函数,计算指定字段的平均值。
1644    ///
1645    /// # 参数
1646    /// - field: 要计算平均值的字段名
1647    ///
1648    /// # 返回
1649    /// - Ok(Some(f64)): 计算成功,返回平均值
1650    /// - Ok(None): 没有匹配记录或所有字段值为 NULL
1651    /// - Err(DbError): 查询失败
1652    ///
1653    /// # 注意
1654    /// - 只对数值类型字段有效
1655    /// - 空结果集返回 None
1656    /// - NULL 值会被忽略(不参与计算)
1657    /// - 可以与 WHERE 条件组合使用
1658    /// - 可以与 GROUP BY 组合使用
1659    ///
1660    /// # 示例
1661    /// ```no_run
1662    /// use yang_db::Database;
1663    ///
1664    /// # async fn example() -> Result<(), yang_db::DbError> {
1665    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
1666    ///
1667    /// // 计算所有用户的平均年龄
1668    /// let avg_age = db.table("users")
1669    ///     .avg("age")
1670    ///     .await?;
1671    ///
1672    /// if let Some(age) = avg_age {
1673    ///     println!("平均年龄: {:.1}", age);
1674    /// } else {
1675    ///     println!("没有数据");
1676    /// }
1677    ///
1678    /// // 计算已完成订单的平均金额
1679    /// let avg_amount = db.table("orders")
1680    ///     .where_and("status", "=", "completed")
1681    ///     .avg("amount")
1682    ///     .await?;
1683    ///
1684    /// println!("已完成订单平均金额: {:.2}", avg_amount.unwrap_or(0.0));
1685    /// # Ok(())
1686    /// # }
1687    /// ```
1688    pub async fn avg(self, field: &str) -> Result<Option<f64>, crate::error::DbError> {
1689        // 记录日志
1690        if self.enable_logging {
1691            log::debug!("执行 avg() 查询,字段: {}", field);
1692        }
1693
1694        // 构建 AVG(field) 表达式,并使用 CAST 转换为 DOUBLE
1695        // 这样可以统一处理整数和浮点数字段的平均值结果
1696        let avg_expr = format!("CAST(AVG({}) AS DOUBLE)", field);
1697
1698        // 清空现有字段选择,只选择 AVG 表达式
1699        let mut builder = self;
1700        builder.fields.clear();
1701        builder.fields.push(avg_expr.clone());
1702
1703        // 自动添加 LIMIT 1(虽然聚合函数只返回一行,但保持一致性)
1704        builder.limit = Some(1);
1705
1706        // 生成 SQL 语句
1707        let mut generator = SqlGenerator::new();
1708        generator.build_select(&builder)?;
1709
1710        let sql = generator.get_sql();
1711        let params = generator.get_params();
1712
1713        // 记录日志
1714        if builder.enable_logging {
1715            log::debug!("执行 avg() 查询: {}", sql);
1716            log::debug!("参数: {:?}", params);
1717        }
1718
1719        // 构建查询 - 使用 Option<f64> 来处理 NULL 值
1720        let mut query = sqlx::query_scalar::<_, Option<f64>>(sql);
1721
1722        // 绑定参数
1723        for param in params {
1724            query = bind_scalar_param_option(query, param);
1725        }
1726
1727        // 执行查询
1728        let result = query.fetch_optional(builder.pool).await;
1729
1730        match result {
1731            Ok(Some(value)) => {
1732                // 查询成功,返回值(可能是 Some(f64) 或 None)
1733                if builder.enable_logging {
1734                    if value.is_some() {
1735                        log::debug!("avg() 查询成功,返回平均值");
1736                    } else {
1737                        log::debug!("avg() 查询成功,返回 None(没有匹配记录或所有值为 NULL)");
1738                    }
1739                }
1740                Ok(value)
1741            }
1742            Ok(None) => {
1743                // 没有记录(理论上不应该发生,因为聚合函数总是返回一行)
1744                if builder.enable_logging {
1745                    log::debug!("avg() 查询成功,未找到匹配记录");
1746                }
1747                Ok(None)
1748            }
1749            Err(e) => {
1750                log::error!("avg() 查询失败: {}", e);
1751                Err(crate::error::DbError::from(e))
1752            }
1753        }
1754    }
1755
1756    /// 获取字段最小值
1757    ///
1758    /// 执行 MIN 聚合函数,获取指定字段的最小值。
1759    ///
1760    /// # 参数
1761    /// - field: 要查询最小值的字段名
1762    ///
1763    /// # 类型参数
1764    /// - T: 字段值类型,必须实现 sqlx::Decode 和 sqlx::Type trait
1765    ///   支持的类型包括:i32, i64, f32, f64, String, chrono::NaiveDateTime 等
1766    ///
1767    /// # 返回
1768    /// - Ok(Some(T)): 查询成功,返回最小值
1769    /// - Ok(None): 没有匹配记录或所有字段值为 NULL
1770    /// - Err(DbError): 查询失败
1771    ///
1772    /// # 注意
1773    /// - 对数值类型字段返回数值最小值
1774    /// - 对字符串类型字段返回字典序最小值
1775    /// - 对日期时间类型字段返回最早时间
1776    /// - 空结果集返回 None
1777    /// - NULL 值会被忽略(不参与比较)
1778    /// - 可以与 WHERE 条件组合使用
1779    /// - 可以与 GROUP BY 组合使用
1780    ///
1781    /// # 示例
1782    /// ```no_run
1783    /// use yang_db::Database;
1784    ///
1785    /// # async fn example() -> Result<(), yang_db::DbError> {
1786    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
1787    ///
1788    /// // 查询最低价格(浮点数)
1789    /// let min_price: Option<f64> = db.table("products")
1790    ///     .min("price")
1791    ///     .await?;
1792    ///
1793    /// if let Some(price) = min_price {
1794    ///     println!("最低价格: {:.2}", price);
1795    /// } else {
1796    ///     println!("没有产品数据");
1797    /// }
1798    ///
1799    /// // 查询最小库存数量(整数)
1800    /// let min_stock: Option<i32> = db.table("products")
1801    ///     .where_and("status", "=", 1)
1802    ///     .min("stock")
1803    ///     .await?;
1804    ///
1805    /// println!("最小库存: {}", min_stock.unwrap_or(0));
1806    ///
1807    /// // 查询最早注册时间(字符串)
1808    /// let earliest_date: Option<String> = db.table("users")
1809    ///     .min("created_at")
1810    ///     .await?;
1811    ///
1812    /// if let Some(date) = earliest_date {
1813    ///     println!("最早注册时间: {}", date);
1814    /// }
1815    /// # Ok(())
1816    /// # }
1817    /// ```
1818    pub async fn min<T>(self, field: &str) -> Result<Option<T>, crate::error::DbError>
1819    where
1820        T: for<'r> sqlx::Decode<'r, sqlx::MySql> + sqlx::Type<sqlx::MySql> + Send + Unpin,
1821    {
1822        // 记录日志
1823        if self.enable_logging {
1824            log::debug!("执行 min() 查询,字段: {}", field);
1825        }
1826
1827        // 构建 MIN(field) 表达式
1828        let min_expr = format!("MIN({})", field);
1829
1830        // 清空现有字段选择,只选择 MIN 表达式
1831        let mut builder = self;
1832        builder.fields.clear();
1833        builder.fields.push(min_expr.clone());
1834
1835        // 自动添加 LIMIT 1(虽然聚合函数只返回一行,但保持一致性)
1836        builder.limit = Some(1);
1837
1838        // 生成 SQL 语句
1839        let mut generator = SqlGenerator::new();
1840        generator.build_select(&builder)?;
1841
1842        let sql = generator.get_sql();
1843        let params = generator.get_params();
1844
1845        // 记录日志
1846        if builder.enable_logging {
1847            log::debug!("执行 min() 查询: {}", sql);
1848            log::debug!("参数: {:?}", params);
1849        }
1850
1851        // 构建查询 - 使用 query_scalar 直接获取单个值
1852        let mut query = sqlx::query_scalar::<_, Option<T>>(sql);
1853
1854        // 绑定参数
1855        for param in params {
1856            query = bind_scalar_param_option(query, param);
1857        }
1858
1859        // 执行查询
1860        let result = query.fetch_optional(builder.pool).await;
1861
1862        match result {
1863            Ok(Some(value)) => {
1864                // 查询成功,返回值(可能是 Some(T) 或 None)
1865                if builder.enable_logging {
1866                    if value.is_some() {
1867                        log::debug!("min() 查询成功,返回最小值");
1868                    } else {
1869                        log::debug!("min() 查询成功,返回 None(没有匹配记录或所有值为 NULL)");
1870                    }
1871                }
1872                Ok(value)
1873            }
1874            Ok(None) => {
1875                // 没有记录(理论上不应该发生,因为聚合函数总是返回一行)
1876                if builder.enable_logging {
1877                    log::debug!("min() 查询成功,未找到匹配记录");
1878                }
1879                Ok(None)
1880            }
1881            Err(e) => {
1882                log::error!("min() 查询失败: {}", e);
1883                Err(crate::error::DbError::from(e))
1884            }
1885        }
1886    }
1887
1888    /// 获取字段最大值
1889    ///
1890    /// 执行 MAX 聚合函数,获取指定字段的最大值。
1891    ///
1892    /// # 参数
1893    /// - field: 要查询最大值的字段名
1894    ///
1895    /// # 类型参数
1896    /// - T: 字段值类型,必须实现 sqlx::Decode 和 sqlx::Type trait
1897    ///   支持的类型包括:i32, i64, f32, f64, String, chrono::NaiveDateTime 等
1898    ///
1899    /// # 返回
1900    /// - Ok(Some(T)): 查询成功,返回最大值
1901    /// - Ok(None): 没有匹配记录或所有字段值为 NULL
1902    /// - Err(DbError): 查询失败
1903    ///
1904    /// # 注意
1905    /// - 对数值类型字段返回数值最大值
1906    /// - 对字符串类型字段返回字典序最大值
1907    /// - 对日期时间类型字段返回最晚时间
1908    /// - 空结果集返回 None
1909    /// - NULL 值会被忽略(不参与比较)
1910    /// - 可以与 WHERE 条件组合使用
1911    /// - 可以与 GROUP BY 组合使用
1912    ///
1913    /// # 示例
1914    /// ```no_run
1915    /// use yang_db::Database;
1916    ///
1917    /// # async fn example() -> Result<(), yang_db::DbError> {
1918    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
1919    ///
1920    /// // 查询最高价格(浮点数)
1921    /// let max_price: Option<f64> = db.table("products")
1922    ///     .max("price")
1923    ///     .await?;
1924    ///
1925    /// if let Some(price) = max_price {
1926    ///     println!("最高价格: {:.2}", price);
1927    /// } else {
1928    ///     println!("没有产品数据");
1929    /// }
1930    ///
1931    /// // 查询最高分数(整数)
1932    /// let max_score: Option<i32> = db.table("scores")
1933    ///     .where_and("exam_id", "=", 1)
1934    ///     .max("score")
1935    ///     .await?;
1936    ///
1937    /// println!("最高分: {}", max_score.unwrap_or(0));
1938    ///
1939    /// // 查询最新更新时间(字符串)
1940    /// let latest_date: Option<String> = db.table("articles")
1941    ///     .max("updated_at")
1942    ///     .await?;
1943    ///
1944    /// if let Some(date) = latest_date {
1945    ///     println!("最新更新时间: {}", date);
1946    /// }
1947    /// # Ok(())
1948    /// # }
1949    /// ```
1950    pub async fn max<T>(self, field: &str) -> Result<Option<T>, crate::error::DbError>
1951    where
1952        T: for<'r> sqlx::Decode<'r, sqlx::MySql> + sqlx::Type<sqlx::MySql> + Send + Unpin,
1953    {
1954        // 记录日志
1955        if self.enable_logging {
1956            log::debug!("执行 max() 查询,字段: {}", field);
1957        }
1958
1959        // 构建 MAX(field) 表达式
1960        let max_expr = format!("MAX({})", field);
1961
1962        // 清空现有字段选择,只选择 MAX 表达式
1963        let mut builder = self;
1964        builder.fields.clear();
1965        builder.fields.push(max_expr.clone());
1966
1967        // 自动添加 LIMIT 1(虽然聚合函数只返回一行,但保持一致性)
1968        builder.limit = Some(1);
1969
1970        // 生成 SQL 语句
1971        let mut generator = SqlGenerator::new();
1972        generator.build_select(&builder)?;
1973
1974        let sql = generator.get_sql();
1975        let params = generator.get_params();
1976
1977        // 记录日志
1978        if builder.enable_logging {
1979            log::debug!("执行 max() 查询: {}", sql);
1980            log::debug!("参数: {:?}", params);
1981        }
1982
1983        // 构建查询 - 使用 query_scalar 直接获取单个值
1984        let mut query = sqlx::query_scalar::<_, Option<T>>(sql);
1985
1986        // 绑定参数
1987        for param in params {
1988            query = bind_scalar_param_option(query, param);
1989        }
1990
1991        // 执行查询
1992        let result = query.fetch_optional(builder.pool).await;
1993
1994        match result {
1995            Ok(Some(value)) => {
1996                // 查询成功,返回值(可能是 Some(T) 或 None)
1997                if builder.enable_logging {
1998                    if value.is_some() {
1999                        log::debug!("max() 查询成功,返回最大值");
2000                    } else {
2001                        log::debug!("max() 查询成功,返回 None(没有匹配记录或所有值为 NULL)");
2002                    }
2003                }
2004                Ok(value)
2005            }
2006            Ok(None) => {
2007                // 没有记录(理论上不应该发生,因为聚合函数总是返回一行)
2008                if builder.enable_logging {
2009                    log::debug!("max() 查询成功,未找到匹配记录");
2010                }
2011                Ok(None)
2012            }
2013            Err(e) => {
2014                log::error!("max() 查询失败: {}", e);
2015                Err(crate::error::DbError::from(e))
2016            }
2017        }
2018    }
2019
2020    /// 插入数据
2021    ///
2022    /// 执行 INSERT 操作,将数据插入到表中。
2023    ///
2024    /// # 类型参数
2025    /// - T: 数据类型,必须实现 Serialize trait
2026    ///
2027    /// # 参数
2028    /// - data: 要插入的数据
2029    ///
2030    /// # 返回
2031    /// - Ok(u64): 插入成功,返回插入记录的 ID(自增主键)
2032    /// - Err(DbError): 插入失败
2033    ///
2034    /// # 示例
2035    /// ```no_run
2036    /// use yang_db::Database;
2037    /// use serde::{Deserialize, Serialize};
2038    /// use serde_json::json;
2039    ///
2040    /// # async fn example() -> Result<(), yang_db::DbError> {
2041    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
2042    ///
2043    /// // 使用 JSON 对象插入
2044    /// let user_data = json!({
2045    ///     "name": "张三",
2046    ///     "email": "zhangsan@example.com",
2047    ///     "age": 25
2048    /// });
2049    ///
2050    /// let user_id = db.table("users")
2051    ///     .insert(&user_data)
2052    ///     .await?;
2053    ///
2054    /// println!("插入成功,用户 ID: {}", user_id);
2055    ///
2056    /// // 插入带 JSON 字段的数据
2057    /// let order_data = json!({
2058    ///     "user_id": user_id,
2059    ///     "total": 199.99,
2060    ///     "items": [{"id": 1, "qty": 2}, {"id": 2, "qty": 1}]
2061    /// });
2062    ///
2063    /// let order_id = db.table("orders")
2064    ///     .json("items")  // 标记 items 字段为 JSON 类型
2065    ///     .insert(&order_data)
2066    ///     .await?;
2067    ///
2068    /// println!("订单插入成功,订单 ID: {}", order_id);
2069    /// # Ok(())
2070    /// # }
2071    /// ```
2072    pub async fn insert<T>(self, data: &T) -> Result<u64, crate::error::DbError>
2073    where
2074        T: serde::Serialize,
2075    {
2076        // 记录日志
2077        if self.enable_logging {
2078            log::debug!("执行 insert() 操作,表: {}", self.table);
2079        }
2080
2081        // 将数据序列化为 JSON
2082        let json_data = serde_json::to_value(data).map_err(|e| {
2083            crate::error::DbError::SerializationError(format!("数据序列化失败: {}", e))
2084        })?;
2085
2086        // 生成 INSERT 语句
2087        let mut generator = SqlGenerator::new();
2088        generator.build_insert(&self.table, &json_data, &self.field_types)?;
2089
2090        let sql = generator.get_sql();
2091        let params = generator.get_params();
2092
2093        // 记录日志
2094        if self.enable_logging {
2095            log::debug!("执行 insert() SQL: {}", sql);
2096            log::debug!("参数: {:?}", params);
2097        }
2098
2099        // 构建查询
2100        let mut query = sqlx::query(sql);
2101
2102        // 绑定参数
2103        for param in params {
2104            query = bind_execute_param(query, param);
2105        }
2106
2107        // 执行插入
2108        let result = query.execute(self.pool).await;
2109
2110        match result {
2111            Ok(query_result) => {
2112                let last_insert_id = query_result.last_insert_id();
2113                if self.enable_logging {
2114                    log::debug!("insert() 成功,插入 ID: {}", last_insert_id);
2115                }
2116                Ok(last_insert_id)
2117            }
2118            Err(e) => {
2119                log::error!("insert() 失败: {}", e);
2120                Err(crate::error::DbError::from(e))
2121            }
2122        }
2123    }
2124
2125    /// 批量插入数据
2126    ///
2127    /// 执行批量 INSERT 操作,将多条数据一次性插入到表中。
2128    /// 相比多次调用 insert(),批量插入性能更高,因为只需要一次数据库往返。
2129    ///
2130    /// # 类型参数
2131    /// - T: 数据类型,必须实现 Serialize trait
2132    ///
2133    /// # 参数
2134    /// - data: 要插入的数据切片
2135    ///
2136    /// # 返回
2137    /// - Ok(u64): 插入成功,返回受影响的行数
2138    /// - Err(DbError): 插入失败
2139    ///
2140    /// # 注意
2141    /// - 所有记录必须具有相同的字段结构
2142    /// - 字段顺序以第一条记录为准
2143    /// - 如果某条记录缺少字段,将使用 NULL 值
2144    /// - 批量插入使用单个 INSERT 语句,性能优于多次单条插入
2145    /// - 自动分批处理:当数据量超过 INSERT_BATCH_SIZE(默认 500)时,会自动分批插入
2146    ///
2147    /// # 示例
2148    /// ```no_run
2149    /// use yang_db::Database;
2150    /// use serde::{Deserialize, Serialize};
2151    /// use serde_json::json;
2152    ///
2153    /// # async fn example() -> Result<(), yang_db::DbError> {
2154    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
2155    ///
2156    /// // 批量插入多个用户
2157    /// let users = vec![
2158    ///     json!({"name": "张三", "email": "zhangsan@example.com", "age": 25}),
2159    ///     json!({"name": "李四", "email": "lisi@example.com", "age": 30}),
2160    ///     json!({"name": "王五", "email": "wangwu@example.com", "age": 28}),
2161    /// ];
2162    ///
2163    /// let affected_rows = db.table("users")
2164    ///     .insert_batch(&users)
2165    ///     .await?;
2166    ///
2167    /// println!("批量插入成功,影响 {} 行", affected_rows);
2168    ///
2169    /// // 批量插入带 JSON 字段的数据
2170    /// let orders = vec![
2171    ///     json!({
2172    ///         "user_id": 1,
2173    ///         "total": 199.99,
2174    ///         "items": [{"id": 1, "qty": 2}]
2175    ///     }),
2176    ///     json!({
2177    ///         "user_id": 2,
2178    ///         "total": 299.99,
2179    ///         "items": [{"id": 2, "qty": 1}]
2180    ///     }),
2181    /// ];
2182    ///
2183    /// let affected_rows = db.table("orders")
2184    ///     .json("items")  // 标记 items 字段为 JSON 类型
2185    ///     .insert_batch(&orders)
2186    ///     .await?;
2187    ///
2188    /// println!("批量插入订单成功,影响 {} 行", affected_rows);
2189    /// # Ok(())
2190    /// # }
2191    /// ```
2192    pub async fn insert_batch<T>(self, data: &[T]) -> Result<u64, crate::error::DbError>
2193    where
2194        T: serde::Serialize,
2195    {
2196        // 记录日志
2197        if self.enable_logging {
2198            log::debug!(
2199                "执行 insert_batch() 操作,表: {},记录数: {}",
2200                self.table,
2201                data.len()
2202            );
2203        }
2204
2205        // 检查数据是否为空
2206        if data.is_empty() {
2207            return Err(crate::error::DbError::SerializationError(
2208                "批量插入数据不能为空".to_string(),
2209            ));
2210        }
2211
2212        // 如果数据量小于等于批次大小,直接插入
2213        if data.len() <= INSERT_BATCH_SIZE {
2214            return self.insert_chunk(data).await;
2215        }
2216
2217        // 数据量大于批次大小,分批插入
2218        let mut total_affected = 0u64;
2219
2220        // 使用 chunks() 方法将数据分批
2221        for (batch_index, chunk) in data.chunks(INSERT_BATCH_SIZE).enumerate() {
2222            if self.enable_logging {
2223                log::debug!(
2224                    "执行第 {} 批插入,本批记录数: {}",
2225                    batch_index + 1,
2226                    chunk.len()
2227                );
2228            }
2229
2230            // 为每个批次创建新的 QueryBuilder(因为 self 已经被 move)
2231            // 我们需要保存必要的信息来重建 QueryBuilder
2232            let chunk_builder = QueryBuilder {
2233                pool: self.pool,
2234                table: self.table.clone(),
2235                fields: self.fields.clone(),
2236                conditions: self.conditions.clone(),
2237                joins: self.joins.clone(),
2238                order_by: self.order_by.clone(),
2239                group_by: self.group_by.clone(),
2240                having_clause: self.having_clause.clone(),
2241                limit: self.limit,
2242                offset: self.offset,
2243                distinct: self.distinct,
2244                field_types: self.field_types.clone(),
2245                enable_logging: self.enable_logging,
2246            };
2247
2248            let affected = chunk_builder.insert_chunk(chunk).await?;
2249            total_affected += affected;
2250
2251            if self.enable_logging {
2252                log::debug!("第 {} 批插入成功,影响 {} 行", batch_index + 1, affected);
2253            }
2254        }
2255
2256        if self.enable_logging {
2257            log::debug!("insert_batch() 全部完成,总共影响 {} 行", total_affected);
2258        }
2259
2260        Ok(total_affected)
2261    }
2262
2263    /// 批量插入数据(自定义批次大小)
2264    ///
2265    /// 与 `insert_batch` 相同,但允许调用方根据场景自定义每批次的最大记录数。
2266    /// 适用于需要根据网络延迟、数据大小或 MySQL max_allowed_packet 调整性能的场景。
2267    ///
2268    /// # 类型参数
2269    /// - T: 数据类型,必须实现 Serialize trait
2270    ///
2271    /// # 参数
2272    /// - data: 要插入的数据切片
2273    /// - batch_size: 每批最多插入的记录数(必须 > 0)
2274    ///
2275    /// # 返回
2276    /// - Ok(u64): 插入成功,返回总受影响行数
2277    /// - Err(DbError::SerializationError): batch_size 为 0 时
2278    /// - Err(DbError): 其他插入失败情况
2279    ///
2280    /// # 示例
2281    /// ```no_run
2282    /// use yang_db::Database;
2283    /// use serde_json::json;
2284    ///
2285    /// # async fn example() -> Result<(), yang_db::DbError> {
2286    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
2287    ///
2288    /// let users = vec![
2289    ///     json!({"name": "张三", "age": 25}),
2290    ///     json!({"name": "李四", "age": 30}),
2291    /// ];
2292    ///
2293    /// // 每批最多插入 100 条记录
2294    /// let affected_rows = db.table("users")
2295    ///     .insert_batch_with_size(&users, 100)
2296    ///     .await?;
2297    ///
2298    /// println!("批量插入成功,影响 {} 行", affected_rows);
2299    /// # Ok(())
2300    /// # }
2301    /// ```
2302    pub async fn insert_batch_with_size<T>(
2303        self,
2304        data: &[T],
2305        batch_size: usize,
2306    ) -> Result<u64, crate::error::DbError>
2307    where
2308        T: serde::Serialize,
2309    {
2310        // 检查 batch_size 是否为 0,为 0 时返回错误
2311        if batch_size == 0 {
2312            return Err(crate::error::DbError::SerializationError(
2313                "batch_size 不能为 0".to_string(),
2314            ));
2315        }
2316
2317        // 记录日志
2318        if self.enable_logging {
2319            log::debug!(
2320                "执行 insert_batch_with_size() 操作,表: {},记录数: {},批次大小: {}",
2321                self.table,
2322                data.len(),
2323                batch_size
2324            );
2325        }
2326
2327        // 数据为空时直接返回错误
2328        if data.is_empty() {
2329            return Err(crate::error::DbError::SerializationError(
2330                "批量插入数据不能为空".to_string(),
2331            ));
2332        }
2333
2334        // 使用 data.chunks(batch_size) 分批,每批调用内部插入逻辑,累加受影响行数
2335        let mut total_affected = 0u64;
2336
2337        for (batch_index, chunk) in data.chunks(batch_size).enumerate() {
2338            if self.enable_logging {
2339                log::debug!(
2340                    "执行第 {} 批插入,本批记录数: {}",
2341                    batch_index + 1,
2342                    chunk.len()
2343                );
2344            }
2345
2346            // 为每个批次创建新的 QueryBuilder(复用当前 builder 的配置)
2347            let chunk_builder = QueryBuilder {
2348                pool: self.pool,
2349                table: self.table.clone(),
2350                fields: self.fields.clone(),
2351                conditions: self.conditions.clone(),
2352                joins: self.joins.clone(),
2353                order_by: self.order_by.clone(),
2354                group_by: self.group_by.clone(),
2355                having_clause: self.having_clause.clone(),
2356                limit: self.limit,
2357                offset: self.offset,
2358                distinct: self.distinct,
2359                field_types: self.field_types.clone(),
2360                enable_logging: self.enable_logging,
2361            };
2362
2363            // 调用内部插入逻辑执行本批次
2364            let affected = chunk_builder.insert_chunk(chunk).await?;
2365            total_affected += affected;
2366
2367            if self.enable_logging {
2368                log::debug!("第 {} 批插入成功,影响 {} 行", batch_index + 1, affected);
2369            }
2370        }
2371
2372        if self.enable_logging {
2373            log::debug!(
2374                "insert_batch_with_size() 全部完成,总共影响 {} 行",
2375                total_affected
2376            );
2377        }
2378
2379        Ok(total_affected)
2380    }
2381
2382    /// 插入单个批次的数据(内部方法)
2383    ///
2384    /// 此方法用于实际执行单个批次的 INSERT 操作。
2385    /// 它被 insert_batch() 方法调用,用于处理分批后的每个数据块。
2386    ///
2387    /// # 类型参数
2388    /// - T: 数据类型,必须实现 Serialize trait
2389    ///
2390    /// # 参数
2391    /// - data: 要插入的数据切片(单个批次)
2392    ///
2393    /// # 返回
2394    /// - Ok(u64): 插入成功,返回受影响的行数
2395    /// - Err(DbError): 插入失败
2396    async fn insert_chunk<T>(&self, data: &[T]) -> Result<u64, crate::error::DbError>
2397    where
2398        T: serde::Serialize,
2399    {
2400        // 将所有数据序列化为 JSON
2401        let json_data_list: Result<Vec<_>, _> = data
2402            .iter()
2403            .map(|item| {
2404                serde_json::to_value(item).map_err(|e| {
2405                    crate::error::DbError::SerializationError(format!("数据序列化失败: {}", e))
2406                })
2407            })
2408            .collect();
2409
2410        let json_data_list = json_data_list?;
2411
2412        // 生成批量 INSERT 语句
2413        let mut generator = SqlGenerator::new();
2414        generator.build_insert_batch(&self.table, &json_data_list, &self.field_types)?;
2415
2416        let sql = generator.get_sql();
2417        let params = generator.get_params();
2418
2419        // 记录日志
2420        if self.enable_logging {
2421            log::debug!("执行 insert_chunk() SQL: {}", sql);
2422            log::debug!("参数数量: {}", params.len());
2423        }
2424
2425        // 构建查询
2426        let mut query = sqlx::query(sql);
2427
2428        // 绑定参数
2429        for param in params {
2430            query = bind_execute_param(query, param);
2431        }
2432
2433        // 执行批量插入
2434        let result = query.execute(self.pool).await;
2435
2436        match result {
2437            Ok(query_result) => {
2438                let rows_affected = query_result.rows_affected();
2439                if self.enable_logging {
2440                    log::debug!("insert_chunk() 成功,影响 {} 行", rows_affected);
2441                }
2442                Ok(rows_affected)
2443            }
2444            Err(e) => {
2445                log::error!("insert_chunk() 失败: {}", e);
2446                Err(crate::error::DbError::from(e))
2447            }
2448        }
2449    }
2450
2451    /// 更新数据
2452    ///
2453    /// 执行 UPDATE 操作,更新表中的数据。
2454    /// 为了防止误操作,必须提供 WHERE 条件,否则会返回错误。
2455    ///
2456    /// # 类型参数
2457    /// - T: 数据类型,必须实现 Serialize trait
2458    ///
2459    /// # 参数
2460    /// - data: 要更新的数据
2461    ///
2462    /// # 返回
2463    /// - Ok(u64): 更新成功,返回受影响的行数
2464    /// - Err(DbError): 更新失败
2465    ///
2466    /// # 示例
2467    /// ```no_run
2468    /// use yang_db::Database;
2469    /// use serde_json::json;
2470    ///
2471    /// # async fn example() -> Result<(), yang_db::DbError> {
2472    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
2473    ///
2474    /// // 更新用户信息
2475    /// let update_data = json!({
2476    ///     "name": "李四",
2477    ///     "age": 30
2478    /// });
2479    ///
2480    /// let rows_affected = db.table("users")
2481    ///     .where_and("id", "=", 1)
2482    ///     .update(&update_data)
2483    ///     .await?;
2484    ///
2485    /// println!("更新了 {} 行数据", rows_affected);
2486    /// # Ok(())
2487    /// # }
2488    /// ```
2489    pub async fn update<T>(self, data: &T) -> Result<u64, crate::error::DbError>
2490    where
2491        T: serde::Serialize,
2492    {
2493        // 记录日志
2494        if self.enable_logging {
2495            log::debug!("执行 update() 操作,表: {}", self.table);
2496        }
2497
2498        // 检查是否有 WHERE 条件
2499        if self.conditions.is_empty() {
2500            log::warn!("update() 操作缺少 WHERE 条件,禁止全表更新");
2501            return Err(crate::error::DbError::MissingWhereClause);
2502        }
2503
2504        // 将数据序列化为 JSON
2505        let json_data = serde_json::to_value(data).map_err(|e| {
2506            crate::error::DbError::SerializationError(format!("数据序列化失败: {}", e))
2507        })?;
2508
2509        // 生成 UPDATE 语句
2510        let mut generator = SqlGenerator::new();
2511        generator.build_update(&self.table, &json_data, &self.field_types, &self.conditions)?;
2512
2513        let sql = generator.get_sql();
2514        let params = generator.get_params();
2515
2516        // 记录日志
2517        if self.enable_logging {
2518            log::debug!("执行 update() SQL: {}", sql);
2519            log::debug!("参数: {:?}", params);
2520        }
2521
2522        // 构建查询
2523        let mut query = sqlx::query(sql);
2524
2525        // 绑定参数
2526        for param in params {
2527            query = bind_execute_param(query, param);
2528        }
2529
2530        // 执行更新
2531        let result = query.execute(self.pool).await;
2532
2533        match result {
2534            Ok(query_result) => {
2535                let rows_affected = query_result.rows_affected();
2536                if self.enable_logging {
2537                    log::debug!("update() 成功,影响 {} 行", rows_affected);
2538                }
2539                Ok(rows_affected)
2540            }
2541            Err(e) => {
2542                log::error!("update() 失败: {}", e);
2543                Err(crate::error::DbError::from(e))
2544            }
2545        }
2546    }
2547
2548    /// 删除数据
2549    ///
2550    /// 执行 DELETE 操作,删除表中的数据。
2551    /// 为了防止误操作,必须提供 WHERE 条件,否则会返回错误。
2552    ///
2553    /// # 返回
2554    /// - Ok(u64): 删除成功,返回受影响的行数
2555    /// - Err(DbError): 删除失败
2556    ///
2557    /// # 示例
2558    /// ```no_run
2559    /// use yang_db::Database;
2560    ///
2561    /// # async fn example() -> Result<(), yang_db::DbError> {
2562    /// let db = Database::connect("mysql://root:password@localhost/test").await?;
2563    ///
2564    /// // 删除指定用户
2565    /// let rows_affected = db.table("users")
2566    ///     .where_and("id", "=", 1)
2567    ///     .delete()
2568    ///     .await?;
2569    ///
2570    /// println!("删除了 {} 行数据", rows_affected);
2571    /// # Ok(())
2572    /// # }
2573    /// ```
2574    pub async fn delete(self) -> Result<u64, crate::error::DbError> {
2575        // 记录日志
2576        if self.enable_logging {
2577            log::debug!("执行 delete() 操作,表: {}", self.table);
2578        }
2579
2580        // 检查是否有 WHERE 条件
2581        if self.conditions.is_empty() {
2582            log::warn!("delete() 操作缺少 WHERE 条件,禁止全表删除");
2583            return Err(crate::error::DbError::MissingWhereClause);
2584        }
2585
2586        // 生成 DELETE 语句
2587        let mut generator = SqlGenerator::new();
2588        generator.build_delete(&self.table, &self.conditions)?;
2589
2590        let sql = generator.get_sql();
2591        let params = generator.get_params();
2592
2593        // 记录日志
2594        if self.enable_logging {
2595            log::debug!("执行 delete() SQL: {}", sql);
2596            log::debug!("参数: {:?}", params);
2597        }
2598
2599        // 构建查询
2600        let mut query = sqlx::query(sql);
2601
2602        // 绑定参数
2603        for param in params {
2604            query = bind_execute_param(query, param);
2605        }
2606
2607        // 执行删除
2608        let result = query.execute(self.pool).await;
2609
2610        match result {
2611            Ok(query_result) => {
2612                let rows_affected = query_result.rows_affected();
2613                if self.enable_logging {
2614                    log::debug!("delete() 成功,影响 {} 行", rows_affected);
2615                }
2616                Ok(rows_affected)
2617            }
2618            Err(e) => {
2619                log::error!("delete() 失败: {}", e);
2620                Err(crate::error::DbError::from(e))
2621            }
2622        }
2623    }
2624
2625    /// 批量更新记录
2626    ///
2627    /// 使用 CASE WHEN 策略在单次查询中更新多条记录。自动分批处理(每批 1000 条),
2628    /// 所有批次在同一事务中执行,保证原子性。
2629    ///
2630    /// # 参数
2631    /// - `records`: 要更新的记录列表(每条必须包含 where_field 字段)
2632    /// - `where_field`: 主键字段名(如 `"id"`),用于匹配记录
2633    ///
2634    /// # 返回
2635    /// - `Ok(u64)`: 总受影响行数
2636    ///
2637    /// # 示例
2638    /// ```no_run
2639    /// # use yang_db::Database;
2640    /// # use serde_json::json;
2641    /// # async fn example() -> Result<(), yang_db::DbError> {
2642    /// # let db = Database::connect("mysql://root:password@localhost/test").await?;
2643    /// let records = vec![
2644    ///     json!({"id": 1, "name": "张三", "age": 25}),
2645    ///     json!({"id": 2, "name": "李四", "age": 30}),
2646    /// ];
2647    /// let affected = db.table("users")
2648    ///     .update_batch(&records, "id")
2649    ///     .await?;
2650    /// println!("批量更新了 {} 行", affected);
2651    /// # Ok(())
2652    /// # }
2653    /// ```
2654    pub async fn update_batch<T>(
2655        self,
2656        records: &[T],
2657        where_field: &str,
2658    ) -> Result<u64, crate::error::DbError>
2659    where
2660        T: serde::Serialize,
2661    {
2662        if records.is_empty() {
2663            return Err(crate::error::DbError::SerializationError(
2664                "批量更新数据不能为空".to_string(),
2665            ));
2666        }
2667
2668        let json_records: Vec<serde_json::Value> = records
2669            .iter()
2670            .map(|r| {
2671                serde_json::to_value(r).map_err(|e| {
2672                    crate::error::DbError::SerializationError(format!("数据序列化失败: {}", e))
2673                })
2674            })
2675            .collect::<Result<_, _>>()?;
2676
2677        let mut tx = self
2678            .pool
2679            .begin()
2680            .await
2681            .map_err(crate::error::DbError::from)?;
2682        let mut total = 0u64;
2683
2684        for chunk in json_records.chunks(UPDATE_BATCH_SIZE) {
2685            let mut generator = SqlGenerator::new();
2686            generator.build_update_batch(&self.table, chunk, where_field, &self.field_types)?;
2687
2688            let sql = generator.get_sql();
2689            let params = generator.get_params();
2690
2691            let mut query = sqlx::query(sql);
2692            for param in params {
2693                query = bind_execute_param(query, param);
2694            }
2695
2696            let result = query
2697                .execute(&mut *tx)
2698                .await
2699                .map_err(crate::error::DbError::from)?;
2700            total += result.rows_affected();
2701        }
2702
2703        tx.commit().await.map_err(crate::error::DbError::from)?;
2704        Ok(total)
2705    }
2706
2707    /// UPSERT - 插入或更新记录
2708    ///
2709    /// 使用 `INSERT ... ON DUPLICATE KEY UPDATE` 语法。当主键或唯一键冲突时
2710    /// 自动更新所有字段,否则插入新记录。
2711    ///
2712    /// # 返回
2713    /// - `Ok(u64)`: MySQL rows_affected(1=插入新记录, 2=更新现有记录)
2714    ///
2715    /// # 示例
2716    /// ```no_run
2717    /// # use yang_db::Database;
2718    /// # use serde_json::json;
2719    /// # async fn example() -> Result<(), yang_db::DbError> {
2720    /// # let db = Database::connect("mysql://root:password@localhost/test").await?;
2721    /// let data = json!({"id": 1, "name": "张三", "email": "zhangsan@example.com"});
2722    /// let rows = db.table("users").upsert(&data).await?;
2723    /// if rows == 1 {
2724    ///     println!("新插入记录");
2725    /// } else if rows == 2 {
2726    ///     println!("更新了已有记录");
2727    /// }
2728    /// # Ok(())
2729    /// # }
2730    /// ```
2731    pub async fn upsert<T>(self, data: &T) -> Result<u64, crate::error::DbError>
2732    where
2733        T: serde::Serialize,
2734    {
2735        if self.enable_logging {
2736            log::debug!("执行 upsert() 操作,表: {}", self.table);
2737        }
2738
2739        let json_data = serde_json::to_value(data).map_err(|e| {
2740            crate::error::DbError::SerializationError(format!("数据序列化失败: {}", e))
2741        })?;
2742
2743        let mut generator = SqlGenerator::new();
2744        generator.build_upsert(&self.table, &json_data, &self.field_types)?;
2745
2746        let sql = generator.get_sql();
2747        let params = generator.get_params();
2748
2749        if self.enable_logging {
2750            log::debug!("执行 upsert() SQL: {}", sql);
2751        }
2752
2753        let mut query = sqlx::query(sql);
2754        for param in params {
2755            query = bind_execute_param(query, param);
2756        }
2757
2758        let result = query
2759            .execute(self.pool)
2760            .await
2761            .map_err(crate::error::DbError::from)?;
2762        let rows = result.rows_affected();
2763
2764        if self.enable_logging {
2765            log::debug!("upsert() 完成,rows_affected: {}", rows);
2766        }
2767
2768        Ok(rows)
2769    }
2770}
2771
2772/// 绑定参数到执行查询(用于 INSERT/UPDATE/DELETE)
2773///
2774/// # 参数
2775/// - query: sqlx 查询对象
2776/// - param: SQL 参数值
2777///
2778/// # 返回
2779/// - 绑定参数后的查询对象
2780fn bind_execute_param<'q>(
2781    query: sqlx::query::Query<'q, sqlx::MySql, sqlx::mysql::MySqlArguments>,
2782    param: &SqlValue,
2783) -> sqlx::query::Query<'q, sqlx::MySql, sqlx::mysql::MySqlArguments> {
2784    // 使用 bind_value_match! 宏统一处理 SqlValue 各变体的绑定逻辑
2785    bind_value_match!(query, param)
2786}
2787
2788/// 绑定参数到查询
2789///
2790/// # 参数
2791/// - query: sqlx 查询对象
2792/// - param: SQL 参数值
2793///
2794/// # 返回
2795/// - 绑定参数后的查询对象
2796fn bind_param<'q, T>(
2797    query: sqlx::query::QueryAs<'q, sqlx::MySql, T, sqlx::mysql::MySqlArguments>,
2798    param: &SqlValue,
2799) -> sqlx::query::QueryAs<'q, sqlx::MySql, T, sqlx::mysql::MySqlArguments>
2800where
2801    T: for<'r> sqlx::FromRow<'r, sqlx::mysql::MySqlRow> + Send + Unpin,
2802{
2803    // 使用 bind_value_match! 宏统一处理 SqlValue 各变体的绑定逻辑
2804    bind_value_match!(query, param)
2805}
2806
2807/// 绑定参数到标量查询
2808///
2809/// # 参数
2810/// - query: sqlx 标量查询对象
2811/// - param: SQL 参数值
2812///
2813/// # 返回
2814/// - 绑定参数后的查询对象
2815fn bind_scalar_param<'q, T>(
2816    query: sqlx::query::QueryScalar<'q, sqlx::MySql, T, sqlx::mysql::MySqlArguments>,
2817    param: &SqlValue,
2818) -> sqlx::query::QueryScalar<'q, sqlx::MySql, T, sqlx::mysql::MySqlArguments>
2819where
2820    T: for<'r> sqlx::Decode<'r, sqlx::MySql> + sqlx::Type<sqlx::MySql> + Send + Unpin,
2821{
2822    // 使用 bind_value_match! 宏统一处理 SqlValue 各变体的绑定逻辑
2823    bind_value_match!(query, param)
2824}
2825
2826/// 绑定参数到标量查询(Option 类型)
2827///
2828/// # 参数
2829/// - query: sqlx 标量查询对象(返回 Option<T>)
2830/// - param: SQL 参数值
2831///
2832/// # 返回
2833/// - 绑定参数后的查询对象
2834fn bind_scalar_param_option<'q, T>(
2835    query: sqlx::query::QueryScalar<'q, sqlx::MySql, Option<T>, sqlx::mysql::MySqlArguments>,
2836    param: &SqlValue,
2837) -> sqlx::query::QueryScalar<'q, sqlx::MySql, Option<T>, sqlx::mysql::MySqlArguments>
2838where
2839    T: for<'r> sqlx::Decode<'r, sqlx::MySql> + sqlx::Type<sqlx::MySql> + Send + Unpin,
2840{
2841    // 使用 bind_value_match! 宏统一处理 SqlValue 各变体的绑定逻辑
2842    bind_value_match!(query, param)
2843}
2844
2845#[cfg(test)]
2846mod tests {
2847    use super::*;
2848    use sqlx::mysql::MySqlPoolOptions;
2849
2850    // 创建测试用的数据库连接池
2851    async fn create_test_pool() -> MySqlPool {
2852        MySqlPoolOptions::new()
2853            .max_connections(1)
2854            .connect("mysql://root:111111@localhost:3306/test")
2855            .await
2856            .expect("无法连接到测试数据库")
2857    }
2858
2859    #[tokio::test]
2860    async fn test_table_name_in_sql() {
2861        let pool = create_test_pool().await;
2862        let builder = QueryBuilder::new(&pool, "users", false);
2863        let sql = builder.to_sql();
2864        assert!(sql.contains("FROM users"));
2865    }
2866
2867    // SqlGenerator 单元测试
2868    #[test]
2869    fn test_sql_generator_new() {
2870        let generator = SqlGenerator::new();
2871        assert_eq!(generator.get_sql(), "");
2872        assert_eq!(generator.get_params().len(), 0);
2873    }
2874
2875    #[test]
2876    fn test_sql_generator_append() {
2877        let mut generator = SqlGenerator::new();
2878        generator.append("SELECT * FROM users");
2879        assert_eq!(generator.get_sql(), "SELECT * FROM users");
2880    }
2881
2882    #[test]
2883    fn test_sql_generator_add_param() {
2884        let mut generator = SqlGenerator::new();
2885        generator.add_param(SqlValue::Int(42));
2886        generator.add_param(SqlValue::String("test".to_string()));
2887        assert_eq!(generator.get_params().len(), 2);
2888    }
2889
2890    #[test]
2891    fn test_sql_generator_clear() {
2892        let mut generator = SqlGenerator::new();
2893        generator.append("SELECT * FROM users");
2894        generator.add_param(SqlValue::Int(1));
2895
2896        generator.clear();
2897
2898        assert_eq!(generator.get_sql(), "");
2899        assert_eq!(generator.get_params().len(), 0);
2900    }
2901
2902    #[test]
2903    fn test_sql_generator_multiple_operations() {
2904        let mut generator = SqlGenerator::new();
2905
2906        generator.append("SELECT * FROM users WHERE id = ?");
2907        generator.add_param(SqlValue::Int(1));
2908        generator.append(" AND name = ?");
2909        generator.add_param(SqlValue::String("test".to_string()));
2910
2911        assert_eq!(
2912            generator.get_sql(),
2913            "SELECT * FROM users WHERE id = ? AND name = ?"
2914        );
2915        assert_eq!(generator.get_params().len(), 2);
2916    }
2917
2918    #[tokio::test]
2919    async fn test_field_selection() {
2920        let pool = create_test_pool().await;
2921        let builder = QueryBuilder::new(&pool, "users", false)
2922            .field("id")
2923            .field("name");
2924        let sql = builder.to_sql();
2925        assert!(sql.contains("id, name"));
2926    }
2927
2928    #[tokio::test]
2929    async fn test_fields_selection() {
2930        let pool = create_test_pool().await;
2931        let builder = QueryBuilder::new(&pool, "users", false).fields(&["id", "name", "email"]);
2932        let sql = builder.to_sql();
2933        assert!(sql.contains("id, name, email"));
2934    }
2935
2936    #[tokio::test]
2937    async fn test_distinct() {
2938        let pool = create_test_pool().await;
2939        let builder = QueryBuilder::new(&pool, "users", false)
2940            .field("name")
2941            .distinct();
2942        let sql = builder.to_sql();
2943        assert!(sql.contains("SELECT DISTINCT"));
2944    }
2945
2946    #[tokio::test]
2947    async fn test_field_type_marking() {
2948        let pool = create_test_pool().await;
2949        let builder = QueryBuilder::new(&pool, "users", false)
2950            .json("data")
2951            .datetime("created_at")
2952            .timestamp("updated_at")
2953            .decimal("price")
2954            .blob("content")
2955            .text("description");
2956
2957        assert_eq!(builder.field_types.get("data"), Some(&FieldType::Json));
2958        assert_eq!(
2959            builder.field_types.get("created_at"),
2960            Some(&FieldType::DateTime)
2961        );
2962        assert_eq!(
2963            builder.field_types.get("updated_at"),
2964            Some(&FieldType::Timestamp)
2965        );
2966        assert_eq!(builder.field_types.get("price"), Some(&FieldType::Decimal));
2967        assert_eq!(builder.field_types.get("content"), Some(&FieldType::Blob));
2968        assert_eq!(
2969            builder.field_types.get("description"),
2970            Some(&FieldType::Text)
2971        );
2972    }
2973
2974    #[tokio::test]
2975    async fn test_where_and() {
2976        let pool = create_test_pool().await;
2977        let builder = QueryBuilder::new(&pool, "users", false)
2978            .where_and_unchecked("name", "=", "test")
2979            .where_and_unchecked("age", ">", 18);
2980
2981        assert_eq!(builder.conditions.len(), 2);
2982    }
2983
2984    #[tokio::test]
2985    async fn test_where_or() {
2986        let pool = create_test_pool().await;
2987        let builder = QueryBuilder::new(&pool, "users", false)
2988            .where_or_unchecked("status", "=", 1)
2989            .where_or_unchecked("status", "=", 2);
2990
2991        // where_or 会将条件组合成 OR
2992        assert_eq!(builder.conditions.len(), 1);
2993    }
2994
2995    #[tokio::test]
2996    async fn test_where_in() {
2997        let pool = create_test_pool().await;
2998        let builder = QueryBuilder::new(&pool, "users", false).where_in("id", vec![1, 2, 3]);
2999
3000        assert_eq!(builder.conditions.len(), 1);
3001    }
3002
3003    #[tokio::test]
3004    async fn test_where_between() {
3005        let pool = create_test_pool().await;
3006        let builder = QueryBuilder::new(&pool, "users", false).where_between("age", 18, 65);
3007
3008        assert_eq!(builder.conditions.len(), 1);
3009    }
3010
3011    #[tokio::test]
3012    async fn test_join() {
3013        let pool = create_test_pool().await;
3014        let builder =
3015            QueryBuilder::new(&pool, "users", false).join("orders", "users.id = orders.user_id");
3016
3017        assert_eq!(builder.joins.len(), 1);
3018    }
3019
3020    #[tokio::test]
3021    async fn test_left_join() {
3022        let pool = create_test_pool().await;
3023        let builder = QueryBuilder::new(&pool, "users", false)
3024            .left_join("orders", "users.id = orders.user_id");
3025
3026        assert_eq!(builder.joins.len(), 1);
3027    }
3028
3029    #[tokio::test]
3030    async fn test_right_join() {
3031        let pool = create_test_pool().await;
3032        let builder = QueryBuilder::new(&pool, "users", false)
3033            .right_join("orders", "users.id = orders.user_id");
3034
3035        assert_eq!(builder.joins.len(), 1);
3036    }
3037
3038    #[tokio::test]
3039    async fn test_order() {
3040        let pool = create_test_pool().await;
3041        let builder = QueryBuilder::new(&pool, "users", false)
3042            .order("name", true)
3043            .order("age", false);
3044
3045        assert_eq!(builder.order_by.len(), 2);
3046    }
3047
3048    #[tokio::test]
3049    async fn test_group() {
3050        let pool = create_test_pool().await;
3051        let builder = QueryBuilder::new(&pool, "users", false)
3052            .group("status")
3053            .group("role");
3054
3055        assert_eq!(builder.group_by.len(), 2);
3056    }
3057
3058    // 测试完整的 SELECT 语句生成
3059    #[tokio::test]
3060    async fn test_select_with_where() {
3061        let pool = create_test_pool().await;
3062        let builder = QueryBuilder::new(&pool, "users", false)
3063            .field("id")
3064            .field("name")
3065            .where_and_unchecked("status", "=", 1);
3066
3067        let sql = builder.to_sql();
3068        assert!(sql.contains("SELECT id, name FROM users"));
3069        assert!(sql.contains("WHERE"));
3070    }
3071
3072    #[tokio::test]
3073    async fn test_select_with_join() {
3074        let pool = create_test_pool().await;
3075        let builder = QueryBuilder::new(&pool, "users", false)
3076            .field("users.id")
3077            .field("orders.total")
3078            .join("orders", "users.id = orders.user_id");
3079
3080        let sql = builder.to_sql();
3081        assert!(sql.contains("SELECT users.id, orders.total FROM users"));
3082        assert!(sql.contains("INNER JOIN orders ON users.id = orders.user_id"));
3083    }
3084
3085    #[tokio::test]
3086    async fn test_select_with_order_by() {
3087        let pool = create_test_pool().await;
3088        let builder = QueryBuilder::new(&pool, "users", false)
3089            .field("name")
3090            .order("name", true)
3091            .order("age", false);
3092
3093        let sql = builder.to_sql();
3094        assert!(sql.contains("ORDER BY name ASC, age DESC"));
3095    }
3096
3097    #[tokio::test]
3098    async fn test_select_with_group_by() {
3099        let pool = create_test_pool().await;
3100        let builder = QueryBuilder::new(&pool, "users", false)
3101            .field("status")
3102            .group("status");
3103
3104        let sql = builder.to_sql();
3105        assert!(sql.contains("GROUP BY status"));
3106    }
3107
3108    #[tokio::test]
3109    async fn test_select_with_limit_offset() {
3110        let pool = create_test_pool().await;
3111        let builder = QueryBuilder::new(&pool, "users", false)
3112            .field("id")
3113            .limit(10)
3114            .offset(20);
3115
3116        let sql = builder.to_sql();
3117        assert!(sql.contains("LIMIT 10"));
3118        assert!(sql.contains("OFFSET 20"));
3119    }
3120
3121    #[tokio::test]
3122    async fn test_select_complex_query() {
3123        let pool = create_test_pool().await;
3124        let builder = QueryBuilder::new(&pool, "users", false)
3125            .field("users.id")
3126            .field("users.name")
3127            .field("orders.total")
3128            .distinct()
3129            .join("orders", "users.id = orders.user_id")
3130            .where_and_unchecked("users.status", "=", 1)
3131            .where_and_unchecked("orders.total", ">", 100)
3132            .group("users.id")
3133            .order("orders.total", false)
3134            .limit(50);
3135
3136        let sql = builder.to_sql();
3137        assert!(sql.contains("SELECT DISTINCT"));
3138        assert!(sql.contains("users.id, users.name, orders.total"));
3139        assert!(sql.contains("FROM users"));
3140        assert!(sql.contains("INNER JOIN orders ON users.id = orders.user_id"));
3141        assert!(sql.contains("WHERE"));
3142        assert!(sql.contains("GROUP BY users.id"));
3143        assert!(sql.contains("ORDER BY orders.total DESC"));
3144        assert!(sql.contains("LIMIT 50"));
3145    }
3146
3147    #[tokio::test]
3148    async fn test_select_with_multiple_joins() {
3149        let pool = create_test_pool().await;
3150        let builder = QueryBuilder::new(&pool, "users", false)
3151            .field("users.name")
3152            .field("orders.total")
3153            .field("products.name")
3154            .join("orders", "users.id = orders.user_id")
3155            .left_join("products", "orders.product_id = products.id");
3156
3157        let sql = builder.to_sql();
3158        assert!(sql.contains("INNER JOIN orders ON users.id = orders.user_id"));
3159        assert!(sql.contains("LEFT JOIN products ON orders.product_id = products.id"));
3160    }
3161
3162    #[tokio::test]
3163    async fn test_select_with_in_condition() {
3164        let pool = create_test_pool().await;
3165        let builder = QueryBuilder::new(&pool, "users", false)
3166            .field("name")
3167            .where_in("id", vec![1, 2, 3, 4, 5]);
3168
3169        let sql = builder.to_sql();
3170        assert!(sql.contains("WHERE"));
3171        assert!(sql.contains("IN"));
3172    }
3173
3174    #[tokio::test]
3175    async fn test_select_with_between_condition() {
3176        let pool = create_test_pool().await;
3177        let builder = QueryBuilder::new(&pool, "users", false)
3178            .field("name")
3179            .where_between("age", 18, 65);
3180
3181        let sql = builder.to_sql();
3182        assert!(sql.contains("WHERE"));
3183        assert!(sql.contains("BETWEEN"));
3184    }
3185
3186    #[test]
3187    fn test_where_null_generates_is_null_sql() {
3188        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
3189        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
3190        let builder = QueryBuilder::new(pool, "users", false).where_null("deleted_at");
3191        let sql = builder.to_sql();
3192        assert!(sql.contains("deleted_at IS NULL"));
3193    }
3194
3195    #[test]
3196    fn test_where_not_null_generates_is_not_null_sql() {
3197        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
3198        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
3199        let builder = QueryBuilder::new(pool, "users", false).where_not_null("email");
3200        let sql = builder.to_sql();
3201        assert!(sql.contains("email IS NOT NULL"));
3202    }
3203
3204    #[test]
3205    fn test_is_null_with_and_condition() {
3206        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
3207        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
3208        let builder = QueryBuilder::new(pool, "users", false)
3209            .where_and_unchecked("status", "=", 1i64)
3210            .where_null("deleted_at");
3211        let sql = builder.to_sql();
3212        assert!(sql.contains("status = ?"));
3213        assert!(sql.contains("deleted_at IS NULL"));
3214    }
3215
3216    #[test]
3217    fn test_having_clause_sql_generation() {
3218        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
3219        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
3220        let builder = QueryBuilder::new(pool, "orders", false)
3221            .field("user_id")
3222            .field("COUNT(*) as cnt")
3223            .group("user_id")
3224            .having_cond_unchecked("cnt", ">", 5i64);
3225        let sql = builder.to_sql();
3226        assert!(sql.contains("HAVING"));
3227        assert!(sql.contains("cnt > ?"));
3228    }
3229
3230    #[test]
3231    fn test_having_without_group_returns_error() {
3232        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
3233        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
3234        let builder = QueryBuilder::new(pool, "orders", false).having_cond_unchecked("cnt", ">", 5i64);
3235        let mut generator = SqlGenerator::new();
3236        let result = generator.build_select(&builder);
3237        assert!(result.is_err());
3238        assert!(matches!(
3239            result.unwrap_err(),
3240            crate::DbError::MissingGroupByClause
3241        ));
3242    }
3243
3244    #[test]
3245    fn test_having_clause_order() {
3246        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
3247        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
3248        let builder = QueryBuilder::new(pool, "orders", false)
3249            .group("user_id")
3250            .having_cond_unchecked("cnt", ">", 5i64)
3251            .order("cnt", false);
3252        let sql = builder.to_sql();
3253        let group_pos = sql.find("GROUP BY").unwrap();
3254        let having_pos = sql.find("HAVING").unwrap();
3255        let order_pos = sql.find("ORDER BY").unwrap();
3256        assert!(group_pos < having_pos);
3257        assert!(having_pos < order_pos);
3258    }
3259
3260    #[test]
3261    fn test_update_batch_case_when_sql() {
3262        let records = vec![
3263            serde_json::json!({"id": 1, "name": "Alice", "age": 25}),
3264            serde_json::json!({"id": 2, "name": "Bob", "age": 30}),
3265        ];
3266        let mut generator = SqlGenerator::new();
3267        generator
3268            .build_update_batch("users", &records, "id", &std::collections::HashMap::new())
3269            .unwrap();
3270        let sql = generator.get_sql();
3271        assert!(sql.starts_with("UPDATE users SET "));
3272        assert!(sql.contains("CASE WHEN id=? THEN ?"));
3273        assert!(sql.contains("WHERE id IN ("));
3274    }
3275
3276    #[test]
3277    fn test_update_batch_empty_returns_error() {
3278        let records: Vec<serde_json::Value> = vec![];
3279        let mut generator = SqlGenerator::new();
3280        let result = generator.build_update_batch(
3281            "users",
3282            &records,
3283            "id",
3284            &std::collections::HashMap::new(),
3285        );
3286        assert!(result.is_err());
3287    }
3288
3289    #[test]
3290    fn test_upsert_sql_generation() {
3291        let data = serde_json::json!({"id": 1, "name": "Alice", "email": "a@b.com"});
3292        let mut generator = SqlGenerator::new();
3293        generator
3294            .build_upsert("users", &data, &std::collections::HashMap::new())
3295            .unwrap();
3296        let sql = generator.get_sql();
3297        assert!(sql.starts_with("INSERT INTO users"));
3298        assert!(sql.contains("ON DUPLICATE KEY UPDATE"));
3299        assert!(sql.contains("name=VALUES(name)"));
3300    }
3301
3302    #[test]
3303    fn test_upsert_empty_data_returns_error() {
3304        let data = serde_json::json!({});
3305        let mut generator = SqlGenerator::new();
3306        let result = generator.build_upsert("users", &data, &std::collections::HashMap::new());
3307        assert!(result.is_err());
3308    }
3309
3310    // 测试 SqlGenerator 的 build_select 方法
3311    #[tokio::test]
3312    async fn test_sql_generator_build_select_basic() {
3313        let pool = create_test_pool().await;
3314        let builder = QueryBuilder::new(&pool, "users", false)
3315            .field("id")
3316            .field("name");
3317
3318        let mut generator = SqlGenerator::new();
3319        let result = generator.build_select(&builder);
3320
3321        assert!(result.is_ok());
3322        assert_eq!(generator.get_sql(), "SELECT id, name FROM users");
3323    }
3324
3325    #[tokio::test]
3326    async fn test_sql_generator_build_select_with_distinct() {
3327        let pool = create_test_pool().await;
3328        let builder = QueryBuilder::new(&pool, "users", false)
3329            .field("name")
3330            .distinct();
3331
3332        let mut generator = SqlGenerator::new();
3333        let result = generator.build_select(&builder);
3334
3335        assert!(result.is_ok());
3336        assert_eq!(generator.get_sql(), "SELECT DISTINCT name FROM users");
3337    }
3338
3339    #[tokio::test]
3340    async fn test_sql_generator_build_select_all_fields() {
3341        let pool = create_test_pool().await;
3342        let builder = QueryBuilder::new(&pool, "users", false);
3343
3344        let mut generator = SqlGenerator::new();
3345        let result = generator.build_select(&builder);
3346
3347        assert!(result.is_ok());
3348        assert_eq!(generator.get_sql(), "SELECT * FROM users");
3349    }
3350
3351    // 测试 WHERE 子句生成
3352    #[tokio::test]
3353    async fn test_sql_generator_build_where() {
3354        let pool = create_test_pool().await;
3355        let builder = QueryBuilder::new(&pool, "users", false)
3356            .where_and_unchecked("status", "=", 1)
3357            .where_and_unchecked("age", ">", 18);
3358
3359        let mut generator = SqlGenerator::new();
3360        let result = generator.build_select(&builder);
3361
3362        assert!(result.is_ok());
3363        let sql = generator.get_sql();
3364        assert!(sql.contains("WHERE"));
3365        assert!(sql.contains("status"));
3366        assert!(sql.contains("age"));
3367    }
3368
3369    // 测试 JOIN 子句生成
3370    #[tokio::test]
3371    async fn test_sql_generator_build_joins() {
3372        let pool = create_test_pool().await;
3373        let builder = QueryBuilder::new(&pool, "users", false)
3374            .join("orders", "users.id = orders.user_id")
3375            .left_join("profiles", "users.id = profiles.user_id");
3376
3377        let mut generator = SqlGenerator::new();
3378        let result = generator.build_select(&builder);
3379
3380        assert!(result.is_ok());
3381        let sql = generator.get_sql();
3382        assert!(sql.contains("INNER JOIN orders ON users.id = orders.user_id"));
3383        assert!(sql.contains("LEFT JOIN profiles ON users.id = profiles.user_id"));
3384    }
3385
3386    // 测试 ORDER BY 子句生成
3387    #[tokio::test]
3388    async fn test_sql_generator_build_order_by() {
3389        let pool = create_test_pool().await;
3390        let builder = QueryBuilder::new(&pool, "users", false)
3391            .order("name", true)
3392            .order("created_at", false);
3393
3394        let mut generator = SqlGenerator::new();
3395        let result = generator.build_select(&builder);
3396
3397        assert!(result.is_ok());
3398        let sql = generator.get_sql();
3399        assert!(sql.contains("ORDER BY name ASC, created_at DESC"));
3400    }
3401
3402    // 测试 GROUP BY 子句生成
3403    #[tokio::test]
3404    async fn test_sql_generator_build_group_by() {
3405        let pool = create_test_pool().await;
3406        let builder = QueryBuilder::new(&pool, "users", false)
3407            .group("status")
3408            .group("role");
3409
3410        let mut generator = SqlGenerator::new();
3411        let result = generator.build_select(&builder);
3412
3413        assert!(result.is_ok());
3414        let sql = generator.get_sql();
3415        assert!(sql.contains("GROUP BY status, role"));
3416    }
3417
3418    // 测试 LIMIT 和 OFFSET 子句生成
3419    #[tokio::test]
3420    async fn test_sql_generator_build_limit_offset() {
3421        let pool = create_test_pool().await;
3422        let builder = QueryBuilder::new(&pool, "users", false)
3423            .limit(10)
3424            .offset(20);
3425
3426        let mut generator = SqlGenerator::new();
3427        let result = generator.build_select(&builder);
3428
3429        assert!(result.is_ok());
3430        let sql = generator.get_sql();
3431        assert!(sql.contains("LIMIT 10"));
3432        assert!(sql.contains("OFFSET 20"));
3433    }
3434
3435    // 测试完整的复杂查询生成
3436    #[tokio::test]
3437    async fn test_sql_generator_complex_query() {
3438        let pool = create_test_pool().await;
3439        let builder = QueryBuilder::new(&pool, "users", false)
3440            .field("users.id")
3441            .field("users.name")
3442            .field("COUNT(orders.id) as order_count")
3443            .distinct()
3444            .join("orders", "users.id = orders.user_id")
3445            .where_and_unchecked("users.status", "=", 1)
3446            .where_and_unchecked("orders.total", ">", 100)
3447            .group("users.id")
3448            .group("users.name")
3449            .order("order_count", false)
3450            .limit(20)
3451            .offset(10);
3452
3453        let mut generator = SqlGenerator::new();
3454        let result = generator.build_select(&builder);
3455
3456        assert!(result.is_ok());
3457        let sql = generator.get_sql();
3458
3459        // 验证各个部分都存在
3460        assert!(sql.starts_with("SELECT DISTINCT"));
3461        assert!(sql.contains("users.id, users.name, COUNT(orders.id) as order_count"));
3462        assert!(sql.contains("FROM users"));
3463        assert!(sql.contains("INNER JOIN orders ON users.id = orders.user_id"));
3464        assert!(sql.contains("WHERE"));
3465        assert!(sql.contains("GROUP BY users.id, users.name"));
3466        assert!(sql.contains("ORDER BY order_count DESC"));
3467        assert!(sql.contains("LIMIT 20"));
3468        assert!(sql.contains("OFFSET 10"));
3469    }
3470
3471    // 测试 find() 方法的 SQL 生成
3472    #[tokio::test]
3473    async fn test_find_adds_limit_one() {
3474        let pool = create_test_pool().await;
3475        let builder = QueryBuilder::new(&pool, "users", false)
3476            .field("id")
3477            .field("name")
3478            .where_and_unchecked("id", "=", 1);
3479
3480        // 在调用 find() 之前,limit 应该是 None
3481        assert_eq!(builder.limit, None);
3482
3483        // 创建一个新的 builder 来测试 SQL 生成
3484        let builder_with_limit = QueryBuilder::new(&pool, "users", false)
3485            .field("id")
3486            .field("name")
3487            .where_and_unchecked("id", "=", 1)
3488            .limit(1);
3489
3490        let sql = builder_with_limit.to_sql();
3491        assert!(sql.contains("LIMIT 1"), "find() 应该自动添加 LIMIT 1");
3492    }
3493
3494    // 测试 INSERT 语句生成
3495    #[test]
3496    fn test_sql_generator_build_insert_basic() {
3497        let mut generator = SqlGenerator::new();
3498        let data = serde_json::json!({
3499            "name": "张三",
3500            "age": 25,
3501            "email": "zhangsan@example.com"
3502        });
3503        let field_types = HashMap::new();
3504
3505        let result = generator.build_insert("users", &data, &field_types);
3506        assert!(result.is_ok());
3507
3508        let sql = generator.get_sql();
3509        assert!(sql.starts_with("INSERT INTO users"));
3510        assert!(sql.contains("name"));
3511        assert!(sql.contains("age"));
3512        assert!(sql.contains("email"));
3513        assert!(sql.contains("VALUES"));
3514        assert_eq!(generator.get_params().len(), 3);
3515    }
3516
3517    #[test]
3518    fn test_sql_generator_build_insert_with_json_field() {
3519        let mut generator = SqlGenerator::new();
3520        let data = serde_json::json!({
3521            "name": "测试用户",
3522            "data": {"role": "admin", "permissions": ["read", "write"]}
3523        });
3524
3525        let mut field_types = HashMap::new();
3526        field_types.insert("data".to_string(), FieldType::Json);
3527
3528        let result = generator.build_insert("users", &data, &field_types);
3529        assert!(result.is_ok());
3530
3531        let sql = generator.get_sql();
3532        assert!(sql.contains("INSERT INTO users"));
3533        assert!(sql.contains("name"));
3534        assert!(sql.contains("data"));
3535        assert_eq!(generator.get_params().len(), 2);
3536
3537        // 验证 JSON 字段被正确处理
3538        let params = generator.get_params();
3539        let has_json = params.iter().any(|p| matches!(p, SqlValue::Json(_)));
3540        assert!(has_json, "应该包含 JSON 类型的参数");
3541    }
3542
3543    #[test]
3544    fn test_sql_generator_build_insert_empty_data() {
3545        let mut generator = SqlGenerator::new();
3546        let data = serde_json::json!({});
3547        let field_types = HashMap::new();
3548
3549        let result = generator.build_insert("users", &data, &field_types);
3550        assert!(result.is_err());
3551        assert!(matches!(
3552            result.unwrap_err(),
3553            crate::error::DbError::SerializationError(_)
3554        ));
3555    }
3556
3557    #[test]
3558    fn test_sql_generator_build_insert_not_object() {
3559        let mut generator = SqlGenerator::new();
3560        let data = serde_json::json!([1, 2, 3]); // 数组而不是对象
3561        let field_types = HashMap::new();
3562
3563        let result = generator.build_insert("users", &data, &field_types);
3564        assert!(result.is_err());
3565        assert!(matches!(
3566            result.unwrap_err(),
3567            crate::error::DbError::SerializationError(_)
3568        ));
3569    }
3570
3571    // ==================== 聚合函数单元测试 ====================
3572
3573    /// 测试 AVG 聚合函数 SQL 生成
3574    #[tokio::test]
3575    async fn test_avg_sql_generation() {
3576        let pool = create_test_pool().await;
3577
3578        // 创建一个新的 builder 来模拟 avg() 方法的行为
3579        let mut test_builder = QueryBuilder::new(&pool, "products", false);
3580        test_builder.fields.clear();
3581        test_builder
3582            .fields
3583            .push("CAST(AVG(price) AS DOUBLE)".to_string());
3584        test_builder.limit = Some(1);
3585
3586        let sql = test_builder.to_sql();
3587        assert!(sql.contains("SELECT CAST(AVG(price) AS DOUBLE)"));
3588        assert!(sql.contains("FROM products"));
3589        assert!(sql.contains("LIMIT 1"));
3590    }
3591
3592    /// 测试 AVG 与 WHERE 条件组合
3593    #[tokio::test]
3594    async fn test_avg_with_where_sql() {
3595        let pool = create_test_pool().await;
3596
3597        // 模拟 avg() 方法与 WHERE 条件组合
3598        let mut test_builder =
3599            QueryBuilder::new(&pool, "products", false).where_and_unchecked("status", "=", 1);
3600        test_builder.fields.clear();
3601        test_builder
3602            .fields
3603            .push("CAST(AVG(price) AS DOUBLE)".to_string());
3604        test_builder.limit = Some(1);
3605
3606        let sql = test_builder.to_sql();
3607        assert!(sql.contains("SELECT CAST(AVG(price) AS DOUBLE)"));
3608        assert!(sql.contains("FROM products"));
3609        assert!(sql.contains("WHERE"));
3610        assert!(sql.contains("status"));
3611    }
3612
3613    /// 测试 MIN 聚合函数 SQL 生成
3614    #[tokio::test]
3615    async fn test_min_sql_generation() {
3616        let pool = create_test_pool().await;
3617
3618        // 模拟 min() 方法的行为
3619        let mut test_builder = QueryBuilder::new(&pool, "products", false);
3620        test_builder.fields.clear();
3621        test_builder.fields.push("MIN(price)".to_string());
3622        test_builder.limit = Some(1);
3623
3624        let sql = test_builder.to_sql();
3625        assert!(sql.contains("SELECT MIN(price)"));
3626        assert!(sql.contains("FROM products"));
3627        assert!(sql.contains("LIMIT 1"));
3628    }
3629
3630    /// 测试 MAX 聚合函数 SQL 生成
3631    #[tokio::test]
3632    async fn test_max_sql_generation() {
3633        let pool = create_test_pool().await;
3634
3635        // 模拟 max() 方法的行为
3636        let mut test_builder = QueryBuilder::new(&pool, "products", false);
3637        test_builder.fields.clear();
3638        test_builder.fields.push("MAX(price)".to_string());
3639        test_builder.limit = Some(1);
3640
3641        let sql = test_builder.to_sql();
3642        assert!(sql.contains("SELECT MAX(price)"));
3643        assert!(sql.contains("FROM products"));
3644        assert!(sql.contains("LIMIT 1"));
3645    }
3646
3647    /// 测试 MIN/MAX 不同数据类型的 SQL 生成
3648    #[tokio::test]
3649    async fn test_min_max_different_types() {
3650        let pool = create_test_pool().await;
3651
3652        // 测试整数类型
3653        let mut builder_int = QueryBuilder::new(&pool, "products", false);
3654        builder_int.fields.clear();
3655        builder_int.fields.push("MIN(stock)".to_string());
3656        let sql_int = builder_int.to_sql();
3657        assert!(sql_int.contains("MIN(stock)"));
3658
3659        // 测试浮点数类型
3660        let mut builder_float = QueryBuilder::new(&pool, "products", false);
3661        builder_float.fields.clear();
3662        builder_float.fields.push("MAX(price)".to_string());
3663        let sql_float = builder_float.to_sql();
3664        assert!(sql_float.contains("MAX(price)"));
3665
3666        // 测试字符串类型
3667        let mut builder_string = QueryBuilder::new(&pool, "users", false);
3668        builder_string.fields.clear();
3669        builder_string.fields.push("MIN(name)".to_string());
3670        let sql_string = builder_string.to_sql();
3671        assert!(sql_string.contains("MIN(name)"));
3672
3673        // 测试日期时间类型
3674        let mut builder_datetime = QueryBuilder::new(&pool, "users", false);
3675        builder_datetime.fields.clear();
3676        builder_datetime.fields.push("MAX(created_at)".to_string());
3677        let sql_datetime = builder_datetime.to_sql();
3678        assert!(sql_datetime.contains("MAX(created_at)"));
3679    }
3680
3681    /// 测试聚合函数与 GROUP BY 组合
3682    #[tokio::test]
3683    async fn test_aggregates_with_group_by_sql() {
3684        let pool = create_test_pool().await;
3685
3686        // 模拟聚合函数与 GROUP BY 组合
3687        let mut test_builder = QueryBuilder::new(&pool, "orders", false).group("user_id");
3688        test_builder.fields.clear();
3689        test_builder.fields.push("user_id".to_string());
3690        test_builder
3691            .fields
3692            .push("CAST(AVG(amount) AS DOUBLE) as avg_amount".to_string());
3693
3694        let sql = test_builder.to_sql();
3695        assert!(sql.contains("SELECT user_id, CAST(AVG(amount) AS DOUBLE) as avg_amount"));
3696        assert!(sql.contains("FROM orders"));
3697        assert!(sql.contains("GROUP BY user_id"));
3698    }
3699
3700    /// 测试多个聚合函数组合
3701    #[tokio::test]
3702    async fn test_multiple_aggregates_sql() {
3703        let pool = create_test_pool().await;
3704
3705        // 模拟多个聚合函数组合
3706        let mut test_builder =
3707            QueryBuilder::new(&pool, "orders", false).where_and_unchecked("status", "=", "completed");
3708        test_builder.fields.clear();
3709        test_builder
3710            .fields
3711            .push("CAST(AVG(amount) AS DOUBLE) as avg_amount".to_string());
3712        test_builder
3713            .fields
3714            .push("CAST(MIN(amount) AS DOUBLE) as min_amount".to_string());
3715        test_builder
3716            .fields
3717            .push("CAST(MAX(amount) AS DOUBLE) as max_amount".to_string());
3718        test_builder
3719            .fields
3720            .push("COUNT(*) as order_count".to_string());
3721
3722        let sql = test_builder.to_sql();
3723        assert!(sql.contains("CAST(AVG(amount) AS DOUBLE) as avg_amount"));
3724        assert!(sql.contains("CAST(MIN(amount) AS DOUBLE) as min_amount"));
3725        assert!(sql.contains("CAST(MAX(amount) AS DOUBLE) as max_amount"));
3726        assert!(sql.contains("COUNT(*) as order_count"));
3727        assert!(sql.contains("WHERE"));
3728        assert!(sql.contains("status"));
3729    }
3730
3731    /// 测试 SQL 子句顺序正确性(WHERE -> GROUP BY -> ORDER BY)
3732    #[tokio::test]
3733    async fn test_sql_clause_order_with_aggregates() {
3734        let pool = create_test_pool().await;
3735
3736        // 创建包含 WHERE、GROUP BY、ORDER BY 的查询
3737        let mut test_builder = QueryBuilder::new(&pool, "orders", false)
3738            .where_and_unchecked("status", "=", "completed")
3739            .group("user_id")
3740            .order("total_amount", false);
3741        test_builder.fields.clear();
3742        test_builder.fields.push("user_id".to_string());
3743        test_builder
3744            .fields
3745            .push("SUM(amount) as total_amount".to_string());
3746
3747        let sql = test_builder.to_sql();
3748
3749        // 验证子句顺序:WHERE 应该在 GROUP BY 之前,GROUP BY 应该在 ORDER BY 之前
3750        let where_pos = sql.find("WHERE").expect("应该包含 WHERE");
3751        let group_pos = sql.find("GROUP BY").expect("应该包含 GROUP BY");
3752        let order_pos = sql.find("ORDER BY").expect("应该包含 ORDER BY");
3753
3754        assert!(where_pos < group_pos, "WHERE 应该在 GROUP BY 之前");
3755        assert!(group_pos < order_pos, "GROUP BY 应该在 ORDER BY 之前");
3756    }
3757
3758    /// 测试空结果集场景的 SQL 生成
3759    #[tokio::test]
3760    async fn test_aggregates_empty_result_sql() {
3761        let pool = create_test_pool().await;
3762
3763        // 创建一个不会匹配任何记录的查询
3764        let mut test_builder = QueryBuilder::new(&pool, "products", false).where_and_unchecked("id", "=", -1); // 假设 id 不会是负数
3765        test_builder.fields.clear();
3766        test_builder
3767            .fields
3768            .push("CAST(AVG(price) AS DOUBLE)".to_string());
3769        test_builder.limit = Some(1);
3770
3771        let sql = test_builder.to_sql();
3772        assert!(sql.contains("SELECT CAST(AVG(price) AS DOUBLE)"));
3773        assert!(sql.contains("WHERE"));
3774        // SQL 生成应该正常,即使结果集为空
3775    }
3776
3777    /// 测试聚合函数字段名包含特殊字符
3778    #[tokio::test]
3779    async fn test_aggregates_with_special_field_names() {
3780        let pool = create_test_pool().await;
3781
3782        // 测试带下划线的字段名
3783        let mut test_builder = QueryBuilder::new(&pool, "products", false);
3784        test_builder.fields.clear();
3785        test_builder.fields.push("AVG(unit_price)".to_string());
3786
3787        let sql = test_builder.to_sql();
3788        assert!(sql.contains("AVG(unit_price)"));
3789
3790        // 测试带反引号的字段名(MySQL 保留字)
3791        let mut test_builder2 = QueryBuilder::new(&pool, "products", false);
3792        test_builder2.fields.clear();
3793        test_builder2.fields.push("MAX(`order`)".to_string());
3794
3795        let sql2 = test_builder2.to_sql();
3796        assert!(sql2.contains("MAX(`order`)"));
3797    }
3798
3799    /// 测试聚合函数与 DISTINCT 组合
3800    #[tokio::test]
3801    async fn test_aggregates_with_distinct() {
3802        let pool = create_test_pool().await;
3803
3804        // 模拟 COUNT(DISTINCT field) 场景
3805        let mut test_builder = QueryBuilder::new(&pool, "orders", false);
3806        test_builder.fields.clear();
3807        test_builder
3808            .fields
3809            .push("COUNT(DISTINCT user_id) as unique_users".to_string());
3810
3811        let sql = test_builder.to_sql();
3812        assert!(sql.contains("COUNT(DISTINCT user_id)"));
3813    }
3814
3815    /// 测试聚合函数与 JOIN 组合
3816    #[tokio::test]
3817    async fn test_aggregates_with_join() {
3818        let pool = create_test_pool().await;
3819
3820        // 模拟聚合函数与 JOIN 组合
3821        let mut test_builder = QueryBuilder::new(&pool, "users", false)
3822            .join("orders", "users.id = orders.user_id")
3823            .group("users.id");
3824        test_builder.fields.clear();
3825        test_builder.fields.push("users.id".to_string());
3826        test_builder.fields.push("users.name".to_string());
3827        test_builder
3828            .fields
3829            .push("COUNT(orders.id) as order_count".to_string());
3830        test_builder
3831            .fields
3832            .push("SUM(orders.amount) as total_amount".to_string());
3833
3834        let sql = test_builder.to_sql();
3835        assert!(sql.contains("INNER JOIN orders ON users.id = orders.user_id"));
3836        assert!(sql.contains("COUNT(orders.id) as order_count"));
3837        assert!(sql.contains("SUM(orders.amount) as total_amount"));
3838        assert!(sql.contains("GROUP BY users.id"));
3839    }
3840
3841    /// 测试聚合函数参数化查询防止 SQL 注入
3842    #[tokio::test]
3843    async fn test_aggregates_sql_injection_prevention() {
3844        let pool = create_test_pool().await;
3845
3846        // 测试 WHERE 条件使用参数化查询
3847        let builder = QueryBuilder::new(&pool, "products", false).where_and_unchecked(
3848            "category",
3849            "=",
3850            "'; DROP TABLE products; --",
3851        );
3852
3853        // 生成 SQL 和参数
3854        let mut generator = SqlGenerator::new();
3855        let result = generator.build_select(&builder);
3856        assert!(result.is_ok());
3857
3858        let sql = generator.get_sql();
3859        let params = generator.get_params();
3860
3861        // 验证 SQL 使用占位符而不是直接拼接值
3862        assert!(sql.contains("?"));
3863        assert!(!sql.contains("DROP TABLE"));
3864
3865        // 验证参数列表包含恶意字符串(作为参数值,不会被执行)
3866        assert_eq!(params.len(), 1);
3867    }
3868}
3869
3870#[cfg(test)]
3871mod property_tests {
3872    use super::*;
3873    use proptest::prelude::*;
3874    use sqlx::mysql::MySqlPoolOptions;
3875
3876    // 生成有效的表名(字母开头,后跟字母数字下划线)
3877    fn table_name_strategy() -> impl Strategy<Value = String> {
3878        "[a-z][a-z0-9_]{0,30}"
3879    }
3880
3881    // 生成有效的字段名
3882    fn field_name_strategy() -> impl Strategy<Value = String> {
3883        "[a-z][a-z0-9_]{0,30}"
3884    }
3885
3886    // 创建测试用的数据库连接池(同步版本用于 proptest)
3887    fn create_test_pool_sync() -> MySqlPool {
3888        tokio::runtime::Runtime::new().unwrap().block_on(async {
3889            MySqlPoolOptions::new()
3890                .max_connections(1)
3891                .connect("mysql://root:111111@localhost:3306/test")
3892                .await
3893                .expect("无法连接到测试数据库")
3894        })
3895    }
3896
3897    // Feature: mysql-query-builder, Property 1: 表名设置正确性
3898    // 验证需求:2.1
3899    proptest! {
3900        #![proptest_config(ProptestConfig::with_cases(100))]
3901
3902        #[test]
3903        fn prop_table_name_in_sql(table_name in table_name_strategy()) {
3904            let pool = create_test_pool_sync();
3905            let builder = QueryBuilder::new(&pool, &table_name, false);
3906            let sql = builder.to_sql();
3907
3908            // 验证 SQL 包含表名
3909            let expected = format!("FROM {}", table_name);
3910            prop_assert!(sql.contains(&expected));
3911        }
3912    }
3913
3914    // Feature: mysql-query-builder, Property 2: 表名覆盖行为
3915    // 验证需求:2.2
3916    proptest! {
3917        #![proptest_config(ProptestConfig::with_cases(100))]
3918
3919        #[test]
3920        fn prop_table_name_override(
3921            table_name1 in table_name_strategy(),
3922            table_name2 in table_name_strategy()
3923        ) {
3924            prop_assume!(table_name1 != table_name2);
3925
3926            let pool = create_test_pool_sync();
3927            // 先创建一个 builder,然后通过重新创建来模拟覆盖
3928            let builder1 = QueryBuilder::new(&pool, &table_name1, false);
3929            let sql1 = builder1.to_sql();
3930            let expected1 = format!("FROM {}", table_name1);
3931            prop_assert!(sql1.contains(&expected1));
3932
3933            // 创建新的 builder 使用 table_name2
3934            let builder2 = QueryBuilder::new(&pool, &table_name2, false);
3935            let sql2 = builder2.to_sql();
3936            let expected2 = format!("FROM {}", table_name2);
3937            prop_assert!(sql2.contains(&expected2));
3938
3939            // 使用更精确的匹配:检查 FROM 后面的完整表名(带空格或 WHERE 等关键字)
3940            // 避免子字符串匹配问题(如 "w" 是 "w_" 的子串)
3941            let pattern1 = format!("FROM {} ", table_name1);
3942            let pattern1_alt = format!("FROM {}\n", table_name1);
3943            prop_assert!(!sql2.contains(&pattern1) && !sql2.contains(&pattern1_alt));
3944        }
3945    }
3946
3947    // Feature: mysql-query-builder, Property 24: 字段选择
3948    // 验证需求:9.1, 9.2
3949    proptest! {
3950        #![proptest_config(ProptestConfig::with_cases(100))]
3951
3952        #[test]
3953        fn prop_field_selection(
3954            table_name in table_name_strategy(),
3955            fields in prop::collection::vec(field_name_strategy(), 1..10)
3956        ) {
3957            let pool = create_test_pool_sync();
3958            let mut builder = QueryBuilder::new(&pool, &table_name, false);
3959
3960            // 添加所有字段
3961            for field in &fields {
3962                builder = builder.field(field);
3963            }
3964
3965            let sql = builder.to_sql();
3966
3967            // 验证所有字段都在 SELECT 子句中
3968            for field in &fields {
3969                prop_assert!(sql.contains(field));
3970            }
3971        }
3972    }
3973
3974    // Feature: mysql-query-builder, Property 25: DISTINCT 关键字
3975    // 验证需求:9.4
3976    proptest! {
3977        #![proptest_config(ProptestConfig::with_cases(100))]
3978
3979        #[test]
3980        fn prop_distinct_keyword(
3981            table_name in table_name_strategy(),
3982            field in field_name_strategy()
3983        ) {
3984            let pool = create_test_pool_sync();
3985            let builder = QueryBuilder::new(&pool, &table_name, false)
3986                .field(&field)
3987                .distinct();
3988
3989            let sql = builder.to_sql();
3990
3991            // 验证 SQL 包含 SELECT DISTINCT
3992            prop_assert!(sql.contains("SELECT DISTINCT"));
3993        }
3994    }
3995
3996    // Feature: mysql-query-builder, Property 27: 特殊字段类型标记
3997    // 验证需求:11.1, 11.2, 11.3, 11.4, 11.5, 11.6
3998    proptest! {
3999        #![proptest_config(ProptestConfig::with_cases(100))]
4000
4001        #[test]
4002        fn prop_special_field_type_marking(
4003            table_name in table_name_strategy(),
4004            json_field in field_name_strategy(),
4005            datetime_field in field_name_strategy(),
4006            timestamp_field in field_name_strategy(),
4007            decimal_field in field_name_strategy(),
4008            blob_field in field_name_strategy(),
4009            text_field in field_name_strategy()
4010        ) {
4011            // 确保所有字段名都不相同,避免覆盖
4012            prop_assume!(json_field != datetime_field);
4013            prop_assume!(json_field != timestamp_field);
4014            prop_assume!(json_field != decimal_field);
4015            prop_assume!(json_field != blob_field);
4016            prop_assume!(json_field != text_field);
4017            prop_assume!(datetime_field != timestamp_field);
4018            prop_assume!(datetime_field != decimal_field);
4019            prop_assume!(datetime_field != blob_field);
4020            prop_assume!(datetime_field != text_field);
4021            prop_assume!(timestamp_field != decimal_field);
4022            prop_assume!(timestamp_field != blob_field);
4023            prop_assume!(timestamp_field != text_field);
4024            prop_assume!(decimal_field != blob_field);
4025            prop_assume!(decimal_field != text_field);
4026            prop_assume!(blob_field != text_field);
4027
4028            let pool = create_test_pool_sync();
4029            let builder = QueryBuilder::new(&pool, &table_name, false)
4030                .json(&json_field)
4031                .datetime(&datetime_field)
4032                .timestamp(&timestamp_field)
4033                .decimal(&decimal_field)
4034                .blob(&blob_field)
4035                .text(&text_field);
4036
4037            // 验证字段类型映射包含正确的类型标记
4038            prop_assert_eq!(builder.field_types.get(&json_field), Some(&FieldType::Json));
4039            prop_assert_eq!(builder.field_types.get(&datetime_field), Some(&FieldType::DateTime));
4040            prop_assert_eq!(builder.field_types.get(&timestamp_field), Some(&FieldType::Timestamp));
4041            prop_assert_eq!(builder.field_types.get(&decimal_field), Some(&FieldType::Decimal));
4042            prop_assert_eq!(builder.field_types.get(&blob_field), Some(&FieldType::Blob));
4043            prop_assert_eq!(builder.field_types.get(&text_field), Some(&FieldType::Text));
4044        }
4045    }
4046
4047    // Feature: mysql-query-builder, Property 4: WHERE 条件添加
4048    // 验证需求:3.1, 3.2
4049    proptest! {
4050        #![proptest_config(ProptestConfig::with_cases(100))]
4051
4052        #[test]
4053        fn prop_where_and_condition_added(
4054            table_name in table_name_strategy(),
4055            field in field_name_strategy(),
4056            value in any::<i32>()
4057        ) {
4058            let pool = create_test_pool_sync();
4059            let builder = QueryBuilder::new(&pool, &table_name, false)
4060                .where_and_unchecked(&field, "=", value);
4061
4062            // 验证条件已添加
4063            prop_assert_eq!(builder.conditions.len(), 1);
4064        }
4065
4066        #[test]
4067        fn prop_where_or_condition_added(
4068            table_name in table_name_strategy(),
4069            field in field_name_strategy(),
4070            value1 in any::<i32>(),
4071            value2 in any::<i32>()
4072        ) {
4073            let pool = create_test_pool_sync();
4074            let builder = QueryBuilder::new(&pool, &table_name, false)
4075                .where_or_unchecked(&field, "=", value1)
4076                .where_or_unchecked(&field, "=", value2);
4077
4078            // where_or 会将条件组合,所以应该有 1 个条件(OR 组合)
4079            prop_assert_eq!(builder.conditions.len(), 1);
4080        }
4081    }
4082
4083    // Feature: mysql-query-builder, Property 6: IN 操作符数组支持
4084    // 验证需求:3.4
4085    proptest! {
4086        #![proptest_config(ProptestConfig::with_cases(100))]
4087
4088        #[test]
4089        fn prop_in_operator_array_support(
4090            table_name in table_name_strategy(),
4091            field in field_name_strategy(),
4092            values in prop::collection::vec(any::<i32>(), 1..10)
4093        ) {
4094            let pool = create_test_pool_sync();
4095            let builder = QueryBuilder::new(&pool, &table_name, false)
4096                .where_in(&field, values);
4097
4098            // 验证 IN 条件已添加
4099            prop_assert_eq!(builder.conditions.len(), 1);
4100        }
4101    }
4102
4103    // Feature: mysql-query-builder, Property 7: BETWEEN 操作符边界支持
4104    // 验证需求:3.5
4105    proptest! {
4106        #![proptest_config(ProptestConfig::with_cases(100))]
4107
4108        #[test]
4109        fn prop_between_operator_boundary_support(
4110            table_name in table_name_strategy(),
4111            field in field_name_strategy(),
4112            start in any::<i32>(),
4113            end in any::<i32>()
4114        ) {
4115            let pool = create_test_pool_sync();
4116            let builder = QueryBuilder::new(&pool, &table_name, false)
4117                .where_between(&field, start, end);
4118
4119            // 验证 BETWEEN 条件已添加
4120            prop_assert_eq!(builder.conditions.len(), 1);
4121        }
4122    }
4123
4124    // Feature: mysql-query-builder, Property 8: 多条件 AND 连接
4125    // 验证需求:3.6
4126    proptest! {
4127        #![proptest_config(ProptestConfig::with_cases(100))]
4128
4129        #[test]
4130        fn prop_multiple_and_conditions(
4131            table_name in table_name_strategy(),
4132            field in field_name_strategy(),
4133            values in prop::collection::vec(any::<i32>(), 2..5)
4134        ) {
4135            let pool = create_test_pool_sync();
4136            let mut builder = QueryBuilder::new(&pool, &table_name, false);
4137
4138            // 添加多个 AND 条件
4139            for value in &values {
4140                builder = builder.where_and_unchecked(&field, "=", *value);
4141            }
4142
4143            // 验证所有条件都已添加
4144            prop_assert_eq!(builder.conditions.len(), values.len());
4145        }
4146    }
4147
4148    // Feature: mysql-query-builder, Property 31: JOIN 子句生成
4149    // 验证需求:17.1, 17.2, 17.3
4150    proptest! {
4151        #![proptest_config(ProptestConfig::with_cases(100))]
4152
4153        #[test]
4154        fn prop_join_clause_generation(
4155            table_name in table_name_strategy(),
4156            join_table in table_name_strategy(),
4157            on_condition in "[a-z][a-z0-9_]{0,20}\\.[a-z][a-z0-9_]{0,20} = [a-z][a-z0-9_]{0,20}\\.[a-z][a-z0-9_]{0,20}"
4158        ) {
4159            let pool = create_test_pool_sync();
4160
4161            // 测试 INNER JOIN
4162            let builder_inner = QueryBuilder::new(&pool, &table_name, false)
4163                .join(&join_table, &on_condition);
4164            prop_assert_eq!(builder_inner.joins.len(), 1);
4165
4166            // 测试 LEFT JOIN
4167            let builder_left = QueryBuilder::new(&pool, &table_name, false)
4168                .left_join(&join_table, &on_condition);
4169            prop_assert_eq!(builder_left.joins.len(), 1);
4170
4171            // 测试 RIGHT JOIN
4172            let builder_right = QueryBuilder::new(&pool, &table_name, false)
4173                .right_join(&join_table, &on_condition);
4174            prop_assert_eq!(builder_right.joins.len(), 1);
4175        }
4176    }
4177
4178    // Feature: mysql-query-builder, Property 32: 多表连接支持
4179    // 验证需求:17.5
4180    proptest! {
4181        #![proptest_config(ProptestConfig::with_cases(100))]
4182
4183        #[test]
4184        fn prop_multiple_join_support(
4185            table_name in table_name_strategy(),
4186            join_tables in prop::collection::vec(table_name_strategy(), 1..5)
4187        ) {
4188            let pool = create_test_pool_sync();
4189            let mut builder = QueryBuilder::new(&pool, &table_name, false);
4190
4191            // 添加多个 JOIN
4192            for join_table in &join_tables {
4193                let on_condition = format!("{}.id = {}.id", table_name, join_table);
4194                builder = builder.join(join_table, &on_condition);
4195            }
4196
4197            // 验证所有 JOIN 都已添加
4198            prop_assert_eq!(builder.joins.len(), join_tables.len());
4199        }
4200    }
4201
4202    // Feature: mysql-query-builder, Property 33: 表别名支持
4203    // 验证需求:17.6
4204    proptest! {
4205        #![proptest_config(ProptestConfig::with_cases(100))]
4206
4207        #[test]
4208        fn prop_table_alias_support(
4209            base_table in table_name_strategy(),
4210            join_table in table_name_strategy(),
4211            base_alias in "[a-z][a-z0-9]{0,5}",
4212            join_alias in "[a-z][a-z0-9]{0,5}"
4213        ) {
4214            prop_assume!(base_table != join_table);
4215            prop_assume!(base_alias != join_alias);
4216
4217            let pool = create_test_pool_sync();
4218
4219            // 构建带别名的表名
4220            let base_table_with_alias = format!("{} AS {}", base_table, base_alias);
4221            let join_table_with_alias = format!("{} AS {}", join_table, join_alias);
4222
4223            // 使用别名构建 ON 条件
4224            let on_condition = format!("{}.id = {}.id", base_alias, join_alias);
4225
4226            // 创建查询构建器,使用带别名的表名
4227            let builder = QueryBuilder::new(&pool, &base_table_with_alias, false)
4228                .field(&format!("{}.id", base_alias))
4229                .field(&format!("{}.name", base_alias))
4230                .join(&join_table_with_alias, &on_condition);
4231
4232            let sql = builder.to_sql();
4233
4234            // 验证 SQL 包含带别名的主表
4235            prop_assert!(sql.contains(&format!("FROM {}", base_table_with_alias)),
4236                "SQL 应该包含带别名的主表: FROM {}", base_table_with_alias);
4237
4238            // 验证 SQL 包含带别名的 JOIN 表
4239            prop_assert!(sql.contains(&join_table_with_alias),
4240                "SQL 应该包含带别名的 JOIN 表: {}", join_table_with_alias);
4241
4242            // 验证 SQL 包含使用别名的 ON 条件
4243            prop_assert!(sql.contains(&on_condition),
4244                "SQL 应该包含使用别名的 ON 条件: {}", on_condition);
4245
4246            // 验证 SQL 包含使用别名的字段选择
4247            prop_assert!(sql.contains(&format!("{}.id", base_alias)),
4248                "SQL 应该包含使用别名的字段: {}.id", base_alias);
4249            prop_assert!(sql.contains(&format!("{}.name", base_alias)),
4250                "SQL 应该包含使用别名的字段: {}.name", base_alias);
4251        }
4252    }
4253
4254    // Feature: mysql-query-builder, Property 20: ORDER BY 子句生成
4255    // 验证需求:8.1
4256    proptest! {
4257        #![proptest_config(ProptestConfig::with_cases(100))]
4258
4259        #[test]
4260        fn prop_order_by_clause_generation(
4261            table_name in table_name_strategy(),
4262            field in field_name_strategy(),
4263            asc in any::<bool>()
4264        ) {
4265            let pool = create_test_pool_sync();
4266            let builder = QueryBuilder::new(&pool, &table_name, false)
4267                .order(&field, asc);
4268
4269            // 验证 ORDER BY 已添加
4270            prop_assert_eq!(builder.order_by.len(), 1);
4271            prop_assert_eq!(&builder.order_by[0].field, &field);
4272            prop_assert_eq!(builder.order_by[0].asc, asc);
4273        }
4274    }
4275
4276    // Feature: mysql-query-builder, Property 21: 多字段排序支持
4277    // 验证需求:8.3
4278    proptest! {
4279        #![proptest_config(ProptestConfig::with_cases(100))]
4280
4281        #[test]
4282        fn prop_multiple_order_by_support(
4283            table_name in table_name_strategy(),
4284            fields in prop::collection::vec(field_name_strategy(), 1..5)
4285        ) {
4286            let pool = create_test_pool_sync();
4287            let mut builder = QueryBuilder::new(&pool, &table_name, false);
4288
4289            // 添加多个排序字段
4290            for field in &fields {
4291                builder = builder.order(field, true);
4292            }
4293
4294            // 验证所有排序字段都已添加
4295            prop_assert_eq!(builder.order_by.len(), fields.len());
4296        }
4297    }
4298
4299    // Feature: mysql-query-builder, Property 22: GROUP BY 子句生成
4300    // 验证需求:8.4
4301    proptest! {
4302        #![proptest_config(ProptestConfig::with_cases(100))]
4303
4304        #[test]
4305        fn prop_group_by_clause_generation(
4306            table_name in table_name_strategy(),
4307            field in field_name_strategy()
4308        ) {
4309            let pool = create_test_pool_sync();
4310            let builder = QueryBuilder::new(&pool, &table_name, false)
4311                .group(&field);
4312
4313            // 验证 GROUP BY 已添加
4314            prop_assert_eq!(builder.group_by.len(), 1);
4315            prop_assert_eq!(&builder.group_by[0], &field);
4316        }
4317    }
4318
4319    // Feature: mysql-query-builder, Property 23: 多字段分组支持
4320    // 验证需求:8.5
4321    proptest! {
4322        #![proptest_config(ProptestConfig::with_cases(100))]
4323
4324        #[test]
4325        fn prop_multiple_group_by_support(
4326            table_name in table_name_strategy(),
4327            fields in prop::collection::vec(field_name_strategy(), 1..5)
4328        ) {
4329            let pool = create_test_pool_sync();
4330            let mut builder = QueryBuilder::new(&pool, &table_name, false);
4331
4332            // 添加多个分组字段
4333            for field in &fields {
4334                builder = builder.group(field);
4335            }
4336
4337            // 验证所有分组字段都已添加
4338            prop_assert_eq!(builder.group_by.len(), fields.len());
4339        }
4340    }
4341
4342    // Feature: mysql-query-builder, Property 30: SQL 语句调试输出
4343    // 验证需求:15.5
4344    proptest! {
4345        #![proptest_config(ProptestConfig::with_cases(100))]
4346
4347        #[test]
4348        fn prop_to_sql_returns_valid_sql(
4349            table_name in table_name_strategy(),
4350            fields in prop::collection::vec(field_name_strategy(), 0..5),
4351            use_distinct in any::<bool>(),
4352            limit_opt in prop::option::of(1u64..100),
4353            offset_opt in prop::option::of(0u64..100)
4354        ) {
4355            let pool = create_test_pool_sync();
4356            let mut builder = QueryBuilder::new(&pool, &table_name, false);
4357
4358            // 添加字段
4359            for field in &fields {
4360                builder = builder.field(field);
4361            }
4362
4363            // 可选的 DISTINCT
4364            if use_distinct {
4365                builder = builder.distinct();
4366            }
4367
4368            // 可选的 LIMIT
4369            if let Some(limit) = limit_opt {
4370                builder = builder.limit(limit);
4371            }
4372
4373            // 可选的 OFFSET
4374            if let Some(offset) = offset_opt {
4375                builder = builder.offset(offset);
4376            }
4377
4378            // 调用 to_sql() 方法
4379            let sql = builder.to_sql();
4380
4381            // 验证返回的 SQL 字符串非空
4382            prop_assert!(!sql.is_empty(), "SQL 字符串不应为空");
4383
4384            // 验证包含基本的 SQL 关键字
4385            prop_assert!(sql.contains("SELECT"), "SQL 应包含 SELECT 关键字");
4386            prop_assert!(sql.contains("FROM"), "SQL 应包含 FROM 关键字");
4387
4388            // 验证包含表名
4389            prop_assert!(sql.contains(&table_name), "SQL 应包含表名");
4390
4391            // 如果使用了 DISTINCT,验证包含 DISTINCT 关键字
4392            if use_distinct {
4393                prop_assert!(sql.contains("DISTINCT"), "SQL 应包含 DISTINCT 关键字");
4394            }
4395
4396            // 如果设置了 LIMIT,验证包含 LIMIT 子句
4397            if let Some(limit) = limit_opt {
4398                prop_assert!(sql.contains("LIMIT"), "SQL 应包含 LIMIT 关键字");
4399                prop_assert!(sql.contains(&limit.to_string()), "SQL 应包含 LIMIT 值");
4400            }
4401
4402            // 如果设置了 OFFSET,验证包含 OFFSET 子句
4403            if let Some(offset) = offset_opt {
4404                prop_assert!(sql.contains("OFFSET"), "SQL 应包含 OFFSET 关键字");
4405                prop_assert!(sql.contains(&offset.to_string()), "SQL 应包含 OFFSET 值");
4406            }
4407
4408            // 验证字段在 SQL 中
4409            if !fields.is_empty() {
4410                for field in &fields {
4411                    prop_assert!(sql.contains(field), "SQL 应包含字段 {}", field);
4412                }
4413            } else {
4414                // 如果没有指定字段,应该使用 SELECT *
4415                prop_assert!(sql.contains("*"), "SQL 应包含 * 表示所有字段");
4416            }
4417        }
4418
4419        #[test]
4420        fn prop_to_sql_with_conditions(
4421            table_name in table_name_strategy(),
4422            field in field_name_strategy(),
4423            value in any::<i32>()
4424        ) {
4425            let pool = create_test_pool_sync();
4426            let builder = QueryBuilder::new(&pool, &table_name, false)
4427                .where_and_unchecked(&field, "=", value);
4428
4429            let sql = builder.to_sql();
4430
4431            // 验证基本 SQL 结构
4432            prop_assert!(!sql.is_empty());
4433            prop_assert!(sql.contains("SELECT"));
4434            prop_assert!(sql.contains("FROM"));
4435            prop_assert!(sql.contains(&table_name));
4436
4437            // 验证包含 WHERE 子句
4438            prop_assert!(sql.contains("WHERE"), "SQL 应包含 WHERE 关键字");
4439        }
4440
4441        #[test]
4442        fn prop_to_sql_with_joins(
4443            table_name in table_name_strategy(),
4444            join_table in table_name_strategy(),
4445            on_field1 in field_name_strategy(),
4446            on_field2 in field_name_strategy()
4447        ) {
4448            let pool = create_test_pool_sync();
4449            let on_condition = format!("{}.{} = {}.{}", table_name, on_field1, join_table, on_field2);
4450            let builder = QueryBuilder::new(&pool, &table_name, false)
4451                .join(&join_table, &on_condition);
4452
4453            let sql = builder.to_sql();
4454
4455            // 验证基本 SQL 结构
4456            prop_assert!(!sql.is_empty());
4457            prop_assert!(sql.contains("SELECT"));
4458            prop_assert!(sql.contains("FROM"));
4459
4460            // 验证包含 JOIN 子句
4461            prop_assert!(sql.contains("JOIN"), "SQL 应包含 JOIN 关键字");
4462            prop_assert!(sql.contains(&join_table), "SQL 应包含连接的表名");
4463        }
4464
4465        #[test]
4466        fn prop_to_sql_with_order_and_group(
4467            table_name in table_name_strategy(),
4468            order_field in field_name_strategy(),
4469            group_field in field_name_strategy(),
4470            asc in any::<bool>()
4471        ) {
4472            let pool = create_test_pool_sync();
4473            let builder = QueryBuilder::new(&pool, &table_name, false)
4474                .order(&order_field, asc)
4475                .group(&group_field);
4476
4477            let sql = builder.to_sql();
4478
4479            // 验证基本 SQL 结构
4480            prop_assert!(!sql.is_empty());
4481            prop_assert!(sql.contains("SELECT"));
4482            prop_assert!(sql.contains("FROM"));
4483
4484            // 验证包含 ORDER BY 和 GROUP BY 子句
4485            prop_assert!(sql.contains("ORDER BY"), "SQL 应包含 ORDER BY 关键字");
4486            prop_assert!(sql.contains("GROUP BY"), "SQL 应包含 GROUP BY 关键字");
4487            prop_assert!(sql.contains(&order_field), "SQL 应包含排序字段");
4488            prop_assert!(sql.contains(&group_field), "SQL 应包含分组字段");
4489        }
4490
4491        #[test]
4492        fn prop_to_sql_complex_query(
4493            table_name in table_name_strategy(),
4494            fields in prop::collection::vec(field_name_strategy(), 1..3),
4495            join_table in table_name_strategy(),
4496            where_field in field_name_strategy(),
4497            order_field in field_name_strategy(),
4498            group_field in field_name_strategy()
4499        ) {
4500            let pool = create_test_pool_sync();
4501            let mut builder = QueryBuilder::new(&pool, &table_name, false);
4502
4503            // 添加字段
4504            for field in &fields {
4505                builder = builder.field(field);
4506            }
4507
4508            // 添加 JOIN
4509            let on_condition = format!("{}.id = {}.id", table_name, join_table);
4510            builder = builder.join(&join_table, &on_condition);
4511
4512            // 添加 WHERE 条件
4513            builder = builder.where_and_unchecked(&where_field, "=", 1);
4514
4515            // 添加 ORDER BY
4516            builder = builder.order(&order_field, true);
4517
4518            // 添加 GROUP BY
4519            builder = builder.group(&group_field);
4520
4521            // 添加 LIMIT
4522            builder = builder.limit(10);
4523
4524            let sql = builder.to_sql();
4525
4526            // 验证这是一个有效的复杂 SQL 查询
4527            prop_assert!(!sql.is_empty());
4528            prop_assert!(sql.contains("SELECT"));
4529            prop_assert!(sql.contains("FROM"));
4530            prop_assert!(sql.contains(&table_name));
4531            prop_assert!(sql.contains("JOIN"));
4532            prop_assert!(sql.contains("WHERE"));
4533            prop_assert!(sql.contains("ORDER BY"));
4534            prop_assert!(sql.contains("GROUP BY"));
4535            prop_assert!(sql.contains("LIMIT"));
4536
4537            // 验证 SQL 子句的顺序正确(SQL 标准顺序)
4538            let select_pos = sql.find("SELECT").unwrap();
4539            let from_pos = sql.find("FROM").unwrap();
4540            let join_pos = sql.find("JOIN").unwrap();
4541            let where_pos = sql.find("WHERE").unwrap();
4542            let group_pos = sql.find("GROUP BY").unwrap();
4543            let order_pos = sql.find("ORDER BY").unwrap();
4544            let limit_pos = sql.find("LIMIT").unwrap();
4545
4546            // 验证子句顺序:SELECT < FROM < JOIN < WHERE < GROUP BY < ORDER BY < LIMIT
4547            prop_assert!(select_pos < from_pos, "SELECT 应在 FROM 之前");
4548            prop_assert!(from_pos < join_pos, "FROM 应在 JOIN 之前");
4549            prop_assert!(join_pos < where_pos, "JOIN 应在 WHERE 之前");
4550            prop_assert!(where_pos < group_pos, "WHERE 应在 GROUP BY 之前");
4551            prop_assert!(group_pos < order_pos, "GROUP BY 应在 ORDER BY 之前");
4552            prop_assert!(order_pos < limit_pos, "ORDER BY 应在 LIMIT 之前");
4553        }
4554    }
4555
4556    // Feature: mysql-query-builder, Property 3: SQL 注入防护
4557    // 验证需求:2.5
4558    proptest! {
4559        #![proptest_config(ProptestConfig::with_cases(100))]
4560
4561        #[test]
4562        fn prop_sql_injection_prevention_single_quote(
4563            table_name in table_name_strategy(),
4564            field in field_name_strategy(),
4565            malicious_input in ".*'.*"
4566        ) {
4567            let pool = create_test_pool_sync();
4568            let builder = QueryBuilder::new(&pool, &table_name, false)
4569                .where_and_unchecked(&field, "=", malicious_input.as_str());
4570
4571            let sql = builder.to_sql();
4572
4573            // SQL 不应该直接包含恶意输入的单引号
4574            // 参数化查询应该使用 ? 占位符
4575            prop_assert!(sql.contains("?"), "SQL 应该使用参数化查询(? 占位符)");
4576
4577            // SQL 中不应该直接出现用户输入的单引号
4578            // 注意:SQL 本身可能包含单引号(如 'table'),但不应该是用户输入的
4579            let where_clause = sql.split("WHERE").nth(1).unwrap_or("");
4580            prop_assert!(!where_clause.contains(&malicious_input),
4581                "WHERE 子句不应该直接包含用户输入的恶意字符串");
4582        }
4583
4584        #[test]
4585        fn prop_sql_injection_prevention_semicolon(
4586            table_name in table_name_strategy(),
4587            field in field_name_strategy(),
4588            malicious_input in ".*;.*"
4589        ) {
4590            let pool = create_test_pool_sync();
4591            let builder = QueryBuilder::new(&pool, &table_name, false)
4592                .where_and_unchecked(&field, "=", malicious_input.as_str());
4593
4594            let sql = builder.to_sql();
4595
4596            // 验证使用参数化查询
4597            prop_assert!(sql.contains("?"), "SQL 应该使用参数化查询");
4598
4599            // SQL 中不应该直接出现用户输入的分号
4600            let where_clause = sql.split("WHERE").nth(1).unwrap_or("");
4601            prop_assert!(!where_clause.contains(&malicious_input),
4602                "WHERE 子句不应该直接包含用户输入的恶意字符串");
4603        }
4604
4605        #[test]
4606        fn prop_sql_injection_prevention_comment(
4607            table_name in table_name_strategy(),
4608            field in field_name_strategy(),
4609            malicious_input in ".*--.*"
4610        ) {
4611            let pool = create_test_pool_sync();
4612            let builder = QueryBuilder::new(&pool, &table_name, false)
4613                .where_and_unchecked(&field, "=", malicious_input.as_str());
4614
4615            let sql = builder.to_sql();
4616
4617            // 验证使用参数化查询
4618            prop_assert!(sql.contains("?"), "SQL 应该使用参数化查询");
4619
4620            // SQL 中不应该直接出现用户输入的注释符
4621            let where_clause = sql.split("WHERE").nth(1).unwrap_or("");
4622            prop_assert!(!where_clause.contains(&malicious_input),
4623                "WHERE 子句不应该直接包含用户输入的恶意字符串");
4624        }
4625
4626        #[test]
4627        fn prop_sql_injection_prevention_drop_table(
4628            table_name in table_name_strategy(),
4629            field in field_name_strategy()
4630        ) {
4631            let pool = create_test_pool_sync();
4632            let malicious_input = "'; DROP TABLE users; --";
4633            let builder = QueryBuilder::new(&pool, &table_name, false)
4634                .where_and_unchecked(&field, "=", malicious_input);
4635
4636            let sql = builder.to_sql();
4637
4638            // 验证使用参数化查询
4639            prop_assert!(sql.contains("?"), "SQL 应该使用参数化查询");
4640
4641            // SQL 不应该包含 DROP TABLE 语句
4642            prop_assert!(!sql.to_uppercase().contains("DROP TABLE"),
4643                "SQL 不应该包含 DROP TABLE 语句");
4644
4645            // WHERE 子句不应该直接包含恶意输入
4646            let where_clause = sql.split("WHERE").nth(1).unwrap_or("");
4647            prop_assert!(!where_clause.contains(malicious_input),
4648                "WHERE 子句不应该直接包含用户输入的恶意字符串");
4649        }
4650
4651        #[test]
4652        fn prop_sql_injection_prevention_union_select(
4653            table_name in table_name_strategy(),
4654            field in field_name_strategy()
4655        ) {
4656            let pool = create_test_pool_sync();
4657            let malicious_input = "' UNION SELECT * FROM passwords --";
4658            let builder = QueryBuilder::new(&pool, &table_name, false)
4659                .where_and_unchecked(&field, "=", malicious_input);
4660
4661            let sql = builder.to_sql();
4662
4663            // 验证使用参数化查询
4664            prop_assert!(sql.contains("?"), "SQL 应该使用参数化查询");
4665
4666            // SQL 不应该包含 UNION SELECT 注入
4667            let sql_upper = sql.to_uppercase();
4668            let union_count = sql_upper.matches("UNION").count();
4669            prop_assert_eq!(union_count, 0, "SQL 不应该包含 UNION 注入");
4670
4671            // WHERE 子句不应该直接包含恶意输入
4672            let where_clause = sql.split("WHERE").nth(1).unwrap_or("");
4673            prop_assert!(!where_clause.contains(malicious_input),
4674                "WHERE 子句不应该直接包含用户输入的恶意字符串");
4675        }
4676
4677        #[test]
4678        fn prop_sql_injection_prevention_or_always_true(
4679            table_name in table_name_strategy(),
4680            field in field_name_strategy()
4681        ) {
4682            let pool = create_test_pool_sync();
4683            let malicious_input = "' OR '1'='1";
4684            let builder = QueryBuilder::new(&pool, &table_name, false)
4685                .where_and_unchecked(&field, "=", malicious_input);
4686
4687            let sql = builder.to_sql();
4688
4689            // 验证使用参数化查询
4690            prop_assert!(sql.contains("?"), "SQL 应该使用参数化查询");
4691
4692            // WHERE 子句不应该直接包含恶意输入
4693            let where_clause = sql.split("WHERE").nth(1).unwrap_or("");
4694            prop_assert!(!where_clause.contains(malicious_input),
4695                "WHERE 子句不应该直接包含用户输入的恶意字符串");
4696
4697            // 验证不会产生永真条件(除了我们自己构建的条件)
4698            // 恶意输入应该被当作参数值,而不是 SQL 代码
4699            let or_count = where_clause.matches(" OR ").count();
4700            // 如果没有使用 where_or,就不应该有 OR
4701            prop_assert_eq!(or_count, 0, "不应该因为用户输入而产生 OR 条件");
4702        }
4703
4704        #[test]
4705        fn prop_sql_injection_prevention_multiple_special_chars(
4706            table_name in table_name_strategy(),
4707            field in field_name_strategy(),
4708            malicious_input in "[a-z0-9]*[';\"\\-][a-z0-9]*[';\"\\-][a-z0-9]*"
4709        ) {
4710            let pool = create_test_pool_sync();
4711            let builder = QueryBuilder::new(&pool, &table_name, false)
4712                .where_and_unchecked(&field, "=", malicious_input.as_str());
4713
4714            let sql = builder.to_sql();
4715
4716            // 验证使用参数化查询
4717            prop_assert!(sql.contains("?"), "SQL 应该使用参数化查询");
4718
4719            // WHERE 子句不应该直接包含恶意输入
4720            let where_clause = sql.split("WHERE").nth(1).unwrap_or("");
4721            prop_assert!(!where_clause.contains(&malicious_input),
4722                "WHERE 子句不应该直接包含用户输入的恶意字符串");
4723        }
4724
4725        #[test]
4726        fn prop_sql_injection_prevention_in_operator(
4727            table_name in table_name_strategy(),
4728            field in field_name_strategy(),
4729            malicious_values in prop::collection::vec(".*[';].*", 1..5)
4730        ) {
4731            let pool = create_test_pool_sync();
4732            let builder = QueryBuilder::new(&pool, &table_name, false)
4733                .where_in(&field, malicious_values.clone());
4734
4735            let sql = builder.to_sql();
4736
4737            // 验证使用参数化查询
4738            prop_assert!(sql.contains("IN"), "SQL 应该包含 IN 操作符");
4739            prop_assert!(sql.contains("?"), "SQL 应该使用参数化查询");
4740
4741            // 验证每个值都有对应的占位符
4742            let placeholder_count = sql.matches("?").count();
4743            prop_assert!(placeholder_count >= malicious_values.len(),
4744                "每个 IN 值都应该有对应的参数占位符");
4745
4746            // WHERE 子句不应该直接包含恶意输入
4747            for malicious_value in &malicious_values {
4748                let where_clause = sql.split("WHERE").nth(1).unwrap_or("");
4749                prop_assert!(!where_clause.contains(malicious_value),
4750                    "WHERE 子句不应该直接包含用户输入的恶意字符串");
4751            }
4752        }
4753
4754        #[test]
4755        fn prop_sql_injection_prevention_like_operator(
4756            table_name in table_name_strategy(),
4757            field in field_name_strategy(),
4758            malicious_pattern in ".*[';].*"
4759        ) {
4760            let pool = create_test_pool_sync();
4761            let builder = QueryBuilder::new(&pool, &table_name, false)
4762                .where_and_unchecked(&field, "like", malicious_pattern.as_str());
4763
4764            let sql = builder.to_sql();
4765
4766            // 验证使用参数化查询
4767            prop_assert!(sql.contains("LIKE"), "SQL 应该包含 LIKE 操作符");
4768            prop_assert!(sql.contains("?"), "SQL 应该使用参数化查询");
4769
4770            // WHERE 子句不应该直接包含恶意输入
4771            let where_clause = sql.split("WHERE").nth(1).unwrap_or("");
4772            prop_assert!(!where_clause.contains(&malicious_pattern),
4773                "WHERE 子句不应该直接包含用户输入的恶意字符串");
4774        }
4775
4776        #[test]
4777        fn prop_sql_injection_prevention_between_operator(
4778            table_name in table_name_strategy(),
4779            field in field_name_strategy(),
4780            malicious_start in ".*[';].*",
4781            malicious_end in ".*[';].*"
4782        ) {
4783            let pool = create_test_pool_sync();
4784            let builder = QueryBuilder::new(&pool, &table_name, false)
4785                .where_between(&field, malicious_start.as_str(), malicious_end.as_str());
4786
4787            let sql = builder.to_sql();
4788
4789            // 验证使用参数化查询
4790            prop_assert!(sql.contains("BETWEEN"), "SQL 应该包含 BETWEEN 操作符");
4791            prop_assert!(sql.contains("?"), "SQL 应该使用参数化查询");
4792
4793            // 验证有两个占位符(start 和 end)
4794            let where_clause = sql.split("WHERE").nth(1).unwrap_or("");
4795            let placeholder_count = where_clause.matches("?").count();
4796            prop_assert!(placeholder_count >= 2, "BETWEEN 应该有两个参数占位符");
4797
4798            // WHERE 子句不应该直接包含恶意输入
4799            prop_assert!(!where_clause.contains(&malicious_start),
4800                "WHERE 子句不应该直接包含用户输入的恶意字符串");
4801            prop_assert!(!where_clause.contains(&malicious_end),
4802                "WHERE 子句不应该直接包含用户输入的恶意字符串");
4803        }
4804    }
4805
4806    // Feature: mysql-query-builder, Property 10: LIMIT 1 用于 find()
4807    // 验证需求:4.1
4808    proptest! {
4809        #![proptest_config(ProptestConfig::with_cases(100))]
4810
4811        #[test]
4812        fn prop_find_adds_limit_one(
4813            table_name in table_name_strategy(),
4814            field in field_name_strategy(),
4815            value in any::<i32>()
4816        ) {
4817            let pool = create_test_pool_sync();
4818
4819            // 创建一个带 WHERE 条件的查询构建器
4820            let builder = QueryBuilder::new(&pool, &table_name, false)
4821                .field(&field)
4822                .where_and_unchecked(&field, "=", value)
4823                .limit(1); // 模拟 find() 会添加的 LIMIT 1
4824
4825            let sql = builder.to_sql();
4826
4827            // 验证 SQL 包含 LIMIT 1
4828            prop_assert!(sql.contains("LIMIT 1"),
4829                "find() 方法应该自动添加 LIMIT 1 到查询中");
4830        }
4831    }
4832
4833    // Feature: mysql-query-builder, Property 11: COUNT 聚合函数
4834    // 验证需求:4.4
4835    //
4836    // 属性:对于任意查询构建器,调用 count() 方法时,生成的 SQL 应该包含 COUNT(*) 或 COUNT(field)
4837    //
4838    // 此测试验证 count() 方法正确生成 COUNT 聚合函数的 SQL 语句。
4839    // count() 方法内部使用 value("COUNT(*)") 来实现,因此我们测试生成的 SQL 是否包含 COUNT。
4840    proptest! {
4841        #![proptest_config(ProptestConfig::with_cases(100))]
4842
4843        #[test]
4844        fn prop_count_aggregation_function(
4845            table_name in table_name_strategy()
4846        ) {
4847            let pool = create_test_pool_sync();
4848
4849            // 创建一个查询构建器并使用 field("COUNT(*)") 模拟 count() 方法的行为
4850            // count() 方法内部调用 value("COUNT(*)"),这等同于 field("COUNT(*)")
4851            let builder = QueryBuilder::new(&pool, &table_name, false)
4852                .field("COUNT(*)");
4853
4854            let sql = builder.to_sql();
4855
4856            // 验证 SQL 包含 COUNT(*) 或 COUNT(field)
4857            prop_assert!(
4858                sql.contains("COUNT(*)") || sql.contains("COUNT("),
4859                "count() 方法应该生成包含 COUNT(*) 或 COUNT(field) 的 SQL 语句,实际 SQL: {}",
4860                sql
4861            );
4862
4863            // 验证 SQL 包含 SELECT 关键字
4864            prop_assert!(
4865                sql.to_uppercase().contains("SELECT"),
4866                "count() 方法应该生成 SELECT 语句,实际 SQL: {}",
4867                sql
4868            );
4869
4870            // 验证 SQL 包含表名
4871            prop_assert!(
4872                sql.contains(&format!("FROM {}", table_name)),
4873                "count() 方法应该包含正确的表名,实际 SQL: {}",
4874                sql
4875            );
4876        }
4877    }
4878
4879    // Feature: mysql-query-builder, Property 11: COUNT 聚合函数 - 带条件
4880    // 验证需求:4.4
4881    //
4882    // 属性:对于任意带 WHERE 条件的查询构建器,调用 count() 方法时,
4883    // 生成的 SQL 应该包含 COUNT(*) 和 WHERE 子句
4884    //
4885    // 此测试验证 count() 方法与 WHERE 条件的组合使用。
4886    proptest! {
4887        #![proptest_config(ProptestConfig::with_cases(100))]
4888
4889        #[test]
4890        fn prop_count_with_where_condition(
4891            table_name in table_name_strategy(),
4892            field_name in field_name_strategy(),
4893            field_value in 1i32..1000i32,
4894        ) {
4895            let pool = create_test_pool_sync();
4896
4897            // 创建带条件的查询构建器
4898            let builder = QueryBuilder::new(&pool, &table_name, false)
4899                .where_and_unchecked(&field_name, "=", field_value)
4900                .field("COUNT(*)");
4901
4902            let sql = builder.to_sql();
4903
4904            // 验证 SQL 包含 COUNT(*)
4905            prop_assert!(
4906                sql.contains("COUNT(*)"),
4907                "带条件的 count() 查询应该包含 COUNT(*),实际 SQL: {}",
4908                sql
4909            );
4910
4911            // 验证 SQL 包含 WHERE 子句
4912            prop_assert!(
4913                sql.to_uppercase().contains("WHERE"),
4914                "带条件的 count() 查询应该包含 WHERE 子句,实际 SQL: {}",
4915                sql
4916            );
4917
4918            // 验证 SQL 包含表名
4919            prop_assert!(
4920                sql.contains(&format!("FROM {}", table_name)),
4921                "count() 方法应该包含正确的表名,实际 SQL: {}",
4922                sql
4923            );
4924        }
4925    }
4926
4927    // Feature: mysql-query-builder, Property 11: COUNT 聚合函数 - 特定字段
4928    // 验证需求:4.4
4929    //
4930    // 属性:对于任意查询构建器,使用 field("COUNT(field_name)") 时,
4931    // 生成的 SQL 应该包含 COUNT(field_name)
4932    //
4933    // 此测试验证对特定字段进行 COUNT 统计的功能。
4934    proptest! {
4935        #![proptest_config(ProptestConfig::with_cases(100))]
4936
4937        #[test]
4938        fn prop_count_specific_field(
4939            table_name in table_name_strategy(),
4940            field_name in field_name_strategy(),
4941        ) {
4942            let pool = create_test_pool_sync();
4943
4944            // 创建查询构建器,统计特定字段
4945            let count_expr = format!("COUNT({})", field_name);
4946            let builder = QueryBuilder::new(&pool, &table_name, false)
4947                .field(&count_expr);
4948
4949            let sql = builder.to_sql();
4950
4951            // 验证 SQL 包含 COUNT(field_name)
4952            prop_assert!(
4953                sql.contains(&count_expr),
4954                "COUNT 特定字段应该包含 COUNT(field_name),实际 SQL: {}",
4955                sql
4956            );
4957
4958            // 验证 SQL 包含 SELECT 关键字
4959            prop_assert!(
4960                sql.to_uppercase().contains("SELECT"),
4961                "COUNT 查询应该是 SELECT 语句,实际 SQL: {}",
4962                sql
4963            );
4964
4965            // 验证 SQL 包含表名
4966            prop_assert!(
4967                sql.contains(&format!("FROM {}", table_name)),
4968                "COUNT 查询应该包含正确的表名,实际 SQL: {}",
4969                sql
4970            );
4971        }
4972    }
4973
4974    // Feature: mysql-query-builder, Property 12: SUM 聚合函数
4975    // 验证需求:4.5
4976    //
4977    // 属性:对于任意字段名,调用 sum(field) 方法时,生成的 SQL 应该包含 SUM(field)
4978    //
4979    // 此测试验证 sum() 方法正确生成 SUM 聚合函数的 SQL 语句。
4980    // sum() 方法内部使用 CAST(SUM(field) AS DOUBLE) 来统一返回类型。
4981    proptest! {
4982        #![proptest_config(ProptestConfig::with_cases(100))]
4983
4984        #[test]
4985        fn prop_sum_aggregation_function(
4986            table_name in table_name_strategy(),
4987            field in field_name_strategy()
4988        ) {
4989            let pool = create_test_pool_sync();
4990
4991            // 创建一个查询构建器并生成 SUM 查询的 SQL
4992            // 模拟 sum() 方法会生成的 SQL
4993            let sum_expr = format!("CAST(SUM({}) AS DOUBLE)", field);
4994            let builder = QueryBuilder::new(&pool, &table_name, false)
4995                .field(&sum_expr);
4996
4997            let sql = builder.to_sql();
4998
4999            // 验证 SQL 包含 SUM(field)
5000            prop_assert!(
5001                sql.contains("SUM("),
5002                "sum() 方法应该生成包含 SUM(field) 的 SQL 语句,实际 SQL: {}",
5003                sql
5004            );
5005
5006            // 验证 SQL 包含字段名
5007            prop_assert!(
5008                sql.contains(&field),
5009                "sum() 方法生成的 SQL 应该包含指定的字段名 {},实际 SQL: {}",
5010                field,
5011                sql
5012            );
5013
5014            // 验证 SQL 包含 SELECT 关键字
5015            prop_assert!(
5016                sql.to_uppercase().contains("SELECT"),
5017                "sum() 方法应该生成 SELECT 语句,实际 SQL: {}",
5018                sql
5019            );
5020
5021            // 验证 SQL 包含表名
5022            prop_assert!(
5023                sql.contains(&format!("FROM {}", table_name)),
5024                "sum() 方法应该包含正确的表名,实际 SQL: {}",
5025                sql
5026            );
5027
5028            // 验证 SQL 包含 CAST 转换(sum() 方法的实现细节)
5029            prop_assert!(
5030                sql.to_uppercase().contains("CAST"),
5031                "sum() 方法应该使用 CAST 转换结果为 DOUBLE,实际 SQL: {}",
5032                sql
5033            );
5034        }
5035    }
5036
5037    // Feature: mysql-query-builder, Property 12: SUM 聚合函数 - 带条件
5038    // 验证需求:4.5
5039    //
5040    // 属性:对于任意带 WHERE 条件的查询构建器,调用 sum(field) 方法时,
5041    // 生成的 SQL 应该包含 SUM(field) 和 WHERE 子句
5042    //
5043    // 此测试验证 sum() 方法与 WHERE 条件的组合使用。
5044    proptest! {
5045        #![proptest_config(ProptestConfig::with_cases(100))]
5046
5047        #[test]
5048        fn prop_sum_with_where_condition(
5049            table_name in table_name_strategy(),
5050            sum_field in field_name_strategy(),
5051            where_field in field_name_strategy(),
5052            where_value in 1i32..1000i32,
5053        ) {
5054            // 确保两个字段名不同
5055            prop_assume!(sum_field != where_field);
5056
5057            let pool = create_test_pool_sync();
5058
5059            // 创建带条件的查询构建器
5060            let sum_expr = format!("CAST(SUM({}) AS DOUBLE)", sum_field);
5061            let builder = QueryBuilder::new(&pool, &table_name, false)
5062                .where_and_unchecked(&where_field, "=", where_value)
5063                .field(&sum_expr);
5064
5065            let sql = builder.to_sql();
5066
5067            // 验证 SQL 包含 SUM(field)
5068            prop_assert!(
5069                sql.contains("SUM("),
5070                "带条件的 sum() 查询应该包含 SUM(field),实际 SQL: {}",
5071                sql
5072            );
5073
5074            // 验证 SQL 包含求和字段名
5075            prop_assert!(
5076                sql.contains(&sum_field),
5077                "sum() 方法应该包含求和字段名 {},实际 SQL: {}",
5078                sum_field,
5079                sql
5080            );
5081
5082            // 验证 SQL 包含 WHERE 子句
5083            prop_assert!(
5084                sql.to_uppercase().contains("WHERE"),
5085                "带条件的 sum() 查询应该包含 WHERE 子句,实际 SQL: {}",
5086                sql
5087            );
5088
5089            // 验证 SQL 包含表名
5090            prop_assert!(
5091                sql.contains(&format!("FROM {}", table_name)),
5092                "sum() 方法应该包含正确的表名,实际 SQL: {}",
5093                sql
5094            );
5095        }
5096    }
5097
5098    // Feature: mysql-query-builder, Property 12: SUM 聚合函数 - 多条件
5099    // 验证需求:4.5
5100    //
5101    // 属性:对于任意带多个 WHERE 条件的查询构建器,调用 sum(field) 方法时,
5102    // 生成的 SQL 应该正确包含所有条件
5103    //
5104    // 此测试验证 sum() 方法在复杂查询中的正确性。
5105    proptest! {
5106        #![proptest_config(ProptestConfig::with_cases(100))]
5107
5108        #[test]
5109        fn prop_sum_with_multiple_conditions(
5110            table_name in table_name_strategy(),
5111            sum_field in field_name_strategy(),
5112            where_field1 in field_name_strategy(),
5113            where_field2 in field_name_strategy(),
5114            value1 in 1i32..1000i32,
5115            value2 in 1i32..1000i32,
5116        ) {
5117            // 确保字段名都不同
5118            prop_assume!(sum_field != where_field1);
5119            prop_assume!(sum_field != where_field2);
5120            prop_assume!(where_field1 != where_field2);
5121
5122            let pool = create_test_pool_sync();
5123
5124            // 创建带多个条件的查询构建器
5125            let sum_expr = format!("CAST(SUM({}) AS DOUBLE)", sum_field);
5126            let builder = QueryBuilder::new(&pool, &table_name, false)
5127                .where_and_unchecked(&where_field1, "=", value1)
5128                .where_and_unchecked(&where_field2, ">", value2)
5129                .field(&sum_expr);
5130
5131            let sql = builder.to_sql();
5132
5133            // 验证 SQL 包含 SUM(field)
5134            prop_assert!(
5135                sql.contains("SUM("),
5136                "多条件 sum() 查询应该包含 SUM(field),实际 SQL: {}",
5137                sql
5138            );
5139
5140            // 验证 SQL 包含求和字段名
5141            prop_assert!(
5142                sql.contains(&sum_field),
5143                "sum() 方法应该包含求和字段名 {},实际 SQL: {}",
5144                sum_field,
5145                sql
5146            );
5147
5148            // 验证 SQL 包含 WHERE 子句
5149            prop_assert!(
5150                sql.to_uppercase().contains("WHERE"),
5151                "多条件查询应该包含 WHERE 子句,实际 SQL: {}",
5152                sql
5153            );
5154
5155            // 验证 SQL 包含 AND 连接符(因为使用了两次 where_and)
5156            prop_assert!(
5157                sql.to_uppercase().contains(" AND "),
5158                "多个 where_and 条件应该用 AND 连接,实际 SQL: {}",
5159                sql
5160            );
5161        }
5162    }
5163
5164    // ==================== 任务 5.7:属性测试 P2 - 不支持操作符返回错误 ====================
5165
5166    // **Validates: Requirements 3.1**
5167    // 属性 P2:对于任意不在支持集合 {=, !=, >, <, >=, <=, like, LIKE} 中的操作符字符串,
5168    // where_and 必须返回 Err(DbError::UnsupportedOperator(_))
5169    proptest! {
5170        #![proptest_config(ProptestConfig::with_cases(200))]
5171
5172        #[test]
5173        fn prop_unsupported_operator_returns_error(
5174            // 生成不在支持集合中的操作符字符串
5175            // 排除所有支持的操作符:=, !=, >, <, >=, <=, like, LIKE
5176            op in "[a-zA-Z0-9!@#$%^&*]{1,10}"
5177        ) {
5178            // 过滤掉支持的操作符
5179            let supported = ["=", "!=", ">", "<", ">=", "<=", "like", "LIKE"];
5180            prop_assume!(!supported.contains(&op.as_str()));
5181
5182            let pool = create_test_pool_sync();
5183            let builder = QueryBuilder::new(&pool, "users", false);
5184
5185            // 调用 where_and 并验证返回 Err(DbError::UnsupportedOperator)
5186            let result = builder.where_and("field", &op, 1i64);
5187
5188            prop_assert!(
5189                matches!(result, Err(crate::DbError::UnsupportedOperator(_))),
5190                "不支持的操作符 '{}' 应该返回 Err(DbError::UnsupportedOperator),实际结果: {:?}",
5191                op,
5192                result.map(|_| "Ok")
5193            );
5194        }
5195    }
5196
5197    // ==================== 任务 5.8:单元测试 - 已支持操作符的现有行为不变 ====================
5198
5199    #[test]
5200    fn test_where_and_supported_operators_eq() {
5201        // 验证需求: 5.8  支持的操作符 = 行为不变
5202        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5203        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5204        let result = QueryBuilder::new(pool, "users", false)
5205            .where_and("age", "=", 18i64);
5206        assert!(result.is_ok(), "操作符 '=' 应该返回 Ok");
5207        let builder = result.unwrap();
5208        assert_eq!(builder.conditions.len(), 1);
5209    }
5210
5211    #[test]
5212    fn test_where_and_supported_operators_ne() {
5213        // 验证需求: 5.8  支持的操作符 != 行为不变
5214        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5215        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5216        let result = QueryBuilder::new(pool, "users", false)
5217            .where_and("status", "!=", 0i64);
5218        assert!(result.is_ok(), "操作符 '!=' 应该返回 Ok");
5219    }
5220
5221    #[test]
5222    fn test_where_and_supported_operators_gt() {
5223        // 验证需求: 5.8  支持的操作符 > 行为不变
5224        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5225        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5226        let result = QueryBuilder::new(pool, "users", false)
5227            .where_and("age", ">", 18i64);
5228        assert!(result.is_ok(), "操作符 '>' 应该返回 Ok");
5229    }
5230
5231    #[test]
5232    fn test_where_and_supported_operators_lt() {
5233        // 验证需求: 5.8  支持的操作符 < 行为不变
5234        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5235        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5236        let result = QueryBuilder::new(pool, "users", false)
5237            .where_and("age", "<", 65i64);
5238        assert!(result.is_ok(), "操作符 '<' 应该返回 Ok");
5239    }
5240
5241    #[test]
5242    fn test_where_and_supported_operators_gte() {
5243        // 验证需求: 5.8  支持的操作符 >= 行为不变
5244        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5245        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5246        let result = QueryBuilder::new(pool, "users", false)
5247            .where_and("score", ">=", 60i64);
5248        assert!(result.is_ok(), "操作符 '>=' 应该返回 Ok");
5249    }
5250
5251    #[test]
5252    fn test_where_and_supported_operators_lte() {
5253        // 验证需求: 5.8  支持的操作符 <= 行为不变
5254        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5255        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5256        let result = QueryBuilder::new(pool, "users", false)
5257            .where_and("score", "<=", 100i64);
5258        assert!(result.is_ok(), "操作符 '<=' 应该返回 Ok");
5259    }
5260
5261    #[test]
5262    fn test_where_and_supported_operators_like_lowercase() {
5263        // 验证需求: 5.8  支持的操作符 like(小写)行为不变
5264        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5265        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5266        let result = QueryBuilder::new(pool, "users", false)
5267            .where_and("name", "like", "%test%");
5268        assert!(result.is_ok(), "操作符 'like' 应该返回 Ok");
5269    }
5270
5271    #[test]
5272    fn test_where_and_supported_operators_like_uppercase() {
5273        // 验证需求: 5.8  支持的操作符 LIKE(大写)行为不变
5274        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5275        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5276        let result = QueryBuilder::new(pool, "users", false)
5277            .where_and("name", "LIKE", "%test%");
5278        assert!(result.is_ok(), "操作符 'LIKE' 应该返回 Ok");
5279    }
5280
5281    #[test]
5282    fn test_where_and_unsupported_operator_returns_error() {
5283        // 验证需求: 5.1  不支持的操作符返回 Err(DbError::UnsupportedOperator)
5284        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5285        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5286        let result = QueryBuilder::new(pool, "users", false)
5287            .where_and("age", "BETWEEN", 18i64);
5288        assert!(
5289            matches!(result, Err(crate::DbError::UnsupportedOperator(_))),
5290            "不支持的操作符 'BETWEEN' 应该返回 Err(DbError::UnsupportedOperator)"
5291        );
5292    }
5293
5294    #[test]
5295    fn test_where_and_unsupported_operator_error_message() {
5296        // 验证需求: 5.1  错误消息包含操作符名称
5297        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5298        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5299        let result = QueryBuilder::new(pool, "users", false)
5300            .where_and("age", "XOR", 1i64);
5301        match result {
5302            Err(crate::DbError::UnsupportedOperator(op)) => {
5303                assert_eq!(op, "XOR", "错误消息应该包含操作符名称");
5304            }
5305            _ => panic!("应该返回 UnsupportedOperator 错误"),
5306        }
5307    }
5308
5309    #[test]
5310    fn test_where_or_unsupported_operator_returns_error() {
5311        // 验证需求: 5.2  where_or 遇到不支持操作符时返回 Err
5312        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5313        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5314        let result = QueryBuilder::new(pool, "users", false)
5315            .where_or("age", "IN", 18i64);
5316        assert!(
5317            matches!(result, Err(crate::DbError::UnsupportedOperator(_))),
5318            "where_or 遇到不支持的操作符 'IN' 应该返回 Err(DbError::UnsupportedOperator)"
5319        );
5320    }
5321
5322    #[test]
5323    fn test_where_or_supported_operators_work() {
5324        // 验证需求: 5.8  where_or 支持的操作符行为不变
5325        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5326        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5327        let result = QueryBuilder::new(pool, "users", false)
5328            .where_or("status", "=", 1i64);
5329        assert!(result.is_ok(), "where_or 操作符 '=' 应该返回 Ok");
5330        let builder = result.unwrap();
5331        assert_eq!(builder.conditions.len(), 1);
5332    }
5333
5334    #[test]
5335    fn test_having_cond_unsupported_operator_returns_error() {
5336        // 验证需求: 5.3  having_cond 遇到不支持操作符时返回 Err
5337        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5338        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5339        let result = QueryBuilder::new(pool, "orders", false)
5340            .having_cond("cnt", "LIKE", 5i64);
5341        assert!(
5342            matches!(result, Err(crate::DbError::UnsupportedOperator(_))),
5343            "having_cond 遇到不支持的操作符 'LIKE' 应该返回 Err(DbError::UnsupportedOperator)"
5344        );
5345    }
5346
5347    #[test]
5348    fn test_having_cond_supported_operators_work() {
5349        // 验证需求: 5.8  having_cond 支持的操作符行为不变
5350        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5351        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5352        let result = QueryBuilder::new(pool, "orders", false)
5353            .having_cond("cnt", ">", 5i64);
5354        assert!(result.is_ok(), "having_cond 操作符 '>' 应该返回 Ok");
5355        let builder = result.unwrap();
5356        assert_eq!(builder.having_clause.len(), 1);
5357    }
5358
5359    #[test]
5360    fn test_where_and_unchecked_works_with_valid_operator() {
5361        // 验证需求: 5.4  where_and_unchecked 对合法操作符正常工作
5362        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5363        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5364        let builder = QueryBuilder::new(pool, "users", false)
5365            .where_and_unchecked("age", "=", 18i64);
5366        assert_eq!(builder.conditions.len(), 1);
5367    }
5368
5369    #[test]
5370    fn test_where_or_unchecked_works_with_valid_operator() {
5371        // 验证需求: 5.5  where_or_unchecked 对合法操作符正常工作
5372        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5373        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5374        let builder = QueryBuilder::new(pool, "users", false)
5375            .where_or_unchecked("status", "=", 1i64)
5376            .where_or_unchecked("status", "=", 2i64);
5377        // where_or 会将条件组合成 OR
5378        assert_eq!(builder.conditions.len(), 1);
5379    }
5380
5381    #[test]
5382    fn test_having_cond_unchecked_works_with_valid_operator() {
5383        // 验证需求: 5.6  having_cond_unchecked 对合法操作符正常工作
5384        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5385        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5386        let builder = QueryBuilder::new(pool, "orders", false)
5387            .having_cond_unchecked("cnt", ">", 5i64);
5388        assert_eq!(builder.having_clause.len(), 1);
5389    }
5390
5391    #[test]
5392    fn test_where_and_chaining_with_result() {
5393        // 验证需求: 5.1  where_and 返回 Result 后可以链式调用
5394        let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5395        let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5396        let result = QueryBuilder::new(pool, "users", false)
5397            .where_and("age", ">", 18i64)
5398            .and_then(|b| b.where_and("status", "=", 1i64));
5399        assert!(result.is_ok(), "链式 where_and 调用应该成功");
5400        let builder = result.unwrap();
5401        assert_eq!(builder.conditions.len(), 2);
5402    }
5403
5404    // ==================== 任务 8.5:属性测试 P5 - 批次大小分割正确性 ====================
5405
5406    // **Validates: Requirements 7.4**
5407    // 属性 P5:对于任意 n 条记录和批次大小 b(b > 0),
5408    // 执行的批次数等于 ceil(n / b)。
5409    //
5410    // 此测试不需要真实数据库连接,直接测试 chunks() 分批逻辑来验证批次数。
5411    proptest! {
5412        #![proptest_config(ProptestConfig::with_cases(500))]
5413
5414        #[test]
5415        fn prop_batch_size_chunk_count(
5416            // n: 记录数,范围 0..=1000
5417            n in 0usize..=1000,
5418            // b: 批次大小,范围 1..=200(b > 0)
5419            b in 1usize..=200
5420        ) {
5421            // 构造 n 条虚拟记录(不需要真实数据,只需验证分批逻辑)
5422            let data: Vec<u32> = (0..n as u32).collect();
5423
5424            // 计算实际分批数(使用 chunks() 分批)
5425            let actual_chunk_count = if data.is_empty() {
5426                0
5427            } else {
5428                data.chunks(b).count()
5429            };
5430
5431            // 计算预期分批数:ceil(n / b)
5432            let expected_chunk_count = if n == 0 {
5433                0
5434            } else {
5435                n.div_ceil(b)  // 等价于 ceil(n / b)
5436            };
5437
5438            // 验证分批数等于 ceil(n / b)
5439            prop_assert_eq!(
5440                actual_chunk_count,
5441                expected_chunk_count,
5442                "n={} 条记录,批次大小 b={},实际分批数 {} 应等于 ceil(n/b)={}",
5443                n, b, actual_chunk_count, expected_chunk_count
5444            );
5445
5446            // 额外验证:每个分批的大小不超过 b
5447            for chunk in data.chunks(b) {
5448                prop_assert!(
5449                    chunk.len() <= b,
5450                    "每个分批的大小 {} 不应超过批次大小 {}",
5451                    chunk.len(), b
5452                );
5453            }
5454
5455            // 额外验证:所有分批的记录总数等于 n
5456            let total_records: usize = data.chunks(b).map(|c| c.len()).sum();
5457            prop_assert_eq!(
5458                total_records,
5459                n,
5460                "所有分批的记录总数 {} 应等于原始记录数 {}",
5461                total_records, n
5462            );
5463        }
5464    }
5465
5466    // 单元测试:验证 batch_size 为 0 时返回错误
5467    #[test]
5468    fn test_insert_batch_with_size_zero_batch_size_returns_error() {
5469        // 验证需求: 7.2  batch_size 为 0 时返回 SerializationError
5470        // 此测试不需要数据库连接,直接验证错误处理逻辑
5471        // 使用 tokio 运行时执行异步测试
5472        let rt = tokio::runtime::Runtime::new().unwrap();
5473        rt.block_on(async {
5474            // 创建一个内存中的虚拟池(不需要真实连接)
5475            // 注意:此处使用 MaybeUninit 是不安全的,但对于测试入口验证是安全的
5476            // 因为 batch_size == 0 的检查在任何数据库操作之前就会返回
5477            let pool_storage = std::mem::MaybeUninit::<MySqlPool>::uninit();
5478            let pool: &MySqlPool = unsafe { &*pool_storage.as_ptr() };
5479            let builder = QueryBuilder::new(pool, "users", false);
5480
5481            // 准备测试数据
5482            let data = vec![serde_json::json!({"name": "张三"})];
5483
5484            // 调用 insert_batch_with_size,batch_size = 0
5485            let result = builder.insert_batch_with_size(&data, 0).await;
5486
5487            // 验证返回 SerializationError
5488            assert!(
5489                matches!(result, Err(crate::DbError::SerializationError(_))),
5490                "batch_size 为 0 应返回 SerializationError,实际结果: {:?}",
5491                result.map(|_| "Ok")
5492            );
5493
5494            // 验证错误消息包含预期内容
5495            if let Err(crate::DbError::SerializationError(msg)) = result {
5496                assert!(
5497                    msg.contains("batch_size") || msg.contains("0"),
5498                    "错误消息应提及 batch_size 不能为 0,实际消息: {}",
5499                    msg
5500                );
5501            }
5502        });
5503    }
5504
5505    // 单元测试:验证分批逻辑的边界情况
5506    #[test]
5507    fn test_batch_chunk_logic_boundary_cases() {
5508        // 验证需求: 7.4  分批逻辑边界情况
5509
5510        // 情况 1:数据量恰好等于批次大小
5511        let data: Vec<u32> = (0..10).collect();
5512        let chunks: Vec<_> = data.chunks(10).collect();
5513        assert_eq!(chunks.len(), 1, "数据量等于批次大小时应只有 1 个分批");
5514        assert_eq!(chunks[0].len(), 10);
5515
5516        // 情况 2:数据量小于批次大小
5517        let data: Vec<u32> = (0..5).collect();
5518        let chunks: Vec<_> = data.chunks(10).collect();
5519        assert_eq!(chunks.len(), 1, "数据量小于批次大小时应只有 1 个分批");
5520        assert_eq!(chunks[0].len(), 5);
5521
5522        // 情况 3:数据量为批次大小的整数倍
5523        let data: Vec<u32> = (0..20).collect();
5524        let chunks: Vec<_> = data.chunks(5).collect();
5525        assert_eq!(chunks.len(), 4, "20 条记录按批次大小 5 分批应得到 4 个分批");
5526        for chunk in &chunks {
5527            assert_eq!(chunk.len(), 5);
5528        }
5529
5530        // 情况 4:数据量不是批次大小的整数倍(最后一批较小)
5531        let data: Vec<u32> = (0..11).collect();
5532        let chunks: Vec<_> = data.chunks(5).collect();
5533        assert_eq!(chunks.len(), 3, "11 条记录按批次大小 5 分批应得到 3 个分批");
5534        assert_eq!(chunks[0].len(), 5);
5535        assert_eq!(chunks[1].len(), 5);
5536        assert_eq!(chunks[2].len(), 1, "最后一批应只有 1 条记录");
5537
5538        // 情况 5:批次大小为 1(每条记录一批)
5539        let data: Vec<u32> = (0..5).collect();
5540        let chunks: Vec<_> = data.chunks(1).collect();
5541        assert_eq!(chunks.len(), 5, "批次大小为 1 时,分批数应等于记录数");
5542    }
5543}