clickhouse_arrow/native/convert/
raw_row.rs1use std::borrow::Cow;
2
3use crate::{Error, FromSql, Result, Row, ToSql, Type, Value};
4
5#[derive(Debug, Default, Clone)]
8pub struct RawRow(Vec<Option<(String, Type, Value)>>);
9
10impl Row for RawRow {
11 const COLUMN_COUNT: Option<usize> = None;
12
13 fn column_names() -> Option<Vec<Cow<'static, str>>> { None }
14
15 fn to_schema() -> Option<Vec<(String, Type, Option<Value>)>> { None }
16
17 fn deserialize_row(map: Vec<(&str, &Type, Value)>) -> Result<Self> {
18 Ok(Self(
19 map.into_iter()
20 .map(|(name, type_, value)| Some((name.to_string(), type_.clone(), value)))
21 .collect(),
22 ))
23 }
24
25 fn serialize_row(
26 self,
27 _type_hints: &[(String, Type)],
28 ) -> Result<Vec<(Cow<'static, str>, Value)>> {
29 Ok(self
30 .0
31 .into_iter()
32 .map(|x| x.expect("cannot serialize a Row which has been retrieved from"))
33 .map(|(name, _, value)| (Cow::Owned(name), value))
34 .collect())
35 }
36}
37
38pub trait RowIndex {
39 fn get<'a, I: IntoIterator<Item = &'a str>>(&self, columns: I) -> Option<usize>;
40}
41
42impl RowIndex for usize {
43 fn get<'a, I: IntoIterator<Item = &'a str>>(&self, columns: I) -> Option<usize> {
44 let count = columns.into_iter().count();
45 if count >= *self { Some(*self) } else { None }
46 }
47}
48
49impl RowIndex for str {
50 fn get<'a, I: IntoIterator<Item = &'a str>>(&self, columns: I) -> Option<usize> {
51 columns.into_iter().position(|x| x == self)
52 }
53}
54
55impl<T: RowIndex + ?Sized> RowIndex for &T {
56 fn get<'a, I: IntoIterator<Item = &'a str>>(&self, columns: I) -> Option<usize> {
57 (*self).get(columns)
58 }
59}
60
61impl RawRow {
62 pub fn is_empty(&self) -> bool { self.0.is_empty() }
64
65 pub fn len(&self) -> usize { self.0.len() }
67
68 pub fn into_values(self) -> Vec<(Type, Value)> {
72 self.0.into_iter().map(|x| x.map(|(_, t, v)| (t, v)).unwrap()).collect()
73 }
74
75 pub fn try_get<I: RowIndex, T: FromSql>(&mut self, index: I) -> Result<T> {
86 let index = index
87 .get(self.0.iter().map(|x| x.as_ref().map_or("", |x| &*x.0)))
88 .ok_or(Error::OutOfBounds)?;
89 let (_, type_, value) = self.0.get_mut(index).unwrap().take().ok_or(Error::DoubleFetch)?;
90 T::from_sql(&type_, value)
91 }
92
93 pub fn get<I: RowIndex, T: FromSql>(&mut self, index: I) -> T {
99 self.try_get(index).expect("failed to convert column")
100 }
101
102 pub fn try_set_typed(
113 &mut self,
114 name: &impl ToString,
115 type_: Option<Type>,
116 value: impl ToSql,
117 ) -> Result<()> {
118 let name = name.to_string();
119 let value = value.to_sql(type_.as_ref())?;
120 let type_ = type_.unwrap_or_else(|| value.guess_type());
121
122 let current_position =
123 self.0.iter().map(|x| x.as_ref().map_or("", |x| &*x.0)).position(|x| x == &*name);
124
125 if let Some(current_position) = current_position {
126 self.0[current_position].as_mut().unwrap().1 = type_;
127 self.0[current_position].as_mut().unwrap().2 = value;
128 } else {
129 self.0.push(Some((name, type_, value)));
130 }
131 Ok(())
132 }
133
134 pub fn try_set(&mut self, name: &impl ToString, value: impl ToSql) -> Result<()> {
140 self.try_set_typed(name, None, value)
141 }
142
143 pub fn set(&mut self, name: &impl ToString, value: impl ToSql) {
149 self.try_set(name, value).expect("failed to convert column");
150 }
151
152 pub fn set_typed(&mut self, name: &impl ToString, type_: Option<Type>, value: impl ToSql) {
157 self.try_set_typed(name, type_, value).expect("failed to convert column");
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn test_raw_row_default() {
167 let row = RawRow::default();
168 assert!(row.is_empty());
169 assert_eq!(row.len(), 0);
170 }
171
172 #[test]
173 fn test_raw_row_basic_operations() {
174 let mut row = RawRow::default();
175
176 assert!(row.is_empty());
178 assert_eq!(row.len(), 0);
179
180 row.set(&"test_col", 42i32);
182 assert!(!row.is_empty());
183 assert_eq!(row.len(), 1);
184
185 row.try_set(&"test_col2", "hello").unwrap();
187 assert_eq!(row.len(), 2);
188 }
189
190 #[test]
191 fn test_raw_row_set_typed() {
192 let mut row = RawRow::default();
193
194 row.set_typed(&"int_col", Some(Type::Int32), 123i32);
196 assert_eq!(row.len(), 1);
197
198 row.try_set_typed(&"str_col", Some(Type::String), "test").unwrap();
200 assert_eq!(row.len(), 2);
201
202 row.try_set_typed(&"int_col", Some(Type::Int32), 456i32).unwrap();
204 assert_eq!(row.len(), 2); }
206
207 #[test]
208 fn test_raw_row_get_by_index() {
209 let mut row = RawRow::default();
210 row.set(&"col1", 42i32);
211 row.set(&"col2", "hello");
212
213 let val: i32 = row.try_get(0usize).unwrap();
215 assert_eq!(val, 42);
216 }
217
218 #[test]
219 fn test_raw_row_get_by_name() {
220 let mut row = RawRow::default();
221 row.set(&"test_column", 123i64);
222
223 let val: i64 = row.try_get("test_column").unwrap();
225 assert_eq!(val, 123);
226 }
227
228 #[test]
229 fn test_raw_row_get_panics() {
230 let mut row = RawRow::default();
231 row.set(&"test", 42i32);
232
233 let _val: i32 = row.get(0usize);
235
236 drop(
238 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
239 let _val2: i32 = row.get(0usize);
240 }))
241 .unwrap_err(),
242 );
243 }
244
245 #[test]
246 fn test_raw_row_errors() {
247 let mut row = RawRow::default();
248 row.set(&"test", 42i32);
249
250 let result: Result<i32> = row.try_get(10usize);
252 assert!(matches!(result, Err(Error::OutOfBounds)));
253
254 let _val: i32 = row.try_get(0usize).unwrap();
256 let result2: Result<i32> = row.try_get(0usize);
257 assert!(matches!(result2, Err(Error::DoubleFetch)));
258 }
259
260 #[test]
261 fn test_raw_row_into_values() {
262 let mut row = RawRow::default();
263 row.set(&"col1", 42i32);
264 row.set(&"col2", "test");
265
266 let values = row.into_values();
267 assert_eq!(values.len(), 2);
268 assert_eq!(values[0].0, Type::Int32);
269 assert_eq!(values[1].0, Type::String);
270 }
271
272 #[test]
273 fn test_row_index_usize() {
274 let columns = ["col1", "col2", "col3"];
275
276 assert_eq!(1usize.get(columns.iter().copied()), Some(1));
278
279 assert_eq!(5usize.get(columns.iter().copied()), None);
281 }
282
283 #[test]
284 fn test_row_index_str() {
285 let columns = ["col1", "col2", "col3"];
286
287 assert_eq!(RowIndex::get("col2", columns.iter().copied()), Some(1));
289
290 assert_eq!(RowIndex::get("nonexistent", columns.iter().copied()), None);
292 }
293
294 #[test]
295 fn test_row_index_ref() {
296 let columns = ["col1", "col2", "col3"];
297 let name = "col2";
298
299 assert_eq!((&name).get(columns.iter().copied()), Some(1));
301 assert_eq!((1usize).get(columns.iter().copied()), Some(1));
302 }
303
304 #[test]
305 fn test_raw_row_deserialize() {
306 let map = vec![
307 ("col1", &Type::Int32, Value::Int32(42)),
308 ("col2", &Type::String, Value::String("test".to_string().into_bytes())),
309 ];
310
311 let row = RawRow::deserialize_row(map).unwrap();
312 assert_eq!(row.len(), 2);
313 assert!(!row.is_empty());
314 }
315
316 #[test]
317 fn test_raw_row_serialize() {
318 let mut row = RawRow::default();
319 row.set(&"col1", 42i32);
320 row.set(&"col2", "test");
321
322 let serialized = row.serialize_row(&[]).unwrap();
323 assert_eq!(serialized.len(), 2);
324 assert_eq!(serialized[0].0, "col1");
325 assert_eq!(serialized[1].0, "col2");
326 }
327
328 #[test]
329 fn test_raw_row_serialize_panic() {
330 let raw_row = RawRow(vec![None]);
332
333 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
335 raw_row.serialize_row(&[]).unwrap()
336 }));
337 assert!(result.is_err());
338 }
339
340 #[test]
341 fn test_raw_row_static_methods() {
342 assert_eq!(RawRow::COLUMN_COUNT, None);
344 assert_eq!(RawRow::column_names(), None);
345 assert_eq!(RawRow::to_schema(), None);
346 }
347}