Coverage Report

Created: 2025-08-26 07:03

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::builder::*;
19
use crate::StructArray;
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
24
    fn len(&self) -> usize {
125
24
        self.null_buffer_builder.len()
126
24
    }
127
128
    /// Builds the array.
129
6
    fn finish(&mut self) -> ArrayRef {
130
6
        Arc::new(self.finish())
131
6
    }
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
1
    fn as_any_mut(&mut self) -> &mut dyn Any {
153
1
        self
154
1
    }
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
8
    pub fn new(fields: impl Into<Fields>, field_builders: Vec<Box<dyn ArrayBuilder>>) -> Self {
165
8
        Self {
166
8
            field_builders,
167
8
            fields: fields.into(),
168
8
            null_buffer_builder: NullBufferBuilder::new(0),
169
8
        }
170
8
    }
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
19
    pub fn field_builder<T: ArrayBuilder>(&mut self, i: usize) -> Option<&mut T> {
186
19
        self.field_builders[i].as_any_mut().downcast_mut::<T>()
187
19
    }
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
    /// Appends an element (either null or non-null) to the struct. The actual elements
205
    /// should be appended for each child sub-array in a consistent way.
206
    #[inline]
207
12
    pub fn append(&mut self, is_valid: bool) {
208
12
        self.null_buffer_builder.append(is_valid);
209
12
    }
210
211
    /// Appends a null element to the struct.
212
    #[inline]
213
    pub fn append_null(&mut self) {
214
        self.append(false)
215
    }
216
217
    /// Appends `n` `null`s into the builder.
218
    #[inline]
219
    pub fn append_nulls(&mut self, n: usize) {
220
        self.null_buffer_builder.append_slice(&vec![false; n]);
221
    }
222
223
    /// Builds the `StructArray` and reset this builder.
224
8
    pub fn finish(&mut self) -> StructArray {
225
8
        self.validate_content();
226
8
        if self.fields.is_empty() {
227
0
            return StructArray::new_empty_fields(self.len(), self.null_buffer_builder.finish());
228
8
        }
229
230
13
        let 
arrays8
=
self.field_builders.iter_mut()8
.
map8
(|f| f.finish()).
collect8
();
231
8
        let nulls = self.null_buffer_builder.finish();
232
8
        StructArray::new(self.fields.clone(), arrays, nulls)
233
8
    }
234
235
    /// Builds the `StructArray` without resetting the builder.
236
0
    pub fn finish_cloned(&self) -> StructArray {
237
0
        self.validate_content();
238
239
0
        if self.fields.is_empty() {
240
0
            return StructArray::new_empty_fields(
241
0
                self.len(),
242
0
                self.null_buffer_builder.finish_cloned(),
243
            );
244
0
        }
245
246
0
        let arrays = self
247
0
            .field_builders
248
0
            .iter()
249
0
            .map(|f| f.finish_cloned())
250
0
            .collect();
251
252
0
        let nulls = self.null_buffer_builder.finish_cloned();
253
254
0
        StructArray::new(self.fields.clone(), arrays, nulls)
255
0
    }
256
257
    /// Constructs and validates contents in the builder to ensure that
258
    /// - fields and field_builders are of equal length
259
    /// - the number of items in individual field_builders are equal to self.len()
260
8
    fn validate_content(&self) {
261
8
        if self.fields.len() != self.field_builders.len() {
262
0
            panic!("Number of fields is not equal to the number of field_builders.");
263
8
        }
264
13
        
self.field_builders.iter()8
.
enumerate8
().
for_each8
(|(idx, x)| {
265
13
            if x.len() != self.len() {
266
0
                let builder = SchemaBuilder::from(&self.fields);
267
0
                let schema = builder.finish();
268
269
0
                panic!("{}", format!(
270
0
                    "StructBuilder ({:?}) and field_builder with index {} ({:?}) are of unequal lengths: ({} != {}).",
271
                    schema,
272
                    idx,
273
0
                    self.fields[idx].data_type(),
274
0
                    self.len(),
275
0
                    x.len()
276
                ));
277
13
            }
278
13
        });
279
8
    }
280
281
    /// Returns the current null buffer as a slice
282
0
    pub fn validity_slice(&self) -> Option<&[u8]> {
283
0
        self.null_buffer_builder.as_slice()
284
0
    }
285
}
286
287
#[cfg(test)]
288
mod tests {
289
    use std::any::type_name;
290
291
    use super::*;
292
    use arrow_buffer::Buffer;
293
    use arrow_data::ArrayData;
294
    use arrow_schema::Field;
295
296
    use crate::{array::Array, types::ArrowDictionaryKeyType};
297
298
    #[test]
299
    fn test_struct_array_builder() {
300
        let string_builder = StringBuilder::new();
301
        let int_builder = Int32Builder::new();
302
303
        let fields = vec![
304
            Field::new("f1", DataType::Utf8, true),
305
            Field::new("f2", DataType::Int32, true),
306
        ];
307
        let field_builders = vec![
308
            Box::new(string_builder) as Box<dyn ArrayBuilder>,
309
            Box::new(int_builder) as Box<dyn ArrayBuilder>,
310
        ];
311
312
        let mut builder = StructBuilder::new(fields, field_builders);
313
        assert_eq!(2, builder.num_fields());
314
315
        let string_builder = builder
316
            .field_builder::<StringBuilder>(0)
317
            .expect("builder at field 0 should be string builder");
318
        string_builder.append_value("joe");
319
        string_builder.append_null();
320
        string_builder.append_null();
321
        string_builder.append_value("mark");
322
        string_builder.append_nulls(2);
323
        string_builder.append_value("terry");
324
325
        let int_builder = builder
326
            .field_builder::<Int32Builder>(1)
327
            .expect("builder at field 1 should be int builder");
328
        int_builder.append_value(1);
329
        int_builder.append_value(2);
330
        int_builder.append_null();
331
        int_builder.append_value(4);
332
        int_builder.append_nulls(2);
333
        int_builder.append_value(3);
334
335
        builder.append(true);
336
        builder.append(true);
337
        builder.append_null();
338
        builder.append(true);
339
340
        builder.append_nulls(2);
341
        builder.append(true);
342
343
        let struct_data = builder.finish().into_data();
344
345
        assert_eq!(7, struct_data.len());
346
        assert_eq!(3, struct_data.null_count());
347
        assert_eq!(&[75_u8], struct_data.nulls().unwrap().validity());
348
349
        let expected_string_data = ArrayData::builder(DataType::Utf8)
350
            .len(7)
351
            .null_bit_buffer(Some(Buffer::from(&[73_u8])))
352
            .add_buffer(Buffer::from_slice_ref([0, 3, 3, 3, 7, 7, 7, 12]))
353
            .add_buffer(Buffer::from_slice_ref(b"joemarkterry"))
354
            .build()
355
            .unwrap();
356
357
        let expected_int_data = ArrayData::builder(DataType::Int32)
358
            .len(7)
359
            .null_bit_buffer(Some(Buffer::from_slice_ref([75_u8])))
360
            .add_buffer(Buffer::from_slice_ref([1, 2, 0, 4, 4, 4, 3]))
361
            .build()
362
            .unwrap();
363
364
        assert_eq!(expected_string_data, struct_data.child_data()[0]);
365
        assert_eq!(expected_int_data, struct_data.child_data()[1]);
366
367
        assert!(struct_data.is_null(4));
368
        assert!(struct_data.is_null(5));
369
    }
370
371
    #[test]
372
    fn test_struct_array_builder_finish() {
373
        let int_builder = Int32Builder::new();
374
        let bool_builder = BooleanBuilder::new();
375
376
        let fields = vec![
377
            Field::new("f1", DataType::Int32, false),
378
            Field::new("f2", DataType::Boolean, false),
379
        ];
380
        let field_builders = vec![
381
            Box::new(int_builder) as Box<dyn ArrayBuilder>,
382
            Box::new(bool_builder) as Box<dyn ArrayBuilder>,
383
        ];
384
385
        let mut builder = StructBuilder::new(fields, field_builders);
386
        builder
387
            .field_builder::<Int32Builder>(0)
388
            .unwrap()
389
            .append_slice(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
390
        builder
391
            .field_builder::<BooleanBuilder>(1)
392
            .unwrap()
393
            .append_slice(&[
394
                false, true, false, true, false, true, false, true, false, true,
395
            ]);
396
397
        // Append slot values - all are valid.
398
        for _ in 0..10 {
399
            builder.append(true);
400
        }
401
402
        assert_eq!(10, builder.len());
403
404
        let arr = builder.finish();
405
406
        assert_eq!(10, arr.len());
407
        assert_eq!(0, builder.len());
408
409
        builder
410
            .field_builder::<Int32Builder>(0)
411
            .unwrap()
412
            .append_slice(&[1, 3, 5, 7, 9]);
413
        builder
414
            .field_builder::<BooleanBuilder>(1)
415
            .unwrap()
416
            .append_slice(&[false, true, false, true, false]);
417
418
        // Append slot values - all are valid.
419
        for _ in 0..5 {
420
            builder.append(true);
421
        }
422
423
        assert_eq!(5, builder.len());
424
425
        let arr = builder.finish();
426
427
        assert_eq!(5, arr.len());
428
        assert_eq!(0, builder.len());
429
    }
430
431
    #[test]
432
    fn test_build_fixed_size_list() {
433
        const LIST_LENGTH: i32 = 4;
434
        let fixed_size_list_dtype =
435
            DataType::new_fixed_size_list(DataType::Int32, LIST_LENGTH, false);
436
        let mut builder = make_builder(&fixed_size_list_dtype, 10);
437
        let builder = builder
438
            .as_any_mut()
439
            .downcast_mut::<FixedSizeListBuilder<Box<dyn ArrayBuilder>>>();
440
        match builder {
441
            Some(builder) => {
442
                assert_eq!(builder.value_length(), LIST_LENGTH);
443
                assert!(builder
444
                    .values()
445
                    .as_any_mut()
446
                    .downcast_mut::<Int32Builder>()
447
                    .is_some());
448
            }
449
            None => panic!("expected FixedSizeListBuilder, got a different builder type"),
450
        }
451
    }
452
453
    #[test]
454
    fn test_struct_array_builder_finish_cloned() {
455
        let int_builder = Int32Builder::new();
456
        let bool_builder = BooleanBuilder::new();
457
458
        let fields = vec![
459
            Field::new("f1", DataType::Int32, false),
460
            Field::new("f2", DataType::Boolean, false),
461
        ];
462
        let field_builders = vec![
463
            Box::new(int_builder) as Box<dyn ArrayBuilder>,
464
            Box::new(bool_builder) as Box<dyn ArrayBuilder>,
465
        ];
466
467
        let mut builder = StructBuilder::new(fields, field_builders);
468
        builder
469
            .field_builder::<Int32Builder>(0)
470
            .unwrap()
471
            .append_slice(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
472
        builder
473
            .field_builder::<BooleanBuilder>(1)
474
            .unwrap()
475
            .append_slice(&[
476
                false, true, false, true, false, true, false, true, false, true,
477
            ]);
478
479
        // Append slot values - all are valid.
480
        for _ in 0..10 {
481
            builder.append(true);
482
        }
483
484
        assert_eq!(10, builder.len());
485
486
        let mut arr = builder.finish_cloned();
487
488
        assert_eq!(10, arr.len());
489
        assert_eq!(10, builder.len());
490
491
        builder
492
            .field_builder::<Int32Builder>(0)
493
            .unwrap()
494
            .append_slice(&[1, 3, 5, 7, 9]);
495
        builder
496
            .field_builder::<BooleanBuilder>(1)
497
            .unwrap()
498
            .append_slice(&[false, true, false, true, false]);
499
500
        // Append slot values - all are valid.
501
        for _ in 0..5 {
502
            builder.append(true);
503
        }
504
505
        assert_eq!(15, builder.len());
506
507
        arr = builder.finish();
508
509
        assert_eq!(15, arr.len());
510
        assert_eq!(0, builder.len());
511
    }
512
513
    #[test]
514
    fn test_struct_array_builder_from_schema() {
515
        let mut fields = vec![
516
            Field::new("f1", DataType::Float32, false),
517
            Field::new("f2", DataType::Utf8, false),
518
        ];
519
        let sub_fields = vec![
520
            Field::new("g1", DataType::Int32, false),
521
            Field::new("g2", DataType::Boolean, false),
522
        ];
523
        let struct_type = DataType::Struct(sub_fields.into());
524
        fields.push(Field::new("f3", struct_type, false));
525
526
        let mut builder = StructBuilder::from_fields(fields, 5);
527
        assert_eq!(3, builder.num_fields());
528
        assert!(builder.field_builder::<Float32Builder>(0).is_some());
529
        assert!(builder.field_builder::<StringBuilder>(1).is_some());
530
        assert!(builder.field_builder::<StructBuilder>(2).is_some());
531
    }
532
533
    #[test]
534
    fn test_datatype_properties() {
535
        let fields = Fields::from(vec![
536
            Field::new("f1", DataType::Decimal128(1, 2), false),
537
            Field::new(
538
                "f2",
539
                DataType::Timestamp(TimeUnit::Millisecond, Some("+00:00".into())),
540
                false,
541
            ),
542
        ]);
543
        let mut builder = StructBuilder::from_fields(fields.clone(), 1);
544
        builder
545
            .field_builder::<Decimal128Builder>(0)
546
            .unwrap()
547
            .append_value(1);
548
        builder
549
            .field_builder::<TimestampMillisecondBuilder>(1)
550
            .unwrap()
551
            .append_value(1);
552
        builder.append(true);
553
        let array = builder.finish();
554
555
        assert_eq!(array.data_type(), &DataType::Struct(fields.clone()));
556
        assert_eq!(array.column(0).data_type(), fields[0].data_type());
557
        assert_eq!(array.column(1).data_type(), fields[1].data_type());
558
    }
559
560
    #[test]
561
    fn test_struct_array_builder_from_dictionary_type_int8_key() {
562
        test_struct_array_builder_from_dictionary_type_inner::<Int8Type>(DataType::Int8);
563
    }
564
565
    #[test]
566
    fn test_struct_array_builder_from_dictionary_type_int16_key() {
567
        test_struct_array_builder_from_dictionary_type_inner::<Int16Type>(DataType::Int16);
568
    }
569
570
    #[test]
571
    fn test_struct_array_builder_from_dictionary_type_int32_key() {
572
        test_struct_array_builder_from_dictionary_type_inner::<Int32Type>(DataType::Int32);
573
    }
574
575
    #[test]
576
    fn test_struct_array_builder_from_dictionary_type_int64_key() {
577
        test_struct_array_builder_from_dictionary_type_inner::<Int64Type>(DataType::Int64);
578
    }
579
580
    fn test_struct_array_builder_from_dictionary_type_inner<K: ArrowDictionaryKeyType>(
581
        key_type: DataType,
582
    ) {
583
        let dict_field = Field::new(
584
            "f1",
585
            DataType::Dictionary(Box::new(key_type), Box::new(DataType::Utf8)),
586
            false,
587
        );
588
        let fields = vec![dict_field.clone()];
589
        let expected_dtype = DataType::Struct(fields.into());
590
        let cloned_dict_field = dict_field.clone();
591
        let expected_child_dtype = dict_field.data_type();
592
        let mut struct_builder = StructBuilder::from_fields(vec![cloned_dict_field], 5);
593
        let Some(dict_builder) = struct_builder.field_builder::<StringDictionaryBuilder<K>>(0)
594
        else {
595
            panic!(
596
                "Builder should be StringDictionaryBuilder<{}>",
597
                type_name::<K>()
598
            )
599
        };
600
        dict_builder.append_value("dict string");
601
        struct_builder.append(true);
602
        let array = struct_builder.finish();
603
604
        assert_eq!(array.data_type(), &expected_dtype);
605
        assert_eq!(array.column(0).data_type(), expected_child_dtype);
606
        assert_eq!(array.column(0).len(), 1);
607
    }
608
609
    #[test]
610
    #[should_panic(
611
        expected = "Data type Dictionary(UInt64, Utf8) with key type UInt64 is not currently supported"
612
    )]
613
    fn test_struct_array_builder_from_schema_unsupported_type() {
614
        let fields = vec![
615
            Field::new("f1", DataType::UInt64, false),
616
            Field::new(
617
                "f2",
618
                DataType::Dictionary(Box::new(DataType::UInt64), Box::new(DataType::Utf8)),
619
                false,
620
            ),
621
        ];
622
623
        let _ = StructBuilder::from_fields(fields, 5);
624
    }
625
626
    #[test]
627
    #[should_panic(expected = "Dictionary value type Int32 is not currently supported")]
628
    fn test_struct_array_builder_from_dict_with_unsupported_value_type() {
629
        let fields = vec![Field::new(
630
            "f1",
631
            DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Int32)),
632
            false,
633
        )];
634
635
        let _ = StructBuilder::from_fields(fields, 5);
636
    }
637
638
    #[test]
639
    fn test_struct_array_builder_field_builder_type_mismatch() {
640
        let int_builder = Int32Builder::with_capacity(10);
641
642
        let fields = vec![Field::new("f1", DataType::Int32, false)];
643
        let field_builders = vec![Box::new(int_builder) as Box<dyn ArrayBuilder>];
644
645
        let mut builder = StructBuilder::new(fields, field_builders);
646
        assert!(builder.field_builder::<BinaryBuilder>(0).is_none());
647
    }
648
649
    #[test]
650
    #[should_panic(
651
        expected = "StructBuilder (Schema { fields: [Field { name: \"f1\", data_type: Int32, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }, Field { name: \"f2\", data_type: Boolean, nullable: false, dict_id: 0, dict_is_ordered: false, metadata: {} }], metadata: {} }) and field_builder with index 1 (Boolean) are of unequal lengths: (2 != 1)."
652
    )]
653
    fn test_struct_array_builder_unequal_field_builders_lengths() {
654
        let mut int_builder = Int32Builder::with_capacity(10);
655
        let mut bool_builder = BooleanBuilder::new();
656
657
        int_builder.append_value(1);
658
        int_builder.append_value(2);
659
        bool_builder.append_value(true);
660
661
        let fields = vec![
662
            Field::new("f1", DataType::Int32, false),
663
            Field::new("f2", DataType::Boolean, false),
664
        ];
665
        let field_builders = vec![
666
            Box::new(int_builder) as Box<dyn ArrayBuilder>,
667
            Box::new(bool_builder) as Box<dyn ArrayBuilder>,
668
        ];
669
670
        let mut builder = StructBuilder::new(fields, field_builders);
671
        builder.append(true);
672
        builder.append(true);
673
        builder.finish();
674
    }
675
676
    #[test]
677
    #[should_panic(expected = "Number of fields is not equal to the number of field_builders.")]
678
    fn test_struct_array_builder_unequal_field_field_builders() {
679
        let int_builder = Int32Builder::with_capacity(10);
680
681
        let fields = vec![
682
            Field::new("f1", DataType::Int32, false),
683
            Field::new("f2", DataType::Boolean, false),
684
        ];
685
        let field_builders = vec![Box::new(int_builder) as Box<dyn ArrayBuilder>];
686
687
        let mut builder = StructBuilder::new(fields, field_builders);
688
        builder.finish();
689
    }
690
691
    #[test]
692
    #[should_panic(
693
        expected = "Incorrect datatype for StructArray field \\\"timestamp\\\", expected Timestamp(Nanosecond, Some(\\\"UTC\\\")) got Timestamp(Nanosecond, None)"
694
    )]
695
    fn test_struct_array_mismatch_builder() {
696
        let fields = vec![Field::new(
697
            "timestamp",
698
            DataType::Timestamp(TimeUnit::Nanosecond, Some("UTC".to_owned().into())),
699
            false,
700
        )];
701
702
        let field_builders: Vec<Box<dyn ArrayBuilder>> =
703
            vec![Box::new(TimestampNanosecondBuilder::new())];
704
705
        let mut sa = StructBuilder::new(fields, field_builders);
706
        sa.finish();
707
    }
708
709
    #[test]
710
    fn test_empty() {
711
        let mut builder = StructBuilder::new(Fields::empty(), vec![]);
712
        builder.append(true);
713
        builder.append(false);
714
715
        let a1 = builder.finish_cloned();
716
        let a2 = builder.finish();
717
        assert_eq!(a1, a2);
718
        assert_eq!(a1.len(), 2);
719
        assert_eq!(a1.null_count(), 1);
720
        assert!(a1.is_valid(0));
721
        assert!(a1.is_null(1));
722
    }
723
}