clickhouse_arrow/native/values/
vec_tuple.rs1use super::unexpected_type;
2use crate::{Error, FromSql, Result, ToSql, Type, Value};
3
4#[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 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]); let tuple_value = Value::Tuple(vec![Value::Int32(1)]); let result: Result<VecTuple<i32>> = VecTuple::from_sql(&tuple_type, tuple_value);
142 assert!(result.is_err());
143
144 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 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 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 let deserialized: VecTuple<i32> = serde_json::from_str(&serialized).unwrap();
221 assert_eq!(deserialized.0, vec![1, 2, 3]);
222 }
223}