1use crate::VariantArrayBuilder;
21use crate::type_conversion::{
22 generic_conversion_single_value, generic_conversion_single_value_with_result,
23 primitive_conversion_single_value,
24};
25use arrow::array::{
26 Array, ArrayRef, AsArray, StructArray, downcast_dictionary_array, downcast_run_array,
27 new_null_array,
28};
29use arrow::buffer::NullBuffer;
30use arrow::compute::cast;
31use arrow::datatypes::{
32 Date32Type, Decimal32Type, Decimal64Type, Decimal128Type, Float16Type, Float32Type,
33 Float64Type, Int8Type, Int16Type, Int32Type, Int64Type, Time64MicrosecondType,
34 TimestampMicrosecondType, TimestampNanosecondType,
35};
36use arrow::error::Result;
37use arrow_schema::extension::{ExtensionType, Uuid as UuidExtension};
38use arrow_schema::{ArrowError, DataType, Field, FieldRef, Fields, TimeUnit};
39use chrono::{DateTime, NaiveTime};
40use parquet_variant::{
41 Uuid, Variant, VariantDecimal4, VariantDecimal8, VariantDecimal16, VariantDecimalType as _,
42};
43
44use std::borrow::Cow;
45use std::sync::Arc;
46
47pub(crate) fn binary_array_value(array: &dyn Array, index: usize) -> Option<&[u8]> {
50 if array.is_null(index) {
51 return None;
52 }
53 match array.data_type() {
54 DataType::Binary => Some(array.as_binary::<i32>().value(index)),
55 DataType::LargeBinary => Some(array.as_binary::<i64>().value(index)),
56 DataType::BinaryView => Some(array.as_binary_view().value(index)),
57 DataType::Dictionary(..) => downcast_dictionary_array! {
58 array => {
59 let index = array.key(index)?;
60 binary_array_value(array.values().as_ref(), index)
61 },
62 _ => unreachable!(),
63 },
64 DataType::RunEndEncoded(..) => downcast_run_array! {
65 array => {
66 let index = array.get_physical_index(index);
67 binary_array_value(array.values().as_ref(), index)
68 },
69 _ => unreachable!(),
70 },
71 _ => None,
72 }
73}
74
75pub(crate) fn variant_from_arrays_at<'m, 'v>(
78 metadata: &'m dyn Array,
79 value: &'v dyn Array,
80 index: usize,
81) -> Option<Variant<'m, 'v>> {
82 let metadata = binary_array_value(metadata, index)?;
83 let value = binary_array_value(value, index)?;
84 Some(Variant::new(metadata, value))
85}
86
87pub(crate) fn all_null_value_column(len: usize) -> ArrayRef {
93 new_null_array(&DataType::BinaryView, len)
94}
95
96pub(crate) fn validate_binary_array(array: &dyn Array, field_name: &str) -> Result<()> {
98 match array.data_type() {
99 DataType::Binary | DataType::LargeBinary | DataType::BinaryView => Ok(()),
100 _ => Err(ArrowError::InvalidArgumentError(format!(
101 "VariantArray '{field_name}' field must be Binary, LargeBinary, or BinaryView, got {}",
102 array.data_type()
103 ))),
104 }
105}
106
107fn validate_metadata_array(array: &dyn Array) -> Result<()> {
109 let is_binary = |data_type: &DataType| {
110 matches!(
111 data_type,
112 DataType::Binary | DataType::LargeBinary | DataType::BinaryView
113 )
114 };
115 match array.data_type() {
116 data_type if is_binary(data_type) => Ok(()),
117 DataType::Dictionary(_, values) if is_binary(values) => Ok(()),
118 DataType::RunEndEncoded(_, values) if is_binary(values.data_type()) => Ok(()),
119 _ => Err(ArrowError::InvalidArgumentError(format!(
120 "VariantArray 'metadata' field must be Binary, LargeBinary, BinaryView, or a Dictionary or RunEndEncoded array of one of those types, got {}",
121 array.data_type()
122 ))),
123 }
124}
125
126pub struct VariantType;
131
132impl ExtensionType for VariantType {
133 const NAME: &'static str = "arrow.parquet.variant";
134
135 type Metadata = &'static str;
138
139 fn metadata(&self) -> &Self::Metadata {
140 &""
141 }
142
143 fn serialize_metadata(&self) -> Option<String> {
144 Some(String::new())
145 }
146
147 fn deserialize_metadata(_metadata: Option<&str>) -> Result<Self::Metadata> {
148 Ok("")
149 }
150
151 fn supports_data_type(&self, data_type: &DataType) -> Result<()> {
152 if matches!(data_type, DataType::Struct(_)) {
153 Ok(())
154 } else {
155 Err(ArrowError::InvalidArgumentError(format!(
156 "VariantType only supports StructArray, got {data_type}"
157 )))
158 }
159 }
160
161 fn try_new(data_type: &DataType, _metadata: Self::Metadata) -> Result<Self> {
162 Self.supports_data_type(data_type)?;
163 Ok(Self)
164 }
165
166 fn validate(data_type: &DataType, _metadata: Self::Metadata) -> Result<()> {
167 Self.supports_data_type(data_type)
168 }
169}
170
171#[derive(Debug, Clone)]
302pub struct VariantArray {
303 inner: StructArray,
305
306 metadata: ArrayRef,
308
309 shredding_state: ShreddingState,
311}
312
313impl VariantArray {
314 pub fn try_new(inner: &dyn Array) -> Result<Self> {
338 let inner = canonicalize_shredded_types(inner)?;
340
341 let Some(inner) = inner.as_struct_opt() else {
342 return Err(ArrowError::InvalidArgumentError(
343 "Invalid VariantArray: requires StructArray as input".to_string(),
344 ));
345 };
346
347 let Some(metadata_col) = inner.column_by_name("metadata") else {
351 return Err(ArrowError::InvalidArgumentError(
352 "Invalid VariantArray: StructArray must contain a 'metadata' field".to_string(),
353 ));
354 };
355 validate_metadata_array(metadata_col.as_ref())?;
356
357 let shredding_state = ShreddingState::try_from(inner)?;
358
359 if inner.column_by_name("value").is_none() {
362 return Ok(Self::from_parts(
363 metadata_col.clone(),
364 shredding_state.value_column().clone(),
365 shredding_state.typed_value_column().cloned(),
366 inner.nulls().cloned(),
367 ));
368 }
369
370 Ok(Self {
372 inner: inner.clone(),
373 metadata: metadata_col.clone(),
374 shredding_state,
375 })
376 }
377
378 pub(crate) fn from_parts(
383 metadata: ArrayRef,
384 value: ArrayRef,
385 typed_value: Option<ArrayRef>,
386 nulls: Option<NullBuffer>,
387 ) -> Self {
388 Self::from_parts_with_nullable_value(metadata, value, typed_value, nulls, true)
389 }
390
391 pub(crate) fn from_parts_unshredded(
397 metadata: ArrayRef,
398 value: ArrayRef,
399 nulls: Option<NullBuffer>,
400 ) -> Self {
401 Self::from_parts_with_nullable_value(metadata, value, None, nulls, false)
402 }
403
404 fn from_parts_with_nullable_value(
405 metadata: ArrayRef,
406 value: ArrayRef,
407 typed_value: Option<ArrayRef>,
408 nulls: Option<NullBuffer>,
409 value_nullable: bool,
410 ) -> Self {
411 let mut builder = StructArrayBuilder::new()
412 .with_field("metadata", metadata.clone(), false)
413 .with_field("value", value.clone(), value_nullable);
414 if let Some(typed_value) = typed_value.clone() {
415 builder = builder.with_field_ref(typed_value_field(&typed_value), typed_value);
416 }
417 if let Some(nulls) = nulls {
418 builder = builder.with_nulls(nulls);
419 }
420
421 Self {
422 inner: builder.build(),
423 metadata,
424 shredding_state: ShreddingState::new(value, typed_value),
425 }
426 }
427
428 pub fn inner(&self) -> &StructArray {
430 &self.inner
431 }
432
433 pub fn into_inner(self) -> StructArray {
435 self.inner
436 }
437
438 pub fn shredding_state(&self) -> &ShreddingState {
440 &self.shredding_state
441 }
442
443 pub fn value(&self, index: usize) -> Variant<'_, '_> {
454 self.try_value(index)
455 .unwrap_or_else(|err| panic!("VariantArray::value({index}) failed: {err}"))
456 }
457
458 pub fn try_value(&self, index: usize) -> Result<Variant<'_, '_>> {
487 if self.len() <= index {
488 return Err(ArrowError::InvalidArgumentError(format!(
489 "Index {index} out of bounds for VariantArray of length {}",
490 self.len()
491 )));
492 }
493
494 let value = self.value_column();
495 match self.typed_value_column() {
496 Some(typed_value) if typed_value.is_valid(index) => {
498 if !matches!(typed_value.data_type(), DataType::Struct(_)) && value.is_valid(index) {
499 return Err(ArrowError::InvalidArgumentError(
501 "Invalid variant, conflicting value and typed_value".to_owned(),
502 ));
503 }
504 typed_value_to_variant(typed_value, index)
505 }
506 _ if value.is_valid(index) => variant_from_arrays_at(&self.metadata, value, index)
508 .ok_or_else(|| {
509 ArrowError::InvalidArgumentError(format!(
510 "metadata and value fields must be binary-like arrays, instead got {} and {}",
511 self.metadata.data_type(),
512 value.data_type()
513 ))
514 }),
515 _ => Ok(Variant::Null),
518 }
519 }
520
521 pub fn metadata_column(&self) -> &ArrayRef {
523 &self.metadata
524 }
525
526 pub fn value_column(&self) -> &ArrayRef {
528 self.shredding_state.value_column()
529 }
530
531 pub fn typed_value_column(&self) -> Option<&ArrayRef> {
533 self.shredding_state.typed_value_column()
534 }
535
536 pub fn field(&self, name: impl Into<String>) -> Field {
539 Field::new(
540 name.into(),
541 self.data_type().clone(),
542 self.inner.is_nullable(),
543 )
544 .with_extension_type(VariantType)
545 }
546
547 pub fn data_type(&self) -> &DataType {
549 self.inner.data_type()
550 }
551
552 pub fn slice(&self, offset: usize, length: usize) -> Self {
553 let inner = self.inner.slice(offset, length);
554 let metadata = self.metadata.slice(offset, length);
555 let shredding_state = self.shredding_state.slice(offset, length);
556 Self {
557 inner,
558 metadata,
559 shredding_state,
560 }
561 }
562
563 pub fn len(&self) -> usize {
564 self.inner.len()
565 }
566
567 pub fn is_empty(&self) -> bool {
568 self.inner.is_empty()
569 }
570
571 pub fn nulls(&self) -> Option<&NullBuffer> {
572 self.inner.nulls()
573 }
574
575 pub fn is_null(&self, index: usize) -> bool {
577 self.nulls().is_some_and(|n| n.is_null(index))
578 }
579
580 pub fn is_valid(&self, index: usize) -> bool {
582 !self.is_null(index)
583 }
584
585 pub fn iter(&self) -> VariantArrayIter<'_> {
587 VariantArrayIter::new(self)
588 }
589}
590
591impl<'a> IntoIterator for &'a VariantArray {
592 type Item = Option<Variant<'a, 'a>>;
593 type IntoIter = VariantArrayIter<'a>;
594
595 fn into_iter(self) -> Self::IntoIter {
596 VariantArrayIter::new(self)
597 }
598}
599
600impl PartialEq for VariantArray {
601 fn eq(&self, other: &Self) -> bool {
602 self.inner == other.inner
603 }
604}
605
606impl From<VariantArray> for StructArray {
607 fn from(variant_array: VariantArray) -> Self {
608 variant_array.into_inner()
609 }
610}
611
612impl From<VariantArray> for ArrayRef {
613 fn from(variant_array: VariantArray) -> Self {
614 Arc::new(variant_array.into_inner())
615 }
616}
617
618impl<'m, 'v> FromIterator<Option<Variant<'m, 'v>>> for VariantArray {
619 fn from_iter<T: IntoIterator<Item = Option<Variant<'m, 'v>>>>(iter: T) -> Self {
620 let iter = iter.into_iter();
621
622 let mut b = VariantArrayBuilder::new(iter.size_hint().0);
623 b.extend(iter);
624 b.build()
625 }
626}
627
628impl<'m, 'v> FromIterator<Variant<'m, 'v>> for VariantArray {
629 fn from_iter<T: IntoIterator<Item = Variant<'m, 'v>>>(iter: T) -> Self {
630 Self::from_iter(iter.into_iter().map(Some))
631 }
632}
633
634#[derive(Debug)]
659pub struct VariantArrayIter<'a> {
660 array: &'a VariantArray,
661 head_i: usize,
662 tail_i: usize,
663}
664
665impl<'a> VariantArrayIter<'a> {
666 pub fn new(array: &'a VariantArray) -> Self {
668 Self {
669 array,
670 head_i: 0,
671 tail_i: array.len(),
672 }
673 }
674
675 fn value_opt(&self, i: usize) -> Option<Variant<'a, 'a>> {
676 self.array.is_valid(i).then(|| self.array.value(i))
677 }
678}
679
680impl<'a> Iterator for VariantArrayIter<'a> {
681 type Item = Option<Variant<'a, 'a>>;
682
683 #[inline]
684 fn next(&mut self) -> Option<Self::Item> {
685 if self.head_i == self.tail_i {
686 return None;
687 }
688
689 let out = self.value_opt(self.head_i);
690
691 self.head_i += 1;
692
693 Some(out)
694 }
695
696 fn size_hint(&self) -> (usize, Option<usize>) {
697 let remainder = self.tail_i - self.head_i;
698
699 (remainder, Some(remainder))
700 }
701}
702
703impl DoubleEndedIterator for VariantArrayIter<'_> {
704 fn next_back(&mut self) -> Option<Self::Item> {
705 if self.head_i == self.tail_i {
706 return None;
707 }
708
709 self.tail_i -= 1;
710
711 Some(self.value_opt(self.tail_i))
712 }
713}
714
715impl ExactSizeIterator for VariantArrayIter<'_> {}
716
717#[derive(Debug)]
752pub struct ShreddedVariantFieldArray {
753 inner: StructArray,
755 shredding_state: ShreddingState,
756}
757
758impl ShreddedVariantFieldArray {
759 pub fn try_new(inner: &dyn Array) -> Result<Self> {
779 let Some(inner_struct) = inner.as_struct_opt() else {
780 return Err(ArrowError::InvalidArgumentError(
781 "Invalid ShreddedVariantFieldArray: requires StructArray as input".to_string(),
782 ));
783 };
784
785 let shredding_state = ShreddingState::try_from(inner_struct)?;
786
787 if inner_struct.column_by_name("value").is_none() {
790 return Ok(Self::from_parts(
791 shredding_state.value_column().clone(),
792 shredding_state.typed_value_column().cloned(),
793 inner_struct.nulls().cloned(),
794 ));
795 }
796
797 Ok(Self {
799 inner: inner_struct.clone(),
800 shredding_state,
801 })
802 }
803
804 pub fn shredding_state(&self) -> &ShreddingState {
806 &self.shredding_state
807 }
808
809 pub fn value_column(&self) -> &ArrayRef {
811 self.shredding_state.value_column()
812 }
813
814 pub fn typed_value_column(&self) -> Option<&ArrayRef> {
816 self.shredding_state.typed_value_column()
817 }
818
819 pub fn inner(&self) -> &StructArray {
821 &self.inner
822 }
823
824 pub(crate) fn from_parts(
825 value: ArrayRef,
826 typed_value: Option<ArrayRef>,
827 nulls: Option<NullBuffer>,
828 ) -> Self {
829 let mut builder = StructArrayBuilder::new().with_field("value", value.clone(), true);
830 if let Some(typed_value) = typed_value.clone() {
831 builder = builder.with_field_ref(typed_value_field(&typed_value), typed_value);
832 }
833 if let Some(nulls) = nulls {
834 builder = builder.with_nulls(nulls);
835 }
836
837 Self {
838 inner: builder.build(),
839 shredding_state: ShreddingState::new(value, typed_value),
840 }
841 }
842
843 pub fn into_inner(self) -> StructArray {
845 self.inner
846 }
847
848 pub fn data_type(&self) -> &DataType {
849 self.inner.data_type()
850 }
851
852 pub fn len(&self) -> usize {
853 self.inner.len()
854 }
855
856 pub fn is_empty(&self) -> bool {
857 self.inner.is_empty()
858 }
859
860 pub fn offset(&self) -> usize {
861 self.inner.offset()
862 }
863
864 pub fn nulls(&self) -> Option<&NullBuffer> {
865 None
869 }
870 pub fn is_null(&self, index: usize) -> bool {
872 self.nulls().is_some_and(|n| n.is_null(index))
873 }
874
875 pub fn is_valid(&self, index: usize) -> bool {
877 !self.is_null(index)
878 }
879}
880
881impl From<ShreddedVariantFieldArray> for ArrayRef {
882 fn from(array: ShreddedVariantFieldArray) -> Self {
883 Arc::new(array.into_inner())
884 }
885}
886
887impl From<ShreddedVariantFieldArray> for StructArray {
888 fn from(array: ShreddedVariantFieldArray) -> Self {
889 array.into_inner()
890 }
891}
892
893#[derive(Debug, Clone)]
930pub struct ShreddingState {
931 value: ArrayRef,
932 typed_value: Option<ArrayRef>,
933}
934
935impl ShreddingState {
936 pub fn new(value: ArrayRef, typed_value: Option<ArrayRef>) -> Self {
951 Self { value, typed_value }
952 }
953
954 pub fn value_column(&self) -> &ArrayRef {
956 &self.value
957 }
958
959 pub fn typed_value_column(&self) -> Option<&ArrayRef> {
961 self.typed_value.as_ref()
962 }
963
964 pub fn slice(&self, offset: usize, length: usize) -> Self {
966 Self {
967 value: self.value.slice(offset, length),
968 typed_value: self.typed_value.as_ref().map(|tv| tv.slice(offset, length)),
969 }
970 }
971}
972
973impl TryFrom<&StructArray> for ShreddingState {
974 type Error = ArrowError;
975
976 fn try_from(inner_struct: &StructArray) -> Result<Self> {
977 let typed_value = inner_struct.column_by_name("typed_value").cloned();
978 let value = match inner_struct.column_by_name("value") {
979 Some(value) => {
980 validate_binary_array(value.as_ref(), "value")?;
981 value.clone()
982 }
983 None if typed_value.is_some() => all_null_value_column(inner_struct.len()),
986 None => {
987 return Err(ArrowError::InvalidArgumentError(
988 "Invalid VariantArray: StructArray must contain a 'value' field".to_string(),
989 ));
990 }
991 };
992 Ok(ShreddingState::new(value, typed_value))
993 }
994}
995
996fn typed_value_field(array: &ArrayRef) -> FieldRef {
1002 let mut field = Field::new("typed_value", array.data_type().clone(), true);
1003 if matches!(array.data_type(), DataType::FixedSizeBinary(16)) {
1004 field = field.with_extension_type(UuidExtension);
1005 }
1006 Arc::new(field)
1007}
1008
1009#[derive(Debug, Default, Clone)]
1013pub(crate) struct StructArrayBuilder {
1014 fields: Vec<FieldRef>,
1015 arrays: Vec<ArrayRef>,
1016 nulls: Option<NullBuffer>,
1017}
1018
1019impl StructArrayBuilder {
1020 pub fn new() -> Self {
1021 Default::default()
1022 }
1023
1024 pub fn with_field(mut self, field_name: &str, array: ArrayRef, nullable: bool) -> Self {
1026 let field = Field::new(field_name, array.data_type().clone(), nullable);
1027 self.fields.push(Arc::new(field));
1028 self.arrays.push(array);
1029 self
1030 }
1031
1032 pub fn with_field_ref(mut self, field: FieldRef, array: ArrayRef) -> Self {
1037 self.fields.push(field);
1038 self.arrays.push(array);
1039 self
1040 }
1041
1042 pub fn with_nulls(mut self, nulls: NullBuffer) -> Self {
1044 self.nulls = Some(nulls);
1045 self
1046 }
1047
1048 pub fn build(self) -> StructArray {
1049 let Self {
1050 fields,
1051 arrays,
1052 nulls,
1053 } = self;
1054 StructArray::new(Fields::from(fields), arrays, nulls)
1055 }
1056}
1057
1058fn typed_value_to_variant(typed_value: &ArrayRef, index: usize) -> Result<Variant<'_, '_>> {
1060 let data_type = typed_value.data_type();
1061 match data_type {
1062 DataType::Null => Ok(Variant::Null),
1063 DataType::Boolean => {
1064 let boolean_array = typed_value.as_boolean();
1065 let value = boolean_array.value(index);
1066 Ok(Variant::from(value))
1067 }
1068 DataType::FixedSizeBinary(16) => {
1070 let array = typed_value.as_fixed_size_binary();
1071 let value = array.value(index);
1072 Ok(Uuid::from_slice(value).unwrap().into()) }
1074 DataType::Binary => {
1075 let array = typed_value.as_binary::<i32>();
1076 let value = array.value(index);
1077 Ok(Variant::from(value))
1078 }
1079 DataType::LargeBinary => {
1080 let array = typed_value.as_binary::<i64>();
1081 let value = array.value(index);
1082 Ok(Variant::from(value))
1083 }
1084 DataType::BinaryView => {
1085 let array = typed_value.as_binary_view();
1086 let value = array.value(index);
1087 Ok(Variant::from(value))
1088 }
1089 DataType::Utf8 => {
1090 let array = typed_value.as_string::<i32>();
1091 let value = array.value(index);
1092 Ok(Variant::from(value))
1093 }
1094 DataType::LargeUtf8 => {
1095 let array = typed_value.as_string::<i64>();
1096 let value = array.value(index);
1097 Ok(Variant::from(value))
1098 }
1099 DataType::Utf8View => {
1100 let array = typed_value.as_string_view();
1101 let value = array.value(index);
1102 Ok(Variant::from(value))
1103 }
1104 DataType::Int8 => {
1105 primitive_conversion_single_value!(Int8Type, typed_value, index)
1106 }
1107 DataType::Int16 => {
1108 primitive_conversion_single_value!(Int16Type, typed_value, index)
1109 }
1110 DataType::Int32 => {
1111 primitive_conversion_single_value!(Int32Type, typed_value, index)
1112 }
1113 DataType::Int64 => {
1114 primitive_conversion_single_value!(Int64Type, typed_value, index)
1115 }
1116 DataType::Float16 => {
1117 primitive_conversion_single_value!(Float16Type, typed_value, index)
1118 }
1119 DataType::Float32 => {
1120 primitive_conversion_single_value!(Float32Type, typed_value, index)
1121 }
1122 DataType::Float64 => {
1123 primitive_conversion_single_value!(Float64Type, typed_value, index)
1124 }
1125 DataType::Decimal32(_, s) => {
1126 generic_conversion_single_value_with_result!(
1127 Decimal32Type,
1128 as_primitive,
1129 |v| VariantDecimal4::try_new(v, *s as u8),
1130 typed_value,
1131 index
1132 )
1133 }
1134 DataType::Decimal64(_, s) => {
1135 generic_conversion_single_value_with_result!(
1136 Decimal64Type,
1137 as_primitive,
1138 |v| VariantDecimal8::try_new(v, *s as u8),
1139 typed_value,
1140 index
1141 )
1142 }
1143 DataType::Decimal128(_, s) => {
1144 generic_conversion_single_value_with_result!(
1145 Decimal128Type,
1146 as_primitive,
1147 |v| VariantDecimal16::try_new(v, *s as u8),
1148 typed_value,
1149 index
1150 )
1151 }
1152 DataType::Date32 => {
1153 generic_conversion_single_value!(
1154 Date32Type,
1155 as_primitive,
1156 |v| Date32Type::to_naive_date_opt(v).unwrap(),
1157 typed_value,
1158 index
1159 )
1160 }
1161 DataType::Time64(TimeUnit::Microsecond) => {
1162 generic_conversion_single_value_with_result!(
1163 Time64MicrosecondType,
1164 as_primitive,
1165 |v| NaiveTime::from_num_seconds_from_midnight_opt(
1166 (v / 1_000_000) as u32,
1167 (v % 1_000_000) as u32 * 1000
1168 )
1169 .ok_or_else(|| format!("Invalid microsecond from midnight: {v}")),
1170 typed_value,
1171 index
1172 )
1173 }
1174 DataType::Timestamp(TimeUnit::Microsecond, Some(_)) => {
1175 generic_conversion_single_value!(
1176 TimestampMicrosecondType,
1177 as_primitive,
1178 |v| DateTime::from_timestamp_micros(v).unwrap(),
1179 typed_value,
1180 index
1181 )
1182 }
1183 DataType::Timestamp(TimeUnit::Microsecond, None) => {
1184 generic_conversion_single_value!(
1185 TimestampMicrosecondType,
1186 as_primitive,
1187 |v| DateTime::from_timestamp_micros(v).unwrap().naive_utc(),
1188 typed_value,
1189 index
1190 )
1191 }
1192 DataType::Timestamp(TimeUnit::Nanosecond, Some(_)) => {
1193 generic_conversion_single_value!(
1194 TimestampNanosecondType,
1195 as_primitive,
1196 DateTime::from_timestamp_nanos,
1197 typed_value,
1198 index
1199 )
1200 }
1201 DataType::Timestamp(TimeUnit::Nanosecond, None) => {
1202 generic_conversion_single_value!(
1203 TimestampNanosecondType,
1204 as_primitive,
1205 |v| DateTime::from_timestamp_nanos(v).naive_utc(),
1206 typed_value,
1207 index
1208 )
1209 }
1210 _ => Err(ArrowError::NotYetImplemented(format!(
1217 "VariantArray::try_value cannot materialize typed_value of type {} \
1218 as a borrowed Variant; call unshred_variant first",
1219 typed_value.data_type()
1220 ))),
1221 }
1222}
1223
1224fn canonicalize_shredded_types(array: &dyn Array) -> Result<ArrayRef> {
1227 let new_type = canonicalize_and_verify_data_type_impl(array.data_type(), true)?;
1228 if let Cow::Borrowed(_) = new_type
1229 && let Some(array) = array.as_struct_opt()
1230 {
1231 return Ok(Arc::new(array.clone())); }
1233 cast(array, new_type.as_ref())
1234}
1235
1236fn canonicalize_and_verify_data_type(data_type: &DataType) -> Result<Cow<'_, DataType>> {
1240 canonicalize_and_verify_data_type_impl(data_type, false)
1241}
1242
1243fn canonicalize_and_verify_data_type_impl(
1244 data_type: &DataType,
1245 skip_top_level_metadata: bool,
1246) -> Result<Cow<'_, DataType>> {
1247 use DataType::*;
1248
1249 macro_rules! fail {
1251 () => {
1252 return Err(ArrowError::InvalidArgumentError(format!(
1253 "Illegal shredded value type: {data_type}"
1254 )))
1255 };
1256 }
1257 macro_rules! borrow {
1258 () => {
1259 Cow::Borrowed(data_type)
1260 };
1261 }
1262
1263 let new_data_type = match data_type {
1264 Null | Boolean => borrow!(),
1266 Int8 | Int16 | Int32 | Int64 | Float32 | Float64 => borrow!(),
1267
1268 UInt8 | UInt16 | UInt32 | UInt64 | Float16 => fail!(),
1270
1271 Decimal64(p, s) | Decimal128(p, s)
1276 if VariantDecimal4::is_valid_precision_and_scale(p, s) =>
1277 {
1278 Cow::Owned(Decimal32(*p, *s))
1279 }
1280 Decimal128(p, s) if VariantDecimal8::is_valid_precision_and_scale(p, s) => {
1281 Cow::Owned(Decimal64(*p, *s))
1282 }
1283 Decimal32(p, s) if VariantDecimal4::is_valid_precision_and_scale(p, s) => borrow!(),
1284 Decimal64(p, s) if VariantDecimal8::is_valid_precision_and_scale(p, s) => borrow!(),
1285 Decimal128(p, s) if VariantDecimal16::is_valid_precision_and_scale(p, s) => borrow!(),
1286 Decimal32(..) | Decimal64(..) | Decimal128(..) | Decimal256(..) => fail!(),
1287
1288 Timestamp(TimeUnit::Microsecond | TimeUnit::Nanosecond, _) => borrow!(),
1290 Timestamp(TimeUnit::Millisecond | TimeUnit::Second, _) => fail!(),
1291
1292 Date32 | Time64(TimeUnit::Microsecond) => borrow!(),
1294 Date64 | Time32(_) | Time64(_) | Duration(_) | Interval(_) => fail!(),
1295
1296 Binary | LargeBinary | BinaryView | Utf8 | LargeUtf8 | Utf8View => borrow!(),
1298
1299 FixedSizeBinary(16) => borrow!(),
1301 FixedSizeBinary(_) => fail!(),
1302
1303 FixedSizeList(field, _) => match canonicalize_and_verify_field(field)? {
1307 Cow::Borrowed(_) => Cow::Owned(DataType::List(field.clone())),
1308 Cow::Owned(new_field) => Cow::Owned(DataType::List(new_field)),
1309 },
1310
1311 List(field) => match canonicalize_and_verify_field(field)? {
1313 Cow::Borrowed(_) => borrow!(),
1314 Cow::Owned(new_field) => Cow::Owned(DataType::List(new_field)),
1315 },
1316 LargeList(field) => match canonicalize_and_verify_field(field)? {
1317 Cow::Borrowed(_) => borrow!(),
1318 Cow::Owned(new_field) => Cow::Owned(DataType::LargeList(new_field)),
1319 },
1320 ListView(field) => match canonicalize_and_verify_field(field)? {
1321 Cow::Borrowed(_) => borrow!(),
1322 Cow::Owned(new_field) => Cow::Owned(DataType::ListView(new_field)),
1323 },
1324 LargeListView(field) => match canonicalize_and_verify_field(field)? {
1325 Cow::Borrowed(_) => borrow!(),
1326 Cow::Owned(new_field) => Cow::Owned(DataType::LargeListView(new_field)),
1327 },
1328 Struct(fields) => {
1330 let mut new_fields = std::collections::HashMap::new();
1333 for (i, field) in fields.iter().enumerate() {
1334 if skip_top_level_metadata && field.name() == "metadata" {
1335 continue;
1336 }
1337 if let Cow::Owned(new_field) = canonicalize_and_verify_field(field)? {
1338 new_fields.insert(i, new_field);
1339 }
1340 }
1341
1342 if new_fields.is_empty() {
1343 borrow!()
1344 } else {
1345 let new_fields = fields
1346 .iter()
1347 .enumerate()
1348 .map(|(i, field)| new_fields.remove(&i).unwrap_or_else(|| field.clone()));
1349 Cow::Owned(DataType::Struct(new_fields.collect()))
1350 }
1351 }
1352 Map(..) | Union(..) => fail!(),
1353
1354 Dictionary(..) | RunEndEncoded(..) => fail!(),
1356 };
1357 Ok(new_data_type)
1358}
1359
1360fn canonicalize_and_verify_field(field: &Arc<Field>) -> Result<Cow<'_, Arc<Field>>> {
1361 let new_data_type = canonicalize_and_verify_data_type(field.data_type())?;
1362
1363 if matches!(new_data_type.as_ref(), DataType::FixedSizeBinary(16))
1367 && !field.has_valid_extension_type::<UuidExtension>()
1368 {
1369 let new_field = field.as_ref().clone().with_extension_type(UuidExtension);
1370 return Ok(Cow::Owned(Arc::new(new_field)));
1371 }
1372
1373 let Cow::Owned(new_data_type) = new_data_type else {
1374 return Ok(Cow::Borrowed(field));
1375 };
1376 let new_field = field.as_ref().clone().with_data_type(new_data_type);
1377 Ok(Cow::Owned(Arc::new(new_field)))
1378}
1379
1380#[cfg(test)]
1383impl VariantArray {
1384 pub(crate) fn perfectly_shredded(
1385 metadata: ArrayRef,
1386 typed_value: ArrayRef,
1387 nulls: Option<NullBuffer>,
1388 ) -> Self {
1389 let value = all_null_value_column(typed_value.len());
1390 Self::from_parts(metadata, value, Some(typed_value), nulls)
1391 }
1392}
1393
1394#[cfg(test)]
1395impl ShreddedVariantFieldArray {
1396 pub(crate) fn perfectly_shredded(typed_value: ArrayRef) -> Self {
1397 let value = all_null_value_column(typed_value.len());
1398 Self::from_parts(value, Some(typed_value), None)
1399 }
1400}
1401
1402#[cfg(test)]
1403mod test {
1404 use crate::{GetOptions, VariantArrayBuilder, json_to_variant, variant_get, variant_to_json};
1405 use std::str::FromStr;
1406
1407 use super::*;
1408 use arrow::array::{
1409 BinaryArray, BinaryDictionaryBuilder, BinaryRunBuilder, BinaryViewArray, Decimal32Array,
1410 Decimal64Array, Decimal128Array, FixedSizeBinaryArray, FixedSizeListArray, Int8Array,
1411 Int32Array, Int64Array, LargeBinaryArray, LargeListArray, LargeListViewArray, ListArray,
1412 ListViewArray, StringArray, Time64MicrosecondArray,
1413 };
1414 use arrow::buffer::{OffsetBuffer, ScalarBuffer};
1415 use arrow_schema::{Field, Fields};
1416 use parquet_variant::{EMPTY_VARIANT_METADATA_BYTES, ShortString};
1417
1418 #[test]
1419 fn invalid_not_a_struct_array() {
1420 let array = make_binary_view_array();
1421 let err = VariantArray::try_new(&array);
1423 assert_eq!(
1424 err.unwrap_err().to_string(),
1425 "Invalid argument error: Invalid VariantArray: requires StructArray as input"
1426 );
1427 }
1428
1429 #[test]
1430 fn invalid_missing_metadata() {
1431 let fields = Fields::from(vec![Field::new("value", DataType::BinaryView, true)]);
1432 let array = StructArray::new(fields, vec![make_binary_view_array()], None);
1433 let err = VariantArray::try_new(&array);
1435 assert_eq!(
1436 err.unwrap_err().to_string(),
1437 "Invalid argument error: Invalid VariantArray: StructArray must contain a 'metadata' field"
1438 );
1439 }
1440
1441 #[test]
1442 fn read_missing_value_column() {
1443 let typed_value = Arc::new(Int64Array::from(vec![Some(1), None, Some(3)])) as ArrayRef;
1447 let metadata =
1448 BinaryViewArray::from_iter_values(std::iter::repeat_n(EMPTY_VARIANT_METADATA_BYTES, 3));
1449 let struct_array = StructArrayBuilder::new()
1450 .with_field("metadata", Arc::new(metadata), false)
1451 .with_field("typed_value", typed_value, true)
1452 .build();
1453 assert!(struct_array.column_by_name("value").is_none());
1454
1455 let variant_array = VariantArray::try_new(&struct_array).unwrap();
1456 assert_eq!(variant_array.value_column().len(), 3);
1457 assert_eq!(variant_array.value_column().null_count(), 3);
1458 assert!(variant_array.inner().column_by_name("value").is_some());
1459 assert!(variant_array.typed_value_column().is_some());
1460 assert_eq!(variant_array.value(0), Variant::from(1i64));
1461 assert_eq!(variant_array.value(1), Variant::Null);
1462 assert_eq!(variant_array.value(2), Variant::from(3i64));
1463
1464 let fields = Fields::from(vec![Field::new("metadata", DataType::BinaryView, false)]);
1466 let metadata_only = StructArray::new(fields, vec![make_binary_view_array()], None);
1467 let err = VariantArray::try_new(&metadata_only);
1468 assert_eq!(
1469 err.unwrap_err().to_string(),
1470 "Invalid argument error: Invalid VariantArray: StructArray must contain a 'value' field"
1471 );
1472 }
1473
1474 #[test]
1475 fn invalid_metadata_field_type() {
1476 let fields = Fields::from(vec![
1477 Field::new("metadata", DataType::Int32, true), Field::new("value", DataType::BinaryView, true),
1479 ]);
1480 let array = StructArray::new(
1481 fields,
1482 vec![make_int32_array(), make_binary_view_array()],
1483 None,
1484 );
1485 let err = VariantArray::try_new(&array);
1486 assert_eq!(
1487 err.unwrap_err().to_string(),
1488 "Invalid argument error: VariantArray 'metadata' field must be Binary, LargeBinary, BinaryView, or a Dictionary or RunEndEncoded array of one of those types, got Int32"
1489 );
1490 }
1491
1492 #[test]
1493 fn encoded_metadata_supports_nulls_slices_and_variant_get() {
1494 let json: ArrayRef = Arc::new(StringArray::from(vec![
1495 Some(r#"{"a":0}"#),
1496 Some(r#"{"a":1}"#),
1497 None,
1498 Some(r#"{"b":3}"#),
1499 Some(r#"{"b":4}"#),
1500 ]));
1501 let baseline = json_to_variant(&json).unwrap();
1502 let metadata = baseline.metadata_column().as_binary_view();
1503 let metadata_a = metadata.value(0);
1504 let metadata_b = metadata.value(3);
1505
1506 let logical_metadata = [
1507 Some(metadata_a),
1508 Some(metadata_a),
1509 None,
1510 Some(metadata_b),
1511 Some(metadata_b),
1512 ];
1513
1514 let mut dictionary = BinaryDictionaryBuilder::<Int8Type>::new();
1515 dictionary.extend(logical_metadata);
1516 let dictionary: ArrayRef = Arc::new(dictionary.finish());
1517
1518 let mut ree = BinaryRunBuilder::<Int16Type>::new();
1519 ree.extend(logical_metadata);
1520 let run_end_encoded: ArrayRef = Arc::new(ree.finish());
1521
1522 for metadata in [dictionary, run_end_encoded] {
1523 assert_eq!(binary_array_value(metadata.as_ref(), 2), None);
1524 let fields = Fields::from(vec![
1525 Field::new("metadata", metadata.data_type().clone(), false),
1526 Field::new("value", baseline.value_column().data_type().clone(), false),
1527 ]);
1528 let input = StructArray::try_new(
1529 fields,
1530 vec![metadata, baseline.value_column().clone()],
1531 baseline.nulls().cloned(),
1532 )
1533 .unwrap()
1534 .slice(1, 3);
1535
1536 let variant = VariantArray::try_new(&input).unwrap();
1537 assert_eq!(variant.value(0), baseline.value(1));
1538 assert!(variant.is_null(1));
1539 assert_eq!(variant.value(2), baseline.value(3));
1540
1541 let input: ArrayRef = Arc::new(input);
1542 let options = GetOptions::new_with_path("b".try_into().unwrap())
1543 .with_as_type(Some(Arc::new(Field::new("b", DataType::Int8, true))));
1544 let result = variant_get(&input, options).unwrap();
1545 assert_eq!(
1546 result.as_primitive::<Int8Type>(),
1547 &Int8Array::from(vec![None, None, Some(3)])
1548 );
1549 assert_eq!(
1550 variant_to_json(&input).unwrap(),
1551 StringArray::from(vec![Some(r#"{"a":1}"#), None, Some(r#"{"b":3}"#)])
1552 );
1553 }
1554 }
1555
1556 #[test]
1557 fn invalid_value_field_type() {
1558 let fields = Fields::from(vec![
1559 Field::new("metadata", DataType::BinaryView, true),
1560 Field::new("value", DataType::Int32, true),
1561 ]);
1562 let array = StructArray::new(
1563 fields,
1564 vec![make_binary_view_array(), make_int32_array()],
1565 None,
1566 );
1567 let err = VariantArray::try_new(&array);
1568 assert_eq!(
1569 err.unwrap_err().to_string(),
1570 "Invalid argument error: VariantArray 'value' field must be Binary, LargeBinary, or BinaryView, got Int32"
1571 );
1572 }
1573
1574 fn make_binary_view_array() -> ArrayRef {
1575 Arc::new(BinaryViewArray::from(vec![b"test" as &[u8]]))
1576 }
1577
1578 fn make_int32_array() -> ArrayRef {
1579 Arc::new(Int32Array::from(vec![1]))
1580 }
1581
1582 fn make_variant_struct_with_typed_value(typed_value: ArrayRef) -> StructArray {
1583 let metadata = BinaryViewArray::from_iter_values(std::iter::repeat_n(
1584 EMPTY_VARIANT_METADATA_BYTES,
1585 typed_value.len(),
1586 ));
1587 let value = new_null_array(&DataType::BinaryView, typed_value.len());
1588 StructArrayBuilder::new()
1589 .with_field("metadata", Arc::new(metadata), false)
1590 .with_field("value", value, true)
1591 .with_field("typed_value", typed_value, true)
1592 .build()
1593 }
1594
1595 #[test]
1596 fn try_new_tags_untagged_uuid_on_read() {
1597 let typed_value = FixedSizeBinaryArray::try_from_iter(std::iter::repeat_n([0u8; 16], 2));
1600 let input = make_variant_struct_with_typed_value(Arc::new(typed_value.unwrap()));
1601
1602 let variant_array = VariantArray::try_new(&input).unwrap();
1604 let typed_value = variant_array.inner().field_by_name("typed_value").unwrap();
1605 assert_eq!(typed_value.data_type(), &DataType::FixedSizeBinary(16));
1606 assert!(typed_value.has_valid_extension_type::<UuidExtension>());
1607 }
1608
1609 #[test]
1610 fn try_new_tags_untagged_nested_uuid_on_read() {
1611 let leaf = FixedSizeBinaryArray::try_from_iter(std::iter::repeat_n([0u8; 16], 1)).unwrap();
1614 let inner = StructArrayBuilder::new()
1615 .with_field("typed_value", Arc::new(leaf), true)
1616 .build();
1617 let object = StructArrayBuilder::new()
1618 .with_field("id", Arc::new(inner), false)
1619 .build();
1620 let input = make_variant_struct_with_typed_value(Arc::new(object));
1621
1622 let variant_array = VariantArray::try_new(&input).unwrap();
1624 let object = variant_array.typed_value_column().unwrap().as_struct();
1625 let id = object.column_by_name("id").unwrap().as_struct();
1626 let uuid_leaf = id.field_by_name("typed_value").unwrap();
1627 assert!(uuid_leaf.has_valid_extension_type::<UuidExtension>());
1628 }
1629
1630 #[test]
1631 fn all_null_value_column_is_valid_and_unshredded() {
1632 let metadata = BinaryViewArray::from(vec![b"test" as &[u8]; 3]);
1635 let value = new_null_array(&DataType::BinaryView, 3);
1636
1637 let fields = Fields::from(vec![
1638 Field::new("metadata", DataType::BinaryView, false),
1639 Field::new("value", DataType::BinaryView, true),
1640 ]);
1641 let struct_array = StructArray::new(fields, vec![Arc::new(metadata), value], None);
1642
1643 let variant_array = VariantArray::try_new(&struct_array).unwrap();
1644 assert!(variant_array.typed_value_column().is_none());
1645
1646 for i in 0..variant_array.len() {
1649 assert!(variant_array.is_valid(i));
1650 assert_eq!(variant_array.value(i), Variant::Null);
1651 }
1652 }
1653
1654 #[test]
1655 fn canonicalize_and_verify_list_like_data_types() {
1656 let make_item_binary = || Arc::new(Field::new("item", DataType::Binary, true));
1660 let make_large_binary = || Arc::new(Field::new("item", DataType::LargeBinary, true));
1661 let make_item_binary_view = || Arc::new(Field::new("item", DataType::BinaryView, true));
1662
1663 let cases = vec![
1664 DataType::LargeList(make_item_binary()),
1666 DataType::ListView(make_item_binary()),
1667 DataType::LargeListView(make_item_binary()),
1668 DataType::LargeList(make_large_binary()),
1670 DataType::ListView(make_large_binary()),
1671 DataType::LargeListView(make_large_binary()),
1672 DataType::LargeList(make_item_binary_view()),
1674 DataType::ListView(make_item_binary_view()),
1675 DataType::LargeListView(make_item_binary_view()),
1676 ];
1677
1678 for input in cases {
1679 assert_eq!(
1680 canonicalize_and_verify_data_type(&input).unwrap().as_ref(),
1681 &input
1682 );
1683 }
1684 }
1685
1686 #[test]
1687 fn variant_array_try_new_supports_list_like_typed_value() {
1688 let item_field = Arc::new(Field::new("item", DataType::Int64, true));
1689 let values: ArrayRef = Arc::new(Int64Array::from(vec![Some(1), None, Some(3)]));
1690
1691 let typed_values = vec![
1692 Arc::new(ListArray::new(
1693 item_field.clone(),
1694 OffsetBuffer::new(ScalarBuffer::from(vec![0, 2, 3])),
1695 values.clone(),
1696 None,
1697 )) as ArrayRef,
1698 Arc::new(LargeListArray::new(
1699 item_field.clone(),
1700 OffsetBuffer::new(ScalarBuffer::from(vec![0_i64, 2, 3])),
1701 values.clone(),
1702 None,
1703 )) as ArrayRef,
1704 Arc::new(ListViewArray::new(
1705 item_field.clone(),
1706 ScalarBuffer::from(vec![0, 2]),
1707 ScalarBuffer::from(vec![2, 1]),
1708 values.clone(),
1709 None,
1710 )) as ArrayRef,
1711 Arc::new(LargeListViewArray::new(
1712 item_field,
1713 ScalarBuffer::from(vec![0_i64, 2]),
1714 ScalarBuffer::from(vec![2_i64, 1]),
1715 values,
1716 None,
1717 )) as ArrayRef,
1718 ];
1719
1720 for typed_value in typed_values {
1721 let input = make_variant_struct_with_typed_value(typed_value.clone());
1722 let variant_array = VariantArray::try_new(&input).unwrap();
1723 assert_eq!(
1724 variant_array.typed_value_column().unwrap().data_type(),
1725 typed_value.data_type(),
1726 );
1727 }
1728 }
1729
1730 #[test]
1731 fn variant_array_try_new_normalizes_fixed_size_list_typed_value() {
1732 let element_values: ArrayRef =
1733 ShreddedVariantFieldArray::perfectly_shredded(Arc::new(Int64Array::from(vec![
1734 1, 2, 3, 4,
1735 ])))
1736 .into();
1737 let item_field = Arc::new(Field::new("item", element_values.data_type().clone(), true));
1738 let typed_value: ArrayRef = Arc::new(FixedSizeListArray::new(
1739 item_field.clone(),
1740 2,
1741 element_values,
1742 None,
1743 ));
1744 let input = make_variant_struct_with_typed_value(typed_value);
1745
1746 let variant_array = VariantArray::try_new(&input).unwrap();
1747 assert_eq!(
1748 variant_array.typed_value_column().unwrap().data_type(),
1749 &DataType::List(item_field),
1750 );
1751
1752 let unshredded = crate::unshred_variant(&variant_array).unwrap();
1753 assert!(unshredded.typed_value_column().is_none());
1754 assert_eq!(unshredded.len(), 2);
1755 }
1756
1757 #[test]
1758 fn test_try_value_out_of_bounds() {
1759 let mut b = VariantArrayBuilder::new(2);
1760 b.append_variant(Variant::from(1_i8));
1761 b.append_variant(Variant::Null);
1762 let v = b.build();
1763
1764 assert_eq!(v.try_value(0).unwrap(), Variant::Int8(1));
1765 assert_eq!(v.try_value(1).unwrap(), Variant::Null);
1766
1767 let err = v.try_value(2).unwrap_err();
1768 assert_eq!(
1769 err.to_string(),
1770 "Invalid argument error: Index 2 out of bounds for VariantArray of length 2"
1771 );
1772 }
1773
1774 #[test]
1775 fn test_variant_array_iterable() {
1776 let mut b = VariantArrayBuilder::new(6);
1777
1778 b.append_null();
1779 b.append_variant(Variant::from(1_i8));
1780 b.append_variant(Variant::Null);
1781 b.append_variant(Variant::from(2_i32));
1782 b.append_variant(Variant::from(3_i64));
1783 b.append_null();
1784
1785 let v = b.build();
1786
1787 let variants = v.iter().collect::<Vec<_>>();
1788
1789 assert_eq!(
1790 variants,
1791 vec![
1792 None,
1793 Some(Variant::Int8(1)),
1794 Some(Variant::Null),
1795 Some(Variant::Int32(2)),
1796 Some(Variant::Int64(3)),
1797 None,
1798 ]
1799 );
1800 }
1801
1802 #[test]
1803 fn test_variant_array_iter_double_ended() {
1804 let mut b = VariantArrayBuilder::new(5);
1805
1806 b.append_variant(Variant::from(0_i32));
1807 b.append_null();
1808 b.append_variant(Variant::from(2_i32));
1809 b.append_null();
1810 b.append_variant(Variant::from(4_i32));
1811
1812 let array = b.build();
1813 let mut iter = array.iter();
1814
1815 assert_eq!(iter.next(), Some(Some(Variant::from(0_i32))));
1816 assert_eq!(iter.next(), Some(None));
1817
1818 assert_eq!(iter.next_back(), Some(Some(Variant::from(4_i32))));
1819 assert_eq!(iter.next_back(), Some(None));
1820 assert_eq!(iter.next_back(), Some(Some(Variant::from(2_i32))));
1821
1822 assert_eq!(iter.next_back(), None);
1823 assert_eq!(iter.next(), None);
1824 }
1825
1826 #[test]
1827 fn test_variant_array_iter_reverse() {
1828 let mut b = VariantArrayBuilder::new(5);
1829
1830 b.append_variant(Variant::from("a"));
1831 b.append_null();
1832 b.append_variant(Variant::from("aaa"));
1833 b.append_null();
1834 b.append_variant(Variant::from("aaaaa"));
1835
1836 let array = b.build();
1837
1838 let result: Vec<_> = array.iter().rev().collect();
1839 assert_eq!(
1840 result,
1841 vec![
1842 Some(Variant::from("aaaaa")),
1843 None,
1844 Some(Variant::from("aaa")),
1845 None,
1846 Some(Variant::from("a")),
1847 ]
1848 );
1849 }
1850
1851 #[test]
1852 fn test_variant_array_iter_empty() {
1853 let v = VariantArrayBuilder::new(0).build();
1854 let mut i = v.iter();
1855 assert!(i.next().is_none());
1856 assert!(i.next_back().is_none());
1857 }
1858
1859 #[test]
1860 fn test_from_variant_opts_into_variant_array() {
1861 let v = vec![None, Some(Variant::Null), Some(Variant::BooleanFalse), None];
1862
1863 let variant_array = VariantArray::from_iter(v);
1864
1865 assert_eq!(variant_array.len(), 4);
1866
1867 assert!(variant_array.is_null(0));
1868
1869 assert!(!variant_array.is_null(1));
1870 assert_eq!(variant_array.value(1), Variant::Null);
1871
1872 assert!(!variant_array.is_null(2));
1873 assert_eq!(variant_array.value(2), Variant::BooleanFalse);
1874
1875 assert!(variant_array.is_null(3));
1876 }
1877
1878 #[test]
1879 fn test_from_variants_into_variant_array() {
1880 let v = vec![
1881 Variant::Null,
1882 Variant::BooleanFalse,
1883 Variant::ShortString(ShortString::try_new("norm").unwrap()),
1884 ];
1885
1886 let variant_array = VariantArray::from_iter(v);
1887
1888 assert_eq!(variant_array.len(), 3);
1889
1890 assert!(!variant_array.is_null(0));
1891 assert_eq!(variant_array.value(0), Variant::Null);
1892
1893 assert!(!variant_array.is_null(1));
1894 assert_eq!(variant_array.value(1), Variant::BooleanFalse);
1895
1896 assert!(!variant_array.is_null(2));
1897 assert_eq!(
1898 variant_array.value(2),
1899 Variant::ShortString(ShortString::try_new("norm").unwrap())
1900 );
1901 }
1902
1903 #[test]
1904 fn test_variant_equality() {
1905 let v_iter = [None, Some(Variant::BooleanFalse), Some(Variant::Null), None];
1906 let v = VariantArray::from_iter(v_iter.clone());
1907
1908 {
1909 let v_copy = v.clone();
1910 assert_eq!(v, v_copy);
1911 }
1912
1913 {
1914 let v_iter_reversed = v_iter.iter().cloned().rev();
1915 let v_reversed = VariantArray::from_iter(v_iter_reversed);
1916
1917 assert_ne!(v, v_reversed);
1918 }
1919
1920 {
1921 let v_sliced = v.slice(0, 1);
1922 assert_ne!(v, v_sliced);
1923 }
1924 }
1925
1926 #[test]
1927 fn binary_typed_value_roundtrips() {
1928 let typed_value: ArrayRef = Arc::new(BinaryArray::from(vec![b"hello" as &[u8]]));
1930 let struct_array = make_variant_struct_with_typed_value(typed_value);
1931
1932 let variant_array = VariantArray::try_new(&struct_array).unwrap();
1933 assert_eq!(variant_array.value(0), Variant::from(b"hello" as &[u8]));
1934 }
1935
1936 #[test]
1937 fn large_binary_typed_value_roundtrips() {
1938 let typed_value: ArrayRef = Arc::new(LargeBinaryArray::from(vec![b"world" as &[u8]]));
1940 let struct_array = make_variant_struct_with_typed_value(typed_value);
1941
1942 let variant_array = VariantArray::try_new(&struct_array).unwrap();
1943 assert_eq!(variant_array.value(0), Variant::from(b"world" as &[u8]));
1944 }
1945
1946 macro_rules! invalid_variant_array_test {
1947 ($fn_name: ident, $invalid_typed_value: expr, $error_msg: literal) => {
1948 #[test]
1949 fn $fn_name() {
1950 let invalid_typed_value = $invalid_typed_value;
1951
1952 let struct_array =
1953 make_variant_struct_with_typed_value(Arc::new(invalid_typed_value));
1954
1955 let array: VariantArray = VariantArray::try_new(&struct_array)
1956 .expect("should create variant array")
1957 .into();
1958
1959 let result = array.try_value(0);
1960 assert!(result.is_err());
1961 let error = result.unwrap_err();
1962 assert!(matches!(error, ArrowError::CastError(_)));
1963
1964 let expected: &str = $error_msg;
1965 assert!(
1966 error.to_string().contains($error_msg),
1967 "error `{}` did not contain `{}`",
1968 error,
1969 expected
1970 )
1971 }
1972 };
1973 }
1974
1975 invalid_variant_array_test!(
1976 test_variant_array_invalid_time,
1977 Time64MicrosecondArray::from(vec![Some(86401000000)]),
1978 "Cast error: Cast failed at index 0 (array type: Time64(µs)): Invalid microsecond from midnight: 86401000000"
1979 );
1980
1981 invalid_variant_array_test!(
1982 test_variant_array_invalid_decimal32,
1983 Decimal32Array::from(vec![Some(1234567890)]),
1984 "Cast error: Cast failed at index 0 (array type: Decimal32(9, 2)): Invalid argument error: 1234567890 is wider than max precision 9"
1985 );
1986
1987 invalid_variant_array_test!(
1988 test_variant_array_invalid_decimal64,
1989 Decimal64Array::from(vec![Some(1234567890123456789)]),
1990 "Cast error: Cast failed at index 0 (array type: Decimal64(18, 6)): Invalid argument error: 1234567890123456789 is wider than max precision 18"
1991 );
1992
1993 invalid_variant_array_test!(
1994 test_variant_array_invalid_decimal128,
1995 Decimal128Array::from(vec![Some(
1996 i128::from_str("123456789012345678901234567890123456789").unwrap()
1997 ),]),
1998 "Cast error: Cast failed at index 0 (array type: Decimal128(38, 10)): Invalid argument error: 123456789012345678901234567890123456789 is wider than max precision 38"
1999 );
2000 #[test]
2001 fn try_value_errors_on_unimplemented_typed_value_type() {
2002 use crate::{json_to_variant, shred_variant};
2003 use arrow::array::StringArray;
2004
2005 let json: ArrayRef = Arc::new(StringArray::from(vec![r#"{"qty": 3}"#]));
2006 let variant = json_to_variant(&json).unwrap();
2007 let shred_type = DataType::Struct(vec![Field::new("qty", DataType::Int64, true)].into());
2008 let shredded = shred_variant(&variant, &shred_type).unwrap();
2009 let err = shredded.try_value(0).unwrap_err();
2013 assert!(
2014 err.to_string().starts_with(
2015 "Not yet implemented: VariantArray::try_value cannot materialize typed_value"
2016 ),
2017 "unexpected error: {err}"
2018 );
2019 }
2020}