clickhouse_client/value/
mod.rs

1//! Data types
2
3mod core;
4mod ext;
5mod ty;
6
7#[cfg(test)]
8mod tests;
9
10pub use core::*;
11pub use ext::*;
12pub use ty::*;
13
14use std::collections::HashMap;
15
16use ::time::{Date, OffsetDateTime};
17use ::uuid::Uuid;
18use ethnum::{I256, U256};
19
20use crate::error::Error;
21use ext::time::{DateExt, DateTimeExt};
22
23/// Trait to represent a Clickhouse value
24pub trait ChValue: Sized {
25    /// Returns the Clickhouse type
26    fn ch_type() -> Type;
27
28    /// Returns the Clickhouse value
29    fn into_ch_value(self) -> Value;
30
31    /// Parses from a [Value]
32    fn from_ch_value(value: Value) -> Result<Self, Error>;
33
34    /// Converts to an SQL value
35    fn into_sql(self) -> String {
36        self.into_ch_value().to_sql_string()
37    }
38}
39
40// derive the Into<Value> implementation
41impl<T> From<T> for Value
42where
43    T: ChValue,
44{
45    fn from(value: T) -> Self {
46        value.into_ch_value()
47    }
48}
49
50/// Clickhouse field value
51#[derive(Debug, Clone, PartialEq)]
52pub enum Value {
53    /// u8
54    UInt8(u8),
55    /// u16
56    UInt16(u16),
57    /// u32
58    UInt32(u32),
59    /// u64
60    UInt64(u64),
61    /// u128
62    UInt128(u128),
63    /// u256
64    UInt256([u128; 2]),
65    /// i8
66    Int8(i8),
67    /// i16
68    Int16(i16),
69    /// i32
70    Int32(i32),
71    /// i64
72    Int64(i64),
73    /// i128
74    Int128(i128),
75    /// i256
76    Int256([i128; 2]),
77    /// f32
78    Float32(f32),
79    /// f64
80    Float64(f64),
81    // > decimals
82    // Decimal(p,s)
83    // Decimal32(i32),
84    // Decimal64(i64),
85    // Decimal128(i128),
86    /// bool
87    Bool(bool),
88    /// string
89    String(String),
90    /// UUID
91    UUID([u8; 16]),
92    /// Number of days since 01-01-1970
93    Date(u16),
94    /// Number of days since 01-01-1970 (signed int)
95    Date32(i32),
96    /// Number of seconds since 01-01-1970
97    DateTime(u32),
98    /// Number of nanosecs since 01-01-1970
99    DateTime64(i64),
100    /// Enum8
101    Enum8(i8),
102    /// Enum16
103    Enum16(i16),
104    /// Array
105    Array(Vec<Value>),
106    /// Tuple
107    Tuple(Vec<Value>),
108    /// Map
109    Map(HashMap<String, Value>),
110    /// Nested
111    Nested(HashMap<String, Value>),
112    /// Nullable u8
113    NullableUInt8(Option<u8>),
114    /// Nullable u16
115    NullableUInt16(Option<u16>),
116    /// Nullable u32
117    NullableUInt32(Option<u32>),
118    /// Nullable u64
119    NullableUInt64(Option<u64>),
120    /// Nullable u128
121    NullableUInt128(Option<u128>),
122    /// Nullable u256
123    NullableUInt256(Option<[u128; 2]>),
124    /// Nullable i8
125    NullableInt8(Option<i8>),
126    /// Nullable i16
127    NullableInt16(Option<i16>),
128    /// Nullable i32
129    NullableInt32(Option<i32>),
130    /// Nullable i64
131    NullableInt64(Option<i64>),
132    /// Nullable i128
133    NullableInt128(Option<i128>),
134    /// Nullable i258
135    NullableInt256(Option<[i128; 2]>),
136    /// Nullable f32
137    NullableFloat32(Option<f32>),
138    /// Nullable f64
139    NullableFloat64(Option<f64>),
140    // > decimal
141    // NullableDecimal32(Option<i32>),
142    // NullableDecimal64(Option<i64>),
143    // NullableDecimal128(Option<i128>),
144    /// Nullable bool
145    NullableBool(Option<bool>),
146    /// Nullable string
147    NullableString(Option<String>),
148    /// Nullable UUID
149    NullableUUID(Option<[u8; 16]>),
150    /// Nullable date
151    NullableDate(Option<u16>),
152    /// Nullable date32
153    NullableDate32(Option<i32>),
154    /// Nullable datetime
155    NullableDateTime(Option<u32>),
156    /// Nullable datetime64
157    NullableDateTime64(Option<i64>),
158    /// Nullable Enum8
159    NullableEnum8(Option<i8>),
160    /// Nullable Enum16
161    NullableEnum16(Option<i16>),
162}
163
164impl Value {
165    /// Tries to convert a [Value] into a specific type T
166    pub fn try_into<T>(self) -> Result<T, Error>
167    where
168        T: ChValue,
169    {
170        T::from_ch_value(self)
171    }
172
173    /// Checks if a [Value] corresponds to a type
174    pub fn is_same_type_as(&self, ty: &Type) -> bool {
175        match self {
176            Value::UInt8(_) => matches!(ty, Type::UInt8),
177            Value::UInt16(_) => matches!(ty, Type::UInt16),
178            Value::UInt32(_) => matches!(ty, Type::UInt32),
179            Value::UInt64(_) => matches!(ty, Type::UInt64),
180            Value::UInt128(_) => matches!(ty, Type::UInt128),
181            Value::UInt256(_) => matches!(ty, Type::UInt256),
182            Value::Int8(_) => matches!(ty, Type::Int8),
183            Value::Int16(_) => matches!(ty, Type::Int16),
184            Value::Int32(_) => matches!(ty, Type::Int32),
185            Value::Int64(_) => matches!(ty, Type::Int64),
186            Value::Int128(_) => matches!(ty, Type::Int128),
187            Value::Int256(_) => matches!(ty, Type::Int256),
188            Value::Float32(_) => matches!(ty, Type::Float32),
189            Value::Float64(_) => matches!(ty, Type::Float64),
190            Value::Bool(_) => matches!(ty, Type::Bool),
191            Value::String(_) => matches!(ty, Type::String),
192            Value::UUID(_) => matches!(ty, Type::UUID),
193            Value::Date(_) => matches!(ty, Type::Date),
194            Value::Date32(_) => matches!(ty, Type::Date32),
195            Value::DateTime(_) => matches!(ty, Type::DateTime),
196            Value::DateTime64(_) => matches!(ty, Type::DateTime64(_)),
197            Value::Enum8(i) => match ty {
198                Type::Enum8(variants) => variants.values().any(|v| v == i),
199                _ => false,
200            },
201            Value::Enum16(i) => match ty {
202                Type::Enum16(variants) => variants.values().any(|v| v == i),
203                _ => false,
204            },
205            Value::Array(values) => match ty {
206                Type::Array(arr_ty) => values.iter().all(|v| v.is_same_type_as(arr_ty.as_ref())),
207                _ => false,
208            },
209            Value::Tuple(values) => match ty {
210                Type::Tuple(types) => {
211                    if values.len() != types.len() {
212                        return false;
213                    }
214                    values.iter().zip(types).all(|(n, t)| n.is_same_type_as(t))
215                }
216                _ => false,
217            },
218            Value::Map(map) => match ty {
219                Type::Map(_key_ty, val_ty) => {
220                    map.values().all(|v| v.is_same_type_as(val_ty.as_ref()))
221                }
222                _ => false,
223            },
224            Value::Nested(values) => match ty {
225                Type::Nested(fields) => {
226                    let keys = fields.iter().map(|(k, _v)| k.as_str()).collect::<Vec<_>>();
227                    values.keys().all(|k| keys.contains(&k.as_str()))
228                        && values
229                            .iter()
230                            .zip(fields)
231                            .all(|((_, v), (_, t))| v.is_same_type_as(t))
232                }
233                _ => false,
234            },
235            Value::NullableUInt8(_) => matches!(ty, Type::NullableUInt8),
236            Value::NullableUInt16(_) => matches!(ty, Type::NullableUInt16),
237            Value::NullableUInt32(_) => matches!(ty, Type::NullableUInt32),
238            Value::NullableUInt64(_) => matches!(ty, Type::NullableUInt64),
239            Value::NullableUInt128(_) => matches!(ty, Type::NullableUInt128),
240            Value::NullableUInt256(_) => matches!(ty, Type::NullableUInt256),
241            Value::NullableInt8(_) => matches!(ty, Type::NullableInt8),
242            Value::NullableInt16(_) => matches!(ty, Type::NullableInt16),
243            Value::NullableInt32(_) => matches!(ty, Type::NullableInt32),
244            Value::NullableInt64(_) => matches!(ty, Type::NullableInt64),
245            Value::NullableInt128(_) => matches!(ty, Type::NullableInt128),
246            Value::NullableInt256(_) => matches!(ty, Type::NullableInt256),
247            Value::NullableFloat32(_) => matches!(ty, Type::NullableFloat32),
248            Value::NullableFloat64(_) => matches!(ty, Type::NullableFloat64),
249            Value::NullableBool(_) => matches!(ty, Type::NullableBool),
250            Value::NullableString(_) => matches!(ty, Type::NullableString),
251            Value::NullableUUID(_) => matches!(ty, Type::NullableUUID),
252            Value::NullableDate(_) => matches!(ty, Type::NullableDate),
253            Value::NullableDate32(_) => matches!(ty, Type::NullableDate32),
254            Value::NullableDateTime(_) => matches!(ty, Type::NullableDateTime),
255            Value::NullableDateTime64(_) => matches!(ty, Type::NullableDateTime64(_)),
256            Value::NullableEnum8(_) => matches!(ty, Type::NullableEnum8(_)),
257            Value::NullableEnum16(_) => matches!(ty, Type::NullableEnum16(_)),
258        }
259    }
260
261    /// Returns the nullable variant of a value
262    pub(crate) fn into_nullable(self) -> Option<Value> {
263        match self {
264            Value::UInt8(v) => Some(Value::NullableUInt8(Some(v))),
265            Value::UInt16(v) => Some(Value::NullableUInt16(Some(v))),
266            Value::UInt32(v) => Some(Value::NullableUInt32(Some(v))),
267            Value::UInt64(v) => Some(Value::NullableUInt64(Some(v))),
268            Value::UInt128(v) => Some(Value::NullableUInt128(Some(v))),
269            Value::UInt256(v) => Some(Value::NullableUInt256(Some(v))),
270            Value::Int8(v) => Some(Value::NullableInt8(Some(v))),
271            Value::Int16(v) => Some(Value::NullableInt16(Some(v))),
272            Value::Int32(v) => Some(Value::NullableInt32(Some(v))),
273            Value::Int64(v) => Some(Value::NullableInt64(Some(v))),
274            Value::Int128(v) => Some(Value::NullableInt128(Some(v))),
275            Value::Int256(v) => Some(Value::NullableInt256(Some(v))),
276            Value::Float32(v) => Some(Value::NullableFloat32(Some(v))),
277            Value::Float64(v) => Some(Value::NullableFloat64(Some(v))),
278            Value::Bool(v) => Some(Value::NullableBool(Some(v))),
279            Value::String(v) => Some(Value::NullableString(Some(v))),
280            Value::UUID(v) => Some(Value::NullableUUID(Some(v))),
281            Value::Date(v) => Some(Value::NullableDate(Some(v))),
282            Value::Date32(v) => Some(Value::NullableDate32(Some(v))),
283            Value::DateTime(v) => Some(Value::NullableDateTime(Some(v))),
284            Value::DateTime64(v) => Some(Value::NullableDateTime64(Some(v))),
285            Value::Enum8(v) => Some(Value::NullableEnum8(Some(v))),
286            Value::Enum16(v) => Some(Value::NullableEnum16(Some(v))),
287            Value::Array(_) => None,
288            Value::Tuple(_) => None,
289            Value::Map(_) => None,
290            Value::Nested(_) => None,
291            // > nullable
292            _ => Some(self),
293        }
294    }
295}
296
297impl std::fmt::Display for Value {
298    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
299        /// Implements the nullable variant for formatting
300        macro_rules! impl_nullable {
301            ($VAL:expr, $VAR:ident) => {
302                match $VAL {
303                    Some(v) => Value::$VAR(v).to_string(),
304                    None => "NULL".to_string(),
305                }
306            };
307        }
308
309        let s = match self {
310            Value::UInt8(v) => v.to_string(),
311            Value::UInt16(v) => v.to_string(),
312            Value::UInt32(v) => v.to_string(),
313            Value::UInt64(v) => v.to_string(),
314            Value::UInt128(v) => v.to_string(),
315            Value::UInt256(_) => {
316                let u256 = self.clone().try_into::<U256>().unwrap();
317                u256.to_string()
318            }
319            Value::Int8(v) => v.to_string(),
320            Value::Int16(v) => v.to_string(),
321            Value::Int32(v) => v.to_string(),
322            Value::Int64(v) => v.to_string(),
323            Value::Int128(v) => v.to_string(),
324            Value::Int256(_) => {
325                let i256 = self.clone().try_into::<I256>().unwrap();
326                i256.to_string()
327            }
328            Value::Float32(v) => v.to_string(),
329            Value::Float64(v) => v.to_string(),
330            Value::Bool(v) => v.to_string(),
331            Value::String(v) => v.to_string(),
332            Value::UUID(_) => {
333                let uuid = self.clone().try_into::<Uuid>().unwrap();
334                uuid.to_string()
335            }
336            Value::Date(_) | Value::Date32(_) => {
337                let date = self.clone().try_into::<Date>().unwrap();
338                date.format_yyyy_mm_dd()
339            }
340            Value::DateTime(_) => {
341                let dt = self.clone().try_into::<OffsetDateTime>().unwrap();
342                dt.format_yyyy_mm_dd_hh_mm_ss()
343            }
344            Value::DateTime64(_) => {
345                let dt = self.clone().try_into::<OffsetDateTime>().unwrap();
346                dt.format_yyyy_mm_dd_hh_mm_ss_ns()
347            }
348            Value::Enum8(v) => v.to_string(),
349            Value::Enum16(v) => v.to_string(),
350            Value::Array(v) => {
351                format!(
352                    "[{}]",
353                    v.iter()
354                        .map(|v| v.to_string())
355                        .collect::<Vec<_>>()
356                        .join(", ")
357                )
358            }
359            Value::Tuple(v) => {
360                format!(
361                    "({})",
362                    v.iter()
363                        .map(|v| v.to_string())
364                        .collect::<Vec<_>>()
365                        .join(", ")
366                )
367            }
368            Value::Map(v) => {
369                format!(
370                    "{{{}}}",
371                    v.iter()
372                        .map(|(k, v)| format!("{}: {}", k, v))
373                        .collect::<Vec<_>>()
374                        .join(", ")
375                )
376            }
377            Value::Nested(v) => {
378                format!(
379                    "{{{}}}",
380                    v.iter()
381                        .map(|(k, v)| format!("{}: {}", k, v))
382                        .collect::<Vec<String>>()
383                        .join(", ")
384                )
385            }
386            Value::NullableUInt8(v) => impl_nullable!(*v, UInt8),
387            Value::NullableUInt16(v) => impl_nullable!(*v, UInt16),
388            Value::NullableUInt32(v) => impl_nullable!(*v, UInt32),
389            Value::NullableUInt64(v) => impl_nullable!(*v, UInt64),
390            Value::NullableUInt128(v) => impl_nullable!(*v, UInt128),
391            Value::NullableUInt256(v) => impl_nullable!(*v, UInt256),
392            Value::NullableInt8(v) => impl_nullable!(*v, Int8),
393            Value::NullableInt16(v) => impl_nullable!(*v, Int16),
394            Value::NullableInt32(v) => impl_nullable!(*v, Int32),
395            Value::NullableInt64(v) => impl_nullable!(*v, Int64),
396            Value::NullableInt128(v) => impl_nullable!(*v, Int128),
397            Value::NullableInt256(v) => impl_nullable!(*v, Int256),
398            Value::NullableFloat32(v) => impl_nullable!(*v, Float32),
399            Value::NullableFloat64(v) => impl_nullable!(*v, Float64),
400            Value::NullableBool(v) => impl_nullable!(*v, Bool),
401            Value::NullableString(v) => impl_nullable!(v.clone(), String),
402            Value::NullableUUID(v) => impl_nullable!(*v, UUID),
403            Value::NullableDate(v) => impl_nullable!(*v, Date),
404            Value::NullableDate32(v) => impl_nullable!(*v, Date32),
405            Value::NullableDateTime(v) => impl_nullable!(*v, DateTime),
406            Value::NullableDateTime64(v) => impl_nullable!(*v, DateTime64),
407            Value::NullableEnum8(v) => impl_nullable!(*v, Enum8),
408            Value::NullableEnum16(v) => impl_nullable!(*v, Enum16),
409        };
410
411        write!(f, "{s}")
412    }
413}