1use crate::type_conversion::VariantCastMode;
21use crate::variant_array::ShreddedVariantFieldArray;
22use crate::variant_to_arrow::{
23 ArrayVariantToArrowRowBuilder, PrimitiveVariantToArrowRowBuilder,
24 make_primitive_variant_to_arrow_row_builder,
25};
26use crate::{VariantArray, VariantValueArrayBuilder};
27use arrow::array::{ArrayRef, BinaryViewArray, NullBufferBuilder, StructArrayAssembler};
28use arrow::buffer::NullBuffer;
29use arrow::compute::CastOptions;
30use arrow::datatypes::{DataType, Field, FieldRef, Fields, TimeUnit};
31use arrow::error::{ArrowError, Result};
32use indexmap::IndexMap;
33use parquet_variant::{Variant, VariantBuilderExt, VariantPath, VariantPathElement};
34use std::collections::BTreeMap;
35use std::sync::Arc;
36
37pub fn shred_variant(array: &VariantArray, as_type: &DataType) -> Result<VariantArray> {
72 shred_variant_with_options(array, as_type, &CastOptions::default())
73}
74
75pub(crate) fn shred_variant_with_options(
76 array: &VariantArray,
77 as_type: &DataType,
78 cast_options: &CastOptions,
79) -> Result<VariantArray> {
80 if array.typed_value_column().is_some() {
81 return Err(ArrowError::InvalidArgumentError(
82 "Input is already shredded".to_string(),
83 ));
84 }
85
86 let mut builder = make_variant_to_shredded_variant_arrow_row_builder(
87 as_type,
88 cast_options,
89 array.len(),
90 NullValue::TopLevelVariant,
91 VariantCastMode::Shred,
92 )?;
93 for i in 0..array.len() {
94 if array.is_null(i) {
95 builder.append_null()?;
96 } else {
97 builder.append_value(array.value(i))?;
98 }
99 }
100 let (value, typed_value, nulls) = builder.finish()?;
101 Ok(VariantArray::from_parts(
102 array.metadata_column().clone(),
103 Arc::new(value),
104 Some(typed_value),
105 nulls,
106 ))
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, Eq)]
117pub(crate) enum NullValue {
118 TopLevelVariant,
119 ObjectField,
120 ArrayElement,
121}
122
123impl NullValue {
124 fn append_to(
125 self,
126 nulls: &mut NullBufferBuilder,
127 value_builder: &mut VariantValueArrayBuilder,
128 ) {
129 match self {
130 Self::TopLevelVariant => nulls.append_null(),
131 Self::ObjectField | Self::ArrayElement => nulls.append_non_null(),
132 }
133 match self {
134 Self::TopLevelVariant | Self::ObjectField => value_builder.append_null(),
135 Self::ArrayElement => value_builder.append_value(Variant::Null),
136 }
137 }
138}
139
140pub(crate) fn make_variant_to_shredded_variant_arrow_row_builder<'a>(
141 data_type: &'a DataType,
142 cast_options: &'a CastOptions,
143 capacity: usize,
144 null_value: NullValue,
145 cast_mode: VariantCastMode,
146) -> Result<VariantToShreddedVariantRowBuilder<'a>> {
147 let builder = match data_type {
148 DataType::Struct(fields) => {
149 let typed_value_builder = VariantToShreddedObjectVariantRowBuilder::try_new(
150 fields,
151 cast_options,
152 capacity,
153 null_value,
154 cast_mode,
155 )?;
156 VariantToShreddedVariantRowBuilder::Object(typed_value_builder)
157 }
158 DataType::List(_)
159 | DataType::LargeList(_)
160 | DataType::ListView(_)
161 | DataType::LargeListView(_) => {
162 let typed_value_builder = VariantToShreddedArrayVariantRowBuilder::try_new(
163 data_type,
164 cast_options,
165 capacity,
166 null_value,
167 )?;
168 VariantToShreddedVariantRowBuilder::Array(typed_value_builder)
169 }
170 DataType::Boolean
173 | DataType::Int8
174 | DataType::Int16
175 | DataType::Int32
176 | DataType::Int64
177 | DataType::Float32
178 | DataType::Float64
179 | DataType::Decimal32(..)
180 | DataType::Decimal64(..)
181 | DataType::Decimal128(..)
182 | DataType::Date32
183 | DataType::Time64(TimeUnit::Microsecond)
184 | DataType::Timestamp(TimeUnit::Microsecond | TimeUnit::Nanosecond, _)
185 | DataType::Binary
186 | DataType::BinaryView
187 | DataType::LargeBinary
188 | DataType::Utf8
189 | DataType::Utf8View
190 | DataType::LargeUtf8
191 | DataType::FixedSizeBinary(16) => {
193 let builder =
194 make_primitive_variant_to_arrow_row_builder(data_type, cast_options, capacity, cast_mode)?;
195 let typed_value_builder =
196 VariantToShreddedPrimitiveVariantRowBuilder::new(builder, capacity, null_value);
197 VariantToShreddedVariantRowBuilder::Primitive(typed_value_builder)
198 }
199 DataType::FixedSizeBinary(_) => {
200 return Err(ArrowError::InvalidArgumentError(format!("{data_type} is not a valid variant shredding type. Only FixedSizeBinary(16) for UUID is supported.")))
201 }
202 _ => {
203 return Err(ArrowError::InvalidArgumentError(format!("{data_type} is not a valid variant shredding type")))
204 }
205 };
206 Ok(builder)
207}
208
209pub(crate) enum VariantToShreddedVariantRowBuilder<'a> {
210 Primitive(VariantToShreddedPrimitiveVariantRowBuilder<'a>),
211 Array(VariantToShreddedArrayVariantRowBuilder<'a>),
212 Object(VariantToShreddedObjectVariantRowBuilder<'a>),
213}
214
215impl VariantToShreddedVariantRowBuilder<'_> {
216 pub fn append_null(&mut self) -> Result<()> {
217 use VariantToShreddedVariantRowBuilder::*;
218 match self {
219 Primitive(b) => b.append_null(),
220 Array(b) => b.append_null(),
221 Object(b) => b.append_null(),
222 }
223 }
224
225 pub fn append_value(&mut self, value: Variant<'_, '_>) -> Result<bool> {
226 use VariantToShreddedVariantRowBuilder::*;
227 match self {
228 Primitive(b) => b.append_value(value),
229 Array(b) => b.append_value(value),
230 Object(b) => b.append_value(value),
231 }
232 }
233
234 pub fn finish(self) -> Result<(BinaryViewArray, ArrayRef, Option<NullBuffer>)> {
235 use VariantToShreddedVariantRowBuilder::*;
236 match self {
237 Primitive(b) => b.finish(),
238 Array(b) => b.finish(),
239 Object(b) => b.finish(),
240 }
241 }
242}
243
244pub(crate) struct VariantToShreddedPrimitiveVariantRowBuilder<'a> {
246 value_builder: VariantValueArrayBuilder,
247 typed_value_builder: PrimitiveVariantToArrowRowBuilder<'a>,
248 nulls: NullBufferBuilder,
249 null_value: NullValue,
250}
251
252impl<'a> VariantToShreddedPrimitiveVariantRowBuilder<'a> {
253 pub(crate) fn new(
254 typed_value_builder: PrimitiveVariantToArrowRowBuilder<'a>,
255 capacity: usize,
256 null_value: NullValue,
257 ) -> Self {
258 Self {
259 value_builder: VariantValueArrayBuilder::new(capacity),
260 typed_value_builder,
261 nulls: NullBufferBuilder::new(capacity),
262 null_value,
263 }
264 }
265
266 fn append_null(&mut self) -> Result<()> {
267 self.null_value
268 .append_to(&mut self.nulls, &mut self.value_builder);
269 self.typed_value_builder.append_null()
270 }
271
272 fn append_value(&mut self, value: Variant<'_, '_>) -> Result<bool> {
273 self.nulls.append_non_null();
274 if self.typed_value_builder.append_value(&value)? {
275 self.value_builder.append_null();
276 } else {
277 self.value_builder.append_value(value);
278 }
279 Ok(true)
280 }
281
282 fn finish(mut self) -> Result<(BinaryViewArray, ArrayRef, Option<NullBuffer>)> {
283 Ok((
284 self.value_builder.build()?,
285 self.typed_value_builder.finish()?,
286 self.nulls.finish(),
287 ))
288 }
289}
290
291pub(crate) struct VariantToShreddedArrayVariantRowBuilder<'a> {
292 value_builder: VariantValueArrayBuilder,
293 typed_value_builder: ArrayVariantToArrowRowBuilder<'a>,
294 nulls: NullBufferBuilder,
295 null_value: NullValue,
296}
297
298impl<'a> VariantToShreddedArrayVariantRowBuilder<'a> {
299 fn try_new(
300 data_type: &'a DataType,
301 cast_options: &'a CastOptions,
302 capacity: usize,
303 null_value: NullValue,
304 ) -> Result<Self> {
305 Ok(Self {
306 value_builder: VariantValueArrayBuilder::new(capacity),
307 typed_value_builder: ArrayVariantToArrowRowBuilder::try_new(
308 data_type,
309 cast_options,
310 capacity,
311 true,
312 )?,
313 nulls: NullBufferBuilder::new(capacity),
314 null_value,
315 })
316 }
317
318 fn append_null(&mut self) -> Result<()> {
319 self.null_value
320 .append_to(&mut self.nulls, &mut self.value_builder);
321 self.typed_value_builder.append_null()?;
322 Ok(())
323 }
324
325 fn append_value(&mut self, variant: Variant<'_, '_>) -> Result<bool> {
326 match variant {
329 Variant::List(list) => {
330 self.nulls.append_non_null();
331 self.value_builder.append_null();
332
333 self.typed_value_builder
334 .append_value(&Variant::List(list))?;
335 Ok(true)
336 }
337 other => {
338 self.nulls.append_non_null();
339 self.value_builder.append_value(other);
340 self.typed_value_builder.append_null()?;
341 Ok(false)
342 }
343 }
344 }
345
346 fn finish(mut self) -> Result<(BinaryViewArray, ArrayRef, Option<NullBuffer>)> {
347 Ok((
348 self.value_builder.build()?,
349 self.typed_value_builder.finish()?,
350 self.nulls.finish(),
351 ))
352 }
353}
354
355pub(crate) struct VariantToShreddedObjectVariantRowBuilder<'a> {
356 value_builder: VariantValueArrayBuilder,
357 typed_value_builders: IndexMap<&'a str, VariantToShreddedVariantRowBuilder<'a>>,
358 typed_value_nulls: NullBufferBuilder,
359 nulls: NullBufferBuilder,
360 null_value: NullValue,
361 seen: Vec<bool>,
364}
365
366impl<'a> VariantToShreddedObjectVariantRowBuilder<'a> {
367 fn try_new(
368 fields: &'a Fields,
369 cast_options: &'a CastOptions,
370 capacity: usize,
371 null_value: NullValue,
372 cast_mode: VariantCastMode,
373 ) -> Result<Self> {
374 let typed_value_builders = fields.iter().map(|field| {
375 let builder = make_variant_to_shredded_variant_arrow_row_builder(
376 field.data_type(),
377 cast_options,
378 capacity,
379 NullValue::ObjectField,
380 cast_mode,
381 )?;
382 Ok((field.name().as_str(), builder))
383 });
384 let typed_value_builders: IndexMap<_, _> = typed_value_builders.collect::<Result<_>>()?;
385 Ok(Self {
386 value_builder: VariantValueArrayBuilder::new(capacity),
387 seen: vec![false; typed_value_builders.len()],
388 typed_value_builders,
389 typed_value_nulls: NullBufferBuilder::new(capacity),
390 nulls: NullBufferBuilder::new(capacity),
391 null_value,
392 })
393 }
394
395 fn append_null(&mut self) -> Result<()> {
396 self.null_value
397 .append_to(&mut self.nulls, &mut self.value_builder);
398 self.typed_value_nulls.append_null();
399 for (_, typed_value_builder) in &mut self.typed_value_builders {
400 typed_value_builder.append_null()?;
401 }
402 Ok(())
403 }
404
405 fn append_value(&mut self, value: Variant<'_, '_>) -> Result<bool> {
406 let Variant::Object(ref obj) = value else {
407 self.nulls.append_non_null();
409 self.value_builder.append_value(value);
410 self.typed_value_nulls.append_null();
411 for (_, typed_value_builder) in &mut self.typed_value_builders {
412 typed_value_builder.append_null()?;
413 }
414 return Ok(false);
415 };
416
417 let Self {
419 value_builder,
420 typed_value_builders,
421 seen,
422 ..
423 } = self;
424 seen.fill(false);
425 let mut builder = value_builder.builder_ext(value.metadata());
426 let mut object_builder = builder.try_new_object()?.with_validate_unique_fields(true);
428 let mut partially_shredded = false;
429 for (field_name, value) in obj.iter() {
430 match typed_value_builders.get_full_mut(field_name) {
431 Some((index, _, typed_value_builder)) => {
432 if seen[index] {
434 return Err(ArrowError::InvalidArgumentError(format!(
435 "Duplicate field name: {field_name}"
436 )));
437 }
438 typed_value_builder.append_value(value)?;
439 seen[index] = true;
440 }
441 None => {
442 object_builder.try_insert_bytes(field_name, value)?;
443 partially_shredded = true;
444 }
445 }
446 }
447
448 for (index, (_, typed_value_builder)) in typed_value_builders.iter_mut().enumerate() {
450 if !seen[index] {
451 typed_value_builder.append_null()?;
452 }
453 }
454
455 if partially_shredded {
457 object_builder.finish();
458 } else {
459 drop(object_builder);
460 drop(builder);
461 value_builder.append_null();
462 }
463
464 self.typed_value_nulls.append_non_null();
465 self.nulls.append_non_null();
466 Ok(true)
467 }
468
469 fn finish(mut self) -> Result<(BinaryViewArray, ArrayRef, Option<NullBuffer>)> {
470 let mut builder = StructArrayAssembler::new();
471 for (field_name, typed_value_builder) in self.typed_value_builders {
472 let (value, typed_value, nulls) = typed_value_builder.finish()?;
473 let array =
474 ShreddedVariantFieldArray::from_parts(Arc::new(value), Some(typed_value), nulls);
475 builder = builder.with_field(field_name, ArrayRef::from(array), false);
476 }
477 if let Some(nulls) = self.typed_value_nulls.finish() {
478 builder = builder.with_nulls(nulls);
479 }
480 Ok((
481 self.value_builder.build()?,
482 Arc::new(builder.build()?),
483 self.nulls.finish(),
484 ))
485 }
486}
487
488#[derive(Clone)]
490pub struct ShreddingField {
491 data_type: DataType,
492 nullable: bool,
493}
494
495impl ShreddingField {
496 fn new(data_type: DataType, nullable: bool) -> Self {
497 Self {
498 data_type,
499 nullable,
500 }
501 }
502
503 fn null() -> Self {
504 Self::new(DataType::Null, true)
505 }
506}
507
508pub trait IntoShreddingField {
510 fn into_shredding_field(self) -> ShreddingField;
511}
512
513impl IntoShreddingField for FieldRef {
514 fn into_shredding_field(self) -> ShreddingField {
515 ShreddingField::new(self.data_type().clone(), self.is_nullable())
516 }
517}
518
519impl IntoShreddingField for &DataType {
520 fn into_shredding_field(self) -> ShreddingField {
521 ShreddingField::new(self.clone(), true)
522 }
523}
524
525impl IntoShreddingField for DataType {
526 fn into_shredding_field(self) -> ShreddingField {
527 ShreddingField::new(self, true)
528 }
529}
530
531impl IntoShreddingField for (&DataType, bool) {
532 fn into_shredding_field(self) -> ShreddingField {
533 ShreddingField::new(self.0.clone(), self.1)
534 }
535}
536
537impl IntoShreddingField for (DataType, bool) {
538 fn into_shredding_field(self) -> ShreddingField {
539 ShreddingField::new(self.0, self.1)
540 }
541}
542
543#[derive(Default, Clone)]
587pub struct ShreddedSchemaBuilder {
588 root: VariantSchemaNode,
589}
590
591impl ShreddedSchemaBuilder {
592 pub fn new() -> Self {
594 Self::default()
595 }
596
597 pub fn with_path<'a, P, F>(mut self, path: P, field: F) -> Result<Self>
611 where
612 P: TryInto<VariantPath<'a>>,
613 P::Error: std::fmt::Debug,
614 F: IntoShreddingField,
615 {
616 let path: VariantPath<'a> = path
617 .try_into()
618 .map_err(|e| ArrowError::InvalidArgumentError(format!("{e:?}")))?;
619 self.root.insert_path(&path, field.into_shredding_field())?;
620 Ok(self)
621 }
622
623 pub fn build(self) -> DataType {
625 let shredding_type = self.root.to_shredding_type();
626 match shredding_type {
627 Some(shredding_type) => shredding_type,
628 None => DataType::Null,
629 }
630 }
631}
632
633#[derive(Clone)]
635enum VariantSchemaNode {
636 Leaf(ShreddingField),
638 Struct(BTreeMap<String, VariantSchemaNode>),
640 List(Box<VariantSchemaNode>),
642}
643
644impl Default for VariantSchemaNode {
645 fn default() -> Self {
646 Self::Leaf(ShreddingField::null())
647 }
648}
649
650impl VariantSchemaNode {
651 fn insert_path(&mut self, path: &VariantPath<'_>, field: ShreddingField) -> Result<()> {
653 self.insert_path_elements(path, field)
654 }
655
656 fn insert_path_elements(
657 &mut self,
658 segments: &[VariantPathElement<'_>],
659 field: ShreddingField,
660 ) -> Result<()> {
661 let Some((head, tail)) = segments.split_first() else {
662 *self = Self::Leaf(field);
663 return Ok(());
664 };
665
666 match head {
667 VariantPathElement::Field { name } => {
668 let children = match self {
670 Self::Struct(children) => children,
671 Self::Leaf(_) | Self::List(_) => {
672 *self = Self::Struct(BTreeMap::new());
673 match self {
674 Self::Struct(children) => children,
675 Self::Leaf(_) | Self::List(_) => unreachable!(),
676 }
677 }
678 };
679
680 children
681 .entry(name.to_string())
682 .or_default()
683 .insert_path_elements(tail, field)
684 }
685 VariantPathElement::ListElement => {
686 let element = match self {
687 Self::List(element) => element,
688 _ => {
689 *self = Self::List(Box::default());
690 match self {
691 Self::List(element) => element,
692 _ => unreachable!(),
693 }
694 }
695 };
696
697 element.insert_path_elements(tail, field)
698 }
699 VariantPathElement::Index { index } => Err(ArrowError::InvalidArgumentError(format!(
700 "List indexes are not supported in schema paths; use [*], got [{index}]"
701 ))),
702 }
703 }
704
705 fn to_shredding_type(&self) -> Option<DataType> {
709 match self {
710 Self::Leaf(field) => Some(field.data_type.clone()),
711 Self::Struct(children) => {
712 let child_fields: Vec<_> = children
713 .iter()
714 .filter_map(|(name, child)| child.to_shredding_field(name))
715 .collect();
716 if child_fields.is_empty() {
717 None
718 } else {
719 Some(DataType::Struct(Fields::from(child_fields)))
720 }
721 }
722 Self::List(element) => element.to_shredding_field("item").map(DataType::List),
723 }
724 }
725
726 fn to_shredding_field(&self, name: &str) -> Option<FieldRef> {
727 match self {
728 Self::Leaf(field) => Some(Arc::new(Field::new(
729 name,
730 field.data_type.clone(),
731 field.nullable,
732 ))),
733 Self::Struct(_) | Self::List(_) => self
734 .to_shredding_type()
735 .map(|data_type| Arc::new(Field::new(name, data_type, true))),
736 }
737 }
738}
739
740#[cfg(test)]
741mod tests {
742 use super::*;
743 use crate::VariantArrayBuilder;
744 use crate::variant_array::{all_null_value_column, binary_array_value, variant_from_arrays_at};
745 use arrow::array::{
746 Array, BinaryViewArray, Decimal32Array, Decimal64Array, Decimal128Array,
747 FixedSizeBinaryArray, Float64Array, GenericListArray, GenericListViewArray, Int64Array,
748 LargeBinaryArray, LargeStringArray, ListArray, ListLikeArray, OffsetSizeTrait,
749 PrimitiveArray, StringArray, StructArray,
750 };
751 use arrow::datatypes::{
752 ArrowPrimitiveType, DataType, Field, Fields, Int64Type, TimeUnit, UnionFields, UnionMode,
753 };
754 use arrow_schema::IntervalUnit;
755 use chrono::{DateTime, NaiveDate, NaiveTime};
756 use parquet_variant::{
757 BuilderSpecificState, EMPTY_VARIANT_METADATA_BYTES, ObjectBuilder, ReadOnlyMetadataBuilder,
758 ShortString, Variant, VariantBuilder, VariantDecimal4, VariantDecimal8, VariantDecimal16,
759 VariantPath, VariantPathElement,
760 };
761 use std::sync::Arc;
762 use uuid::Uuid;
763
764 const NULL_VALUES: [NullValue; 3] = [
765 NullValue::TopLevelVariant,
766 NullValue::ObjectField,
767 NullValue::ArrayElement,
768 ];
769
770 #[derive(Clone)]
771 enum VariantValue<'a> {
772 Value(Variant<'a, 'a>),
773 List(Vec<VariantValue<'a>>),
774 Object(Vec<(&'a str, VariantValue<'a>)>),
775 Null,
776 }
777
778 impl<'a, T> From<T> for VariantValue<'a>
779 where
780 T: Into<Variant<'a, 'a>>,
781 {
782 fn from(value: T) -> Self {
783 Self::Value(value.into())
784 }
785 }
786
787 #[derive(Clone)]
788 enum VariantRow<'a> {
789 Value(VariantValue<'a>),
790 List(Vec<VariantValue<'a>>),
791 Object(Vec<(&'a str, VariantValue<'a>)>),
792 Null,
793 }
794
795 fn build_variant_array(rows: Vec<VariantRow<'static>>) -> VariantArray {
796 let mut builder = VariantArrayBuilder::new(rows.len());
797
798 fn append_variant_value<B: VariantBuilderExt>(builder: &mut B, value: VariantValue) {
799 match value {
800 VariantValue::Value(v) => builder.append_value(v),
801 VariantValue::List(values) => {
802 let mut list = builder.new_list();
803 for v in values {
804 append_variant_value(&mut list, v);
805 }
806 list.finish();
807 }
808 VariantValue::Object(fields) => {
809 let mut object = builder.new_object();
810 for (name, value) in fields {
811 append_variant_field(&mut object, name, value);
812 }
813 object.finish();
814 }
815 VariantValue::Null => builder.append_null(),
816 }
817 }
818
819 fn append_variant_field<'a, S: BuilderSpecificState>(
820 object: &mut ObjectBuilder<'_, S>,
821 name: &'a str,
822 value: VariantValue<'a>,
823 ) {
824 match value {
825 VariantValue::Value(v) => {
826 object.insert(name, v);
827 }
828 VariantValue::List(values) => {
829 let mut list = object.new_list(name);
830 for v in values {
831 append_variant_value(&mut list, v);
832 }
833 list.finish();
834 }
835 VariantValue::Object(fields) => {
836 let mut nested = object.new_object(name);
837 for (field_name, v) in fields {
838 append_variant_field(&mut nested, field_name, v);
839 }
840 nested.finish();
841 }
842 VariantValue::Null => {
843 object.insert(name, Variant::Null);
844 }
845 }
846 }
847
848 rows.into_iter().for_each(|row| match row {
849 VariantRow::Value(value) => append_variant_value(&mut builder, value),
850 VariantRow::List(values) => {
851 let mut list = builder.new_list();
852 for value in values {
853 append_variant_value(&mut list, value);
854 }
855 list.finish();
856 }
857 VariantRow::Object(fields) => {
858 let mut object = builder.new_object();
859 for (name, value) in fields {
860 append_variant_field(&mut object, name, value);
861 }
862 object.finish();
863 }
864 VariantRow::Null => builder.append_null(),
865 });
866 builder.build()
867 }
868
869 trait TestListLikeArray: ListLikeArray {
870 type OffsetSize: OffsetSizeTrait;
871 fn value_offsets(&self) -> Option<&[Self::OffsetSize]>;
872 fn value_size(&self, index: usize) -> Self::OffsetSize;
873 }
874
875 impl<O: OffsetSizeTrait> TestListLikeArray for GenericListArray<O> {
876 type OffsetSize = O;
877
878 fn value_offsets(&self) -> Option<&[Self::OffsetSize]> {
879 Some(GenericListArray::value_offsets(self))
880 }
881
882 fn value_size(&self, index: usize) -> Self::OffsetSize {
883 GenericListArray::value_length(self, index)
884 }
885 }
886
887 impl<O: OffsetSizeTrait> TestListLikeArray for GenericListViewArray<O> {
888 type OffsetSize = O;
889
890 fn value_offsets(&self) -> Option<&[Self::OffsetSize]> {
891 Some(GenericListViewArray::value_offsets(self))
892 }
893
894 fn value_size(&self, index: usize) -> Self::OffsetSize {
895 GenericListViewArray::value_size(self, index)
896 }
897 }
898
899 fn downcast_list_like_array<O: OffsetSizeTrait>(
900 array: &VariantArray,
901 ) -> &dyn TestListLikeArray<OffsetSize = O> {
902 let typed_value = array.typed_value_column().unwrap();
903 if let Some(list) = typed_value.as_any().downcast_ref::<GenericListArray<O>>() {
904 list
905 } else if let Some(list_view) = typed_value
906 .as_any()
907 .downcast_ref::<GenericListViewArray<O>>()
908 {
909 list_view
910 } else {
911 panic!(
912 "Expected list-like typed_value with matching offset type, got {}",
913 typed_value.data_type()
914 );
915 }
916 }
917
918 fn assert_list_structure<O: OffsetSizeTrait>(
919 array: &VariantArray,
920 expected_len: usize,
921 expected_offsets: &[O],
922 expected_sizes: &[Option<O>],
923 expected_fallbacks: &[Option<Variant<'static, 'static>>],
924 ) {
925 assert_eq!(array.len(), expected_len);
926
927 let fallback_value = array.value_column();
928 let fallback_metadata = array.metadata_column();
929 let array = downcast_list_like_array::<O>(array);
930
931 assert_eq!(
932 array.value_offsets().unwrap(),
933 expected_offsets,
934 "list offsets mismatch"
935 );
936 assert_eq!(
937 array.len(),
938 expected_sizes.len(),
939 "expected_sizes should match array length"
940 );
941 assert_eq!(
942 array.len(),
943 expected_fallbacks.len(),
944 "expected_fallbacks should match array length"
945 );
946 assert_eq!(
947 array.len(),
948 fallback_value.len(),
949 "fallbacks value field should match array length"
950 );
951
952 for (idx, (expected_size, expected_fallback)) in expected_sizes
954 .iter()
955 .zip(expected_fallbacks.iter())
956 .enumerate()
957 {
958 match expected_size {
959 Some(len) => {
960 assert!(array.is_valid(idx));
962 assert_eq!(array.value_size(idx), *len);
963 assert!(fallback_value.is_null(idx));
964 }
965 None => {
966 assert!(array.is_null(idx));
968 assert_eq!(array.value_size(idx), O::zero());
969 match expected_fallback {
970 Some(expected_variant) => {
971 assert!(fallback_value.is_valid(idx));
972 let metadata_bytes =
973 binary_array_value(fallback_metadata.as_ref(), idx).unwrap();
974 let metadata_bytes =
975 if fallback_metadata.is_valid(idx) && !metadata_bytes.is_empty() {
976 metadata_bytes
977 } else {
978 EMPTY_VARIANT_METADATA_BYTES
979 };
980 assert_eq!(
981 Variant::new(
982 metadata_bytes,
983 binary_array_value(fallback_value.as_ref(), idx).unwrap()
984 ),
985 expected_variant.clone()
986 );
987 }
988 None => {
989 assert!(fallback_value.is_null(idx));
990 }
991 }
992 }
993 }
994 }
995 }
996
997 fn assert_list_structure_and_elements<T: ArrowPrimitiveType, O: OffsetSizeTrait>(
998 array: &VariantArray,
999 expected_len: usize,
1000 expected_offsets: &[O],
1001 expected_sizes: &[Option<O>],
1002 expected_fallbacks: &[Option<Variant<'static, 'static>>],
1003 expected_shredded_elements: (&[Option<T::Native>], &[Option<Variant<'static, 'static>>]),
1004 ) {
1005 assert_list_structure(
1006 array,
1007 expected_len,
1008 expected_offsets,
1009 expected_sizes,
1010 expected_fallbacks,
1011 );
1012 let array = downcast_list_like_array::<O>(array);
1013
1014 let (expected_values, expected_fallbacks) = expected_shredded_elements;
1016 assert_eq!(
1017 expected_values.len(),
1018 expected_fallbacks.len(),
1019 "expected_values and expected_fallbacks should be aligned"
1020 );
1021
1022 let element_array = ShreddedVariantFieldArray::try_new(array.values().as_ref()).unwrap();
1024 let element_values = element_array
1025 .typed_value_column()
1026 .unwrap()
1027 .as_any()
1028 .downcast_ref::<PrimitiveArray<T>>()
1029 .unwrap();
1030 assert_eq!(element_values.len(), expected_values.len());
1031 for (idx, expected_value) in expected_values.iter().enumerate() {
1032 match expected_value {
1033 Some(value) => {
1034 assert!(element_values.is_valid(idx));
1035 assert_eq!(element_values.value(idx), *value);
1036 }
1037 None => assert!(element_values.is_null(idx)),
1038 }
1039 }
1040
1041 let element_fallbacks = element_array.value_column();
1043 assert_eq!(element_fallbacks.len(), expected_fallbacks.len());
1044 for (idx, expected_fallback) in expected_fallbacks.iter().enumerate() {
1045 match expected_fallback {
1046 Some(expected_variant) => {
1047 assert!(element_fallbacks.is_valid(idx));
1048 assert_eq!(
1049 Variant::new(
1050 EMPTY_VARIANT_METADATA_BYTES,
1051 binary_array_value(element_fallbacks.as_ref(), idx).unwrap()
1052 ),
1053 expected_variant.clone()
1054 );
1055 }
1056 None => assert!(element_fallbacks.is_null(idx)),
1057 }
1058 }
1059 }
1060
1061 fn assert_append_null_mode_value_and_struct_nulls(
1062 mode: NullValue,
1063 value: &BinaryViewArray,
1064 nulls: Option<&arrow::buffer::NullBuffer>,
1065 ) {
1066 if mode == NullValue::TopLevelVariant {
1067 assert!(nulls.is_some_and(|n| n.is_null(0)));
1068 } else {
1069 assert!(nulls.is_none());
1070 }
1071
1072 if mode == NullValue::ArrayElement {
1073 assert!(value.is_valid(0));
1074 assert_eq!(
1075 Variant::new(EMPTY_VARIANT_METADATA_BYTES, value.value(0)),
1076 Variant::Null
1077 );
1078 } else {
1079 assert!(value.is_null(0));
1080 }
1081 }
1082
1083 #[test]
1084 fn test_append_null_mode_semantics_primitive_builder() {
1085 let cast_options = arrow::compute::CastOptions::default();
1086
1087 for mode in NULL_VALUES {
1088 let mut primitive_builder = make_variant_to_shredded_variant_arrow_row_builder(
1089 &DataType::Int64,
1090 &cast_options,
1091 1,
1092 mode,
1093 VariantCastMode::Shred,
1094 )
1095 .unwrap();
1096 primitive_builder.append_null().unwrap();
1097 let (primitive_value, primitive_typed_value, primitive_nulls) =
1098 primitive_builder.finish().unwrap();
1099 let primitive_typed_value = primitive_typed_value
1100 .as_any()
1101 .downcast_ref::<Int64Array>()
1102 .unwrap();
1103
1104 assert!(primitive_typed_value.is_null(0));
1105 assert_append_null_mode_value_and_struct_nulls(
1106 mode,
1107 &primitive_value,
1108 primitive_nulls.as_ref(),
1109 );
1110 }
1111 }
1112
1113 #[test]
1114 fn test_append_null_mode_semantics_array_builder() {
1115 let cast_options = arrow::compute::CastOptions::default();
1116 let list_type = DataType::List(Arc::new(Field::new("item", DataType::Int64, true)));
1117
1118 for mode in NULL_VALUES {
1119 let mut array_builder = make_variant_to_shredded_variant_arrow_row_builder(
1120 &list_type,
1121 &cast_options,
1122 1,
1123 mode,
1124 VariantCastMode::Shred,
1125 )
1126 .unwrap();
1127 array_builder.append_null().unwrap();
1128 let (value, typed_value, nulls) = array_builder.finish().unwrap();
1129
1130 assert_append_null_mode_value_and_struct_nulls(mode, &value, nulls.as_ref());
1131
1132 let typed_value = typed_value.as_any().downcast_ref::<ListArray>().unwrap();
1133 assert_eq!(typed_value.len(), 1);
1134 assert!(typed_value.is_null(0));
1135 assert_eq!(typed_value.values().len(), 0);
1136 }
1137 }
1138
1139 #[test]
1140 fn test_append_null_mode_semantics_object_builder() {
1141 let cast_options = arrow::compute::CastOptions::default();
1142 let object_type = DataType::Struct(Fields::from(vec![
1143 Field::new("id", DataType::Int64, true),
1144 Field::new("name", DataType::Utf8, true),
1145 ]));
1146
1147 for mode in NULL_VALUES {
1148 let mut object_builder = make_variant_to_shredded_variant_arrow_row_builder(
1149 &object_type,
1150 &cast_options,
1151 1,
1152 mode,
1153 VariantCastMode::Shred,
1154 )
1155 .unwrap();
1156 object_builder.append_null().unwrap();
1157 let (value, typed_value, nulls) = object_builder.finish().unwrap();
1158
1159 assert_append_null_mode_value_and_struct_nulls(mode, &value, nulls.as_ref());
1160
1161 let typed_struct = typed_value
1162 .as_any()
1163 .downcast_ref::<arrow::array::StructArray>()
1164 .unwrap();
1165 assert_eq!(typed_struct.len(), 1);
1166 assert!(typed_struct.is_null(0));
1167
1168 for field_name in ["id", "name"] {
1169 let field = ShreddedVariantFieldArray::try_new(
1170 typed_struct.column_by_name(field_name).unwrap(),
1171 )
1172 .unwrap();
1173 assert!(field.value_column().is_null(0));
1174 assert!(field.typed_value_column().unwrap().is_null(0));
1175 }
1176 }
1177 }
1178
1179 #[test]
1180 fn test_already_shredded_input_error() {
1181 let temp_array = VariantArray::from_iter([Some("test")]);
1184 let metadata = temp_array.metadata_column().clone();
1185 let value = temp_array.value_column().clone();
1186 let typed_value = Arc::new(Int64Array::from(vec![42])) as ArrayRef;
1187
1188 let shredded_array = VariantArray::from_parts(metadata, value, Some(typed_value), None);
1189
1190 let result = shred_variant(&shredded_array, &DataType::Int64);
1191 assert!(matches!(
1192 result.unwrap_err(),
1193 ArrowError::InvalidArgumentError(_)
1194 ));
1195 }
1196
1197 #[test]
1198 fn test_all_null_input() {
1199 let metadata = Arc::new(BinaryViewArray::from_iter_values([
1201 EMPTY_VARIANT_METADATA_BYTES,
1202 ]));
1203 let all_null_array =
1204 VariantArray::from_parts(metadata, all_null_value_column(1), None, None);
1205 let result = shred_variant(&all_null_array, &DataType::Int64).unwrap();
1206
1207 assert!(result.typed_value_column().unwrap().is_null(0));
1210 assert_eq!(result.value(0), Variant::Null);
1211 }
1212
1213 #[test]
1214 fn test_invalid_fixed_size_binary_shredding() {
1215 let mock_uuid_1 = Uuid::new_v4();
1216
1217 let input = VariantArray::from_iter([Some(mock_uuid_1), None]);
1218
1219 let err = shred_variant(&input, &DataType::FixedSizeBinary(17)).unwrap_err();
1221
1222 assert_eq!(
1223 err.to_string(),
1224 "Invalid argument error: FixedSizeBinary(17) is not a valid variant shredding type. Only FixedSizeBinary(16) for UUID is supported."
1225 );
1226 }
1227
1228 #[test]
1229 fn test_uuid_shredding() {
1230 let mock_uuid_1 = Uuid::new_v4();
1231 let mock_uuid_2 = Uuid::new_v4();
1232
1233 let input = VariantArray::from_iter([
1234 Some(Variant::from(mock_uuid_1)),
1235 None,
1236 Some(Variant::from(false)),
1237 Some(Variant::from(mock_uuid_2)),
1238 ]);
1239
1240 let variant_array = shred_variant(&input, &DataType::FixedSizeBinary(16)).unwrap();
1241
1242 let typed_value_field = variant_array.inner().field_by_name("typed_value").unwrap();
1243
1244 assert!(typed_value_field.has_valid_extension_type::<arrow_schema::extension::Uuid>());
1245
1246 let uuids = variant_array
1248 .typed_value_column()
1249 .unwrap()
1250 .as_any()
1251 .downcast_ref::<FixedSizeBinaryArray>()
1252 .unwrap();
1253
1254 assert_eq!(uuids.len(), 4);
1255
1256 assert!(!uuids.is_null(0));
1257
1258 let got_uuid_1: &[u8] = uuids.value(0);
1259 assert_eq!(got_uuid_1, mock_uuid_1.as_bytes());
1260
1261 assert!(uuids.is_null(1));
1262 assert!(uuids.is_null(2));
1263
1264 assert!(!uuids.is_null(3));
1265
1266 let got_uuid_2: &[u8] = uuids.value(3);
1267 assert_eq!(got_uuid_2, mock_uuid_2.as_bytes());
1268 }
1269
1270 #[test]
1271 fn test_uuid_nested_shredding() {
1272 let mock_uuid = Uuid::new_v4();
1273 let input = build_variant_array(vec![VariantRow::Object(vec![(
1274 "id",
1275 VariantValue::from(mock_uuid),
1276 )])]);
1277 let target = ShreddedSchemaBuilder::default()
1278 .with_path("id", DataType::FixedSizeBinary(16))
1279 .unwrap()
1280 .build();
1281
1282 let result = shred_variant(&input, &target).unwrap();
1283
1284 let typed_value = result.typed_value_column().unwrap();
1285 let typed_struct = typed_value.as_any().downcast_ref::<StructArray>().unwrap();
1286 let id =
1287 ShreddedVariantFieldArray::try_new(typed_struct.column_by_name("id").unwrap()).unwrap();
1288
1289 let leaf = id.inner().field_by_name("typed_value").unwrap();
1291
1292 assert_eq!(leaf.data_type(), &DataType::FixedSizeBinary(16));
1293 assert!(leaf.has_valid_extension_type::<arrow_schema::extension::Uuid>());
1294 }
1295
1296 #[test]
1297 fn test_primitive_shredding_comprehensive() {
1298 let input = VariantArray::from_iter(vec![
1300 Some(Variant::from(42i64)), Some(Variant::from("hello")), Some(Variant::from(100i64)), None, Some(Variant::Null), Some(Variant::from(3i8)), ]);
1307
1308 let result = shred_variant(&input, &DataType::Int64).unwrap();
1309
1310 let metadata_field = result.metadata_column();
1312 let value_field = result.value_column();
1313 let typed_value_field = result
1314 .typed_value_column()
1315 .unwrap()
1316 .as_any()
1317 .downcast_ref::<Int64Array>()
1318 .unwrap();
1319
1320 assert_eq!(result.len(), 6);
1322
1323 assert!(!result.is_null(0));
1325 assert!(value_field.is_null(0)); assert!(!typed_value_field.is_null(0));
1327 assert_eq!(typed_value_field.value(0), 42);
1328
1329 assert!(!result.is_null(1));
1331 assert!(!value_field.is_null(1)); assert!(typed_value_field.is_null(1)); assert_eq!(
1334 variant_from_arrays_at(metadata_field, value_field, 1).unwrap(),
1335 Variant::from("hello")
1336 );
1337
1338 assert!(!result.is_null(2));
1340 assert!(value_field.is_null(2));
1341 assert_eq!(typed_value_field.value(2), 100);
1342
1343 assert!(result.is_null(3));
1345
1346 assert!(!result.is_null(4));
1348 assert!(!value_field.is_null(4)); assert_eq!(
1350 variant_from_arrays_at(metadata_field, value_field, 4).unwrap(),
1351 Variant::Null
1352 );
1353 assert!(typed_value_field.is_null(4));
1354
1355 assert!(!result.is_null(5));
1357 assert!(value_field.is_null(5)); assert!(!typed_value_field.is_null(5));
1359 assert_eq!(typed_value_field.value(5), 3);
1360 }
1361
1362 #[test]
1363 fn test_primitive_different_target_types() {
1364 let input = VariantArray::from_iter(vec![
1365 Variant::from(42i32),
1366 Variant::from(3.15f64),
1367 Variant::from("not_a_number"),
1368 ]);
1369
1370 let result_int32 = shred_variant(&input, &DataType::Int32).unwrap();
1372 let typed_value_int32 = result_int32
1373 .typed_value_column()
1374 .unwrap()
1375 .as_any()
1376 .downcast_ref::<arrow::array::Int32Array>()
1377 .unwrap();
1378 assert_eq!(typed_value_int32.value(0), 42);
1379 assert!(typed_value_int32.is_null(1)); assert!(typed_value_int32.is_null(2)); let result_float64 = shred_variant(&input, &DataType::Float64).unwrap();
1384 let typed_value_float64 = result_float64
1385 .typed_value_column()
1386 .unwrap()
1387 .as_any()
1388 .downcast_ref::<Float64Array>()
1389 .unwrap();
1390 assert!(typed_value_float64.is_null(0)); assert_eq!(typed_value_float64.value(1), 3.15);
1392 assert!(typed_value_float64.is_null(2)); }
1394
1395 #[test]
1396 fn test_largeutf8_shredding() {
1397 let input = VariantArray::from_iter(vec![
1398 Some(Variant::from("hello")),
1399 Some(Variant::from(42i64)),
1400 None,
1401 Some(Variant::Null),
1402 Some(Variant::from("world")),
1403 ]);
1404
1405 let result = shred_variant(&input, &DataType::LargeUtf8).unwrap();
1406 let metadata = result.metadata_column();
1407 let value = result.value_column();
1408 let typed_value = result
1409 .typed_value_column()
1410 .unwrap()
1411 .as_any()
1412 .downcast_ref::<LargeStringArray>()
1413 .unwrap();
1414
1415 assert_eq!(result.len(), 5);
1416
1417 assert!(result.is_valid(0));
1419 assert!(value.is_null(0));
1420 assert_eq!(typed_value.value(0), "hello");
1421
1422 assert!(result.is_valid(1));
1424 assert!(value.is_valid(1));
1425 assert!(typed_value.is_null(1));
1426 assert_eq!(
1427 variant_from_arrays_at(metadata, value, 1).unwrap(),
1428 Variant::from(42i64)
1429 );
1430
1431 assert!(result.is_null(2));
1433 assert!(value.is_null(2));
1434 assert!(typed_value.is_null(2));
1435
1436 assert!(result.is_valid(3));
1438 assert!(value.is_valid(3));
1439 assert!(typed_value.is_null(3));
1440 assert_eq!(
1441 variant_from_arrays_at(metadata, value, 3).unwrap(),
1442 Variant::Null
1443 );
1444
1445 assert!(result.is_valid(4));
1447 assert!(value.is_null(4));
1448 assert_eq!(typed_value.value(4), "world");
1449 }
1450
1451 #[test]
1452 fn test_largebinary_shredding() {
1453 let input = VariantArray::from_iter(vec![
1454 Some(Variant::from(&b"\x00\x01\x02"[..])),
1455 Some(Variant::from("not_binary")),
1456 None,
1457 Some(Variant::Null),
1458 Some(Variant::from(&b"\xff\xaa"[..])),
1459 ]);
1460
1461 let result = shred_variant(&input, &DataType::LargeBinary).unwrap();
1462 let metadata = result.metadata_column();
1463 let value = result.value_column();
1464 let typed_value = result
1465 .typed_value_column()
1466 .unwrap()
1467 .as_any()
1468 .downcast_ref::<LargeBinaryArray>()
1469 .unwrap();
1470
1471 assert_eq!(result.len(), 5);
1472
1473 assert!(result.is_valid(0));
1475 assert!(value.is_null(0));
1476 assert_eq!(typed_value.value(0), &[0x00, 0x01, 0x02]);
1477
1478 assert!(result.is_valid(1));
1480 assert!(value.is_valid(1));
1481 assert!(typed_value.is_null(1));
1482 assert_eq!(
1483 variant_from_arrays_at(metadata, value, 1).unwrap(),
1484 Variant::from("not_binary")
1485 );
1486
1487 assert!(result.is_null(2));
1489 assert!(value.is_null(2));
1490 assert!(typed_value.is_null(2));
1491
1492 assert!(result.is_valid(3));
1494 assert!(value.is_valid(3));
1495 assert!(typed_value.is_null(3));
1496 assert_eq!(
1497 variant_from_arrays_at(metadata, value, 3).unwrap(),
1498 Variant::Null
1499 );
1500
1501 assert!(result.is_valid(4));
1503 assert!(value.is_null(4));
1504 assert_eq!(typed_value.value(4), &[0xff, 0xaa]);
1505 }
1506
1507 #[test]
1508 fn test_invalid_shredded_types_rejected() {
1509 let input = VariantArray::from_iter([Some(42)]);
1510
1511 let invalid_types = vec![
1512 DataType::UInt8,
1513 DataType::Float16,
1514 DataType::Decimal256(38, 10),
1515 DataType::Date64,
1516 DataType::Time32(TimeUnit::Second),
1517 DataType::Time64(TimeUnit::Nanosecond),
1518 DataType::Timestamp(TimeUnit::Millisecond, None),
1519 DataType::FixedSizeList(Arc::new(Field::new("item", DataType::Int64, true)), 2),
1520 DataType::FixedSizeBinary(17),
1521 DataType::Union(
1522 UnionFields::from_fields(vec![
1523 Field::new("int_field", DataType::Int32, false),
1524 Field::new("str_field", DataType::Utf8, true),
1525 ]),
1526 UnionMode::Dense,
1527 ),
1528 DataType::Map(
1529 Arc::new(Field::new(
1530 Field::MAP_ENTRIES_FIELD_DEFAULT_NAME,
1531 DataType::Struct(Fields::from(vec![
1532 Field::new(Field::MAP_KEY_FIELD_DEFAULT_NAME, DataType::Utf8, false),
1533 Field::new(Field::MAP_VALUE_FIELD_DEFAULT_NAME, DataType::Int32, true),
1534 ])),
1535 false,
1536 )),
1537 false,
1538 ),
1539 DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)),
1540 DataType::RunEndEncoded(
1541 Arc::new(Field::new(
1542 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
1543 DataType::Int32,
1544 false,
1545 )),
1546 Arc::new(Field::new(
1547 Field::REE_VALUES_FIELD_DEFAULT_NAME,
1548 DataType::Utf8,
1549 true,
1550 )),
1551 ),
1552 ];
1553
1554 for data_type in invalid_types {
1555 let err = shred_variant(&input, &data_type).unwrap_err();
1556 assert!(
1557 matches!(err, ArrowError::InvalidArgumentError(_)),
1558 "expected InvalidArgumentError for {data_type:?}, got {err:?}"
1559 );
1560 }
1561 }
1562
1563 #[test]
1564 fn test_array_shredding_as_list() {
1565 let input = build_variant_array(vec![
1566 VariantRow::List(vec![
1568 VariantValue::from(1i64),
1569 VariantValue::from(2i64),
1570 VariantValue::from(3i64),
1571 ]),
1572 VariantRow::List(vec![
1574 VariantValue::from(1i64),
1575 VariantValue::from("two"),
1576 VariantValue::from(Variant::Null),
1577 ]),
1578 VariantRow::Value(VariantValue::from("not a list")),
1580 VariantRow::Null,
1582 VariantRow::List(vec![]),
1584 ]);
1585 let list_schema = DataType::List(Arc::new(Field::new("item", DataType::Int64, true)));
1586 let result = shred_variant(&input, &list_schema).unwrap();
1587 assert_eq!(result.len(), 5);
1588
1589 assert_list_structure_and_elements::<Int64Type, i32>(
1590 &result,
1591 5,
1592 &[0, 3, 6, 6, 6, 6],
1593 &[Some(3), Some(3), None, None, Some(0)],
1594 &[None, None, Some(Variant::from("not a list")), None, None],
1595 (
1596 &[Some(1), Some(2), Some(3), Some(1), None, None],
1597 &[
1598 None,
1599 None,
1600 None,
1601 None,
1602 Some(Variant::from("two")),
1603 Some(Variant::Null),
1604 ],
1605 ),
1606 );
1607 }
1608
1609 #[test]
1610 fn test_array_shredding_as_large_list() {
1611 let input = build_variant_array(vec![
1612 VariantRow::List(vec![VariantValue::from(1i64), VariantValue::from(2i64)]),
1614 VariantRow::Value(VariantValue::from("not a list")),
1616 VariantRow::List(vec![]),
1618 ]);
1619 let list_schema = DataType::LargeList(Arc::new(Field::new("item", DataType::Int64, true)));
1620 let result = shred_variant(&input, &list_schema).unwrap();
1621 assert_eq!(result.len(), 3);
1622
1623 assert_list_structure_and_elements::<Int64Type, i64>(
1624 &result,
1625 3,
1626 &[0, 2, 2, 2],
1627 &[Some(2), None, Some(0)],
1628 &[None, Some(Variant::from("not a list")), None],
1629 (&[Some(1), Some(2)], &[None, None]),
1630 );
1631 }
1632
1633 #[test]
1634 fn test_array_shredding_as_list_view() {
1635 let input = build_variant_array(vec![
1636 VariantRow::List(vec![
1638 VariantValue::from(1i64),
1639 VariantValue::from(2i64),
1640 VariantValue::from(3i64),
1641 ]),
1642 VariantRow::List(vec![
1644 VariantValue::from(1i64),
1645 VariantValue::from("two"),
1646 VariantValue::from(Variant::Null),
1647 ]),
1648 VariantRow::Value(VariantValue::from("not a list")),
1650 VariantRow::Null,
1652 VariantRow::List(vec![]),
1654 ]);
1655 let list_schema = DataType::ListView(Arc::new(Field::new("item", DataType::Int64, true)));
1656 let result = shred_variant(&input, &list_schema).unwrap();
1657 assert_eq!(result.len(), 5);
1658
1659 assert_list_structure_and_elements::<Int64Type, i32>(
1660 &result,
1661 5,
1662 &[0, 3, 6, 6, 6],
1663 &[Some(3), Some(3), None, None, Some(0)],
1664 &[None, None, Some(Variant::from("not a list")), None, None],
1665 (
1666 &[Some(1), Some(2), Some(3), Some(1), None, None],
1667 &[
1668 None,
1669 None,
1670 None,
1671 None,
1672 Some(Variant::from("two")),
1673 Some(Variant::Null),
1674 ],
1675 ),
1676 );
1677 }
1678
1679 #[test]
1680 fn test_array_shredding_as_large_list_view() {
1681 let input = build_variant_array(vec![
1682 VariantRow::List(vec![VariantValue::from(1i64), VariantValue::from(2i64)]),
1684 VariantRow::Value(VariantValue::from("fallback")),
1686 VariantRow::List(vec![]),
1688 ]);
1689 let list_schema =
1690 DataType::LargeListView(Arc::new(Field::new("item", DataType::Int64, true)));
1691 let result = shred_variant(&input, &list_schema).unwrap();
1692 assert_eq!(result.len(), 3);
1693
1694 assert_list_structure_and_elements::<Int64Type, i64>(
1695 &result,
1696 3,
1697 &[0, 2, 2],
1698 &[Some(2), None, Some(0)],
1699 &[None, Some(Variant::from("fallback")), None],
1700 (&[Some(1), Some(2)], &[None, None]),
1701 );
1702 }
1703
1704 #[test]
1705 fn test_array_shredding_with_array_elements() {
1706 let input = build_variant_array(vec![
1707 VariantRow::List(vec![
1709 VariantValue::List(vec![VariantValue::from(1i64), VariantValue::from(2i64)]),
1710 VariantValue::List(vec![VariantValue::from(3i64), VariantValue::from(4i64)]),
1711 VariantValue::List(vec![]),
1712 ]),
1713 VariantRow::List(vec![
1715 VariantValue::List(vec![
1716 VariantValue::from(5i64),
1717 VariantValue::from("bad"),
1718 VariantValue::from(Variant::Null),
1719 ]),
1720 VariantValue::from("not a list inner"),
1721 VariantValue::Null,
1722 ]),
1723 VariantRow::Value(VariantValue::from("not a list")),
1725 VariantRow::Null,
1727 ]);
1728 let inner_field = Arc::new(Field::new("item", DataType::Int64, true));
1729 let inner_list_schema = DataType::List(inner_field);
1730 let list_schema = DataType::List(Arc::new(Field::new(
1731 "item",
1732 inner_list_schema.clone(),
1733 true,
1734 )));
1735 let result = shred_variant(&input, &list_schema).unwrap();
1736 assert_eq!(result.len(), 4);
1737
1738 let typed_value = result
1739 .typed_value_column()
1740 .unwrap()
1741 .as_any()
1742 .downcast_ref::<ListArray>()
1743 .unwrap();
1744
1745 assert_list_structure::<i32>(
1746 &result,
1747 4,
1748 &[0, 3, 6, 6, 6],
1749 &[Some(3), Some(3), None, None],
1750 &[None, None, Some(Variant::from("not a list")), None],
1751 );
1752
1753 let outer_elements =
1754 ShreddedVariantFieldArray::try_new(typed_value.values().as_ref()).unwrap();
1755 assert_eq!(outer_elements.len(), 6);
1756 let outer_values = outer_elements
1757 .typed_value_column()
1758 .unwrap()
1759 .as_any()
1760 .downcast_ref::<ListArray>()
1761 .unwrap();
1762 let outer_fallbacks = outer_elements.value_column();
1763
1764 let outer_metadata = Arc::new(BinaryViewArray::from_iter_values(std::iter::repeat_n(
1765 EMPTY_VARIANT_METADATA_BYTES,
1766 outer_elements.len(),
1767 )));
1768 let outer_variant = VariantArray::from_parts(
1769 outer_metadata,
1770 outer_fallbacks.clone(),
1771 Some(Arc::new(outer_values.clone())),
1772 None,
1773 );
1774
1775 assert_list_structure_and_elements::<Int64Type, i32>(
1776 &outer_variant,
1777 outer_elements.len(),
1778 &[0, 2, 4, 4, 7, 7, 7],
1779 &[Some(2), Some(2), Some(0), Some(3), None, None],
1780 &[
1781 None,
1782 None,
1783 None,
1784 None,
1785 Some(Variant::from("not a list inner")),
1786 Some(Variant::Null),
1787 ],
1788 (
1789 &[Some(1), Some(2), Some(3), Some(4), Some(5), None, None],
1790 &[
1791 None,
1792 None,
1793 None,
1794 None,
1795 None,
1796 Some(Variant::from("bad")),
1797 Some(Variant::Null),
1798 ],
1799 ),
1800 );
1801 }
1802
1803 #[test]
1804 fn test_array_shredding_with_object_elements() {
1805 let input = build_variant_array(vec![
1806 VariantRow::List(vec![
1808 VariantValue::Object(vec![
1809 ("id", VariantValue::from(1i64)),
1810 ("name", VariantValue::from("Alice")),
1811 ]),
1812 VariantValue::Object(vec![("id", VariantValue::from(Variant::Null))]),
1813 ]),
1814 VariantRow::Value(VariantValue::from("not a list")),
1816 VariantRow::Null,
1818 ]);
1819
1820 let list_schema = ShreddedSchemaBuilder::default()
1822 .with_path("[*].id", &DataType::Int64)
1823 .unwrap()
1824 .with_path("[*].name", &DataType::Utf8)
1825 .unwrap()
1826 .build();
1827 let result = shred_variant(&input, &list_schema).unwrap();
1828 assert_eq!(result.len(), 3);
1829
1830 assert_list_structure::<i32>(
1831 &result,
1832 3,
1833 &[0, 2, 2, 2],
1834 &[Some(2), None, None],
1835 &[None, Some(Variant::from("not a list")), None],
1836 );
1837
1838 let typed_value = result
1840 .typed_value_column()
1841 .unwrap()
1842 .as_any()
1843 .downcast_ref::<ListArray>()
1844 .unwrap();
1845 let element_array =
1846 ShreddedVariantFieldArray::try_new(typed_value.values().as_ref()).unwrap();
1847 assert_eq!(element_array.len(), 2);
1848 let element_objects = element_array
1849 .typed_value_column()
1850 .unwrap()
1851 .as_any()
1852 .downcast_ref::<arrow::array::StructArray>()
1853 .unwrap();
1854
1855 let id_field =
1857 ShreddedVariantFieldArray::try_new(element_objects.column_by_name("id").unwrap())
1858 .unwrap();
1859 let id_values = id_field.value_column();
1860 let id_typed_values = id_field
1861 .typed_value_column()
1862 .unwrap()
1863 .as_any()
1864 .downcast_ref::<Int64Array>()
1865 .unwrap();
1866 assert!(id_values.is_null(0));
1867 assert_eq!(id_typed_values.value(0), 1);
1868 assert!(id_values.is_valid(1));
1870 assert_eq!(
1871 Variant::new(
1872 EMPTY_VARIANT_METADATA_BYTES,
1873 binary_array_value(id_values.as_ref(), 1).unwrap()
1874 ),
1875 Variant::Null
1876 );
1877 assert!(id_typed_values.is_null(1));
1878
1879 let name_field =
1881 ShreddedVariantFieldArray::try_new(element_objects.column_by_name("name").unwrap())
1882 .unwrap();
1883 let name_values = name_field.value_column();
1884 let name_typed_values = name_field
1885 .typed_value_column()
1886 .unwrap()
1887 .as_any()
1888 .downcast_ref::<StringArray>()
1889 .unwrap();
1890 assert!(name_values.is_null(0));
1891 assert_eq!(name_typed_values.value(0), "Alice");
1892 assert!(name_values.is_null(1));
1894 assert!(name_typed_values.is_null(1));
1895 }
1896
1897 #[test]
1898 fn test_object_shredding_comprehensive() -> Result<()> {
1899 let input = build_variant_array(vec![
1900 VariantRow::Object(vec![
1902 ("score", VariantValue::from(95.5f64)),
1903 ("age", VariantValue::from(30i64)),
1904 ]),
1905 VariantRow::Object(vec![
1907 ("score", VariantValue::from(87.2f64)),
1908 ("age", VariantValue::from(25i64)),
1909 ("email", VariantValue::from("bob@example.com")),
1910 ]),
1911 VariantRow::Object(vec![("age", VariantValue::from(35i64))]),
1913 VariantRow::Object(vec![
1915 ("score", VariantValue::from("ninety-five")),
1916 ("age", VariantValue::from("thirty")),
1917 ]),
1918 VariantRow::Value(VariantValue::from("not an object")),
1920 VariantRow::Object(vec![]),
1922 VariantRow::Null,
1924 VariantRow::Object(vec![("foo", VariantValue::from(10))]),
1926 VariantRow::Object(vec![
1928 ("score", VariantValue::from(66.67f64)),
1929 ("foo", VariantValue::from(10)),
1930 ]),
1931 ]);
1932
1933 let target_schema = ShreddedSchemaBuilder::default()
1936 .with_path("score", &DataType::Float64)?
1937 .with_path("age", &DataType::Int64)?
1938 .build();
1939
1940 let result = shred_variant(&input, &target_schema).unwrap();
1941
1942 assert!(result.typed_value_column().is_some());
1944 assert_eq!(result.len(), 9);
1945
1946 let metadata = result.metadata_column();
1947 let value = result.value_column();
1948 let typed_value = result
1949 .typed_value_column()
1950 .unwrap()
1951 .as_any()
1952 .downcast_ref::<arrow::array::StructArray>()
1953 .unwrap();
1954
1955 let score_field =
1957 ShreddedVariantFieldArray::try_new(typed_value.column_by_name("score").unwrap())
1958 .unwrap();
1959 let age_field =
1960 ShreddedVariantFieldArray::try_new(typed_value.column_by_name("age").unwrap()).unwrap();
1961
1962 let score_value = score_field.value_column();
1963 let score_typed_value = score_field
1964 .typed_value_column()
1965 .unwrap()
1966 .as_any()
1967 .downcast_ref::<Float64Array>()
1968 .unwrap();
1969 let age_value = age_field.value_column();
1970 let age_typed_value = age_field
1971 .typed_value_column()
1972 .unwrap()
1973 .as_any()
1974 .downcast_ref::<Int64Array>()
1975 .unwrap();
1976
1977 struct ShreddedValue<'m, 'v, T> {
1979 value: Option<Variant<'m, 'v>>,
1980 typed_value: Option<T>,
1981 }
1982 struct ShreddedStruct<'m, 'v> {
1983 score: ShreddedValue<'m, 'v, f64>,
1984 age: ShreddedValue<'m, 'v, i64>,
1985 }
1986 fn get_value<'m, 'v>(
1987 i: usize,
1988 metadata: &'m dyn Array,
1989 value: &'v dyn Array,
1990 ) -> Variant<'m, 'v> {
1991 variant_from_arrays_at(metadata, value, i).unwrap()
1992 }
1993 let expect = |i, expected_result: Option<ShreddedValue<ShreddedStruct>>| {
1994 match expected_result {
1995 Some(ShreddedValue {
1996 value: expected_value,
1997 typed_value: expected_typed_value,
1998 }) => {
1999 assert!(result.is_valid(i));
2000 match expected_value {
2001 Some(expected_value) => {
2002 assert!(value.is_valid(i));
2003 assert_eq!(
2004 expected_value,
2005 get_value(i, metadata.as_ref(), value.as_ref())
2006 );
2007 }
2008 None => {
2009 assert!(value.is_null(i));
2010 }
2011 }
2012 match expected_typed_value {
2013 Some(ShreddedStruct {
2014 score: expected_score,
2015 age: expected_age,
2016 }) => {
2017 assert!(typed_value.is_valid(i));
2018 assert!(score_field.is_valid(i)); assert!(age_field.is_valid(i)); match expected_score.value {
2021 Some(expected_score_value) => {
2022 assert!(score_value.is_valid(i));
2023 assert_eq!(
2024 expected_score_value,
2025 get_value(i, metadata.as_ref(), score_value.as_ref())
2026 );
2027 }
2028 None => {
2029 assert!(score_value.is_null(i));
2030 }
2031 }
2032 match expected_score.typed_value {
2033 Some(expected_score) => {
2034 assert!(score_typed_value.is_valid(i));
2035 assert_eq!(expected_score, score_typed_value.value(i));
2036 }
2037 None => {
2038 assert!(score_typed_value.is_null(i));
2039 }
2040 }
2041 match expected_age.value {
2042 Some(expected_age_value) => {
2043 assert!(age_value.is_valid(i));
2044 assert_eq!(
2045 expected_age_value,
2046 get_value(i, metadata.as_ref(), age_value.as_ref())
2047 );
2048 }
2049 None => {
2050 assert!(age_value.is_null(i));
2051 }
2052 }
2053 match expected_age.typed_value {
2054 Some(expected_age) => {
2055 assert!(age_typed_value.is_valid(i));
2056 assert_eq!(expected_age, age_typed_value.value(i));
2057 }
2058 None => {
2059 assert!(age_typed_value.is_null(i));
2060 }
2061 }
2062 }
2063 None => {
2064 assert!(typed_value.is_null(i));
2065 }
2066 }
2067 }
2068 None => {
2069 assert!(result.is_null(i));
2070 }
2071 }
2072 };
2073
2074 expect(
2076 0,
2077 Some(ShreddedValue {
2078 value: None,
2079 typed_value: Some(ShreddedStruct {
2080 score: ShreddedValue {
2081 value: None,
2082 typed_value: Some(95.5),
2083 },
2084 age: ShreddedValue {
2085 value: None,
2086 typed_value: Some(30),
2087 },
2088 }),
2089 }),
2090 );
2091
2092 let mut builder = VariantBuilder::new();
2094 builder
2095 .new_object()
2096 .with_field("email", "bob@example.com")
2097 .finish();
2098 let (m, v) = builder.finish();
2099 let expected_value = Variant::new(&m, &v);
2100
2101 expect(
2102 1,
2103 Some(ShreddedValue {
2104 value: Some(expected_value),
2105 typed_value: Some(ShreddedStruct {
2106 score: ShreddedValue {
2107 value: None,
2108 typed_value: Some(87.2),
2109 },
2110 age: ShreddedValue {
2111 value: None,
2112 typed_value: Some(25),
2113 },
2114 }),
2115 }),
2116 );
2117
2118 expect(
2120 2,
2121 Some(ShreddedValue {
2122 value: None,
2123 typed_value: Some(ShreddedStruct {
2124 score: ShreddedValue {
2125 value: None,
2126 typed_value: None,
2127 },
2128 age: ShreddedValue {
2129 value: None,
2130 typed_value: Some(35),
2131 },
2132 }),
2133 }),
2134 );
2135
2136 expect(
2138 3,
2139 Some(ShreddedValue {
2140 value: None,
2141 typed_value: Some(ShreddedStruct {
2142 score: ShreddedValue {
2143 value: Some(Variant::from("ninety-five")),
2144 typed_value: None,
2145 },
2146 age: ShreddedValue {
2147 value: Some(Variant::from("thirty")),
2148 typed_value: None,
2149 },
2150 }),
2151 }),
2152 );
2153
2154 expect(
2156 4,
2157 Some(ShreddedValue {
2158 value: Some(Variant::from("not an object")),
2159 typed_value: None,
2160 }),
2161 );
2162
2163 expect(
2165 5,
2166 Some(ShreddedValue {
2167 value: None,
2168 typed_value: Some(ShreddedStruct {
2169 score: ShreddedValue {
2170 value: None,
2171 typed_value: None,
2172 },
2173 age: ShreddedValue {
2174 value: None,
2175 typed_value: None,
2176 },
2177 }),
2178 }),
2179 );
2180
2181 expect(6, None);
2183
2184 let object_with_foo_field = |i| {
2186 use parquet_variant::{ParentState, ValueBuilder, VariantMetadata};
2187 let metadata = VariantMetadata::new(binary_array_value(metadata.as_ref(), i).unwrap());
2188 let mut metadata_builder = ReadOnlyMetadataBuilder::new(&metadata);
2189 let mut value_builder = ValueBuilder::new();
2190 let state = ParentState::variant(&mut value_builder, &mut metadata_builder);
2191 ObjectBuilder::new(state, false)
2192 .with_field("foo", 10)
2193 .finish();
2194 (metadata, value_builder.into_inner())
2195 };
2196
2197 let (m, v) = object_with_foo_field(7);
2199 expect(
2200 7,
2201 Some(ShreddedValue {
2202 value: Some(Variant::new_with_metadata(m, &v)),
2203 typed_value: Some(ShreddedStruct {
2204 score: ShreddedValue {
2205 value: None,
2206 typed_value: None,
2207 },
2208 age: ShreddedValue {
2209 value: None,
2210 typed_value: None,
2211 },
2212 }),
2213 }),
2214 );
2215
2216 let (m, v) = object_with_foo_field(8);
2218 expect(
2219 8,
2220 Some(ShreddedValue {
2221 value: Some(Variant::new_with_metadata(m, &v)),
2222 typed_value: Some(ShreddedStruct {
2223 score: ShreddedValue {
2224 value: None,
2225 typed_value: Some(66.67),
2226 },
2227 age: ShreddedValue {
2228 value: None,
2229 typed_value: None,
2230 },
2231 }),
2232 }),
2233 );
2234 Ok(())
2235 }
2236
2237 #[test]
2238 fn test_object_shredding_with_array_field() {
2239 let input = build_variant_array(vec![
2240 VariantRow::Object(vec![(
2242 "scores",
2243 VariantValue::List(vec![VariantValue::from(10i64), VariantValue::from(20i64)]),
2244 )]),
2245 VariantRow::Object(vec![(
2247 "scores",
2248 VariantValue::List(vec![
2249 VariantValue::from("oops"),
2250 VariantValue::from(Variant::Null),
2251 ]),
2252 )]),
2253 VariantRow::Object(vec![]),
2255 VariantRow::Value(VariantValue::from("not an object")),
2257 VariantRow::Null,
2259 ]);
2260 let list_field = Arc::new(Field::new("item", DataType::Int64, true));
2261 let inner_list_schema = DataType::List(list_field);
2262 let schema = DataType::Struct(Fields::from(vec![Field::new(
2263 "scores",
2264 inner_list_schema.clone(),
2265 true,
2266 )]));
2267
2268 let result = shred_variant(&input, &schema).unwrap();
2269 assert_eq!(result.len(), 5);
2270
2271 let value_field = result.value_column();
2273 let typed_struct = result
2274 .typed_value_column()
2275 .unwrap()
2276 .as_any()
2277 .downcast_ref::<arrow::array::StructArray>()
2278 .unwrap();
2279
2280 assert!(value_field.is_null(0));
2282 assert!(value_field.is_null(1));
2283 assert!(value_field.is_null(2));
2284 assert!(value_field.is_valid(3));
2285 assert_eq!(
2286 variant_from_arrays_at(result.metadata_column(), value_field, 3).unwrap(),
2287 Variant::from("not an object")
2288 );
2289 assert!(value_field.is_null(4));
2290
2291 assert!(typed_struct.is_valid(0));
2293 assert!(typed_struct.is_valid(1));
2294 assert!(typed_struct.is_valid(2));
2295 assert!(typed_struct.is_null(3));
2296 assert!(typed_struct.is_null(4));
2297
2298 let scores_field =
2300 ShreddedVariantFieldArray::try_new(typed_struct.column_by_name("scores").unwrap())
2301 .unwrap();
2302 assert_list_structure_and_elements::<Int64Type, i32>(
2303 &VariantArray::from_parts(
2304 Arc::new(BinaryViewArray::from_iter_values(std::iter::repeat_n(
2305 EMPTY_VARIANT_METADATA_BYTES,
2306 scores_field.len(),
2307 ))),
2308 scores_field.value_column().clone(),
2309 Some(scores_field.typed_value_column().unwrap().clone()),
2310 None,
2311 ),
2312 scores_field.len(),
2313 &[0i32, 2, 4, 4, 4, 4],
2314 &[Some(2), Some(2), None, None, None],
2315 &[None, None, None, None, None],
2316 (
2317 &[Some(10), Some(20), None, None],
2318 &[None, None, Some(Variant::from("oops")), Some(Variant::Null)],
2319 ),
2320 );
2321 }
2322
2323 #[test]
2324 fn test_object_different_schemas() -> Result<()> {
2325 let input = build_variant_array(vec![VariantRow::Object(vec![
2327 ("id", VariantValue::from(123i32)),
2328 ("age", VariantValue::from(25i64)),
2329 ("score", VariantValue::from(95.5f64)),
2330 ])]);
2331
2332 let schema1 = ShreddedSchemaBuilder::default()
2334 .with_path("id", &DataType::Int32)?
2335 .build();
2336 let result1 = shred_variant(&input, &schema1).unwrap();
2337 let value_field1 = result1.value_column();
2338 assert!(!value_field1.is_null(0)); let schema2 = ShreddedSchemaBuilder::default()
2342 .with_path("id", &DataType::Int32)?
2343 .with_path("age", &DataType::Int64)?
2344 .build();
2345 let result2 = shred_variant(&input, &schema2).unwrap();
2346 let value_field2 = result2.value_column();
2347 assert!(!value_field2.is_null(0)); let schema3 = ShreddedSchemaBuilder::default()
2351 .with_path("id", &DataType::Int32)?
2352 .with_path("age", &DataType::Int64)?
2353 .with_path("score", &DataType::Float64)?
2354 .build();
2355 let result3 = shred_variant(&input, &schema3).unwrap();
2356 let value_field3 = result3.value_column();
2357 assert!(value_field3.is_null(0)); Ok(())
2360 }
2361
2362 #[test]
2363 fn test_object_with_duplicate_field_names_errors() -> Result<()> {
2364 let metadata_a: &[u8] = &[0x01, 1, 0, 1, b'a'];
2366 let metadata_aa: &[u8] = &[0x01, 2, 0, 1, 2, b'a', b'a'];
2367 let same_ids: &[u8] = &[0x02, 2, 0, 0, 0, 2, 4, 0x0C, 0, 0x0C, 1];
2369 let distinct_ids: &[u8] = &[0x02, 2, 0, 1, 0, 2, 4, 0x0C, 0, 0x0C, 1];
2370
2371 for (metadata, value) in [(metadata_a, same_ids), (metadata_aa, distinct_ids)] {
2372 assert!(Variant::try_new(metadata, value).is_err());
2374 let input = VariantArray::from_parts(
2375 Arc::new(BinaryViewArray::from_iter_values([metadata])),
2376 Arc::new(BinaryViewArray::from_iter_values([value])),
2377 None,
2378 None,
2379 );
2380 for path in ["a", "b"] {
2382 let as_type = ShreddedSchemaBuilder::default()
2383 .with_path(path, &DataType::Int8)?
2384 .build();
2385 let err = shred_variant(&input, &as_type).unwrap_err();
2386 assert_eq!(
2387 err.to_string(),
2388 "Invalid argument error: Duplicate field name: a"
2389 );
2390 }
2391 }
2392 Ok(())
2393 }
2394
2395 #[test]
2396 fn test_uuid_shredding_in_objects() -> Result<()> {
2397 let mock_uuid_1 = Uuid::new_v4();
2398 let mock_uuid_2 = Uuid::new_v4();
2399 let mock_uuid_3 = Uuid::new_v4();
2400
2401 let input = build_variant_array(vec![
2402 VariantRow::Object(vec![
2404 ("id", VariantValue::from(mock_uuid_1)),
2405 ("session_id", VariantValue::from(mock_uuid_2)),
2406 ]),
2407 VariantRow::Object(vec![
2409 ("id", VariantValue::from(mock_uuid_2)),
2410 ("session_id", VariantValue::from(mock_uuid_3)),
2411 ("name", VariantValue::from("test_user")),
2412 ]),
2413 VariantRow::Object(vec![("id", VariantValue::from(mock_uuid_1))]),
2415 VariantRow::Object(vec![
2417 ("id", VariantValue::from(mock_uuid_3)),
2418 ("session_id", VariantValue::from("not-a-uuid")),
2419 ]),
2420 VariantRow::Object(vec![
2422 ("id", VariantValue::from(12345i64)),
2423 ("session_id", VariantValue::from(mock_uuid_1)),
2424 ]),
2425 VariantRow::Null,
2427 ]);
2428
2429 let target_schema = ShreddedSchemaBuilder::default()
2430 .with_path("id", DataType::FixedSizeBinary(16))?
2431 .with_path("session_id", DataType::FixedSizeBinary(16))?
2432 .build();
2433
2434 let result = shred_variant(&input, &target_schema).unwrap();
2435
2436 assert!(result.typed_value_column().is_some());
2437 assert_eq!(result.len(), 6);
2438
2439 let metadata = result.metadata_column();
2440 let value = result.value_column();
2441 let typed_value = result
2442 .typed_value_column()
2443 .unwrap()
2444 .as_any()
2445 .downcast_ref::<arrow::array::StructArray>()
2446 .unwrap();
2447
2448 let id_field =
2450 ShreddedVariantFieldArray::try_new(typed_value.column_by_name("id").unwrap()).unwrap();
2451 let session_id_field =
2452 ShreddedVariantFieldArray::try_new(typed_value.column_by_name("session_id").unwrap())
2453 .unwrap();
2454
2455 let id_value = id_field.value_column();
2456 let id_typed_value = id_field
2457 .typed_value_column()
2458 .unwrap()
2459 .as_any()
2460 .downcast_ref::<FixedSizeBinaryArray>()
2461 .unwrap();
2462 let session_id_value = session_id_field.value_column();
2463 let session_id_typed_value = session_id_field
2464 .typed_value_column()
2465 .unwrap()
2466 .as_any()
2467 .downcast_ref::<FixedSizeBinaryArray>()
2468 .unwrap();
2469
2470 assert!(result.is_valid(0));
2472
2473 assert!(value.is_null(0)); assert!(id_value.is_null(0));
2475 assert!(session_id_value.is_null(0));
2476
2477 assert!(typed_value.is_valid(0));
2478 assert!(id_typed_value.is_valid(0));
2479 assert!(session_id_typed_value.is_valid(0));
2480
2481 assert_eq!(id_typed_value.value(0), mock_uuid_1.as_bytes());
2482 assert_eq!(session_id_typed_value.value(0), mock_uuid_2.as_bytes());
2483
2484 assert!(result.is_valid(1));
2486
2487 assert!(value.is_valid(1)); assert!(typed_value.is_valid(1));
2489
2490 assert!(id_value.is_null(1));
2491 assert!(id_typed_value.is_valid(1));
2492 assert_eq!(id_typed_value.value(1), mock_uuid_2.as_bytes());
2493
2494 assert!(session_id_value.is_null(1));
2495 assert!(session_id_typed_value.is_valid(1));
2496 assert_eq!(session_id_typed_value.value(1), mock_uuid_3.as_bytes());
2497
2498 let row_1_variant = variant_from_arrays_at(metadata, value, 1).unwrap();
2500 let Variant::Object(obj) = row_1_variant else {
2501 panic!("Expected object");
2502 };
2503
2504 assert_eq!(obj.get("name"), Some(Variant::from("test_user")));
2505
2506 assert!(result.is_valid(2));
2508
2509 assert!(value.is_null(2)); assert!(typed_value.is_valid(2));
2511
2512 assert!(id_value.is_null(2));
2513 assert!(id_typed_value.is_valid(2));
2514 assert_eq!(id_typed_value.value(2), mock_uuid_1.as_bytes());
2515
2516 assert!(session_id_value.is_null(2));
2517 assert!(session_id_typed_value.is_null(2)); assert!(result.is_valid(3));
2521
2522 assert!(value.is_null(3)); assert!(typed_value.is_valid(3));
2524
2525 assert!(id_value.is_null(3));
2526 assert!(id_typed_value.is_valid(3));
2527 assert_eq!(id_typed_value.value(3), mock_uuid_3.as_bytes());
2528
2529 assert!(session_id_value.is_valid(3)); assert!(session_id_typed_value.is_null(3));
2531 let session_id_variant = variant_from_arrays_at(metadata, session_id_value, 3).unwrap();
2532 assert_eq!(session_id_variant, Variant::from("not-a-uuid"));
2533
2534 assert!(result.is_valid(4));
2536
2537 assert!(value.is_null(4)); assert!(typed_value.is_valid(4));
2539
2540 assert!(id_value.is_valid(4)); assert!(id_typed_value.is_null(4));
2542 let id_variant = variant_from_arrays_at(metadata, id_value, 4).unwrap();
2543 assert_eq!(id_variant, Variant::from(12345i64));
2544
2545 assert!(session_id_value.is_null(4));
2546 assert!(session_id_typed_value.is_valid(4));
2547 assert_eq!(session_id_typed_value.value(4), mock_uuid_1.as_bytes());
2548
2549 assert!(result.is_null(5));
2551
2552 Ok(())
2553 }
2554
2555 macro_rules! validate_decimal_shredding {
2556 ($shred_type: expr, $array_type: ty, $expected_typed_value: ident $(, $expected_precision: literal, $expected_scale:literal)? $(,)?) => {{
2557 let input = VariantArray::from_iter(vec![
2558 Variant::from(12i8),
2559 Variant::from(234i16),
2560 Variant::from(456i32),
2561 Variant::from(456i64),
2562 Variant::from(VariantDecimal4::try_new(1200, 2).unwrap()),
2563 Variant::from(VariantDecimal8::try_new(1230, 2).unwrap()),
2564 Variant::from(VariantDecimal16::try_new(1234, 2).unwrap()),
2565 ]);
2566
2567 let result = shred_variant(&input, &$shred_type).unwrap();
2568
2569 assert!(result.typed_value_column().is_some());
2570 assert_eq!(result.len(), input.len());
2571
2572 let value = result.value_column();
2573 let typed_value = result
2574 .typed_value_column()
2575 .unwrap()
2576 .as_any()
2577 .downcast_ref::<$array_type>()
2578 .unwrap();
2579
2580 $(assert_eq!(typed_value.precision(), $expected_precision);)?
2581 $(assert_eq!(typed_value.scale(), $expected_scale);)?
2582
2583 for i in 0..$expected_typed_value.len() {
2584 assert_eq!(value.is_valid(i), $expected_typed_value.is_null(i));
2585 assert_eq!(typed_value.is_valid(i), $expected_typed_value.is_valid(i));
2586 assert_eq!(typed_value.value(i), $expected_typed_value.value(i));
2587 }
2588 }};
2589 }
2590
2591 #[test]
2592 fn test_shredding_decimal32_with_same_scale() {
2593 let expected_array = Decimal32Array::from(vec![
2594 Some(1200),
2595 None, None, None, Some(1200),
2599 Some(1230),
2600 Some(1234),
2601 ])
2602 .with_precision_and_scale(4, 2)
2603 .unwrap();
2604 validate_decimal_shredding!(
2605 DataType::Decimal32(4, 2),
2606 arrow::array::Decimal32Array,
2607 expected_array,
2608 4,
2609 2,
2610 );
2611 }
2612
2613 #[test]
2614 fn test_shredding_decimal32_with_bigger_scale() {
2615 let expected_array = Decimal32Array::from(vec![
2616 Some(12000),
2617 Some(234000),
2618 Some(456000),
2619 Some(456000),
2620 Some(12000),
2621 Some(12300),
2622 Some(12340),
2623 ])
2624 .with_precision_and_scale(6, 3)
2625 .unwrap();
2626
2627 validate_decimal_shredding!(
2628 DataType::Decimal32(6, 3),
2629 arrow::array::Decimal32Array,
2630 expected_array,
2631 6,
2632 3,
2633 );
2634 }
2635
2636 #[test]
2637 fn test_shredding_decimal32_with_smaller_scale() {
2638 let expected_array = Decimal32Array::from(vec![
2639 Some(12),
2640 Some(234),
2641 Some(456),
2642 Some(456),
2643 Some(12),
2644 None, None, ])
2647 .with_precision_and_scale(6, 0)
2648 .unwrap();
2649 validate_decimal_shredding!(
2650 DataType::Decimal32(6, 0),
2651 arrow::array::Decimal32Array,
2652 expected_array,
2653 6,
2654 0
2655 );
2656 }
2657
2658 #[test]
2659 fn test_shredding_decimal64_with_same_scale() {
2660 let expected_array_decimal64_same_scale = Decimal64Array::from(vec![
2661 Some(1200),
2662 None, None, None, Some(1200),
2666 Some(1230),
2667 Some(1234),
2668 ])
2669 .with_precision_and_scale(4, 2)
2670 .unwrap();
2671 validate_decimal_shredding!(
2672 DataType::Decimal64(4, 2),
2673 arrow::array::Decimal64Array,
2674 expected_array_decimal64_same_scale,
2675 4,
2676 2
2677 );
2678 }
2679
2680 #[test]
2681 fn test_shredding_decimal64_with_big_scale() {
2682 let expected_array = Decimal64Array::from(vec![
2683 Some(12000),
2684 Some(234000),
2685 Some(456000),
2686 Some(456000),
2687 Some(12000),
2688 Some(12300),
2689 Some(12340),
2690 ])
2691 .with_precision_and_scale(6, 3)
2692 .unwrap();
2693 validate_decimal_shredding!(
2694 DataType::Decimal64(6, 3),
2695 arrow::array::Decimal64Array,
2696 expected_array,
2697 6,
2698 3,
2699 );
2700 }
2701
2702 #[test]
2703 fn test_shredding_decimal64_with_smaller_scale() {
2704 let expected_array = Decimal64Array::from(vec![
2705 Some(12),
2706 Some(234),
2707 Some(456),
2708 Some(456),
2709 Some(12),
2710 None, None, ])
2713 .with_precision_and_scale(6, 0)
2714 .unwrap();
2715 validate_decimal_shredding!(
2716 DataType::Decimal64(6, 0),
2717 arrow::array::Decimal64Array,
2718 expected_array,
2719 6,
2720 0
2721 );
2722 }
2723
2724 #[test]
2725 fn test_shredding_decimal128_with_same_scale() {
2726 let expected_array = Decimal128Array::from(vec![
2727 Some(1200),
2728 None, None, None, Some(1200),
2732 Some(1230),
2733 Some(1234),
2734 ])
2735 .with_precision_and_scale(4, 2)
2736 .unwrap();
2737
2738 validate_decimal_shredding!(
2739 DataType::Decimal128(4, 2),
2740 arrow::array::Decimal128Array,
2741 expected_array,
2742 4,
2743 2,
2744 );
2745 }
2746
2747 #[test]
2748 fn test_shredding_decimal128_with_big_scale() {
2749 let expected_array = Decimal128Array::from(vec![
2750 Some(12000),
2751 Some(234000),
2752 Some(456000),
2753 Some(456000),
2754 Some(12000),
2755 Some(12300),
2756 Some(12340),
2757 ])
2758 .with_precision_and_scale(6, 3)
2759 .unwrap();
2760 validate_decimal_shredding!(
2761 DataType::Decimal128(6, 3),
2762 arrow::array::Decimal128Array,
2763 expected_array,
2764 6,
2765 3
2766 );
2767 }
2768
2769 #[test]
2770 fn test_shredding_decimal128_with_smaller_scale() {
2771 let expected_array = Decimal128Array::from(vec![
2772 Some(12),
2773 Some(234),
2774 Some(456),
2775 Some(456),
2776 Some(12),
2777 None, None, ])
2780 .with_precision_and_scale(6, 0)
2781 .unwrap();
2782 validate_decimal_shredding!(
2783 DataType::Decimal128(6, 0),
2784 arrow::array::Decimal128Array,
2785 expected_array,
2786 6,
2787 0
2788 );
2789 }
2790
2791 #[test]
2792 fn test_shredding_decimal128_to_integer() {
2793 let expected_array = Int64Array::from(vec![
2794 Some(12),
2795 Some(234),
2796 Some(456),
2797 Some(456),
2798 Some(12),
2799 None, None, ]);
2802
2803 validate_decimal_shredding!(DataType::Int64, arrow::array::Int64Array, expected_array);
2804 }
2805
2806 #[test]
2807 fn test_spec_compliance() {
2808 let input = VariantArray::from_iter(vec![Variant::from(42i64), Variant::from("hello")]);
2809
2810 let result = shred_variant(&input, &DataType::Int64).unwrap();
2811
2812 let inner_struct = result.inner();
2814 assert!(inner_struct.column_by_name("metadata").is_some());
2815 assert!(inner_struct.column_by_name("value").is_some());
2816 assert!(inner_struct.column_by_name("typed_value").is_some());
2817
2818 assert_eq!(
2820 result.metadata_column().len(),
2821 input.metadata_column().len()
2822 );
2823 assert_eq!(
2826 result.metadata_column().len(),
2827 input.metadata_column().len()
2828 );
2829
2830 assert_eq!(result.len(), input.len());
2832 assert!(result.typed_value_column().is_some());
2833
2834 let value_field = result.value_column();
2837 let typed_value_field = result
2838 .typed_value_column()
2839 .unwrap()
2840 .as_any()
2841 .downcast_ref::<Int64Array>()
2842 .unwrap();
2843
2844 for i in 0..result.len() {
2845 if !result.is_null(i) {
2846 let value_is_null = value_field.is_null(i);
2847 let typed_value_is_null = typed_value_field.is_null(i);
2848 assert!(
2850 value_is_null || typed_value_is_null,
2851 "Row {i}: both value and typed_value are non-null for primitive shredding"
2852 );
2853 }
2854 }
2855 }
2856
2857 #[test]
2858 fn test_variant_schema_builder_simple() -> Result<()> {
2859 let shredding_type = ShreddedSchemaBuilder::default()
2860 .with_path("a", &DataType::Int64)?
2861 .with_path("b", &DataType::Float64)?
2862 .build();
2863
2864 assert_eq!(
2865 shredding_type,
2866 DataType::Struct(Fields::from(vec![
2867 Field::new("a", DataType::Int64, true),
2868 Field::new("b", DataType::Float64, true),
2869 ]))
2870 );
2871
2872 Ok(())
2873 }
2874
2875 #[test]
2876 fn test_variant_schema_builder_nested() -> Result<()> {
2877 let shredding_type = ShreddedSchemaBuilder::default()
2878 .with_path("a", &DataType::Int64)?
2879 .with_path("b.c", &DataType::Utf8)?
2880 .with_path("b.d", &DataType::Float64)?
2881 .build();
2882
2883 assert_eq!(
2884 shredding_type,
2885 DataType::Struct(Fields::from(vec![
2886 Field::new("a", DataType::Int64, true),
2887 Field::new(
2888 "b",
2889 DataType::Struct(Fields::from(vec![
2890 Field::new("c", DataType::Utf8, true),
2891 Field::new("d", DataType::Float64, true),
2892 ])),
2893 true
2894 ),
2895 ]))
2896 );
2897
2898 Ok(())
2899 }
2900
2901 #[test]
2902 fn test_variant_schema_builder_list() -> Result<()> {
2903 let shredding_type = ShreddedSchemaBuilder::default()
2904 .with_path("items[*].id", &DataType::Int64)?
2905 .with_path("items[*].name", &DataType::Utf8)?
2906 .build();
2907
2908 assert_eq!(
2909 shredding_type,
2910 DataType::Struct(Fields::from(vec![Field::new(
2911 "items",
2912 DataType::new_list(
2913 DataType::Struct(Fields::from(vec![
2914 Field::new("id", DataType::Int64, true),
2915 Field::new("name", DataType::Utf8, true),
2916 ])),
2917 true,
2918 ),
2919 true,
2920 )]))
2921 );
2922
2923 Ok(())
2924 }
2925
2926 #[test]
2927 fn test_variant_schema_builder_nested_lists() -> Result<()> {
2928 let shredding_type = ShreddedSchemaBuilder::default()
2929 .with_path("matrix[*][*]", (&DataType::Float64, false))?
2930 .build();
2931
2932 assert_eq!(
2933 shredding_type,
2934 DataType::Struct(Fields::from(vec![Field::new(
2935 "matrix",
2936 DataType::new_list(DataType::new_list(DataType::Float64, false), true),
2937 true,
2938 )]))
2939 );
2940
2941 Ok(())
2942 }
2943
2944 #[test]
2945 fn test_variant_schema_builder_rejects_list_indexes() {
2946 for (path, index) in [("items[0].id", 0), ("items[42].name", 42)] {
2947 let error = ShreddedSchemaBuilder::default()
2948 .with_path(path, &DataType::Int64)
2949 .err()
2950 .unwrap();
2951
2952 let ArrowError::InvalidArgumentError(message) = error else {
2953 panic!("expected InvalidArgumentError, got {error:?}");
2954 };
2955 assert_eq!(
2956 message,
2957 format!("List indexes are not supported in schema paths; use [*], got [{index}]")
2958 );
2959 }
2960 }
2961
2962 #[test]
2963 fn test_variant_schema_builder_with_path_variant_path_arg() -> Result<()> {
2964 let path = VariantPath::from_iter([VariantPathElement::from("a.b")]);
2965 let shredding_type = ShreddedSchemaBuilder::default()
2966 .with_path(path, &DataType::Int64)?
2967 .build();
2968
2969 match shredding_type {
2970 DataType::Struct(fields) => {
2971 assert_eq!(fields.len(), 1);
2972 assert_eq!(fields[0].name(), "a.b");
2973 assert_eq!(fields[0].data_type(), &DataType::Int64);
2974 }
2975 _ => panic!("expected struct data type"),
2976 }
2977
2978 Ok(())
2979 }
2980
2981 #[test]
2982 fn test_variant_schema_builder_custom_nullability() -> Result<()> {
2983 let shredding_type = ShreddedSchemaBuilder::default()
2984 .with_path(
2985 "foo",
2986 Arc::new(Field::new("should_be_renamed", DataType::Utf8, false)),
2987 )?
2988 .with_path("bar", (&DataType::Int64, false))?
2989 .build();
2990
2991 let DataType::Struct(fields) = shredding_type else {
2992 panic!("expected struct data type");
2993 };
2994
2995 let foo = fields.iter().find(|f| f.name() == "foo").unwrap();
2996 assert_eq!(foo.data_type(), &DataType::Utf8);
2997 assert!(!foo.is_nullable());
2998
2999 let bar = fields.iter().find(|f| f.name() == "bar").unwrap();
3000 assert_eq!(bar.data_type(), &DataType::Int64);
3001 assert!(!bar.is_nullable());
3002
3003 Ok(())
3004 }
3005
3006 #[test]
3007 fn test_variant_schema_builder_with_shred_variant() -> Result<()> {
3008 let input = build_variant_array(vec![
3009 VariantRow::Object(vec![
3010 ("time", VariantValue::from(1234567890i64)),
3011 ("hostname", VariantValue::from("server1")),
3012 ("extra", VariantValue::from(42)),
3013 ]),
3014 VariantRow::Object(vec![
3015 ("time", VariantValue::from(9876543210i64)),
3016 ("hostname", VariantValue::from("server2")),
3017 ]),
3018 VariantRow::Null,
3019 ]);
3020
3021 let shredding_type = ShreddedSchemaBuilder::default()
3022 .with_path("time", &DataType::Int64)?
3023 .with_path("hostname", &DataType::Utf8)?
3024 .build();
3025
3026 let result = shred_variant(&input, &shredding_type).unwrap();
3027
3028 assert_eq!(
3029 result.data_type(),
3030 &DataType::Struct(Fields::from(vec![
3031 Field::new("metadata", DataType::BinaryView, false),
3032 Field::new("value", DataType::BinaryView, true),
3033 Field::new(
3034 "typed_value",
3035 DataType::Struct(Fields::from(vec![
3036 Field::new(
3037 "hostname",
3038 DataType::Struct(Fields::from(vec![
3039 Field::new("value", DataType::BinaryView, true),
3040 Field::new("typed_value", DataType::Utf8, true),
3041 ])),
3042 false,
3043 ),
3044 Field::new(
3045 "time",
3046 DataType::Struct(Fields::from(vec![
3047 Field::new("value", DataType::BinaryView, true),
3048 Field::new("typed_value", DataType::Int64, true),
3049 ])),
3050 false,
3051 ),
3052 ])),
3053 true,
3054 ),
3055 ]))
3056 );
3057
3058 assert_eq!(result.len(), 3);
3059 assert!(result.typed_value_column().is_some());
3060
3061 let typed_value = result
3062 .typed_value_column()
3063 .unwrap()
3064 .as_any()
3065 .downcast_ref::<arrow::array::StructArray>()
3066 .unwrap();
3067
3068 let time_field =
3069 ShreddedVariantFieldArray::try_new(typed_value.column_by_name("time").unwrap())
3070 .unwrap();
3071 let hostname_field =
3072 ShreddedVariantFieldArray::try_new(typed_value.column_by_name("hostname").unwrap())
3073 .unwrap();
3074
3075 let time_typed = time_field
3076 .typed_value_column()
3077 .unwrap()
3078 .as_any()
3079 .downcast_ref::<Int64Array>()
3080 .unwrap();
3081 let hostname_typed = hostname_field
3082 .typed_value_column()
3083 .unwrap()
3084 .as_any()
3085 .downcast_ref::<arrow::array::StringArray>()
3086 .unwrap();
3087
3088 assert!(!result.is_null(0));
3090 assert_eq!(time_typed.value(0), 1234567890);
3091 assert_eq!(hostname_typed.value(0), "server1");
3092
3093 assert!(!result.is_null(1));
3095 assert_eq!(time_typed.value(1), 9876543210);
3096 assert_eq!(hostname_typed.value(1), "server2");
3097
3098 assert!(result.is_null(2));
3100
3101 Ok(())
3102 }
3103
3104 #[test]
3105 fn test_variant_schema_builder_conflicting_path() -> Result<()> {
3106 let shredding_type = ShreddedSchemaBuilder::default()
3107 .with_path("a", &DataType::Int64)?
3108 .with_path("a", &DataType::Float64)?
3109 .build();
3110
3111 assert_eq!(
3112 shredding_type,
3113 DataType::Struct(Fields::from(
3114 vec![Field::new("a", DataType::Float64, true),]
3115 ))
3116 );
3117
3118 Ok(())
3119 }
3120
3121 #[test]
3122 fn test_variant_schema_builder_root_path() -> Result<()> {
3123 let path = VariantPath::new(vec![]);
3124 let shredding_type = ShreddedSchemaBuilder::default()
3125 .with_path(path, &DataType::Int64)?
3126 .build();
3127
3128 assert_eq!(shredding_type, DataType::Int64);
3129
3130 Ok(())
3131 }
3132
3133 #[test]
3134 fn test_variant_schema_builder_empty_path() -> Result<()> {
3135 let shredding_type = ShreddedSchemaBuilder::default()
3136 .with_path("", &DataType::Int64)?
3137 .build();
3138
3139 assert_eq!(shredding_type, DataType::Int64);
3140 Ok(())
3141 }
3142
3143 #[test]
3144 fn test_variant_schema_builder_default() {
3145 let shredding_type = ShreddedSchemaBuilder::default().build();
3146 assert_eq!(shredding_type, DataType::Null);
3147 }
3148
3149 #[test]
3151 fn test_variant_type_shredded_correctly() {
3152 let mut array_builder = VariantArrayBuilder::new(30);
3154 array_builder.append_value(Variant::Null);
3155 array_builder.append_value(Variant::Int8(1));
3156 array_builder.append_value(Variant::Int16(2));
3157 array_builder.append_value(Variant::Int32(3));
3158 array_builder.append_value(Variant::Int64(4));
3159 array_builder.append_value(Variant::Date(NaiveDate::from_epoch_days(12345).unwrap()));
3160 array_builder.append_value(Variant::TimestampMicros(
3161 DateTime::from_timestamp_micros(123456789).unwrap(),
3162 ));
3163 array_builder.append_value(Variant::TimestampNtzMicros(
3164 DateTime::from_timestamp_micros(123456789)
3165 .unwrap()
3166 .naive_utc(),
3167 ));
3168 array_builder.append_value(Variant::TimestampNanos(DateTime::from_timestamp_nanos(
3169 1234567890000,
3170 )));
3171 array_builder.append_value(Variant::TimestampNtzNanos(
3172 DateTime::from_timestamp_nanos(1234567890000).naive_utc(),
3173 ));
3174 array_builder.append_value(VariantDecimal4::try_new(123, 0).unwrap());
3175 array_builder.append_value(VariantDecimal8::try_new(123, 0).unwrap());
3176 array_builder.append_value(VariantDecimal16::try_new(123, 0).unwrap());
3177 array_builder.append_value(Variant::Float(5.0));
3178 array_builder.append_value(Variant::Double(6f64));
3179 array_builder.append_value(Variant::BooleanTrue);
3180 array_builder.append_value(Variant::BooleanFalse);
3181 array_builder.append_value(Variant::Binary(b"helow"));
3182 array_builder.append_value(Variant::String("hello"));
3183 array_builder.append_value(Variant::ShortString(
3184 ShortString::try_from("world").unwrap(),
3185 ));
3186 array_builder.append_value(Variant::Time(
3187 NaiveTime::from_num_seconds_from_midnight_opt(12345, 123).unwrap(),
3188 ));
3189
3190 let array = array_builder.build();
3191
3192 fn can_shred_to(v: &Variant, dt: &DataType) -> bool {
3193 matches!(
3194 (v, dt),
3195 (
3196 Variant::Int8(_)
3197 | Variant::Int16(_)
3198 | Variant::Int32(_)
3199 | Variant::Int64(_)
3200 | Variant::Decimal4(_)
3201 | Variant::Decimal8(_)
3202 | Variant::Decimal16(_),
3203 DataType::Int8
3204 | DataType::Int16
3205 | DataType::Int32
3206 | DataType::Int64
3207 | DataType::Decimal32(_, _)
3208 | DataType::Decimal64(_, _)
3209 | DataType::Decimal128(_, _)
3210 ) | (Variant::Date(_), DataType::Date32)
3211 | (
3212 Variant::TimestampMicros(_) | Variant::TimestampNanos(_),
3213 DataType::Timestamp(TimeUnit::Microsecond | TimeUnit::Nanosecond, Some(_))
3214 )
3215 | (
3216 Variant::TimestampNtzMicros(_) | Variant::TimestampNtzNanos(_),
3217 DataType::Timestamp(TimeUnit::Microsecond | TimeUnit::Nanosecond, None)
3218 )
3219 | (Variant::Float(_), DataType::Float32)
3220 | (Variant::Double(_), DataType::Float64)
3221 | (
3222 Variant::BooleanFalse | Variant::BooleanTrue,
3223 DataType::Boolean
3224 )
3225 | (
3226 Variant::Binary(_),
3227 DataType::Binary | DataType::BinaryView | DataType::LargeBinary
3228 )
3229 | (
3230 Variant::ShortString(_) | Variant::String(_),
3231 DataType::Utf8 | DataType::Utf8View | DataType::LargeUtf8
3232 )
3233 | (Variant::Time(_), DataType::Time64(_))
3234 )
3235 }
3236
3237 macro_rules! assert_shred_type {
3238 ($shred_type:expr, $expected_value_valid_bits:expr) => {
3239 let shredded_array_result = shred_variant(&array, &$shred_type);
3240 match shredded_array_result {
3241 Ok(shredded_array) => {
3242 let value_column = shredded_array.inner().column_by_name("value").unwrap();
3243 for (idx, valid) in $expected_value_valid_bits.iter().enumerate() {
3244 match valid {
3245 true => assert!(
3246 value_column.is_null(idx),
3247 "{:?} should be shredded to {}",
3248 array.value(idx),
3249 $shred_type
3250 ),
3251 false => assert!(
3252 value_column.is_valid(idx),
3253 "{:?} should not be shredded to {}",
3254 array.value(idx),
3255 $shred_type
3256 ),
3257 }
3258 }
3259 }
3260 Err(e) => {
3261 let error_msg = format!("is not a valid variant shredding type");
3262 assert!(
3263 e.to_string().contains(error_msg.as_str()),
3264 "{} => {}",
3265 $shred_type,
3266 e.to_string()
3267 );
3268 }
3269 }
3270 };
3271 }
3272
3273 let types = [
3274 DataType::Null,
3275 DataType::Boolean,
3276 DataType::Int8,
3277 DataType::Int16,
3278 DataType::Int32,
3279 DataType::Int64,
3280 DataType::UInt8,
3281 DataType::UInt16,
3282 DataType::UInt32,
3283 DataType::UInt64,
3284 DataType::Float32,
3285 DataType::Float64,
3286 DataType::Timestamp(TimeUnit::Second, Some("+00:00".into())),
3287 DataType::Timestamp(TimeUnit::Second, None),
3288 DataType::Timestamp(TimeUnit::Millisecond, Some("-00:00".into())),
3289 DataType::Timestamp(TimeUnit::Millisecond, None),
3290 DataType::Timestamp(TimeUnit::Microsecond, Some("-00:00".into())),
3291 DataType::Timestamp(TimeUnit::Microsecond, None),
3292 DataType::Timestamp(TimeUnit::Nanosecond, Some("+00:00".into())),
3293 DataType::Timestamp(TimeUnit::Nanosecond, None),
3294 DataType::Date32,
3295 DataType::Date64,
3296 DataType::Time32(TimeUnit::Second),
3297 DataType::Time32(TimeUnit::Millisecond),
3298 DataType::Time64(TimeUnit::Microsecond),
3299 DataType::Time64(TimeUnit::Nanosecond),
3300 DataType::Duration(TimeUnit::Nanosecond),
3301 DataType::Interval(IntervalUnit::DayTime),
3302 DataType::Binary,
3303 DataType::FixedSizeBinary(16), DataType::FixedSizeBinary(32),
3305 DataType::LargeBinary,
3306 DataType::BinaryView,
3307 DataType::Utf8,
3308 DataType::LargeUtf8,
3309 DataType::Utf8View,
3310 DataType::Decimal32(7, 4),
3311 DataType::Decimal64(7, 4),
3312 DataType::Decimal128(7, 4),
3313 DataType::Decimal256(7, 4),
3314 ];
3315
3316 for data_type in types {
3317 let expected_bits = array
3318 .iter()
3319 .map(|v| can_shred_to(&v.unwrap(), &data_type))
3320 .collect::<Vec<bool>>();
3321 assert_shred_type!(data_type, expected_bits);
3322 }
3323 }
3324}