clickhouse_arrow/native/values/
vec_tuple.rs

1use super::unexpected_type;
2use crate::{Error, FromSql, Result, ToSql, Type, Value};
3
4/// A `Vec` wrapper that is encoded as a tuple in SQL as opposed to a Vec
5#[derive(Clone, Debug, Default)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7pub struct VecTuple<T>(pub Vec<T>);
8
9impl<T: ToSql> ToSql for VecTuple<T> {
10    fn to_sql(self, type_hint: Option<&Type>) -> Result<Value> {
11        Ok(Value::Tuple(
12            self.0
13                .into_iter()
14                .enumerate()
15                .map(|(i, x)| x.to_sql(type_hint.and_then(|x| x.untuple()?.get(i))))
16                .collect::<Result<Vec<_>>>()?,
17        ))
18    }
19}
20
21impl<T: FromSql> FromSql for VecTuple<T> {
22    fn from_sql(type_: &Type, value: Value) -> Result<Self> {
23        let subtype = match type_ {
24            Type::Tuple(x) => &**x,
25            x => return Err(unexpected_type(x)),
26        };
27        let Value::Tuple(values) = value else { return Err(unexpected_type(type_)) };
28        if values.len() != subtype.len() {
29            return Err(Error::DeserializeError(format!(
30                "unexpected type: mismatch tuple length expected {}, got {}",
31                subtype.len(),
32                values.len()
33            )));
34        }
35        let mut out = Vec::with_capacity(values.len());
36        for (type_, value) in subtype.iter().zip(values.into_iter()) {
37            out.push(T::from_sql(type_, value)?);
38        }
39        Ok(VecTuple(out))
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn test_vec_tuple_creation() {
49        let vec_tuple = VecTuple(vec![1, 2, 3]);
50        assert_eq!(vec_tuple.0, vec![1, 2, 3]);
51    }
52
53    #[test]
54    fn test_vec_tuple_default() {
55        let vec_tuple: VecTuple<i32> = VecTuple::default();
56        assert_eq!(vec_tuple.0, Vec::<i32>::new());
57    }
58
59    #[test]
60    fn test_vec_tuple_clone_debug() {
61        let vec_tuple = VecTuple(vec![1, 2, 3]);
62        let cloned = vec_tuple.clone();
63        assert_eq!(vec_tuple.0, cloned.0);
64
65        // Test Debug implementation
66        let debug_str = format!("{vec_tuple:?}");
67        assert!(debug_str.contains("VecTuple"));
68        assert!(debug_str.contains('1'));
69        assert!(debug_str.contains('2'));
70        assert!(debug_str.contains('3'));
71    }
72
73    #[test]
74    fn test_vec_tuple_to_sql() {
75        let vec_tuple = VecTuple(vec![1i32, 2i32, 3i32]);
76        let tuple_type = Type::Tuple(vec![Type::Int32, Type::Int32, Type::Int32]);
77
78        let result = vec_tuple.to_sql(Some(&tuple_type)).unwrap();
79
80        match result {
81            Value::Tuple(values) => {
82                assert_eq!(values.len(), 3);
83                assert_eq!(values[0], Value::Int32(1));
84                assert_eq!(values[1], Value::Int32(2));
85                assert_eq!(values[2], Value::Int32(3));
86            }
87            _ => panic!("Expected Value::Tuple"),
88        }
89    }
90
91    #[test]
92    fn test_vec_tuple_to_sql_no_hint() {
93        let vec_tuple = VecTuple(vec![1i32, 2i32]);
94
95        let result = vec_tuple.to_sql(None).unwrap();
96
97        match result {
98            Value::Tuple(values) => {
99                assert_eq!(values.len(), 2);
100                assert_eq!(values[0], Value::Int32(1));
101                assert_eq!(values[1], Value::Int32(2));
102            }
103            _ => panic!("Expected Value::Tuple"),
104        }
105    }
106
107    #[test]
108    fn test_vec_tuple_from_sql_success() {
109        let tuple_type = Type::Tuple(vec![Type::Int32, Type::Int32, Type::Int32]);
110        let tuple_value = Value::Tuple(vec![Value::Int32(10), Value::Int32(20), Value::Int32(30)]);
111
112        let result: VecTuple<i32> = VecTuple::from_sql(&tuple_type, tuple_value).unwrap();
113        assert_eq!(result.0, vec![10, 20, 30]);
114    }
115
116    #[test]
117    fn test_vec_tuple_from_sql_wrong_type() {
118        let int_type = Type::Int32;
119        let tuple_value = Value::Tuple(vec![Value::Int32(1)]);
120
121        let result: Result<VecTuple<i32>> = VecTuple::from_sql(&int_type, tuple_value);
122        assert!(result.is_err());
123        assert!(matches!(result.unwrap_err(), Error::DeserializeError(_)));
124    }
125
126    #[test]
127    fn test_vec_tuple_from_sql_wrong_value_type() {
128        let tuple_type = Type::Tuple(vec![Type::Int32]);
129        let int_value = Value::Int32(42);
130
131        let result: Result<VecTuple<i32>> = VecTuple::from_sql(&tuple_type, int_value);
132        assert!(result.is_err());
133        assert!(matches!(result.unwrap_err(), Error::DeserializeError(_)));
134    }
135
136    #[test]
137    fn test_vec_tuple_length_mismatch() {
138        let tuple_type = Type::Tuple(vec![Type::Int32, Type::Int32]); // Expects 2 elements
139        let tuple_value = Value::Tuple(vec![Value::Int32(1)]); // Has 1 element
140
141        let result: Result<VecTuple<i32>> = VecTuple::from_sql(&tuple_type, tuple_value);
142        assert!(result.is_err());
143
144        // Check the error message
145        match result {
146            Err(Error::DeserializeError(msg)) => {
147                assert!(msg.contains("mismatch tuple length"));
148                assert!(msg.contains("expected 2"));
149                assert!(msg.contains("got 1"));
150            }
151            _ => panic!("Expected DeserializeError with specific message"),
152        }
153    }
154
155    #[test]
156    fn test_vec_tuple_empty() {
157        let vec_tuple: VecTuple<i32> = VecTuple(vec![]);
158        let tuple_type = Type::Tuple(vec![]);
159
160        let result = vec_tuple.to_sql(Some(&tuple_type)).unwrap();
161        match result {
162            Value::Tuple(values) => {
163                assert_eq!(values.len(), 0);
164            }
165            _ => panic!("Expected Value::Tuple"),
166        }
167    }
168
169    #[test]
170    fn test_vec_tuple_empty_from_sql() {
171        let tuple_type = Type::Tuple(vec![]);
172        let tuple_value = Value::Tuple(vec![]);
173
174        let result: VecTuple<i32> = VecTuple::from_sql(&tuple_type, tuple_value).unwrap();
175        assert_eq!(result.0, Vec::<i32>::new());
176    }
177
178    #[test]
179    fn test_vec_tuple_mixed_types() {
180        // Test with different types in tuple - using String type for testing
181        let vec_tuple = VecTuple(vec!["hello".to_string(), "world".to_string()]);
182        let tuple_type = Type::Tuple(vec![Type::String, Type::String]);
183
184        let result = vec_tuple.to_sql(Some(&tuple_type)).unwrap();
185
186        match result {
187            Value::Tuple(values) => {
188                assert_eq!(values.len(), 2);
189                assert_eq!(values[0], Value::String("hello".to_string().into_bytes()));
190                assert_eq!(values[1], Value::String("world".to_string().into_bytes()));
191            }
192            _ => panic!("Expected Value::Tuple"),
193        }
194    }
195
196    #[test]
197    fn test_vec_tuple_string_from_sql() {
198        let tuple_type = Type::Tuple(vec![Type::String, Type::String]);
199        let tuple_value = Value::Tuple(vec![
200            Value::String("test1".to_string().into_bytes()),
201            Value::String("test2".to_string().into_bytes()),
202        ]);
203
204        let result: VecTuple<String> = VecTuple::from_sql(&tuple_type, tuple_value).unwrap();
205        assert_eq!(result.0, vec!["test1".to_string(), "test2".to_string()]);
206    }
207
208    #[cfg(feature = "serde")]
209    #[test]
210    fn test_vec_tuple_serde() {
211        let vec_tuple = VecTuple(vec![1, 2, 3]);
212
213        // Test serialization
214        let serialized = serde_json::to_string(&vec_tuple).unwrap();
215        assert!(serialized.contains('1'));
216        assert!(serialized.contains('2'));
217        assert!(serialized.contains('3'));
218
219        // Test deserialization
220        let deserialized: VecTuple<i32> = serde_json::from_str(&serialized).unwrap();
221        assert_eq!(deserialized.0, vec![1, 2, 3]);
222    }
223}