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