klickhouse/convert/
std_serialize.rs

1use std::{
2    any::TypeId,
3    collections::{BTreeMap, HashMap},
4};
5
6use indexmap::IndexMap;
7
8use super::*;
9
10impl ToSql for u8 {
11    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
12        Ok(Value::UInt8(self))
13    }
14}
15
16impl ToSql for bool {
17    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
18        Ok(Value::UInt8(self as u8))
19    }
20}
21
22impl ToSql for u16 {
23    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
24        Ok(Value::UInt16(self))
25    }
26}
27
28impl ToSql for u32 {
29    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
30        Ok(Value::UInt32(self))
31    }
32}
33
34impl ToSql for u64 {
35    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
36        Ok(Value::UInt64(self))
37    }
38}
39
40impl ToSql for u128 {
41    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
42        Ok(Value::UInt128(self))
43    }
44}
45
46impl ToSql for i8 {
47    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
48        Ok(Value::Int8(self))
49    }
50}
51
52impl ToSql for i16 {
53    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
54        Ok(Value::Int16(self))
55    }
56}
57
58impl ToSql for i32 {
59    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
60        Ok(Value::Int32(self))
61    }
62}
63
64impl ToSql for i64 {
65    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
66        Ok(Value::Int64(self))
67    }
68}
69
70impl ToSql for i128 {
71    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
72        Ok(Value::Int128(self))
73    }
74}
75
76impl ToSql for f32 {
77    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
78        Ok(Value::Float32(self))
79    }
80}
81
82impl ToSql for f64 {
83    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
84        Ok(Value::Float64(self))
85    }
86}
87
88impl ToSql for String {
89    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
90        Ok(Value::String(self.into_bytes()))
91    }
92}
93
94impl ToSql for &str {
95    fn to_sql(self, _type_hint: Option<&Type>) -> Result<Value> {
96        Ok(Value::String(self.as_bytes().to_vec()))
97    }
98}
99
100impl<T: ToSql + 'static> ToSql for Vec<T> {
101    fn to_sql(self, type_hint: Option<&Type>) -> Result<Value> {
102        let type_hint = type_hint
103            .and_then(|x| x.unarray())
104            .map(|x| x.strip_low_cardinality());
105        if matches!(type_hint, Some(Type::String) | Some(Type::FixedString(_))) {
106            let type_id = TypeId::of::<T>();
107            if type_id == TypeId::of::<u8>() || type_id == TypeId::of::<i8>() {
108                assert_eq!(std::mem::size_of::<T>(), 1);
109                return Ok(Value::String(unsafe {
110                    std::mem::transmute::<Vec<T>, Vec<u8>>(self)
111                }));
112            }
113        }
114        Ok(Value::Array(
115            self.into_iter()
116                .map(|x| x.to_sql(type_hint))
117                .collect::<Result<Vec<_>>>()?,
118        ))
119    }
120}
121
122impl<T: ToSql, Y: ToSql> ToSql for HashMap<T, Y> {
123    fn to_sql(self, type_hint: Option<&Type>) -> Result<Value> {
124        let mut keys = Vec::with_capacity(self.len());
125        let mut values = Vec::with_capacity(self.len());
126        let type_hint = type_hint.and_then(|x| x.unmap());
127        for (key, value) in self {
128            keys.push(key.to_sql(type_hint.map(|x| x.0))?);
129            values.push(value.to_sql(type_hint.map(|x| x.1))?);
130        }
131        Ok(Value::Map(keys, values))
132    }
133}
134
135impl<T: ToSql, Y: ToSql> ToSql for BTreeMap<T, Y> {
136    fn to_sql(self, type_hint: Option<&Type>) -> Result<Value> {
137        let mut keys = Vec::with_capacity(self.len());
138        let mut values = Vec::with_capacity(self.len());
139        let type_hint = type_hint.and_then(|x| x.unmap());
140        for (key, value) in self {
141            keys.push(key.to_sql(type_hint.map(|x| x.0))?);
142            values.push(value.to_sql(type_hint.map(|x| x.1))?);
143        }
144        Ok(Value::Map(keys, values))
145    }
146}
147
148impl<T: ToSql, Y: ToSql> ToSql for IndexMap<T, Y> {
149    fn to_sql(self, type_hint: Option<&Type>) -> Result<Value> {
150        let mut keys = Vec::with_capacity(self.len());
151        let mut values = Vec::with_capacity(self.len());
152        let type_hint = type_hint.and_then(|x| x.unmap());
153        for (key, value) in self {
154            keys.push(key.to_sql(type_hint.map(|x| x.0))?);
155            values.push(value.to_sql(type_hint.map(|x| x.1))?);
156        }
157        Ok(Value::Map(keys, values))
158    }
159}
160
161impl<T: ToSql> ToSql for Option<T> {
162    fn to_sql(self, type_hint: Option<&Type>) -> Result<Value> {
163        match self {
164            Some(x) => Ok(x.to_sql(type_hint.and_then(|x| x.unnull()))?),
165            None => Ok(Value::Null),
166        }
167    }
168}
169
170impl<T: ToSql, const N: usize> ToSql for [T; N] {
171    fn to_sql(self, type_hint: Option<&Type>) -> Result<Value> {
172        let type_hint = type_hint
173            .and_then(|x| x.unarray())
174            .map(|x| x.strip_low_cardinality());
175        Ok(Value::Array(
176            IntoIterator::into_iter(self)
177                .map(|x| x.to_sql(type_hint))
178                .collect::<Result<Vec<_>>>()?,
179        ))
180    }
181}
182
183impl<T: ToSql + Clone> ToSql for &T {
184    fn to_sql(self, type_hint: Option<&Type>) -> Result<Value> {
185        self.clone().to_sql(type_hint)
186    }
187}
188
189impl<T: ToSql + Clone> ToSql for &mut T {
190    fn to_sql(self, type_hint: Option<&Type>) -> Result<Value> {
191        self.clone().to_sql(type_hint)
192    }
193}
194
195impl<T: ToSql> ToSql for Box<T> {
196    fn to_sql(self, type_hint: Option<&Type>) -> Result<Value> {
197        (*self).to_sql(type_hint)
198    }
199}
200
201macro_rules! tuple_impls {
202    ($($len:expr => ($($n:tt $name:ident)+))+) => {
203        $(
204            impl<$($name: ToSql),+> ToSql for ($($name,)+) {
205                fn to_sql(self, type_hint: Option<&Type>) -> Result<Value> {
206                    let type_hint = type_hint.and_then(|x| x.untuple());
207
208                    Ok(Value::Tuple(vec![
209                        $(
210                            self.$n.to_sql(type_hint.and_then(|x| x.get($n)))?,
211                        )+
212                    ]))
213                }
214            }
215        )+
216    }
217}
218
219tuple_impls! {
220    1 => (0 T0)
221    2 => (0 T0 1 T1)
222    3 => (0 T0 1 T1 2 T2)
223    4 => (0 T0 1 T1 2 T2 3 T3)
224    5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
225    6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
226    7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
227    8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
228    9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
229    10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
230    11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
231    12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
232    13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12)
233    14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13)
234    15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14)
235    16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15)
236}