clickhouse_arrow/native/values/
bytes.rs

1use std::ops::{Deref, DerefMut};
2
3use crate::{FromSql, Result, ToSql, Type, Value, unexpected_type};
4
5/// Wrapper over [`Vec<u8>`] to allow more efficient serialization/deserialization of raw bytes
6/// The corresponding `ClickHouse` type here is [`Type::String`] or [`Type::FixedSizedString`], not
7/// [`Type::Array`]. Conversion to [`Type::Array(UInt8)`] will happen, but it is not efficient.
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct Bytes(pub Vec<u8>);
11
12impl ToSql for Bytes {
13    fn to_sql(self, type_hint: Option<&Type>) -> Result<Value> {
14        match type_hint {
15            Some(Type::Array(x)) if **x == Type::UInt8 || **x == Type::Int8 => Ok(Value::Array(
16                self.0
17                    .into_iter()
18                    .map(|byte| match &**x {
19                        Type::UInt8 => Value::UInt8(byte),
20                        #[expect(clippy::cast_possible_wrap)]
21                        Type::Int8 => Value::Int8(byte as i8),
22                        _ => unreachable!(),
23                    })
24                    .collect(),
25            )),
26            _ => Ok(Value::String(self.0)),
27        }
28    }
29}
30
31impl FromSql for Bytes {
32    fn from_sql(type_: &Type, value: Value) -> Result<Self> {
33        match type_ {
34            Type::String | Type::FixedSizedString(_) => match value {
35                Value::String(s) => Ok(Self(s)),
36                _ => unreachable!(),
37            },
38            Type::Array(x) if **x == Type::UInt8 || **x == Type::Int8 => match value {
39                Value::Array(values) => Ok(Self(
40                    values
41                        .into_iter()
42                        .map(|x| {
43                            Ok(match x {
44                                Value::UInt8(x) => x,
45                                #[expect(clippy::cast_sign_loss)]
46                                Value::Int8(x) => x as u8,
47                                _ => return Err(unexpected_type(&x.guess_type())),
48                            })
49                        })
50                        .collect::<Result<Vec<u8>>>()?,
51                )),
52                _ => unreachable!(),
53            },
54            _ => Err(unexpected_type(type_)),
55        }
56    }
57}
58
59impl Deref for Bytes {
60    type Target = Vec<u8>;
61
62    fn deref(&self) -> &Self::Target { &self.0 }
63}
64
65impl DerefMut for Bytes {
66    fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
67}
68
69impl From<Bytes> for Vec<u8> {
70    fn from(value: Bytes) -> Self { value.0 }
71}
72
73impl From<Vec<u8>> for Bytes {
74    fn from(value: Vec<u8>) -> Self { Self(value) }
75}