mongreldb_kit/
arrow_util.rs1use arrow::array::{
8 Array, BooleanArray, Float64Array, Int32Array, Int64Array, NullArray, StringArray,
9};
10use arrow::ipc::reader::FileReader;
11use arrow::ipc::writer::FileWriter;
12use arrow::record_batch::RecordBatch;
13use serde_json::{json, Map, Value};
14
15use crate::error::{KitError, Result};
16
17pub fn read_arrow_ipc(bytes: &[u8]) -> Result<Vec<RecordBatch>> {
20 if bytes.is_empty() {
21 return Ok(Vec::new());
22 }
23 let cursor = std::io::Cursor::new(bytes);
24 let reader = FileReader::try_new(cursor, None)
25 .map_err(|e| KitError::Storage(format!("arrow ipc decode: {e}")))?;
26 reader
27 .into_iter()
28 .collect::<std::result::Result<Vec<_>, _>>()
29 .map_err(|e| KitError::Storage(format!("arrow ipc decode: {e}")))
30}
31
32pub fn batches_to_ipc(batches: &[RecordBatch]) -> Result<Vec<u8>> {
36 let schema = batches
37 .first()
38 .map(|b| b.schema())
39 .unwrap_or_else(|| std::sync::Arc::new(arrow::datatypes::Schema::empty()));
40 let mut out = Vec::new();
41 let mut writer =
42 FileWriter::try_new(&mut out, &schema).map_err(|e| KitError::Storage(e.to_string()))?;
43 for batch in batches {
44 writer
45 .write(batch)
46 .map_err(|e| KitError::Storage(format!("arrow ipc encode: {e}")))?;
47 }
48 writer
49 .finish()
50 .map_err(|e| KitError::Storage(format!("arrow ipc encode: {e}")))?;
51 Ok(out)
52}
53
54pub fn batch_to_rows(b: &RecordBatch) -> Result<Vec<Map<String, Value>>> {
56 let schema = b.schema();
57 let mut rows = Vec::with_capacity(b.num_rows());
58 for r in 0..b.num_rows() {
59 let mut row = Map::new();
60 for (c, field) in schema.fields().iter().enumerate() {
61 let name = field.name();
62 let arr = b.column(c);
63 row.insert(name.clone(), cell_value(arr.as_ref(), r));
64 }
65 rows.push(row);
66 }
67 Ok(rows)
68}
69
70pub fn batches_to_rows(batches: &[RecordBatch]) -> Result<Vec<Map<String, Value>>> {
72 let mut rows = Vec::new();
73 for batch in batches {
74 rows.extend(batch_to_rows(batch)?);
75 }
76 Ok(rows)
77}
78
79fn cell_value(arr: &dyn Array, r: usize) -> Value {
80 if arr.is_null(r) {
81 return Value::Null;
82 }
83 if let Some(a) = arr.as_any().downcast_ref::<Int64Array>() {
84 return json!(a.value(r));
85 }
86 if let Some(a) = arr.as_any().downcast_ref::<Int32Array>() {
87 return json!(a.value(r));
88 }
89 if let Some(a) = arr.as_any().downcast_ref::<Float64Array>() {
90 return serde_json::Number::from_f64(a.value(r))
91 .map(Value::Number)
92 .unwrap_or(Value::Null);
93 }
94 if let Some(a) = arr.as_any().downcast_ref::<BooleanArray>() {
95 return Value::Bool(a.value(r));
96 }
97 if let Some(a) = arr.as_any().downcast_ref::<StringArray>() {
98 return Value::String(a.value(r).to_string());
99 }
100 if arr.as_any().downcast_ref::<NullArray>().is_some() {
101 return Value::Null;
102 }
103 Value::String(format!("{arr:?}"))
105}