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