Skip to main content

parquet_variant_compute/
variant_get.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17use arrow::{
18    array::{self, Array, ArrayRef, StructArray, make_array},
19    buffer::NullBuffer,
20    compute::CastOptions,
21    datatypes::Field,
22    error::Result,
23};
24use arrow_schema::{ArrowError, DataType, FieldRef};
25use parquet_variant::{VariantPath, VariantPathElement};
26
27use crate::VariantArray;
28use crate::variant_array::BorrowedShreddingState;
29use crate::variant_to_arrow::make_variant_to_arrow_row_builder;
30
31use arrow::array::AsArray;
32use std::sync::Arc;
33
34pub(crate) enum ShreddedPathStep<'a> {
35    /// Path step succeeded, return the new shredding state
36    Success(BorrowedShreddingState<'a>),
37    /// The path element is not present in the `typed_value` column and there is no `value` column,
38    /// so we know it does not exist. It, and all paths under it, are all-NULL.
39    Missing,
40    /// The path element is not present in the `typed_value` column and must be retrieved from the `value`
41    /// column instead. The caller should be prepared to handle any value, including the requested
42    /// type, an arbitrary "wrong" type, or `Variant::Null`.
43    NotShredded,
44}
45
46/// Given a shredded variant field -- a `(value?, typed_value?)` pair -- try to take one path step
47/// deeper. For a `VariantPathElement::Field`, if there is no `typed_value` at this level, if
48/// `typed_value` is not a struct, or if the requested field name does not exist, traversal returns
49/// a missing-path step (`Missing` or `NotShredded` depending on whether `value` exists).
50///
51/// TODO: Support `VariantPathElement::Index`? It wouldn't be easy, and maybe not even possible.
52pub(crate) fn follow_shredded_path_element<'a>(
53    shredding_state: &BorrowedShreddingState<'a>,
54    path_element: &VariantPathElement<'_>,
55    _cast_options: &CastOptions,
56) -> Result<ShreddedPathStep<'a>> {
57    // If the requested path element is not present in `typed_value`, and `value` is missing, then
58    // we know it does not exist; it, and all paths under it, are all-NULL.
59    let missing_path_step = || match shredding_state.value_field() {
60        Some(_) => ShreddedPathStep::NotShredded,
61        None => ShreddedPathStep::Missing,
62    };
63
64    let Some(typed_value) = shredding_state.typed_value_field() else {
65        return Ok(missing_path_step());
66    };
67
68    match path_element {
69        VariantPathElement::Field { name } => {
70            // Try to step into the requested field name of a struct.
71            // First, try to downcast to StructArray
72            let Some(struct_array) = typed_value.as_any().downcast_ref::<StructArray>() else {
73                // Object field path step follows JSONPath semantics and returns missing path step (NotShredded/Missing) on non-struct path
74                return Ok(missing_path_step());
75            };
76
77            // Now try to find the column - missing column in a present struct is just missing data
78            let Some(field) = struct_array.column_by_name(name) else {
79                // Missing column in a present struct is just missing, not wrong - return Ok
80                return Ok(missing_path_step());
81            };
82
83            let struct_array = field.as_struct_opt().ok_or_else(|| {
84                // TODO: Should we blow up? Or just end the traversal and let the normal
85                // variant pathing code sort out the mess that it must anyway be
86                // prepared to handle?
87                ArrowError::InvalidArgumentError(format!(
88                    "Expected Struct array while following path, got {}",
89                    field.data_type(),
90                ))
91            })?;
92
93            let state = BorrowedShreddingState::try_from(struct_array)?;
94            Ok(ShreddedPathStep::Success(state))
95        }
96        VariantPathElement::Index { .. } => {
97            // TODO: Support array indexing. Among other things, it will require slicing not
98            // only the array we have here, but also the corresponding metadata and null masks.
99            Err(ArrowError::NotYetImplemented(
100                "Pathing into shredded variant array index".into(),
101            ))
102        }
103    }
104}
105
106/// Follows the given path as far as possible through shredded variant fields. If the path ends on a
107/// shredded field, return it directly. Otherwise, use a row shredder to follow the rest of the path
108/// and extract the requested value on a per-row basis.
109fn shredded_get_path(
110    input: &VariantArray,
111    path: &[VariantPathElement<'_>],
112    as_field: Option<&Field>,
113    cast_options: &CastOptions,
114) -> Result<ArrayRef> {
115    // Helper that creates a new VariantArray from the given nested value and typed_value columns,
116    // properly accounting for accumulated nulls from path traversal
117    let make_target_variant =
118        |value: Option<ArrayRef>,
119         typed_value: Option<ArrayRef>,
120         accumulated_nulls: Option<NullBuffer>| {
121            let metadata = input.metadata_field().clone();
122            VariantArray::from_parts(metadata, value, typed_value, accumulated_nulls)
123        };
124
125    // Helper that shreds a VariantArray to a specific type.
126    let shred_basic_variant =
127        |target: VariantArray, path: VariantPath<'_>, as_field: Option<&Field>| {
128            let as_type = as_field.map(|f| f.data_type());
129            let mut builder = make_variant_to_arrow_row_builder(
130                target.metadata_field(),
131                path,
132                as_type,
133                cast_options,
134                target.len(),
135            )?;
136            for i in 0..target.len() {
137                if target.is_null(i) {
138                    builder.append_null()?;
139                } else if !cast_options.safe {
140                    let value = target.try_value(i)?;
141                    builder.append_value(value)?;
142                } else {
143                    let _ = match target.try_value(i) {
144                        Ok(v) => builder.append_value(v)?,
145                        Err(_) => {
146                            builder.append_null()?;
147                            false // add this to make match arms have the same return type
148                        }
149                    };
150                }
151            }
152            builder.finish()
153        };
154
155    // Peel away the prefix of path elements that traverses the shredded parts of this variant
156    // column. Shredding will traverse the rest of the path on a per-row basis.
157    let mut shredding_state = input.shredding_state().borrow();
158    let mut accumulated_nulls = input.inner().nulls().cloned();
159    let mut path_index = 0;
160    for path_element in path {
161        match follow_shredded_path_element(&shredding_state, path_element, cast_options)? {
162            ShreddedPathStep::Success(state) => {
163                // Union nulls from the typed_value we just accessed
164                if let Some(typed_value) = shredding_state.typed_value_field() {
165                    accumulated_nulls =
166                        NullBuffer::union(accumulated_nulls.as_ref(), typed_value.nulls());
167                }
168                shredding_state = state;
169                path_index += 1;
170                continue;
171            }
172            ShreddedPathStep::Missing => {
173                let num_rows = input.len();
174                let arr = match as_field.map(|f| f.data_type()) {
175                    Some(data_type) => array::new_null_array(data_type, num_rows),
176                    None => Arc::new(array::NullArray::new(num_rows)) as _,
177                };
178                return Ok(arr);
179            }
180            ShreddedPathStep::NotShredded => {
181                let target = make_target_variant(
182                    shredding_state.value_field().cloned(),
183                    None,
184                    accumulated_nulls,
185                );
186                return shred_basic_variant(target, path[path_index..].into(), as_field);
187            }
188        };
189    }
190
191    // Path exhausted! Create a new `VariantArray` for the location we landed on.
192    let target = make_target_variant(
193        shredding_state.value_field().cloned(),
194        shredding_state.typed_value_field().cloned(),
195        accumulated_nulls,
196    );
197
198    // If our caller did not request any specific type, we can just return whatever we landed on.
199    let Some(as_field) = as_field else {
200        return Ok(ArrayRef::from(target));
201    };
202
203    // Try to return the typed value directly when we have a perfect shredding match.
204    if let Some(shredded) = try_perfect_shredding(&target, as_field) {
205        return Ok(shredded);
206    }
207
208    // Structs are special.
209    //
210    // For fully unshredded targets (`typed_value` absent), delegate to the row builder so we
211    // preserve struct-level cast semantics:
212    // - safe mode: non-object rows become NULL structs
213    // - strict mode: non-object rows raise a cast error
214    //
215    // For shredded/partially-shredded targets (`typed_value` present), recurse into each field
216    // separately to take advantage of deeper shredding in child fields.
217    if let DataType::Struct(fields) = as_field.data_type() {
218        if target.typed_value_field().is_none() {
219            return shred_basic_variant(target, VariantPath::default(), Some(as_field));
220        }
221
222        let children = fields
223            .iter()
224            .map(|field| {
225                shredded_get_path(
226                    &target,
227                    &[VariantPathElement::from(field.name().as_str())],
228                    Some(field),
229                    cast_options,
230                )
231            })
232            .collect::<Result<Vec<_>>>()?;
233
234        let struct_nulls = target.nulls().cloned();
235
236        return Ok(Arc::new(StructArray::try_new(
237            fields.clone(),
238            children,
239            struct_nulls,
240        )?));
241    }
242
243    // Not a struct, so directly shred the variant as the requested type
244    shred_basic_variant(target, VariantPath::default(), Some(as_field))
245}
246
247fn try_perfect_shredding(variant_array: &VariantArray, as_field: &Field) -> Option<ArrayRef> {
248    // Try to return the typed value directly when we have a perfect shredding match.
249    if matches!(as_field.data_type(), DataType::Struct(_)) {
250        return None;
251    }
252    let typed_value = variant_array.typed_value_field()?;
253
254    if typed_value.data_type() == as_field.data_type()
255        && variant_array
256            .value_field()
257            .is_none_or(|v| v.null_count() == v.len())
258    {
259        // Here we need to gate against the case where the `typed_value` is null but data is in the `value` column.
260        // 1. If the `value` column is null, or
261        // 2. If every row in the `value` column is null
262
263        // This is a perfect shredding, where the value is entirely shredded out,
264        // so we can just return the typed value after merging the accumulated nulls.
265        let parent_nulls = variant_array.nulls();
266
267        // If we have no nulls OR the shredded array is `Null`, which doesn't support external nulls.
268        let target_array = if parent_nulls.is_none() || typed_value.data_type().is_null() {
269            typed_value.clone()
270        } else {
271            let merged_nulls = NullBuffer::union(parent_nulls, typed_value.nulls());
272            let data = typed_value
273                .to_data()
274                .into_builder()
275                .nulls(merged_nulls)
276                .build()
277                .ok()?;
278            make_array(data)
279        };
280
281        return Some(target_array);
282    }
283
284    None
285}
286
287/// Returns an array with the specified path extracted from the variant values.
288///
289/// The return array type depends on the `as_type` field of the options parameter
290/// 1. `as_type: None`: a VariantArray is returned. The values in this new VariantArray will point
291///    to the specified path.
292/// 2. `as_type: Some(<specific field>)`: an array of the specified type is returned.
293///
294/// TODO: How would a caller request a struct or list type where the fields/elements can be any
295/// variant? Caller can pass None as the requested type to fetch a specific path, but it would
296/// quickly become annoying (and inefficient) to call `variant_get` for each leaf value in a struct or
297/// list and then try to assemble the results.
298pub fn variant_get(input: &ArrayRef, options: GetOptions) -> Result<ArrayRef> {
299    let variant_array = VariantArray::try_new(input)?;
300
301    let GetOptions {
302        as_type,
303        path,
304        cast_options,
305    } = options;
306
307    shredded_get_path(&variant_array, &path, as_type.as_deref(), &cast_options)
308}
309
310/// Controls the action of the variant_get kernel.
311#[derive(Debug, Clone, Default)]
312pub struct GetOptions<'a> {
313    /// What path to extract
314    pub path: VariantPath<'a>,
315    /// if `as_type` is None, the returned array will itself be a VariantArray.
316    ///
317    /// if `as_type` is `Some(type)` the field is returned as the specified type.
318    pub as_type: Option<FieldRef>,
319    /// Controls the casting behavior (e.g. error vs substituting null on cast error).
320    pub cast_options: CastOptions<'a>,
321}
322
323impl<'a> GetOptions<'a> {
324    /// Construct default options to get the specified path as a variant.
325    pub fn new() -> Self {
326        Default::default()
327    }
328
329    /// Construct options to get the specified path as a variant.
330    pub fn new_with_path(path: VariantPath<'a>) -> Self {
331        Self {
332            path,
333            as_type: None,
334            cast_options: Default::default(),
335        }
336    }
337
338    /// Specify the type to return.
339    pub fn with_as_type(mut self, as_type: Option<FieldRef>) -> Self {
340        self.as_type = as_type;
341        self
342    }
343
344    /// Specify the cast options to use when casting to the specified type.
345    pub fn with_cast_options(mut self, cast_options: CastOptions<'a>) -> Self {
346        self.cast_options = cast_options;
347        self
348    }
349}
350
351#[cfg(test)]
352mod test {
353    use std::str::FromStr;
354    use std::sync::Arc;
355
356    use super::{GetOptions, variant_get};
357    use crate::variant_array::{ShreddedVariantFieldArray, StructArrayBuilder};
358    use crate::{
359        VariantArray, VariantArrayBuilder, cast_to_variant, json_to_variant, shred_variant,
360    };
361    use arrow::array::{
362        Array, ArrayRef, AsArray, BinaryArray, BinaryViewArray, BooleanArray, Date32Array,
363        Date64Array, Decimal32Array, Decimal64Array, Decimal128Array, Decimal256Array,
364        Float32Array, Float64Array, Int8Array, Int16Array, Int32Array, Int64Array,
365        LargeBinaryArray, LargeListArray, LargeListViewArray, LargeStringArray, ListArray,
366        ListViewArray, NullArray, NullBuilder, StringArray, StringViewArray, StructArray,
367        Time32MillisecondArray, Time32SecondArray, Time64MicrosecondArray, Time64NanosecondArray,
368    };
369    use arrow::buffer::{NullBuffer, OffsetBuffer, ScalarBuffer};
370    use arrow::compute::CastOptions;
371    use arrow::datatypes::DataType::{Int16, Int32, Int64};
372    use arrow::datatypes::i256;
373    use arrow::util::display::FormatOptions;
374    use arrow_schema::DataType::{Boolean, Float32, Float64, Int8};
375    use arrow_schema::{DataType, Field, FieldRef, Fields, IntervalUnit, TimeUnit};
376    use chrono::DateTime;
377    use parquet_variant::{
378        EMPTY_VARIANT_METADATA_BYTES, Variant, VariantDecimal4, VariantDecimal8, VariantDecimal16,
379        VariantDecimalType, VariantPath,
380    };
381
382    fn single_variant_get_test(input_json: &str, path: VariantPath, expected_json: &str) {
383        // Create input array from JSON string
384        let input_array_ref: ArrayRef = Arc::new(StringArray::from(vec![Some(input_json)]));
385        let input_variant_array_ref = ArrayRef::from(json_to_variant(&input_array_ref).unwrap());
386
387        let result =
388            variant_get(&input_variant_array_ref, GetOptions::new_with_path(path)).unwrap();
389
390        // Create expected array from JSON string
391        let expected_array_ref: ArrayRef = Arc::new(StringArray::from(vec![Some(expected_json)]));
392        let expected_variant_array = json_to_variant(&expected_array_ref).unwrap();
393
394        let result_array = VariantArray::try_new(&result).unwrap();
395        assert_eq!(
396            result_array.len(),
397            1,
398            "Expected result array to have length 1"
399        );
400        assert!(
401            result_array.nulls().is_none(),
402            "Expected no nulls in result array"
403        );
404        let result_variant = result_array.value(0);
405        let expected_variant = expected_variant_array.value(0);
406        assert_eq!(
407            result_variant, expected_variant,
408            "Result variant does not match expected variant"
409        );
410    }
411
412    #[test]
413    fn get_primitive_variant_field() {
414        single_variant_get_test(
415            r#"{"some_field": 1234}"#,
416            VariantPath::try_from("some_field").unwrap(),
417            "1234",
418        );
419    }
420
421    #[test]
422    fn get_primitive_variant_list_index() {
423        single_variant_get_test("[1234, 5678]", VariantPath::from(0), "1234");
424    }
425
426    #[test]
427    fn get_primitive_variant_inside_object_of_object() {
428        single_variant_get_test(
429            r#"{"top_level_field": {"inner_field": 1234}}"#,
430            VariantPath::try_from("top_level_field")
431                .unwrap()
432                .join("inner_field"),
433            "1234",
434        );
435    }
436
437    #[test]
438    fn get_primitive_variant_inside_list_of_object() {
439        single_variant_get_test(
440            r#"[{"some_field": 1234}]"#,
441            VariantPath::from(0).join("some_field"),
442            "1234",
443        );
444    }
445
446    #[test]
447    fn get_primitive_variant_inside_object_of_list() {
448        single_variant_get_test(
449            r#"{"some_field": [1234]}"#,
450            VariantPath::try_from("some_field").unwrap().join(0),
451            "1234",
452        );
453    }
454
455    #[test]
456    fn get_complex_variant() {
457        single_variant_get_test(
458            r#"{"top_level_field": {"inner_field": 1234}}"#,
459            VariantPath::try_from("top_level_field").unwrap(),
460            r#"{"inner_field": 1234}"#,
461        );
462    }
463
464    /// Partial Shredding: extract a value as a VariantArray
465    macro_rules! numeric_partially_shredded_test {
466        ($primitive_type:ty, $data_fn:ident) => {
467            let array = $data_fn();
468            let options = GetOptions::new();
469            let result = variant_get(&array, options).unwrap();
470
471            // expect the result is a VariantArray
472            let result = VariantArray::try_new(&result).unwrap();
473            assert_eq!(result.len(), 4);
474
475            // Expect the values are the same as the original values
476            assert_eq!(
477                result.value(0),
478                Variant::from(<$primitive_type>::try_from(34u8).unwrap())
479            );
480            assert!(!result.is_valid(1));
481            assert_eq!(result.value(2), Variant::from("n/a"));
482            assert_eq!(
483                result.value(3),
484                Variant::from(<$primitive_type>::try_from(100u8).unwrap())
485            );
486        };
487    }
488
489    /// Build a mixed input [typed, null, fallback, typed] and let shred_variant
490    /// generate the shredded fixture for the requested type.
491    macro_rules! partially_shredded_variant_array_gen {
492        ($func_name:ident,  $typed_value_array_gen: expr) => {
493            partially_shredded_variant_array_gen!(
494                $func_name,
495                $typed_value_array_gen,
496                Variant::from("n/a")
497            );
498        };
499        ($func_name:ident,  $typed_value_array_gen: expr, $fallback_variant:expr) => {
500            fn $func_name() -> ArrayRef {
501                let typed_value: ArrayRef = Arc::new($typed_value_array_gen());
502                let typed_as_variant = cast_to_variant(typed_value.as_ref())
503                    .expect("should cast typed array to variant");
504                let mut input_builder = VariantArrayBuilder::new(typed_as_variant.len());
505                input_builder.append_variant(typed_as_variant.value(0));
506                input_builder.append_null();
507                input_builder.append_variant($fallback_variant);
508                input_builder.append_variant(typed_as_variant.value(3));
509
510                let variant_array = shred_variant(&input_builder.build(), typed_value.data_type())
511                    .expect("should shred variant array");
512                ArrayRef::from(variant_array)
513            }
514        };
515    }
516
517    // Fixture definitions grouped with the partially-shredded tests.
518    macro_rules! numeric_partially_shredded_variant_array_fn {
519        ($func:ident, $array_type:ident, $primitive_type:ty) => {
520            partially_shredded_variant_array_gen!($func, || $array_type::from(vec![
521                Some(<$primitive_type>::try_from(34u8).unwrap()),
522                None,
523                None,
524                Some(<$primitive_type>::try_from(100u8).unwrap()),
525            ]));
526        };
527    }
528
529    numeric_partially_shredded_variant_array_fn!(
530        partially_shredded_int8_variant_array,
531        Int8Array,
532        i8
533    );
534    numeric_partially_shredded_variant_array_fn!(
535        partially_shredded_int16_variant_array,
536        Int16Array,
537        i16
538    );
539    numeric_partially_shredded_variant_array_fn!(
540        partially_shredded_int32_variant_array,
541        Int32Array,
542        i32
543    );
544    numeric_partially_shredded_variant_array_fn!(
545        partially_shredded_int64_variant_array,
546        Int64Array,
547        i64
548    );
549    numeric_partially_shredded_variant_array_fn!(
550        partially_shredded_float32_variant_array,
551        Float32Array,
552        f32
553    );
554    numeric_partially_shredded_variant_array_fn!(
555        partially_shredded_float64_variant_array,
556        Float64Array,
557        f64
558    );
559
560    partially_shredded_variant_array_gen!(partially_shredded_bool_variant_array, || {
561        arrow::array::BooleanArray::from(vec![Some(true), None, None, Some(false)])
562    });
563
564    partially_shredded_variant_array_gen!(
565        partially_shredded_utf8_variant_array,
566        || { StringArray::from(vec![Some("hello"), None, None, Some("world")]) },
567        Variant::from(42i32)
568    );
569
570    partially_shredded_variant_array_gen!(partially_shredded_date32_variant_array, || {
571        Date32Array::from(vec![
572            Some(20348), // 2025-09-17
573            None,
574            None,
575            Some(20340), // 2025-09-09
576        ])
577    });
578
579    #[test]
580    fn get_variant_partially_shredded_int8_as_variant() {
581        numeric_partially_shredded_test!(i8, partially_shredded_int8_variant_array);
582    }
583
584    #[test]
585    fn get_variant_partially_shredded_int16_as_variant() {
586        numeric_partially_shredded_test!(i16, partially_shredded_int16_variant_array);
587    }
588
589    #[test]
590    fn get_variant_partially_shredded_int32_as_variant() {
591        numeric_partially_shredded_test!(i32, partially_shredded_int32_variant_array);
592    }
593
594    #[test]
595    fn get_variant_partially_shredded_int64_as_variant() {
596        numeric_partially_shredded_test!(i64, partially_shredded_int64_variant_array);
597    }
598
599    #[test]
600    fn get_variant_partially_shredded_float32_as_variant() {
601        numeric_partially_shredded_test!(f32, partially_shredded_float32_variant_array);
602    }
603
604    #[test]
605    fn get_variant_partially_shredded_float64_as_variant() {
606        numeric_partially_shredded_test!(f64, partially_shredded_float64_variant_array);
607    }
608
609    #[test]
610    fn get_variant_partially_shredded_bool_as_variant() {
611        let array = partially_shredded_bool_variant_array();
612        let options = GetOptions::new();
613        let result = variant_get(&array, options).unwrap();
614
615        // expect the result is a VariantArray
616        let result = VariantArray::try_new(&result).unwrap();
617        assert_eq!(result.len(), 4);
618
619        // Expect the values are the same as the original values
620        assert_eq!(result.value(0), Variant::from(true));
621        assert!(!result.is_valid(1));
622        assert_eq!(result.value(2), Variant::from("n/a"));
623        assert_eq!(result.value(3), Variant::from(false));
624    }
625
626    #[test]
627    fn get_variant_partially_shredded_utf8_as_variant() {
628        let array = partially_shredded_utf8_variant_array();
629        let options = GetOptions::new();
630        let result = variant_get(&array, options).unwrap();
631
632        // expect the result is a VariantArray
633        let result = VariantArray::try_new(&result).unwrap();
634        assert_eq!(result.len(), 4);
635
636        // Expect the values are the same as the original values
637        assert_eq!(result.value(0), Variant::from("hello"));
638        assert!(!result.is_valid(1));
639        assert_eq!(result.value(2), Variant::from(42i32));
640        assert_eq!(result.value(3), Variant::from("world"));
641    }
642
643    partially_shredded_variant_array_gen!(partially_shredded_binary_view_variant_array, || {
644        BinaryViewArray::from(vec![
645            Some(&[1u8, 2u8, 3u8][..]), // row 0 is shredded
646            None,                       // row 1 is null
647            None,                       // row 2 is a string
648            Some(&[4u8, 5u8, 6u8][..]), // row 3 is shredded
649        ])
650    });
651
652    #[test]
653    fn get_variant_partially_shredded_date32_as_variant() {
654        let array = partially_shredded_date32_variant_array();
655        let options = GetOptions::new();
656        let result = variant_get(&array, options).unwrap();
657
658        // expect the result is a VariantArray
659        let result = VariantArray::try_new(&result).unwrap();
660        assert_eq!(result.len(), 4);
661
662        // Expect the values are the same as the original values
663        use chrono::NaiveDate;
664        let date1 = NaiveDate::from_ymd_opt(2025, 9, 17).unwrap();
665        let date2 = NaiveDate::from_ymd_opt(2025, 9, 9).unwrap();
666        assert_eq!(result.value(0), Variant::from(date1));
667        assert!(!result.is_valid(1));
668        assert_eq!(result.value(2), Variant::from("n/a"));
669        assert_eq!(result.value(3), Variant::from(date2));
670    }
671
672    #[test]
673    fn get_variant_partially_shredded_binary_view_as_variant() {
674        let array = partially_shredded_binary_view_variant_array();
675        let options = GetOptions::new();
676        let result = variant_get(&array, options).unwrap();
677
678        // expect the result is a VariantArray
679        let result = VariantArray::try_new(&result).unwrap();
680        assert_eq!(result.len(), 4);
681
682        // Expect the values are the same as the original values
683        assert_eq!(result.value(0), Variant::from(&[1u8, 2u8, 3u8][..]));
684        assert!(!result.is_valid(1));
685        assert_eq!(result.value(2), Variant::from("n/a"));
686        assert_eq!(result.value(3), Variant::from(&[4u8, 5u8, 6u8][..]));
687    }
688
689    // Timestamp partially-shredded tests grouped with the other partially-shredded cases.
690    macro_rules! assert_variant_get_as_variant_array_with_default_option {
691        ($variant_array: expr, $array_expected: expr) => {{
692            let options = GetOptions::new();
693            let array = $variant_array;
694            let result = variant_get(&array, options).unwrap();
695            let result = VariantArray::try_new(&result).unwrap();
696
697            assert_eq!(result.len(), $array_expected.len());
698
699            for (idx, item) in $array_expected.into_iter().enumerate() {
700                match item {
701                    Some(item) => assert_eq!(result.value(idx), item),
702                    None => assert!(result.is_null(idx)),
703                }
704            }
705        }};
706    }
707
708    partially_shredded_variant_array_gen!(
709        partially_shredded_timestamp_micro_ntz_variant_array,
710        || {
711            arrow::array::TimestampMicrosecondArray::from(vec![
712                Some(-456000),
713                None,
714                None,
715                Some(1758602096000000),
716            ])
717        }
718    );
719
720    #[test]
721    fn get_variant_partial_shredded_timestamp_micro_ntz_as_variant() {
722        let array = partially_shredded_timestamp_micro_ntz_variant_array();
723        assert_variant_get_as_variant_array_with_default_option!(
724            array,
725            vec![
726                Some(Variant::from(
727                    DateTime::from_timestamp_micros(-456000i64)
728                        .unwrap()
729                        .naive_utc(),
730                )),
731                None,
732                Some(Variant::from("n/a")),
733                Some(Variant::from(
734                    DateTime::parse_from_rfc3339("2025-09-23T12:34:56+08:00")
735                        .unwrap()
736                        .naive_utc(),
737                )),
738            ]
739        )
740    }
741
742    partially_shredded_variant_array_gen!(partially_shredded_timestamp_micro_variant_array, || {
743        arrow::array::TimestampMicrosecondArray::from(vec![
744            Some(-456000),
745            None,
746            None,
747            Some(1758602096000000),
748        ])
749        .with_timezone("+00:00")
750    });
751
752    #[test]
753    fn get_variant_partial_shredded_timestamp_micro_as_variant() {
754        let array = partially_shredded_timestamp_micro_variant_array();
755        assert_variant_get_as_variant_array_with_default_option!(
756            array,
757            vec![
758                Some(Variant::from(
759                    DateTime::from_timestamp_micros(-456000i64)
760                        .unwrap()
761                        .to_utc(),
762                )),
763                None,
764                Some(Variant::from("n/a")),
765                Some(Variant::from(
766                    DateTime::parse_from_rfc3339("2025-09-23T12:34:56+08:00")
767                        .unwrap()
768                        .to_utc(),
769                )),
770            ]
771        )
772    }
773
774    partially_shredded_variant_array_gen!(
775        partially_shredded_timestamp_nano_ntz_variant_array,
776        || {
777            arrow::array::TimestampNanosecondArray::from(vec![
778                Some(-4999999561),
779                None,
780                None,
781                Some(1758602096000000000),
782            ])
783        }
784    );
785
786    #[test]
787    fn get_variant_partial_shredded_timestamp_nano_ntz_as_variant() {
788        let array = partially_shredded_timestamp_nano_ntz_variant_array();
789        assert_variant_get_as_variant_array_with_default_option!(
790            array,
791            vec![
792                Some(Variant::from(
793                    DateTime::from_timestamp(-5, 439).unwrap().naive_utc()
794                )),
795                None,
796                Some(Variant::from("n/a")),
797                Some(Variant::from(
798                    DateTime::parse_from_rfc3339("2025-09-23T12:34:56+08:00")
799                        .unwrap()
800                        .naive_utc()
801                )),
802            ]
803        )
804    }
805
806    partially_shredded_variant_array_gen!(partially_shredded_timestamp_nano_variant_array, || {
807        arrow::array::TimestampNanosecondArray::from(vec![
808            Some(-4999999561),
809            None,
810            None,
811            Some(1758602096000000000),
812        ])
813        .with_timezone("+00:00")
814    });
815
816    #[test]
817    fn get_variant_partial_shredded_timestamp_nano_as_variant() {
818        let array = partially_shredded_timestamp_nano_variant_array();
819        assert_variant_get_as_variant_array_with_default_option!(
820            array,
821            vec![
822                Some(Variant::from(
823                    DateTime::from_timestamp(-5, 439).unwrap().to_utc()
824                )),
825                None,
826                Some(Variant::from("n/a")),
827                Some(Variant::from(
828                    DateTime::parse_from_rfc3339("2025-09-23T12:34:56+08:00")
829                        .unwrap()
830                        .to_utc()
831                )),
832            ]
833        )
834    }
835
836    /// Shredding: extract a value as an Int32Array
837    #[test]
838    fn get_variant_shredded_int32_as_int32_safe_cast() {
839        // Extract the typed value as Int32Array
840        let array = partially_shredded_int32_variant_array();
841        // specify we want the typed value as Int32
842        let field = Field::new("typed_value", DataType::Int32, true);
843        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
844        let result = variant_get(&array, options).unwrap();
845        let expected: ArrayRef = Arc::new(Int32Array::from(vec![
846            Some(34),
847            None,
848            None, // "n/a" is not an Int32 so converted to null
849            Some(100),
850        ]));
851        assert_eq!(&result, &expected)
852    }
853
854    /// Shredding: extract a value as an Int32Array, unsafe cast (should error on "n/a")
855    #[test]
856    fn get_variant_shredded_int32_as_int32_unsafe_cast() {
857        // Extract the typed value as Int32Array
858        let array = partially_shredded_int32_variant_array();
859        let field = Field::new("typed_value", DataType::Int32, true);
860        let cast_options = CastOptions {
861            safe: false, // unsafe cast
862            ..Default::default()
863        };
864        let options = GetOptions::new()
865            .with_as_type(Some(FieldRef::from(field)))
866            .with_cast_options(cast_options);
867
868        let err = variant_get(&array, options).unwrap_err();
869        // TODO make this error message nicer (not Debug format)
870        assert_eq!(
871            err.to_string(),
872            "Cast error: Failed to extract primitive of type Int32 from variant ShortString(ShortString(\"n/a\")) at path VariantPath([])"
873        );
874    }
875
876    /// Perfect Shredding: extract the typed value as a VariantArray
877    macro_rules! numeric_perfectly_shredded_test {
878        ($primitive_type:ty, $data_fn:ident) => {
879            let array = $data_fn();
880            let options = GetOptions::new();
881            let result = variant_get(&array, options).unwrap();
882
883            // expect the result is a VariantArray
884            let result = VariantArray::try_new(&result).unwrap();
885            assert_eq!(result.len(), 3);
886
887            // Expect the values are the same as the original values
888            assert_eq!(
889                result.value(0),
890                Variant::from(<$primitive_type>::try_from(1u8).unwrap())
891            );
892            assert_eq!(
893                result.value(1),
894                Variant::from(<$primitive_type>::try_from(2u8).unwrap())
895            );
896            assert_eq!(
897                result.value(2),
898                Variant::from(<$primitive_type>::try_from(3u8).unwrap())
899            );
900        };
901    }
902
903    #[test]
904    fn get_variant_perfectly_shredded_int8_as_variant() {
905        numeric_perfectly_shredded_test!(i8, perfectly_shredded_int8_variant_array);
906    }
907
908    #[test]
909    fn get_variant_perfectly_shredded_int16_as_variant() {
910        numeric_perfectly_shredded_test!(i16, perfectly_shredded_int16_variant_array);
911    }
912
913    #[test]
914    fn get_variant_perfectly_shredded_int32_as_variant() {
915        numeric_perfectly_shredded_test!(i32, perfectly_shredded_int32_variant_array);
916    }
917
918    #[test]
919    fn get_variant_perfectly_shredded_int64_as_variant() {
920        numeric_perfectly_shredded_test!(i64, perfectly_shredded_int64_variant_array);
921    }
922
923    #[test]
924    fn get_variant_perfectly_shredded_float32_as_variant() {
925        numeric_perfectly_shredded_test!(f32, perfectly_shredded_float32_variant_array);
926    }
927
928    #[test]
929    fn get_variant_perfectly_shredded_float64_as_variant() {
930        numeric_perfectly_shredded_test!(f64, perfectly_shredded_float64_variant_array);
931    }
932
933    /// AllNull: extract a value as a VariantArray
934    #[test]
935    fn get_variant_all_null_as_variant() {
936        let array = all_null_variant_array();
937        let options = GetOptions::new();
938        let result = variant_get(&array, options).unwrap();
939
940        // expect the result is a VariantArray
941        let result = VariantArray::try_new(&result).unwrap();
942        assert_eq!(result.len(), 3);
943
944        // All values should be null
945        assert!(!result.is_valid(0));
946        assert!(!result.is_valid(1));
947        assert!(!result.is_valid(2));
948    }
949
950    /// AllNull: extract a value as an Int32Array
951    #[test]
952    fn get_variant_all_null_as_int32() {
953        let array = all_null_variant_array();
954        // specify we want the typed value as Int32
955        let field = Field::new("typed_value", DataType::Int32, true);
956        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
957        let result = variant_get(&array, options).unwrap();
958
959        let expected: ArrayRef = Arc::new(Int32Array::from(vec![
960            Option::<i32>::None,
961            Option::<i32>::None,
962            Option::<i32>::None,
963        ]));
964        assert_eq!(&result, &expected)
965    }
966
967    macro_rules! perfectly_shredded_to_arrow_primitive_test {
968        ($name:ident, $primitive_type:expr, $perfectly_shredded_array_gen_fun:ident, $expected_array:expr) => {
969            #[test]
970            fn $name() {
971                let array = $perfectly_shredded_array_gen_fun();
972                let field = Field::new("typed_value", $primitive_type, true);
973                let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
974                let result = variant_get(&array, options).unwrap();
975                let expected_array: ArrayRef = Arc::new($expected_array);
976                assert_eq!(&result, &expected_array);
977            }
978        };
979    }
980
981    perfectly_shredded_to_arrow_primitive_test!(
982        get_variant_perfectly_shredded_int18_as_int8,
983        Int8,
984        perfectly_shredded_int8_variant_array,
985        Int8Array::from(vec![Some(1), Some(2), Some(3)])
986    );
987
988    perfectly_shredded_to_arrow_primitive_test!(
989        get_variant_perfectly_shredded_int16_as_int16,
990        Int16,
991        perfectly_shredded_int16_variant_array,
992        Int16Array::from(vec![Some(1), Some(2), Some(3)])
993    );
994
995    perfectly_shredded_to_arrow_primitive_test!(
996        get_variant_perfectly_shredded_int32_as_int32,
997        Int32,
998        perfectly_shredded_int32_variant_array,
999        Int32Array::from(vec![Some(1), Some(2), Some(3)])
1000    );
1001
1002    perfectly_shredded_to_arrow_primitive_test!(
1003        get_variant_perfectly_shredded_int64_as_int64,
1004        Int64,
1005        perfectly_shredded_int64_variant_array,
1006        Int64Array::from(vec![Some(1), Some(2), Some(3)])
1007    );
1008
1009    perfectly_shredded_to_arrow_primitive_test!(
1010        get_variant_perfectly_shredded_float32_as_float32,
1011        Float32,
1012        perfectly_shredded_float32_variant_array,
1013        Float32Array::from(vec![Some(1.0), Some(2.0), Some(3.0)])
1014    );
1015
1016    perfectly_shredded_to_arrow_primitive_test!(
1017        get_variant_perfectly_shredded_float64_as_float64,
1018        Float64,
1019        perfectly_shredded_float64_variant_array,
1020        Float64Array::from(vec![Some(1.0), Some(2.0), Some(3.0)])
1021    );
1022
1023    perfectly_shredded_to_arrow_primitive_test!(
1024        get_variant_perfectly_shredded_boolean_as_boolean,
1025        Boolean,
1026        perfectly_shredded_bool_variant_array,
1027        BooleanArray::from(vec![Some(true), Some(false), Some(true)])
1028    );
1029
1030    perfectly_shredded_to_arrow_primitive_test!(
1031        get_variant_perfectly_shredded_utf8_as_utf8,
1032        DataType::Utf8,
1033        perfectly_shredded_utf8_variant_array,
1034        StringArray::from(vec![Some("foo"), Some("bar"), Some("baz")])
1035    );
1036
1037    perfectly_shredded_to_arrow_primitive_test!(
1038        get_variant_perfectly_shredded_large_utf8_as_utf8,
1039        DataType::Utf8,
1040        perfectly_shredded_large_utf8_variant_array,
1041        StringArray::from(vec![Some("foo"), Some("bar"), Some("baz")])
1042    );
1043
1044    perfectly_shredded_to_arrow_primitive_test!(
1045        get_variant_perfectly_shredded_utf8_view_as_utf8,
1046        DataType::Utf8,
1047        perfectly_shredded_utf8_view_variant_array,
1048        StringArray::from(vec![Some("foo"), Some("bar"), Some("baz")])
1049    );
1050
1051    macro_rules! perfectly_shredded_variant_array_fn {
1052        ($func:ident, $typed_value_gen:expr) => {
1053            fn $func() -> ArrayRef {
1054                // Prefer producing fixtures with shred_variant from unshredded input.
1055                // Fall back for remaining non-shreddable test-only Arrow types (currently Null).
1056                let typed_value: ArrayRef = Arc::new($typed_value_gen());
1057                if let Some(shredded) = cast_to_variant(typed_value.as_ref())
1058                    .ok()
1059                    .and_then(|unshredded| shred_variant(&unshredded, typed_value.data_type()).ok())
1060                {
1061                    return shredded.into();
1062                }
1063
1064                let metadata = BinaryViewArray::from_iter_values(std::iter::repeat_n(
1065                    EMPTY_VARIANT_METADATA_BYTES,
1066                    typed_value.len(),
1067                ));
1068                VariantArray::from_parts(Arc::new(metadata), None, Some(typed_value), None).into()
1069            }
1070        };
1071    }
1072
1073    perfectly_shredded_variant_array_fn!(perfectly_shredded_utf8_variant_array, || {
1074        StringArray::from(vec![Some("foo"), Some("bar"), Some("baz")])
1075    });
1076
1077    perfectly_shredded_variant_array_fn!(perfectly_shredded_large_utf8_variant_array, || {
1078        LargeStringArray::from(vec![Some("foo"), Some("bar"), Some("baz")])
1079    });
1080
1081    perfectly_shredded_variant_array_fn!(perfectly_shredded_utf8_view_variant_array, || {
1082        StringViewArray::from(vec![Some("foo"), Some("bar"), Some("baz")])
1083    });
1084
1085    perfectly_shredded_variant_array_fn!(perfectly_shredded_bool_variant_array, || {
1086        BooleanArray::from(vec![Some(true), Some(false), Some(true)])
1087    });
1088
1089    /// Return a VariantArray that represents a perfectly "shredded" variant
1090    /// for the given typed value.
1091    ///
1092    /// The schema of the corresponding `StructArray` would look like this:
1093    ///
1094    /// ```text
1095    /// StructArray {
1096    ///   metadata: BinaryViewArray,
1097    ///   typed_value: Int32Array,
1098    /// }
1099    /// ```
1100    macro_rules! numeric_perfectly_shredded_variant_array_fn {
1101        ($func:ident, $array_type:ident, $primitive_type:ty) => {
1102            perfectly_shredded_variant_array_fn!($func, || {
1103                $array_type::from(vec![
1104                    Some(<$primitive_type>::try_from(1u8).unwrap()),
1105                    Some(<$primitive_type>::try_from(2u8).unwrap()),
1106                    Some(<$primitive_type>::try_from(3u8).unwrap()),
1107                ])
1108            });
1109        };
1110    }
1111
1112    numeric_perfectly_shredded_variant_array_fn!(
1113        perfectly_shredded_int8_variant_array,
1114        Int8Array,
1115        i8
1116    );
1117    numeric_perfectly_shredded_variant_array_fn!(
1118        perfectly_shredded_int16_variant_array,
1119        Int16Array,
1120        i16
1121    );
1122    numeric_perfectly_shredded_variant_array_fn!(
1123        perfectly_shredded_int32_variant_array,
1124        Int32Array,
1125        i32
1126    );
1127    numeric_perfectly_shredded_variant_array_fn!(
1128        perfectly_shredded_int64_variant_array,
1129        Int64Array,
1130        i64
1131    );
1132    numeric_perfectly_shredded_variant_array_fn!(
1133        perfectly_shredded_float32_variant_array,
1134        Float32Array,
1135        f32
1136    );
1137    numeric_perfectly_shredded_variant_array_fn!(
1138        perfectly_shredded_float64_variant_array,
1139        Float64Array,
1140        f64
1141    );
1142
1143    perfectly_shredded_variant_array_fn!(
1144        perfectly_shredded_timestamp_micro_ntz_variant_array,
1145        || {
1146            arrow::array::TimestampMicrosecondArray::from(vec![
1147                Some(-456000),
1148                Some(1758602096000001),
1149                Some(1758602096000002),
1150            ])
1151        }
1152    );
1153
1154    perfectly_shredded_to_arrow_primitive_test!(
1155        get_variant_perfectly_shredded_timestamp_micro_ntz_as_timestamp_micro_ntz,
1156        DataType::Timestamp(TimeUnit::Microsecond, None),
1157        perfectly_shredded_timestamp_micro_ntz_variant_array,
1158        arrow::array::TimestampMicrosecondArray::from(vec![
1159            Some(-456000),
1160            Some(1758602096000001),
1161            Some(1758602096000002),
1162        ])
1163    );
1164
1165    // test converting micro to nano
1166    perfectly_shredded_to_arrow_primitive_test!(
1167        get_variant_perfectly_shredded_timestamp_micro_ntz_as_nano_ntz,
1168        DataType::Timestamp(TimeUnit::Nanosecond, None),
1169        perfectly_shredded_timestamp_micro_ntz_variant_array,
1170        arrow::array::TimestampNanosecondArray::from(vec![
1171            Some(-456000000),
1172            Some(1758602096000001000),
1173            Some(1758602096000002000)
1174        ])
1175    );
1176
1177    perfectly_shredded_variant_array_fn!(perfectly_shredded_timestamp_micro_variant_array, || {
1178        arrow::array::TimestampMicrosecondArray::from(vec![
1179            Some(-456000),
1180            Some(1758602096000001),
1181            Some(1758602096000002),
1182        ])
1183        .with_timezone("+00:00")
1184    });
1185
1186    perfectly_shredded_to_arrow_primitive_test!(
1187        get_variant_perfectly_shredded_timestamp_micro_as_timestamp_micro,
1188        DataType::Timestamp(TimeUnit::Microsecond, Some(Arc::from("+00:00"))),
1189        perfectly_shredded_timestamp_micro_variant_array,
1190        arrow::array::TimestampMicrosecondArray::from(vec![
1191            Some(-456000),
1192            Some(1758602096000001),
1193            Some(1758602096000002),
1194        ])
1195        .with_timezone("+00:00")
1196    );
1197
1198    // test converting micro to nano
1199    perfectly_shredded_to_arrow_primitive_test!(
1200        get_variant_perfectly_shredded_timestamp_micro_as_nano,
1201        DataType::Timestamp(TimeUnit::Nanosecond, Some(Arc::from("+00:00"))),
1202        perfectly_shredded_timestamp_micro_variant_array,
1203        arrow::array::TimestampNanosecondArray::from(vec![
1204            Some(-456000000),
1205            Some(1758602096000001000),
1206            Some(1758602096000002000)
1207        ])
1208        .with_timezone("+00:00")
1209    );
1210
1211    perfectly_shredded_variant_array_fn!(
1212        perfectly_shredded_timestamp_nano_ntz_variant_array,
1213        || {
1214            arrow::array::TimestampNanosecondArray::from(vec![
1215                Some(-4999999561),
1216                Some(1758602096000000001),
1217                Some(1758602096000000002),
1218            ])
1219        }
1220    );
1221
1222    perfectly_shredded_variant_array_fn!(
1223        perfectly_shredded_timestamp_micro_variant_array_for_second_and_milli_second,
1224        || {
1225            arrow::array::TimestampMicrosecondArray::from(vec![
1226                Some(1234),       // can't be cast to second & millisecond
1227                Some(1234000),    // can be cast to millisecond, but not second
1228                Some(1234000000), // can be cast to second & millisecond
1229            ])
1230            .with_timezone("+00:00")
1231        }
1232    );
1233
1234    // The following two tests wants to cover the micro with timezone -> milli/second cases
1235    // there are three test items, which contains some items can be cast safely, and some can't
1236    perfectly_shredded_to_arrow_primitive_test!(
1237        get_variant_perfectly_shredded_timestamp_micro_as_timestamp_second,
1238        DataType::Timestamp(TimeUnit::Second, Some(Arc::from("+00:00"))),
1239        perfectly_shredded_timestamp_micro_variant_array_for_second_and_milli_second,
1240        arrow::array::TimestampSecondArray::from(vec![
1241            None,
1242            None, // Return None if can't be cast to second safely
1243            Some(1234)
1244        ])
1245        .with_timezone("+00:00")
1246    );
1247
1248    perfectly_shredded_to_arrow_primitive_test!(
1249        get_variant_perfectly_shredded_timestamp_micro_as_timestamp_milli,
1250        DataType::Timestamp(TimeUnit::Millisecond, Some(Arc::from("+00:00"))),
1251        perfectly_shredded_timestamp_micro_variant_array_for_second_and_milli_second,
1252        arrow::array::TimestampMillisecondArray::from(vec![
1253            None, // Return None if can't be cast to millisecond safely
1254            Some(1234),
1255            Some(1234000)
1256        ])
1257        .with_timezone("+00:00")
1258    );
1259
1260    perfectly_shredded_variant_array_fn!(
1261        perfectly_shredded_timestamp_micro_ntz_variant_array_for_second_and_milli_second,
1262        || {
1263            arrow::array::TimestampMicrosecondArray::from(vec![
1264                Some(1234),       // can't be cast to second & millisecond
1265                Some(1234000),    // can be cast to millisecond, but not second
1266                Some(1234000000), // can be cast to second & millisecond
1267            ])
1268        }
1269    );
1270
1271    // The following two tests wants to cover the micro_ntz -> milli/second cases
1272    // there are three test items, which contains some items can be cast safely, and some can't
1273    perfectly_shredded_to_arrow_primitive_test!(
1274        get_variant_perfectly_shredded_timestamp_micro_ntz_as_timestamp_second,
1275        DataType::Timestamp(TimeUnit::Second, None),
1276        perfectly_shredded_timestamp_micro_ntz_variant_array_for_second_and_milli_second,
1277        arrow::array::TimestampSecondArray::from(vec![
1278            None,
1279            None, // Return None if can't be cast to second safely
1280            Some(1234)
1281        ])
1282    );
1283
1284    perfectly_shredded_to_arrow_primitive_test!(
1285        get_variant_perfectly_shredded_timestamp_micro_ntz_as_timestamp_milli,
1286        DataType::Timestamp(TimeUnit::Millisecond, None),
1287        perfectly_shredded_timestamp_micro_ntz_variant_array_for_second_and_milli_second,
1288        arrow::array::TimestampMillisecondArray::from(vec![
1289            None, // Return None if can't be cast to millisecond safely
1290            Some(1234),
1291            Some(1234000)
1292        ])
1293    );
1294
1295    perfectly_shredded_variant_array_fn!(
1296        perfectly_shredded_timestamp_nano_variant_array_for_second_and_milli_second,
1297        || {
1298            arrow::array::TimestampNanosecondArray::from(vec![
1299                Some(1234000),       // can't be cast to second & millisecond
1300                Some(1234000000),    // can be cast to millisecond, but not second
1301                Some(1234000000000), // can be cast to second & millisecond
1302            ])
1303            .with_timezone("+00:00")
1304        }
1305    );
1306
1307    // The following two tests wants to cover the nano with timezone -> milli/second cases
1308    // there are three test items, which contains some items can be cast safely, and some can't
1309    perfectly_shredded_to_arrow_primitive_test!(
1310        get_variant_perfectly_shredded_timestamp_nano_as_timestamp_second,
1311        DataType::Timestamp(TimeUnit::Second, Some(Arc::from("+00:00"))),
1312        perfectly_shredded_timestamp_nano_variant_array_for_second_and_milli_second,
1313        arrow::array::TimestampSecondArray::from(vec![
1314            None,
1315            None, // Return None if can't be cast to second safely
1316            Some(1234)
1317        ])
1318        .with_timezone("+00:00")
1319    );
1320
1321    perfectly_shredded_to_arrow_primitive_test!(
1322        get_variant_perfectly_shredded_timestamp_nano_as_timestamp_milli,
1323        DataType::Timestamp(TimeUnit::Millisecond, Some(Arc::from("+00:00"))),
1324        perfectly_shredded_timestamp_nano_variant_array_for_second_and_milli_second,
1325        arrow::array::TimestampMillisecondArray::from(vec![
1326            None, // Return None if can't be cast to millisecond safely
1327            Some(1234),
1328            Some(1234000)
1329        ])
1330        .with_timezone("+00:00")
1331    );
1332
1333    perfectly_shredded_variant_array_fn!(
1334        perfectly_shredded_timestamp_nano_ntz_variant_array_for_second_and_milli_second,
1335        || {
1336            arrow::array::TimestampNanosecondArray::from(vec![
1337                Some(1234000),       // can't be cast to second & millisecond
1338                Some(1234000000),    // can be cast to millisecond, but not second
1339                Some(1234000000000), // can be cast to second & millisecond
1340            ])
1341        }
1342    );
1343
1344    // The following two tests wants to cover the nano_ntz -> milli/second cases
1345    // there are three test items, which contains some items can be cast safely, and some can't
1346    perfectly_shredded_to_arrow_primitive_test!(
1347        get_variant_perfectly_shredded_timestamp_nano_ntz_as_timestamp_second,
1348        DataType::Timestamp(TimeUnit::Second, None),
1349        perfectly_shredded_timestamp_nano_ntz_variant_array_for_second_and_milli_second,
1350        arrow::array::TimestampSecondArray::from(vec![
1351            None,
1352            None, // Return None if can't be cast to second safely
1353            Some(1234)
1354        ])
1355    );
1356
1357    perfectly_shredded_to_arrow_primitive_test!(
1358        get_variant_perfectly_shredded_timestamp_nano_ntz_as_timestamp_milli,
1359        DataType::Timestamp(TimeUnit::Millisecond, None),
1360        perfectly_shredded_timestamp_nano_ntz_variant_array_for_second_and_milli_second,
1361        arrow::array::TimestampMillisecondArray::from(vec![
1362            None, // Return None if can't be cast to millisecond safely
1363            Some(1234),
1364            Some(1234000)
1365        ])
1366    );
1367
1368    perfectly_shredded_to_arrow_primitive_test!(
1369        get_variant_perfectly_shredded_timestamp_nano_ntz_as_timestamp_nano_ntz,
1370        DataType::Timestamp(TimeUnit::Nanosecond, None),
1371        perfectly_shredded_timestamp_nano_ntz_variant_array,
1372        arrow::array::TimestampNanosecondArray::from(vec![
1373            Some(-4999999561),
1374            Some(1758602096000000001),
1375            Some(1758602096000000002),
1376        ])
1377    );
1378
1379    perfectly_shredded_variant_array_fn!(perfectly_shredded_timestamp_nano_variant_array, || {
1380        arrow::array::TimestampNanosecondArray::from(vec![
1381            Some(-4999999561),
1382            Some(1758602096000000001),
1383            Some(1758602096000000002),
1384        ])
1385        .with_timezone("+00:00")
1386    });
1387
1388    perfectly_shredded_to_arrow_primitive_test!(
1389        get_variant_perfectly_shredded_timestamp_nano_as_timestamp_nano,
1390        DataType::Timestamp(TimeUnit::Nanosecond, Some(Arc::from("+00:00"))),
1391        perfectly_shredded_timestamp_nano_variant_array,
1392        arrow::array::TimestampNanosecondArray::from(vec![
1393            Some(-4999999561),
1394            Some(1758602096000000001),
1395            Some(1758602096000000002),
1396        ])
1397        .with_timezone("+00:00")
1398    );
1399
1400    perfectly_shredded_variant_array_fn!(perfectly_shredded_date_variant_array, || {
1401        Date32Array::from(vec![Some(-12345), Some(17586), Some(20000)])
1402    });
1403
1404    perfectly_shredded_to_arrow_primitive_test!(
1405        get_variant_perfectly_shredded_date_as_date,
1406        DataType::Date32,
1407        perfectly_shredded_date_variant_array,
1408        Date32Array::from(vec![Some(-12345), Some(17586), Some(20000)])
1409    );
1410
1411    perfectly_shredded_to_arrow_primitive_test!(
1412        get_variant_perfectly_shredded_date_as_date64,
1413        DataType::Date64,
1414        perfectly_shredded_date_variant_array,
1415        Date64Array::from(vec![
1416            Some(-1066608000000),
1417            Some(1519430400000),
1418            Some(1728000000000)
1419        ])
1420    );
1421
1422    perfectly_shredded_variant_array_fn!(perfectly_shredded_time_variant_array, || {
1423        Time64MicrosecondArray::from(vec![Some(12345000), Some(87654000), Some(135792000)])
1424    });
1425
1426    perfectly_shredded_to_arrow_primitive_test!(
1427        get_variant_perfectly_shredded_time_as_time,
1428        DataType::Time64(TimeUnit::Microsecond),
1429        perfectly_shredded_time_variant_array,
1430        Time64MicrosecondArray::from(vec![Some(12345000), Some(87654000), Some(135792000)])
1431    );
1432
1433    perfectly_shredded_to_arrow_primitive_test!(
1434        get_variant_perfectly_shredded_time_as_time64_nano,
1435        DataType::Time64(TimeUnit::Nanosecond),
1436        perfectly_shredded_time_variant_array,
1437        Time64NanosecondArray::from(vec![
1438            Some(12345000000),
1439            Some(87654000000),
1440            Some(135792000000)
1441        ])
1442    );
1443
1444    perfectly_shredded_variant_array_fn!(perfectly_shredded_time_variant_array_for_time32, || {
1445        Time64MicrosecondArray::from(vec![
1446            Some(1234),        // This can't be cast to Time32 losslessly
1447            Some(7654000),     // This can be cast to Time32(Millisecond), but not Time32(Second)
1448            Some(35792000000), // This can be cast to Time32(Second) & Time32(Millisecond)
1449        ])
1450    });
1451
1452    perfectly_shredded_to_arrow_primitive_test!(
1453        get_variant_perfectly_shredded_time_as_time32_second,
1454        DataType::Time32(TimeUnit::Second),
1455        perfectly_shredded_time_variant_array_for_time32,
1456        Time32SecondArray::from(vec![
1457            None,
1458            None, // Return None if can't be cast to Time32(Second) safely
1459            Some(35792)
1460        ])
1461    );
1462
1463    perfectly_shredded_to_arrow_primitive_test!(
1464        get_variant_perfectly_shredded_time_as_time32_milli,
1465        DataType::Time32(TimeUnit::Millisecond),
1466        perfectly_shredded_time_variant_array_for_time32,
1467        Time32MillisecondArray::from(vec![
1468            None, // Return None if can't be cast to Time32(Second) safely
1469            Some(7654),
1470            Some(35792000)
1471        ])
1472    );
1473
1474    perfectly_shredded_variant_array_fn!(perfectly_shredded_null_variant_array, || {
1475        let mut builder = NullBuilder::new();
1476        builder.append_nulls(3);
1477        builder.finish()
1478    });
1479
1480    perfectly_shredded_to_arrow_primitive_test!(
1481        get_variant_perfectly_shredded_null_as_null,
1482        DataType::Null,
1483        perfectly_shredded_null_variant_array,
1484        arrow::array::NullArray::new(3)
1485    );
1486
1487    perfectly_shredded_variant_array_fn!(perfectly_shredded_null_variant_array_with_int, || {
1488        Int32Array::from(vec![Some(32), Some(64), Some(48)])
1489    });
1490
1491    // We append null values if type miss match happens in safe mode
1492    perfectly_shredded_to_arrow_primitive_test!(
1493        get_variant_perfectly_shredded_null_with_type_missmatch_in_safe_mode,
1494        DataType::Null,
1495        perfectly_shredded_null_variant_array_with_int,
1496        arrow::array::NullArray::new(3)
1497    );
1498
1499    // We'll return an error if type miss match happens in strict mode
1500    #[test]
1501    fn get_variant_perfectly_shredded_null_as_null_with_type_missmatch_in_strict_mode() {
1502        let array = perfectly_shredded_null_variant_array_with_int();
1503        let field = Field::new("typed_value", DataType::Null, true);
1504        let options = GetOptions::new()
1505            .with_as_type(Some(FieldRef::from(field)))
1506            .with_cast_options(CastOptions {
1507                safe: false,
1508                format_options: FormatOptions::default(),
1509            });
1510
1511        let result = variant_get(&array, options);
1512
1513        assert!(result.is_err());
1514        let error_msg = format!("{}", result.unwrap_err());
1515        assert!(
1516            error_msg
1517                .contains("Cast error: Failed to extract primitive of type Null from variant Int32(32) at path VariantPath([])"),
1518            "Expected=[Cast error: Failed to extract primitive of type Null from variant Int32(32) at path VariantPath([])],\
1519                Got error message=[{}]",
1520            error_msg
1521        );
1522    }
1523
1524    perfectly_shredded_variant_array_fn!(perfectly_shredded_decimal4_variant_array, || {
1525        Decimal32Array::from(vec![Some(12345), Some(23400), Some(-12342)])
1526            .with_precision_and_scale(5, 2)
1527            .unwrap()
1528    });
1529
1530    perfectly_shredded_to_arrow_primitive_test!(
1531        get_variant_perfectly_shredded_decimal4_as_decimal4,
1532        DataType::Decimal32(5, 2),
1533        perfectly_shredded_decimal4_variant_array,
1534        Decimal32Array::from(vec![Some(12345), Some(23400), Some(-12342)])
1535            .with_precision_and_scale(5, 2)
1536            .unwrap()
1537    );
1538
1539    perfectly_shredded_variant_array_fn!(
1540        perfectly_shredded_decimal8_variant_array_cast2decimal32,
1541        || {
1542            Decimal64Array::from(vec![Some(123456), Some(145678), Some(-123456)])
1543                .with_precision_and_scale(6, 1)
1544                .unwrap()
1545        }
1546    );
1547
1548    // The input will be cast to Decimal32 when transformed to Variant
1549    // This tests will covert the logic DataType::Decimal64(the original array)
1550    // -> Variant::Decimal4(VariantArray) -> DataType::Decimal64(the result array)
1551    perfectly_shredded_to_arrow_primitive_test!(
1552        get_variant_perfectly_shredded_decimal8_through_decimal32_as_decimal8,
1553        DataType::Decimal64(6, 1),
1554        perfectly_shredded_decimal8_variant_array_cast2decimal32,
1555        Decimal64Array::from(vec![Some(123456), Some(145678), Some(-123456)])
1556            .with_precision_and_scale(6, 1)
1557            .unwrap()
1558    );
1559
1560    // This tests will covert the logic DataType::Decimal64(the original array)
1561    //  -> Variant::Decimal8(VariantArray) -> DataType::Decimal64(the result array)
1562    perfectly_shredded_variant_array_fn!(perfectly_shredded_decimal8_variant_array, || {
1563        Decimal64Array::from(vec![Some(1234567809), Some(1456787000), Some(-1234561203)])
1564            .with_precision_and_scale(10, 1)
1565            .unwrap()
1566    });
1567
1568    perfectly_shredded_to_arrow_primitive_test!(
1569        get_variant_perfectly_shredded_decimal8_as_decimal8,
1570        DataType::Decimal64(10, 1),
1571        perfectly_shredded_decimal8_variant_array,
1572        Decimal64Array::from(vec![Some(1234567809), Some(1456787000), Some(-1234561203)])
1573            .with_precision_and_scale(10, 1)
1574            .unwrap()
1575    );
1576
1577    // This tests will covert the logic DataType::Decimal128(the original array)
1578    //  -> Variant::Decimal4(VariantArray) -> DataType::Decimal128(the result array)
1579    perfectly_shredded_variant_array_fn!(
1580        perfectly_shredded_decimal16_within_decimal4_variant_array,
1581        || {
1582            Decimal128Array::from(vec![
1583                Some(i128::from(1234589)),
1584                Some(i128::from(2344444)),
1585                Some(i128::from(-1234789)),
1586            ])
1587            .with_precision_and_scale(7, 3)
1588            .unwrap()
1589        }
1590    );
1591
1592    // This tests will covert the logic DataType::Decimal128(the original array)
1593    // -> Variant::Decimal4(VariantArray) -> DataType::Decimal128(the result array)
1594    perfectly_shredded_to_arrow_primitive_test!(
1595        get_variant_perfectly_shredded_decimal16_within_decimal4_as_decimal16,
1596        DataType::Decimal128(7, 3),
1597        perfectly_shredded_decimal16_within_decimal4_variant_array,
1598        Decimal128Array::from(vec![
1599            Some(i128::from(1234589)),
1600            Some(i128::from(2344444)),
1601            Some(i128::from(-1234789)),
1602        ])
1603        .with_precision_and_scale(7, 3)
1604        .unwrap()
1605    );
1606
1607    perfectly_shredded_variant_array_fn!(
1608        perfectly_shredded_decimal16_within_decimal8_variant_array,
1609        || {
1610            Decimal128Array::from(vec![Some(1234567809), Some(1456787000), Some(-1234561203)])
1611                .with_precision_and_scale(10, 1)
1612                .unwrap()
1613        }
1614    );
1615
1616    // This tests will covert the logic DataType::Decimal128(the original array)
1617    // -> Variant::Decimal8(VariantArray) -> DataType::Decimal128(the result array)
1618    perfectly_shredded_to_arrow_primitive_test!(
1619        get_variant_perfectly_shredded_decimal16_within8_as_decimal16,
1620        DataType::Decimal128(10, 1),
1621        perfectly_shredded_decimal16_within_decimal8_variant_array,
1622        Decimal128Array::from(vec![Some(1234567809), Some(1456787000), Some(-1234561203)])
1623            .with_precision_and_scale(10, 1)
1624            .unwrap()
1625    );
1626
1627    perfectly_shredded_variant_array_fn!(perfectly_shredded_decimal16_variant_array, || {
1628        Decimal128Array::from(vec![
1629            Some(i128::from_str("12345678901234567899").unwrap()),
1630            Some(i128::from_str("23445677483748324300").unwrap()),
1631            Some(i128::from_str("-12345678901234567899").unwrap()),
1632        ])
1633        .with_precision_and_scale(20, 3)
1634        .unwrap()
1635    });
1636
1637    // This tests will covert the logic DataType::Decimal128(the original array)
1638    // -> Variant::Decimal16(VariantArray) -> DataType::Decimal128(the result array)
1639    perfectly_shredded_to_arrow_primitive_test!(
1640        get_variant_perfectly_shredded_decimal16_as_decimal16,
1641        DataType::Decimal128(20, 3),
1642        perfectly_shredded_decimal16_variant_array,
1643        Decimal128Array::from(vec![
1644            Some(i128::from_str("12345678901234567899").unwrap()),
1645            Some(i128::from_str("23445677483748324300").unwrap()),
1646            Some(i128::from_str("-12345678901234567899").unwrap())
1647        ])
1648        .with_precision_and_scale(20, 3)
1649        .unwrap()
1650    );
1651
1652    perfectly_shredded_variant_array_fn!(perfectly_shredded_binary_variant_array, || {
1653        BinaryArray::from(vec![
1654            Some(b"Apache" as &[u8]),
1655            Some(b"Arrow-rs" as &[u8]),
1656            Some(b"Parquet-variant" as &[u8]),
1657        ])
1658    });
1659
1660    perfectly_shredded_to_arrow_primitive_test!(
1661        get_variant_perfectly_shredded_binary_as_binary,
1662        DataType::Binary,
1663        perfectly_shredded_binary_variant_array,
1664        BinaryArray::from(vec![
1665            Some(b"Apache" as &[u8]),
1666            Some(b"Arrow-rs" as &[u8]),
1667            Some(b"Parquet-variant" as &[u8]),
1668        ])
1669    );
1670
1671    perfectly_shredded_variant_array_fn!(perfectly_shredded_large_binary_variant_array, || {
1672        LargeBinaryArray::from(vec![
1673            Some(b"Apache" as &[u8]),
1674            Some(b"Arrow-rs" as &[u8]),
1675            Some(b"Parquet-variant" as &[u8]),
1676        ])
1677    });
1678
1679    perfectly_shredded_to_arrow_primitive_test!(
1680        get_variant_perfectly_shredded_large_binary_as_large_binary,
1681        DataType::LargeBinary,
1682        perfectly_shredded_large_binary_variant_array,
1683        LargeBinaryArray::from(vec![
1684            Some(b"Apache" as &[u8]),
1685            Some(b"Arrow-rs" as &[u8]),
1686            Some(b"Parquet-variant" as &[u8]),
1687        ])
1688    );
1689
1690    perfectly_shredded_variant_array_fn!(perfectly_shredded_binary_view_variant_array, || {
1691        BinaryViewArray::from(vec![
1692            Some(b"Apache" as &[u8]),
1693            Some(b"Arrow-rs" as &[u8]),
1694            Some(b"Parquet-variant" as &[u8]),
1695        ])
1696    });
1697
1698    perfectly_shredded_to_arrow_primitive_test!(
1699        get_variant_perfectly_shredded_binary_view_as_binary_view,
1700        DataType::BinaryView,
1701        perfectly_shredded_binary_view_variant_array,
1702        BinaryViewArray::from(vec![
1703            Some(b"Apache" as &[u8]),
1704            Some(b"Arrow-rs" as &[u8]),
1705            Some(b"Parquet-variant" as &[u8]),
1706        ])
1707    );
1708
1709    /// Return a VariantArray that represents an "all null" variant
1710    /// for the following example (3 null values):
1711    ///
1712    /// ```text
1713    /// null
1714    /// null
1715    /// null
1716    /// ```
1717    ///
1718    /// The schema of the corresponding `StructArray` would look like this:
1719    ///
1720    /// ```text
1721    /// StructArray {
1722    ///   metadata: BinaryViewArray,
1723    /// }
1724    /// ```
1725    fn all_null_variant_array() -> ArrayRef {
1726        let nulls = NullBuffer::from(vec![
1727            false, // row 0 is null
1728            false, // row 1 is null
1729            false, // row 2 is null
1730        ]);
1731
1732        // metadata is the same for all rows (though they're all null)
1733        let metadata =
1734            BinaryViewArray::from_iter_values(std::iter::repeat_n(EMPTY_VARIANT_METADATA_BYTES, 3));
1735
1736        ArrayRef::from(VariantArray::from_parts(
1737            Arc::new(metadata),
1738            None,
1739            None,
1740            Some(nulls),
1741        ))
1742    }
1743    /// This test manually constructs a shredded variant array representing objects
1744    /// like {"x": 1, "y": "foo"} and {"x": 42} and tests extracting the "x" field
1745    /// as VariantArray using variant_get.
1746    #[test]
1747    fn test_shredded_object_field_access() {
1748        let array = shredded_object_with_x_field_variant_array();
1749
1750        // Test: Extract the "x" field as VariantArray first
1751        let options = GetOptions::new_with_path(VariantPath::try_from("x").unwrap());
1752        let result = variant_get(&array, options).unwrap();
1753
1754        let result_variant = VariantArray::try_new(&result).unwrap();
1755        assert_eq!(result_variant.len(), 2);
1756
1757        // Row 0: expect x=1
1758        assert_eq!(result_variant.value(0), Variant::Int32(1));
1759        // Row 1: expect x=42
1760        assert_eq!(result_variant.value(1), Variant::Int32(42));
1761    }
1762
1763    /// Test extracting shredded object field with type conversion
1764    #[test]
1765    fn test_shredded_object_field_as_int32() {
1766        let array = shredded_object_with_x_field_variant_array();
1767
1768        // Test: Extract the "x" field as Int32Array (type conversion)
1769        let field = Field::new("x", DataType::Int32, false);
1770        let options = GetOptions::new_with_path(VariantPath::try_from("x").unwrap())
1771            .with_as_type(Some(FieldRef::from(field)));
1772        let result = variant_get(&array, options).unwrap();
1773
1774        // Should get Int32Array
1775        let expected: ArrayRef = Arc::new(Int32Array::from(vec![Some(1), Some(42)]));
1776        assert_eq!(&result, &expected);
1777    }
1778
1779    /// Helper function to create a shredded variant array representing objects
1780    ///
1781    /// This creates an array that represents:
1782    /// Row 0: {"x": 1, "y": "foo"}  (x is shredded, y is in value field)
1783    /// Row 1: {"x": 42}             (x is shredded, perfect shredding)
1784    ///
1785    /// The physical layout follows the shredding spec where:
1786    /// - metadata: contains object metadata
1787    /// - typed_value: StructArray with field "x" (ShreddedVariantFieldArray)
1788    /// - value: contains fallback for unshredded fields like {"y": "foo"}
1789    /// - The "x" field has typed_value=Int32Array and value=NULL (perfect shredding)
1790    fn shredded_object_with_x_field_variant_array() -> ArrayRef {
1791        // Create the base metadata for objects
1792        let (metadata, y_field_value) = {
1793            let mut builder = parquet_variant::VariantBuilder::new();
1794            let mut obj = builder.new_object();
1795            obj.insert("x", Variant::Int32(42));
1796            obj.insert("y", Variant::from("foo"));
1797            obj.finish();
1798            builder.finish()
1799        };
1800
1801        // Create metadata array (same for both rows)
1802        let metadata_array = BinaryViewArray::from_iter_values(std::iter::repeat_n(&metadata, 2));
1803
1804        // Create the main value field per the 3-step shredding spec:
1805        // Step 2: If field not in shredding schema, check value field
1806        // Row 0: {"y": "foo"} (y is not shredded, stays in value for step 2)
1807        // Row 1: {} (empty object - no unshredded fields)
1808        let empty_object_value = {
1809            let mut builder = parquet_variant::VariantBuilder::new();
1810            let obj = builder.new_object();
1811            obj.finish();
1812            let (_, value) = builder.finish();
1813            value
1814        };
1815
1816        let value_array = BinaryViewArray::from(vec![
1817            Some(y_field_value.as_slice()),      // Row 0 has {"y": "foo"}
1818            Some(empty_object_value.as_slice()), // Row 1 has {}
1819        ]);
1820
1821        // Create the "x" field as a ShreddedVariantFieldArray
1822        // This represents the shredded Int32 values for the "x" field
1823        let x_field_typed_value = Int32Array::from(vec![Some(1), Some(42)]);
1824
1825        // For perfect shredding of the x field, no "value" column, only typed_value
1826        let x_field_shredded = ShreddedVariantFieldArray::from_parts(
1827            None,
1828            Some(Arc::new(x_field_typed_value) as ArrayRef),
1829            None,
1830        );
1831
1832        // Create the main typed_value as a struct containing the "x" field
1833        let typed_value_fields = Fields::from(vec![Field::new(
1834            "x",
1835            x_field_shredded.data_type().clone(),
1836            true,
1837        )]);
1838        let typed_value_struct = StructArray::try_new(
1839            typed_value_fields,
1840            vec![ArrayRef::from(x_field_shredded)],
1841            None, // No nulls - both rows have the object structure
1842        )
1843        .unwrap();
1844
1845        // Create the main VariantArray
1846        ArrayRef::from(VariantArray::from_parts(
1847            Arc::new(metadata_array),
1848            Some(Arc::new(value_array)),
1849            Some(Arc::new(typed_value_struct)),
1850            None,
1851        ))
1852    }
1853
1854    /// Simple test to check if nested paths are supported by current implementation
1855    #[test]
1856    fn test_simple_nested_path_support() {
1857        // Check: How does VariantPath parse different strings?
1858        println!("Testing path parsing:");
1859
1860        let path_x = VariantPath::try_from("x").unwrap();
1861        let elements_x: Vec<_> = path_x.iter().collect();
1862        println!("  'x' -> {} elements: {:?}", elements_x.len(), elements_x);
1863
1864        let path_ax = VariantPath::try_from("a.x").unwrap();
1865        let elements_ax: Vec<_> = path_ax.iter().collect();
1866        println!(
1867            "  'a.x' -> {} elements: {:?}",
1868            elements_ax.len(),
1869            elements_ax
1870        );
1871
1872        let path_ax_alt = VariantPath::try_from("$.a.x").unwrap();
1873        let elements_ax_alt: Vec<_> = path_ax_alt.iter().collect();
1874        println!(
1875            "  '$.a.x' -> {} elements: {:?}",
1876            elements_ax_alt.len(),
1877            elements_ax_alt
1878        );
1879
1880        let path_nested = VariantPath::try_from("a").unwrap().join("x");
1881        let elements_nested: Vec<_> = path_nested.iter().collect();
1882        println!(
1883            "  VariantPath::try_from('a').unwrap().join('x') -> {} elements: {:?}",
1884            elements_nested.len(),
1885            elements_nested
1886        );
1887
1888        // Use your existing simple test data but try "a.x" instead of "x"
1889        let array = shredded_object_with_x_field_variant_array();
1890
1891        // Test if variant_get with REAL nested path throws not implemented error
1892        let real_nested_path = VariantPath::try_from("a").unwrap().join("x");
1893        let options = GetOptions::new_with_path(real_nested_path);
1894        let result = variant_get(&array, options);
1895
1896        match result {
1897            Ok(_) => {
1898                println!("Nested path 'a.x' works unexpectedly!");
1899            }
1900            Err(e) => {
1901                println!("Nested path 'a.x' error: {}", e);
1902                if e.to_string().contains("Not yet implemented")
1903                    || e.to_string().contains("NotYetImplemented")
1904                {
1905                    println!("This is expected - nested paths are not implemented");
1906                    return;
1907                }
1908                // Any other error is also expected for now
1909                println!("This shows nested paths need implementation");
1910            }
1911        }
1912    }
1913
1914    /// Test comprehensive variant_get scenarios with Int32 conversion
1915    /// Test depth 0: Direct field access "x" with Int32 conversion
1916    /// Covers shredded vs non-shredded VariantArrays for simple field access
1917    #[test]
1918    fn test_depth_0_int32_conversion() {
1919        println!("=== Testing Depth 0: Direct field access ===");
1920
1921        // Non-shredded test data: [{"x": 42}, {"x": "foo"}, {"y": 10}]
1922        let unshredded_array = create_depth_0_test_data();
1923
1924        let field = Field::new("result", DataType::Int32, true);
1925        let path = VariantPath::try_from("x").unwrap();
1926        let options = GetOptions::new_with_path(path).with_as_type(Some(FieldRef::from(field)));
1927        let result = variant_get(&unshredded_array, options).unwrap();
1928
1929        let expected: ArrayRef = Arc::new(Int32Array::from(vec![
1930            Some(42), // {"x": 42} -> 42
1931            None,     // {"x": "foo"} -> NULL (type mismatch)
1932            None,     // {"y": 10} -> NULL (field missing)
1933        ]));
1934        assert_eq!(&result, &expected);
1935        println!("Depth 0 (unshredded) passed");
1936
1937        // Shredded test data: using simplified approach based on working pattern
1938        let shredded_array = create_depth_0_shredded_test_data_simple();
1939
1940        let field = Field::new("result", DataType::Int32, true);
1941        let path = VariantPath::try_from("x").unwrap();
1942        let options = GetOptions::new_with_path(path).with_as_type(Some(FieldRef::from(field)));
1943        let result = variant_get(&shredded_array, options).unwrap();
1944
1945        let expected: ArrayRef = Arc::new(Int32Array::from(vec![
1946            Some(42), // {"x": 42} -> 42 (from typed_value)
1947            None,     // {"x": "foo"} -> NULL (type mismatch, from value field)
1948        ]));
1949        assert_eq!(&result, &expected);
1950        println!("Depth 0 (shredded) passed");
1951    }
1952
1953    /// Test depth 1: Single nested field access "a.x" with Int32 conversion
1954    /// Covers shredded vs non-shredded VariantArrays for nested field access
1955    #[test]
1956    fn test_depth_1_int32_conversion() {
1957        println!("=== Testing Depth 1: Single nested field access ===");
1958
1959        // Non-shredded test data from the GitHub issue
1960        let unshredded_array = create_nested_path_test_data();
1961
1962        let field = Field::new("result", DataType::Int32, true);
1963        let path = VariantPath::try_from("a.x").unwrap(); // Dot notation!
1964        let options = GetOptions::new_with_path(path).with_as_type(Some(FieldRef::from(field)));
1965        let result = variant_get(&unshredded_array, options).unwrap();
1966
1967        let expected: ArrayRef = Arc::new(Int32Array::from(vec![
1968            Some(55), // {"a": {"x": 55}} -> 55
1969            None,     // {"a": {"x": "foo"}} -> NULL (type mismatch)
1970        ]));
1971        assert_eq!(&result, &expected);
1972        println!("Depth 1 (unshredded) passed");
1973
1974        // Shredded test data: depth 1 nested shredding
1975        let shredded_array = create_depth_1_shredded_test_data_working();
1976
1977        let field = Field::new("result", DataType::Int32, true);
1978        let path = VariantPath::try_from("a.x").unwrap(); // Dot notation!
1979        let options = GetOptions::new_with_path(path).with_as_type(Some(FieldRef::from(field)));
1980        let result = variant_get(&shredded_array, options).unwrap();
1981
1982        let expected: ArrayRef = Arc::new(Int32Array::from(vec![
1983            Some(55), // {"a": {"x": 55}} -> 55 (from nested shredded x)
1984            None,     // {"a": {"x": "foo"}} -> NULL (type mismatch in nested value)
1985        ]));
1986        assert_eq!(&result, &expected);
1987        println!("Depth 1 (shredded) passed");
1988    }
1989
1990    /// Test depth 2: Double nested field access "a.b.x" with Int32 conversion  
1991    /// Covers shredded vs non-shredded VariantArrays for deeply nested field access
1992    #[test]
1993    fn test_depth_2_int32_conversion() {
1994        println!("=== Testing Depth 2: Double nested field access ===");
1995
1996        // Non-shredded test data: [{"a": {"b": {"x": 100}}}, {"a": {"b": {"x": "bar"}}}, {"a": {"b": {"y": 200}}}]
1997        let unshredded_array = create_depth_2_test_data();
1998
1999        let field = Field::new("result", DataType::Int32, true);
2000        let path = VariantPath::try_from("a.b.x").unwrap(); // Double nested dot notation!
2001        let options = GetOptions::new_with_path(path).with_as_type(Some(FieldRef::from(field)));
2002        let result = variant_get(&unshredded_array, options).unwrap();
2003
2004        let expected: ArrayRef = Arc::new(Int32Array::from(vec![
2005            Some(100), // {"a": {"b": {"x": 100}}} -> 100
2006            None,      // {"a": {"b": {"x": "bar"}}} -> NULL (type mismatch)
2007            None,      // {"a": {"b": {"y": 200}}} -> NULL (field missing)
2008        ]));
2009        assert_eq!(&result, &expected);
2010        println!("Depth 2 (unshredded) passed");
2011
2012        // Shredded test data: depth 2 nested shredding
2013        let shredded_array = create_depth_2_shredded_test_data_working();
2014
2015        let field = Field::new("result", DataType::Int32, true);
2016        let path = VariantPath::try_from("a.b.x").unwrap(); // Double nested dot notation!
2017        let options = GetOptions::new_with_path(path).with_as_type(Some(FieldRef::from(field)));
2018        let result = variant_get(&shredded_array, options).unwrap();
2019
2020        let expected: ArrayRef = Arc::new(Int32Array::from(vec![
2021            Some(100), // {"a": {"b": {"x": 100}}} -> 100 (from deeply nested shredded x)
2022            None,      // {"a": {"b": {"x": "bar"}}} -> NULL (type mismatch in deep value)
2023            None,      // {"a": {"b": {"y": 200}}} -> NULL (field missing in deep structure)
2024        ]));
2025        assert_eq!(&result, &expected);
2026        println!("Depth 2 (shredded) passed");
2027    }
2028
2029    /// Test that demonstrates what CURRENTLY WORKS
2030    ///
2031    /// This shows that nested path functionality does work, but only when the
2032    /// test data matches what the current implementation expects
2033    #[test]
2034    fn test_current_nested_path_functionality() {
2035        let array = shredded_object_with_x_field_variant_array();
2036
2037        // Test: Extract the "x" field (single level) - this works
2038        let single_path = VariantPath::try_from("x").unwrap();
2039        let field = Field::new("result", DataType::Int32, true);
2040        let options =
2041            GetOptions::new_with_path(single_path).with_as_type(Some(FieldRef::from(field)));
2042        let result = variant_get(&array, options).unwrap();
2043
2044        println!("Single path 'x' works - result: {:?}", result);
2045
2046        // Test: Try nested path "a.x" - this is what we need to implement
2047        let nested_path = VariantPath::try_from("a").unwrap().join("x");
2048        let field = Field::new("result", DataType::Int32, true);
2049        let options =
2050            GetOptions::new_with_path(nested_path).with_as_type(Some(FieldRef::from(field)));
2051        let result = variant_get(&array, options).unwrap();
2052
2053        println!("Nested path 'a.x' result: {:?}", result);
2054    }
2055
2056    /// Create test data for depth 0 (direct field access)
2057    /// [{"x": 42}, {"x": "foo"}, {"y": 10}]
2058    fn create_depth_0_test_data() -> ArrayRef {
2059        let mut builder = crate::VariantArrayBuilder::new(3);
2060
2061        // Row 1: {"x": 42}
2062        {
2063            let json_str = r#"{"x": 42}"#;
2064            let string_array: ArrayRef = Arc::new(StringArray::from(vec![json_str]));
2065            if let Ok(variant_array) = json_to_variant(&string_array) {
2066                builder.append_variant(variant_array.value(0));
2067            } else {
2068                builder.append_null();
2069            }
2070        }
2071
2072        // Row 2: {"x": "foo"}
2073        {
2074            let json_str = r#"{"x": "foo"}"#;
2075            let string_array: ArrayRef = Arc::new(StringArray::from(vec![json_str]));
2076            if let Ok(variant_array) = json_to_variant(&string_array) {
2077                builder.append_variant(variant_array.value(0));
2078            } else {
2079                builder.append_null();
2080            }
2081        }
2082
2083        // Row 3: {"y": 10} (missing "x" field)
2084        {
2085            let json_str = r#"{"y": 10}"#;
2086            let string_array: ArrayRef = Arc::new(StringArray::from(vec![json_str]));
2087            if let Ok(variant_array) = json_to_variant(&string_array) {
2088                builder.append_variant(variant_array.value(0));
2089            } else {
2090                builder.append_null();
2091            }
2092        }
2093
2094        ArrayRef::from(builder.build())
2095    }
2096
2097    /// Create test data for depth 1 (single nested field)
2098    /// This represents the exact scenarios from the GitHub issue: "a.x"
2099    fn create_nested_path_test_data() -> ArrayRef {
2100        let mut builder = crate::VariantArrayBuilder::new(2);
2101
2102        // Row 1: {"a": {"x": 55}, "b": 42}
2103        {
2104            let json_str = r#"{"a": {"x": 55}, "b": 42}"#;
2105            let string_array: ArrayRef = Arc::new(StringArray::from(vec![json_str]));
2106            if let Ok(variant_array) = json_to_variant(&string_array) {
2107                builder.append_variant(variant_array.value(0));
2108            } else {
2109                builder.append_null();
2110            }
2111        }
2112
2113        // Row 2: {"a": {"x": "foo"}, "b": 42}
2114        {
2115            let json_str = r#"{"a": {"x": "foo"}, "b": 42}"#;
2116            let string_array: ArrayRef = Arc::new(StringArray::from(vec![json_str]));
2117            if let Ok(variant_array) = json_to_variant(&string_array) {
2118                builder.append_variant(variant_array.value(0));
2119            } else {
2120                builder.append_null();
2121            }
2122        }
2123
2124        ArrayRef::from(builder.build())
2125    }
2126
2127    /// Create test data for depth 2 (double nested field)
2128    /// [{"a": {"b": {"x": 100}}}, {"a": {"b": {"x": "bar"}}}, {"a": {"b": {"y": 200}}}]
2129    fn create_depth_2_test_data() -> ArrayRef {
2130        let mut builder = crate::VariantArrayBuilder::new(3);
2131
2132        // Row 1: {"a": {"b": {"x": 100}}}
2133        {
2134            let json_str = r#"{"a": {"b": {"x": 100}}}"#;
2135            let string_array: ArrayRef = Arc::new(StringArray::from(vec![json_str]));
2136            if let Ok(variant_array) = json_to_variant(&string_array) {
2137                builder.append_variant(variant_array.value(0));
2138            } else {
2139                builder.append_null();
2140            }
2141        }
2142
2143        // Row 2: {"a": {"b": {"x": "bar"}}}
2144        {
2145            let json_str = r#"{"a": {"b": {"x": "bar"}}}"#;
2146            let string_array: ArrayRef = Arc::new(StringArray::from(vec![json_str]));
2147            if let Ok(variant_array) = json_to_variant(&string_array) {
2148                builder.append_variant(variant_array.value(0));
2149            } else {
2150                builder.append_null();
2151            }
2152        }
2153
2154        // Row 3: {"a": {"b": {"y": 200}}} (missing "x" field)
2155        {
2156            let json_str = r#"{"a": {"b": {"y": 200}}}"#;
2157            let string_array: ArrayRef = Arc::new(StringArray::from(vec![json_str]));
2158            if let Ok(variant_array) = json_to_variant(&string_array) {
2159                builder.append_variant(variant_array.value(0));
2160            } else {
2161                builder.append_null();
2162            }
2163        }
2164
2165        ArrayRef::from(builder.build())
2166    }
2167
2168    /// Create simple shredded test data for depth 0 using a simplified working pattern
2169    /// Creates 2 rows: [{"x": 42}, {"x": "foo"}] with "x" shredded where possible
2170    fn create_depth_0_shredded_test_data_simple() -> ArrayRef {
2171        // Create base metadata using the working pattern
2172        let (metadata, string_x_value) = {
2173            let mut builder = parquet_variant::VariantBuilder::new();
2174            let mut obj = builder.new_object();
2175            obj.insert("x", Variant::from("foo"));
2176            obj.finish();
2177            builder.finish()
2178        };
2179
2180        // Metadata array (same for both rows)
2181        let metadata_array = BinaryViewArray::from_iter_values(std::iter::repeat_n(&metadata, 2));
2182
2183        // Value array following the 3-step shredding spec:
2184        // Row 0: {} (x is shredded, no unshredded fields)
2185        // Row 1: {"x": "foo"} (x is a string, can't be shredded to Int32)
2186        let empty_object_value = {
2187            let mut builder = parquet_variant::VariantBuilder::new();
2188            let obj = builder.new_object();
2189            obj.finish();
2190            let (_, value) = builder.finish();
2191            value
2192        };
2193
2194        let value_array = BinaryViewArray::from(vec![
2195            Some(empty_object_value.as_slice()), // Row 0: {} (x shredded out)
2196            Some(string_x_value.as_slice()),     // Row 1: {"x": "foo"} (fallback)
2197        ]);
2198
2199        // Create the "x" field as a ShreddedVariantFieldArray
2200        let x_field_typed_value = Int32Array::from(vec![Some(42), None]);
2201
2202        // For the x field, only typed_value (perfect shredding when possible)
2203        let x_field_shredded = ShreddedVariantFieldArray::from_parts(
2204            None,
2205            Some(Arc::new(x_field_typed_value) as ArrayRef),
2206            None,
2207        );
2208
2209        // Create the main typed_value as a struct containing the "x" field
2210        let typed_value_fields = Fields::from(vec![Field::new(
2211            "x",
2212            x_field_shredded.data_type().clone(),
2213            true,
2214        )]);
2215        let typed_value_struct = StructArray::try_new(
2216            typed_value_fields,
2217            vec![ArrayRef::from(x_field_shredded)],
2218            None,
2219        )
2220        .unwrap();
2221
2222        // Build final VariantArray
2223        ArrayRef::from(VariantArray::from_parts(
2224            Arc::new(metadata_array),
2225            Some(Arc::new(value_array)),
2226            Some(Arc::new(typed_value_struct)),
2227            None,
2228        ))
2229    }
2230
2231    /// Create working depth 1 shredded test data based on the existing working pattern
2232    /// This creates a properly structured shredded variant for "a.x" where:
2233    /// - Row 0: {"a": {"x": 55}, "b": 42} with a.x shredded into typed_value
2234    /// - Row 1: {"a": {"x": "foo"}, "b": 42} with a.x fallback to value field due to type mismatch
2235    fn create_depth_1_shredded_test_data_working() -> ArrayRef {
2236        // Create metadata following the working pattern from shredded_object_with_x_field_variant_array
2237        let (metadata, _) = {
2238            // Create nested structure: {"a": {"x": 55}, "b": 42}
2239            let mut builder = parquet_variant::VariantBuilder::new();
2240            let mut obj = builder.new_object();
2241
2242            // Create the nested "a" object
2243            let mut a_obj = obj.new_object("a");
2244            a_obj.insert("x", Variant::Int32(55));
2245            a_obj.finish();
2246
2247            obj.insert("b", Variant::Int32(42));
2248            obj.finish();
2249            builder.finish()
2250        };
2251
2252        let metadata_array = BinaryViewArray::from_iter_values(std::iter::repeat_n(&metadata, 2));
2253
2254        // Create value arrays for the fallback case
2255        // Following the spec: if field cannot be shredded, it stays in value
2256        let empty_object_value = {
2257            let mut builder = parquet_variant::VariantBuilder::new();
2258            let obj = builder.new_object();
2259            obj.finish();
2260            let (_, value) = builder.finish();
2261            value
2262        };
2263
2264        // Row 1 fallback: use the working pattern from the existing shredded test
2265        // This avoids metadata issues by using the simple fallback approach
2266        let row1_fallback = {
2267            let mut builder = parquet_variant::VariantBuilder::new();
2268            let mut obj = builder.new_object();
2269            obj.insert("fallback", Variant::from("data"));
2270            obj.finish();
2271            let (_, value) = builder.finish();
2272            value
2273        };
2274
2275        let value_array = BinaryViewArray::from(vec![
2276            Some(empty_object_value.as_slice()), // Row 0: {} (everything shredded except b in unshredded fields)
2277            Some(row1_fallback.as_slice()), // Row 1: {"a": {"x": "foo"}, "b": 42} (a.x can't be shredded)
2278        ]);
2279
2280        // Create the nested shredded structure
2281        // Level 2: x field (the deepest level)
2282        let x_typed_value = Int32Array::from(vec![Some(55), None]);
2283        let x_field_shredded = ShreddedVariantFieldArray::from_parts(
2284            None,
2285            Some(Arc::new(x_typed_value) as ArrayRef),
2286            None,
2287        );
2288
2289        // Level 1: a field containing x field + value field for fallbacks
2290        // The "a" field needs both typed_value (for shredded x) and value (for fallback cases)
2291
2292        // Create the value field for "a" (for cases where a.x can't be shredded)
2293        let a_value_data = {
2294            let mut builder = parquet_variant::VariantBuilder::new();
2295            let obj = builder.new_object();
2296            obj.finish();
2297            let (_, value) = builder.finish();
2298            value
2299        };
2300        let a_value_array = BinaryViewArray::from(vec![
2301            None,                          // Row 0: x is shredded, so no value fallback needed
2302            Some(a_value_data.as_slice()), // Row 1: fallback for a.x="foo" (but logic will check typed_value first)
2303        ]);
2304
2305        let a_inner_fields = Fields::from(vec![Field::new(
2306            "x",
2307            x_field_shredded.data_type().clone(),
2308            true,
2309        )]);
2310        let a_inner_typed_value = Arc::new(
2311            StructArray::try_new(a_inner_fields, vec![ArrayRef::from(x_field_shredded)], None)
2312                .unwrap(),
2313        ) as ArrayRef;
2314        let a_field_shredded = ShreddedVariantFieldArray::from_parts(
2315            Some(Arc::new(a_value_array)),
2316            Some(a_inner_typed_value),
2317            None,
2318        );
2319
2320        // Level 0: main typed_value struct containing a field
2321        let typed_value_fields = Fields::from(vec![Field::new(
2322            "a",
2323            a_field_shredded.data_type().clone(),
2324            true,
2325        )]);
2326        let typed_value_struct = StructArray::try_new(
2327            typed_value_fields,
2328            vec![ArrayRef::from(a_field_shredded)],
2329            None,
2330        )
2331        .unwrap();
2332
2333        // Build final VariantArray
2334        ArrayRef::from(VariantArray::from_parts(
2335            Arc::new(metadata_array),
2336            Some(Arc::new(value_array)),
2337            Some(Arc::new(typed_value_struct)),
2338            None,
2339        ))
2340    }
2341
2342    /// Create working depth 2 shredded test data for "a.b.x" paths
2343    /// This creates a 3-level nested shredded structure where:
2344    /// - Row 0: {"a": {"b": {"x": 100}}} with a.b.x shredded into typed_value
2345    /// - Row 1: {"a": {"b": {"x": "bar"}}} with type mismatch fallback
2346    /// - Row 2: {"a": {"b": {"y": 200}}} with missing field fallback
2347    fn create_depth_2_shredded_test_data_working() -> ArrayRef {
2348        // Create metadata following the working pattern
2349        let (metadata, _) = {
2350            // Create deeply nested structure: {"a": {"b": {"x": 100}}}
2351            let mut builder = parquet_variant::VariantBuilder::new();
2352            let mut obj = builder.new_object();
2353
2354            // Create the nested "a.b" structure
2355            let mut a_obj = obj.new_object("a");
2356            let mut b_obj = a_obj.new_object("b");
2357            b_obj.insert("x", Variant::Int32(100));
2358            b_obj.finish();
2359            a_obj.finish();
2360
2361            obj.finish();
2362            builder.finish()
2363        };
2364
2365        let metadata_array = BinaryViewArray::from_iter_values(std::iter::repeat_n(&metadata, 3));
2366
2367        // Create value arrays for fallback cases
2368        let empty_object_value = {
2369            let mut builder = parquet_variant::VariantBuilder::new();
2370            let obj = builder.new_object();
2371            obj.finish();
2372            let (_, value) = builder.finish();
2373            value
2374        };
2375
2376        // Simple fallback values - avoiding complex nested metadata
2377        let value_array = BinaryViewArray::from(vec![
2378            Some(empty_object_value.as_slice()), // Row 0: fully shredded
2379            Some(empty_object_value.as_slice()), // Row 1: fallback (simplified)
2380            Some(empty_object_value.as_slice()), // Row 2: fallback (simplified)
2381        ]);
2382
2383        // Create the deeply nested shredded structure: a.b.x
2384
2385        // Level 3: x field (deepest level)
2386        let x_typed_value = Int32Array::from(vec![Some(100), None, None]);
2387        let x_field_shredded = ShreddedVariantFieldArray::from_parts(
2388            None,
2389            Some(Arc::new(x_typed_value) as ArrayRef),
2390            None,
2391        );
2392
2393        // Level 2: b field containing x field + value field
2394        let b_value_data = {
2395            let mut builder = parquet_variant::VariantBuilder::new();
2396            let obj = builder.new_object();
2397            obj.finish();
2398            let (_, value) = builder.finish();
2399            value
2400        };
2401        let b_value_array = BinaryViewArray::from(vec![
2402            None,                          // Row 0: x is shredded
2403            Some(b_value_data.as_slice()), // Row 1: fallback for b.x="bar"
2404            Some(b_value_data.as_slice()), // Row 2: fallback for b.y=200
2405        ]);
2406
2407        let b_inner_fields = Fields::from(vec![Field::new(
2408            "x",
2409            x_field_shredded.data_type().clone(),
2410            true,
2411        )]);
2412        let b_inner_typed_value = Arc::new(
2413            StructArray::try_new(b_inner_fields, vec![ArrayRef::from(x_field_shredded)], None)
2414                .unwrap(),
2415        ) as ArrayRef;
2416        let b_field_shredded = ShreddedVariantFieldArray::from_parts(
2417            Some(Arc::new(b_value_array)),
2418            Some(b_inner_typed_value),
2419            None,
2420        );
2421
2422        // Level 1: a field containing b field + value field
2423        let a_value_data = {
2424            let mut builder = parquet_variant::VariantBuilder::new();
2425            let obj = builder.new_object();
2426            obj.finish();
2427            let (_, value) = builder.finish();
2428            value
2429        };
2430        let a_value_array = BinaryViewArray::from(vec![
2431            None,                          // Row 0: b is shredded
2432            Some(a_value_data.as_slice()), // Row 1: fallback for a.b.*
2433            Some(a_value_data.as_slice()), // Row 2: fallback for a.b.*
2434        ]);
2435
2436        let a_inner_fields = Fields::from(vec![Field::new(
2437            "b",
2438            b_field_shredded.data_type().clone(),
2439            true,
2440        )]);
2441        let a_inner_typed_value = Arc::new(
2442            StructArray::try_new(a_inner_fields, vec![ArrayRef::from(b_field_shredded)], None)
2443                .unwrap(),
2444        ) as ArrayRef;
2445        let a_field_shredded = ShreddedVariantFieldArray::from_parts(
2446            Some(Arc::new(a_value_array)),
2447            Some(a_inner_typed_value),
2448            None,
2449        );
2450
2451        // Level 0: main typed_value struct containing a field
2452        let typed_value_fields = Fields::from(vec![Field::new(
2453            "a",
2454            a_field_shredded.data_type().clone(),
2455            true,
2456        )]);
2457        let typed_value_struct = StructArray::try_new(
2458            typed_value_fields,
2459            vec![ArrayRef::from(a_field_shredded)],
2460            None,
2461        )
2462        .unwrap();
2463
2464        // Build final VariantArray
2465        ArrayRef::from(VariantArray::from_parts(
2466            Arc::new(metadata_array),
2467            Some(Arc::new(value_array)),
2468            Some(Arc::new(typed_value_struct)),
2469            None,
2470        ))
2471    }
2472
2473    #[test]
2474    fn test_field_path_non_struct_returns_missing_path_step() {
2475        // Use the existing simple test data that has Int32 as typed_value
2476        let variant_array = perfectly_shredded_int32_variant_array();
2477
2478        for safe in [true, false] {
2479            let options = GetOptions {
2480                path: VariantPath::try_from("nonexistent_field").unwrap(),
2481                as_type: Some(Arc::new(Field::new("result", DataType::Int32, true))),
2482                cast_options: CastOptions {
2483                    safe,
2484                    ..Default::default()
2485                },
2486            };
2487
2488            let result_array = variant_get(&variant_array, options).unwrap();
2489            assert_eq!(result_array.len(), 3);
2490            assert!(result_array.is_null(0));
2491            assert!(result_array.is_null(1));
2492            assert!(result_array.is_null(2));
2493        }
2494    }
2495
2496    #[test]
2497    fn test_error_message_boolean_type_display() {
2498        let mut builder = VariantArrayBuilder::new(1);
2499        builder.append_variant(Variant::from("abcd"));
2500        let variant_array: ArrayRef = ArrayRef::from(builder.build());
2501
2502        // Request Boolean with strict casting to force an error
2503        let options = GetOptions {
2504            path: VariantPath::default(),
2505            as_type: Some(Arc::new(Field::new("result", DataType::Boolean, true))),
2506            cast_options: CastOptions {
2507                safe: false,
2508                ..Default::default()
2509            },
2510        };
2511
2512        let err = variant_get(&variant_array, options).unwrap_err();
2513        let msg = err.to_string();
2514        assert!(msg.contains("Failed to extract primitive of type Boolean"));
2515    }
2516
2517    #[test]
2518    fn test_error_message_numeric_type_display() {
2519        let mut builder = VariantArrayBuilder::new(1);
2520        builder.append_variant(Variant::from("abcd"));
2521        let variant_array: ArrayRef = ArrayRef::from(builder.build());
2522
2523        // Request Float32 with strict casting to force an error
2524        let options = GetOptions {
2525            path: VariantPath::default(),
2526            as_type: Some(Arc::new(Field::new("result", DataType::Float32, true))),
2527            cast_options: CastOptions {
2528                safe: false,
2529                ..Default::default()
2530            },
2531        };
2532
2533        let err = variant_get(&variant_array, options).unwrap_err();
2534        let msg = err.to_string();
2535        assert!(msg.contains("Failed to extract primitive of type Float32"));
2536    }
2537
2538    #[test]
2539    fn test_error_message_temporal_type_display() {
2540        let mut builder = VariantArrayBuilder::new(1);
2541        builder.append_variant(Variant::BooleanFalse);
2542        let variant_array: ArrayRef = ArrayRef::from(builder.build());
2543
2544        // Request Timestamp with strict casting to force an error
2545        let options = GetOptions {
2546            path: VariantPath::default(),
2547            as_type: Some(Arc::new(Field::new(
2548                "result",
2549                DataType::Timestamp(TimeUnit::Nanosecond, None),
2550                true,
2551            ))),
2552            cast_options: CastOptions {
2553                safe: false,
2554                ..Default::default()
2555            },
2556        };
2557
2558        let err = variant_get(&variant_array, options).unwrap_err();
2559        let msg = err.to_string();
2560        assert!(msg.contains("Failed to extract primitive of type Timestamp(ns)"));
2561    }
2562
2563    #[test]
2564    fn test_null_buffer_union_for_shredded_paths() {
2565        // Test that null buffers are properly unioned when traversing shredded paths
2566        // This test verifies scovich's null buffer union requirement
2567
2568        // Create a depth-1 shredded variant array where:
2569        // - The top-level variant array has some nulls
2570        // - The nested typed_value also has some nulls
2571        // - The result should be the union of both null buffers
2572
2573        let variant_array = create_depth_1_shredded_test_data_working();
2574
2575        // Get the field "x" which should union nulls from:
2576        // 1. The top-level variant array nulls
2577        // 2. The "a" field's typed_value nulls
2578        // 3. The "x" field's typed_value nulls
2579        let options = GetOptions {
2580            path: VariantPath::try_from("a.x").unwrap(),
2581            as_type: Some(Arc::new(Field::new("result", DataType::Int32, true))),
2582            cast_options: CastOptions::default(),
2583        };
2584
2585        let result = variant_get(&variant_array, options).unwrap();
2586
2587        // Verify the result length matches input
2588        assert_eq!(result.len(), variant_array.len());
2589
2590        // The null pattern should reflect the union of all ancestor nulls
2591        // Row 0: Should have valid data (path exists and is shredded as Int32)
2592        // Row 1: Should be null (due to type mismatch - "foo" can't cast to Int32)
2593        assert!(!result.is_null(0), "Row 0 should have valid Int32 data");
2594        assert!(
2595            result.is_null(1),
2596            "Row 1 should be null due to type casting failure"
2597        );
2598
2599        // Verify the actual values
2600        let int32_result = result.as_any().downcast_ref::<Int32Array>().unwrap();
2601        assert_eq!(int32_result.value(0), 55); // The valid Int32 value
2602    }
2603
2604    #[test]
2605    fn test_struct_null_mask_union_from_children() {
2606        // Test that struct null masks properly union nulls from children field extractions
2607        // This verifies scovich's concern about incomplete null masks in struct construction
2608
2609        // Create test data where some fields will fail type casting
2610        let json_strings = vec![
2611            r#"{"a": 42, "b": "hello"}"#, // Row 0: a=42 (castable to int), b="hello" (not castable to int)
2612            r#"{"a": "world", "b": 100}"#, // Row 1: a="world" (not castable to int), b=100 (castable to int)
2613            r#"{"a": 55, "b": 77}"#,       // Row 2: a=55 (castable to int), b=77 (castable to int)
2614        ];
2615
2616        let string_array: Arc<dyn arrow::array::Array> = Arc::new(StringArray::from(json_strings));
2617        let variant_array = json_to_variant(&string_array).unwrap();
2618
2619        // Request extraction as a struct with both fields as Int32
2620        // This should create child arrays where some fields are null due to casting failures
2621        let struct_fields = Fields::from(vec![
2622            Field::new("a", DataType::Int32, true),
2623            Field::new("b", DataType::Int32, true),
2624        ]);
2625        let struct_type = DataType::Struct(struct_fields);
2626
2627        let options = GetOptions {
2628            path: VariantPath::default(), // Extract the whole object as struct
2629            as_type: Some(Arc::new(Field::new("result", struct_type, true))),
2630            cast_options: CastOptions::default(),
2631        };
2632
2633        let variant_array_ref = ArrayRef::from(variant_array);
2634        let result = variant_get(&variant_array_ref, options).unwrap();
2635
2636        // Verify the result is a StructArray
2637        let struct_result = result.as_struct();
2638        assert_eq!(struct_result.len(), 3);
2639
2640        // Get the individual field arrays
2641        let field_a = struct_result
2642            .column(0)
2643            .as_any()
2644            .downcast_ref::<Int32Array>()
2645            .unwrap();
2646        let field_b = struct_result
2647            .column(1)
2648            .as_any()
2649            .downcast_ref::<Int32Array>()
2650            .unwrap();
2651
2652        // Verify field values and nulls
2653        // Row 0: a=42 (valid), b=null (casting failure)
2654        assert!(!field_a.is_null(0));
2655        assert_eq!(field_a.value(0), 42);
2656        assert!(field_b.is_null(0)); // "hello" can't cast to int
2657
2658        // Row 1: a=null (casting failure), b=100 (valid)
2659        assert!(field_a.is_null(1)); // "world" can't cast to int
2660        assert!(!field_b.is_null(1));
2661        assert_eq!(field_b.value(1), 100);
2662
2663        // Row 2: a=55 (valid), b=77 (valid)
2664        assert!(!field_a.is_null(2));
2665        assert_eq!(field_a.value(2), 55);
2666        assert!(!field_b.is_null(2));
2667        assert_eq!(field_b.value(2), 77);
2668
2669        // Verify the struct-level null mask properly unions child nulls
2670        // The struct should NOT be null in any row because each row has at least one valid field
2671        // (This tests that we're not incorrectly making the entire struct null when children fail)
2672        assert!(!struct_result.is_null(0)); // Has valid field 'a'
2673        assert!(!struct_result.is_null(1)); // Has valid field 'b'
2674        assert!(!struct_result.is_null(2)); // Has both valid fields
2675    }
2676
2677    #[test]
2678    fn test_field_nullability_preservation() {
2679        // Test that field nullability from GetOptions.as_type is preserved in the result
2680
2681        let json_strings = vec![
2682            r#"{"x": 42}"#,                  // Row 0: Valid int that should convert to Int32
2683            r#"{"x": "not_a_number"}"#,      // Row 1: String that can't cast to Int32
2684            r#"{"x": null}"#,                // Row 2: Explicit null value
2685            r#"{"x": "hello"}"#,             // Row 3: Another string (wrong type)
2686            r#"{"y": 100}"#,                 // Row 4: Missing "x" field (SQL NULL case)
2687            r#"{"x": 127}"#, // Row 5: Small int (could be Int8, widening cast candidate)
2688            r#"{"x": 32767}"#, // Row 6: Medium int (could be Int16, widening cast candidate)
2689            r#"{"x": 2147483647}"#, // Row 7: Max Int32 value (fits in Int32)
2690            r#"{"x": 9223372036854775807}"#, // Row 8: Large Int64 value (cannot convert to Int32)
2691        ];
2692
2693        let string_array: Arc<dyn arrow::array::Array> = Arc::new(StringArray::from(json_strings));
2694        let variant_array = json_to_variant(&string_array).unwrap();
2695
2696        // Test 1: nullable field (should allow nulls from cast failures)
2697        let nullable_field = Arc::new(Field::new("result", DataType::Int32, true));
2698        let options_nullable = GetOptions {
2699            path: VariantPath::try_from("x").unwrap(),
2700            as_type: Some(nullable_field.clone()),
2701            cast_options: CastOptions::default(),
2702        };
2703
2704        let variant_array_ref = ArrayRef::from(variant_array);
2705        let result_nullable = variant_get(&variant_array_ref, options_nullable).unwrap();
2706
2707        // Verify we get an Int32Array with nulls for cast failures
2708        let int32_result = result_nullable
2709            .as_any()
2710            .downcast_ref::<Int32Array>()
2711            .unwrap();
2712        assert_eq!(int32_result.len(), 9);
2713
2714        // Row 0: 42 converts successfully to Int32
2715        assert!(!int32_result.is_null(0));
2716        assert_eq!(int32_result.value(0), 42);
2717
2718        // Row 1: "not_a_number" fails to convert -> NULL
2719        assert!(int32_result.is_null(1));
2720
2721        // Row 2: explicit null value -> NULL
2722        assert!(int32_result.is_null(2));
2723
2724        // Row 3: "hello" (wrong type) fails to convert -> NULL
2725        assert!(int32_result.is_null(3));
2726
2727        // Row 4: missing "x" field (SQL NULL case) -> NULL
2728        assert!(int32_result.is_null(4));
2729
2730        // Row 5: 127 (small int, potential Int8 -> Int32 widening)
2731        // Current behavior: JSON parses to Int8, should convert to Int32
2732        assert!(!int32_result.is_null(5));
2733        assert_eq!(int32_result.value(5), 127);
2734
2735        // Row 6: 32767 (medium int, potential Int16 -> Int32 widening)
2736        // Current behavior: JSON parses to Int16, should convert to Int32
2737        assert!(!int32_result.is_null(6));
2738        assert_eq!(int32_result.value(6), 32767);
2739
2740        // Row 7: 2147483647 (max Int32, fits exactly)
2741        // Current behavior: Should convert successfully
2742        assert!(!int32_result.is_null(7));
2743        assert_eq!(int32_result.value(7), 2147483647);
2744
2745        // Row 8: 9223372036854775807 (large Int64, cannot fit in Int32)
2746        // Current behavior: Should fail conversion -> NULL
2747        assert!(int32_result.is_null(8));
2748
2749        // Test 2: non-nullable field (behavior should be the same with safe casting)
2750        let non_nullable_field = Arc::new(Field::new("result", DataType::Int32, false));
2751        let options_non_nullable = GetOptions {
2752            path: VariantPath::try_from("x").unwrap(),
2753            as_type: Some(non_nullable_field.clone()),
2754            cast_options: CastOptions::default(), // safe=true by default
2755        };
2756
2757        // Create variant array again since we moved it
2758        let variant_array_2 = json_to_variant(&string_array).unwrap();
2759        let variant_array_ref_2 = ArrayRef::from(variant_array_2);
2760        let result_non_nullable = variant_get(&variant_array_ref_2, options_non_nullable).unwrap();
2761        let int32_result_2 = result_non_nullable
2762            .as_any()
2763            .downcast_ref::<Int32Array>()
2764            .unwrap();
2765
2766        // Even with a non-nullable field, safe casting should still produce nulls for failures
2767        assert_eq!(int32_result_2.len(), 9);
2768
2769        // Row 0: 42 converts successfully to Int32
2770        assert!(!int32_result_2.is_null(0));
2771        assert_eq!(int32_result_2.value(0), 42);
2772
2773        // Rows 1-4: All should be null due to safe casting behavior
2774        // (non-nullable field specification doesn't override safe casting behavior)
2775        assert!(int32_result_2.is_null(1)); // "not_a_number"
2776        assert!(int32_result_2.is_null(2)); // explicit null
2777        assert!(int32_result_2.is_null(3)); // "hello"
2778        assert!(int32_result_2.is_null(4)); // missing field
2779
2780        // Rows 5-7: These should also convert successfully (numeric widening/fitting)
2781        assert!(!int32_result_2.is_null(5)); // 127 (Int8 -> Int32)
2782        assert_eq!(int32_result_2.value(5), 127);
2783        assert!(!int32_result_2.is_null(6)); // 32767 (Int16 -> Int32)
2784        assert_eq!(int32_result_2.value(6), 32767);
2785        assert!(!int32_result_2.is_null(7)); // 2147483647 (fits in Int32)
2786        assert_eq!(int32_result_2.value(7), 2147483647);
2787
2788        // Row 8: Large Int64 should fail conversion -> NULL
2789        assert!(int32_result_2.is_null(8)); // 9223372036854775807 (too large for Int32)
2790    }
2791
2792    #[test]
2793    fn test_struct_extraction_subset_superset_schema_perfectly_shredded() {
2794        // Create variant with diverse null patterns and empty objects
2795        let variant_array = create_comprehensive_shredded_variant();
2796
2797        // Request struct with fields "a", "b", "d" (skip existing "c", add missing "d")
2798        let struct_fields = Fields::from(vec![
2799            Field::new("a", DataType::Int32, true),
2800            Field::new("b", DataType::Int32, true),
2801            Field::new("d", DataType::Int32, true),
2802        ]);
2803        let struct_type = DataType::Struct(struct_fields);
2804
2805        let options = GetOptions {
2806            path: VariantPath::default(),
2807            as_type: Some(Arc::new(Field::new("result", struct_type, true))),
2808            cast_options: CastOptions::default(),
2809        };
2810
2811        let result = variant_get(&variant_array, options).unwrap();
2812
2813        // Verify the result is a StructArray with 3 fields and 5 rows
2814        let struct_result = result.as_any().downcast_ref::<StructArray>().unwrap();
2815        assert_eq!(struct_result.len(), 5);
2816        assert_eq!(struct_result.num_columns(), 3);
2817
2818        let field_a = struct_result
2819            .column(0)
2820            .as_any()
2821            .downcast_ref::<Int32Array>()
2822            .unwrap();
2823        let field_b = struct_result
2824            .column(1)
2825            .as_any()
2826            .downcast_ref::<Int32Array>()
2827            .unwrap();
2828        let field_d = struct_result
2829            .column(2)
2830            .as_any()
2831            .downcast_ref::<Int32Array>()
2832            .unwrap();
2833
2834        // Row 0: Normal values {"a": 1, "b": 2, "c": 3} → {a: 1, b: 2, d: NULL}
2835        assert!(!struct_result.is_null(0));
2836        assert_eq!(field_a.value(0), 1);
2837        assert_eq!(field_b.value(0), 2);
2838        assert!(field_d.is_null(0)); // Missing field "d"
2839
2840        // Row 1: Top-level NULL → struct-level NULL
2841        assert!(struct_result.is_null(1));
2842
2843        // Row 2: Field "a" missing → {a: NULL, b: 2, d: NULL}
2844        assert!(!struct_result.is_null(2));
2845        assert!(field_a.is_null(2)); // Missing field "a"
2846        assert_eq!(field_b.value(2), 2);
2847        assert!(field_d.is_null(2)); // Missing field "d"
2848
2849        // Row 3: Field "b" missing → {a: 1, b: NULL, d: NULL}
2850        assert!(!struct_result.is_null(3));
2851        assert_eq!(field_a.value(3), 1);
2852        assert!(field_b.is_null(3)); // Missing field "b"
2853        assert!(field_d.is_null(3)); // Missing field "d"
2854
2855        // Row 4: Empty object {} → {a: NULL, b: NULL, d: NULL}
2856        assert!(!struct_result.is_null(4));
2857        assert!(field_a.is_null(4)); // Empty object
2858        assert!(field_b.is_null(4)); // Empty object
2859        assert!(field_d.is_null(4)); // Missing field "d"
2860    }
2861
2862    #[test]
2863    fn test_nested_struct_extraction_perfectly_shredded() {
2864        // Create nested variant with diverse null patterns
2865        let variant_array = create_comprehensive_nested_shredded_variant();
2866        println!("variant_array: {variant_array:?}");
2867
2868        // Request 3-level nested struct type {"outer": {"inner": INT}}
2869        let inner_field = Field::new("inner", DataType::Int32, true);
2870        let inner_type = DataType::Struct(Fields::from(vec![inner_field]));
2871        let outer_field = Field::new("outer", inner_type, true);
2872        let result_type = DataType::Struct(Fields::from(vec![outer_field]));
2873
2874        let options = GetOptions {
2875            path: VariantPath::default(),
2876            as_type: Some(Arc::new(Field::new("result", result_type, true))),
2877            cast_options: CastOptions::default(),
2878        };
2879
2880        let result = variant_get(&variant_array, options).unwrap();
2881        println!("result: {result:?}");
2882
2883        // Verify the result is a StructArray with "outer" field and 4 rows
2884        let outer_struct = result.as_any().downcast_ref::<StructArray>().unwrap();
2885        assert_eq!(outer_struct.len(), 4);
2886        assert_eq!(outer_struct.num_columns(), 1);
2887
2888        // Get the "inner" struct column
2889        let inner_struct = outer_struct
2890            .column(0)
2891            .as_any()
2892            .downcast_ref::<StructArray>()
2893            .unwrap();
2894        assert_eq!(inner_struct.num_columns(), 1);
2895
2896        // Get the "leaf" field (Int32 values)
2897        let leaf_field = inner_struct
2898            .column(0)
2899            .as_any()
2900            .downcast_ref::<Int32Array>()
2901            .unwrap();
2902
2903        // Row 0: Normal nested {"outer": {"inner": {"leaf": 42}}}
2904        assert!(!outer_struct.is_null(0));
2905        assert!(!inner_struct.is_null(0));
2906        assert_eq!(leaf_field.value(0), 42);
2907
2908        // Row 1: "inner" field missing → {outer: {inner: NULL}}
2909        assert!(!outer_struct.is_null(1));
2910        assert!(!inner_struct.is_null(1)); // outer exists, inner exists but leaf is NULL
2911        assert!(leaf_field.is_null(1)); // leaf field is NULL
2912
2913        // Row 2: "outer" field missing → {outer: NULL}
2914        assert!(!outer_struct.is_null(2));
2915        assert!(inner_struct.is_null(2)); // outer field is NULL
2916
2917        // Row 3: Top-level NULL → struct-level NULL
2918        assert!(outer_struct.is_null(3));
2919    }
2920
2921    #[test]
2922    fn test_path_based_null_masks_one_step() {
2923        // Create nested variant with diverse null patterns
2924        let variant_array = create_comprehensive_nested_shredded_variant();
2925
2926        // Extract "outer" field using path-based variant_get
2927        let path = VariantPath::try_from("outer").unwrap();
2928        let inner_field = Field::new("inner", DataType::Int32, true);
2929        let result_type = DataType::Struct(Fields::from(vec![inner_field]));
2930
2931        let options = GetOptions {
2932            path,
2933            as_type: Some(Arc::new(Field::new("result", result_type, true))),
2934            cast_options: CastOptions::default(),
2935        };
2936
2937        let result = variant_get(&variant_array, options).unwrap();
2938
2939        // Verify the result is a StructArray with "inner" field and 4 rows
2940        let outer_result = result.as_any().downcast_ref::<StructArray>().unwrap();
2941        assert_eq!(outer_result.len(), 4);
2942        assert_eq!(outer_result.num_columns(), 1);
2943
2944        // Get the "inner" field (Int32 values)
2945        let inner_field = outer_result
2946            .column(0)
2947            .as_any()
2948            .downcast_ref::<Int32Array>()
2949            .unwrap();
2950
2951        // Row 0: Normal nested {"outer": {"inner": 42}} → {"inner": 42}
2952        assert!(!outer_result.is_null(0));
2953        assert_eq!(inner_field.value(0), 42);
2954
2955        // Row 1: Inner field null {"outer": {"inner": null}} → {"inner": null}
2956        assert!(!outer_result.is_null(1));
2957        assert!(inner_field.is_null(1));
2958
2959        // Row 2: Outer field null {"outer": null} → null (entire struct is null)
2960        assert!(outer_result.is_null(2));
2961
2962        // Row 3: Top-level null → null (entire struct is null)
2963        assert!(outer_result.is_null(3));
2964    }
2965
2966    #[test]
2967    fn test_path_based_null_masks_two_steps() {
2968        // Create nested variant with diverse null patterns
2969        let variant_array = create_comprehensive_nested_shredded_variant();
2970
2971        // Extract "outer.inner" field using path-based variant_get
2972        let path = VariantPath::try_from("outer").unwrap().join("inner");
2973
2974        let options = GetOptions {
2975            path,
2976            as_type: Some(Arc::new(Field::new("result", DataType::Int32, true))),
2977            cast_options: CastOptions::default(),
2978        };
2979
2980        let result = variant_get(&variant_array, options).unwrap();
2981
2982        // Verify the result is an Int32Array with 4 rows
2983        let int_result = result.as_any().downcast_ref::<Int32Array>().unwrap();
2984        assert_eq!(int_result.len(), 4);
2985
2986        // Row 0: Normal nested {"outer": {"inner": 42}} → 42
2987        assert!(!int_result.is_null(0));
2988        assert_eq!(int_result.value(0), 42);
2989
2990        // Row 1: Inner field null {"outer": {"inner": null}} → null
2991        assert!(int_result.is_null(1));
2992
2993        // Row 2: Outer field null {"outer": null} → null (path traversal fails)
2994        assert!(int_result.is_null(2));
2995
2996        // Row 3: Top-level null → null (path traversal fails)
2997        assert!(int_result.is_null(3));
2998    }
2999
3000    #[test]
3001    fn test_struct_extraction_mixed_and_unshredded() {
3002        // Create a partially shredded variant (x shredded, y not)
3003        let variant_array = create_mixed_and_unshredded_variant();
3004
3005        // Request struct with both shredded and unshredded fields
3006        let struct_fields = Fields::from(vec![
3007            Field::new("x", DataType::Int32, true),
3008            Field::new("y", DataType::Int32, true),
3009        ]);
3010        let struct_type = DataType::Struct(struct_fields);
3011
3012        let options = GetOptions {
3013            path: VariantPath::default(),
3014            as_type: Some(Arc::new(Field::new("result", struct_type, true))),
3015            cast_options: CastOptions::default(),
3016        };
3017
3018        let result = variant_get(&variant_array, options).unwrap();
3019
3020        // Verify the mixed shredding works (should succeed with current implementation)
3021        let struct_result = result.as_any().downcast_ref::<StructArray>().unwrap();
3022        assert_eq!(struct_result.len(), 4);
3023        assert_eq!(struct_result.num_columns(), 2);
3024
3025        let field_x = struct_result
3026            .column(0)
3027            .as_any()
3028            .downcast_ref::<Int32Array>()
3029            .unwrap();
3030        let field_y = struct_result
3031            .column(1)
3032            .as_any()
3033            .downcast_ref::<Int32Array>()
3034            .unwrap();
3035
3036        // Row 0: {"x": 1, "y": 42} - x from shredded, y from value field
3037        assert_eq!(field_x.value(0), 1);
3038        assert_eq!(field_y.value(0), 42);
3039
3040        // Row 1: {"x": 2} - x from shredded, y missing (perfect shredding)
3041        assert_eq!(field_x.value(1), 2);
3042        assert!(field_y.is_null(1));
3043
3044        // Row 2: {"x": 3, "y": null} - x from shredded, y explicitly null in value
3045        assert_eq!(field_x.value(2), 3);
3046        assert!(field_y.is_null(2));
3047
3048        // Row 3: top-level null - entire struct row should be null
3049        assert!(struct_result.is_null(3));
3050    }
3051
3052    #[test]
3053    fn test_struct_row_builder_handles_unshredded_nested_structs() {
3054        // Create completely unshredded JSON variant (no typed_value at all)
3055        let json_strings = vec![
3056            r#"{"outer": {"inner": 42}}"#,
3057            r#"{"outer": {"inner": 100}}"#,
3058        ];
3059        let string_array: Arc<dyn Array> = Arc::new(StringArray::from(json_strings));
3060        let variant_array = json_to_variant(&string_array).unwrap();
3061
3062        // Request nested struct
3063        let inner_fields = Fields::from(vec![Field::new("inner", DataType::Int32, true)]);
3064        let inner_struct_type = DataType::Struct(inner_fields);
3065        let outer_fields = Fields::from(vec![Field::new("outer", inner_struct_type, true)]);
3066        let outer_struct_type = DataType::Struct(outer_fields);
3067
3068        let options = GetOptions {
3069            path: VariantPath::default(),
3070            as_type: Some(Arc::new(Field::new("result", outer_struct_type, true))),
3071            cast_options: CastOptions::default(),
3072        };
3073
3074        let variant_array_ref = ArrayRef::from(variant_array);
3075        let result = variant_get(&variant_array_ref, options).unwrap();
3076
3077        let outer_struct = result.as_struct();
3078        assert_eq!(outer_struct.len(), 2);
3079        assert_eq!(outer_struct.num_columns(), 1);
3080
3081        let inner_struct = outer_struct.column(0).as_struct();
3082        assert_eq!(inner_struct.num_columns(), 1);
3083
3084        let inner_values = inner_struct
3085            .column(0)
3086            .as_any()
3087            .downcast_ref::<Int32Array>()
3088            .unwrap();
3089        assert_eq!(inner_values.value(0), 42);
3090        assert_eq!(inner_values.value(1), 100);
3091    }
3092
3093    #[test]
3094    fn test_unshredded_struct_safe_cast_non_object_rows_are_null() {
3095        let json_strings = vec![r#"{"a": 1, "b": 2}"#, "123", "{}"];
3096        let string_array: Arc<dyn Array> = Arc::new(StringArray::from(json_strings));
3097        let variant_array_ref = ArrayRef::from(json_to_variant(&string_array).unwrap());
3098
3099        let struct_fields = Fields::from(vec![
3100            Field::new("a", DataType::Int32, true),
3101            Field::new("b", DataType::Int32, true),
3102        ]);
3103        let options = GetOptions {
3104            path: VariantPath::default(),
3105            as_type: Some(Arc::new(Field::new(
3106                "result",
3107                DataType::Struct(struct_fields),
3108                true,
3109            ))),
3110            cast_options: CastOptions::default(),
3111        };
3112
3113        let result = variant_get(&variant_array_ref, options).unwrap();
3114        let struct_result = result.as_struct();
3115        let field_a = struct_result
3116            .column(0)
3117            .as_primitive::<arrow::datatypes::Int32Type>();
3118        let field_b = struct_result
3119            .column(1)
3120            .as_primitive::<arrow::datatypes::Int32Type>();
3121
3122        // Row 0 is an object, so the struct row is valid with extracted fields.
3123        assert!(!struct_result.is_null(0));
3124        assert_eq!(field_a.value(0), 1);
3125        assert_eq!(field_b.value(0), 2);
3126
3127        // Row 1 is a scalar, so safe struct cast should produce a NULL struct row.
3128        assert!(struct_result.is_null(1));
3129        assert!(field_a.is_null(1));
3130        assert!(field_b.is_null(1));
3131
3132        // Row 2 is an empty object, so the struct row is valid with missing fields as NULL.
3133        assert!(!struct_result.is_null(2));
3134        assert!(field_a.is_null(2));
3135        assert!(field_b.is_null(2));
3136    }
3137
3138    #[test]
3139    fn test_unshredded_struct_strict_cast_non_object_errors() {
3140        let json_strings = vec![r#"{"a": 1, "b": 2}"#, "123"];
3141        let string_array: Arc<dyn Array> = Arc::new(StringArray::from(json_strings));
3142        let variant_array_ref = ArrayRef::from(json_to_variant(&string_array).unwrap());
3143
3144        let struct_fields = Fields::from(vec![
3145            Field::new("a", DataType::Int32, true),
3146            Field::new("b", DataType::Int32, true),
3147        ]);
3148        let options = GetOptions {
3149            path: VariantPath::default(),
3150            as_type: Some(Arc::new(Field::new(
3151                "result",
3152                DataType::Struct(struct_fields),
3153                true,
3154            ))),
3155            cast_options: CastOptions {
3156                safe: false,
3157                ..Default::default()
3158            },
3159        };
3160
3161        let err = variant_get(&variant_array_ref, options).unwrap_err();
3162        assert!(
3163            err.to_string()
3164                .contains("Failed to extract struct from variant")
3165        );
3166    }
3167
3168    /// Create comprehensive shredded variant with diverse null patterns and empty objects
3169    /// Rows: normal values, top-level null, missing field a, missing field b, empty object
3170    fn create_comprehensive_shredded_variant() -> ArrayRef {
3171        let (metadata, _) = {
3172            let mut builder = parquet_variant::VariantBuilder::new();
3173            let obj = builder.new_object();
3174            obj.finish();
3175            builder.finish()
3176        };
3177
3178        // Create null buffer for top-level nulls
3179        let nulls = NullBuffer::from(vec![
3180            true,  // row 0: normal values
3181            false, // row 1: top-level null
3182            true,  // row 2: missing field a
3183            true,  // row 3: missing field b
3184            true,  // row 4: empty object
3185        ]);
3186
3187        let metadata_array = BinaryViewArray::from_iter_values(std::iter::repeat_n(&metadata, 5));
3188
3189        // Create shredded fields with different null patterns
3190        // Field "a": present in rows 0,3 (missing in rows 1,2,4)
3191        let a_field_typed_value = Int32Array::from(vec![Some(1), None, None, Some(1), None]);
3192        let a_field_shredded = ShreddedVariantFieldArray::from_parts(
3193            None,
3194            Some(Arc::new(a_field_typed_value) as ArrayRef),
3195            None,
3196        );
3197
3198        // Field "b": present in rows 0,2 (missing in rows 1,3,4)
3199        let b_field_typed_value = Int32Array::from(vec![Some(2), None, Some(2), None, None]);
3200        let b_field_shredded = ShreddedVariantFieldArray::from_parts(
3201            None,
3202            Some(Arc::new(b_field_typed_value) as ArrayRef),
3203            None,
3204        );
3205
3206        // Field "c": present in row 0 only (missing in all other rows)
3207        let c_field_typed_value = Int32Array::from(vec![Some(3), None, None, None, None]);
3208        let c_field_shredded = ShreddedVariantFieldArray::from_parts(
3209            None,
3210            Some(Arc::new(c_field_typed_value) as ArrayRef),
3211            None,
3212        );
3213
3214        // Create main typed_value struct
3215        let typed_value_fields = Fields::from(vec![
3216            Field::new("a", a_field_shredded.data_type().clone(), true),
3217            Field::new("b", b_field_shredded.data_type().clone(), true),
3218            Field::new("c", c_field_shredded.data_type().clone(), true),
3219        ]);
3220        let typed_value_struct = StructArray::try_new(
3221            typed_value_fields,
3222            vec![
3223                ArrayRef::from(a_field_shredded),
3224                ArrayRef::from(b_field_shredded),
3225                ArrayRef::from(c_field_shredded),
3226            ],
3227            None,
3228        )
3229        .unwrap();
3230
3231        // Build final VariantArray with top-level nulls
3232        ArrayRef::from(VariantArray::from_parts(
3233            Arc::new(metadata_array),
3234            None,
3235            Some(Arc::new(typed_value_struct)),
3236            Some(nulls),
3237        ))
3238    }
3239
3240    /// Create comprehensive nested shredded variant with diverse null patterns
3241    /// Represents 3-level structure: variant -> outer -> inner (INT value)
3242    /// The shredding schema is: {"metadata": BINARY, "typed_value": {"outer": {"typed_value": {"inner": {"typed_value": INT}}}}}
3243    /// Rows: normal nested value, inner field null, outer field null, top-level null
3244    fn create_comprehensive_nested_shredded_variant() -> ArrayRef {
3245        // Create the inner level: contains typed_value with Int32 values
3246        // Row 0: has value 42, Row 1: inner null, Row 2: outer null, Row 3: top-level null
3247        let inner_typed_value = Int32Array::from(vec![Some(42), None, None, None]); // dummy value for row 2
3248        let inner = ShreddedVariantFieldArray::from_parts(
3249            None,
3250            Some(Arc::new(inner_typed_value) as ArrayRef),
3251            None,
3252        );
3253
3254        let outer_typed_value_nulls = NullBuffer::from(vec![
3255            true,  // row 0: inner struct exists with typed_value=42
3256            false, // row 1: inner field NULL
3257            false, // row 2: outer field NULL
3258            false, // row 3: top-level NULL
3259        ]);
3260        let outer_typed_value = StructArrayBuilder::new()
3261            .with_field("inner", ArrayRef::from(inner), false)
3262            .with_nulls(outer_typed_value_nulls)
3263            .build();
3264
3265        let outer = ShreddedVariantFieldArray::from_parts(
3266            None,
3267            Some(Arc::new(outer_typed_value) as ArrayRef),
3268            None,
3269        );
3270
3271        let typed_value_nulls = NullBuffer::from(vec![
3272            true,  // row 0: inner struct exists with typed_value=42
3273            true,  // row 1: inner field NULL
3274            false, // row 2: outer field NULL
3275            false, // row 3: top-level NULL
3276        ]);
3277        let typed_value = StructArrayBuilder::new()
3278            .with_field("outer", ArrayRef::from(outer), false)
3279            .with_nulls(typed_value_nulls)
3280            .build();
3281
3282        // Build final VariantArray with top-level nulls
3283        let metadata_array =
3284            BinaryViewArray::from_iter_values(std::iter::repeat_n(EMPTY_VARIANT_METADATA_BYTES, 4));
3285        let nulls = NullBuffer::from(vec![
3286            true,  // row 0: inner struct exists with typed_value=42
3287            true,  // row 1: inner field NULL
3288            true,  // row 2: outer field NULL
3289            false, // row 3: top-level NULL
3290        ]);
3291        ArrayRef::from(VariantArray::from_parts(
3292            Arc::new(metadata_array),
3293            None,
3294            Some(Arc::new(typed_value)),
3295            Some(nulls),
3296        ))
3297    }
3298
3299    /// Create variant with mixed shredding (spec-compliant) including null scenarios
3300    /// Field "x" is globally shredded, field "y" is never shredded
3301    fn create_mixed_and_unshredded_variant() -> ArrayRef {
3302        // Create spec-compliant mixed shredding:
3303        // - Field "x" is globally shredded (has typed_value column)
3304        // - Field "y" is never shredded (only appears in value field when present)
3305
3306        let (metadata, y_field_value) = {
3307            let mut builder = parquet_variant::VariantBuilder::new();
3308            let mut obj = builder.new_object();
3309            obj.insert("y", Variant::from(42));
3310            obj.finish();
3311            builder.finish()
3312        };
3313
3314        let metadata_array = BinaryViewArray::from_iter_values(std::iter::repeat_n(&metadata, 4));
3315
3316        // Value field contains objects with unshredded fields only (never contains "x")
3317        // Row 0: {"y": "foo"} - x is shredded out, y remains in value
3318        // Row 1: {} - both x and y are absent (perfect shredding for x, y missing)
3319        // Row 2: {"y": null} - x is shredded out, y explicitly null
3320        // Row 3: top-level null (encoded in VariantArray's null mask, but fields contain valid data)
3321
3322        let empty_object_value = {
3323            let mut builder = parquet_variant::VariantBuilder::new();
3324            builder.new_object().finish();
3325            let (_, value) = builder.finish();
3326            value
3327        };
3328
3329        let y_null_value = {
3330            let mut builder = parquet_variant::VariantBuilder::new();
3331            builder.new_object().with_field("y", Variant::Null).finish();
3332            let (_, value) = builder.finish();
3333            value
3334        };
3335
3336        let value_array = BinaryViewArray::from(vec![
3337            Some(y_field_value.as_slice()),      // Row 0: {"y": 42}
3338            Some(empty_object_value.as_slice()), // Row 1: {}
3339            Some(y_null_value.as_slice()),       // Row 2: {"y": null}
3340            Some(empty_object_value.as_slice()), // Row 3: top-level null (but value field contains valid data)
3341        ]);
3342
3343        // Create shredded field "x" (globally shredded - never appears in value field)
3344        // For top-level null row, the field still needs valid content (not null)
3345        let x_field_typed_value = Int32Array::from(vec![Some(1), Some(2), Some(3), Some(0)]);
3346        let x_field_shredded = ShreddedVariantFieldArray::from_parts(
3347            None,
3348            Some(Arc::new(x_field_typed_value) as ArrayRef),
3349            None,
3350        );
3351
3352        // Create main typed_value struct (only contains shredded fields)
3353        let typed_value_struct = StructArrayBuilder::new()
3354            .with_field("x", ArrayRef::from(x_field_shredded), false)
3355            .build();
3356
3357        // Build VariantArray with both value and typed_value (PartiallyShredded)
3358        // Top-level null is encoded in the main StructArray's null mask
3359        let variant_nulls = NullBuffer::from(vec![true, true, true, false]); // Row 3 is top-level null
3360        ArrayRef::from(VariantArray::from_parts(
3361            Arc::new(metadata_array),
3362            Some(Arc::new(value_array)),
3363            Some(Arc::new(typed_value_struct)),
3364            Some(variant_nulls),
3365        ))
3366    }
3367
3368    #[test]
3369    fn get_decimal32_rescaled_to_scale2() {
3370        // Build unshredded variant values with different scales
3371        let mut builder = crate::VariantArrayBuilder::new(5);
3372        builder.append_variant(VariantDecimal4::try_new(1234, 2).unwrap().into()); // 12.34
3373        builder.append_variant(VariantDecimal4::try_new(1234, 3).unwrap().into()); // 1.234
3374        builder.append_variant(VariantDecimal4::try_new(1234, 0).unwrap().into()); // 1234
3375        builder.append_null();
3376        builder.append_variant(
3377            VariantDecimal8::try_new((VariantDecimal4::MAX_UNSCALED_VALUE as i64) + 1, 3)
3378                .unwrap()
3379                .into(),
3380        ); // should fit into Decimal32
3381        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3382
3383        let field = Field::new("result", DataType::Decimal32(9, 2), true);
3384        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3385        let result = variant_get(&variant_array, options).unwrap();
3386        let result = result.as_any().downcast_ref::<Decimal32Array>().unwrap();
3387
3388        assert_eq!(result.precision(), 9);
3389        assert_eq!(result.scale(), 2);
3390        assert_eq!(result.value(0), 1234);
3391        assert_eq!(result.value(1), 123);
3392        assert_eq!(result.value(2), 123400);
3393        assert!(result.is_null(3));
3394        assert_eq!(
3395            result.value(4),
3396            VariantDecimal4::MAX_UNSCALED_VALUE / 10 + 1
3397        ); // should not be null as the final result fits into Decimal32
3398    }
3399
3400    #[test]
3401    fn get_decimal32_scale_down_rounding() {
3402        let mut builder = crate::VariantArrayBuilder::new(7);
3403        builder.append_variant(VariantDecimal4::try_new(1235, 0).unwrap().into());
3404        builder.append_variant(VariantDecimal4::try_new(1245, 0).unwrap().into());
3405        builder.append_variant(VariantDecimal4::try_new(-1235, 0).unwrap().into());
3406        builder.append_variant(VariantDecimal4::try_new(-1245, 0).unwrap().into());
3407        builder.append_variant(VariantDecimal4::try_new(1235, 2).unwrap().into()); // 12.35 rounded down to 10 for scale -1
3408        builder.append_variant(VariantDecimal4::try_new(1235, 3).unwrap().into()); // 1.235 rounded down to 0 for scale -1
3409        builder.append_variant(VariantDecimal4::try_new(5235, 3).unwrap().into()); // 5.235 rounded up to 10 for scale -1
3410        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3411
3412        let field = Field::new("result", DataType::Decimal32(9, -1), true);
3413        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3414        let result = variant_get(&variant_array, options).unwrap();
3415        let result = result.as_any().downcast_ref::<Decimal32Array>().unwrap();
3416
3417        assert_eq!(result.precision(), 9);
3418        assert_eq!(result.scale(), -1);
3419        assert_eq!(result.value(0), 124);
3420        assert_eq!(result.value(1), 125);
3421        assert_eq!(result.value(2), -124);
3422        assert_eq!(result.value(3), -125);
3423        assert_eq!(result.value(4), 1);
3424        assert!(result.is_valid(5));
3425        assert_eq!(result.value(5), 0);
3426        assert_eq!(result.value(6), 1);
3427    }
3428
3429    #[test]
3430    fn get_decimal32_large_scale_reduction() {
3431        let mut builder = crate::VariantArrayBuilder::new(2);
3432        builder.append_variant(
3433            VariantDecimal4::try_new(-VariantDecimal4::MAX_UNSCALED_VALUE, 0)
3434                .unwrap()
3435                .into(),
3436        );
3437        builder.append_variant(
3438            VariantDecimal4::try_new(VariantDecimal4::MAX_UNSCALED_VALUE, 0)
3439                .unwrap()
3440                .into(),
3441        );
3442        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3443
3444        let field = Field::new("result", DataType::Decimal32(9, -9), true);
3445        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3446        let result = variant_get(&variant_array, options).unwrap();
3447        let result = result.as_any().downcast_ref::<Decimal32Array>().unwrap();
3448
3449        assert_eq!(result.precision(), 9);
3450        assert_eq!(result.scale(), -9);
3451        assert_eq!(result.value(0), -1);
3452        assert_eq!(result.value(1), 1);
3453
3454        let field = Field::new("result", DataType::Decimal32(9, -10), true);
3455        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3456        let result = variant_get(&variant_array, options).unwrap();
3457        let result = result.as_any().downcast_ref::<Decimal32Array>().unwrap();
3458
3459        assert_eq!(result.precision(), 9);
3460        assert_eq!(result.scale(), -10);
3461        assert!(result.is_valid(0));
3462        assert_eq!(result.value(0), 0);
3463        assert!(result.is_valid(1));
3464        assert_eq!(result.value(1), 0);
3465    }
3466
3467    #[test]
3468    fn get_decimal32_precision_overflow_safe() {
3469        // Exceed Decimal32 after scaling and rounding
3470        let mut builder = crate::VariantArrayBuilder::new(2);
3471        builder.append_variant(
3472            VariantDecimal4::try_new(VariantDecimal4::MAX_UNSCALED_VALUE, 0)
3473                .unwrap()
3474                .into(),
3475        );
3476        builder.append_variant(
3477            VariantDecimal4::try_new(VariantDecimal4::MAX_UNSCALED_VALUE, 9)
3478                .unwrap()
3479                .into(),
3480        ); // integer value round up overflows
3481        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3482
3483        let field = Field::new("result", DataType::Decimal32(2, 2), true);
3484        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3485        let result = variant_get(&variant_array, options).unwrap();
3486        let result = result.as_any().downcast_ref::<Decimal32Array>().unwrap();
3487
3488        assert!(result.is_null(0));
3489        assert!(result.is_null(1)); // should overflow because 1.00 does not fit into precision (2)
3490    }
3491
3492    #[test]
3493    fn get_decimal32_precision_overflow_unsafe_errors() {
3494        let mut builder = crate::VariantArrayBuilder::new(1);
3495        builder.append_variant(
3496            VariantDecimal4::try_new(VariantDecimal4::MAX_UNSCALED_VALUE, 0)
3497                .unwrap()
3498                .into(),
3499        );
3500        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3501
3502        let field = Field::new("result", DataType::Decimal32(9, 2), true);
3503        let cast_options = CastOptions {
3504            safe: false,
3505            ..Default::default()
3506        };
3507        let options = GetOptions::new()
3508            .with_as_type(Some(FieldRef::from(field)))
3509            .with_cast_options(cast_options);
3510        let err = variant_get(&variant_array, options).unwrap_err();
3511
3512        assert!(
3513            err.to_string().contains(
3514                "Failed to cast to Decimal32(precision=9, scale=2) from variant Decimal4"
3515            )
3516        );
3517    }
3518
3519    #[test]
3520    fn get_decimal64_rescaled_to_scale2() {
3521        let mut builder = crate::VariantArrayBuilder::new(5);
3522        builder.append_variant(VariantDecimal8::try_new(1234, 2).unwrap().into()); // 12.34
3523        builder.append_variant(VariantDecimal8::try_new(1234, 3).unwrap().into()); // 1.234
3524        builder.append_variant(VariantDecimal8::try_new(1234, 0).unwrap().into()); // 1234
3525        builder.append_null();
3526        builder.append_variant(
3527            VariantDecimal16::try_new((VariantDecimal8::MAX_UNSCALED_VALUE as i128) + 1, 3)
3528                .unwrap()
3529                .into(),
3530        ); // should fit into Decimal64
3531        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3532
3533        let field = Field::new("result", DataType::Decimal64(18, 2), true);
3534        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3535        let result = variant_get(&variant_array, options).unwrap();
3536        let result = result.as_any().downcast_ref::<Decimal64Array>().unwrap();
3537
3538        assert_eq!(result.precision(), 18);
3539        assert_eq!(result.scale(), 2);
3540        assert_eq!(result.value(0), 1234);
3541        assert_eq!(result.value(1), 123);
3542        assert_eq!(result.value(2), 123400);
3543        assert!(result.is_null(3));
3544        assert_eq!(
3545            result.value(4),
3546            VariantDecimal8::MAX_UNSCALED_VALUE / 10 + 1
3547        ); // should not be null as the final result fits into Decimal64
3548    }
3549
3550    #[test]
3551    fn get_decimal64_scale_down_rounding() {
3552        let mut builder = crate::VariantArrayBuilder::new(7);
3553        builder.append_variant(VariantDecimal8::try_new(1235, 0).unwrap().into());
3554        builder.append_variant(VariantDecimal8::try_new(1245, 0).unwrap().into());
3555        builder.append_variant(VariantDecimal8::try_new(-1235, 0).unwrap().into());
3556        builder.append_variant(VariantDecimal8::try_new(-1245, 0).unwrap().into());
3557        builder.append_variant(VariantDecimal8::try_new(1235, 2).unwrap().into()); // 12.35 rounded down to 10 for scale -1
3558        builder.append_variant(VariantDecimal8::try_new(1235, 3).unwrap().into()); // 1.235 rounded down to 0 for scale -1
3559        builder.append_variant(VariantDecimal8::try_new(5235, 3).unwrap().into()); // 5.235 rounded up to 10 for scale -1
3560        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3561
3562        let field = Field::new("result", DataType::Decimal64(18, -1), true);
3563        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3564        let result = variant_get(&variant_array, options).unwrap();
3565        let result = result.as_any().downcast_ref::<Decimal64Array>().unwrap();
3566
3567        assert_eq!(result.precision(), 18);
3568        assert_eq!(result.scale(), -1);
3569        assert_eq!(result.value(0), 124);
3570        assert_eq!(result.value(1), 125);
3571        assert_eq!(result.value(2), -124);
3572        assert_eq!(result.value(3), -125);
3573        assert_eq!(result.value(4), 1);
3574        assert!(result.is_valid(5));
3575        assert_eq!(result.value(5), 0);
3576        assert_eq!(result.value(6), 1);
3577    }
3578
3579    #[test]
3580    fn get_decimal64_large_scale_reduction() {
3581        let mut builder = crate::VariantArrayBuilder::new(2);
3582        builder.append_variant(
3583            VariantDecimal8::try_new(-VariantDecimal8::MAX_UNSCALED_VALUE, 0)
3584                .unwrap()
3585                .into(),
3586        );
3587        builder.append_variant(
3588            VariantDecimal8::try_new(VariantDecimal8::MAX_UNSCALED_VALUE, 0)
3589                .unwrap()
3590                .into(),
3591        );
3592        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3593
3594        let field = Field::new("result", DataType::Decimal64(18, -18), true);
3595        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3596        let result = variant_get(&variant_array, options).unwrap();
3597        let result = result.as_any().downcast_ref::<Decimal64Array>().unwrap();
3598
3599        assert_eq!(result.precision(), 18);
3600        assert_eq!(result.scale(), -18);
3601        assert_eq!(result.value(0), -1);
3602        assert_eq!(result.value(1), 1);
3603
3604        let field = Field::new("result", DataType::Decimal64(18, -19), true);
3605        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3606        let result = variant_get(&variant_array, options).unwrap();
3607        let result = result.as_any().downcast_ref::<Decimal64Array>().unwrap();
3608
3609        assert_eq!(result.precision(), 18);
3610        assert_eq!(result.scale(), -19);
3611        assert!(result.is_valid(0));
3612        assert_eq!(result.value(0), 0);
3613        assert!(result.is_valid(1));
3614        assert_eq!(result.value(1), 0);
3615    }
3616
3617    #[test]
3618    fn get_decimal64_precision_overflow_safe() {
3619        // Exceed Decimal64 after scaling and rounding
3620        let mut builder = crate::VariantArrayBuilder::new(2);
3621        builder.append_variant(
3622            VariantDecimal8::try_new(VariantDecimal8::MAX_UNSCALED_VALUE, 0)
3623                .unwrap()
3624                .into(),
3625        );
3626        builder.append_variant(
3627            VariantDecimal8::try_new(VariantDecimal8::MAX_UNSCALED_VALUE, 18)
3628                .unwrap()
3629                .into(),
3630        ); // integer value round up overflows
3631        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3632
3633        let field = Field::new("result", DataType::Decimal64(2, 2), true);
3634        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3635        let result = variant_get(&variant_array, options).unwrap();
3636        let result = result.as_any().downcast_ref::<Decimal64Array>().unwrap();
3637
3638        assert!(result.is_null(0));
3639        assert!(result.is_null(1));
3640    }
3641
3642    #[test]
3643    fn get_decimal64_precision_overflow_unsafe_errors() {
3644        let mut builder = crate::VariantArrayBuilder::new(1);
3645        builder.append_variant(
3646            VariantDecimal8::try_new(VariantDecimal8::MAX_UNSCALED_VALUE, 0)
3647                .unwrap()
3648                .into(),
3649        );
3650        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3651
3652        let field = Field::new("result", DataType::Decimal64(18, 2), true);
3653        let cast_options = CastOptions {
3654            safe: false,
3655            ..Default::default()
3656        };
3657        let options = GetOptions::new()
3658            .with_as_type(Some(FieldRef::from(field)))
3659            .with_cast_options(cast_options);
3660        let err = variant_get(&variant_array, options).unwrap_err();
3661
3662        assert!(
3663            err.to_string().contains(
3664                "Failed to cast to Decimal64(precision=18, scale=2) from variant Decimal8"
3665            )
3666        );
3667    }
3668
3669    #[test]
3670    fn get_decimal128_rescaled_to_scale2() {
3671        let mut builder = crate::VariantArrayBuilder::new(4);
3672        builder.append_variant(VariantDecimal16::try_new(1234, 2).unwrap().into());
3673        builder.append_variant(VariantDecimal16::try_new(1234, 3).unwrap().into());
3674        builder.append_variant(VariantDecimal16::try_new(1234, 0).unwrap().into());
3675        builder.append_null();
3676        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3677
3678        let field = Field::new("result", DataType::Decimal128(38, 2), true);
3679        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3680        let result = variant_get(&variant_array, options).unwrap();
3681        let result = result.as_any().downcast_ref::<Decimal128Array>().unwrap();
3682
3683        assert_eq!(result.precision(), 38);
3684        assert_eq!(result.scale(), 2);
3685        assert_eq!(result.value(0), 1234);
3686        assert_eq!(result.value(1), 123);
3687        assert_eq!(result.value(2), 123400);
3688        assert!(result.is_null(3));
3689    }
3690
3691    #[test]
3692    fn get_decimal128_scale_down_rounding() {
3693        let mut builder = crate::VariantArrayBuilder::new(7);
3694        builder.append_variant(VariantDecimal16::try_new(1235, 0).unwrap().into());
3695        builder.append_variant(VariantDecimal16::try_new(1245, 0).unwrap().into());
3696        builder.append_variant(VariantDecimal16::try_new(-1235, 0).unwrap().into());
3697        builder.append_variant(VariantDecimal16::try_new(-1245, 0).unwrap().into());
3698        builder.append_variant(VariantDecimal16::try_new(1235, 2).unwrap().into()); // 12.35 rounded down to 10 for scale -1
3699        builder.append_variant(VariantDecimal16::try_new(1235, 3).unwrap().into()); // 1.235 rounded down to 0 for scale -1
3700        builder.append_variant(VariantDecimal16::try_new(5235, 3).unwrap().into()); // 5.235 rounded up to 10 for scale -1
3701        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3702
3703        let field = Field::new("result", DataType::Decimal128(38, -1), true);
3704        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3705        let result = variant_get(&variant_array, options).unwrap();
3706        let result = result.as_any().downcast_ref::<Decimal128Array>().unwrap();
3707
3708        assert_eq!(result.precision(), 38);
3709        assert_eq!(result.scale(), -1);
3710        assert_eq!(result.value(0), 124);
3711        assert_eq!(result.value(1), 125);
3712        assert_eq!(result.value(2), -124);
3713        assert_eq!(result.value(3), -125);
3714        assert_eq!(result.value(4), 1);
3715        assert!(result.is_valid(5));
3716        assert_eq!(result.value(5), 0);
3717        assert_eq!(result.value(6), 1);
3718    }
3719
3720    #[test]
3721    fn get_decimal128_precision_overflow_safe() {
3722        // Exceed Decimal128 after scaling and rounding
3723        let mut builder = crate::VariantArrayBuilder::new(2);
3724        builder.append_variant(
3725            VariantDecimal16::try_new(VariantDecimal16::MAX_UNSCALED_VALUE, 0)
3726                .unwrap()
3727                .into(),
3728        );
3729        builder.append_variant(
3730            VariantDecimal16::try_new(VariantDecimal16::MAX_UNSCALED_VALUE, 38)
3731                .unwrap()
3732                .into(),
3733        ); // integer value round up overflows
3734        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3735
3736        let field = Field::new("result", DataType::Decimal128(2, 2), true);
3737        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3738        let result = variant_get(&variant_array, options).unwrap();
3739        let result = result.as_any().downcast_ref::<Decimal128Array>().unwrap();
3740
3741        assert!(result.is_null(0));
3742        assert!(result.is_null(1)); // should overflow because 1.00 does not fit into precision (2)
3743    }
3744
3745    #[test]
3746    fn get_decimal128_precision_overflow_unsafe_errors() {
3747        let mut builder = crate::VariantArrayBuilder::new(1);
3748        builder.append_variant(
3749            VariantDecimal16::try_new(VariantDecimal16::MAX_UNSCALED_VALUE, 0)
3750                .unwrap()
3751                .into(),
3752        );
3753        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3754
3755        let field = Field::new("result", DataType::Decimal128(38, 2), true);
3756        let cast_options = CastOptions {
3757            safe: false,
3758            ..Default::default()
3759        };
3760        let options = GetOptions::new()
3761            .with_as_type(Some(FieldRef::from(field)))
3762            .with_cast_options(cast_options);
3763        let err = variant_get(&variant_array, options).unwrap_err();
3764
3765        assert!(err.to_string().contains(
3766            "Failed to cast to Decimal128(precision=38, scale=2) from variant Decimal16"
3767        ));
3768    }
3769
3770    #[test]
3771    fn get_decimal256_rescaled_to_scale2() {
3772        // Build unshredded variant values with different scales using Decimal16 source
3773        let mut builder = crate::VariantArrayBuilder::new(4);
3774        builder.append_variant(VariantDecimal16::try_new(1234, 2).unwrap().into()); // 12.34
3775        builder.append_variant(VariantDecimal16::try_new(1234, 3).unwrap().into()); // 1.234
3776        builder.append_variant(VariantDecimal16::try_new(1234, 0).unwrap().into()); // 1234
3777        builder.append_null();
3778        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3779
3780        let field = Field::new("result", DataType::Decimal256(76, 2), true);
3781        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3782        let result = variant_get(&variant_array, options).unwrap();
3783        let result = result.as_any().downcast_ref::<Decimal256Array>().unwrap();
3784
3785        assert_eq!(result.precision(), 76);
3786        assert_eq!(result.scale(), 2);
3787        assert_eq!(result.value(0), i256::from_i128(1234));
3788        assert_eq!(result.value(1), i256::from_i128(123));
3789        assert_eq!(result.value(2), i256::from_i128(123400));
3790        assert!(result.is_null(3));
3791    }
3792
3793    #[test]
3794    fn get_decimal256_scale_down_rounding() {
3795        let mut builder = crate::VariantArrayBuilder::new(7);
3796        builder.append_variant(VariantDecimal16::try_new(1235, 0).unwrap().into());
3797        builder.append_variant(VariantDecimal16::try_new(1245, 0).unwrap().into());
3798        builder.append_variant(VariantDecimal16::try_new(-1235, 0).unwrap().into());
3799        builder.append_variant(VariantDecimal16::try_new(-1245, 0).unwrap().into());
3800        builder.append_variant(VariantDecimal16::try_new(1235, 2).unwrap().into()); // 12.35 rounded down to 10 for scale -1
3801        builder.append_variant(VariantDecimal16::try_new(1235, 3).unwrap().into()); // 1.235 rounded down to 0 for scale -1
3802        builder.append_variant(VariantDecimal16::try_new(5235, 3).unwrap().into()); // 5.235 rounded up to 10 for scale -1
3803        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3804
3805        let field = Field::new("result", DataType::Decimal256(76, -1), true);
3806        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3807        let result = variant_get(&variant_array, options).unwrap();
3808        let result = result.as_any().downcast_ref::<Decimal256Array>().unwrap();
3809
3810        assert_eq!(result.precision(), 76);
3811        assert_eq!(result.scale(), -1);
3812        assert_eq!(result.value(0), i256::from_i128(124));
3813        assert_eq!(result.value(1), i256::from_i128(125));
3814        assert_eq!(result.value(2), i256::from_i128(-124));
3815        assert_eq!(result.value(3), i256::from_i128(-125));
3816        assert_eq!(result.value(4), i256::from_i128(1));
3817        assert!(result.is_valid(5));
3818        assert_eq!(result.value(5), i256::from_i128(0));
3819        assert_eq!(result.value(6), i256::from_i128(1));
3820    }
3821
3822    #[test]
3823    fn get_decimal256_precision_overflow_safe() {
3824        // Exceed Decimal128 max precision (38) after scaling
3825        let mut builder = crate::VariantArrayBuilder::new(2);
3826        builder.append_variant(
3827            VariantDecimal16::try_new(VariantDecimal16::MAX_UNSCALED_VALUE, 1)
3828                .unwrap()
3829                .into(),
3830        );
3831        builder.append_variant(
3832            VariantDecimal16::try_new(VariantDecimal16::MAX_UNSCALED_VALUE, 0)
3833                .unwrap()
3834                .into(),
3835        );
3836        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3837
3838        let field = Field::new("result", DataType::Decimal256(76, 39), true);
3839        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3840        let result = variant_get(&variant_array, options).unwrap();
3841        let result = result.as_any().downcast_ref::<Decimal256Array>().unwrap();
3842
3843        // Input is Decimal16 with integer = 10^38-1 and scale = 1, target scale = 39
3844        // So expected integer is (10^38-1) * 10^(39-1) = (10^38-1) * 10^38
3845        let base = i256::from_i128(10);
3846        let factor = base.checked_pow(38).unwrap();
3847        let expected = i256::from_i128(VariantDecimal16::MAX_UNSCALED_VALUE)
3848            .checked_mul(factor)
3849            .unwrap();
3850        assert_eq!(result.value(0), expected);
3851        assert!(result.is_null(1));
3852    }
3853
3854    #[test]
3855    fn get_decimal256_precision_overflow_unsafe_errors() {
3856        // Exceed Decimal128 max precision (38) after scaling
3857        let mut builder = crate::VariantArrayBuilder::new(2);
3858        builder.append_variant(
3859            VariantDecimal16::try_new(VariantDecimal16::MAX_UNSCALED_VALUE, 1)
3860                .unwrap()
3861                .into(),
3862        );
3863        builder.append_variant(
3864            VariantDecimal16::try_new(VariantDecimal16::MAX_UNSCALED_VALUE, 0)
3865                .unwrap()
3866                .into(),
3867        );
3868        let variant_array: ArrayRef = ArrayRef::from(builder.build());
3869
3870        let field = Field::new("result", DataType::Decimal256(76, 39), true);
3871        let cast_options = CastOptions {
3872            safe: false,
3873            ..Default::default()
3874        };
3875        let options = GetOptions::new()
3876            .with_as_type(Some(FieldRef::from(field)))
3877            .with_cast_options(cast_options);
3878        let err = variant_get(&variant_array, options).unwrap_err();
3879
3880        assert!(err.to_string().contains(
3881            "Failed to cast to Decimal256(precision=76, scale=39) from variant Decimal16"
3882        ));
3883    }
3884
3885    #[test]
3886    fn get_non_supported_temporal_types_error() {
3887        let values = vec![None, Some(Variant::Null), Some(Variant::BooleanFalse)];
3888        let variant_array: ArrayRef = ArrayRef::from(VariantArray::from_iter(values));
3889
3890        let test_cases = vec![
3891            FieldRef::from(Field::new(
3892                "result",
3893                DataType::Duration(TimeUnit::Microsecond),
3894                true,
3895            )),
3896            FieldRef::from(Field::new(
3897                "result",
3898                DataType::Interval(IntervalUnit::YearMonth),
3899                true,
3900            )),
3901        ];
3902
3903        for field in test_cases {
3904            let options = GetOptions::new().with_as_type(Some(field));
3905            let err = variant_get(&variant_array, options).unwrap_err();
3906            assert!(
3907                err.to_string()
3908                    .contains("Casting Variant to duration/interval types is not supported")
3909            );
3910        }
3911    }
3912
3913    fn invalid_time_variant_array() -> ArrayRef {
3914        let mut builder = VariantArrayBuilder::new(3);
3915        // 86401000000 is invalid for Time64Microsecond (max is 86400000000)
3916        builder.append_variant(Variant::Int64(86401000000));
3917        builder.append_variant(Variant::Int64(86401000000));
3918        builder.append_variant(Variant::Int64(86401000000));
3919        Arc::new(builder.build().into_inner())
3920    }
3921
3922    #[test]
3923    fn test_variant_get_error_when_cast_failure_and_safe_false() {
3924        let variant_array = invalid_time_variant_array();
3925
3926        let field = Field::new("result", DataType::Time64(TimeUnit::Microsecond), true);
3927        let cast_options = CastOptions {
3928            safe: false, // Will error on cast failure
3929            ..Default::default()
3930        };
3931        let options = GetOptions::new()
3932            .with_as_type(Some(FieldRef::from(field)))
3933            .with_cast_options(cast_options);
3934        let err = variant_get(&variant_array, options).unwrap_err();
3935        assert!(
3936            err.to_string().contains(
3937                "Cast error: Failed to extract primitive of type Time64(µs) from variant Int64(86401000000) at path VariantPath([])"
3938            ),
3939            "actual: {err}",
3940        );
3941    }
3942
3943    #[test]
3944    fn test_variant_get_return_null_when_cast_failure_and_safe_true() {
3945        let variant_array = invalid_time_variant_array();
3946
3947        let field = Field::new("result", DataType::Time64(TimeUnit::Microsecond), true);
3948        let cast_options = CastOptions {
3949            safe: true, // Will return null on cast failure
3950            ..Default::default()
3951        };
3952        let options = GetOptions::new()
3953            .with_as_type(Some(FieldRef::from(field)))
3954            .with_cast_options(cast_options);
3955        let result = variant_get(&variant_array, options).unwrap();
3956        assert_eq!(3, result.len());
3957
3958        for i in 0..3 {
3959            assert!(result.is_null(i));
3960        }
3961    }
3962
3963    #[test]
3964    fn test_perfect_shredding_returns_same_arc_ptr() {
3965        let variant_array = perfectly_shredded_int32_variant_array();
3966
3967        let variant_array_ref = VariantArray::try_new(&variant_array).unwrap();
3968        let typed_value_arc = variant_array_ref.typed_value_field().unwrap().clone();
3969
3970        let field = Field::new("result", DataType::Int32, true);
3971        let options = GetOptions::new().with_as_type(Some(FieldRef::from(field)));
3972        let result = variant_get(&variant_array, options).unwrap();
3973
3974        assert!(Arc::ptr_eq(&typed_value_arc, &result));
3975    }
3976
3977    #[test]
3978    fn test_perfect_shredding_three_typed_value_columns() {
3979        // Column 1: perfectly shredded primitive with all nulls
3980        let all_nulls_values: Arc<Int32Array> = Arc::new(Int32Array::from(vec![
3981            Option::<i32>::None,
3982            Option::<i32>::None,
3983            Option::<i32>::None,
3984        ]));
3985        let all_nulls_erased: ArrayRef = all_nulls_values.clone();
3986        let all_nulls_field =
3987            ShreddedVariantFieldArray::from_parts(None, Some(all_nulls_erased.clone()), None);
3988        let all_nulls_type = all_nulls_field.data_type().clone();
3989        let all_nulls_struct: ArrayRef = ArrayRef::from(all_nulls_field);
3990
3991        // Column 2: perfectly shredded primitive with some nulls
3992        let some_nulls_values: Arc<Int32Array> =
3993            Arc::new(Int32Array::from(vec![Some(10), None, Some(30)]));
3994        let some_nulls_erased: ArrayRef = some_nulls_values.clone();
3995        let some_nulls_field =
3996            ShreddedVariantFieldArray::from_parts(None, Some(some_nulls_erased.clone()), None);
3997        let some_nulls_type = some_nulls_field.data_type().clone();
3998        let some_nulls_struct: ArrayRef = ArrayRef::from(some_nulls_field);
3999
4000        // Column 3: perfectly shredded nested struct
4001        let inner_values: Arc<Int32Array> =
4002            Arc::new(Int32Array::from(vec![Some(111), None, Some(333)]));
4003        let inner_erased: ArrayRef = inner_values.clone();
4004        let inner_field =
4005            ShreddedVariantFieldArray::from_parts(None, Some(inner_erased.clone()), None);
4006        let inner_field_type = inner_field.data_type().clone();
4007        let inner_struct_array: ArrayRef = ArrayRef::from(inner_field);
4008
4009        let nested_struct = Arc::new(
4010            StructArray::try_new(
4011                Fields::from(vec![Field::new("inner", inner_field_type, true)]),
4012                vec![inner_struct_array],
4013                None,
4014            )
4015            .unwrap(),
4016        );
4017        let nested_struct_erased: ArrayRef = nested_struct.clone();
4018        let struct_field =
4019            ShreddedVariantFieldArray::from_parts(None, Some(nested_struct_erased.clone()), None);
4020        let struct_field_type = struct_field.data_type().clone();
4021        let struct_field_struct: ArrayRef = ArrayRef::from(struct_field);
4022
4023        // Assemble the top-level typed_value struct with the three columns above
4024        let typed_value_struct = StructArray::try_new(
4025            Fields::from(vec![
4026                Field::new("all_nulls", all_nulls_type, true),
4027                Field::new("some_nulls", some_nulls_type, true),
4028                Field::new("struct_field", struct_field_type, true),
4029            ]),
4030            vec![all_nulls_struct, some_nulls_struct, struct_field_struct],
4031            None,
4032        )
4033        .unwrap();
4034
4035        let metadata = BinaryViewArray::from_iter_values(std::iter::repeat_n(
4036            EMPTY_VARIANT_METADATA_BYTES,
4037            all_nulls_values.len(),
4038        ));
4039        let variant_array: ArrayRef = VariantArray::from_parts(
4040            Arc::new(metadata),
4041            None,
4042            Some(Arc::new(typed_value_struct)),
4043            None,
4044        )
4045        .into();
4046
4047        // Case 1: all-null primitive column should reuse the typed_value Arc directly
4048        let all_nulls_field_ref = FieldRef::from(Field::new("result", DataType::Int32, true));
4049        let all_nulls_result = variant_get(
4050            &variant_array,
4051            GetOptions::new_with_path(VariantPath::try_from("all_nulls").unwrap())
4052                .with_as_type(Some(all_nulls_field_ref)),
4053        )
4054        .unwrap();
4055        assert!(Arc::ptr_eq(&all_nulls_result, &all_nulls_erased));
4056
4057        // Case 2: primitive column with some nulls should also reuse its typed_value Arc
4058        let some_nulls_field_ref = FieldRef::from(Field::new("result", DataType::Int32, true));
4059        let some_nulls_result = variant_get(
4060            &variant_array,
4061            GetOptions::new_with_path(VariantPath::try_from("some_nulls").unwrap())
4062                .with_as_type(Some(some_nulls_field_ref)),
4063        )
4064        .unwrap();
4065        assert!(Arc::ptr_eq(&some_nulls_result, &some_nulls_erased));
4066
4067        // Case 3: struct column should return a StructArray composed from the nested field
4068        let struct_child_fields = Fields::from(vec![Field::new("inner", DataType::Int32, true)]);
4069        let struct_field_ref = FieldRef::from(Field::new(
4070            "result",
4071            DataType::Struct(struct_child_fields.clone()),
4072            true,
4073        ));
4074        let struct_result = variant_get(
4075            &variant_array,
4076            GetOptions::new_with_path(VariantPath::try_from("struct_field").unwrap())
4077                .with_as_type(Some(struct_field_ref)),
4078        )
4079        .unwrap();
4080        let struct_array = struct_result
4081            .as_any()
4082            .downcast_ref::<StructArray>()
4083            .unwrap();
4084        assert_eq!(struct_array.len(), 3);
4085        assert_eq!(struct_array.null_count(), 0);
4086
4087        let inner_values_result = struct_array
4088            .column(0)
4089            .as_any()
4090            .downcast_ref::<Int32Array>()
4091            .unwrap();
4092        assert_eq!(inner_values_result.len(), 3);
4093        assert_eq!(inner_values_result.value(0), 111);
4094        assert!(inner_values_result.is_null(1));
4095        assert_eq!(inner_values_result.value(2), 333);
4096    }
4097
4098    #[test]
4099    fn test_variant_get_list_like_safe_cast() {
4100        let string_array: ArrayRef = Arc::new(StringArray::from(vec![
4101            r#"{"outer":{"list":[1, "two", 3]}}"#,
4102            r#"{"outer":{"list":"not a list"}}"#,
4103        ]));
4104        let variant_array = ArrayRef::from(json_to_variant(&string_array).unwrap());
4105
4106        let element_array: ArrayRef = Arc::new(Int64Array::from(vec![Some(1), None, Some(3)]));
4107        let field = Arc::new(Field::new("item", Int64, true));
4108
4109        let expectations = vec![
4110            (
4111                DataType::List(field.clone()),
4112                Arc::new(ListArray::new(
4113                    field.clone(),
4114                    OffsetBuffer::new(ScalarBuffer::from(vec![0, 3, 3])),
4115                    element_array.clone(),
4116                    Some(NullBuffer::from(vec![true, false])),
4117                )) as ArrayRef,
4118            ),
4119            (
4120                DataType::LargeList(field.clone()),
4121                Arc::new(LargeListArray::new(
4122                    field.clone(),
4123                    OffsetBuffer::new(ScalarBuffer::from(vec![0, 3, 3])),
4124                    element_array.clone(),
4125                    Some(NullBuffer::from(vec![true, false])),
4126                )) as ArrayRef,
4127            ),
4128            (
4129                DataType::ListView(field.clone()),
4130                Arc::new(ListViewArray::new(
4131                    field.clone(),
4132                    ScalarBuffer::from(vec![0, 3]),
4133                    ScalarBuffer::from(vec![3, 0]),
4134                    element_array.clone(),
4135                    Some(NullBuffer::from(vec![true, false])),
4136                )) as ArrayRef,
4137            ),
4138            (
4139                DataType::LargeListView(field.clone()),
4140                Arc::new(LargeListViewArray::new(
4141                    field,
4142                    ScalarBuffer::from(vec![0, 3]),
4143                    ScalarBuffer::from(vec![3, 0]),
4144                    element_array,
4145                    Some(NullBuffer::from(vec![true, false])),
4146                )) as ArrayRef,
4147            ),
4148        ];
4149
4150        for (request_type, expected) in expectations {
4151            let options =
4152                GetOptions::new_with_path(VariantPath::try_from("outer").unwrap().join("list"))
4153                    .with_as_type(Some(FieldRef::from(Field::new(
4154                        "result",
4155                        request_type.clone(),
4156                        true,
4157                    ))));
4158
4159            let result = variant_get(&variant_array, options).unwrap();
4160            assert_eq!(result.data_type(), expected.data_type());
4161            assert_eq!(&result, &expected);
4162        }
4163
4164        for (idx, expected) in [
4165            (0, vec![Some(1), None]),
4166            (1, vec![None, None]),
4167            (2, vec![Some(3), None]),
4168        ] {
4169            let index_options = GetOptions::new_with_path(
4170                VariantPath::try_from("outer")
4171                    .unwrap()
4172                    .join("list")
4173                    .join(idx),
4174            )
4175            .with_as_type(Some(FieldRef::from(Field::new(
4176                "result",
4177                DataType::Int64,
4178                true,
4179            ))));
4180            let index_result = variant_get(&variant_array, index_options).unwrap();
4181            let index_expected: ArrayRef = Arc::new(Int64Array::from(expected));
4182            assert_eq!(&index_result, &index_expected);
4183        }
4184    }
4185
4186    #[test]
4187    fn test_variant_get_nested_list() {
4188        use arrow::datatypes::Int64Type;
4189
4190        let string_array: ArrayRef = Arc::new(StringArray::from(vec![
4191            r#"[[1, 2], [3]]"#,
4192            r#"[[4], "not a list", [5, 6]]"#,
4193        ]));
4194        let variant_array = ArrayRef::from(json_to_variant(&string_array).unwrap());
4195
4196        let inner_field = Arc::new(Field::new("item", Int64, true));
4197        let outer_field = Arc::new(Field::new(
4198            "item",
4199            DataType::List(inner_field.clone()),
4200            true,
4201        ));
4202        let request_type = DataType::List(outer_field.clone());
4203
4204        let options = GetOptions::new().with_as_type(Some(FieldRef::from(Field::new(
4205            "result",
4206            request_type,
4207            true,
4208        ))));
4209        let result = variant_get(&variant_array, options).unwrap();
4210        let outer = result.as_list::<i32>();
4211
4212        // Row 0: [[1, 2], [3]]
4213        let row0 = outer.value(0);
4214        let row0 = row0.as_list::<i32>();
4215        assert_eq!(row0.len(), 2);
4216        let elem0 = row0.value(0);
4217        assert_eq!(elem0.as_primitive::<Int64Type>().values(), &[1, 2]);
4218        let elem1 = row0.value(1);
4219        assert_eq!(elem1.as_primitive::<Int64Type>().values(), &[3]);
4220
4221        // Row 1: [[4], null, [5, 6]] — "not a list" becomes null inner list
4222        let row1 = outer.value(1);
4223        let row1 = row1.as_list::<i32>();
4224        assert_eq!(row1.len(), 3);
4225        let elem0 = row1.value(0);
4226        assert_eq!(elem0.as_primitive::<Int64Type>().values(), &[4]);
4227        assert!(row1.is_null(1));
4228        let elem2 = row1.value(2);
4229        assert_eq!(elem2.as_primitive::<Int64Type>().values(), &[5, 6]);
4230    }
4231
4232    #[test]
4233    fn test_variant_get_list_like_unsafe_cast_errors_on_element_mismatch() {
4234        let string_array: ArrayRef =
4235            Arc::new(StringArray::from(vec![r#"[1, "two", 3]"#, "[4, 5]"]));
4236        let variant_array = ArrayRef::from(json_to_variant(&string_array).unwrap());
4237        let cast_options = CastOptions {
4238            safe: false,
4239            ..Default::default()
4240        };
4241
4242        let item_field = Arc::new(Field::new("item", DataType::Int64, true));
4243        let request_types = vec![
4244            DataType::List(item_field.clone()),
4245            DataType::LargeList(item_field.clone()),
4246            DataType::ListView(item_field.clone()),
4247            DataType::LargeListView(item_field),
4248        ];
4249
4250        for request_type in request_types {
4251            let options = GetOptions::new()
4252                .with_as_type(Some(FieldRef::from(Field::new(
4253                    "result",
4254                    request_type.clone(),
4255                    true,
4256                ))))
4257                .with_cast_options(cast_options.clone());
4258
4259            let err = variant_get(&variant_array, options).unwrap_err();
4260            assert!(
4261                err.to_string()
4262                    .contains("Failed to extract primitive of type Int64")
4263            );
4264        }
4265    }
4266
4267    #[test]
4268    fn test_variant_get_list_like_unsafe_cast_preserves_null_elements() {
4269        let string_array: ArrayRef = Arc::new(StringArray::from(vec![r#"[1, null, 3]"#]));
4270        let variant_array = ArrayRef::from(json_to_variant(&string_array).unwrap());
4271        let cast_options = CastOptions {
4272            safe: false,
4273            ..Default::default()
4274        };
4275        let options = GetOptions::new()
4276            .with_as_type(Some(FieldRef::from(Field::new(
4277                "result",
4278                DataType::List(Arc::new(Field::new("item", DataType::Int64, true))),
4279                true,
4280            ))))
4281            .with_cast_options(cast_options);
4282
4283        let result = variant_get(&variant_array, options).unwrap();
4284        let list_array = result.as_any().downcast_ref::<ListArray>().unwrap();
4285        let values = list_array
4286            .values()
4287            .as_any()
4288            .downcast_ref::<Int64Array>()
4289            .unwrap();
4290
4291        assert_eq!(values.len(), 3);
4292        assert_eq!(values.value(0), 1);
4293        assert!(values.is_null(1));
4294        assert_eq!(values.value(2), 3);
4295    }
4296
4297    #[test]
4298    fn test_variant_get_list_like_unsafe_cast_errors_on_non_list() {
4299        let string_array: ArrayRef = Arc::new(StringArray::from(vec!["[1, 2]", "\"not a list\""]));
4300        let variant_array = ArrayRef::from(json_to_variant(&string_array).unwrap());
4301        let cast_options = CastOptions {
4302            safe: false,
4303            ..Default::default()
4304        };
4305        let item_field = Arc::new(Field::new("item", Int64, true));
4306        let data_types = vec![
4307            DataType::List(item_field.clone()),
4308            DataType::LargeList(item_field.clone()),
4309            DataType::ListView(item_field.clone()),
4310            DataType::LargeListView(item_field),
4311        ];
4312
4313        for data_type in data_types {
4314            let options = GetOptions::new()
4315                .with_as_type(Some(FieldRef::from(Field::new("result", data_type, true))))
4316                .with_cast_options(cast_options.clone());
4317
4318            let err = variant_get(&variant_array, options).unwrap_err();
4319            assert!(
4320                err.to_string()
4321                    .contains("Failed to extract list from variant"),
4322            );
4323        }
4324    }
4325
4326    #[test]
4327    fn test_variant_get_fixed_size_list_not_implemented() {
4328        let string_array: ArrayRef = Arc::new(StringArray::from(vec!["[1, 2]", "\"not a list\""]));
4329        let variant_array = ArrayRef::from(json_to_variant(&string_array).unwrap());
4330        let item_field = Arc::new(Field::new("item", Int64, true));
4331        for safe in [true, false] {
4332            let options = GetOptions::new()
4333                .with_as_type(Some(FieldRef::from(Field::new(
4334                    "result",
4335                    DataType::FixedSizeList(item_field.clone(), 2),
4336                    true,
4337                ))))
4338                .with_cast_options(CastOptions {
4339                    safe,
4340                    ..Default::default()
4341                });
4342
4343            let err = variant_get(&variant_array, options).unwrap_err();
4344            assert!(
4345                err.to_string()
4346                    .contains("Converting unshredded variant arrays to arrow fixed-size lists")
4347            );
4348        }
4349    }
4350
4351    macro_rules! perfectly_shredded_preserves_top_level_nulls_test {
4352        ($name:ident, $result_type:expr, $typed_value:expr, $expected_array:expr) => {
4353            perfectly_shredded_preserves_top_level_nulls_test!(
4354                $name,
4355                $result_type,
4356                $typed_value,
4357                Some(NullBuffer::from(vec![true, false, true])),
4358                $expected_array
4359            );
4360        };
4361        ($name:ident, $result_type:expr, $typed_value:expr, $parent_nulls:expr, $expected_array:expr) => {
4362            #[test]
4363            fn $name() {
4364                let metadata = Arc::new(BinaryViewArray::from_iter_values(std::iter::repeat_n(
4365                    EMPTY_VARIANT_METADATA_BYTES,
4366                    3,
4367                )));
4368                let typed_value: ArrayRef = Arc::new($typed_value);
4369                let variant_array: ArrayRef =
4370                    VariantArray::from_parts(metadata, None, Some(typed_value), $parent_nulls)
4371                        .into();
4372
4373                let result = variant_get(
4374                    &variant_array,
4375                    GetOptions::new().with_as_type(Some(FieldRef::from(Field::new(
4376                        "result",
4377                        $result_type,
4378                        true,
4379                    )))),
4380                )
4381                .unwrap();
4382
4383                let expected_array: ArrayRef = Arc::new($expected_array);
4384                assert_eq!(&result, &expected_array);
4385            }
4386        };
4387    }
4388
4389    perfectly_shredded_preserves_top_level_nulls_test!(
4390        test_variant_get_perfectly_shredded_integer_preserves_top_level_nulls,
4391        DataType::Int32,
4392        Int32Array::from(vec![Some(0_i32), Some(1_i32), Some(2_i32)]),
4393        Int32Array::from(vec![Some(0_i32), None, Some(2_i32)])
4394    );
4395
4396    perfectly_shredded_preserves_top_level_nulls_test!(
4397        test_variant_get_perfectly_shredded_integer_unions_child_and_top_level_nulls,
4398        DataType::Int32,
4399        Int32Array::from(vec![None, Some(1_i32), Some(2_i32)]),
4400        Some(NullBuffer::from(vec![true, false, true])),
4401        Int32Array::from(vec![None, None, Some(2_i32)])
4402    );
4403
4404    perfectly_shredded_preserves_top_level_nulls_test!(
4405        test_variant_get_perfectly_shredded_null_preserves_top_level_nulls,
4406        DataType::Null,
4407        NullArray::new(3),
4408        NullArray::new(3)
4409    );
4410
4411    perfectly_shredded_preserves_top_level_nulls_test!(
4412        test_variant_get_perfectly_shredded_binary_view_preserves_top_level_nulls,
4413        DataType::BinaryView,
4414        BinaryViewArray::from(vec![
4415            Some(b"Apache" as &[u8]),
4416            Some(b"masked-null" as &[u8]),
4417            Some(b"Parquet-variant" as &[u8]),
4418        ]),
4419        BinaryViewArray::from(vec![
4420            Some(b"Apache" as &[u8]),
4421            None,
4422            Some(b"Parquet-variant" as &[u8]),
4423        ])
4424    );
4425
4426    perfectly_shredded_preserves_top_level_nulls_test!(
4427        test_variant_get_perfectly_shredded_binary_preserves_top_level_nulls,
4428        DataType::Binary,
4429        BinaryArray::from(vec![
4430            Some(b"Apache" as &[u8]),
4431            Some(b"masked-null" as &[u8]),
4432            Some(b"Parquet-variant" as &[u8]),
4433        ]),
4434        BinaryArray::from(vec![
4435            Some(b"Apache" as &[u8]),
4436            None,
4437            Some(b"Parquet-variant" as &[u8]),
4438        ])
4439    );
4440
4441    perfectly_shredded_preserves_top_level_nulls_test!(
4442        test_variant_get_perfectly_shredded_decimal4_preserves_top_level_nulls,
4443        DataType::Decimal32(5, 2),
4444        Decimal32Array::from(vec![Some(12345), Some(23400), Some(-12342)])
4445            .with_precision_and_scale(5, 2)
4446            .unwrap(),
4447        Decimal32Array::from(vec![Some(12345), None, Some(-12342)])
4448            .with_precision_and_scale(5, 2)
4449            .unwrap()
4450    );
4451
4452    perfectly_shredded_preserves_top_level_nulls_test!(
4453        test_variant_get_perfectly_shredded_decimal8_preserves_top_level_nulls,
4454        DataType::Decimal64(10, 1),
4455        Decimal64Array::from(vec![Some(1234567809), Some(1456787000), Some(-1234561203)])
4456            .with_precision_and_scale(10, 1)
4457            .unwrap(),
4458        Decimal64Array::from(vec![Some(1234567809), None, Some(-1234561203)])
4459            .with_precision_and_scale(10, 1)
4460            .unwrap()
4461    );
4462
4463    perfectly_shredded_preserves_top_level_nulls_test!(
4464        test_variant_get_perfectly_shredded_decimal16_preserves_top_level_nulls,
4465        DataType::Decimal128(20, 3),
4466        Decimal128Array::from(vec![
4467            Some(i128::from_str("12345678901234567899").unwrap()),
4468            Some(i128::from_str("23445677483748324300").unwrap()),
4469            Some(i128::from_str("-12345678901234567899").unwrap()),
4470        ])
4471        .with_precision_and_scale(20, 3)
4472        .unwrap(),
4473        Decimal128Array::from(vec![
4474            Some(i128::from_str("12345678901234567899").unwrap()),
4475            None,
4476            Some(i128::from_str("-12345678901234567899").unwrap()),
4477        ])
4478        .with_precision_and_scale(20, 3)
4479        .unwrap()
4480    );
4481}