clickhouse_arrow/native/
values.rs

1mod bytes;
2mod clickhouse_uuid;
3mod date;
4#[cfg(feature = "rust_decimal")]
5mod decimal;
6mod fixed_point;
7mod geo;
8mod int256;
9mod ip;
10#[cfg(feature = "serde")]
11pub mod json;
12pub mod vec_tuple;
13
14#[cfg(test)]
15mod tests;
16
17use std::borrow::Cow;
18use std::fmt;
19use std::hash::Hash;
20
21pub use bytes::*;
22use chrono::{NaiveDate, SecondsFormat};
23use chrono_tz::Tz;
24pub use date::*;
25pub use fixed_point::*;
26pub use geo::*;
27pub use int256::*;
28pub use ip::*;
29
30use super::convert::{FromSql, ToSql, unexpected_type};
31use super::types::Type;
32use crate::Result;
33
34/// A raw `ClickHouse` value.
35/// Types are not strictly/completely preserved (i.e. types `Type::String` and `Type::FixedString`
36/// both are value `Type::String`). Use this if you want dynamically typed queries.
37#[derive(Clone)]
38#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
39pub enum Value {
40    Int8(i8),
41    Int16(i16),
42    Int32(i32),
43    Int64(i64),
44    Int128(i128),
45    Int256(i256),
46
47    UInt8(u8),
48    UInt16(u16),
49    UInt32(u32),
50    UInt64(u64),
51    UInt128(u128),
52    UInt256(u256),
53
54    Float32(f32),
55    Float64(f64),
56
57    Decimal32(usize, i32),
58    Decimal64(usize, i64),
59    Decimal128(usize, i128),
60    Decimal256(usize, i256),
61
62    String(Vec<u8>),
63
64    Uuid(::uuid::Uuid),
65
66    Date(Date),
67    Date32(Date32),
68    DateTime(DateTime),
69    DateTime64(DynDateTime64),
70
71    Enum8(String, i8),
72    Enum16(String, i16),
73    Array(Vec<Value>),
74
75    Tuple(Vec<Value>),
76
77    Null,
78
79    Map(Vec<Value>, Vec<Value>),
80
81    Ipv4(Ipv4),
82    Ipv6(Ipv6),
83
84    Point(Point),
85    Ring(Ring),
86    Polygon(Polygon),
87    MultiPolygon(MultiPolygon),
88
89    Object(Vec<u8>),
90}
91
92impl PartialEq for Value {
93    fn eq(&self, other: &Self) -> bool {
94        #[expect(clippy::match_same_arms)]
95        match (self, other) {
96            (Self::Int8(l0), Self::Int8(r0)) => l0 == r0,
97            (Self::Int16(l0), Self::Int16(r0)) => l0 == r0,
98            (Self::Int32(l0), Self::Int32(r0)) => l0 == r0,
99            (Self::Int64(l0), Self::Int64(r0)) => l0 == r0,
100            (Self::Int128(l0), Self::Int128(r0)) => l0 == r0,
101            (Self::Int256(l0), Self::Int256(r0)) => l0 == r0,
102            (Self::UInt8(l0), Self::UInt8(r0)) => l0 == r0,
103            (Self::UInt16(l0), Self::UInt16(r0)) => l0 == r0,
104            (Self::UInt32(l0), Self::UInt32(r0)) => l0 == r0,
105            (Self::UInt64(l0), Self::UInt64(r0)) => l0 == r0,
106            (Self::UInt128(l0), Self::UInt128(r0)) => l0 == r0,
107            (Self::UInt256(l0), Self::UInt256(r0)) => l0 == r0,
108            (Self::Float32(l0), Self::Float32(r0)) => l0.to_bits() == r0.to_bits(),
109            (Self::Float64(l0), Self::Float64(r0)) => l0.to_bits() == r0.to_bits(),
110            (Self::Decimal32(l0, l1), Self::Decimal32(r0, r1)) => l0 == r0 && l1 == r1,
111            (Self::Decimal64(l0, l1), Self::Decimal64(r0, r1)) => l0 == r0 && l1 == r1,
112            (Self::Decimal128(l0, l1), Self::Decimal128(r0, r1)) => l0 == r0 && l1 == r1,
113            (Self::Decimal256(l0, l1), Self::Decimal256(r0, r1)) => l0 == r0 && l1 == r1,
114            (Self::String(l0), Self::String(r0)) => l0 == r0,
115            (Self::Uuid(l0), Self::Uuid(r0)) => l0 == r0,
116            (Self::Date(l0), Self::Date(r0)) => l0 == r0,
117            (Self::Date32(l0), Self::Date32(r0)) => l0 == r0,
118            (Self::DateTime(l0), Self::DateTime(r0)) => l0 == r0,
119            (Self::DateTime64(l0), Self::DateTime64(r0)) => l0 == r0,
120            (Self::Enum8(v0, l0), Self::Enum8(v1, r0)) => l0 == r0 && v0 == v1,
121            (Self::Enum16(v0, l0), Self::Enum16(v1, r0)) => l0 == r0 && v0 == v1,
122            (Self::Array(l0), Self::Array(r0)) => l0 == r0,
123            (Self::Tuple(l0), Self::Tuple(r0)) => l0 == r0,
124            (Self::Map(l0, l1), Self::Map(r0, r1)) => l0 == r0 && l1 == r1,
125            (Self::Ipv4(l0), Self::Ipv4(r0)) => l0 == r0,
126            (Self::Ipv6(l0), Self::Ipv6(r0)) => l0 == r0,
127            (Self::Point(l0), Self::Point(r0)) => l0 == r0,
128            (Self::Ring(l0), Self::Ring(r0)) => l0 == r0,
129            (Self::Polygon(l0), Self::Polygon(r0)) => l0 == r0,
130            (Self::MultiPolygon(l0), Self::MultiPolygon(r0)) => l0 == r0,
131            _ => core::mem::discriminant(self) == core::mem::discriminant(other),
132        }
133    }
134}
135
136impl Hash for Value {
137    fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
138        Hash::hash(&core::mem::discriminant(self), state);
139        #[expect(clippy::match_same_arms)]
140        match self {
141            Value::Int8(x) => ::core::hash::Hash::hash(x, state),
142            Value::Int16(x) => ::core::hash::Hash::hash(x, state),
143            Value::Int32(x) => ::core::hash::Hash::hash(x, state),
144            Value::Int64(x) => ::core::hash::Hash::hash(x, state),
145            Value::Int128(x) => ::core::hash::Hash::hash(x, state),
146            Value::Int256(x) => ::core::hash::Hash::hash(x, state),
147            Value::UInt8(x) => ::core::hash::Hash::hash(x, state),
148            Value::UInt16(x) => ::core::hash::Hash::hash(x, state),
149            Value::UInt32(x) => ::core::hash::Hash::hash(x, state),
150            Value::UInt64(x) => ::core::hash::Hash::hash(x, state),
151            Value::UInt128(x) => ::core::hash::Hash::hash(x, state),
152            Value::UInt256(x) => ::core::hash::Hash::hash(x, state),
153            Value::Float32(x) => ::core::hash::Hash::hash(&x.to_bits(), state),
154            Value::Float64(x) => ::core::hash::Hash::hash(&x.to_bits(), state),
155            Value::Decimal32(x, __self_1) => {
156                ::core::hash::Hash::hash(x, state);
157                ::core::hash::Hash::hash(__self_1, state);
158            }
159            Value::Decimal64(x, __self_1) => {
160                ::core::hash::Hash::hash(x, state);
161                ::core::hash::Hash::hash(__self_1, state);
162            }
163            Value::Decimal128(x, __self_1) => {
164                ::core::hash::Hash::hash(x, state);
165                ::core::hash::Hash::hash(__self_1, state);
166            }
167            Value::Decimal256(x, __self_1) => {
168                ::core::hash::Hash::hash(x, state);
169                ::core::hash::Hash::hash(__self_1, state);
170            }
171            Value::String(x) => ::core::hash::Hash::hash(x, state),
172            Value::Object(x) => ::core::hash::Hash::hash(x, state),
173            Value::Uuid(x) => ::core::hash::Hash::hash(x, state),
174            Value::Date(x) => ::core::hash::Hash::hash(x, state),
175            Value::Date32(x) => ::core::hash::Hash::hash(x, state),
176            Value::DateTime(x) => ::core::hash::Hash::hash(x, state),
177            Value::DateTime64(x) => {
178                ::core::hash::Hash::hash(x, state);
179            }
180            Value::Enum8(_, x) => ::core::hash::Hash::hash(x, state),
181            Value::Enum16(_, x) => ::core::hash::Hash::hash(x, state),
182            Value::Array(x) => ::core::hash::Hash::hash(x, state),
183            Value::Tuple(x) => ::core::hash::Hash::hash(x, state),
184            Value::Map(x, __self_1) => {
185                ::core::hash::Hash::hash(x, state);
186                ::core::hash::Hash::hash(__self_1, state);
187            }
188            Value::Ipv4(x) => ::core::hash::Hash::hash(x, state),
189            Value::Ipv6(x) => ::core::hash::Hash::hash(x, state),
190
191            Value::Point(x) => ::core::hash::Hash::hash(x, state),
192            Value::Ring(x) => ::core::hash::Hash::hash(x, state),
193            Value::Polygon(x) => ::core::hash::Hash::hash(x, state),
194            Value::MultiPolygon(x) => ::core::hash::Hash::hash(x, state),
195
196            Value::Null => {}
197        }
198    }
199}
200
201impl Eq for Value {}
202
203impl Value {
204    pub fn string(value: impl Into<String>) -> Self { Value::String(value.into().into_bytes()) }
205
206    /// # Errors
207    /// Returns an error if the value is an unsigned integer.
208    pub(crate) fn index_value(&self) -> Result<usize> {
209        Ok(match self {
210            Value::UInt8(x) => *x as usize,
211            Value::UInt16(x) => *x as usize,
212            Value::UInt32(x) => *x as usize,
213            #[expect(clippy::cast_possible_truncation)]
214            Value::UInt64(x) => *x as usize,
215            _ => {
216                return Err(crate::errors::Error::Protocol(format!(
217                    "Expected integer, got {self}"
218                )));
219            }
220        })
221    }
222
223    /// # Errors
224    /// Returns an error if the value is not an array.
225    pub fn unwrap_array_ref(&self) -> Result<&[Value]> {
226        match self {
227            Value::Array(a) => Ok(&a[..]),
228            _ => Err(crate::errors::Error::Protocol(format!("Expected array, got {self}"))),
229        }
230    }
231
232    /// # Errors
233    /// Returns an error if the value is not an array.
234    pub fn unwrap_array(self) -> Result<Vec<Value>> {
235        match self {
236            Value::Array(a) => Ok(a),
237            _ => Err(crate::errors::Error::Protocol(format!("Expected array, got {self}"))),
238        }
239    }
240
241    /// # Errors
242    /// Returns an error if the value is not a tuple.
243    pub fn unwrap_tuple(self) -> Result<Vec<Value>> {
244        match self {
245            Value::Tuple(a) => Ok(a),
246            _ => Err(crate::errors::Error::Protocol(format!("Expected tuple, got {self}"))),
247        }
248    }
249
250    pub fn unarray(self) -> Option<Vec<Value>> {
251        match self {
252            Value::Array(a) => Some(a),
253            _ => None,
254        }
255    }
256
257    pub(crate) fn justify_null_ref<'a>(&'a self, type_: &Type) -> Cow<'a, Value> {
258        if self == &Value::Null { Cow::Owned(type_.default_value()) } else { Cow::Borrowed(self) }
259    }
260
261    /// Converts a [`Value`] to a `T` type by calling [`FromSql::from_sql`] on `T`.
262    ///
263    /// # Errors
264    /// Returns an error if the conversion fails.
265    pub fn to_value<T: FromSql>(self, type_: &Type) -> Result<T> { T::from_sql(type_, self) }
266
267    /// Converts a [`Value`] to a `T` type by calling [`ToSql::to_sql`] on `T`.
268    ///
269    /// # Errors
270    /// Returns an error if the conversion fails.
271    pub fn from_value<T: ToSql>(value: T) -> Result<Self> { value.to_sql(None) }
272
273    /// Guesses a [`Type`] from the value, may not correspond to actual column type in `ClickHouse`
274    pub fn guess_type(&self) -> Type {
275        match self {
276            Value::Int8(_) => Type::Int8,
277            Value::Int16(_) => Type::Int16,
278            Value::Int32(_) => Type::Int32,
279            Value::Int64(_) => Type::Int64,
280            Value::Int128(_) => Type::Int128,
281            Value::Int256(_) => Type::Int256,
282            Value::UInt8(_) => Type::UInt8,
283            Value::UInt16(_) => Type::UInt16,
284            Value::UInt32(_) => Type::UInt32,
285            Value::UInt64(_) => Type::UInt64,
286            Value::UInt128(_) => Type::UInt128,
287            Value::UInt256(_) => Type::UInt256,
288            Value::Float32(_) => Type::Float32,
289            Value::Float64(_) => Type::Float64,
290            Value::Decimal32(p, _) => Type::Decimal32(*p),
291            Value::Decimal64(p, _) => Type::Decimal64(*p),
292            Value::Decimal128(p, _) => Type::Decimal128(*p),
293            Value::Decimal256(p, _) => Type::Decimal256(*p),
294            Value::String(_) => Type::String,
295            Value::Uuid(_) => Type::Uuid,
296            Value::Date(_) => Type::Date,
297            Value::Date32(_) => Type::Date32,
298            Value::DateTime(time) => Type::DateTime(time.0),
299            Value::DateTime64(x) => Type::DateTime64(x.2, x.0),
300            Value::Enum8(_, i) => Type::Enum8(vec![(String::new(), *i)]),
301            Value::Enum16(_, i) => Type::Enum16(vec![(String::new(), *i)]),
302            Value::Array(x) => {
303                Type::Array(Box::new(x.first().map_or(Type::String, Value::guess_type)))
304            }
305            Value::Tuple(values) => Type::Tuple(values.iter().map(Value::guess_type).collect()),
306            Value::Null => Type::Nullable(Box::new(Type::String)),
307            Value::Map(k, v) => Type::Map(
308                Box::new(k.first().map_or(Type::String, Value::guess_type)),
309                Box::new(v.first().map_or(Type::String, Value::guess_type)),
310            ),
311            Value::Ipv4(_) => Type::Ipv4,
312            Value::Ipv6(_) => Type::Ipv6,
313
314            Value::Point(_) => Type::Point,
315            Value::Ring(_) => Type::Ring,
316            Value::Polygon(_) => Type::Polygon,
317            Value::MultiPolygon(_) => Type::MultiPolygon,
318            Value::Object(_) => Type::Object,
319        }
320    }
321}
322
323fn escape_string(f: &mut fmt::Formatter<'_>, from: impl AsRef<[u8]>) -> fmt::Result {
324    let from = from.as_ref();
325    for byte in from.iter().copied() {
326        if byte < 128 {
327            match byte {
328                b'\\' => write!(f, "\\\\")?,
329                b'\'' => write!(f, "\\'")?,
330                0x08 => write!(f, "\\b")?,
331                0x0C => write!(f, "\\f")?,
332                b'\r' => write!(f, "\\r")?,
333                b'\n' => write!(f, "\\n")?,
334                b'\t' => write!(f, "\\t")?,
335                b'\0' => write!(f, "\\0")?,
336                0x07 => write!(f, "\\a")?,
337                0x0B => write!(f, "\\v")?,
338                _ => write!(f, "{}", Into::<char>::into(byte))?,
339            }
340        } else {
341            write!(f, "\\x{byte:02X}")?;
342        }
343    }
344    Ok(())
345}
346
347impl fmt::Debug for Value {
348    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
349        <Self as fmt::Display>::fmt(self, f)
350    }
351}
352
353impl fmt::Display for Value {
354    #[expect(clippy::too_many_lines)]
355    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
356        #[expect(clippy::match_same_arms)]
357        match self {
358            Value::Int8(x) => write!(f, "{x}"),
359            Value::Int16(x) => write!(f, "{x}"),
360            Value::Int32(x) => write!(f, "{x}"),
361            Value::Int64(x) => write!(f, "{x}"),
362            Value::Int128(x) => write!(f, "{x}::Int128"),
363            Value::Int256(x) => write!(f, "{x}::Int256"),
364            Value::UInt8(x) => write!(f, "{x}"),
365            Value::UInt16(x) => write!(f, "{x}"),
366            Value::UInt32(x) => write!(f, "{x}"),
367            Value::UInt64(x) => write!(f, "{x}"),
368            Value::UInt128(x) => write!(f, "{x}::UInt128"),
369            Value::UInt256(x) => write!(f, "{x}::UInt256"),
370            Value::Float32(x) => write!(f, "{x}"),
371            Value::Float64(x) => write!(f, "{x}"),
372            Value::Decimal32(scale, value) => {
373                let raw_value = value.to_string();
374                if raw_value.len() < *scale {
375                    write!(f, "{raw_value}")
376                } else {
377                    let pre = &raw_value[..raw_value.len() - scale];
378                    let fraction = &raw_value[raw_value.len() - scale..];
379                    write!(f, "{pre}.{fraction}")
380                }
381            }
382            Value::Decimal64(scale, value) => {
383                let raw_value = value.to_string();
384                if raw_value.len() < *scale {
385                    write!(f, "{raw_value}")
386                } else {
387                    let pre = &raw_value[..raw_value.len() - scale];
388                    let fraction = &raw_value[raw_value.len() - scale..];
389                    write!(f, "{pre}.{fraction}")
390                }
391            }
392            Value::Decimal128(scale, value) => {
393                let raw_value = value.to_string();
394                if raw_value.len() < *scale {
395                    write!(f, "{raw_value}")
396                } else {
397                    let pre = &raw_value[..raw_value.len() - scale];
398                    let fraction = &raw_value[raw_value.len() - scale..];
399                    write!(f, "{pre}.{fraction}")
400                }
401            }
402            Value::Decimal256(scale, value) => {
403                let raw_value = value.to_string();
404                if raw_value.len() < *scale {
405                    write!(f, "{raw_value}")
406                } else {
407                    let pre = &raw_value[..raw_value.len() - scale];
408                    let fraction = &raw_value[raw_value.len() - scale..];
409                    write!(f, "{pre}.{fraction}")
410                }
411            }
412            Value::String(string) => {
413                write!(f, "'")?;
414                escape_string(f, string)?;
415                write!(f, "'")
416            }
417            Value::Uuid(uuid) => {
418                write!(f, "'{uuid}'")
419            }
420            Value::Date(date) => {
421                let chrono_date: NaiveDate = (*date).into();
422                write!(f, "'{}'", chrono_date.format("makeDate(%Y-%m-%d)"))
423            }
424            Value::Date32(date) => {
425                let chrono_date: NaiveDate = (*date).into();
426                write!(f, "'{}'", chrono_date.format("makeDate(%Y-%m-%d)"))
427            }
428            Value::DateTime(datetime) => {
429                let chrono_date: chrono::DateTime<Tz> =
430                    (*datetime).try_into().map_err(|_| fmt::Error)?;
431                let string = chrono_date.to_rfc3339_opts(SecondsFormat::AutoSi, true);
432                write!(f, "parseDateTimeBestEffort('")?;
433                escape_string(f, &string)?;
434                write!(f, "')")
435            }
436            Value::DateTime64(datetime) => {
437                let chrono_date: chrono::DateTime<Tz> =
438                    FromSql::from_sql(&Type::DateTime64(datetime.2, datetime.0), self.clone())
439                        .map_err(|_| fmt::Error)?;
440                let string = chrono_date.to_rfc3339_opts(SecondsFormat::AutoSi, true);
441                write!(f, "parseDateTime64BestEffort('")?;
442                escape_string(f, &string)?;
443                write!(f, "', {})", datetime.2)
444            }
445            Value::Enum8(x, _) => write!(f, "{x}"),
446            Value::Enum16(x, _) => write!(f, "{x}"),
447            Value::Array(array) => {
448                write!(f, "[")?;
449                if let Some(item) = array.first() {
450                    write!(f, "{item}")?;
451                }
452                for item in array.iter().skip(1) {
453                    write!(f, ",{item}")?;
454                }
455                write!(f, "]")
456            }
457            Value::Tuple(tuple) => {
458                write!(f, "(")?;
459                if let Some(item) = tuple.first() {
460                    write!(f, "{item}")?;
461                }
462                for item in tuple.iter().skip(1) {
463                    write!(f, ",{item}")?;
464                }
465                write!(f, ")")
466            }
467            Value::Null => write!(f, "NULL"),
468            Value::Map(keys, values) => {
469                assert_eq!(keys.len(), values.len());
470                write!(f, "{{")?;
471                let mut iter = keys.iter().zip(values.iter());
472                if let Some((key, value)) = iter.next() {
473                    write!(f, "{key}:{value}")?;
474                }
475                for (key, value) in iter {
476                    write!(f, ",{key}:{value}")?;
477                }
478                write!(f, "}}")
479            }
480            Value::Ipv4(ipv4) => write!(f, "'{ipv4}'"),
481            Value::Ipv6(ipv6) => write!(f, "'{ipv6}'"),
482            Value::Point(x) => write!(f, "{x:?}"),
483            Value::Ring(x) => write!(f, "{x:?}"),
484            Value::Polygon(x) => write!(f, "{x:?}"),
485            Value::MultiPolygon(x) => write!(f, "{x:?}"),
486            Value::Object(x) => {
487                write!(f, "'")?;
488                let obj_str = std::str::from_utf8(x).ok();
489                #[cfg(not(feature = "serde"))]
490                {
491                    if let Some(x) = obj_str {
492                        escape_string(f, x)?;
493                    }
494                }
495                #[cfg(feature = "serde")]
496                {
497                    if let Some(x) = serde_json::from_slice(x).unwrap_or(obj_str) {
498                        escape_string(f, x)?;
499                    }
500                }
501                write!(f, "'")
502            }
503        }
504    }
505}