Skip to main content

parquet_variant_compute/
variant_get.rs

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