databend_driver_core/value/
convert.rs

1// Copyright 2021 Datafuse Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use chrono::{
16    DateTime, Datelike, FixedOffset, LocalResult, NaiveDate, NaiveDateTime, TimeZone, Utc,
17};
18use chrono_tz::Tz;
19use std::collections::HashMap;
20use std::hash::Hash;
21
22use crate::error::{ConvertError, Error, Result};
23
24use super::{NumberValue, Value, DAYS_FROM_CE};
25use jiff::{tz::TimeZone as JiffTimeZone, Timestamp, Zoned};
26
27impl TryFrom<Value> for bool {
28    type Error = Error;
29    fn try_from(val: Value) -> Result<Self> {
30        match val {
31            Value::Boolean(b) => Ok(b),
32            Value::Number(n) => Ok(n != NumberValue::Int8(0)),
33            _ => Err(ConvertError::new("bool", format!("{val:?}")).into()),
34        }
35    }
36}
37
38// This macro implements TryFrom for NumberValue
39macro_rules! impl_try_from_number_value {
40    ($($t:ty),*) => {
41        $(
42            impl TryFrom<Value> for $t {
43                type Error = Error;
44                fn try_from(val: Value) -> Result<Self> {
45                    match val {
46                        Value::Number(NumberValue::Int8(i)) => Ok(i as $t),
47                        Value::Number(NumberValue::Int16(i)) => Ok(i as $t),
48                        Value::Number(NumberValue::Int32(i)) => Ok(i as $t),
49                        Value::Number(NumberValue::Int64(i)) => Ok(i as $t),
50                        Value::Number(NumberValue::UInt8(i)) => Ok(i as $t),
51                        Value::Number(NumberValue::UInt16(i)) => Ok(i as $t),
52                        Value::Number(NumberValue::UInt32(i)) => Ok(i as $t),
53                        Value::Number(NumberValue::UInt64(i)) => Ok(i as $t),
54                        Value::Number(NumberValue::Float32(i)) => Ok(i as $t),
55                        Value::Number(NumberValue::Float64(i)) => Ok(i as $t),
56                        Value::Date(i) => Ok(i as $t),
57                        _ => Err(ConvertError::new("number", format!("{:?}", val)).into()),
58                    }
59                }
60            }
61        )*
62    };
63}
64
65impl_try_from_number_value!(u8);
66impl_try_from_number_value!(u16);
67impl_try_from_number_value!(u32);
68impl_try_from_number_value!(u64);
69impl_try_from_number_value!(i8);
70impl_try_from_number_value!(i16);
71impl_try_from_number_value!(i32);
72impl_try_from_number_value!(i64);
73impl_try_from_number_value!(f32);
74impl_try_from_number_value!(f64);
75
76fn unix_micros_from_zoned(zdt: &Zoned) -> i64 {
77    zdt.timestamp().as_microsecond()
78}
79
80fn naive_datetime_from_micros(micros: i64) -> Result<NaiveDateTime> {
81    DateTime::<Utc>::from_timestamp_micros(micros)
82        .map(|dt| dt.naive_utc())
83        .ok_or_else(|| Error::Parsing(format!("invalid unix timestamp {micros}")))
84}
85
86pub fn zoned_to_chrono_datetime(zdt: &Zoned) -> Result<DateTime<Tz>> {
87    let tz_name = zdt.time_zone().iana_name().ok_or_else(|| {
88        ConvertError::new(
89            "DateTime",
90            "timestamp does not contain an IANA time zone".to_string(),
91        )
92    })?;
93    let tz: Tz = tz_name.parse().map_err(|_| {
94        ConvertError::new(
95            "DateTime",
96            format!("invalid time zone identifier {tz_name}"),
97        )
98    })?;
99    let micros = unix_micros_from_zoned(zdt);
100    match tz.timestamp_micros(micros) {
101        LocalResult::Single(dt) => Ok(dt),
102        LocalResult::Ambiguous(dt, _) => Ok(dt),
103        LocalResult::None => Err(Error::Parsing(format!(
104            "time {micros} not exists in timezone {tz_name}"
105        ))),
106    }
107}
108
109pub fn zoned_to_chrono_fixed_offset(zdt: &Zoned) -> Result<DateTime<FixedOffset>> {
110    let offset_seconds = zdt.offset().seconds();
111    let offset = FixedOffset::east_opt(offset_seconds)
112        .ok_or_else(|| Error::Parsing(format!("invalid offset {offset_seconds}")))?;
113    let micros = unix_micros_from_zoned(zdt);
114    let naive = naive_datetime_from_micros(micros)?;
115    Ok(DateTime::<FixedOffset>::from_naive_utc_and_offset(
116        naive, offset,
117    ))
118}
119
120fn zoned_from_naive_datetime(naive_dt: &NaiveDateTime) -> Zoned {
121    let micros = naive_dt.and_utc().timestamp_micros();
122    let timestamp = Timestamp::from_microsecond(micros)
123        .expect("NaiveDateTime out of range for Timestamp conversion");
124    timestamp.to_zoned(JiffTimeZone::UTC)
125}
126
127impl TryFrom<Value> for NaiveDateTime {
128    type Error = Error;
129    fn try_from(val: Value) -> Result<Self> {
130        match val {
131            Value::Timestamp(dt) => naive_datetime_from_micros(unix_micros_from_zoned(&dt)),
132            _ => Err(ConvertError::new("NaiveDateTime", format!("{val}")).into()),
133        }
134    }
135}
136
137impl TryFrom<Value> for DateTime<Tz> {
138    type Error = Error;
139    fn try_from(val: Value) -> Result<Self> {
140        match val {
141            Value::Timestamp(dt) => zoned_to_chrono_datetime(&dt),
142            _ => Err(ConvertError::new("DateTime", format!("{val}")).into()),
143        }
144    }
145}
146
147impl TryFrom<Value> for NaiveDate {
148    type Error = Error;
149    fn try_from(val: Value) -> Result<Self> {
150        match val {
151            Value::Date(i) => {
152                let days = i + DAYS_FROM_CE;
153                match NaiveDate::from_num_days_from_ce_opt(days) {
154                    Some(d) => Ok(d),
155                    None => Err(ConvertError::new("NaiveDate", "".to_string()).into()),
156                }
157            }
158            _ => Err(ConvertError::new("NaiveDate", format!("{val}")).into()),
159        }
160    }
161}
162
163impl<V> TryFrom<Value> for Vec<V>
164where
165    V: TryFrom<Value, Error = Error>,
166{
167    type Error = Error;
168    fn try_from(val: Value) -> Result<Self> {
169        match val {
170            Value::Binary(vals) => vals
171                .into_iter()
172                .map(|v| V::try_from(Value::Number(NumberValue::UInt8(v))))
173                .collect(),
174            Value::Array(vals) => vals.into_iter().map(V::try_from).collect(),
175            Value::EmptyArray => Ok(vec![]),
176            _ => Err(ConvertError::new("Vec", format!("{val}")).into()),
177        }
178    }
179}
180
181impl<K, V> TryFrom<Value> for HashMap<K, V>
182where
183    K: TryFrom<Value, Error = Error> + Eq + Hash,
184    V: TryFrom<Value, Error = Error>,
185{
186    type Error = Error;
187    fn try_from(val: Value) -> Result<Self> {
188        match val {
189            Value::Map(kvs) => {
190                let mut map = HashMap::new();
191                for (k, v) in kvs {
192                    let k = K::try_from(k)?;
193                    let v = V::try_from(v)?;
194                    map.insert(k, v);
195                }
196                Ok(map)
197            }
198            Value::EmptyMap => Ok(HashMap::new()),
199            _ => Err(ConvertError::new("HashMap", format!("{val}")).into()),
200        }
201    }
202}
203
204macro_rules! replace_expr {
205    ($_t:tt $sub:expr) => {
206        $sub
207    };
208}
209
210// This macro implements TryFrom for tuple of types
211macro_rules! impl_tuple_from_value {
212    ( $($Ti:tt),+ ) => {
213        impl<$($Ti),+> TryFrom<Value> for ($($Ti,)+)
214        where
215            $($Ti: TryFrom<Value>),+
216        {
217            type Error = String;
218            fn try_from(val: Value) -> Result<Self, String> {
219                // It is not possible yet to get the number of metavariable repetitions
220                // ref: https://github.com/rust-lang/lang-team/issues/28#issue-644523674
221                // This is a workaround
222                let expected_len = <[()]>::len(&[$(replace_expr!(($Ti) ())),*]);
223
224                match val {
225                    Value::Tuple(vals) => {
226                        if expected_len != vals.len() {
227                            return Err(format!("value tuple size mismatch: expected {} columns, got {}", expected_len, vals.len()));
228                        }
229                        let mut vals_iter = vals.into_iter().enumerate();
230
231                        Ok((
232                            $(
233                                {
234                                    let (col_ix, col_value) = vals_iter
235                                        .next()
236                                        .unwrap(); // vals_iter size is checked before this code is reached,
237                                                   // so it is safe to unwrap
238                                    let t = col_value.get_type();
239                                    $Ti::try_from(col_value)
240                                        .map_err(|_| format!("failed converting column {} from type({:?}) to type({})", col_ix, t, std::any::type_name::<$Ti>()))?
241                                }
242                            ,)+
243                        ))
244                    }
245                    _ => Err(format!("expected tuple, got {:?}", val)),
246                }
247            }
248        }
249    }
250}
251
252// Implement From Value for tuples of size up to 16
253impl_tuple_from_value!(T1);
254impl_tuple_from_value!(T1, T2);
255impl_tuple_from_value!(T1, T2, T3);
256impl_tuple_from_value!(T1, T2, T3, T4);
257impl_tuple_from_value!(T1, T2, T3, T4, T5);
258impl_tuple_from_value!(T1, T2, T3, T4, T5, T6);
259impl_tuple_from_value!(T1, T2, T3, T4, T5, T6, T7);
260impl_tuple_from_value!(T1, T2, T3, T4, T5, T6, T7, T8);
261impl_tuple_from_value!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
262impl_tuple_from_value!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
263impl_tuple_from_value!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
264impl_tuple_from_value!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
265impl_tuple_from_value!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
266impl_tuple_from_value!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
267impl_tuple_from_value!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
268impl_tuple_from_value!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
269impl_tuple_from_value!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17);
270impl_tuple_from_value!(
271    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18
272);
273impl_tuple_from_value!(
274    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19
275);
276impl_tuple_from_value!(
277    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20
278);
279impl_tuple_from_value!(
280    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21
281);
282impl_tuple_from_value!(
283    T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21,
284    T22
285);
286
287// This macro implements TryFrom to Option for Nullable column
288macro_rules! impl_try_from_to_option {
289    ($($t:ty),*) => {
290        $(
291            impl TryFrom<Value> for Option<$t> {
292                type Error = Error;
293                fn try_from(val: Value) -> Result<Self> {
294                    match val {
295                        Value::Null => Ok(None),
296                        _ => {
297                            let inner: $t = val.try_into()?;
298                            Ok(Some(inner))
299                        },
300                    }
301
302                }
303            }
304        )*
305    };
306}
307
308impl_try_from_to_option!(String);
309impl_try_from_to_option!(bool);
310impl_try_from_to_option!(u8);
311impl_try_from_to_option!(u16);
312impl_try_from_to_option!(u32);
313impl_try_from_to_option!(u64);
314impl_try_from_to_option!(i8);
315impl_try_from_to_option!(i16);
316impl_try_from_to_option!(i32);
317impl_try_from_to_option!(i64);
318impl_try_from_to_option!(f32);
319impl_try_from_to_option!(f64);
320impl_try_from_to_option!(NaiveDateTime);
321impl_try_from_to_option!(NaiveDate);
322
323impl From<&String> for Value {
324    fn from(s: &String) -> Self {
325        Value::String(s.clone())
326    }
327}
328
329impl From<String> for Value {
330    fn from(s: String) -> Self {
331        Value::String(s)
332    }
333}
334
335impl From<&str> for Value {
336    fn from(s: &str) -> Self {
337        Value::String(s.to_string())
338    }
339}
340
341impl From<bool> for Value {
342    fn from(b: bool) -> Self {
343        Value::Boolean(b)
344    }
345}
346
347impl From<&bool> for Value {
348    fn from(b: &bool) -> Self {
349        Value::Boolean(*b)
350    }
351}
352
353impl From<u8> for Value {
354    fn from(n: u8) -> Self {
355        Value::Number(NumberValue::UInt8(n))
356    }
357}
358
359impl From<&u8> for Value {
360    fn from(n: &u8) -> Self {
361        Value::Number(NumberValue::UInt8(*n))
362    }
363}
364
365impl From<u16> for Value {
366    fn from(n: u16) -> Self {
367        Value::Number(NumberValue::UInt16(n))
368    }
369}
370
371impl From<&u16> for Value {
372    fn from(n: &u16) -> Self {
373        Value::Number(NumberValue::UInt16(*n))
374    }
375}
376
377impl From<u32> for Value {
378    fn from(n: u32) -> Self {
379        Value::Number(NumberValue::UInt32(n))
380    }
381}
382
383impl From<&u32> for Value {
384    fn from(n: &u32) -> Self {
385        Value::Number(NumberValue::UInt32(*n))
386    }
387}
388
389impl From<u64> for Value {
390    fn from(n: u64) -> Self {
391        Value::Number(NumberValue::UInt64(n))
392    }
393}
394
395impl From<&u64> for Value {
396    fn from(n: &u64) -> Self {
397        Value::Number(NumberValue::UInt64(*n))
398    }
399}
400
401impl From<i8> for Value {
402    fn from(n: i8) -> Self {
403        Value::Number(NumberValue::Int8(n))
404    }
405}
406
407impl From<&i8> for Value {
408    fn from(n: &i8) -> Self {
409        Value::Number(NumberValue::Int8(*n))
410    }
411}
412
413impl From<i16> for Value {
414    fn from(n: i16) -> Self {
415        Value::Number(NumberValue::Int16(n))
416    }
417}
418
419impl From<&i16> for Value {
420    fn from(n: &i16) -> Self {
421        Value::Number(NumberValue::Int16(*n))
422    }
423}
424
425impl From<i32> for Value {
426    fn from(n: i32) -> Self {
427        Value::Number(NumberValue::Int32(n))
428    }
429}
430
431impl From<&i32> for Value {
432    fn from(n: &i32) -> Self {
433        Value::Number(NumberValue::Int32(*n))
434    }
435}
436
437impl From<i64> for Value {
438    fn from(n: i64) -> Self {
439        Value::Number(NumberValue::Int64(n))
440    }
441}
442
443impl From<&i64> for Value {
444    fn from(n: &i64) -> Self {
445        Value::Number(NumberValue::Int64(*n))
446    }
447}
448
449impl From<f32> for Value {
450    fn from(n: f32) -> Self {
451        Value::Number(NumberValue::Float32(n))
452    }
453}
454
455impl From<&f32> for Value {
456    fn from(n: &f32) -> Self {
457        Value::Number(NumberValue::Float32(*n))
458    }
459}
460
461impl From<f64> for Value {
462    fn from(n: f64) -> Self {
463        Value::Number(NumberValue::Float64(n))
464    }
465}
466
467impl From<NaiveDate> for Value {
468    fn from(date: NaiveDate) -> Self {
469        let days = date.num_days_from_ce() - DAYS_FROM_CE;
470        Value::Date(days)
471    }
472}
473
474impl From<&NaiveDate> for Value {
475    fn from(date: &NaiveDate) -> Self {
476        let days = date.num_days_from_ce() - DAYS_FROM_CE;
477        Value::Date(days)
478    }
479}
480
481impl From<NaiveDateTime> for Value {
482    fn from(naive_dt: NaiveDateTime) -> Self {
483        Value::Timestamp(zoned_from_naive_datetime(&naive_dt))
484    }
485}
486
487impl From<&NaiveDateTime> for Value {
488    fn from(naive_dt: &NaiveDateTime) -> Self {
489        Value::Timestamp(zoned_from_naive_datetime(naive_dt))
490    }
491}
492
493impl From<&f64> for Value {
494    fn from(n: &f64) -> Self {
495        Value::Number(NumberValue::Float64(*n))
496    }
497}