## Coverage Report

#### Created: 2025-11-17 14:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /Users/andrewlamb/Software/arrow-rs/arrow-array/src/builder/struct_builder.rs

    Line
    Count
    Source
    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.
    17
    18
    use crate::StructArray;
    19
    use crate::builder::*;
    20
    use arrow_buffer::NullBufferBuilder;
    21
    use arrow_schema::{Fields, SchemaBuilder};
    22
    use std::sync::Arc;
    23
    24
    /// Builder for [`StructArray`]
    25
    ///
    26
    /// Note that callers should make sure that methods of all the child field builders are
    27
    /// properly called to maintain the consistency of the data structure.
    28
    ///
    29
    ///
    30
    /// Handling arrays with complex layouts, such as `List<Struct<List<Struct>>>`, in Rust can be challenging due to its strong typing system.
    31
    /// To construct a collection builder ([`ListBuilder`], [`LargeListBuilder`], or [`MapBuilder`]) using [`make_builder`], multiple calls are required. This complexity arises from the recursive approach utilized by [`StructBuilder::from_fields`].
    32
    ///
    33
    /// Initially, [`StructBuilder::from_fields`] invokes [`make_builder`], which returns a `Box<dyn ArrayBuilder>`. To obtain the specific collection builder, one must first use [`StructBuilder::field_builder`] to get a `Collection<[Box<dyn ArrayBuilder>]>`. Subsequently, the `values()` result from this operation can be downcast to the desired builder type.
    34
    ///
    35
    /// For example, when working with [`ListBuilder`], you would first call [`StructBuilder::field_builder::<ListBuilder<Box<dyn ArrayBuilder>>>`] and then downcast the [`Box<dyn ArrayBuilder>`] to the specific [`StructBuilder`] you need.
    36
    ///
    37
    /// For a practical example see the code below:
    38
    ///
    39
    /// ```rust
    40
    ///    use arrow_array::builder::{ArrayBuilder, ListBuilder, StringBuilder, StructBuilder};
    41
    ///    use arrow_schema::{DataType, Field, Fields};
    42
    ///    use std::sync::Arc;
    43
    ///
    44
    ///    // This is an example column that has a List<Struct<List<Struct>>> layout
    45
    ///    let mut example_col = ListBuilder::new(StructBuilder::from_fields(
    46
    ///        vec![Field::new(
    47
    ///            "value_list",
    48
    ///            DataType::List(Arc::new(Field::new_list_field(
    49
    ///                DataType::Struct(Fields::from(vec![
    50
    ///                    Field::new("key", DataType::Utf8, true),
    51
    ///                    Field::new("value", DataType::Utf8, true),
    52
    ///                ])), //In this example we are trying to get to this builder and insert key/value pairs
    53
    ///                true,
    54
    ///            ))),
    55
    ///            true,
    56
    ///        )],
    57
    ///        0,
    58
    ///    ));
    59
    ///
    60
    ///   // We can obtain the StructBuilder without issues, because example_col was created with StructBuilder
    61
    ///   let col_struct_builder: &mut StructBuilder = example_col.values();
    62
    ///
    63
    ///   // We can't obtain the ListBuilder<StructBuilder> with the expected generic types, because under the hood
    64
    ///   // the StructBuilder was returned as a Box<dyn ArrayBuilder> and passed as such to the ListBuilder constructor
    65
    ///
    66
    ///   // This panics in runtime, even though we know that the builder is a ListBuilder<StructBuilder>.
    67
    ///   // let sb = col_struct_builder
    68
    ///   //     .field_builder::<ListBuilder<StructBuilder>>(0)
    69
    ///   //     .as_mut()
    70
    ///   //     .unwrap();
    71
    ///
    72
    ///   //To keep in line with Rust's strong typing, we fetch a ListBuilder<Box<dyn ArrayBuilder>> from the column StructBuilder first...
    73
    ///   let mut list_builder_option =
    74
    ///       col_struct_builder.field_builder::<ListBuilder<Box<dyn ArrayBuilder>>>(0);
    75
    ///
    76
    ///   let list_builder = list_builder_option.as_mut().unwrap();
    77
    ///
    78
    ///   // ... and then downcast the key/value pair values to a StructBuilder
    79
    ///   let struct_builder = list_builder
    80
    ///       .values()
    81
    ///       .as_any_mut()
    82
    ///       .downcast_mut::<StructBuilder>()
    83
    ///       .unwrap();
    84
    ///
    85
    ///   // We can now append values to the StructBuilder
    86
    ///   let key_builder = struct_builder.field_builder::<StringBuilder>(0).unwrap();
    87
    ///   key_builder.append_value("my key");
    88
    ///
    89
    ///   let value_builder = struct_builder.field_builder::<StringBuilder>(1).unwrap();
    90
    ///   value_builder.append_value("my value");
    91
    ///
    92
    ///   struct_builder.append(true);
    93
    ///   list_builder.append(true);
    94
    ///   col_struct_builder.append(true);
    95
    ///   example_col.append(true);
    96
    ///
    97
    ///   let array = example_col.finish();
    98
    ///
    99
    ///   println!("My array: {:?}", array);
    100
    /// ```
    101
    ///
    102
    pub struct StructBuilder {
    103
        fields: Fields,
    104
        field_builders: Vec<Box<dyn ArrayBuilder>>,
    105
        null_buffer_builder: NullBufferBuilder,
    106
    }
    107
    108
    impl std::fmt::Debug for StructBuilder {
    109
    0
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    110
    0
            f.debug_struct("StructBuilder")
    111
    0
                .field("fields", &self.fields)
    112
    0
                .field("bitmap_builder", &self.null_buffer_builder)
    113
    0
                .field("len", &self.len())
    114
    0
                .finish()
    115
    0
        }
    116
    }
    117
    118
    impl ArrayBuilder for StructBuilder {
    119
        /// Returns the number of array slots in the builder.
    120
        ///
    121
        /// Note that this always return the first child field builder's length, and it is
    122
        /// the caller's responsibility to maintain the consistency that all the child field
    123
        /// builder should have the equal number of elements.
    124
    14
        fn len(&self) -> usize {
    125
    14
            self.null_buffer_builder.len()
    126
    14
        }
    127
    128
        /// Builds the array.
    129
    0
        fn finish(&mut self) -> ArrayRef {
    130
    0
            Arc::new(self.finish())
    131
    0
        }
    132
    133
        /// Builds the array without resetting the builder.
    134
    0
        fn finish_cloned(&self) -> ArrayRef {
    135
    0
            Arc::new(self.finish_cloned())
    136
    0
        }
    137
    138
        /// Returns the builder as a non-mutable `Any` reference.
    139
        ///
    140
        /// This is most useful when one wants to call non-mutable APIs on a specific builder
    141
        /// type. In this case, one can first cast this into a `Any`, and then use
    142
        /// `downcast_ref` to get a reference on the specific builder.
    143
    0
        fn as_any(&self) -> &dyn Any {
    144
    0
            self
    145
    0
        }
    146
    147
        /// Returns the builder as a mutable `Any` reference.
    148
        ///
    149
        /// This is most useful when one wants to call mutable APIs on a specific builder
    150
        /// type. In this case, one can first cast this into a `Any`, and then use
    151
        /// `downcast_mut` to get a reference on the specific builder.
    152
    0
        fn as_any_mut(&mut self) -> &mut dyn Any {
    153
    0
            self
    154
    0
        }
    155
    156
        /// Returns the boxed builder as a box of `Any`.
    157
    0
        fn into_box_any(self: Box<Self>) -> Box<dyn Any> {
    158
    0
            self
    159
    0
        }
    160
    }
    161
    162
    impl StructBuilder {
    163
        /// Creates a new `StructBuilder`
    164
    7
        pub fn new(fields: impl Into<Fields>, field_builders: Vec<Box<dyn ArrayBuilder>>) -> Self {
    165
    7
            Self {
    166
    7
                field_builders,
    167
    7
                fields: fields.into(),
    168
    7
                null_buffer_builder: NullBufferBuilder::new(0),
    169
    7
            }
    170
    7
        }
    171
    172
        /// Creates a new `StructBuilder` from [`Fields`] and `capacity`
    173
    0
        pub fn from_fields(fields: impl Into<Fields>, capacity: usize) -> Self {
    174
    0
            let fields = fields.into();
    175
    0
            let mut builders = Vec::with_capacity(fields.len());
    176
    0
            for field in &fields {
    177
    0
                builders.push(make_builder(field.data_type(), capacity));
    178
    0
            }
    179
    0
            Self::new(fields, builders)
    180
    0
        }
    181
    182
        /// Returns a mutable reference to the child field builder at index `i`.
    183
        /// Result will be `None` if the input type `T` provided doesn't match the actual
    184
        /// field builder's type.
    185
    78
        pub fn field_builder<T: ArrayBuilder>(&mut self, i: usize) -> Option<&mut T> {
    186
    78
            self.field_builders[i].as_any_mut().downcast_mut::<T>()
    187
    78
        }
    188
    189
        /// Returns a reference to field builders
    190
    0
        pub fn field_builders(&self) -> &[Box<dyn ArrayBuilder>] {
    191
    0
            &self.field_builders
    192
    0
        }
    193
    194
        /// Returns a mutable reference to field builders
    195
    0
        pub fn field_builders_mut(&mut self) -> &mut [Box<dyn ArrayBuilder>] {
    196
    0
            &mut self.field_builders
    197
    0
        }
    198
    199
        /// Returns the number of fields for the struct this builder is building.
    200
    0
        pub fn num_fields(&self) -> usize {
    201
    0
            self.field_builders.len()
    202
    0
        }
    203
    204
        /// Returns the fields for the struct this builder is building.
    205
    0
        pub fn fields(&self) -> &Fields {
    206
    0
            &self.fields
    207
    0
        }
    208
    209
        /// Appends an element (either null or non-null) to the struct. The actual elements
    210
        /// should be appended for each child sub-array in a consistent way.
    211
        #[inline]
    212
    39
        pub fn append(&mut self, is_valid: bool) {
    213
    39
            self.null_buffer_builder.append(is_valid);
    214
    39
        }
    215
    216
        /// Appends a null element to the struct.
    217
        #[inline]
    218
        pub fn append_null(&mut self) {
    219
            self.append(false)
    220
        }
    221
    222
        /// Appends `n` `null`s into the builder.
    223
        #[inline]
    224
        pub fn append_nulls(&mut self, n: usize) {
    225
            self.null_buffer_builder.append_slice(&vec![false; n]);
    226
        }
    227
    228
        /// Builds the `StructArray` and reset this builder.
    229
    7
        pub fn finish(&mut self) -> StructArray {
    230
    7
            self.validate_content();
    231
    7
            if self.fields.is_empty() {
    232
    0
                return StructArray::new_empty_fields(self.len(), self.null_buffer_builder.finish());
    233
    7
            }
    234
    235
    14
            let arrays7 = self.field_builders.iter_mut()7.map7(|f| f.finish()).collect7();
    236
    7
            let nulls = self.null_buffer_builder.finish();
    237
    7
            StructArray::new(self.fields.clone(), arrays, nulls)
    238
    7
        }
    239
    240
        /// Builds the `StructArray` without resetting the builder.
    241
    0
        pub fn finish_cloned(&self) -> StructArray {
    242
    0
            self.validate_content();
    243
    244
    0
            if self.fields.is_empty() {
    245
    0
                return StructArray::new_empty_fields(
    246
    0
                    self.len(),
    247
    0
                    self.null_buffer_builder.finish_cloned(),
    248
                );
    249
    0
            }
    250
    251
    0
            let arrays = self
    252
    0
                .field_builders
    253
    0
                .iter()
    254
    0
                .map(|f| f.finish_cloned())
    255
    0
                .collect();
    256
    257
    0
            let nulls = self.null_buffer_builder.finish_cloned();
    258
    259
    0
            StructArray::new(self.fields.clone(), arrays, nulls)
    260
    0
        }
    261
    262
        /// Constructs and validates contents in the builder to ensure that
    263
        /// - fields and field_builders are of equal length
    264
        /// - the number of items in individual field_builders are equal to self.len()
    265
    7
        fn validate_content(&self) {
    266
    7
            if self.fields.len() != self.field_builders.len() {
    267
    0
                panic!("Number of fields is not equal to the number of field_builders.");
    268
    7
            }
    269
    14
            self.field_builders.iter()7.enumerate7().for_each7(|(idx, x)| {
    270
    14
                if x.len() != self.len() {
    271
    0
                    let builder = SchemaBuilder::from(&self.fields);
    272
    0
                    let schema = builder.finish();
    273
    274
    0
                    panic!("{}", format!(
    275
    0
                        "StructBuilder ({}) and field_builder with index {} ({}) are of unequal lengths: ({} != {}).",
    276
                        schema,
    277
                        idx,
    278
    0
                        self.fields[idx].data_type(),
    279
    0
                        self.len(),
    280
    0
                        x.len()
    281
                    ));
    282
    14
                }
    283
    14
            });
    284
    7
        }
    285
    286
        /// Returns the current null buffer as a slice
    287
    0
        pub fn validity_slice(&self) -> Option<&[u8]> {
    288
    0
            self.null_buffer_builder.as_slice()
    289
    0
        }
    290
    }
    291
    292
    #[cfg(test)]
    293
    mod tests {
    294
        use std::any::type_name;
    295
    296
        use super::*;
    297
        use arrow_buffer::Buffer;
    298
        use arrow_data::ArrayData;
    299
        use arrow_schema::Field;
    300
    301
        use crate::{array::Array, types::ArrowDictionaryKeyType};
    302
    303
        #[test]
    304
        fn test_struct_array_builder() {
    305
            let string_builder = StringBuilder::new();
    306
            let int_builder = Int32Builder::new();
    307
    308
            let fields = vec![
    309
                Field::new("f1", DataType::Utf8, true),
    310
                Field::new("f2", DataType::Int32, true),
    311
            ];
    312
            let field_builders = vec![
    313
                Box::new(string_builder) as Box<dyn ArrayBuilder>,
    314
                Box::new(int_builder) as Box<dyn ArrayBuilder>,
    315
            ];
    316
    317
            let mut builder = StructBuilder::new(fields, field_builders);
    318
            assert_eq!(2, builder.num_fields());
    319
    320
            let string_builder = builder
    321
                .field_builder::<StringBuilder>(0)
    322
                .expect("builder at field 0 should be string builder");
    323
            string_builder.append_value("joe");
    324
            string_builder.append_null();
    325
            string_builder.append_null();
    326
            string_builder.append_value("mark");
    327
            string_builder.append_nulls(2);
    328
            string_builder.append_value("terry");
    329
    330
            let int_builder = builder
    331
                .field_builder::<Int32Builder>(1)
    332
                .expect("builder at field 1 should be int builder");
    333
            int_builder.append_value(1);
    334
            int_builder.append_value(2);
    335
            int_builder.append_null();
    336
            int_builder.append_value(4);
    337
            int_builder.append_nulls(2);
    338
            int_builder.append_value(3);
    339
    340
            builder.append(true);
    341
            builder.append(true);
    342
            builder.append_null();
    343
            builder.append(true);
    344
    345
            builder.append_nulls(2);
    346
            builder.append(true);
    347
    348
            let struct_data = builder.finish().into_data();
    349
    350
            assert_eq!(7, struct_data.len());
    351
            assert_eq!(3, struct_data.null_count());
    352
            assert_eq!(&[75_u8], struct_data.nulls().unwrap().validity());
    353
    354
            let expected_string_data = ArrayData::builder(DataType::Utf8)
    355
                .len(7)
    356
                .null_bit_buffer(Some(Buffer::from(&[73_u8])))
    357
                .add_buffer(Buffer::from_slice_ref([0, 3, 3, 3, 7, 7, 7, 12]))
    358
                .add_buffer(Buffer::from_slice_ref(b"joemarkterry"))
    359
                .build()
    360
                .unwrap();
    361
    362
            let expected_int_data = ArrayData::builder(DataType::Int32)
    363
                .len(7)
    364
                .null_bit_buffer(Some(Buffer::from_slice_ref([75_u8])))
    365
                .add_buffer(Buffer::from_slice_ref([1, 2, 0, 4, 4, 4, 3]))
    366
                .build()
    367
                .unwrap();
    368
    369
            assert_eq!(expected_string_data, struct_data.child_data()[0]);
    370
            assert_eq!(expected_int_data, struct_data.child_data()[1]);
    371
    372
            assert!(struct_data.is_null(4));
    373
            assert!(struct_data.is_null(5));
    374
        }
    375
    376
        #[test]
    377
        fn test_struct_array_builder_finish() {
    378
            let int_builder = Int32Builder::new();
    379
            let bool_builder = BooleanBuilder::new();
    380
    381
            let fields = vec![
    382
                Field::new("f1", DataType::Int32, false),
    383
                Field::new("f2", DataType::Boolean, false),
    384
            ];
    385
            let field_builders = vec![
    386
                Box::new(int_builder) as Box<dyn ArrayBuilder>,
    387
                Box::new(bool_builder) as Box<dyn ArrayBuilder>,
    388
            ];
    389
    390
            let mut builder = StructBuilder::new(fields, field_builders);
    391
            builder
    392
                .field_builder::<Int32Builder>(0)
    393
                .unwrap()
    394
                .append_slice(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    395
            builder
    396
                .field_builder::<BooleanBuilder>(1)
    397
                .unwrap()
    398
                .append_slice(&[
    399
                    false, true, false, true, false, true, false, true, false, true,
    400
                ]);
    401
    402
            // Append slot values - all are valid.
    403
            for _ in 0..10 {
    404
                builder.append(true);
    405
            }
    406
    407
            assert_eq!(10, builder.len());
    408
    409
            let arr = builder.finish();
    410
    411
            assert_eq!(10, arr.len());
    412
            assert_eq!(0, builder.len());
    413
    414
            builder
    415
                .field_builder::<Int32Builder>(0)
    416
                .unwrap()
    417
                .append_slice(&[1, 3, 5, 7, 9]);
    418
            builder
    419
                .field_builder::<BooleanBuilder>(1)
    420
                .unwrap()
    421
                .append_slice(&[false, true, false, true, false]);
    422
    423
            // Append slot values - all are valid.
    424
            for _ in 0..5 {
    425
                builder.append(true);
    426
            }
    427
    428
            assert_eq!(5, builder.len());
    429
    430
            let arr = builder.finish();
    431
    432
            assert_eq!(5, arr.len());
    433
            assert_eq!(0, builder.len());
    434
        }
    435
    436
        #[test]
    437
        fn test_build_fixed_size_list() {
    438
            const LIST_LENGTH: i32 = 4;
    439
            let fixed_size_list_dtype =
    440
                DataType::new_fixed_size_list(DataType::Int32, LIST_LENGTH, false);
    441
            let mut builder = make_builder(&fixed_size_list_dtype, 10);
    442
            let builder = builder
    443
                .as_any_mut()
    444
                .downcast_mut::<FixedSizeListBuilder<Box<dyn ArrayBuilder>>>();
    445
            match builder {
    446
                Some(builder) => {
    447
                    assert_eq!(builder.value_length(), LIST_LENGTH);
    448
                    assert!(
    449
                        builder
    450
                            .values()
    451
                            .as_any_mut()
    452
                            .downcast_mut::<Int32Builder>()
    453
                            .is_some()
    454
                    );
    455
                }
    456
                None => panic!("expected FixedSizeListBuilder, got a different builder type"),
    457
            }
    458
        }
    459
    460
        #[test]
    461
        fn test_struct_array_builder_finish_cloned() {
    462
            let int_builder = Int32Builder::new();
    463
            let bool_builder = BooleanBuilder::new();
    464
    465
            let fields = vec![
    466
                Field::new("f1", DataType::Int32, false),
    467
                Field::new("f2", DataType::Boolean, false),
    468
            ];
    469
            let field_builders = vec![
    470
                Box::new(int_builder) as Box<dyn ArrayBuilder>,
    471
                Box::new(bool_builder) as Box<dyn ArrayBuilder>,
    472
            ];
    473
    474
            let mut builder = StructBuilder::new(fields, field_builders);
    475
            builder
    476
                .field_builder::<Int32Builder>(0)
    477
                .unwrap()
    478
                .append_slice(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    479
            builder
    480
                .field_builder::<BooleanBuilder>(1)
    481
                .unwrap()
    482
                .append_slice(&[
    483
                    false, true, false, true, false, true, false, true, false, true,
    484
                ]);
    485
    486
            // Append slot values - all are valid.
    487
            for _ in 0..10 {
    488
                builder.append(true);
    489
            }
    490
    491
            assert_eq!(10, builder.len());
    492
    493
            let mut arr = builder.finish_cloned();
    494
    495
            assert_eq!(10, arr.len());
    496
            assert_eq!(10, builder.len());
    497
    498
            builder
    499
                .field_builder::<Int32Builder>(0)
    500
                .unwrap()
    501
                .append_slice(&[1, 3, 5, 7, 9]);
    502
            builder
    503
                .field_builder::<BooleanBuilder>(1)
    504
                .unwrap()
    505
                .append_slice(&[false, true, false, true, false]);
    506
    507
            // Append slot values - all are valid.
    508
            for _ in 0..5 {
    509
                builder.append(true);
    510
            }
    511
    512
            assert_eq!(15, builder.len());
    513
    514
            arr = builder.finish();
    515
    516
            assert_eq!(15, arr.len());
    517
            assert_eq!(0, builder.len());
    518
        }
    519
    520
        #[test]
    521
        fn test_struct_array_builder_from_schema() {
    522
            let mut fields = vec![
    523
                Field::new("f1", DataType::Float32, false),
    524
                Field::new("f2", DataType::Utf8, false),
    525
            ];
    526
            let sub_fields = vec![
    527
                Field::new("g1", DataType::Int32, false),
    528
                Field::new("g2", DataType::Boolean, false),
    529
            ];
    530
            let struct_type = DataType::Struct(sub_fields.into());
    531
            fields.push(Field::new("f3", struct_type, false));
    532
    533
            let mut builder = StructBuilder::from_fields(fields, 5);
    534
            assert_eq!(3, builder.num_fields());
    535
            assert!(builder.field_builder::<Float32Builder>(0).is_some());
    536
            assert!(builder.field_builder::<StringBuilder>(1).is_some());
    537
            assert!(builder.field_builder::<StructBuilder>(2).is_some());
    538
        }
    539
    540
        #[test]
    541
        fn test_datatype_properties() {
    542
            let fields = Fields::from(vec![
    543
                Field::new("f1", DataType::Decimal128(1, 2), false),
    544
                Field::new(
    545
                    "f2",
    546
                    DataType::Timestamp(TimeUnit::Millisecond, Some("+00:00".into())),
    547
                    false,
    548
                ),
    549
            ]);
    550
            let mut builder = StructBuilder::from_fields(fields.clone(), 1);
    551
            builder
    552
                .field_builder::<Decimal128Builder>(0)
    553
                .unwrap()
    554
                .append_value(1);
    555
            builder
    556
                .field_builder::<TimestampMillisecondBuilder>(1)
    557
                .unwrap()
    558
                .append_value(1);
    559
            builder.append(true);
    560
            let array = builder.finish();
    561
    562
            assert_eq!(array.data_type(), &DataType::Struct(fields.clone()));
    563
            assert_eq!(array.column(0).data_type(), fields[0].data_type());
    564
            assert_eq!(array.column(1).data_type(), fields[1].data_type());
    565
        }
    566
    567
        #[test]
    568
        fn test_struct_array_builder_from_dictionary_type_int8_key() {
    569
            test_struct_array_builder_from_dictionary_type_inner::<Int8Type>(DataType::Int8);
    570
        }
    571
    572
        #[test]
    573
        fn test_struct_array_builder_from_dictionary_type_int16_key() {
    574
            test_struct_array_builder_from_dictionary_type_inner::<Int16Type>(DataType::Int16);
    575
        }
    576
    577
        #[test]
    578
        fn test_struct_array_builder_from_dictionary_type_int32_key() {
    579
            test_struct_array_builder_from_dictionary_type_inner::<Int32Type>(DataType::Int32);
    580
        }
    581
    582
        #[test]
    583
        fn test_struct_array_builder_from_dictionary_type_int64_key() {
    584
            test_struct_array_builder_from_dictionary_type_inner::<Int64Type>(DataType::Int64);
    585
        }
    586
    587
        fn test_struct_array_builder_from_dictionary_type_inner<K: ArrowDictionaryKeyType>(
    588
            key_type: DataType,
    589
        ) {
    590
            let dict_field = Field::new(
    591
                "f1",
    592
                DataType::Dictionary(Box::new(key_type), Box::new(DataType::Utf8)),
    593
                false,
    594
            );
    595
            let fields = vec![dict_field.clone()];
    596
            let expected_dtype = DataType::Struct(fields.into());
    597
            let cloned_dict_field = dict_field.clone();
    598
            let expected_child_dtype = dict_field.data_type();
    599
            let mut struct_builder = StructBuilder::from_fields(vec![cloned_dict_field], 5);
    600
            let Some(dict_builder) = struct_builder.field_builder::<StringDictionaryBuilder<K>>(0)
    601
            else {
    602
                panic!(
    603
                    "Builder should be StringDictionaryBuilder<{}>",
    604
                    type_name::<K>()
    605
                )
    606
            };
    607
            dict_builder.append_value("dict string");
    608
            struct_builder.append(true);
    609
            let array = struct_builder.finish();
    610
    611
            assert_eq!(array.data_type(), &expected_dtype);
    612
            assert_eq!(array.column(0).data_type(), expected_child_dtype);
    613
            assert_eq!(array.column(0).len(), 1);
    614
        }
    615
    616
        #[test]
    617
        #[should_panic(
    618
            expected = "Data type Dictionary(UInt64, Utf8) with key type UInt64 is not currently supported"
    619
        )]
    620
        fn test_struct_array_builder_from_schema_unsupported_type() {
    621
            let fields = vec![
    622
                Field::new("f1", DataType::UInt64, false),
    623
                Field::new(
    624
                    "f2",
    625
                    DataType::Dictionary(Box::new(DataType::UInt64), Box::new(DataType::Utf8)),
    626
                    false,
    627
                ),
    628
            ];
    629
    630
            let _ = StructBuilder::from_fields(fields, 5);
    631
        }
    632
    633
        #[test]
    634
        #[should_panic(expected = "Dictionary value type Int32 is not currently supported")]
    635
        fn test_struct_array_builder_from_dict_with_unsupported_value_type() {
    636
            let fields = vec![Field::new(
    637
                "f1",
    638
                DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Int32)),
    639
                false,
    640
            )];
    641
    642
            let _ = StructBuilder::from_fields(fields, 5);
    643
        }
    644
    645
        #[test]
    646
        fn test_struct_array_builder_field_builder_type_mismatch() {
    647
            let int_builder = Int32Builder::with_capacity(10);
    648
    649
            let fields = vec![Field::new("f1", DataType::Int32, false)];
    650
            let field_builders = vec![Box::new(int_builder) as Box<dyn ArrayBuilder>];
    651
    652
            let mut builder = StructBuilder::new(fields, field_builders);
    653
            assert!(builder.field_builder::<BinaryBuilder>(0).is_none());
    654
        }
    655
    656
        #[test]
    657
        #[should_panic(
    658
            expected = "StructBuilder (Field { \"f1\": Int32 }, Field { \"f2\": Boolean }) and field_builder with index 1 (Boolean) are of unequal lengths: (2 != 1)."
    659
        )]
    660
        fn test_struct_array_builder_unequal_field_builders_lengths() {
    661
            let mut int_builder = Int32Builder::with_capacity(10);
    662
            let mut bool_builder = BooleanBuilder::new();
    663
    664
            int_builder.append_value(1);
    665
            int_builder.append_value(2);
    666
            bool_builder.append_value(true);
    667
    668
            let fields = vec![
    669
                Field::new("f1", DataType::Int32, false),
    670
                Field::new("f2", DataType::Boolean, false),
    671
            ];
    672
            let field_builders = vec![
    673
                Box::new(int_builder) as Box<dyn ArrayBuilder>,
    674
                Box::new(bool_builder) as Box<dyn ArrayBuilder>,
    675
            ];
    676
    677
            let mut builder = StructBuilder::new(fields, field_builders);
    678
            builder.append(true);
    679
            builder.append(true);
    680
            builder.finish();
    681
        }
    682
    683
        #[test]
    684
        #[should_panic(expected = "Number of fields is not equal to the number of field_builders.")]
    685
        fn test_struct_array_builder_unequal_field_field_builders() {
    686
            let int_builder = Int32Builder::with_capacity(10);
    687
    688
            let fields = vec![
    689
                Field::new("f1", DataType::Int32, false),
    690
                Field::new("f2", DataType::Boolean, false),
    691
            ];
    692
            let field_builders = vec![Box::new(int_builder) as Box<dyn ArrayBuilder>];
    693
    694
            let mut builder = StructBuilder::new(fields, field_builders);
    695
            builder.finish();
    696
        }
    697
    698
        #[test]
    699
        #[should_panic(
    700
            expected = "Incorrect datatype for StructArray field \\\"timestamp\\\", expected Timestamp(ns, \\\"UTC\\\") got Timestamp(ns)"
    701
        )]
    702
        fn test_struct_array_mismatch_builder() {
    703
            let fields = vec![Field::new(
    704
                "timestamp",
    705
                DataType::Timestamp(TimeUnit::Nanosecond, Some("UTC".to_owned().into())),
    706
                false,
    707
            )];
    708
    709
            let field_builders: Vec<Box<dyn ArrayBuilder>> =
    710
                vec![Box::new(TimestampNanosecondBuilder::new())];
    711
    712
            let mut sa = StructBuilder::new(fields, field_builders);
    713
            sa.finish();
    714
        }
    715
    716
        #[test]
    717
        fn test_empty() {
    718
            let mut builder = StructBuilder::new(Fields::empty(), vec![]);
    719
            builder.append(true);
    720
            builder.append(false);
    721
    722
            let a1 = builder.finish_cloned();
    723
            let a2 = builder.finish();
    724
            assert_eq!(a1, a2);
    725
            assert_eq!(a1.len(), 2);
    726
            assert_eq!(a1.null_count(), 1);
    727
            assert!(a1.is_valid(0));
    728
            assert!(a1.is_null(1));
    729
        }
    730
    }