halo/
value.rs

1//! SQL 参数值类型。
2
3use std::borrow::Cow;
4
5/// SQL 参数值。
6#[derive(Debug, Clone, PartialEq)]
7pub enum SqlValue {
8    Null,
9    Bool(bool),
10    I64(i64),
11    U64(u64),
12    F64(f64),
13    String(Cow<'static, str>),
14    Bytes(Vec<u8>),
15    DateTime(SqlDateTime),
16}
17
18/// 用于对齐 go-sqlbuilder `time.Time` 的插值行为(含可选时区缩写)。
19#[derive(Debug, Clone, PartialEq)]
20pub struct SqlDateTime {
21    pub dt: time::OffsetDateTime,
22    pub tz_abbr: Option<Cow<'static, str>>,
23}
24
25impl SqlDateTime {
26    pub fn new(dt: time::OffsetDateTime) -> Self {
27        Self { dt, tz_abbr: None }
28    }
29
30    pub fn with_tz_abbr(mut self, abbr: impl Into<Cow<'static, str>>) -> Self {
31        self.tz_abbr = Some(abbr.into());
32        self
33    }
34}
35
36impl SqlValue {
37    /// 将 `Option<T>` 映射为 `SqlValue`:`None => Null`,`Some(v) => v.into()`。
38    pub fn from_option<T: Into<SqlValue>>(v: Option<T>) -> Self {
39        match v {
40            Some(v) => v.into(),
41            None => Self::Null,
42        }
43    }
44}
45
46impl From<()> for SqlValue {
47    fn from(_: ()) -> Self {
48        Self::Null
49    }
50}
51
52impl From<bool> for SqlValue {
53    fn from(v: bool) -> Self {
54        Self::Bool(v)
55    }
56}
57
58impl From<i8> for SqlValue {
59    fn from(v: i8) -> Self {
60        Self::I64(v as i64)
61    }
62}
63
64impl From<i16> for SqlValue {
65    fn from(v: i16) -> Self {
66        Self::I64(v as i64)
67    }
68}
69
70impl From<i32> for SqlValue {
71    fn from(v: i32) -> Self {
72        Self::I64(v as i64)
73    }
74}
75
76impl From<i64> for SqlValue {
77    fn from(v: i64) -> Self {
78        Self::I64(v)
79    }
80}
81
82impl From<u8> for SqlValue {
83    fn from(v: u8) -> Self {
84        Self::U64(v as u64)
85    }
86}
87
88impl From<u16> for SqlValue {
89    fn from(v: u16) -> Self {
90        Self::U64(v as u64)
91    }
92}
93
94impl From<u32> for SqlValue {
95    fn from(v: u32) -> Self {
96        Self::U64(v as u64)
97    }
98}
99
100impl From<u64> for SqlValue {
101    fn from(v: u64) -> Self {
102        Self::U64(v)
103    }
104}
105
106impl From<f32> for SqlValue {
107    fn from(v: f32) -> Self {
108        Self::F64(v as f64)
109    }
110}
111
112impl From<f64> for SqlValue {
113    fn from(v: f64) -> Self {
114        Self::F64(v)
115    }
116}
117
118impl From<String> for SqlValue {
119    fn from(v: String) -> Self {
120        Self::String(Cow::Owned(v))
121    }
122}
123
124impl From<&'static str> for SqlValue {
125    fn from(v: &'static str) -> Self {
126        Self::String(Cow::Borrowed(v))
127    }
128}
129
130impl From<Vec<u8>> for SqlValue {
131    fn from(v: Vec<u8>) -> Self {
132        Self::Bytes(v)
133    }
134}
135
136impl From<time::OffsetDateTime> for SqlValue {
137    fn from(v: time::OffsetDateTime) -> Self {
138        Self::DateTime(SqlDateTime::new(v))
139    }
140}
141
142#[cfg(test)]
143mod tests {
144    use super::SqlValue;
145
146    #[test]
147    fn from_option_some() {
148        assert_eq!(SqlValue::from_option(Some(123_i64)), SqlValue::I64(123));
149    }
150
151    #[test]
152    fn from_option_none() {
153        assert_eq!(SqlValue::from_option::<i64>(None), SqlValue::Null);
154    }
155
156    #[test]
157    fn from_unit_is_null() {
158        let v: SqlValue = ().into();
159        assert_eq!(v, SqlValue::Null);
160    }
161
162    #[test]
163    fn from_string_borrowed() {
164        let v: SqlValue = "abc".into();
165        assert_eq!(v, SqlValue::String("abc".into()));
166    }
167
168    #[test]
169    fn from_string_owned() {
170        let v: SqlValue = String::from("abc").into();
171        assert_eq!(v, SqlValue::String("abc".into()));
172    }
173}