Skip to main content

sz_orm_core/
value.rs

1//! Value 类型定义
2//!
3//! 数据库操作的统一值表示
4
5use std::borrow::Cow;
6use std::fmt;
7
8use serde::{Deserialize, Serialize};
9
10/// 数据库值类型
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
12#[non_exhaustive]
13pub enum Value {
14    /// Null 值
15    #[default]
16    Null,
17
18    /// 布尔值
19    Bool(bool),
20
21    /// 8 位有符号整数
22    I8(i8),
23
24    /// 16 位有符号整数
25    I16(i16),
26
27    /// 32 位有符号整数
28    I32(i32),
29
30    /// 64 位有符号整数
31    I64(i64),
32
33    /// 8 位无符号整数
34    U8(u8),
35
36    /// 16 位无符号整数
37    U16(u16),
38
39    /// 32 位无符号整数
40    U32(u32),
41
42    /// 64 位无符号整数
43    U64(u64),
44
45    /// 32 位浮点数
46    F32(f32),
47
48    /// 64 位浮点数
49    F64(f64),
50
51    /// 高精度十进制数(NUMERIC/DECIMAL),以字符串形式存储避免 f64 精度丢失
52    Decimal(String),
53
54    /// 字符串值
55    String(String),
56
57    /// 字节值
58    Bytes(Vec<u8>),
59
60    /// UUID 值(以字符串形式存储)
61    Uuid(String),
62
63    /// 日期值(ISO 8601 格式)
64    Date(String),
65
66    /// 日期时间值(ISO 8601 格式)
67    DateTime(String),
68
69    /// 时间值
70    Time(String),
71
72    /// JSON 值
73    Json(String),
74
75    /// 值数组
76    Array(Vec<Value>),
77
78    /// 基于 HashMap 的对象值,用于存储关系数据
79    Object(std::collections::HashMap<String, Value>),
80}
81
82// ---------------------------------------------------------------------------
83// FromQueryResult trait
84// ---------------------------------------------------------------------------
85
86/// 从 `Value` 反序列化查询结果行的字段值。
87///
88/// 由 `#[derive(FromQueryResult)]` 自动为结构体生成实现,
89/// 也可手动为自定义类型实现。
90///
91/// # 示例
92///
93/// ```ignore
94/// use sz_orm_core::value::{Value, FromQueryResult};
95///
96/// #[derive(FromQueryResult)]
97/// struct User {
98///     id: i64,
99///     name: String,
100/// }
101///
102/// let row = vec![
103///     ("id".to_string(), Value::from(1i64)),
104///     ("name".to_string(), Value::from("Alice")),
105/// ];
106/// let user = User::from_row(&row).unwrap();
107/// assert_eq!(user.id, 1);
108/// ```
109pub trait FromQueryResult: Sized {
110    /// 从单个 `Value` 提取字段值
111    ///
112    /// 对结构体类型无意义(结构体由多列组成,不能从单个 Value 构造),
113    /// 因此提供默认实现返回错误。仅基础标量类型(i64, String, bool 等)
114    /// 需要真正重写此方法。
115    fn from_value(_value: &Value) -> Result<Self, String> {
116        Err(
117            "from_value not implemented for this type; use from_query_result for structs"
118                .to_string(),
119        )
120    }
121
122    /// 从一行数据(列名→值的 HashMap 表示)构建自身
123    fn from_row(row: &std::collections::HashMap<String, Value>) -> Result<Self, String> {
124        Self::from_query_result(row)
125    }
126
127    /// 从一行数据构建自身(主入口,由 `#[derive(FromQueryResult)]` 自动生成)
128    fn from_query_result(_row: &std::collections::HashMap<String, Value>) -> Result<Self, String> {
129        Err("from_query_result not implemented for this type".to_string())
130    }
131
132    /// 返回该类型期望的列名列表(由 `#[derive(FromQueryResult)]` 自动生成)。
133    ///
134    /// 用于 `query_as!` 宏在 `db-verify` 模式下做编译期列名交叉验证:
135    /// 确保 SQL 的 SELECT 列全部出现在结构体字段中。
136    fn row_desc() -> Vec<&'static str> {
137        Vec::new()
138    }
139
140    /// 返回该类型期望的列名 + SQL 类型列表(由 `#[derive(FromQueryResult)]` 自动生成)。
141    ///
142    /// 用于 `query_as!` 宏在 `db-verify` 模式下做编译期列类型匹配验证:
143    /// 确保 SQL 的 SELECT 列类型与结构体字段类型兼容。
144    ///
145    /// 返回格式:`&[(&'static str, &'static str)]`,例如 `[("id", "bigint"), ("name", "varchar")]`。
146    /// SQL 类型名使用 `INFORMATION_SCHEMA.DATA_TYPE`(MySQL)或 `udt_name`(PostgreSQL)
147    /// 的规范化小写形式。
148    fn column_types() -> &'static [(&'static str, &'static str)] {
149        &[]
150    }
151}
152
153/// 列名枚举抽象(P2-2:由 `#[derive(ColumnEnum)]` 自动实现)。
154///
155/// 从结构体字段自动生成 `<StructName>Column` 枚举,每个变体对应一个数据库列:
156/// ```rust,ignore
157/// #[derive(ColumnEnum)]
158/// struct User { id: i64, name: String }
159///
160/// let col = UserColumn::Id;
161/// assert_eq!(col.as_str(), "id");
162/// ```
163///
164/// 支持 `#[column(name = "...")]` 覆盖列名(与 `#[derive(FromQueryResult)]` 一致)。
165pub trait ColumnTrait {
166    /// 返回当前变体对应的数据库列名。
167    fn as_str(&self) -> &'static str;
168    /// 返回全部列变体(保持结构体字段声明顺序)。
169    fn all() -> Vec<Self>
170    where
171        Self: Sized;
172}
173
174/// 编译期字符串相等比较(const 上下文专用,供 `query_as!` 生成的编译期验证代码使用)。
175///
176/// `str == str` 在 const 上下文中不可用(`PartialEq` 非 const),
177/// 因此提供逐字节比较的 const 实现。
178pub const fn __sz_orm_const_str_eq(a: &str, b: &str) -> bool {
179    if a.len() != b.len() {
180        return false;
181    }
182    let ab = a.as_bytes();
183    let bb = b.as_bytes();
184    let mut i = 0;
185    while i < ab.len() {
186        if ab[i] != bb[i] {
187            return false;
188        }
189        i += 1;
190    }
191    true
192}
193
194/// 编译期 SQL 类型兼容性比较(const 上下文专用,供 `query_as!` 生成的编译期验证代码使用)。
195///
196/// 与 `sz-orm-macros` crate 内 `types_compatible()` 保持同一分类逻辑:
197/// 将类型名映射到逻辑分类(整数/浮点/文本/二进制/时间/JSON/UUID 等),
198/// 分类相同即视为兼容(如 `BIGINT` 与 `INT8`)。
199pub const fn __sz_orm_const_types_compatible(
200    actual_db_type: &str,
201    expected_rust_type: &str,
202) -> bool {
203    // 逐字节大小写不敏感比较(const 上下文不支持 to_uppercase()/slice range 索引)
204    const fn ci_eq(t: &str, pat: &[u8]) -> bool {
205        let tb = t.as_bytes();
206        if tb.len() != pat.len() {
207            return false;
208        }
209        let mut i = 0;
210        while i < tb.len() {
211            let c = tb[i];
212            let u = if c >= b'a' && c <= b'z' { c - 32 } else { c };
213            if u != pat[i] {
214                return false;
215            }
216            i += 1;
217        }
218        true
219    }
220    const fn classify(t: &str) -> u8 {
221        if ci_eq(t, b"BOOLEAN") || ci_eq(t, b"BOOL") {
222            1
223        } else if ci_eq(t, b"TINYINT") {
224            2
225        } else if ci_eq(t, b"SMALLINT") || ci_eq(t, b"INT2") {
226            3
227        } else if ci_eq(t, b"INT")
228            || ci_eq(t, b"INT4")
229            || ci_eq(t, b"OID")
230            || ci_eq(t, b"MEDIUMINT")
231            || ci_eq(t, b"INTEGER")
232        {
233            4
234        } else if ci_eq(t, b"BIGINT") || ci_eq(t, b"INT8") {
235            5
236        } else if ci_eq(t, b"TINYINT UNSIGNED") {
237            6
238        } else if ci_eq(t, b"SMALLINT UNSIGNED") {
239            7
240        } else if ci_eq(t, b"INT UNSIGNED") || ci_eq(t, b"MEDIUMINT UNSIGNED") {
241            8
242        } else if ci_eq(t, b"BIGINT UNSIGNED") {
243            9
244        } else if ci_eq(t, b"FLOAT") || ci_eq(t, b"FLOAT4") || ci_eq(t, b"REAL") {
245            10
246        } else if ci_eq(t, b"DOUBLE") || ci_eq(t, b"FLOAT8") {
247            11
248        } else if ci_eq(t, b"DECIMAL")
249            || ci_eq(t, b"NUMERIC")
250            || ci_eq(t, b"NEWDECIMAL")
251            || ci_eq(t, b"MONEY")
252        {
253            12
254        } else if ci_eq(t, b"TEXT")
255            || ci_eq(t, b"VARCHAR")
256            || ci_eq(t, b"CHAR")
257            || ci_eq(t, b"NAME")
258            || ci_eq(t, b"CLOB")
259            || ci_eq(t, b"STRING")
260        {
261            13
262        } else if ci_eq(t, b"BLOB")
263            || ci_eq(t, b"BYTEA")
264            || ci_eq(t, b"BINARY")
265            || ci_eq(t, b"VARBINARY")
266        {
267            14
268        } else if ci_eq(t, b"DATE") {
269            15
270        } else if ci_eq(t, b"DATETIME") || ci_eq(t, b"TIMESTAMP") || ci_eq(t, b"TIMESTAMPTZ") {
271            16
272        } else if ci_eq(t, b"TIME") || ci_eq(t, b"TIMETZ") {
273            17
274        } else if ci_eq(t, b"JSON") || ci_eq(t, b"JSONB") {
275            18
276        } else if ci_eq(t, b"UUID") {
277            19
278        } else {
279            0
280        }
281    }
282    let a = classify(actual_db_type);
283    let b = classify(expected_rust_type);
284    a == b || a == 0 || b == 0
285}
286
287// 基础类型的 FromQueryResult 实现
288
289macro_rules! impl_from_query_result_int {
290    ($t:ty, $variant:ident) => {
291        impl FromQueryResult for $t {
292            fn from_value(value: &Value) -> Result<Self, String> {
293                match value {
294                    // 精确匹配对应变体;数据库整数变体间不做隐式截断转换,
295                    // 需要转换时由调用方显式处理。
296                    Value::$variant(n) => Ok(*n as $t),
297                    Value::Null => Err("NULL value cannot be converted to integer".to_string()),
298                    other => Err(format!("cannot convert {:?} to {}", other, stringify!($t))),
299                }
300            }
301        }
302    };
303}
304
305impl_from_query_result_int!(i64, I64);
306impl_from_query_result_int!(i32, I32);
307impl_from_query_result_int!(i16, I16);
308impl_from_query_result_int!(i8, I8);
309impl_from_query_result_int!(u64, U64);
310impl_from_query_result_int!(u32, U32);
311impl_from_query_result_int!(u16, U16);
312impl_from_query_result_int!(u8, U8);
313
314macro_rules! impl_from_query_result_float {
315    ($t:ty, $variant:ident) => {
316        impl FromQueryResult for $t {
317            fn from_value(value: &Value) -> Result<Self, String> {
318                match value {
319                    Value::$variant(n) => Ok(*n as $t),
320                    Value::Null => Err("NULL value cannot be converted to float".to_string()),
321                    other => Err(format!("cannot convert {:?} to {}", other, stringify!($t))),
322                }
323            }
324        }
325    };
326}
327
328impl_from_query_result_float!(f64, F64);
329impl_from_query_result_float!(f32, F32);
330
331impl FromQueryResult for bool {
332    fn from_value(value: &Value) -> Result<Self, String> {
333        match value {
334            Value::Bool(b) => Ok(*b),
335            Value::I64(n) => Ok(*n != 0),
336            Value::Null => Err("NULL value cannot be converted to bool".to_string()),
337            other => Err(format!("cannot convert {:?} to bool", other)),
338        }
339    }
340}
341
342impl FromQueryResult for String {
343    fn from_value(value: &Value) -> Result<Self, String> {
344        match value {
345            Value::String(s) => Ok(s.clone()),
346            Value::Decimal(s) => Ok(s.clone()),
347            Value::Uuid(s) => Ok(s.clone()),
348            Value::Date(s) => Ok(s.clone()),
349            Value::DateTime(s) => Ok(s.clone()),
350            Value::Time(s) => Ok(s.clone()),
351            Value::Json(s) => Ok(s.clone()),
352            Value::Null => Err("NULL value cannot be converted to String".to_string()),
353            other => Err(format!("cannot convert {:?} to String", other)),
354        }
355    }
356}
357
358impl<T: FromQueryResult> FromQueryResult for Option<T> {
359    fn from_value(value: &Value) -> Result<Self, String> {
360        match value {
361            Value::Null => Ok(None),
362            other => T::from_value(other).map(Some),
363        }
364    }
365}
366
367// 基础类型实现后,为 Option<T> 补充 from_row 不支持的兜底
368impl FromQueryResult for () {
369    fn from_value(_value: &Value) -> Result<Self, String> {
370        Ok(())
371    }
372}
373
374// ---------------------------------------------------------------------------
375// 快捷函数:从 QueryRows 中提取 Vec<T>
376// ---------------------------------------------------------------------------
377
378/// 将 `QueryRows` 转换为 `Vec<T>`,其中 `T: FromQueryResult`。
379///
380/// # 示例
381///
382/// ```ignore
383/// let users: Vec<User> = rows_to::<User>(rows)?;
384/// ```
385pub fn rows_to<T: FromQueryResult>(rows: &crate::pool::QueryRows) -> Result<Vec<T>, String> {
386    rows.iter().map(T::from_query_result).collect()
387}
388
389impl Value {
390    /// 判断是否为 null
391    pub fn is_null(&self) -> bool {
392        matches!(self, Value::Null)
393    }
394
395    /// 判断是否为布尔值
396    pub fn is_bool(&self) -> bool {
397        matches!(self, Value::Bool(_))
398    }
399
400    /// 判断是否为整数
401    pub fn is_i64(&self) -> bool {
402        matches!(self, Value::I64(_))
403    }
404
405    /// 判断是否为浮点数
406    pub fn is_f64(&self) -> bool {
407        matches!(self, Value::F64(_))
408    }
409
410    /// 判断是否为字符串
411    pub fn is_string(&self) -> bool {
412        matches!(self, Value::String(_))
413    }
414
415    /// 判断是否为字节
416    pub fn is_bytes(&self) -> bool {
417        matches!(self, Value::Bytes(_))
418    }
419
420    /// 判断是否为对象
421    pub fn is_object(&self) -> bool {
422        matches!(self, Value::Object(_))
423    }
424
425    /// 从 HashMap 构造 Value
426    pub fn from_map(map: std::collections::HashMap<String, Value>) -> Self {
427        Value::Object(map)
428    }
429
430    /// 若可能,返回 &str 形式的值
431    pub fn as_str(&self) -> Option<&str> {
432        match self {
433            Value::String(s) => Some(s),
434            Value::Decimal(s) => Some(s),
435            _ => None,
436        }
437    }
438
439    /// 若可能,返回 i64 形式的值
440    /// 支持 F32/F64 → i64 的有损转换(数据库 SUM/AVG 等聚合函数常返回浮点类型)
441    /// U64 → i64 使用 `try_from`,超过 `i64::MAX` 时返回 `None`(避免静默截断为负数)
442    pub fn as_i64(&self) -> Option<i64> {
443        match self {
444            Value::I8(v) => Some(*v as i64),
445            Value::I16(v) => Some(*v as i64),
446            Value::I32(v) => Some(*v as i64),
447            Value::I64(v) => Some(*v),
448            Value::U8(v) => Some(*v as i64),
449            Value::U16(v) => Some(*v as i64),
450            Value::U32(v) => Some(*v as i64),
451            Value::U64(v) => i64::try_from(*v).ok(),
452            Value::F32(v) => Some(*v as i64),
453            Value::F64(v) => Some(*v as i64),
454            Value::Bool(v) => Some(if *v { 1 } else { 0 }),
455            Value::String(s) => s.parse::<i64>().ok(),
456            Value::Decimal(s) => s.parse::<i64>().ok(),
457            _ => None,
458        }
459    }
460
461    /// 若可能,返回 f64 形式的值
462    /// 支持整数类型 → f64 的转换
463    pub fn as_f64(&self) -> Option<f64> {
464        match self {
465            Value::F32(v) => Some(*v as f64),
466            Value::F64(v) => Some(*v),
467            Value::I8(v) => Some(*v as f64),
468            Value::I16(v) => Some(*v as f64),
469            Value::I32(v) => Some(*v as f64),
470            Value::I64(v) => Some(*v as f64),
471            Value::U8(v) => Some(*v as f64),
472            Value::U16(v) => Some(*v as f64),
473            Value::U32(v) => Some(*v as f64),
474            Value::U64(v) => Some(*v as f64),
475            Value::Bool(v) => Some(if *v { 1.0 } else { 0.0 }),
476            Value::Decimal(s) => s.parse::<f64>().ok(),
477            _ => None,
478        }
479    }
480
481    /// 若可能,返回 bool 形式的值
482    /// 支持整数(非 0 即真)、浮点(非 0.0 即真)、字符串("1"/"true"/"yes"/"on" 为真)的转换
483    pub fn as_bool(&self) -> Option<bool> {
484        match self {
485            Value::Bool(v) => Some(*v),
486            Value::I8(v) => Some(*v != 0),
487            Value::I16(v) => Some(*v != 0),
488            Value::I32(v) => Some(*v != 0),
489            Value::I64(v) => Some(*v != 0),
490            Value::U8(v) => Some(*v != 0),
491            Value::U16(v) => Some(*v != 0),
492            Value::U32(v) => Some(*v != 0),
493            Value::U64(v) => Some(*v != 0),
494            Value::F32(v) => Some(*v != 0.0),
495            Value::F64(v) => Some(*v != 0.0),
496            Value::String(s) => match s.to_lowercase().as_str() {
497                "1" | "true" | "yes" | "on" => Some(true),
498                "0" | "false" | "no" | "off" => Some(false),
499                _ => None,
500            },
501            Value::Null => Some(false),
502            _ => None,
503        }
504    }
505
506    /// 若可能,返回字节切片形式(&[u8])的值
507    /// 字符串类型会返回其 UTF-8 字节
508    pub fn as_bytes(&self) -> Option<&[u8]> {
509        match self {
510            Value::Bytes(v) => Some(v),
511            Value::String(s) => Some(s.as_bytes()),
512            _ => None,
513        }
514    }
515
516    /// 转换为 SQL 参数字符串(用于直接拼接 SQL 语句)
517    /// 字符串类型会进行转义并加引号;字节类型转换为 X'..' 形式
518    ///
519    /// # 安全性警告
520    ///
521    /// 本方法使用简单的 `'` → `''` 转义,对 PostgreSQL/SQLite 默认配置安全,
522    /// 但对 MySQL 默认配置(backslash 是转义字符)不安全:含 `\` 的字符串
523    /// 可能被 MySQL 误解。**生产环境请使用 [`Value::to_param_with_dialect`]**
524    /// 以获得方言感知的转义。
525    pub fn to_param(&self) -> Cow<'_, str> {
526        match self {
527            Value::Null => Cow::Borrowed("NULL"),
528            Value::Bool(b) => Cow::Owned(if *b { "TRUE" } else { "FALSE" }.to_string()),
529            Value::I8(v) => Cow::Owned(v.to_string()),
530            Value::I16(v) => Cow::Owned(v.to_string()),
531            Value::I32(v) => Cow::Owned(v.to_string()),
532            Value::I64(v) => Cow::Owned(v.to_string()),
533            Value::U8(v) => Cow::Owned(v.to_string()),
534            Value::U16(v) => Cow::Owned(v.to_string()),
535            Value::U32(v) => Cow::Owned(v.to_string()),
536            Value::U64(v) => Cow::Owned(v.to_string()),
537            Value::F32(v) => Cow::Owned(v.to_string()),
538            Value::F64(v) => Cow::Owned(v.to_string()),
539            Value::Decimal(s) => Cow::Owned(s.clone()),
540            Value::String(s) => Cow::Owned(format!("'{}'", escape_string(s))),
541            Value::Bytes(b) => Cow::Owned(format!("X'{}'", hex_encode(b))),
542            Value::Uuid(s) => Cow::Owned(format!("'{}'", escape_string(s))),
543            Value::Date(s) => Cow::Owned(format!("'{}'", escape_string(s))),
544            Value::DateTime(s) => Cow::Owned(format!("'{}'", escape_string(s))),
545            Value::Time(s) => Cow::Owned(format!("'{}'", escape_string(s))),
546            Value::Json(s) => Cow::Owned(format!("'{}'", escape_string(s))),
547            Value::Array(arr) => {
548                let params: Vec<String> = arr.iter().map(|v| v.to_param().into_owned()).collect();
549                Cow::Owned(format!("({})", params.join(", ")))
550            }
551            Value::Object(_) => Cow::Borrowed("NULL"),
552        }
553    }
554
555    /// v0.2.2 修复 H-1:方言感知的 SQL 参数转换
556    ///
557    /// 与 [`to_param`](Self::to_param) 的区别:字符串类型使用 `dialect.escape_string()`
558    /// 而非简单的 `'` → `''` 转义,确保在所有方言下都安全:
559    ///
560    /// - **MySQL**:转义 `\`、`'`、`\0`、`\n`、`\r`、`\t`、`\x1a`
561    /// - **PostgreSQL**:仅转义 `'`(依赖 `standard_conforming_strings=on` 默认配置)
562    /// - **SQLite**:仅转义 `'`
563    ///
564    /// # 推荐用法
565    ///
566    /// ```ignore
567    /// use sz_orm_core::{DbType, get_dialect};
568    /// let dialect = get_dialect(DbType::MySQL)?;
569    /// let v = Value::String("hello\\nworld".to_string());
570    /// let param = v.to_param_with_dialect(&**dialect);
571    /// ```
572    pub fn to_param_with_dialect(&self, dialect: &dyn crate::dialect::Dialect) -> Cow<'_, str> {
573        match self {
574            Value::Null => Cow::Borrowed("NULL"),
575            Value::Bool(b) => Cow::Owned(if *b { "TRUE" } else { "FALSE" }.to_string()),
576            Value::I8(v) => Cow::Owned(v.to_string()),
577            Value::I16(v) => Cow::Owned(v.to_string()),
578            Value::I32(v) => Cow::Owned(v.to_string()),
579            Value::I64(v) => Cow::Owned(v.to_string()),
580            Value::U8(v) => Cow::Owned(v.to_string()),
581            Value::U16(v) => Cow::Owned(v.to_string()),
582            Value::U32(v) => Cow::Owned(v.to_string()),
583            Value::U64(v) => Cow::Owned(v.to_string()),
584            Value::F32(v) => Cow::Owned(v.to_string()),
585            Value::F64(v) => Cow::Owned(v.to_string()),
586            Value::Decimal(s) => Cow::Owned(s.clone()),
587            Value::String(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
588            Value::Bytes(b) => Cow::Owned(format!("X'{}'", hex_encode(b))),
589            Value::Uuid(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
590            Value::Date(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
591            Value::DateTime(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
592            Value::Time(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
593            Value::Json(s) => Cow::Owned(format!("'{}'", dialect.escape_string(s))),
594            Value::Array(arr) => {
595                let params: Vec<String> = arr
596                    .iter()
597                    .map(|v| v.to_param_with_dialect(dialect).into_owned())
598                    .collect();
599                Cow::Owned(format!("({})", params.join(", ")))
600            }
601            Value::Object(_) => Cow::Borrowed("NULL"),
602        }
603    }
604
605    /// 从任何实现了 `Into<Value>` 的类型构造 Value
606    pub fn from<T: Into<Value>>(v: T) -> Self {
607        v.into()
608    }
609}
610
611impl fmt::Display for Value {
612    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
613        match self {
614            Value::Null => write!(f, "NULL"),
615            Value::Bool(b) => write!(f, "{}", b),
616            Value::I8(v) => write!(f, "{}", v),
617            Value::I16(v) => write!(f, "{}", v),
618            Value::I32(v) => write!(f, "{}", v),
619            Value::I64(v) => write!(f, "{}", v),
620            Value::U8(v) => write!(f, "{}", v),
621            Value::U16(v) => write!(f, "{}", v),
622            Value::U32(v) => write!(f, "{}", v),
623            Value::U64(v) => write!(f, "{}", v),
624            Value::F32(v) => write!(f, "{}", v),
625            Value::F64(v) => write!(f, "{}", v),
626            Value::Decimal(v) => write!(f, "{}", v),
627            Value::String(v) => write!(f, "'{}'", v),
628            Value::Bytes(v) => write!(f, "X'{}'", hex_encode(v)),
629            Value::Uuid(v) => write!(f, "'{}'", v),
630            Value::Date(v) => write!(f, "'{}'", v),
631            Value::DateTime(v) => write!(f, "'{}'", v),
632            Value::Time(v) => write!(f, "'{}'", v),
633            Value::Json(v) => write!(f, "'{}'", v),
634            Value::Array(v) => {
635                let items: Vec<String> = v.iter().map(|i| format!("{}", i)).collect();
636                write!(f, "({})", items.join(", "))
637            }
638            Value::Object(map) => {
639                let items: Vec<String> = map.iter().map(|(k, v)| format!("{}: {}", k, v)).collect();
640                write!(f, "{{{}}}", items.join(", "))
641            }
642        }
643    }
644}
645
646impl From<()> for Value {
647    fn from(_: ()) -> Self {
648        Value::Null
649    }
650}
651
652impl From<bool> for Value {
653    fn from(v: bool) -> Self {
654        Value::Bool(v)
655    }
656}
657
658impl From<i8> for Value {
659    fn from(v: i8) -> Self {
660        Value::I8(v)
661    }
662}
663
664impl From<i16> for Value {
665    fn from(v: i16) -> Self {
666        Value::I16(v)
667    }
668}
669
670impl From<i32> for Value {
671    fn from(v: i32) -> Self {
672        Value::I32(v)
673    }
674}
675
676impl From<i64> for Value {
677    fn from(v: i64) -> Self {
678        Value::I64(v)
679    }
680}
681
682impl From<u8> for Value {
683    fn from(v: u8) -> Self {
684        Value::U8(v)
685    }
686}
687
688impl From<u16> for Value {
689    fn from(v: u16) -> Self {
690        Value::U16(v)
691    }
692}
693
694impl From<u32> for Value {
695    fn from(v: u32) -> Self {
696        Value::U32(v)
697    }
698}
699
700impl From<u64> for Value {
701    fn from(v: u64) -> Self {
702        Value::U64(v)
703    }
704}
705
706impl From<f32> for Value {
707    fn from(v: f32) -> Self {
708        Value::F32(v)
709    }
710}
711
712impl From<f64> for Value {
713    fn from(v: f64) -> Self {
714        Value::F64(v)
715    }
716}
717
718impl From<String> for Value {
719    fn from(v: String) -> Self {
720        Value::String(v)
721    }
722}
723
724impl From<&str> for Value {
725    fn from(v: &str) -> Self {
726        Value::String(v.to_string())
727    }
728}
729
730impl From<Vec<u8>> for Value {
731    fn from(v: Vec<u8>) -> Self {
732        Value::Bytes(v)
733    }
734}
735
736impl From<&[u8]> for Value {
737    fn from(v: &[u8]) -> Self {
738        Value::Bytes(v.to_vec())
739    }
740}
741
742impl From<Vec<Value>> for Value {
743    fn from(v: Vec<Value>) -> Self {
744        Value::Array(v)
745    }
746}
747
748/// 字符串字面量转义(v0.2.1 修复 Critical D-1)
749///
750/// # 旧实现的问题
751///
752/// 旧实现同时使用 `'` → `''`(标准 SQL)和 `\` → `\\`(MySQL 风格)转义,
753/// 导致在 PostgreSQL/SQLite 等不把 `\` 作为转义字符的方言下数据完整性受损
754/// (写入 `\\n` 字面量而非 `\n`)。
755///
756/// # 新实现
757///
758/// 只使用标准 SQL 转义:`'` → `''`。
759///
760/// - **SQL 注入防御**:`'` 被转义为 `''`,攻击者无法突破字符串字面量
761/// - **数据完整性**:在所有方言(MySQL/PG/SQLite/Oracle)下数据保持原样
762/// - **MySQL 兼容性**:MySQL 默认把 `\` 作为转义字符,但我们不主动转义 `\`,
763///   所以写入的 `\` 会被 MySQL 解析为字面 `\`(与 PG/SQLite 一致)
764///
765/// # 注意
766///
767/// 对于需要方言感知转义的场景(如 MySQL 的 `NO_BACKSLASH_ESCAPES` 模式),
768/// 应使用 `Dialect::escape_string()` 方法。
769fn escape_string(s: &str) -> String {
770    let mut escaped = String::with_capacity(s.len() + s.chars().filter(|&c| c == '\'').count());
771    for c in s.chars() {
772        if c == '\'' {
773            escaped.push_str("''");
774        } else {
775            escaped.push(c);
776        }
777    }
778    escaped
779}
780
781fn hex_encode(bytes: &[u8]) -> String {
782    bytes.iter().map(|b| format!("{:02x}", b)).collect()
783}
784
785/// 列类型枚举(v1.1.0 新增)
786///
787/// 用于 `row_to_value_*` 函数的预解析列类型分派,避免每行每列做字符串 `match`。
788/// 适配器在第一行解析列类型为 `Vec<ColType>`,后续行复用枚举分派(编译器优化为跳转表)。
789///
790/// # 性能优势
791///
792/// - 字符串 `match type_name` 无法被 LLVM 优化为跳转表(`&str` 比较)
793/// - 枚举 `match col_type` 编译为跳转表,O(1) 且缓存友好
794/// - 在 SELECT ALL 大结果集场景下,每行每列节省 1 次字符串比较
795#[derive(Debug, Clone, Copy, PartialEq, Eq)]
796#[non_exhaustive]
797pub enum ColType {
798    /// 布尔类型(SQLite BOOLEAN / MySQL BOOLEAN/TINYINT(1) / PG BOOL / Oracle Boolean)
799    Bool,
800    /// 8 位有符号整数(MySQL TINYINT)
801    I8,
802    /// 16 位有符号整数(MySQL SMALLINT / PG INT2)
803    I16,
804    /// 32 位有符号整数(MySQL INT/MEDIUMINT / PG INT4)
805    I32,
806    /// 64 位有符号整数(MySQL BIGINT / PG INT8 / SQLite INTEGER / Oracle NUMBER)
807    I64,
808    /// 8 位无符号整数(MySQL TINYINT UNSIGNED)
809    U8,
810    /// 16 位无符号整数(MySQL SMALLINT UNSIGNED)
811    U16,
812    /// 32 位无符号整数(MySQL INT UNSIGNED/MEDIUMINT UNSIGNED)
813    U32,
814    /// 64 位无符号整数(MySQL BIGINT UNSIGNED)
815    U64,
816    /// 32 位浮点数(MySQL FLOAT / PG FLOAT4 / SQLite REAL)
817    F32,
818    /// 64 位浮点数(MySQL DOUBLE / PG FLOAT8 / Oracle BinaryDouble)
819    F64,
820    /// 高精度十进制数(MySQL DECIMAL/NUMERIC/NEWDECIMAL / PG NUMERIC / Oracle NUMBER(p,s))
821    Decimal,
822    /// 字符串类型(TEXT/VARCHAR/CHAR/CLOB 等)
823    String,
824    /// 字节类型(BLOB/BYTEA/RAW 等)
825    Bytes,
826    /// 日期类型(DATE)
827    Date,
828    /// 日期时间类型(DATETIME/TIMESTAMP)
829    DateTime,
830    /// 时间类型(TIME)
831    Time,
832    /// JSON 类型
833    Json,
834    /// UUID 类型
835    Uuid,
836    /// 未知类型(回退到 i64 → f64 → bool → String 顺序尝试)
837    Unknown,
838}
839
840impl ColType {
841    /// 从数据库类型名解析为 ColType(通用回退实现)
842    ///
843    /// 各适配器应优先使用自己专门的 `parse_col_type_<db>` 函数(覆盖数据库特有类型名),
844    /// 此函数作为通用回退,覆盖最常见的标准 SQL 类型名。
845    ///
846    /// # 注意
847    ///
848    /// "INTEGER" 在通用映射中被归为 I32(与 MySQL INT/PG INT4 一致)。
849    /// **SQLite 适配器必须使用 [`ColType::parse_sqlite`]**:SQLite 的 INTEGER
850    /// 类型采用动态存储,可容纳 64 位整数(sqlx 默认按 i64 解码),若按 I32
851    /// 解码会在数值超过 i32::MAX 时截断。
852    pub fn from_type_name(type_name: &str) -> Self {
853        match type_name {
854            "BOOLEAN" | "BOOL" => Self::Bool,
855            "TINYINT" => Self::I8,
856            "SMALLINT" | "INT2" => Self::I16,
857            "INT" | "INT4" | "OID" | "MEDIUMINT" | "INTEGER" => Self::I32,
858            "BIGINT" | "INT8" => Self::I64,
859            "TINYINT UNSIGNED" => Self::U8,
860            "SMALLINT UNSIGNED" => Self::U16,
861            "INT UNSIGNED" | "MEDIUMINT UNSIGNED" => Self::U32,
862            "BIGINT UNSIGNED" => Self::U64,
863            "FLOAT" | "FLOAT4" | "REAL" => Self::F32,
864            "DOUBLE" | "FLOAT8" => Self::F64,
865            "DECIMAL" | "NUMERIC" | "NEWDECIMAL" | "MONEY" => Self::Decimal,
866            "TEXT" | "VARCHAR" | "CHAR" | "NAME" => Self::String,
867            "BLOB" | "BYTEA" => Self::Bytes,
868            "DATE" => Self::Date,
869            "DATETIME" | "TIMESTAMP" => Self::DateTime,
870            "TIME" => Self::Time,
871            "JSON" => Self::Json,
872            "UUID" => Self::Uuid,
873            _ => Self::Unknown,
874        }
875    }
876
877    /// SQLite 专用列类型解析
878    ///
879    /// SQLite 使用动态类型系统(type affinity),同一列可存储 INT/REAL/TEXT/BLOB 任意类型。
880    /// sqlx 报告的类型名遵循 SQLite 的"声明类型"(declared type)规则:
881    ///
882    /// - **INTEGER**:实际可容纳 8 字节整数(最大 2^63-1),sqlx 默认按 `i64` 解码。
883    ///   若按 I32 解码,数值超过 `i32::MAX` 会静默截断。
884    /// - **INT/INTEGER/BIGINT** 等:在 SQLite 中都按 INTEGER 亲和性处理,应统一映射为 I64。
885    /// - **REAL/FLOAT/DOUBLE**:映射为 F64(SQLite REAL 是 8 字节 IEEE 754)。
886    /// - **TEXT/CLOB**:映射为 String。
887    /// - **BLOB**:映射为 Bytes。
888    /// - **NUMERIC/DECIMAL**:保留为 Decimal(按字符串解码避免精度丢失)。
889    /// - **BOOLEAN**:SQLite 无原生 BOOLEAN,存为 INTEGER 0/1,但声明 BOOLEAN 时按 Bool 解码。
890    /// - **DATETIME/TIMESTAMP/DATE/TIME**:SQLite 通常以 TEXT 存储,按 String 解码。
891    /// - **JSON**:SQLite 4.x 后有 JSON 类型,按 String 解码(保留原始 JSON 文本)。
892    pub fn parse_sqlite(type_name: &str) -> Self {
893        // SQLite type_info 可能返回空字符串(NULL 或表达式结果),按 Unknown 处理
894        if type_name.is_empty() {
895            return Self::Unknown;
896        }
897        match type_name.to_uppercase().as_str() {
898            // SQLite INTEGER 亲和性:实际为 64 位有符号整数
899            "INTEGER" | "INT" | "BIGINT" | "INT8" | "INT4" | "INT2" | "TINYINT" | "SMALLINT"
900            | "MEDIUMINT" => Self::I64,
901            "BOOLEAN" | "BOOL" => Self::Bool,
902            "REAL" | "FLOAT" | "DOUBLE" | "FLOAT8" | "DOUBLE PRECISION" => Self::F64,
903            "DECIMAL" | "NUMERIC" => Self::Decimal,
904            "TEXT" | "CLOB" | "VARCHAR" | "CHAR" | "NAME" => Self::String,
905            "BLOB" => Self::Bytes,
906            "DATE" => Self::Date,
907            "DATETIME" | "TIMESTAMP" => Self::DateTime,
908            "TIME" => Self::Time,
909            "JSON" => Self::Json,
910            _ => Self::Unknown,
911        }
912    }
913
914    /// MySQL 专用列类型解析
915    ///
916    /// MySQL 类型名来自 `Column::type_info().name()`,遵循 MySQL 协议报告的类型名。
917    pub fn parse_mysql(type_name: &str) -> Self {
918        match type_name.to_uppercase().as_str() {
919            "TINYINT" => Self::I8,
920            "SMALLINT" => Self::I16,
921            "INT" | "INTEGER" | "MEDIUMINT" => Self::I32,
922            "BIGINT" => Self::I64,
923            "TINYINT UNSIGNED" => Self::U8,
924            "SMALLINT UNSIGNED" => Self::U16,
925            "INT UNSIGNED" | "MEDIUMINT UNSIGNED" => Self::U32,
926            "BIGINT UNSIGNED" => Self::U64,
927            "FLOAT" => Self::F32,
928            "DOUBLE" => Self::F64,
929            "DECIMAL" | "NUMERIC" | "NEWDECIMAL" => Self::Decimal,
930            "VARCHAR" | "CHAR" | "TEXT" | "TINYTEXT" | "MEDIUMTEXT" | "LONGTEXT" | "ENUM"
931            | "SET" => Self::String,
932            "BLOB" | "TINYBLOB" | "MEDIUMBLOB" | "LONGBLOB" | "BINARY" | "VARBINARY" => Self::Bytes,
933            "DATE" => Self::Date,
934            "DATETIME" | "TIMESTAMP" => Self::DateTime,
935            "TIME" => Self::Time,
936            "YEAR" => Self::I16,
937            "JSON" => Self::Json,
938            "BOOLEAN" | "BOOL" => Self::Bool,
939            _ => Self::from_type_name(type_name),
940        }
941    }
942
943    /// PostgreSQL 专用列类型解析
944    ///
945    /// PostgreSQL 类型名来自 `Column::type_info().name()`,使用 PG 内部类型名(如 INT4/INT8/FLOAT8)。
946    pub fn parse_postgres(type_name: &str) -> Self {
947        match type_name.to_uppercase().as_str() {
948            "BOOL" => Self::Bool,
949            "INT2" | "SMALLINT" => Self::I16,
950            "INT4" | "INTEGER" | "INT" => Self::I32,
951            "INT8" | "BIGINT" => Self::I64,
952            "FLOAT4" | "REAL" => Self::F32,
953            "FLOAT8" | "DOUBLE PRECISION" => Self::F64,
954            "NUMERIC" | "DECIMAL" | "MONEY" => Self::Decimal,
955            "TEXT" | "VARCHAR" | "CHAR" | "BPCHAR" | "NAME" | "CITEXT" => Self::String,
956            "BYTEA" => Self::Bytes,
957            "DATE" => Self::Date,
958            "TIMESTAMP" | "TIMESTAMPTZ" => Self::DateTime,
959            "TIME" | "TIMETZ" => Self::Time,
960            "JSON" | "JSONB" => Self::Json,
961            "UUID" => Self::Uuid,
962            "OID" => Self::I32,
963            _ => Self::from_type_name(type_name),
964        }
965    }
966}
967
968/// 位置式查询结果类型
969///
970/// 用于 `Connection::query_values` / `query_values_with_params`,绕过
971/// `HashMap<String, Value>` 行映射的开销,直接返回列名 + 按列顺序的值矩阵。
972///
973/// # 性能优势
974///
975/// - 普通 `query` 返回 `Vec<HashMap<String, Value>>`,每行每列需哈希计算 + 字符串克隆
976/// - `QueryValues` 返回 `(Vec<String>, Vec<Vec<Value>>)`,列名只分配一次,
977///   每行值按列序号直接 `Vec::push`,无哈希计算
978/// - 在 SELECT ALL 大结果集场景下,比 `query` 提升 30%~50%
979///
980/// # 用法
981///
982/// ```rust,ignore
983/// let (names, values_matrix): QueryValues = conn.query_values("SELECT id, name FROM users").await?;
984/// // names = ["id", "name"]
985/// // values_matrix[0] = [Value::I64(1), Value::String("Alice".into())]
986/// ```
987pub type QueryValues = (Vec<String>, Vec<Vec<Value>>);
988
989#[cfg(test)]
990mod tests {
991    use super::*;
992
993    #[test]
994    fn test_value_is_null() {
995        assert!(Value::Null.is_null());
996        assert!(!Value::I64(0).is_null());
997    }
998
999    // ---- P0-2:编译期 const 辅助函数测试 ----
1000
1001    #[test]
1002    fn test_const_str_eq() {
1003        assert!(__sz_orm_const_str_eq("id", "id"));
1004        assert!(__sz_orm_const_str_eq("user_id", "user_id"));
1005        assert!(!__sz_orm_const_str_eq("id", "ID"));
1006        assert!(!__sz_orm_const_str_eq("id", "idd"));
1007        assert!(!__sz_orm_const_str_eq("", "id"));
1008        assert!(__sz_orm_const_str_eq("", ""));
1009    }
1010
1011    #[test]
1012    fn test_const_types_compatible_same_category() {
1013        // 同一逻辑分类 → 兼容
1014        assert!(__sz_orm_const_types_compatible("BIGINT", "BIGINT"));
1015        assert!(__sz_orm_const_types_compatible("bigint", "BIGINT"));
1016        assert!(__sz_orm_const_types_compatible("INT8", "BIGINT")); // PG 风格
1017        assert!(__sz_orm_const_types_compatible("varchar", "TEXT"));
1018        assert!(__sz_orm_const_types_compatible("VARCHAR", "VARCHAR"));
1019        assert!(__sz_orm_const_types_compatible("timestamp", "DATETIME"));
1020        assert!(__sz_orm_const_types_compatible("int4", "INT"));
1021        assert!(__sz_orm_const_types_compatible("jsonb", "JSON"));
1022        assert!(__sz_orm_const_types_compatible("numeric", "DECIMAL"));
1023    }
1024
1025    #[test]
1026    fn test_const_types_compatible_different_category() {
1027        // 不同逻辑分类 → 不兼容
1028        assert!(!__sz_orm_const_types_compatible("BIGINT", "TEXT"));
1029        assert!(!__sz_orm_const_types_compatible("VARCHAR", "INT"));
1030        assert!(!__sz_orm_const_types_compatible("JSON", "BIGINT"));
1031        assert!(!__sz_orm_const_types_compatible("BLOB", "DATE"));
1032        assert!(!__sz_orm_const_types_compatible("DOUBLE", "INT"));
1033    }
1034
1035    #[test]
1036    fn test_const_types_compatible_unknown_tolerant() {
1037        // 未知类型分类为 0 → 容忍(不误报)
1038        assert!(__sz_orm_const_types_compatible("CUSTOM_TYPE", "BIGINT"));
1039        assert!(__sz_orm_const_types_compatible("BIGINT", "CUSTOM_TYPE"));
1040        assert!(__sz_orm_const_types_compatible("UNKNOWN1", "UNKNOWN2"));
1041    }
1042
1043    #[test]
1044    fn test_col_type_from_type_name() {
1045        // 标准类型
1046        assert_eq!(ColType::from_type_name("BOOLEAN"), ColType::Bool);
1047        assert_eq!(ColType::from_type_name("TINYINT"), ColType::I8);
1048        assert_eq!(ColType::from_type_name("SMALLINT"), ColType::I16);
1049        assert_eq!(ColType::from_type_name("INT"), ColType::I32);
1050        assert_eq!(ColType::from_type_name("BIGINT"), ColType::I64);
1051        assert_eq!(ColType::from_type_name("INT UNSIGNED"), ColType::U32);
1052        assert_eq!(ColType::from_type_name("FLOAT"), ColType::F32);
1053        assert_eq!(ColType::from_type_name("DOUBLE"), ColType::F64);
1054        assert_eq!(ColType::from_type_name("TEXT"), ColType::String);
1055        assert_eq!(ColType::from_type_name("BLOB"), ColType::Bytes);
1056        assert_eq!(ColType::from_type_name("DATE"), ColType::Date);
1057        assert_eq!(ColType::from_type_name("TIMESTAMP"), ColType::DateTime);
1058        assert_eq!(ColType::from_type_name("JSON"), ColType::Json);
1059        // PG 风格
1060        assert_eq!(ColType::from_type_name("INT2"), ColType::I16);
1061        assert_eq!(ColType::from_type_name("INT4"), ColType::I32);
1062        assert_eq!(ColType::from_type_name("INT8"), ColType::I64);
1063        assert_eq!(ColType::from_type_name("FLOAT4"), ColType::F32);
1064        assert_eq!(ColType::from_type_name("FLOAT8"), ColType::F64);
1065        assert_eq!(ColType::from_type_name("BYTEA"), ColType::Bytes);
1066        // 未知类型
1067        assert_eq!(ColType::from_type_name("UNKNOWN_TYPE"), ColType::Unknown);
1068        assert_eq!(ColType::from_type_name(""), ColType::Unknown);
1069    }
1070
1071    #[test]
1072    fn test_value_as_i64() {
1073        assert_eq!(Value::I64(42).as_i64(), Some(42));
1074        assert_eq!(Value::I32(42).as_i64(), Some(42));
1075        assert_eq!(Value::Bool(true).as_i64(), Some(1));
1076        assert!(Value::String("test".to_string()).as_i64().is_none());
1077    }
1078
1079    #[test]
1080    fn test_value_as_f64() {
1081        assert_eq!(Value::F64(2.5).as_f64(), Some(2.5));
1082        assert_eq!(Value::I64(42).as_f64(), Some(42.0));
1083    }
1084
1085    #[test]
1086    fn test_value_as_str() {
1087        assert_eq!(Value::String("hello".to_string()).as_str(), Some("hello"));
1088    }
1089
1090    #[test]
1091    fn test_value_to_param() {
1092        assert_eq!(Value::Null.to_param(), "NULL");
1093        assert_eq!(Value::Bool(true).to_param(), "TRUE");
1094        assert_eq!(Value::I64(42).to_param(), "42");
1095        assert_eq!(Value::String("test".to_string()).to_param(), "'test'");
1096        assert_eq!(Value::String("it's".to_string()).to_param(), "'it''s'");
1097    }
1098
1099    #[test]
1100    fn test_value_into() {
1101        let v: Value = 42i64.into();
1102        assert_eq!(v, Value::I64(42));
1103
1104        let v: Value = "hello".into();
1105        assert_eq!(v, Value::String("hello".to_string()));
1106
1107        let arr: Vec<Value> = vec![Value::I64(1), Value::I64(2)];
1108        let v: Value = arr.into();
1109        assert_eq!(v, Value::Array(vec![Value::I64(1), Value::I64(2)]));
1110    }
1111
1112    #[test]
1113    fn test_value_display() {
1114        assert_eq!(format!("{}", Value::Null), "NULL");
1115        assert_eq!(format!("{}", Value::Bool(true)), "true");
1116        assert_eq!(format!("{}", Value::I64(42)), "42");
1117        assert_eq!(format!("{}", Value::String("test".to_string())), "'test'");
1118    }
1119}