1use crate::VariantArrayBuilder;
8use crate::type_conversion::{
9 generic_conversion_single_value, generic_conversion_single_value_with_result,
10 primitive_conversion_single_value,
11};
12use arrow::array::{
13 Array, ArrayRef, AsArray, StructArray, StructArrayAssembler, downcast_dictionary_array,
14 downcast_run_array, new_null_array,
15};
16use arrow::buffer::NullBuffer;
17use arrow::compute::cast;
18use arrow::datatypes::{
19 Date32Type, Decimal32Type, Decimal64Type, Decimal128Type, Float16Type, Float32Type,
20 Float64Type, Int8Type, Int16Type, Int32Type, Int64Type, Time64MicrosecondType,
21 TimestampMicrosecondType, TimestampNanosecondType,
22};
23use arrow::error::Result;
24use arrow_schema::extension::Uuid as UuidExtension;
25use arrow_schema::{ArrowError, DataType, Field, FieldRef, TimeUnit};
26use chrono::{DateTime, NaiveTime};
27use parquet_variant::{
28 Uuid, Variant, VariantDecimal4, VariantDecimal8, VariantDecimal16, VariantDecimalType as _,
29 VariantType,
30};
31
32use std::borrow::Cow;
33use std::sync::Arc;
34
35pub(crate) fn binary_array_value(array: &dyn Array, index: usize) -> Option<&[u8]> {
38 if array.is_null(index) {
39 return None;
40 }
41 match array.data_type() {
42 DataType::Binary => Some(array.as_binary::<i32>().value(index)),
43 DataType::LargeBinary => Some(array.as_binary::<i64>().value(index)),
44 DataType::BinaryView => Some(array.as_binary_view().value(index)),
45 DataType::Dictionary(..) => downcast_dictionary_array! {
46 array => {
47 let index = array.key(index)?;
48 binary_array_value(array.values().as_ref(), index)
49 },
50 _ => unreachable!(),
51 },
52 DataType::RunEndEncoded(..) => downcast_run_array! {
53 array => {
54 let index = array.get_physical_index(index);
55 binary_array_value(array.values().as_ref(), index)
56 },
57 _ => unreachable!(),
58 },
59 _ => None,
60 }
61}
62
63pub(crate) fn variant_from_arrays_at<'m, 'v>(
66 metadata: &'m dyn Array,
67 value: &'v dyn Array,
68 index: usize,
69) -> Option<Variant<'m, 'v>> {
70 let metadata = binary_array_value(metadata, index)?;
71 let value = binary_array_value(value, index)?;
72 Some(Variant::new(metadata, value))
73}
74
75pub(crate) fn all_null_value_column(len: usize) -> ArrayRef {
81 new_null_array(&DataType::BinaryView, len)
82}
83
84pub(crate) fn validate_binary_array(array: &dyn Array, field_name: &str) -> Result<()> {
86 match array.data_type() {
87 DataType::Binary | DataType::LargeBinary | DataType::BinaryView => Ok(()),
88 _ => Err(ArrowError::InvalidArgumentError(format!(
89 "VariantArray '{field_name}' field must be Binary, LargeBinary, or BinaryView, got {}",
90 array.data_type()
91 ))),
92 }
93}
94
95fn validate_metadata_array(array: &dyn Array) -> Result<()> {
97 let is_binary = |data_type: &DataType| {
98 matches!(
99 data_type,
100 DataType::Binary | DataType::LargeBinary | DataType::BinaryView
101 )
102 };
103 match array.data_type() {
104 data_type if is_binary(data_type) => Ok(()),
105 DataType::Dictionary(_, values) if is_binary(values) => Ok(()),
106 DataType::RunEndEncoded(_, values) if is_binary(values.data_type()) => Ok(()),
107 _ => Err(ArrowError::InvalidArgumentError(format!(
108 "VariantArray 'metadata' field must be Binary, LargeBinary, BinaryView, or a Dictionary or RunEndEncoded array of one of those types, got {}",
109 array.data_type()
110 ))),
111 }
112}
113
114#[derive(Debug, Clone)]
256pub struct VariantArray {
257 inner: StructArray,
259
260 metadata: ArrayRef,
262
263 shredding_state: ShreddingState,
265}
266
267impl VariantArray {
268 pub fn try_new(inner: &dyn Array) -> Result<Self> {
292 let inner = canonicalize_shredded_types(inner)?;
294
295 let Some(inner) = inner.as_struct_opt() else {
296 return Err(ArrowError::InvalidArgumentError(
297 "Invalid VariantArray: requires StructArray as input".to_string(),
298 ));
299 };
300
301 let Some(metadata_col) = inner.column_by_name("metadata") else {
305 return Err(ArrowError::InvalidArgumentError(
306 "Invalid VariantArray: StructArray must contain a 'metadata' field".to_string(),
307 ));
308 };
309 validate_metadata_array(metadata_col.as_ref())?;
310
311 let shredding_state = ShreddingState::try_from(inner)?;
312
313 if inner.column_by_name("value").is_none() {
316 return Ok(Self::from_parts(
317 metadata_col.clone(),
318 shredding_state.value_column().clone(),
319 shredding_state.typed_value_column().cloned(),
320 inner.nulls().cloned(),
321 ));
322 }
323
324 Ok(Self {
326 inner: inner.clone(),
327 metadata: metadata_col.clone(),
328 shredding_state,
329 })
330 }
331
332 pub(crate) fn from_parts(
337 metadata: ArrayRef,
338 value: ArrayRef,
339 typed_value: Option<ArrayRef>,
340 nulls: Option<NullBuffer>,
341 ) -> Self {
342 Self::from_parts_with_nullable_value(metadata, value, typed_value, nulls, true)
343 }
344
345 pub(crate) fn from_parts_unshredded(
351 metadata: ArrayRef,
352 value: ArrayRef,
353 nulls: Option<NullBuffer>,
354 ) -> Self {
355 Self::from_parts_with_nullable_value(metadata, value, None, nulls, false)
356 }
357
358 fn from_parts_with_nullable_value(
359 metadata: ArrayRef,
360 value: ArrayRef,
361 typed_value: Option<ArrayRef>,
362 nulls: Option<NullBuffer>,
363 value_nullable: bool,
364 ) -> Self {
365 let mut builder = StructArrayAssembler::new()
366 .with_field("metadata", metadata.clone(), false)
367 .with_field("value", value.clone(), value_nullable);
368 if let Some(typed_value) = typed_value.clone() {
369 builder = builder.with_field_ref(typed_value_field(&typed_value), typed_value);
370 }
371 if let Some(nulls) = nulls {
372 builder = builder.with_nulls(nulls);
373 }
374
375 Self {
376 inner: builder.build().unwrap(),
377 metadata,
378 shredding_state: ShreddingState::new(value, typed_value),
379 }
380 }
381
382 pub fn inner(&self) -> &StructArray {
384 &self.inner
385 }
386
387 pub fn into_inner(self) -> StructArray {
389 self.inner
390 }
391
392 pub fn shredding_state(&self) -> &ShreddingState {
394 &self.shredding_state
395 }
396
397 pub fn value(&self, index: usize) -> Variant<'_, '_> {
408 self.try_value(index)
409 .unwrap_or_else(|err| panic!("VariantArray::value({index}) failed: {err}"))
410 }
411
412 pub fn try_value(&self, index: usize) -> Result<Variant<'_, '_>> {
441 if self.len() <= index {
442 return Err(ArrowError::InvalidArgumentError(format!(
443 "Index {index} out of bounds for VariantArray of length {}",
444 self.len()
445 )));
446 }
447
448 let value = self.value_column();
449 match self.typed_value_column() {
450 Some(typed_value) if typed_value.is_valid(index) => {
452 if !matches!(typed_value.data_type(), DataType::Struct(_)) && value.is_valid(index) {
453 return Err(ArrowError::InvalidArgumentError(
455 "Invalid variant, conflicting value and typed_value".to_owned(),
456 ));
457 }
458 typed_value_to_variant(typed_value, index)
459 }
460 _ if value.is_valid(index) => variant_from_arrays_at(&self.metadata, value, index)
462 .ok_or_else(|| {
463 ArrowError::InvalidArgumentError(format!(
464 "metadata and value fields must be binary-like arrays, instead got {} and {}",
465 self.metadata.data_type(),
466 value.data_type()
467 ))
468 }),
469 _ => Ok(Variant::Null),
472 }
473 }
474
475 pub fn metadata_column(&self) -> &ArrayRef {
477 &self.metadata
478 }
479
480 pub fn value_column(&self) -> &ArrayRef {
482 self.shredding_state.value_column()
483 }
484
485 pub fn typed_value_column(&self) -> Option<&ArrayRef> {
487 self.shredding_state.typed_value_column()
488 }
489
490 pub fn field(&self, name: impl Into<String>) -> Field {
493 Field::new(
494 name.into(),
495 self.data_type().clone(),
496 self.inner.is_nullable(),
497 )
498 .with_extension_type(VariantType)
499 }
500
501 pub fn data_type(&self) -> &DataType {
503 self.inner.data_type()
504 }
505
506 pub fn slice(&self, offset: usize, length: usize) -> Self {
507 let inner = self.inner.slice(offset, length);
508 let metadata = self.metadata.slice(offset, length);
509 let shredding_state = self.shredding_state.slice(offset, length);
510 Self {
511 inner,
512 metadata,
513 shredding_state,
514 }
515 }
516
517 pub fn len(&self) -> usize {
518 self.inner.len()
519 }
520
521 pub fn is_empty(&self) -> bool {
522 self.inner.is_empty()
523 }
524
525 pub fn nulls(&self) -> Option<&NullBuffer> {
526 self.inner.nulls()
527 }
528
529 pub fn is_null(&self, index: usize) -> bool {
531 self.nulls().is_some_and(|n| n.is_null(index))
532 }
533
534 pub fn is_valid(&self, index: usize) -> bool {
536 !self.is_null(index)
537 }
538
539 pub fn iter(&self) -> VariantArrayIter<'_> {
541 VariantArrayIter::new(self)
542 }
543}
544
545impl<'a> IntoIterator for &'a VariantArray {
546 type Item = Option<Variant<'a, 'a>>;
547 type IntoIter = VariantArrayIter<'a>;
548
549 fn into_iter(self) -> Self::IntoIter {
550 VariantArrayIter::new(self)
551 }
552}
553
554impl PartialEq for VariantArray {
555 fn eq(&self, other: &Self) -> bool {
556 self.inner == other.inner
557 }
558}
559
560impl From<VariantArray> for StructArray {
561 fn from(variant_array: VariantArray) -> Self {
562 variant_array.into_inner()
563 }
564}
565
566impl From<VariantArray> for ArrayRef {
567 fn from(variant_array: VariantArray) -> Self {
568 Arc::new(variant_array.into_inner())
569 }
570}
571
572impl<'m, 'v, V: Into<Variant<'m, 'v>>> FromIterator<Option<V>> for VariantArray {
573 fn from_iter<T: IntoIterator<Item = Option<V>>>(iter: T) -> Self {
574 let iter = iter.into_iter().map(|value| value.map(Into::into));
575
576 let mut b = VariantArrayBuilder::new(iter.size_hint().0);
577 b.extend(iter);
578 b.build()
579 }
580}
581
582impl<'m, 'v> FromIterator<Variant<'m, 'v>> for VariantArray {
583 fn from_iter<T: IntoIterator<Item = Variant<'m, 'v>>>(iter: T) -> Self {
584 Self::from_iter(iter.into_iter().map(Some))
585 }
586}
587
588#[derive(Debug)]
613pub struct VariantArrayIter<'a> {
614 array: &'a VariantArray,
615 head_i: usize,
616 tail_i: usize,
617}
618
619impl<'a> VariantArrayIter<'a> {
620 pub fn new(array: &'a VariantArray) -> Self {
622 Self {
623 array,
624 head_i: 0,
625 tail_i: array.len(),
626 }
627 }
628
629 fn value_opt(&self, i: usize) -> Option<Variant<'a, 'a>> {
630 self.array.is_valid(i).then(|| self.array.value(i))
631 }
632}
633
634impl<'a> Iterator for VariantArrayIter<'a> {
635 type Item = Option<Variant<'a, 'a>>;
636
637 #[inline]
638 fn next(&mut self) -> Option<Self::Item> {
639 if self.head_i == self.tail_i {
640 return None;
641 }
642
643 let out = self.value_opt(self.head_i);
644
645 self.head_i += 1;
646
647 Some(out)
648 }
649
650 fn size_hint(&self) -> (usize, Option<usize>) {
651 let remainder = self.tail_i - self.head_i;
652
653 (remainder, Some(remainder))
654 }
655}
656
657impl DoubleEndedIterator for VariantArrayIter<'_> {
658 fn next_back(&mut self) -> Option<Self::Item> {
659 if self.head_i == self.tail_i {
660 return None;
661 }
662
663 self.tail_i -= 1;
664
665 Some(self.value_opt(self.tail_i))
666 }
667}
668
669impl ExactSizeIterator for VariantArrayIter<'_> {}
670
671#[derive(Debug)]
706pub struct ShreddedVariantFieldArray {
707 inner: StructArray,
709 shredding_state: ShreddingState,
710}
711
712impl ShreddedVariantFieldArray {
713 pub fn try_new(inner: &dyn Array) -> Result<Self> {
733 let Some(inner_struct) = inner.as_struct_opt() else {
734 return Err(ArrowError::InvalidArgumentError(
735 "Invalid ShreddedVariantFieldArray: requires StructArray as input".to_string(),
736 ));
737 };
738
739 let shredding_state = ShreddingState::try_from(inner_struct)?;
740
741 if inner_struct.column_by_name("value").is_none() {
744 return Ok(Self::from_parts(
745 shredding_state.value_column().clone(),
746 shredding_state.typed_value_column().cloned(),
747 inner_struct.nulls().cloned(),
748 ));
749 }
750
751 Ok(Self {
753 inner: inner_struct.clone(),
754 shredding_state,
755 })
756 }
757
758 pub fn shredding_state(&self) -> &ShreddingState {
760 &self.shredding_state
761 }
762
763 pub fn value_column(&self) -> &ArrayRef {
765 self.shredding_state.value_column()
766 }
767
768 pub fn typed_value_column(&self) -> Option<&ArrayRef> {
770 self.shredding_state.typed_value_column()
771 }
772
773 pub fn inner(&self) -> &StructArray {
775 &self.inner
776 }
777
778 pub(crate) fn from_parts(
779 value: ArrayRef,
780 typed_value: Option<ArrayRef>,
781 nulls: Option<NullBuffer>,
782 ) -> Self {
783 let mut builder = StructArrayAssembler::new().with_field("value", value.clone(), true);
784 if let Some(typed_value) = typed_value.clone() {
785 builder = builder.with_field_ref(typed_value_field(&typed_value), typed_value);
786 }
787 if let Some(nulls) = nulls {
788 builder = builder.with_nulls(nulls);
789 }
790
791 Self {
792 inner: builder.build().unwrap(),
793 shredding_state: ShreddingState::new(value, typed_value),
794 }
795 }
796
797 pub fn into_inner(self) -> StructArray {
799 self.inner
800 }
801
802 pub fn data_type(&self) -> &DataType {
803 self.inner.data_type()
804 }
805
806 pub fn len(&self) -> usize {
807 self.inner.len()
808 }
809
810 pub fn is_empty(&self) -> bool {
811 self.inner.is_empty()
812 }
813
814 pub fn offset(&self) -> usize {
815 self.inner.offset()
816 }
817
818 pub fn nulls(&self) -> Option<&NullBuffer> {
819 None
823 }
824 pub fn is_null(&self, index: usize) -> bool {
826 self.nulls().is_some_and(|n| n.is_null(index))
827 }
828
829 pub fn is_valid(&self, index: usize) -> bool {
831 !self.is_null(index)
832 }
833}
834
835impl From<ShreddedVariantFieldArray> for ArrayRef {
836 fn from(array: ShreddedVariantFieldArray) -> Self {
837 Arc::new(array.into_inner())
838 }
839}
840
841impl From<ShreddedVariantFieldArray> for StructArray {
842 fn from(array: ShreddedVariantFieldArray) -> Self {
843 array.into_inner()
844 }
845}
846
847#[derive(Debug, Clone)]
884pub struct ShreddingState {
885 value: ArrayRef,
886 typed_value: Option<ArrayRef>,
887}
888
889impl ShreddingState {
890 pub fn new(value: ArrayRef, typed_value: Option<ArrayRef>) -> Self {
905 Self { value, typed_value }
906 }
907
908 pub fn value_column(&self) -> &ArrayRef {
910 &self.value
911 }
912
913 pub fn typed_value_column(&self) -> Option<&ArrayRef> {
915 self.typed_value.as_ref()
916 }
917
918 pub fn slice(&self, offset: usize, length: usize) -> Self {
920 Self {
921 value: self.value.slice(offset, length),
922 typed_value: self.typed_value.as_ref().map(|tv| tv.slice(offset, length)),
923 }
924 }
925}
926
927impl TryFrom<&StructArray> for ShreddingState {
928 type Error = ArrowError;
929
930 fn try_from(inner_struct: &StructArray) -> Result<Self> {
931 let typed_value = inner_struct.column_by_name("typed_value").cloned();
932 let value = match inner_struct.column_by_name("value") {
933 Some(value) => {
934 validate_binary_array(value.as_ref(), "value")?;
935 value.clone()
936 }
937 None if typed_value.is_some() => all_null_value_column(inner_struct.len()),
940 None => {
941 return Err(ArrowError::InvalidArgumentError(
942 "Invalid VariantArray: StructArray must contain a 'value' field".to_string(),
943 ));
944 }
945 };
946 Ok(ShreddingState::new(value, typed_value))
947 }
948}
949
950fn typed_value_field(array: &ArrayRef) -> FieldRef {
956 let mut field = Field::new("typed_value", array.data_type().clone(), true);
957 if matches!(array.data_type(), DataType::FixedSizeBinary(16)) {
958 field = field.with_extension_type(UuidExtension);
959 }
960 Arc::new(field)
961}
962
963fn typed_value_to_variant(typed_value: &ArrayRef, index: usize) -> Result<Variant<'_, '_>> {
965 let data_type = typed_value.data_type();
966 match data_type {
967 DataType::Null => Ok(Variant::Null),
968 DataType::Boolean => {
969 let boolean_array = typed_value.as_boolean();
970 let value = boolean_array.value(index);
971 Ok(Variant::from(value))
972 }
973 DataType::FixedSizeBinary(16) => {
975 let array = typed_value.as_fixed_size_binary();
976 let value = array.value(index);
977 Ok(Uuid::from_slice(value).unwrap().into()) }
979 DataType::Binary => {
980 let array = typed_value.as_binary::<i32>();
981 let value = array.value(index);
982 Ok(Variant::from(value))
983 }
984 DataType::LargeBinary => {
985 let array = typed_value.as_binary::<i64>();
986 let value = array.value(index);
987 Ok(Variant::from(value))
988 }
989 DataType::BinaryView => {
990 let array = typed_value.as_binary_view();
991 let value = array.value(index);
992 Ok(Variant::from(value))
993 }
994 DataType::Utf8 => {
995 let array = typed_value.as_string::<i32>();
996 let value = array.value(index);
997 Ok(Variant::from(value))
998 }
999 DataType::LargeUtf8 => {
1000 let array = typed_value.as_string::<i64>();
1001 let value = array.value(index);
1002 Ok(Variant::from(value))
1003 }
1004 DataType::Utf8View => {
1005 let array = typed_value.as_string_view();
1006 let value = array.value(index);
1007 Ok(Variant::from(value))
1008 }
1009 DataType::Int8 => {
1010 primitive_conversion_single_value!(Int8Type, typed_value, index)
1011 }
1012 DataType::Int16 => {
1013 primitive_conversion_single_value!(Int16Type, typed_value, index)
1014 }
1015 DataType::Int32 => {
1016 primitive_conversion_single_value!(Int32Type, typed_value, index)
1017 }
1018 DataType::Int64 => {
1019 primitive_conversion_single_value!(Int64Type, typed_value, index)
1020 }
1021 DataType::Float16 => {
1022 primitive_conversion_single_value!(Float16Type, typed_value, index)
1023 }
1024 DataType::Float32 => {
1025 primitive_conversion_single_value!(Float32Type, typed_value, index)
1026 }
1027 DataType::Float64 => {
1028 primitive_conversion_single_value!(Float64Type, typed_value, index)
1029 }
1030 DataType::Decimal32(_, s) => {
1031 generic_conversion_single_value_with_result!(
1032 Decimal32Type,
1033 as_primitive,
1034 |v| VariantDecimal4::try_new(v, *s as u8),
1035 typed_value,
1036 index
1037 )
1038 }
1039 DataType::Decimal64(_, s) => {
1040 generic_conversion_single_value_with_result!(
1041 Decimal64Type,
1042 as_primitive,
1043 |v| VariantDecimal8::try_new(v, *s as u8),
1044 typed_value,
1045 index
1046 )
1047 }
1048 DataType::Decimal128(_, s) => {
1049 generic_conversion_single_value_with_result!(
1050 Decimal128Type,
1051 as_primitive,
1052 |v| VariantDecimal16::try_new(v, *s as u8),
1053 typed_value,
1054 index
1055 )
1056 }
1057 DataType::Date32 => {
1058 generic_conversion_single_value!(
1059 Date32Type,
1060 as_primitive,
1061 |v| Date32Type::to_naive_date_opt(v).unwrap(),
1062 typed_value,
1063 index
1064 )
1065 }
1066 DataType::Time64(TimeUnit::Microsecond) => {
1067 generic_conversion_single_value_with_result!(
1068 Time64MicrosecondType,
1069 as_primitive,
1070 |v| NaiveTime::from_num_seconds_from_midnight_opt(
1071 (v / 1_000_000) as u32,
1072 (v % 1_000_000) as u32 * 1000
1073 )
1074 .ok_or_else(|| format!("Invalid microsecond from midnight: {v}")),
1075 typed_value,
1076 index
1077 )
1078 }
1079 DataType::Timestamp(TimeUnit::Microsecond, Some(_)) => {
1080 generic_conversion_single_value!(
1081 TimestampMicrosecondType,
1082 as_primitive,
1083 |v| DateTime::from_timestamp_micros(v).unwrap(),
1084 typed_value,
1085 index
1086 )
1087 }
1088 DataType::Timestamp(TimeUnit::Microsecond, None) => {
1089 generic_conversion_single_value!(
1090 TimestampMicrosecondType,
1091 as_primitive,
1092 |v| DateTime::from_timestamp_micros(v).unwrap().naive_utc(),
1093 typed_value,
1094 index
1095 )
1096 }
1097 DataType::Timestamp(TimeUnit::Nanosecond, Some(_)) => {
1098 generic_conversion_single_value!(
1099 TimestampNanosecondType,
1100 as_primitive,
1101 DateTime::from_timestamp_nanos,
1102 typed_value,
1103 index
1104 )
1105 }
1106 DataType::Timestamp(TimeUnit::Nanosecond, None) => {
1107 generic_conversion_single_value!(
1108 TimestampNanosecondType,
1109 as_primitive,
1110 |v| DateTime::from_timestamp_nanos(v).naive_utc(),
1111 typed_value,
1112 index
1113 )
1114 }
1115 _ => Err(ArrowError::NotYetImplemented(format!(
1122 "VariantArray::try_value cannot materialize typed_value of type {} \
1123 as a borrowed Variant; call unshred_variant first",
1124 typed_value.data_type()
1125 ))),
1126 }
1127}
1128
1129fn canonicalize_shredded_types(array: &dyn Array) -> Result<ArrayRef> {
1132 let new_type = canonicalize_and_verify_data_type_impl(array.data_type(), true)?;
1133 if let Cow::Borrowed(_) = new_type
1134 && let Some(array) = array.as_struct_opt()
1135 {
1136 return Ok(Arc::new(array.clone())); }
1138 cast(array, new_type.as_ref())
1139}
1140
1141fn canonicalize_and_verify_data_type(data_type: &DataType) -> Result<Cow<'_, DataType>> {
1145 canonicalize_and_verify_data_type_impl(data_type, false)
1146}
1147
1148fn canonicalize_and_verify_data_type_impl(
1149 data_type: &DataType,
1150 skip_top_level_metadata: bool,
1151) -> Result<Cow<'_, DataType>> {
1152 use DataType::*;
1153
1154 macro_rules! fail {
1156 () => {
1157 return Err(ArrowError::InvalidArgumentError(format!(
1158 "Illegal shredded value type: {data_type}"
1159 )))
1160 };
1161 }
1162 macro_rules! borrow {
1163 () => {
1164 Cow::Borrowed(data_type)
1165 };
1166 }
1167
1168 let new_data_type = match data_type {
1169 Null | Boolean => borrow!(),
1171 Int8 | Int16 | Int32 | Int64 | Float32 | Float64 => borrow!(),
1172
1173 UInt8 | UInt16 | UInt32 | UInt64 | Float16 => fail!(),
1175
1176 Decimal64(p, s) | Decimal128(p, s)
1181 if VariantDecimal4::is_valid_precision_and_scale(p, s) =>
1182 {
1183 Cow::Owned(Decimal32(*p, *s))
1184 }
1185 Decimal128(p, s) if VariantDecimal8::is_valid_precision_and_scale(p, s) => {
1186 Cow::Owned(Decimal64(*p, *s))
1187 }
1188 Decimal32(p, s) if VariantDecimal4::is_valid_precision_and_scale(p, s) => borrow!(),
1189 Decimal64(p, s) if VariantDecimal8::is_valid_precision_and_scale(p, s) => borrow!(),
1190 Decimal128(p, s) if VariantDecimal16::is_valid_precision_and_scale(p, s) => borrow!(),
1191 Decimal32(..) | Decimal64(..) | Decimal128(..) | Decimal256(..) => fail!(),
1192
1193 Timestamp(TimeUnit::Microsecond | TimeUnit::Nanosecond, _) => borrow!(),
1195 Timestamp(TimeUnit::Millisecond | TimeUnit::Second, _) => fail!(),
1196
1197 Date32 | Time64(TimeUnit::Microsecond) => borrow!(),
1199 Date64 | Time32(_) | Time64(_) | Duration(_) | Interval(_) => fail!(),
1200
1201 Binary | LargeBinary | BinaryView | Utf8 | LargeUtf8 | Utf8View => borrow!(),
1203
1204 FixedSizeBinary(16) => borrow!(),
1206 FixedSizeBinary(_) => fail!(),
1207
1208 FixedSizeList(field, _) => match canonicalize_and_verify_field(field)? {
1212 Cow::Borrowed(_) => Cow::Owned(DataType::List(field.clone())),
1213 Cow::Owned(new_field) => Cow::Owned(DataType::List(new_field)),
1214 },
1215
1216 List(field) => match canonicalize_and_verify_field(field)? {
1218 Cow::Borrowed(_) => borrow!(),
1219 Cow::Owned(new_field) => Cow::Owned(DataType::List(new_field)),
1220 },
1221 LargeList(field) => match canonicalize_and_verify_field(field)? {
1222 Cow::Borrowed(_) => borrow!(),
1223 Cow::Owned(new_field) => Cow::Owned(DataType::LargeList(new_field)),
1224 },
1225 ListView(field) => match canonicalize_and_verify_field(field)? {
1226 Cow::Borrowed(_) => borrow!(),
1227 Cow::Owned(new_field) => Cow::Owned(DataType::ListView(new_field)),
1228 },
1229 LargeListView(field) => match canonicalize_and_verify_field(field)? {
1230 Cow::Borrowed(_) => borrow!(),
1231 Cow::Owned(new_field) => Cow::Owned(DataType::LargeListView(new_field)),
1232 },
1233 Struct(fields) => {
1235 let mut new_fields = std::collections::HashMap::new();
1238 for (i, field) in fields.iter().enumerate() {
1239 if skip_top_level_metadata && field.name() == "metadata" {
1240 continue;
1241 }
1242 if let Cow::Owned(new_field) = canonicalize_and_verify_field(field)? {
1243 new_fields.insert(i, new_field);
1244 }
1245 }
1246
1247 if new_fields.is_empty() {
1248 borrow!()
1249 } else {
1250 let new_fields = fields
1251 .iter()
1252 .enumerate()
1253 .map(|(i, field)| new_fields.remove(&i).unwrap_or_else(|| field.clone()));
1254 Cow::Owned(DataType::Struct(new_fields.collect()))
1255 }
1256 }
1257 Map(..) | Union(..) => fail!(),
1258
1259 Dictionary(..) | RunEndEncoded(..) => fail!(),
1261 };
1262 Ok(new_data_type)
1263}
1264
1265fn canonicalize_and_verify_field(field: &Arc<Field>) -> Result<Cow<'_, Arc<Field>>> {
1266 let new_data_type = canonicalize_and_verify_data_type(field.data_type())?;
1267
1268 if matches!(new_data_type.as_ref(), DataType::FixedSizeBinary(16))
1272 && !field.has_valid_extension_type::<UuidExtension>()
1273 {
1274 let new_field = field.as_ref().clone().with_extension_type(UuidExtension);
1275 return Ok(Cow::Owned(Arc::new(new_field)));
1276 }
1277
1278 let Cow::Owned(new_data_type) = new_data_type else {
1279 return Ok(Cow::Borrowed(field));
1280 };
1281 let new_field = field.as_ref().clone().with_data_type(new_data_type);
1282 Ok(Cow::Owned(Arc::new(new_field)))
1283}
1284
1285#[cfg(test)]
1288impl VariantArray {
1289 pub(crate) fn perfectly_shredded(
1290 metadata: ArrayRef,
1291 typed_value: ArrayRef,
1292 nulls: Option<NullBuffer>,
1293 ) -> Self {
1294 let value = all_null_value_column(typed_value.len());
1295 Self::from_parts(metadata, value, Some(typed_value), nulls)
1296 }
1297}
1298
1299#[cfg(test)]
1300impl ShreddedVariantFieldArray {
1301 pub(crate) fn perfectly_shredded(typed_value: ArrayRef) -> Self {
1302 let value = all_null_value_column(typed_value.len());
1303 Self::from_parts(value, Some(typed_value), None)
1304 }
1305}
1306
1307#[cfg(test)]
1308mod test {
1309 use crate::{GetOptions, VariantArrayBuilder, json_to_variant, variant_get, variant_to_json};
1310 use std::str::FromStr;
1311
1312 use super::*;
1313 use arrow::array::{
1314 BinaryArray, BinaryDictionaryBuilder, BinaryRunBuilder, BinaryViewArray, Decimal32Array,
1315 Decimal64Array, Decimal128Array, FixedSizeBinaryArray, FixedSizeListArray, Int8Array,
1316 Int32Array, Int64Array, LargeBinaryArray, LargeListArray, LargeListViewArray, ListArray,
1317 ListViewArray, StringArray, Time64MicrosecondArray,
1318 };
1319 use arrow::buffer::{OffsetBuffer, ScalarBuffer};
1320 use arrow_schema::{Field, Fields};
1321 use parquet_variant::{EMPTY_VARIANT_METADATA_BYTES, ShortString};
1322
1323 #[test]
1324 fn invalid_not_a_struct_array() {
1325 let array = make_binary_view_array();
1326 let err = VariantArray::try_new(&array);
1328 assert_eq!(
1329 err.unwrap_err().to_string(),
1330 "Invalid argument error: Invalid VariantArray: requires StructArray as input"
1331 );
1332 }
1333
1334 #[test]
1335 fn invalid_missing_metadata() {
1336 let fields = Fields::from(vec![Field::new("value", DataType::BinaryView, true)]);
1337 let array = StructArray::new(fields, vec![make_binary_view_array()], None);
1338 let err = VariantArray::try_new(&array);
1340 assert_eq!(
1341 err.unwrap_err().to_string(),
1342 "Invalid argument error: Invalid VariantArray: StructArray must contain a 'metadata' field"
1343 );
1344 }
1345
1346 #[test]
1347 fn read_missing_value_column() {
1348 let typed_value = Arc::new(Int64Array::from(vec![Some(1), None, Some(3)])) as ArrayRef;
1352 let metadata =
1353 BinaryViewArray::from_iter_values(std::iter::repeat_n(EMPTY_VARIANT_METADATA_BYTES, 3));
1354 let struct_array = StructArrayAssembler::new()
1355 .with_field("metadata", Arc::new(metadata), false)
1356 .with_field("typed_value", typed_value, true)
1357 .build()
1358 .unwrap();
1359 assert!(struct_array.column_by_name("value").is_none());
1360
1361 let variant_array = VariantArray::try_new(&struct_array).unwrap();
1362 assert_eq!(variant_array.value_column().len(), 3);
1363 assert_eq!(variant_array.value_column().null_count(), 3);
1364 assert!(variant_array.inner().column_by_name("value").is_some());
1365 assert!(variant_array.typed_value_column().is_some());
1366 assert_eq!(variant_array.value(0), Variant::from(1i64));
1367 assert_eq!(variant_array.value(1), Variant::Null);
1368 assert_eq!(variant_array.value(2), Variant::from(3i64));
1369
1370 let fields = Fields::from(vec![Field::new("metadata", DataType::BinaryView, false)]);
1372 let metadata_only = StructArray::new(fields, vec![make_binary_view_array()], None);
1373 let err = VariantArray::try_new(&metadata_only);
1374 assert_eq!(
1375 err.unwrap_err().to_string(),
1376 "Invalid argument error: Invalid VariantArray: StructArray must contain a 'value' field"
1377 );
1378 }
1379
1380 #[test]
1381 fn invalid_metadata_field_type() {
1382 let fields = Fields::from(vec![
1383 Field::new("metadata", DataType::Int32, true), Field::new("value", DataType::BinaryView, true),
1385 ]);
1386 let array = StructArray::new(
1387 fields,
1388 vec![make_int32_array(), make_binary_view_array()],
1389 None,
1390 );
1391 let err = VariantArray::try_new(&array);
1392 assert_eq!(
1393 err.unwrap_err().to_string(),
1394 "Invalid argument error: VariantArray 'metadata' field must be Binary, LargeBinary, BinaryView, or a Dictionary or RunEndEncoded array of one of those types, got Int32"
1395 );
1396 }
1397
1398 #[test]
1399 fn encoded_metadata_supports_nulls_slices_and_variant_get() {
1400 let json: ArrayRef = Arc::new(StringArray::from(vec![
1401 Some(r#"{"a":0}"#),
1402 Some(r#"{"a":1}"#),
1403 None,
1404 Some(r#"{"b":3}"#),
1405 Some(r#"{"b":4}"#),
1406 ]));
1407 let baseline = json_to_variant(&json).unwrap();
1408 let metadata = baseline.metadata_column().as_binary_view();
1409 let metadata_a = metadata.value(0);
1410 let metadata_b = metadata.value(3);
1411
1412 let logical_metadata = [
1413 Some(metadata_a),
1414 Some(metadata_a),
1415 None,
1416 Some(metadata_b),
1417 Some(metadata_b),
1418 ];
1419
1420 let mut dictionary = BinaryDictionaryBuilder::<Int8Type>::new();
1421 dictionary.extend(logical_metadata);
1422 let dictionary: ArrayRef = Arc::new(dictionary.finish());
1423
1424 let mut ree = BinaryRunBuilder::<Int16Type>::new();
1425 ree.extend(logical_metadata);
1426 let run_end_encoded: ArrayRef = Arc::new(ree.finish());
1427
1428 for metadata in [dictionary, run_end_encoded] {
1429 assert_eq!(binary_array_value(metadata.as_ref(), 2), None);
1430 let fields = Fields::from(vec![
1431 Field::new("metadata", metadata.data_type().clone(), false),
1432 Field::new("value", baseline.value_column().data_type().clone(), false),
1433 ]);
1434 let input = StructArray::try_new(
1435 fields,
1436 vec![metadata, baseline.value_column().clone()],
1437 baseline.nulls().cloned(),
1438 )
1439 .unwrap()
1440 .slice(1, 3);
1441
1442 let variant = VariantArray::try_new(&input).unwrap();
1443 assert_eq!(variant.value(0), baseline.value(1));
1444 assert!(variant.is_null(1));
1445 assert_eq!(variant.value(2), baseline.value(3));
1446
1447 let input: ArrayRef = Arc::new(input);
1448 let options = GetOptions::new_with_path("b".try_into().unwrap())
1449 .with_as_type(Some(Arc::new(Field::new("b", DataType::Int8, true))));
1450 let result = variant_get(&input, options).unwrap();
1451 assert_eq!(
1452 result.as_primitive::<Int8Type>(),
1453 &Int8Array::from(vec![None, None, Some(3)])
1454 );
1455 assert_eq!(
1456 variant_to_json(&input).unwrap(),
1457 StringArray::from(vec![Some(r#"{"a":1}"#), None, Some(r#"{"b":3}"#)])
1458 );
1459 }
1460 }
1461
1462 #[test]
1463 fn invalid_value_field_type() {
1464 let fields = Fields::from(vec![
1465 Field::new("metadata", DataType::BinaryView, true),
1466 Field::new("value", DataType::Int32, true),
1467 ]);
1468 let array = StructArray::new(
1469 fields,
1470 vec![make_binary_view_array(), make_int32_array()],
1471 None,
1472 );
1473 let err = VariantArray::try_new(&array);
1474 assert_eq!(
1475 err.unwrap_err().to_string(),
1476 "Invalid argument error: VariantArray 'value' field must be Binary, LargeBinary, or BinaryView, got Int32"
1477 );
1478 }
1479
1480 fn make_binary_view_array() -> ArrayRef {
1481 Arc::new(BinaryViewArray::from(vec![b"test" as &[u8]]))
1482 }
1483
1484 fn make_int32_array() -> ArrayRef {
1485 Arc::new(Int32Array::from(vec![1]))
1486 }
1487
1488 fn make_variant_struct_with_typed_value(typed_value: ArrayRef) -> StructArray {
1489 let metadata = BinaryViewArray::from_iter_values(std::iter::repeat_n(
1490 EMPTY_VARIANT_METADATA_BYTES,
1491 typed_value.len(),
1492 ));
1493 let value = new_null_array(&DataType::BinaryView, typed_value.len());
1494 StructArrayAssembler::new()
1495 .with_field("metadata", Arc::new(metadata), false)
1496 .with_field("value", value, true)
1497 .with_field("typed_value", typed_value, true)
1498 .build()
1499 .unwrap()
1500 }
1501
1502 #[test]
1503 fn try_new_tags_untagged_uuid_on_read() {
1504 let typed_value = FixedSizeBinaryArray::try_from_iter(std::iter::repeat_n([0u8; 16], 2));
1507 let input = make_variant_struct_with_typed_value(Arc::new(typed_value.unwrap()));
1508
1509 let variant_array = VariantArray::try_new(&input).unwrap();
1511 let typed_value = variant_array.inner().field_by_name("typed_value").unwrap();
1512 assert_eq!(typed_value.data_type(), &DataType::FixedSizeBinary(16));
1513 assert!(typed_value.has_valid_extension_type::<UuidExtension>());
1514 }
1515
1516 #[test]
1517 fn try_new_tags_untagged_nested_uuid_on_read() {
1518 let leaf = FixedSizeBinaryArray::try_from_iter(std::iter::repeat_n([0u8; 16], 1)).unwrap();
1521 let inner = StructArrayAssembler::new()
1522 .with_field("typed_value", Arc::new(leaf), true)
1523 .build()
1524 .unwrap();
1525 let object = StructArrayAssembler::new()
1526 .with_field("id", Arc::new(inner), false)
1527 .build()
1528 .unwrap();
1529 let input = make_variant_struct_with_typed_value(Arc::new(object));
1530
1531 let variant_array = VariantArray::try_new(&input).unwrap();
1533 let object = variant_array.typed_value_column().unwrap().as_struct();
1534 let id = object.column_by_name("id").unwrap().as_struct();
1535 let uuid_leaf = id.field_by_name("typed_value").unwrap();
1536 assert!(uuid_leaf.has_valid_extension_type::<UuidExtension>());
1537 }
1538
1539 #[test]
1540 fn all_null_value_column_is_valid_and_unshredded() {
1541 let metadata = BinaryViewArray::from(vec![b"test" as &[u8]; 3]);
1544 let value = new_null_array(&DataType::BinaryView, 3);
1545
1546 let fields = Fields::from(vec![
1547 Field::new("metadata", DataType::BinaryView, false),
1548 Field::new("value", DataType::BinaryView, true),
1549 ]);
1550 let struct_array = StructArray::new(fields, vec![Arc::new(metadata), value], None);
1551
1552 let variant_array = VariantArray::try_new(&struct_array).unwrap();
1553 assert!(variant_array.typed_value_column().is_none());
1554
1555 for i in 0..variant_array.len() {
1558 assert!(variant_array.is_valid(i));
1559 assert_eq!(variant_array.value(i), Variant::Null);
1560 }
1561 }
1562
1563 #[test]
1564 fn canonicalize_and_verify_list_like_data_types() {
1565 let make_item_binary = || Arc::new(Field::new("item", DataType::Binary, true));
1569 let make_large_binary = || Arc::new(Field::new("item", DataType::LargeBinary, true));
1570 let make_item_binary_view = || Arc::new(Field::new("item", DataType::BinaryView, true));
1571
1572 let cases = vec![
1573 DataType::LargeList(make_item_binary()),
1575 DataType::ListView(make_item_binary()),
1576 DataType::LargeListView(make_item_binary()),
1577 DataType::LargeList(make_large_binary()),
1579 DataType::ListView(make_large_binary()),
1580 DataType::LargeListView(make_large_binary()),
1581 DataType::LargeList(make_item_binary_view()),
1583 DataType::ListView(make_item_binary_view()),
1584 DataType::LargeListView(make_item_binary_view()),
1585 ];
1586
1587 for input in cases {
1588 assert_eq!(
1589 canonicalize_and_verify_data_type(&input).unwrap().as_ref(),
1590 &input
1591 );
1592 }
1593 }
1594
1595 #[test]
1596 fn variant_array_try_new_supports_list_like_typed_value() {
1597 let item_field = Arc::new(Field::new("item", DataType::Int64, true));
1598 let values: ArrayRef = Arc::new(Int64Array::from(vec![Some(1), None, Some(3)]));
1599
1600 let typed_values = vec![
1601 Arc::new(ListArray::new(
1602 item_field.clone(),
1603 OffsetBuffer::new(ScalarBuffer::from(vec![0, 2, 3])),
1604 values.clone(),
1605 None,
1606 )) as ArrayRef,
1607 Arc::new(LargeListArray::new(
1608 item_field.clone(),
1609 OffsetBuffer::new(ScalarBuffer::from(vec![0_i64, 2, 3])),
1610 values.clone(),
1611 None,
1612 )) as ArrayRef,
1613 Arc::new(ListViewArray::new(
1614 item_field.clone(),
1615 ScalarBuffer::from(vec![0, 2]),
1616 ScalarBuffer::from(vec![2, 1]),
1617 values.clone(),
1618 None,
1619 )) as ArrayRef,
1620 Arc::new(LargeListViewArray::new(
1621 item_field,
1622 ScalarBuffer::from(vec![0_i64, 2]),
1623 ScalarBuffer::from(vec![2_i64, 1]),
1624 values,
1625 None,
1626 )) as ArrayRef,
1627 ];
1628
1629 for typed_value in typed_values {
1630 let input = make_variant_struct_with_typed_value(typed_value.clone());
1631 let variant_array = VariantArray::try_new(&input).unwrap();
1632 assert_eq!(
1633 variant_array.typed_value_column().unwrap().data_type(),
1634 typed_value.data_type(),
1635 );
1636 }
1637 }
1638
1639 #[test]
1640 fn variant_array_try_new_normalizes_fixed_size_list_typed_value() {
1641 let element_values: ArrayRef =
1642 ShreddedVariantFieldArray::perfectly_shredded(Arc::new(Int64Array::from(vec![
1643 1, 2, 3, 4,
1644 ])))
1645 .into();
1646 let item_field = Arc::new(Field::new("item", element_values.data_type().clone(), true));
1647 let typed_value: ArrayRef = Arc::new(FixedSizeListArray::new(
1648 item_field.clone(),
1649 2,
1650 element_values,
1651 None,
1652 ));
1653 let input = make_variant_struct_with_typed_value(typed_value);
1654
1655 let variant_array = VariantArray::try_new(&input).unwrap();
1656 assert_eq!(
1657 variant_array.typed_value_column().unwrap().data_type(),
1658 &DataType::List(item_field),
1659 );
1660
1661 let unshredded = crate::unshred_variant(&variant_array).unwrap();
1662 assert!(unshredded.typed_value_column().is_none());
1663 assert_eq!(unshredded.len(), 2);
1664 }
1665
1666 #[test]
1667 fn test_try_value_out_of_bounds() {
1668 let mut b = VariantArrayBuilder::new(2);
1669 b.append_variant(Variant::from(1_i8));
1670 b.append_variant(Variant::Null);
1671 let v = b.build();
1672
1673 assert_eq!(v.try_value(0).unwrap(), Variant::Int8(1));
1674 assert_eq!(v.try_value(1).unwrap(), Variant::Null);
1675
1676 let err = v.try_value(2).unwrap_err();
1677 assert_eq!(
1678 err.to_string(),
1679 "Invalid argument error: Index 2 out of bounds for VariantArray of length 2"
1680 );
1681 }
1682
1683 #[test]
1684 fn test_variant_array_iterable() {
1685 let mut b = VariantArrayBuilder::new(6);
1686
1687 b.append_null();
1688 b.append_variant(Variant::from(1_i8));
1689 b.append_variant(Variant::Null);
1690 b.append_variant(Variant::from(2_i32));
1691 b.append_variant(Variant::from(3_i64));
1692 b.append_null();
1693
1694 let v = b.build();
1695
1696 let variants = v.iter().collect::<Vec<_>>();
1697
1698 assert_eq!(
1699 variants,
1700 vec![
1701 None,
1702 Some(Variant::Int8(1)),
1703 Some(Variant::Null),
1704 Some(Variant::Int32(2)),
1705 Some(Variant::Int64(3)),
1706 None,
1707 ]
1708 );
1709 }
1710
1711 #[test]
1712 fn test_variant_array_iter_double_ended() {
1713 let array = VariantArray::from_iter([Some(0_i32), None, Some(2_i32), None, Some(4_i32)]);
1714 let mut iter = array.iter();
1715
1716 assert_eq!(iter.next(), Some(Some(Variant::from(0_i32))));
1717 assert_eq!(iter.next(), Some(None));
1718
1719 assert_eq!(iter.next_back(), Some(Some(Variant::from(4_i32))));
1720 assert_eq!(iter.next_back(), Some(None));
1721 assert_eq!(iter.next_back(), Some(Some(Variant::from(2_i32))));
1722
1723 assert_eq!(iter.next_back(), None);
1724 assert_eq!(iter.next(), None);
1725 }
1726
1727 #[test]
1728 fn test_variant_array_iter_reverse() {
1729 let array = VariantArray::from_iter([Some("a"), None, Some("aaa"), None, Some("aaaaa")]);
1730
1731 let result: Vec<_> = array.iter().rev().collect();
1732 assert_eq!(
1733 result,
1734 vec![
1735 Some(Variant::from("aaaaa")),
1736 None,
1737 Some(Variant::from("aaa")),
1738 None,
1739 Some(Variant::from("a")),
1740 ]
1741 );
1742 }
1743
1744 #[test]
1745 fn test_variant_array_iter_empty() {
1746 let v = VariantArrayBuilder::new(0).build();
1747 let mut i = v.iter();
1748 assert!(i.next().is_none());
1749 assert!(i.next_back().is_none());
1750 }
1751
1752 #[test]
1753 fn test_from_variant_opts_into_variant_array() {
1754 let v = vec![None, Some(Variant::Null), Some(Variant::BooleanFalse), None];
1755
1756 let variant_array = VariantArray::from_iter(v);
1757
1758 assert_eq!(variant_array.len(), 4);
1759
1760 assert!(variant_array.is_null(0));
1761
1762 assert!(!variant_array.is_null(1));
1763 assert_eq!(variant_array.value(1), Variant::Null);
1764
1765 assert!(!variant_array.is_null(2));
1766 assert_eq!(variant_array.value(2), Variant::BooleanFalse);
1767
1768 assert!(variant_array.is_null(3));
1769 }
1770
1771 #[test]
1772 fn test_from_option_into_variants_into_variant_array() {
1773 let v = vec![Some(42_i64), None, Some(-1_i64)];
1776
1777 let variant_array = VariantArray::from_iter(v);
1778
1779 assert_eq!(variant_array.len(), 3);
1780
1781 assert!(!variant_array.is_null(0));
1782 assert_eq!(variant_array.value(0), Variant::Int64(42));
1783
1784 assert!(variant_array.is_null(1));
1785
1786 assert!(!variant_array.is_null(2));
1787 assert_eq!(variant_array.value(2), Variant::Int64(-1));
1788 }
1789
1790 #[test]
1791 fn test_from_option_str_into_variant_array() {
1792 let v = vec![
1793 Some("hello"),
1794 None,
1795 Some(
1796 "hello world this is much longer than the maximum short string length of sixty three bytes",
1797 ),
1798 ];
1799
1800 let variant_array: VariantArray = v.into_iter().collect();
1801
1802 assert_eq!(variant_array.len(), 3);
1803
1804 assert!(!variant_array.is_null(0));
1805 assert_eq!(
1806 variant_array.value(0),
1807 Variant::ShortString(ShortString::try_new("hello").unwrap())
1808 );
1809
1810 assert!(variant_array.is_null(1));
1811
1812 assert!(!variant_array.is_null(2));
1813 assert_eq!(
1814 variant_array.value(2),
1815 Variant::String(
1816 "hello world this is much longer than the maximum short string length of sixty three bytes"
1817 )
1818 );
1819 }
1820
1821 #[test]
1822 fn test_from_variants_into_variant_array() {
1823 let v = vec![
1824 Variant::Null,
1825 Variant::BooleanFalse,
1826 Variant::ShortString(ShortString::try_new("norm").unwrap()),
1827 ];
1828
1829 let variant_array = VariantArray::from_iter(v);
1830
1831 assert_eq!(variant_array.len(), 3);
1832
1833 assert!(!variant_array.is_null(0));
1834 assert_eq!(variant_array.value(0), Variant::Null);
1835
1836 assert!(!variant_array.is_null(1));
1837 assert_eq!(variant_array.value(1), Variant::BooleanFalse);
1838
1839 assert!(!variant_array.is_null(2));
1840 assert_eq!(
1841 variant_array.value(2),
1842 Variant::ShortString(ShortString::try_new("norm").unwrap())
1843 );
1844 }
1845
1846 #[test]
1847 fn test_variant_equality() {
1848 let v_iter = [None, Some(Variant::BooleanFalse), Some(Variant::Null), None];
1849 let v = VariantArray::from_iter(v_iter.clone());
1850
1851 {
1852 let v_copy = v.clone();
1853 assert_eq!(v, v_copy);
1854 }
1855
1856 {
1857 let v_iter_reversed = v_iter.iter().cloned().rev();
1858 let v_reversed = VariantArray::from_iter(v_iter_reversed);
1859
1860 assert_ne!(v, v_reversed);
1861 }
1862
1863 {
1864 let v_sliced = v.slice(0, 1);
1865 assert_ne!(v, v_sliced);
1866 }
1867 }
1868
1869 #[test]
1870 fn binary_typed_value_roundtrips() {
1871 let typed_value: ArrayRef = Arc::new(BinaryArray::from(vec![b"hello" as &[u8]]));
1873 let struct_array = make_variant_struct_with_typed_value(typed_value);
1874
1875 let variant_array = VariantArray::try_new(&struct_array).unwrap();
1876 assert_eq!(variant_array.value(0), Variant::from(b"hello" as &[u8]));
1877 }
1878
1879 #[test]
1880 fn large_binary_typed_value_roundtrips() {
1881 let typed_value: ArrayRef = Arc::new(LargeBinaryArray::from(vec![b"world" as &[u8]]));
1883 let struct_array = make_variant_struct_with_typed_value(typed_value);
1884
1885 let variant_array = VariantArray::try_new(&struct_array).unwrap();
1886 assert_eq!(variant_array.value(0), Variant::from(b"world" as &[u8]));
1887 }
1888
1889 macro_rules! invalid_variant_array_test {
1890 ($fn_name: ident, $invalid_typed_value: expr, $error_msg: literal) => {
1891 #[test]
1892 fn $fn_name() {
1893 let invalid_typed_value = $invalid_typed_value;
1894
1895 let struct_array =
1896 make_variant_struct_with_typed_value(Arc::new(invalid_typed_value));
1897
1898 let array: VariantArray = VariantArray::try_new(&struct_array)
1899 .expect("should create variant array")
1900 .into();
1901
1902 let result = array.try_value(0);
1903 assert!(result.is_err());
1904 let error = result.unwrap_err();
1905 assert!(matches!(error, ArrowError::CastError(_)));
1906
1907 let expected: &str = $error_msg;
1908 assert!(
1909 error.to_string().contains($error_msg),
1910 "error `{}` did not contain `{}`",
1911 error,
1912 expected
1913 )
1914 }
1915 };
1916 }
1917
1918 invalid_variant_array_test!(
1919 test_variant_array_invalid_time,
1920 Time64MicrosecondArray::from(vec![Some(86401000000)]),
1921 "Cast error: Cast failed at index 0 (array type: Time64(µs)): Invalid microsecond from midnight: 86401000000"
1922 );
1923
1924 invalid_variant_array_test!(
1925 test_variant_array_invalid_decimal32,
1926 Decimal32Array::from(vec![Some(1234567890)]),
1927 "Cast error: Cast failed at index 0 (array type: Decimal32(9, 2)): Invalid argument error: 1234567890 is wider than max precision 9"
1928 );
1929
1930 invalid_variant_array_test!(
1931 test_variant_array_invalid_decimal64,
1932 Decimal64Array::from(vec![Some(1234567890123456789)]),
1933 "Cast error: Cast failed at index 0 (array type: Decimal64(18, 6)): Invalid argument error: 1234567890123456789 is wider than max precision 18"
1934 );
1935
1936 invalid_variant_array_test!(
1937 test_variant_array_invalid_decimal128,
1938 Decimal128Array::from(vec![Some(
1939 i128::from_str("123456789012345678901234567890123456789").unwrap()
1940 ),]),
1941 "Cast error: Cast failed at index 0 (array type: Decimal128(38, 10)): Invalid argument error: 123456789012345678901234567890123456789 is wider than max precision 38"
1942 );
1943 #[test]
1944 fn try_value_errors_on_unimplemented_typed_value_type() {
1945 use crate::{json_to_variant, shred_variant};
1946 use arrow::array::StringArray;
1947
1948 let json: ArrayRef = Arc::new(StringArray::from(vec![r#"{"qty": 3}"#]));
1949 let variant = json_to_variant(&json).unwrap();
1950 let shred_type = DataType::Struct(vec![Field::new("qty", DataType::Int64, true)].into());
1951 let shredded = shred_variant(&variant, &shred_type).unwrap();
1952 let err = shredded.try_value(0).unwrap_err();
1956 assert!(
1957 err.to_string().starts_with(
1958 "Not yet implemented: VariantArray::try_value cannot materialize typed_value"
1959 ),
1960 "unexpected error: {err}"
1961 );
1962 }
1963}