Skip to content

Commit 773cf18

Browse files
authored
feat: clarifying comments in struct_builder.rs #5494 (#5499)
* feat: clarifying comments in struct_builder.rs Added clarifying comments to StructBuilder about creating collection columns * fixed commented line, improved comments * Removed redundant line in comment * fixed slightly misleading comment * moved example code to comment * better comment * fixed comment type
1 parent 5dd5418 commit 773cf18

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

arrow-array/src/builder/struct_builder.rs

+77
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,81 @@ use std::sync::Arc;
2525
///
2626
/// Note that callers should make sure that methods of all the child field builders are
2727
/// 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(
49+
/// "item",
50+
/// DataType::Struct(Fields::from(vec![
51+
/// Field::new("key", DataType::Utf8, true),
52+
/// Field::new("value", DataType::Utf8, true),
53+
/// ])), //In this example we are trying to get to this builder and insert key/value pairs
54+
/// true,
55+
/// ))),
56+
/// true,
57+
/// )],
58+
/// 0,
59+
/// ));
60+
///
61+
/// // We can obtain the StructBuilder without issues, because example_col was created with StructBuilder
62+
/// let col_struct_builder: &mut StructBuilder = example_col.values();
63+
///
64+
/// // We can't obtain the ListBuilder<StructBuilder> with the expected generic types, because under the hood
65+
/// // the StructBuilder was returned as a Box<dyn ArrayBuilder> and passed as such to the ListBuilder constructor
66+
///
67+
/// // This panics in runtime, even though we know that the builder is a ListBuilder<StructBuilder>.
68+
/// // let sb = col_struct_builder
69+
/// // .field_builder::<ListBuilder<StructBuilder>>(0)
70+
/// // .as_mut()
71+
/// // .unwrap();
72+
///
73+
/// //To keep in line with Rust's strong typing, we fetch a ListBuilder<Box<dyn ArrayBuilder>> from the column StructBuilder first...
74+
/// let mut list_builder_option =
75+
/// col_struct_builder.field_builder::<ListBuilder<Box<dyn ArrayBuilder>>>(0);
76+
///
77+
/// let list_builder = list_builder_option.as_mut().unwrap();
78+
///
79+
/// // ... and then downcast the key/value pair values to a StructBuilder
80+
/// let struct_builder = list_builder
81+
/// .values()
82+
/// .as_any_mut()
83+
/// .downcast_mut::<StructBuilder>()
84+
/// .unwrap();
85+
///
86+
/// // We can now append values to the StructBuilder
87+
/// let key_builder = struct_builder.field_builder::<StringBuilder>(0).unwrap();
88+
/// key_builder.append_value("my key");
89+
///
90+
/// let value_builder = struct_builder.field_builder::<StringBuilder>(1).unwrap();
91+
/// value_builder.append_value("my value");
92+
///
93+
/// struct_builder.append(true);
94+
/// list_builder.append(true);
95+
/// col_struct_builder.append(true);
96+
/// example_col.append(true);
97+
///
98+
/// let array = example_col.finish();
99+
///
100+
/// println!("My array: {:?}", array);
101+
/// ```
102+
///
28103
pub struct StructBuilder {
29104
fields: Fields,
30105
field_builders: Vec<Box<dyn ArrayBuilder>>,
@@ -88,6 +163,8 @@ impl ArrayBuilder for StructBuilder {
88163
/// Returns a builder with capacity `capacity` that corresponds to the datatype `DataType`
89164
/// This function is useful to construct arrays from an arbitrary vectors with known/expected
90165
/// schema.
166+
///
167+
/// See comments on StructBuilder on how to retreive collection builders built by make_builder.
91168
pub fn make_builder(datatype: &DataType, capacity: usize) -> Box<dyn ArrayBuilder> {
92169
use crate::builder::*;
93170
match datatype {

0 commit comments

Comments
 (0)