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
}