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