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