clickhouse_srv/types/
from_sql.rs

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