Skip to main content

clickhouse_utils/
serde.rs

1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2
3#[cfg(feature = "fastnum")]
4pub mod fastnum {
5    use super::*;
6
7    #[cfg(feature = "fastnum")]
8    use ::fastnum::{
9        bint::UInt,
10        decimal::{Context, Decimal as FastnumDecimal, Sign},
11    };
12
13    pub struct Decimal<const E: i16, const S: usize>;
14
15    /// Serde serializer/deserializer for fastnum::decimal with a clickhouse Decimal<FIXED_EXPONENT, N>
16    ///
17    /// N is the number of internal 64 bits words, for example a D256 is a Decimal<X, 4>  
18    /// DECIMAL_PLACE is the number of digits after the decimal point
19    #[cfg(feature = "fastnum")]
20    impl<const DECIMAL_PLACE: i16, const N: usize> Decimal<DECIMAL_PLACE, N> {
21        pub fn deserialize<'de, D>(deserializer: D) -> Result<FastnumDecimal<N>, D::Error>
22        where
23            D: Deserializer<'de>,
24        {
25            let mut uint: UInt<N> = Deserialize::deserialize(deserializer)?;
26
27            // We receive the number scaled to the fixed exponent defined in the schema
28            uint /= UInt::from_u16(10u16).pow((DECIMAL_PLACE as u16).into());
29
30            let value = FastnumDecimal::from_parts(
31                UInt::from_le(uint),
32                -DECIMAL_PLACE as i32,
33                Sign::Plus,
34                Context::default(),
35            );
36            Ok(value)
37        }
38
39        pub fn serialize<S: Serializer>(
40            value: &FastnumDecimal<N>,
41            serializer: S,
42        ) -> Result<S::Ok, S::Error> {
43            // Scale the value to match the fixed exponent defined in the schema
44            let mut value = value.rescale(DECIMAL_PLACE);
45            // Transform the fractional part to have significant zeros, so we have them in the value.digits()
46            value *= FastnumDecimal::from_u16(10u16).pow((DECIMAL_PLACE as u16).into());
47
48            value.digits().serialize(serializer)
49        }
50    }
51}
52
53/// Serde serializer/deserializer for HashMap<String, String> for a clickhouse Map(String, String)
54pub mod map {
55    use std::collections::HashMap;
56
57    use super::*;
58
59    pub fn serialize<S: Serializer>(
60        value: &HashMap<String, String>,
61        serializer: S,
62    ) -> Result<S::Ok, S::Error> {
63        // Clickhouse expects a Vec<(String, String)> for maps
64        let value: Vec<(String, String)> = value.clone().into_iter().collect();
65        value.serialize(serializer)
66    }
67
68    pub fn deserialize<'de, D>(deserializer: D) -> Result<HashMap<String, String>, D::Error>
69    where
70        D: Deserializer<'de>,
71    {
72        let value: Vec<(String, String)> = Deserialize::deserialize(deserializer)?;
73        Ok(value.into_iter().collect())
74    }
75}