Skip to main content

parquet_variant_compute/
variant_get.rs

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