use crate::{ArrayRef, StructArray};
use arrow_buffer::NullBuffer;
use arrow_schema::{ArrowError, Field, FieldRef, Fields};
use std::sync::Arc;
#[derive(Debug, Default, Clone)]
pub struct StructArrayAssembler {
fields: Vec<FieldRef>,
arrays: Vec<ArrayRef>,
nulls: Option<NullBuffer>,
}
impl StructArrayAssembler {
pub fn new() -> Self {
Self::default()
}
pub fn with_field(
mut self,
field_name: impl Into<String>,
array: ArrayRef,
nullable: bool,
) -> Self {
self.fields.push(Arc::new(Field::new(
field_name,
array.data_type().clone(),
nullable,
)));
self.arrays.push(array);
self
}
pub fn with_field_ref(mut self, field: FieldRef, array: ArrayRef) -> Self {
self.fields.push(field);
self.arrays.push(array);
self
}
pub fn with_nulls(mut self, nulls: NullBuffer) -> Self {
self.nulls = Some(nulls);
self
}
pub fn build(self) -> Result<StructArray, ArrowError> {
StructArray::try_new(Fields::from(self.fields), self.arrays, self.nulls)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Array, Int32Array, StringArray};
use arrow_schema::DataType;
use std::collections::HashMap;
#[test]
fn build_from_completed_arrays() {
let names = Arc::new(StringArray::from(vec!["one", "two"])) as ArrayRef;
let values = Arc::new(Int32Array::from(vec![1, 2])) as ArrayRef;
let metadata = HashMap::from([("key".to_string(), "value".to_string())]);
let value_field =
Arc::new(Field::new("value", DataType::Int32, false).with_metadata(metadata.clone()));
let nulls = NullBuffer::from(vec![true, false]);
let array = StructArrayAssembler::new()
.with_field("name", names, false)
.with_field_ref(value_field, values)
.with_nulls(nulls.clone())
.build()
.unwrap();
assert_eq!(array.len(), 2);
assert_eq!(array.column_names(), &["name", "value"]);
assert_eq!(array.fields()[1].metadata(), &metadata);
assert_eq!(array.nulls(), Some(&nulls));
}
#[test]
fn build_errors_on_mismatched_child_lengths() {
let names = Arc::new(StringArray::from(vec!["one", "two"])) as ArrayRef;
let values = Arc::new(Int32Array::from(vec![1])) as ArrayRef;
let err = StructArrayAssembler::new()
.with_field("name", names, false)
.with_field("value", values, false)
.build()
.unwrap_err();
assert_eq!(
err.to_string(),
"Invalid argument error: Incorrect array length for StructArray field \"value\", expected 2 got 1"
);
}
#[test]
fn build_errors_on_mismatched_field_data_type() {
let value_field = Arc::new(Field::new("value", DataType::Int64, false));
let values = Arc::new(Int32Array::from(vec![1, 2])) as ArrayRef;
let err = StructArrayAssembler::new()
.with_field_ref(value_field, values)
.build()
.unwrap_err();
assert_eq!(
err.to_string(),
"Invalid argument error: Incorrect datatype for StructArray field \"value\", expected Int64 got Int32"
);
}
}