This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new e49c2edbde [Variant] Support array shredding into 
`List/LargeList/ListView/LargeListView` (#8831)
e49c2edbde is described below

commit e49c2edbde46c09cf19d2be344a841a041d416f0
Author: Liam Bao <[email protected]>
AuthorDate: Mon Dec 15 07:29:37 2025 -0500

    [Variant] Support array shredding into 
`List/LargeList/ListView/LargeListView` (#8831)
    
    # Which issue does this PR close?
    
    - Closes #8830.
    
    # Rationale for this change
    
    # What changes are included in this PR?
    
    Implement array shredding into `List/LargeList/ListView/LargeListView`
    to close the gaps in `shred_variant`. Part of the changes lay the
    groundwork for adding `variant_get` support for list types in a
    follow-up.
    
    # Are these changes tested?
    
    Yes
    
    # Are there any user-facing changes?
    
    New shredding types supported
---
 parquet-variant-compute/src/arrow_to_variant.rs |   12 +-
 parquet-variant-compute/src/shred_variant.rs    | 1166 ++++++++++++++++++++---
 2 files changed, 1054 insertions(+), 124 deletions(-)

diff --git a/parquet-variant-compute/src/arrow_to_variant.rs 
b/parquet-variant-compute/src/arrow_to_variant.rs
index 5e01aba3c1..5db1530025 100644
--- a/parquet-variant-compute/src/arrow_to_variant.rs
+++ b/parquet-variant-compute/src/arrow_to_variant.rs
@@ -17,8 +17,8 @@
 
 use crate::type_conversion::CastOptions;
 use arrow::array::{
-    Array, AsArray, FixedSizeListArray, GenericBinaryArray, GenericListArray, 
GenericListViewArray,
-    GenericStringArray, OffsetSizeTrait, PrimitiveArray,
+    Array, ArrayRef, AsArray, FixedSizeListArray, GenericBinaryArray, 
GenericListArray,
+    GenericListViewArray, GenericStringArray, OffsetSizeTrait, PrimitiveArray,
 };
 use arrow::compute::kernels::cast;
 use arrow::datatypes::{
@@ -556,14 +556,14 @@ impl<'a, L: ListLikeArray> ListArrowToVariantBuilder<'a, 
L> {
 /// Trait for list-like arrays that can provide element ranges
 pub(crate) trait ListLikeArray: Array {
     /// Get the values array
-    fn values(&self) -> &dyn Array;
+    fn values(&self) -> &ArrayRef;
 
     /// Get the start and end indices for a list element
     fn element_range(&self, index: usize) -> Range<usize>;
 }
 
 impl<O: OffsetSizeTrait> ListLikeArray for GenericListArray<O> {
-    fn values(&self) -> &dyn Array {
+    fn values(&self) -> &ArrayRef {
         self.values()
     }
 
@@ -576,7 +576,7 @@ impl<O: OffsetSizeTrait> ListLikeArray for 
GenericListArray<O> {
 }
 
 impl<O: OffsetSizeTrait> ListLikeArray for GenericListViewArray<O> {
-    fn values(&self) -> &dyn Array {
+    fn values(&self) -> &ArrayRef {
         self.values()
     }
 
@@ -590,7 +590,7 @@ impl<O: OffsetSizeTrait> ListLikeArray for 
GenericListViewArray<O> {
 }
 
 impl ListLikeArray for FixedSizeListArray {
-    fn values(&self) -> &dyn Array {
+    fn values(&self) -> &ArrayRef {
         self.values()
     }
 
diff --git a/parquet-variant-compute/src/shred_variant.rs 
b/parquet-variant-compute/src/shred_variant.rs
index 7b8dc28d5f..7367336379 100644
--- a/parquet-variant-compute/src/shred_variant.rs
+++ b/parquet-variant-compute/src/shred_variant.rs
@@ -22,14 +22,16 @@ use crate::variant_to_arrow::{
     PrimitiveVariantToArrowRowBuilder, 
make_primitive_variant_to_arrow_row_builder,
 };
 use crate::{VariantArray, VariantValueArrayBuilder};
-use arrow::array::{ArrayRef, BinaryViewArray, NullBufferBuilder};
-use arrow::buffer::NullBuffer;
+use arrow::array::{
+    ArrayRef, BinaryViewArray, GenericListArray, GenericListViewArray, 
NullBufferBuilder,
+    OffsetSizeTrait,
+};
+use arrow::buffer::{NullBuffer, OffsetBuffer, ScalarBuffer};
 use arrow::compute::CastOptions;
-use arrow::datatypes::{DataType, Field, FieldRef, Fields, TimeUnit};
+use arrow::datatypes::{ArrowNativeTypeOp, DataType, Field, FieldRef, Fields, 
TimeUnit};
 use arrow::error::{ArrowError, Result};
-use parquet_variant::{Variant, VariantBuilderExt, VariantPath, 
VariantPathElement};
-
 use indexmap::IndexMap;
+use parquet_variant::{Variant, VariantBuilderExt, VariantList, VariantPath, 
VariantPathElement};
 use std::collections::BTreeMap;
 use std::sync::Arc;
 
@@ -121,10 +123,17 @@ pub(crate) fn 
make_variant_to_shredded_variant_arrow_row_builder<'a>(
         DataType::List(_)
         | DataType::LargeList(_)
         | DataType::ListView(_)
-        | DataType::LargeListView(_)
-        | DataType::FixedSizeList(..) => {
+        | DataType::LargeListView(_) => {
+            let typed_value_builder = 
VariantToShreddedArrayVariantRowBuilder::try_new(
+                data_type,
+                cast_options,
+                capacity,
+            )?;
+            VariantToShreddedVariantRowBuilder::Array(typed_value_builder)
+        }
+        DataType::FixedSizeList(..) => {
             return Err(ArrowError::NotYetImplemented(
-                "Shredding variant array values as arrow lists".to_string(),
+                "Shredding variant array values as fixed-size 
lists".to_string(),
             ));
         }
         // Supported shredded primitive types, see Variant shredding spec:
@@ -166,13 +175,16 @@ pub(crate) fn 
make_variant_to_shredded_variant_arrow_row_builder<'a>(
 
 pub(crate) enum VariantToShreddedVariantRowBuilder<'a> {
     Primitive(VariantToShreddedPrimitiveVariantRowBuilder<'a>),
+    Array(VariantToShreddedArrayVariantRowBuilder<'a>),
     Object(VariantToShreddedObjectVariantRowBuilder<'a>),
 }
+
 impl<'a> VariantToShreddedVariantRowBuilder<'a> {
     pub fn append_null(&mut self) -> Result<()> {
         use VariantToShreddedVariantRowBuilder::*;
         match self {
             Primitive(b) => b.append_null(),
+            Array(b) => b.append_null(),
             Object(b) => b.append_null(),
         }
     }
@@ -181,6 +193,7 @@ impl<'a> VariantToShreddedVariantRowBuilder<'a> {
         use VariantToShreddedVariantRowBuilder::*;
         match self {
             Primitive(b) => b.append_value(value),
+            Array(b) => b.append_value(value),
             Object(b) => b.append_value(value),
         }
     }
@@ -189,6 +202,7 @@ impl<'a> VariantToShreddedVariantRowBuilder<'a> {
         use VariantToShreddedVariantRowBuilder::*;
         match self {
             Primitive(b) => b.finish(),
+            Array(b) => b.finish(),
             Object(b) => b.finish(),
         }
     }
@@ -215,6 +229,7 @@ impl<'a> VariantToShreddedPrimitiveVariantRowBuilder<'a> {
             top_level,
         }
     }
+
     fn append_null(&mut self) -> Result<()> {
         // Only the top-level struct that represents the variant can be 
nullable; object fields and
         // array elements are non-nullable.
@@ -222,6 +237,7 @@ impl<'a> VariantToShreddedPrimitiveVariantRowBuilder<'a> {
         self.value_builder.append_null();
         self.typed_value_builder.append_null()
     }
+
     fn append_value(&mut self, value: Variant<'_, '_>) -> Result<bool> {
         self.nulls.append_non_null();
         if self.typed_value_builder.append_value(&value)? {
@@ -231,6 +247,7 @@ impl<'a> VariantToShreddedPrimitiveVariantRowBuilder<'a> {
         }
         Ok(true)
     }
+
     fn finish(mut self) -> Result<(BinaryViewArray, ArrayRef, 
Option<NullBuffer>)> {
         Ok((
             self.value_builder.build()?,
@@ -240,6 +257,226 @@ impl<'a> VariantToShreddedPrimitiveVariantRowBuilder<'a> {
     }
 }
 
+pub(crate) struct VariantToShreddedArrayVariantRowBuilder<'a> {
+    value_builder: VariantValueArrayBuilder,
+    typed_value_builder: ArrayVariantToArrowRowBuilder<'a>,
+}
+
+impl<'a> VariantToShreddedArrayVariantRowBuilder<'a> {
+    fn try_new(
+        data_type: &'a DataType,
+        cast_options: &'a CastOptions,
+        capacity: usize,
+    ) -> Result<Self> {
+        Ok(Self {
+            value_builder: VariantValueArrayBuilder::new(capacity),
+            typed_value_builder: ArrayVariantToArrowRowBuilder::try_new(
+                data_type,
+                cast_options,
+                capacity,
+            )?,
+        })
+    }
+
+    fn append_null(&mut self) -> Result<()> {
+        self.value_builder.append_value(Variant::Null);
+        self.typed_value_builder.append_null();
+        Ok(())
+    }
+
+    fn append_value(&mut self, variant: Variant<'_, '_>) -> Result<bool> {
+        // If the variant is not an array, typed_value must be null.
+        // If the variant is an array, value must be null.
+        match variant {
+            Variant::List(list) => {
+                self.value_builder.append_null();
+                self.typed_value_builder.append_value(list)?;
+                Ok(true)
+            }
+            other => {
+                self.value_builder.append_value(other);
+                self.typed_value_builder.append_null();
+                Ok(false)
+            }
+        }
+    }
+
+    fn finish(self) -> Result<(BinaryViewArray, ArrayRef, Option<NullBuffer>)> 
{
+        Ok((
+            self.value_builder.build()?,
+            self.typed_value_builder.finish()?,
+            // All elements of an array must be present (not missing) because
+            // the array Variant encoding does not allow missing elements
+            None,
+        ))
+    }
+}
+
+enum ArrayVariantToArrowRowBuilder<'a> {
+    List(VariantToListArrowRowBuilder<'a, i32, false>),
+    LargeList(VariantToListArrowRowBuilder<'a, i64, false>),
+    ListView(VariantToListArrowRowBuilder<'a, i32, true>),
+    LargeListView(VariantToListArrowRowBuilder<'a, i64, true>),
+}
+
+impl<'a> ArrayVariantToArrowRowBuilder<'a> {
+    fn try_new(
+        data_type: &'a DataType,
+        cast_options: &'a CastOptions,
+        capacity: usize,
+    ) -> Result<Self> {
+        use ArrayVariantToArrowRowBuilder::*;
+
+        // Make List/ListView builders without repeating the constructor 
boilerplate.
+        macro_rules! make_list_builder {
+            ($variant:ident, $offset:ty, $is_view:expr, $field:ident) => {
+                $variant(VariantToListArrowRowBuilder::<$offset, 
$is_view>::try_new(
+                    $field.clone(),
+                    $field.data_type(),
+                    cast_options,
+                    capacity,
+                )?)
+            };
+        }
+
+        let builder = match data_type {
+            DataType::List(field) => make_list_builder!(List, i32, false, 
field),
+            DataType::LargeList(field) => make_list_builder!(LargeList, i64, 
false, field),
+            DataType::ListView(field) => make_list_builder!(ListView, i32, 
true, field),
+            DataType::LargeListView(field) => 
make_list_builder!(LargeListView, i64, true, field),
+            other => {
+                return Err(ArrowError::InvalidArgumentError(format!(
+                    "Casting to {other:?} is not applicable for array Variant 
types"
+                )));
+            }
+        };
+        Ok(builder)
+    }
+
+    fn append_null(&mut self) {
+        match self {
+            Self::List(builder) => builder.append_null(),
+            Self::LargeList(builder) => builder.append_null(),
+            Self::ListView(builder) => builder.append_null(),
+            Self::LargeListView(builder) => builder.append_null(),
+        }
+    }
+
+    fn append_value(&mut self, list: VariantList<'_, '_>) -> Result<()> {
+        match self {
+            Self::List(builder) => builder.append_value(list),
+            Self::LargeList(builder) => builder.append_value(list),
+            Self::ListView(builder) => builder.append_value(list),
+            Self::LargeListView(builder) => builder.append_value(list),
+        }
+    }
+
+    fn finish(self) -> Result<ArrayRef> {
+        match self {
+            Self::List(builder) => builder.finish(),
+            Self::LargeList(builder) => builder.finish(),
+            Self::ListView(builder) => builder.finish(),
+            Self::LargeListView(builder) => builder.finish(),
+        }
+    }
+}
+
+struct VariantToListArrowRowBuilder<'a, O, const IS_VIEW: bool>
+where
+    O: OffsetSizeTrait + ArrowNativeTypeOp,
+{
+    field: FieldRef,
+    offsets: Vec<O>,
+    element_builder: Box<VariantToShreddedVariantRowBuilder<'a>>,
+    nulls: NullBufferBuilder,
+    current_offset: O,
+}
+
+impl<'a, O, const IS_VIEW: bool> VariantToListArrowRowBuilder<'a, O, IS_VIEW>
+where
+    O: OffsetSizeTrait + ArrowNativeTypeOp,
+{
+    fn try_new(
+        field: FieldRef,
+        element_data_type: &'a DataType,
+        cast_options: &'a CastOptions,
+        capacity: usize,
+    ) -> Result<Self> {
+        if capacity >= isize::MAX as usize {
+            return Err(ArrowError::ComputeError(
+                "Capacity exceeds isize::MAX when reserving list 
offsets".to_string(),
+            ));
+        }
+        let mut offsets = Vec::with_capacity(capacity + 1);
+        offsets.push(O::ZERO);
+        let element_builder = 
make_variant_to_shredded_variant_arrow_row_builder(
+            element_data_type,
+            cast_options,
+            capacity,
+            false,
+        )?;
+        Ok(Self {
+            field,
+            offsets,
+            element_builder: Box::new(element_builder),
+            nulls: NullBufferBuilder::new(capacity),
+            current_offset: O::ZERO,
+        })
+    }
+
+    fn append_null(&mut self) {
+        self.offsets.push(self.current_offset);
+        self.nulls.append_null();
+    }
+
+    fn append_value(&mut self, list: VariantList<'_, '_>) -> Result<()> {
+        for element in list.iter() {
+            self.element_builder.append_value(element)?;
+            self.current_offset = self.current_offset.add_checked(O::ONE)?;
+        }
+        self.offsets.push(self.current_offset);
+        self.nulls.append_non_null();
+        Ok(())
+    }
+
+    fn finish(mut self) -> Result<ArrayRef> {
+        let (value, typed_value, nulls) = self.element_builder.finish()?;
+        let element_array =
+            ShreddedVariantFieldArray::from_parts(Some(value), 
Some(typed_value), nulls);
+        let field = Arc::new(
+            self.field
+                .as_ref()
+                .clone()
+                .with_data_type(element_array.data_type().clone()),
+        );
+
+        if IS_VIEW {
+            // NOTE: `offsets` is never empty (constructor pushes an entry)
+            let mut sizes = Vec::with_capacity(self.offsets.len() - 1);
+            for i in 1..self.offsets.len() {
+                sizes.push(self.offsets[i] - self.offsets[i - 1]);
+            }
+            self.offsets.pop();
+            let list_view_array = GenericListViewArray::<O>::new(
+                field,
+                ScalarBuffer::from(self.offsets),
+                ScalarBuffer::from(sizes),
+                ArrayRef::from(element_array),
+                self.nulls.finish(),
+            );
+            Ok(Arc::new(list_view_array))
+        } else {
+            let list_array = GenericListArray::<O>::new(
+                field,
+                OffsetBuffer::<O>::new(ScalarBuffer::from(self.offsets)),
+                ArrayRef::from(element_array),
+                self.nulls.finish(),
+            );
+            Ok(Arc::new(list_array))
+        }
+    }
+}
+
 pub(crate) struct VariantToShreddedObjectVariantRowBuilder<'a> {
     value_builder: VariantValueArrayBuilder,
     typed_value_builders: IndexMap<&'a str, 
VariantToShreddedVariantRowBuilder<'a>>,
@@ -284,6 +521,7 @@ impl<'a> VariantToShreddedObjectVariantRowBuilder<'a> {
         }
         Ok(())
     }
+
     fn append_value(&mut self, value: Variant<'_, '_>) -> Result<bool> {
         let Variant::Object(ref obj) = value else {
             // Not an object => fall back
@@ -333,6 +571,7 @@ impl<'a> VariantToShreddedObjectVariantRowBuilder<'a> {
         self.nulls.append_non_null();
         Ok(true)
     }
+
     fn finish(mut self) -> Result<(BinaryViewArray, ArrayRef, 
Option<NullBuffer>)> {
         let mut builder = StructArrayBuilder::new();
         for (field_name, typed_value_builder) in self.typed_value_builders {
@@ -578,15 +817,301 @@ impl VariantSchemaNode {
 mod tests {
     use super::*;
     use crate::VariantArrayBuilder;
-    use arrow::array::{Array, FixedSizeBinaryArray, Float64Array, Int64Array};
-    use arrow::datatypes::{DataType, Field, Fields, TimeUnit, UnionFields, 
UnionMode};
+    use crate::arrow_to_variant::ListLikeArray;
+    use arrow::array::{
+        Array, BinaryViewArray, FixedSizeBinaryArray, Float64Array, 
GenericListArray,
+        GenericListViewArray, Int64Array, ListArray, OffsetSizeTrait, 
PrimitiveArray, StringArray,
+    };
+    use arrow::datatypes::{
+        ArrowPrimitiveType, DataType, Field, Fields, Int64Type, TimeUnit, 
UnionFields, UnionMode,
+    };
     use parquet_variant::{
-        ObjectBuilder, ReadOnlyMetadataBuilder, Variant, VariantBuilder, 
VariantPath,
-        VariantPathElement,
+        BuilderSpecificState, EMPTY_VARIANT_METADATA_BYTES, ObjectBuilder, 
ReadOnlyMetadataBuilder,
+        Variant, VariantBuilder, VariantPath, VariantPathElement,
     };
     use std::sync::Arc;
     use uuid::Uuid;
 
+    #[derive(Clone)]
+    enum VariantValue<'a> {
+        Value(Variant<'a, 'a>),
+        List(Vec<VariantValue<'a>>),
+        Object(Vec<(&'a str, VariantValue<'a>)>),
+        Null,
+    }
+
+    impl<'a, T> From<T> for VariantValue<'a>
+    where
+        T: Into<Variant<'a, 'a>>,
+    {
+        fn from(value: T) -> Self {
+            Self::Value(value.into())
+        }
+    }
+
+    #[derive(Clone)]
+    enum VariantRow<'a> {
+        Value(VariantValue<'a>),
+        List(Vec<VariantValue<'a>>),
+        Object(Vec<(&'a str, VariantValue<'a>)>),
+        Null,
+    }
+
+    fn build_variant_array(rows: Vec<VariantRow<'static>>) -> VariantArray {
+        let mut builder = VariantArrayBuilder::new(rows.len());
+
+        fn append_variant_value<B: VariantBuilderExt>(builder: &mut B, value: 
VariantValue) {
+            match value {
+                VariantValue::Value(v) => builder.append_value(v),
+                VariantValue::List(values) => {
+                    let mut list = builder.new_list();
+                    for v in values {
+                        append_variant_value(&mut list, v);
+                    }
+                    list.finish();
+                }
+                VariantValue::Object(fields) => {
+                    let mut object = builder.new_object();
+                    for (name, value) in fields {
+                        append_variant_field(&mut object, name, value);
+                    }
+                    object.finish();
+                }
+                VariantValue::Null => builder.append_null(),
+            }
+        }
+
+        fn append_variant_field<'a, S: BuilderSpecificState>(
+            object: &mut ObjectBuilder<'_, S>,
+            name: &'a str,
+            value: VariantValue<'a>,
+        ) {
+            match value {
+                VariantValue::Value(v) => {
+                    object.insert(name, v);
+                }
+                VariantValue::List(values) => {
+                    let mut list = object.new_list(name);
+                    for v in values {
+                        append_variant_value(&mut list, v);
+                    }
+                    list.finish();
+                }
+                VariantValue::Object(fields) => {
+                    let mut nested = object.new_object(name);
+                    for (field_name, v) in fields {
+                        append_variant_field(&mut nested, field_name, v);
+                    }
+                    nested.finish();
+                }
+                VariantValue::Null => {
+                    object.insert(name, Variant::Null);
+                }
+            }
+        }
+
+        rows.into_iter().for_each(|row| match row {
+            VariantRow::Value(value) => append_variant_value(&mut builder, 
value),
+            VariantRow::List(values) => {
+                let mut list = builder.new_list();
+                for value in values {
+                    append_variant_value(&mut list, value);
+                }
+                list.finish();
+            }
+            VariantRow::Object(fields) => {
+                let mut object = builder.new_object();
+                for (name, value) in fields {
+                    append_variant_field(&mut object, name, value);
+                }
+                object.finish();
+            }
+            VariantRow::Null => builder.append_null(),
+        });
+        builder.build()
+    }
+
+    trait TestListLikeArray: ListLikeArray {
+        type OffsetSize: OffsetSizeTrait;
+        fn value_offsets(&self) -> Option<&[Self::OffsetSize]>;
+        fn value_size(&self, index: usize) -> Self::OffsetSize;
+    }
+
+    impl<O: OffsetSizeTrait> TestListLikeArray for GenericListArray<O> {
+        type OffsetSize = O;
+
+        fn value_offsets(&self) -> Option<&[Self::OffsetSize]> {
+            Some(GenericListArray::value_offsets(self))
+        }
+
+        fn value_size(&self, index: usize) -> Self::OffsetSize {
+            GenericListArray::value_length(self, index)
+        }
+    }
+
+    impl<O: OffsetSizeTrait> TestListLikeArray for GenericListViewArray<O> {
+        type OffsetSize = O;
+
+        fn value_offsets(&self) -> Option<&[Self::OffsetSize]> {
+            Some(GenericListViewArray::value_offsets(self))
+        }
+
+        fn value_size(&self, index: usize) -> Self::OffsetSize {
+            GenericListViewArray::value_size(self, index)
+        }
+    }
+
+    fn downcast_list_like_array<O: OffsetSizeTrait>(
+        array: &VariantArray,
+    ) -> &dyn TestListLikeArray<OffsetSize = O> {
+        let typed_value = array.typed_value_field().unwrap();
+        if let Some(list) = 
typed_value.as_any().downcast_ref::<GenericListArray<O>>() {
+            list
+        } else if let Some(list_view) = typed_value
+            .as_any()
+            .downcast_ref::<GenericListViewArray<O>>()
+        {
+            list_view
+        } else {
+            panic!(
+                "Expected list-like typed_value with matching offset type, got 
{}",
+                typed_value.data_type()
+            );
+        }
+    }
+
+    fn assert_list_structure<O: OffsetSizeTrait>(
+        array: &VariantArray,
+        expected_len: usize,
+        expected_offsets: &[O],
+        expected_sizes: &[Option<O>],
+        expected_fallbacks: &[Option<Variant<'static, 'static>>],
+    ) {
+        assert_eq!(array.len(), expected_len);
+
+        let fallbacks = (array.value_field().unwrap(), 
Some(array.metadata_field()));
+        let array = downcast_list_like_array::<O>(array);
+
+        assert_eq!(
+            array.value_offsets().unwrap(),
+            expected_offsets,
+            "list offsets mismatch"
+        );
+        assert_eq!(
+            array.len(),
+            expected_sizes.len(),
+            "expected_sizes should match array length"
+        );
+        assert_eq!(
+            array.len(),
+            expected_fallbacks.len(),
+            "expected_fallbacks should match array length"
+        );
+        assert_eq!(
+            array.len(),
+            fallbacks.0.len(),
+            "fallbacks value field should match array length"
+        );
+
+        // Validate per-row shredding outcomes for the list array
+        for (idx, (expected_size, expected_fallback)) in expected_sizes
+            .iter()
+            .zip(expected_fallbacks.iter())
+            .enumerate()
+        {
+            match expected_size {
+                Some(len) => {
+                    // Successfully shredded: typed list value present, no 
fallback value
+                    assert!(array.is_valid(idx));
+                    assert_eq!(array.value_size(idx), *len);
+                    assert!(fallbacks.0.is_null(idx));
+                }
+                None => {
+                    // Unable to shred: typed list value absent, fallback 
should carry the variant
+                    assert!(array.is_null(idx));
+                    assert_eq!(array.value_size(idx), O::zero());
+                    match expected_fallback {
+                        Some(expected_variant) => {
+                            assert!(fallbacks.0.is_valid(idx));
+                            let metadata_bytes = fallbacks
+                                .1
+                                .filter(|m| m.is_valid(idx))
+                                .map(|m| m.value(idx))
+                                .filter(|bytes| !bytes.is_empty())
+                                .unwrap_or(EMPTY_VARIANT_METADATA_BYTES);
+                            assert_eq!(
+                                Variant::new(metadata_bytes, 
fallbacks.0.value(idx)),
+                                expected_variant.clone()
+                            );
+                        }
+                        None => unreachable!(),
+                    }
+                }
+            }
+        }
+    }
+
+    fn assert_list_structure_and_elements<T: ArrowPrimitiveType, O: 
OffsetSizeTrait>(
+        array: &VariantArray,
+        expected_len: usize,
+        expected_offsets: &[O],
+        expected_sizes: &[Option<O>],
+        expected_fallbacks: &[Option<Variant<'static, 'static>>],
+        expected_shredded_elements: (&[Option<T::Native>], 
&[Option<Variant<'static, 'static>>]),
+    ) {
+        assert_list_structure(
+            array,
+            expected_len,
+            expected_offsets,
+            expected_sizes,
+            expected_fallbacks,
+        );
+        let array = downcast_list_like_array::<O>(array);
+
+        // Validate the shredded state of list elements (typed values and 
fallbacks)
+        let (expected_values, expected_fallbacks) = expected_shredded_elements;
+        assert_eq!(
+            expected_values.len(),
+            expected_fallbacks.len(),
+            "expected_values and expected_fallbacks should be aligned"
+        );
+
+        // Validate the shredded primitive values for list elements
+        let element_array = 
ShreddedVariantFieldArray::try_new(array.values().as_ref()).unwrap();
+        let element_values = element_array
+            .typed_value_field()
+            .unwrap()
+            .as_any()
+            .downcast_ref::<PrimitiveArray<T>>()
+            .unwrap();
+        assert_eq!(element_values.len(), expected_values.len());
+        for (idx, expected_value) in expected_values.iter().enumerate() {
+            match expected_value {
+                Some(value) => {
+                    assert!(element_values.is_valid(idx));
+                    assert_eq!(element_values.value(idx), *value);
+                }
+                None => assert!(element_values.is_null(idx)),
+            }
+        }
+
+        // Validate fallback variants for list elements that could not be 
shredded
+        let element_fallbacks = element_array.value_field().unwrap();
+        assert_eq!(element_fallbacks.len(), expected_fallbacks.len());
+        for (idx, expected_fallback) in expected_fallbacks.iter().enumerate() {
+            match expected_fallback {
+                Some(expected_variant) => {
+                    assert!(element_fallbacks.is_valid(idx));
+                    assert_eq!(
+                        Variant::new(EMPTY_VARIANT_METADATA_BYTES, 
element_fallbacks.value(idx)),
+                        expected_variant.clone()
+                    );
+                }
+                None => assert!(element_fallbacks.is_null(idx)),
+            }
+        }
+    }
+
     #[test]
     fn test_already_shredded_input_error() {
         // Create a VariantArray that already has typed_value_field
@@ -618,13 +1143,6 @@ mod tests {
         assert!(result.typed_value_field().is_none());
     }
 
-    #[test]
-    fn test_unsupported_list_schema() {
-        let input = VariantArray::from_iter([Variant::from(42)]);
-        let list_schema = DataType::List(Arc::new(Field::new("item", 
DataType::Int64, true)));
-        shred_variant(&input, &list_schema).expect_err("unsupported");
-    }
-
     #[test]
     fn test_invalid_fixed_size_binary_shredding() {
         let mock_uuid_1 = Uuid::new_v4();
@@ -846,54 +1364,391 @@ mod tests {
     }
 
     #[test]
-    fn test_object_shredding_comprehensive() {
-        let mut builder = VariantArrayBuilder::new(7);
+    fn test_array_shredding_as_list() {
+        let input = build_variant_array(vec![
+            // Row 0: List of ints should shred entirely into typed_value
+            VariantRow::List(vec![
+                VariantValue::from(1i64),
+                VariantValue::from(2i64),
+                VariantValue::from(3i64),
+            ]),
+            // Row 1: Contains incompatible types so values fall back
+            VariantRow::List(vec![
+                VariantValue::from(1i64),
+                VariantValue::from("two"),
+                VariantValue::from(Variant::Null),
+            ]),
+            // Row 2: Not a list -> entire row falls back
+            VariantRow::Value(VariantValue::from("not a list")),
+            // Row 3: Array-level null propagates
+            VariantRow::Null,
+            // Row 4: Empty list exercises zero-length offsets
+            VariantRow::List(vec![]),
+        ]);
+        let list_schema = DataType::List(Arc::new(Field::new("item", 
DataType::Int64, true)));
+        let result = shred_variant(&input, &list_schema).unwrap();
+        assert_eq!(result.len(), 5);
 
-        // Row 0: Fully shredded object
-        builder
-            .new_object()
-            .with_field("score", 95.5f64)
-            .with_field("age", 30i64)
-            .finish();
+        assert_list_structure_and_elements::<Int64Type, i32>(
+            &result,
+            5,
+            &[0, 3, 6, 6, 6, 6],
+            &[Some(3), Some(3), None, None, Some(0)],
+            &[
+                None,
+                None,
+                Some(Variant::from("not a list")),
+                Some(Variant::Null),
+                None,
+            ],
+            (
+                &[Some(1), Some(2), Some(3), Some(1), None, None],
+                &[
+                    None,
+                    None,
+                    None,
+                    None,
+                    Some(Variant::from("two")),
+                    Some(Variant::Null),
+                ],
+            ),
+        );
+    }
 
-        // Row 1: Partially shredded object (extra email field)
-        builder
-            .new_object()
-            .with_field("score", 87.2f64)
-            .with_field("age", 25i64)
-            .with_field("email", "[email protected]")
-            .finish();
+    #[test]
+    fn test_array_shredding_as_large_list() {
+        let input = build_variant_array(vec![
+            // Row 0: List of ints shreds to typed_value
+            VariantRow::List(vec![VariantValue::from(1i64), 
VariantValue::from(2i64)]),
+            // Row 1: Not a list -> entire row falls back
+            VariantRow::Value(VariantValue::from("not a list")),
+            // Row 2: Empty list
+            VariantRow::List(vec![]),
+        ]);
+        let list_schema = DataType::LargeList(Arc::new(Field::new("item", 
DataType::Int64, true)));
+        let result = shred_variant(&input, &list_schema).unwrap();
+        assert_eq!(result.len(), 3);
 
-        // Row 2: Missing field (no score)
-        builder.new_object().with_field("age", 35i64).finish();
+        assert_list_structure_and_elements::<Int64Type, i64>(
+            &result,
+            3,
+            &[0, 2, 2, 2],
+            &[Some(2), None, Some(0)],
+            &[None, Some(Variant::from("not a list")), None],
+            (&[Some(1), Some(2)], &[None, None]),
+        );
+    }
 
-        // Row 3: Type mismatch (score is string, age is string)
-        builder
-            .new_object()
-            .with_field("score", "ninety-five")
-            .with_field("age", "thirty")
-            .finish();
+    #[test]
+    fn test_array_shredding_as_list_view() {
+        let input = build_variant_array(vec![
+            // Row 0: Standard list
+            VariantRow::List(vec![
+                VariantValue::from(1i64),
+                VariantValue::from(2i64),
+                VariantValue::from(3i64),
+            ]),
+            // Row 1: List with incompatible types -> element fallback
+            VariantRow::List(vec![
+                VariantValue::from(1i64),
+                VariantValue::from("two"),
+                VariantValue::from(Variant::Null),
+            ]),
+            // Row 2: Not a list -> top-level fallback
+            VariantRow::Value(VariantValue::from("not a list")),
+            // Row 3: Top-level Null
+            VariantRow::Null,
+            // Row 4: Empty list
+            VariantRow::List(vec![]),
+        ]);
+        let list_schema = DataType::ListView(Arc::new(Field::new("item", 
DataType::Int64, true)));
+        let result = shred_variant(&input, &list_schema).unwrap();
+        assert_eq!(result.len(), 5);
 
-        // Row 4: Non-object
-        builder.append_variant(Variant::from("not an object"));
+        assert_list_structure_and_elements::<Int64Type, i32>(
+            &result,
+            5,
+            &[0, 3, 6, 6, 6],
+            &[Some(3), Some(3), None, None, Some(0)],
+            &[
+                None,
+                None,
+                Some(Variant::from("not a list")),
+                Some(Variant::Null),
+                None,
+            ],
+            (
+                &[Some(1), Some(2), Some(3), Some(1), None, None],
+                &[
+                    None,
+                    None,
+                    None,
+                    None,
+                    Some(Variant::from("two")),
+                    Some(Variant::Null),
+                ],
+            ),
+        );
+    }
 
-        // Row 5: Empty object
-        builder.new_object().finish();
+    #[test]
+    fn test_array_shredding_as_large_list_view() {
+        let input = build_variant_array(vec![
+            // Row 0: List of ints shreds to typed_value
+            VariantRow::List(vec![VariantValue::from(1i64), 
VariantValue::from(2i64)]),
+            // Row 1: Not a list -> entire row falls back
+            VariantRow::Value(VariantValue::from("fallback")),
+            // Row 2: Empty list
+            VariantRow::List(vec![]),
+        ]);
+        let list_schema =
+            DataType::LargeListView(Arc::new(Field::new("item", 
DataType::Int64, true)));
+        let result = shred_variant(&input, &list_schema).unwrap();
+        assert_eq!(result.len(), 3);
 
-        // Row 6: Null
-        builder.append_null();
+        assert_list_structure_and_elements::<Int64Type, i64>(
+            &result,
+            3,
+            &[0, 2, 2],
+            &[Some(2), None, Some(0)],
+            &[None, Some(Variant::from("fallback")), None],
+            (&[Some(1), Some(2)], &[None, None]),
+        );
+    }
 
-        // Row 7: Object with only "wrong" fields
-        builder.new_object().with_field("foo", 10).finish();
+    #[test]
+    fn test_array_shredding_with_array_elements() {
+        let input = build_variant_array(vec![
+            // Row 0: [[1, 2], [3, 4], []] - clean nested lists
+            VariantRow::List(vec![
+                VariantValue::List(vec![VariantValue::from(1i64), 
VariantValue::from(2i64)]),
+                VariantValue::List(vec![VariantValue::from(3i64), 
VariantValue::from(4i64)]),
+                VariantValue::List(vec![]),
+            ]),
+            // Row 1: [[5, "bad", null], "not a list inner", null] - inner 
fallbacks
+            VariantRow::List(vec![
+                VariantValue::List(vec![
+                    VariantValue::from(5i64),
+                    VariantValue::from("bad"),
+                    VariantValue::from(Variant::Null),
+                ]),
+                VariantValue::from("not a list inner"),
+                VariantValue::Null,
+            ]),
+            // Row 2: "not a list" - top-level fallback
+            VariantRow::Value(VariantValue::from("not a list")),
+            // Row 3: null row
+            VariantRow::Null,
+        ]);
+        let inner_field = Arc::new(Field::new("item", DataType::Int64, true));
+        let inner_list_schema = DataType::List(inner_field);
+        let list_schema = DataType::List(Arc::new(Field::new(
+            "item",
+            inner_list_schema.clone(),
+            true,
+        )));
+        let result = shred_variant(&input, &list_schema).unwrap();
+        assert_eq!(result.len(), 4);
 
-        // Row 8: Object with one "right" and one "wrong" field
-        builder
-            .new_object()
-            .with_field("score", 66.67f64)
-            .with_field("foo", 10)
-            .finish();
+        let typed_value = result
+            .typed_value_field()
+            .unwrap()
+            .as_any()
+            .downcast_ref::<ListArray>()
+            .unwrap();
+
+        assert_list_structure::<i32>(
+            &result,
+            4,
+            &[0, 3, 6, 6, 6],
+            &[Some(3), Some(3), None, None],
+            &[
+                None,
+                None,
+                Some(Variant::from("not a list")),
+                Some(Variant::Null),
+            ],
+        );
+
+        let outer_elements =
+            
ShreddedVariantFieldArray::try_new(typed_value.values().as_ref()).unwrap();
+        assert_eq!(outer_elements.len(), 6);
+        let outer_values = outer_elements
+            .typed_value_field()
+            .unwrap()
+            .as_any()
+            .downcast_ref::<ListArray>()
+            .unwrap();
+        let outer_fallbacks = outer_elements.value_field().unwrap();
+
+        let outer_metadata = 
BinaryViewArray::from_iter_values(std::iter::repeat_n(
+            EMPTY_VARIANT_METADATA_BYTES,
+            outer_elements.len(),
+        ));
+        let outer_variant = VariantArray::from_parts(
+            outer_metadata,
+            Some(outer_fallbacks.clone()),
+            Some(Arc::new(outer_values.clone())),
+            None,
+        );
 
-        let input = builder.build();
+        assert_list_structure_and_elements::<Int64Type, i32>(
+            &outer_variant,
+            outer_elements.len(),
+            &[0, 2, 4, 4, 7, 7, 7],
+            &[Some(2), Some(2), Some(0), Some(3), None, None],
+            &[
+                None,
+                None,
+                None,
+                None,
+                Some(Variant::from("not a list inner")),
+                Some(Variant::Null),
+            ],
+            (
+                &[Some(1), Some(2), Some(3), Some(4), Some(5), None, None],
+                &[
+                    None,
+                    None,
+                    None,
+                    None,
+                    None,
+                    Some(Variant::from("bad")),
+                    Some(Variant::Null),
+                ],
+            ),
+        );
+    }
+
+    #[test]
+    fn test_array_shredding_with_object_elements() {
+        let input = build_variant_array(vec![
+            // Row 0: [{"id": 1, "name": "Alice"}, {"id": null}] fully shards
+            VariantRow::List(vec![
+                VariantValue::Object(vec![
+                    ("id", VariantValue::from(1i64)),
+                    ("name", VariantValue::from("Alice")),
+                ]),
+                VariantValue::Object(vec![("id", 
VariantValue::from(Variant::Null))]),
+            ]),
+            // Row 1: "not a list" -> fallback
+            VariantRow::Value(VariantValue::from("not a list")),
+            // Row 2: Null row
+            VariantRow::Null,
+        ]);
+
+        // Target schema is List<Struct<id:int64,name:utf8>>
+        let object_fields = Fields::from(vec![
+            Field::new("id", DataType::Int64, true),
+            Field::new("name", DataType::Utf8, true),
+        ]);
+        let list_schema = DataType::List(Arc::new(Field::new(
+            "item",
+            DataType::Struct(object_fields),
+            true,
+        )));
+        let result = shred_variant(&input, &list_schema).unwrap();
+        assert_eq!(result.len(), 3);
+
+        assert_list_structure::<i32>(
+            &result,
+            3,
+            &[0, 2, 2, 2],
+            &[Some(2), None, None],
+            &[None, Some(Variant::from("not a list")), Some(Variant::Null)],
+        );
+
+        // Validate nested struct fields for each element
+        let typed_value = result
+            .typed_value_field()
+            .unwrap()
+            .as_any()
+            .downcast_ref::<ListArray>()
+            .unwrap();
+        let element_array =
+            
ShreddedVariantFieldArray::try_new(typed_value.values().as_ref()).unwrap();
+        assert_eq!(element_array.len(), 2);
+        let element_objects = element_array
+            .typed_value_field()
+            .unwrap()
+            .as_any()
+            .downcast_ref::<arrow::array::StructArray>()
+            .unwrap();
+
+        // Id field [1, Variant::Null]
+        let id_field =
+            
ShreddedVariantFieldArray::try_new(element_objects.column_by_name("id").unwrap())
+                .unwrap();
+        let id_values = id_field.value_field().unwrap();
+        let id_typed_values = id_field
+            .typed_value_field()
+            .unwrap()
+            .as_any()
+            .downcast_ref::<Int64Array>()
+            .unwrap();
+        assert!(id_values.is_null(0));
+        assert_eq!(id_typed_values.value(0), 1);
+        // null is stored as Variant::Null in values
+        assert!(id_values.is_valid(1));
+        assert_eq!(
+            Variant::new(EMPTY_VARIANT_METADATA_BYTES, id_values.value(1)),
+            Variant::Null
+        );
+        assert!(id_typed_values.is_null(1));
+
+        // Name field ["Alice", null]
+        let name_field =
+            
ShreddedVariantFieldArray::try_new(element_objects.column_by_name("name").unwrap())
+                .unwrap();
+        let name_values = name_field.value_field().unwrap();
+        let name_typed_values = name_field
+            .typed_value_field()
+            .unwrap()
+            .as_any()
+            .downcast_ref::<StringArray>()
+            .unwrap();
+        assert!(name_values.is_null(0));
+        assert_eq!(name_typed_values.value(0), "Alice");
+        // No value provided, both value and typed_value are null
+        assert!(name_values.is_null(1));
+        assert!(name_typed_values.is_null(1));
+    }
+
+    #[test]
+    fn test_object_shredding_comprehensive() {
+        let input = build_variant_array(vec![
+            // Row 0: Fully shredded object
+            VariantRow::Object(vec![
+                ("score", VariantValue::from(95.5f64)),
+                ("age", VariantValue::from(30i64)),
+            ]),
+            // Row 1: Partially shredded object (extra email field)
+            VariantRow::Object(vec![
+                ("score", VariantValue::from(87.2f64)),
+                ("age", VariantValue::from(25i64)),
+                ("email", VariantValue::from("[email protected]")),
+            ]),
+            // Row 2: Missing field (no score)
+            VariantRow::Object(vec![("age", VariantValue::from(35i64))]),
+            // Row 3: Type mismatch (score is string, age is string)
+            VariantRow::Object(vec![
+                ("score", VariantValue::from("ninety-five")),
+                ("age", VariantValue::from("thirty")),
+            ]),
+            // Row 4: Non-object
+            VariantRow::Value(VariantValue::from("not an object")),
+            // Row 5: Empty object
+            VariantRow::Object(vec![]),
+            // Row 6: Null
+            VariantRow::Null,
+            // Row 7: Object with only "wrong" fields
+            VariantRow::Object(vec![("foo", VariantValue::from(10))]),
+            // Row 8: Object with one "right" and one "wrong" field
+            VariantRow::Object(vec![
+                ("score", VariantValue::from(66.67f64)),
+                ("foo", VariantValue::from(10)),
+            ]),
+        ]);
 
         // Create target schema: struct<score: float64, age: int64>
         // Both types are supported for shredding
@@ -1207,17 +2062,106 @@ mod tests {
         );
     }
 
+    #[test]
+    fn test_object_shredding_with_array_field() {
+        let input = build_variant_array(vec![
+            // Row 0: Object with well-typed scores list
+            VariantRow::Object(vec![(
+                "scores",
+                VariantValue::List(vec![VariantValue::from(10i64), 
VariantValue::from(20i64)]),
+            )]),
+            // Row 1: Object whose scores list contains incompatible type
+            VariantRow::Object(vec![(
+                "scores",
+                VariantValue::List(vec![
+                    VariantValue::from("oops"),
+                    VariantValue::from(Variant::Null),
+                ]),
+            )]),
+            // Row 2: Object missing the scores field entirely
+            VariantRow::Object(vec![]),
+            // Row 3: Non-object fallback
+            VariantRow::Value(VariantValue::from("not an object")),
+            // Row 4: Top-level Null
+            VariantRow::Null,
+        ]);
+        let list_field = Arc::new(Field::new("item", DataType::Int64, true));
+        let inner_list_schema = DataType::List(list_field);
+        let schema = DataType::Struct(Fields::from(vec![Field::new(
+            "scores",
+            inner_list_schema.clone(),
+            true,
+        )]));
+
+        let result = shred_variant(&input, &schema).unwrap();
+        assert_eq!(result.len(), 5);
+
+        // Access base value/typed_value columns
+        let value_field = result.value_field().unwrap();
+        let typed_struct = result
+            .typed_value_field()
+            .unwrap()
+            .as_any()
+            .downcast_ref::<arrow::array::StructArray>()
+            .unwrap();
+
+        // Validate base value fallbacks for non-object rows
+        assert!(value_field.is_null(0));
+        assert!(value_field.is_null(1));
+        assert!(value_field.is_null(2));
+        assert!(value_field.is_valid(3));
+        assert_eq!(
+            Variant::new(result.metadata_field().value(3), 
value_field.value(3)),
+            Variant::from("not an object")
+        );
+        assert!(value_field.is_null(4));
+
+        // Typed struct should only be null for the fallback row
+        assert!(typed_struct.is_valid(0));
+        assert!(typed_struct.is_valid(1));
+        assert!(typed_struct.is_valid(2));
+        assert!(typed_struct.is_null(3));
+        assert!(typed_struct.is_null(4));
+
+        // Drill into the scores field on the typed struct
+        let scores_field =
+            
ShreddedVariantFieldArray::try_new(typed_struct.column_by_name("scores").unwrap())
+                .unwrap();
+        assert_list_structure_and_elements::<Int64Type, i32>(
+            &VariantArray::from_parts(
+                BinaryViewArray::from_iter_values(std::iter::repeat_n(
+                    EMPTY_VARIANT_METADATA_BYTES,
+                    scores_field.len(),
+                )),
+                Some(scores_field.value_field().unwrap().clone()),
+                Some(scores_field.typed_value_field().unwrap().clone()),
+                None,
+            ),
+            scores_field.len(),
+            &[0i32, 2, 4, 4, 4, 4],
+            &[Some(2), Some(2), None, None, None],
+            &[
+                None,
+                None,
+                Some(Variant::Null),
+                Some(Variant::Null),
+                Some(Variant::Null),
+            ],
+            (
+                &[Some(10), Some(20), None, None],
+                &[None, None, Some(Variant::from("oops")), 
Some(Variant::Null)],
+            ),
+        );
+    }
+
     #[test]
     fn test_object_different_schemas() {
         // Create object with multiple fields
-        let mut builder = VariantArrayBuilder::new(1);
-        builder
-            .new_object()
-            .with_field("id", 123i32)
-            .with_field("age", 25i64)
-            .with_field("score", 95.5f64)
-            .finish();
-        let input = builder.build();
+        let input = build_variant_array(vec![VariantRow::Object(vec![
+            ("id", VariantValue::from(123i32)),
+            ("age", VariantValue::from(25i64)),
+            ("score", VariantValue::from(95.5f64)),
+        ])]);
 
         // Test with schema containing only id field
         let schema1 = ShreddedSchemaBuilder::default()
@@ -1253,44 +2197,33 @@ mod tests {
         let mock_uuid_2 = Uuid::new_v4();
         let mock_uuid_3 = Uuid::new_v4();
 
-        let mut builder = VariantArrayBuilder::new(6);
-
-        // Row 0: Fully shredded object with both UUID fields
-        builder
-            .new_object()
-            .with_field("id", mock_uuid_1)
-            .with_field("session_id", mock_uuid_2)
-            .finish();
-
-        // Row 1: Partially shredded object - UUID fields plus extra field
-        builder
-            .new_object()
-            .with_field("id", mock_uuid_2)
-            .with_field("session_id", mock_uuid_3)
-            .with_field("name", "test_user")
-            .finish();
-
-        // Row 2: Missing UUID field (no session_id)
-        builder.new_object().with_field("id", mock_uuid_1).finish();
-
-        // Row 3: Type mismatch - id is UUID but session_id is a string
-        builder
-            .new_object()
-            .with_field("id", mock_uuid_3)
-            .with_field("session_id", "not-a-uuid")
-            .finish();
-
-        // Row 4: Object with non-UUID value in id field
-        builder
-            .new_object()
-            .with_field("id", 12345i64)
-            .with_field("session_id", mock_uuid_1)
-            .finish();
-
-        // Row 5: Null
-        builder.append_null();
-
-        let input = builder.build();
+        let input = build_variant_array(vec![
+            // Row 0: Fully shredded object with both UUID fields
+            VariantRow::Object(vec![
+                ("id", VariantValue::from(mock_uuid_1)),
+                ("session_id", VariantValue::from(mock_uuid_2)),
+            ]),
+            // Row 1: Partially shredded object - UUID fields plus extra field
+            VariantRow::Object(vec![
+                ("id", VariantValue::from(mock_uuid_2)),
+                ("session_id", VariantValue::from(mock_uuid_3)),
+                ("name", VariantValue::from("test_user")),
+            ]),
+            // Row 2: Missing UUID field (no session_id)
+            VariantRow::Object(vec![("id", VariantValue::from(mock_uuid_1))]),
+            // Row 3: Type mismatch - id is UUID but session_id is a string
+            VariantRow::Object(vec![
+                ("id", VariantValue::from(mock_uuid_3)),
+                ("session_id", VariantValue::from("not-a-uuid")),
+            ]),
+            // Row 4: Object with non-UUID value in id field
+            VariantRow::Object(vec![
+                ("id", VariantValue::from(12345i64)),
+                ("session_id", VariantValue::from(mock_uuid_1)),
+            ]),
+            // Row 5: Null
+            VariantRow::Null,
+        ]);
 
         let target_schema = ShreddedSchemaBuilder::default()
             .with_path("id", DataType::FixedSizeBinary(16))
@@ -1556,21 +2489,18 @@ mod tests {
 
     #[test]
     fn test_variant_schema_builder_with_shred_variant() {
-        let mut builder = VariantArrayBuilder::new(3);
-        builder
-            .new_object()
-            .with_field("time", 1234567890i64)
-            .with_field("hostname", "server1")
-            .with_field("extra", 42)
-            .finish();
-        builder
-            .new_object()
-            .with_field("time", 9876543210i64)
-            .with_field("hostname", "server2")
-            .finish();
-        builder.append_null();
-
-        let input = builder.build();
+        let input = build_variant_array(vec![
+            VariantRow::Object(vec![
+                ("time", VariantValue::from(1234567890i64)),
+                ("hostname", VariantValue::from("server1")),
+                ("extra", VariantValue::from(42)),
+            ]),
+            VariantRow::Object(vec![
+                ("time", VariantValue::from(9876543210i64)),
+                ("hostname", VariantValue::from("server2")),
+            ]),
+            VariantRow::Null,
+        ]);
 
         let shredding_type = ShreddedSchemaBuilder::default()
             .with_path("time", &DataType::Int64)

Reply via email to