use crate::{Result, ScalarValue};
use arrow::array::{ArrayRef, StructArray};
use arrow::datatypes::{DataType, Field, FieldRef, Fields};
use std::sync::Arc;
#[derive(Debug, Default)]
pub struct ScalarStructBuilder {
fields: Vec<FieldRef>,
arrays: Vec<ArrayRef>,
}
impl ScalarStructBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn new_null(fields: impl IntoFields) -> ScalarValue {
DataType::Struct(fields.into()).try_into().unwrap()
}
pub fn with_array(mut self, field: impl IntoFieldRef, value: ArrayRef) -> Self {
self.fields.push(field.into_field_ref());
self.arrays.push(value);
self
}
#[expect(clippy::needless_pass_by_value)] pub fn with_scalar(self, field: impl IntoFieldRef, value: ScalarValue) -> Self {
let array = value.to_array().unwrap();
self.with_array(field, array)
}
pub fn with_name_and_scalar(self, name: &str, value: ScalarValue) -> Self {
let field = Field::new(name, value.data_type(), false);
self.with_scalar(field, value)
}
pub fn build(self) -> Result<ScalarValue> {
let Self { fields, arrays } = self;
let struct_array =
StructArray::try_new_with_length(Fields::from(fields), arrays, None, 1)?;
Ok(ScalarValue::Struct(Arc::new(struct_array)))
}
}
pub trait IntoFieldRef {
fn into_field_ref(self) -> FieldRef;
}
impl IntoFieldRef for FieldRef {
fn into_field_ref(self) -> FieldRef {
self
}
}
impl IntoFieldRef for &FieldRef {
fn into_field_ref(self) -> FieldRef {
Arc::clone(self)
}
}
impl IntoFieldRef for Field {
fn into_field_ref(self) -> FieldRef {
FieldRef::new(self)
}
}
pub trait IntoFields {
fn into(self) -> Fields;
}
impl IntoFields for Fields {
fn into(self) -> Fields {
self
}
}
impl IntoFields for &Fields {
fn into(self) -> Fields {
self.clone()
}
}
impl IntoFields for Vec<Field> {
fn into(self) -> Fields {
Fields::from(self)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_struct() {
let sv = ScalarStructBuilder::new().build().unwrap();
assert_eq!(format!("{sv}"), "{}");
}
}