clickhouse_rs/types/
from_sql.rs

1use chrono::prelude::*;
2use chrono_tz::Tz;
3use std::net::{Ipv4Addr, Ipv6Addr};
4
5use crate::types::{Enum16, Enum8};
6use crate::{
7    errors::{Error, FromSqlError},
8    types::{column::{Either, datetime64::to_datetime}, Decimal, SqlType, ValueRef},
9};
10
11pub type FromSqlResult<T> = Result<T, Error>;
12
13pub trait FromSql<'a>: Sized {
14    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self>;
15}
16
17macro_rules! from_sql_impl {
18    ( $( $t:ident: $k:ident ),* ) => {
19        $(
20            impl<'a> FromSql<'a> for $t {
21                fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
22                    match value {
23                        ValueRef::$k(v) => Ok(v),
24                        _ => {
25                            let from = SqlType::from(value.clone()).to_string();
26                            Err(Error::FromSql(FromSqlError::InvalidType { src: from, dst: stringify!($t).into() }))
27                        }
28                    }
29                }
30            }
31        )*
32    };
33}
34
35impl<'a> FromSql<'a> for Decimal {
36    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
37        match value {
38            ValueRef::Decimal(v) => Ok(v),
39            _ => {
40                let from = SqlType::from(value.clone()).to_string();
41                Err(Error::FromSql(FromSqlError::InvalidType {
42                    src: from,
43                    dst: "Decimal".into(),
44                }))
45            }
46        }
47    }
48}
49
50impl<'a> FromSql<'a> for Enum8 {
51    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
52        match value {
53            ValueRef::Enum8(_enum_values, v) => Ok(v),
54            _ => {
55                let from = SqlType::from(value.clone()).to_string();
56
57                Err(Error::FromSql(FromSqlError::InvalidType {
58                    src: from,
59                    dst: "Enum8".into(),
60                }))
61            }
62        }
63    }
64}
65
66impl<'a> FromSql<'a> for Enum16 {
67    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
68        match value {
69            ValueRef::Enum16(_enum_values, v) => Ok(v),
70            _ => {
71                let from = SqlType::from(value.clone()).to_string();
72
73                Err(Error::FromSql(FromSqlError::InvalidType {
74                    src: from,
75                    dst: "Enum16".into(),
76                }))
77            }
78        }
79    }
80}
81
82impl<'a> FromSql<'a> for &'a str {
83    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<&'a str> {
84        value.as_str()
85    }
86}
87
88impl<'a> FromSql<'a> for &'a [u8] {
89    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<&'a [u8]> {
90        value.as_bytes()
91    }
92}
93
94impl<'a> FromSql<'a> for String {
95    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
96        value.as_str().map(str::to_string)
97    }
98}
99
100impl<'a> FromSql<'a> for Ipv4Addr {
101    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
102        match value {
103            ValueRef::Ipv4(ip) => Ok(Ipv4Addr::from(ip)),
104            _ => {
105                let from = SqlType::from(value.clone()).to_string();
106                Err(Error::FromSql(FromSqlError::InvalidType {
107                    src: from,
108                    dst: "Ipv4".into(),
109                }))
110            }
111        }
112    }
113}
114
115impl<'a> FromSql<'a> for Ipv6Addr {
116    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
117        match value {
118            ValueRef::Ipv6(ip) => Ok(Ipv6Addr::from(ip)),
119            _ => {
120                let from = SqlType::from(value.clone()).to_string();
121                Err(Error::FromSql(FromSqlError::InvalidType {
122                    src: from,
123                    dst: "Ipv6".into(),
124                }))
125            }
126        }
127    }
128}
129
130impl<'a> FromSql<'a> for uuid::Uuid {
131    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
132        match value {
133            ValueRef::Uuid(row) => Ok(uuid::Uuid::from_bytes(row)),
134            _ => {
135                let from = SqlType::from(value.clone()).to_string();
136                Err(Error::FromSql(FromSqlError::InvalidType {
137                    src: from,
138                    dst: "Uuid".into(),
139                }))
140            }
141        }
142    }
143}
144
145macro_rules! from_sql_vec_impl {
146    ( $( $t:ty: $k:pat => $f:expr ),* ) => {
147        $(
148            impl<'a> FromSql<'a> for Vec<$t> {
149                fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
150                    match value {
151                        ValueRef::Array($k, vs) => {
152                            let f: fn(ValueRef<'a>) -> FromSqlResult<$t> = $f;
153                            let mut result = Vec::with_capacity(vs.len());
154                            for v in vs.iter() {
155                                let value: $t = f(v.clone())?;
156                                result.push(value);
157                            }
158                            Ok(result)
159                        }
160                        _ => {
161                            let from = SqlType::from(value.clone()).to_string();
162                            Err(Error::FromSql(FromSqlError::InvalidType {
163                                src: from,
164                                dst: format!("Vec<{}>", stringify!($t)).into(),
165                            }))
166                        }
167                    }
168                }
169            }
170        )*
171    };
172}
173
174from_sql_vec_impl! {
175    &'a str: SqlType::String => |v| v.as_str(),
176    String: SqlType::String => |v| v.as_string(),
177    Date<Tz>: SqlType::Date => |z| Ok(z.into()),
178    DateTime<Tz>: SqlType::DateTime(_) => |z| Ok(z.into())
179}
180
181impl<'a> FromSql<'a> for Vec<u8> {
182    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
183        match value {
184            ValueRef::Array(SqlType::UInt8, vs) => {
185                let mut result = Vec::with_capacity(vs.len());
186                for v in vs.iter() {
187                    result.push(v.clone().into());
188                }
189                Ok(result)
190            }
191            _ => value.as_bytes().map(|bs| bs.to_vec()),
192        }
193    }
194}
195
196macro_rules! from_sql_vec_impl {
197    ( $( $t:ident: $k:ident ),* ) => {
198        $(
199            impl<'a> FromSql<'a> for Vec<$t> {
200                fn from_sql(value: ValueRef<'a>) -> Result<Self, Error> {
201                    match value {
202                        ValueRef::Array(SqlType::$k, vs) => {
203                            let mut result = Vec::with_capacity(vs.len());
204                            for v in vs.iter() {
205                                let val: $t = v.clone().into();
206                                result.push(val);
207                            }
208                            Ok(result)
209                        }
210                        _ => {
211                            let from = SqlType::from(value.clone()).to_string();
212                            Err(Error::FromSql(FromSqlError::InvalidType { src: from, dst: stringify!($t).into() }))
213                        }
214                    }
215                }
216            }
217        )*
218    };
219}
220
221from_sql_vec_impl! {
222    i8: Int8,
223    i16: Int16,
224    i32: Int32,
225    i64: Int64,
226
227    u16: UInt16,
228    u32: UInt32,
229    u64: UInt64,
230
231    f32: Float32,
232    f64: Float64
233}
234
235impl<'a, T> FromSql<'a> for Option<T>
236where
237    T: FromSql<'a>,
238{
239    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
240        match value {
241            ValueRef::Nullable(e) => match e {
242                Either::Left(_) => Ok(None),
243                Either::Right(u) => {
244                    let value_ref = u.as_ref().clone();
245                    Ok(Some(T::from_sql(value_ref)?))
246                }
247            },
248            _ => {
249                let from = SqlType::from(value.clone()).to_string();
250                Err(Error::FromSql(FromSqlError::InvalidType {
251                    src: from,
252                    dst: stringify!($t).into(),
253                }))
254            }
255        }
256    }
257}
258
259impl<'a> FromSql<'a> for Date<Tz> {
260    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
261        match value {
262            ValueRef::Date(v, tz) => {
263                let time = tz.timestamp(i64::from(v) * 24 * 3600, 0);
264                Ok(time.date())
265            }
266            _ => {
267                let from = SqlType::from(value).to_string();
268                Err(Error::FromSql(FromSqlError::InvalidType {
269                    src: from,
270                    dst: "Date<Tz>".into(),
271                }))
272            }
273        }
274    }
275}
276
277impl<'a> FromSql<'a> for DateTime<Tz> {
278    fn from_sql(value: ValueRef<'a>) -> FromSqlResult<Self> {
279        match value {
280            ValueRef::DateTime(v, tz) => {
281                let time = tz.timestamp(i64::from(v), 0);
282                Ok(time)
283            }
284            ValueRef::DateTime64(v, params) => {
285                let (precision, tz) = *params;
286                Ok(to_datetime(v, precision, tz))
287            }
288            _ => {
289                let from = SqlType::from(value).to_string();
290                Err(Error::FromSql(FromSqlError::InvalidType {
291                    src: from,
292                    dst: "DateTime<Tz>".into(),
293                }))
294            }
295        }
296    }
297}
298
299from_sql_impl! {
300    u8: UInt8,
301    u16: UInt16,
302    u32: UInt32,
303    u64: UInt64,
304
305    i8: Int8,
306    i16: Int16,
307    i32: Int32,
308    i64: Int64,
309
310    f32: Float32,
311    f64: Float64
312}
313
314#[cfg(test)]
315mod test {
316    use crate::types::{from_sql::FromSql, ValueRef};
317
318    #[test]
319    fn test_u8() {
320        let v = ValueRef::from(42_u8);
321        let actual = u8::from_sql(v).unwrap();
322        assert_eq!(actual, 42_u8);
323    }
324
325    #[test]
326    fn test_bad_convert() {
327        let v = ValueRef::from(42_u16);
328        match u32::from_sql(v) {
329            Ok(_) => panic!("should fail"),
330            Err(e) => assert_eq!(
331                "From SQL error: `SqlType::UInt16 cannot be cast to u32.`".to_string(),
332                format!("{}", e)
333            ),
334        }
335    }
336}