Skip to main content

arrow_schema/
schema.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::fmt;
19use std::hash::Hash;
20use std::sync::Arc;
21
22use crate::error::ArrowError;
23use crate::field::Field;
24use crate::{DataType, FieldRef, Fields, Metadata};
25
26/// A builder to facilitate building a [`Schema`] from iteratively from [`FieldRef`]
27#[derive(Debug, Default)]
28pub struct SchemaBuilder {
29    fields: Vec<FieldRef>,
30    metadata: Metadata,
31}
32
33impl SchemaBuilder {
34    /// Creates a new empty [`SchemaBuilder`]
35    pub fn new() -> Self {
36        Self::default()
37    }
38
39    /// Creates a new empty [`SchemaBuilder`] with space for `capacity` fields
40    pub fn with_capacity(capacity: usize) -> Self {
41        Self {
42            fields: Vec::with_capacity(capacity),
43            metadata: Default::default(),
44        }
45    }
46
47    /// Appends a [`FieldRef`] to this [`SchemaBuilder`] without checking for collision
48    pub fn push(&mut self, field: impl Into<FieldRef>) {
49        self.fields.push(field.into())
50    }
51
52    /// Removes and returns the [`FieldRef`] as index `idx`
53    ///
54    /// # Panics
55    ///
56    /// Panics if index out of bounds
57    pub fn remove(&mut self, idx: usize) -> FieldRef {
58        self.fields.remove(idx)
59    }
60
61    /// Returns an immutable reference to the [`FieldRef`] at index `idx`
62    ///
63    /// # Panics
64    ///
65    /// Panics if index out of bounds
66    pub fn field(&mut self, idx: usize) -> &FieldRef {
67        &mut self.fields[idx]
68    }
69
70    /// Returns a mutable reference to the [`FieldRef`] at index `idx`
71    ///
72    /// # Panics
73    ///
74    /// Panics if index out of bounds
75    pub fn field_mut(&mut self, idx: usize) -> &mut FieldRef {
76        &mut self.fields[idx]
77    }
78
79    /// Returns an immutable reference to the Map of custom metadata key-value pairs.
80    pub fn metadata(&mut self) -> &Metadata {
81        &self.metadata
82    }
83
84    /// Returns a mutable reference to the Map of custom metadata key-value pairs.
85    pub fn metadata_mut(&mut self) -> &mut Metadata {
86        &mut self.metadata
87    }
88
89    /// Reverse the fileds
90    pub fn reverse(&mut self) {
91        self.fields.reverse();
92    }
93
94    /// Appends a [`FieldRef`] to this [`SchemaBuilder`] checking for collision
95    ///
96    /// If an existing field exists with the same name, calls [`Field::try_merge`]
97    pub fn try_merge(&mut self, field: &FieldRef) -> Result<(), ArrowError> {
98        // This could potentially be sped up with a HashMap or similar
99        let existing = self.fields.iter_mut().find(|f| f.name() == field.name());
100        match existing {
101            Some(e) if Arc::ptr_eq(e, field) => {} // Nothing to do
102            Some(e) => match Arc::get_mut(e) {
103                Some(e) => e.try_merge(field.as_ref())?,
104                None => {
105                    let mut t = e.as_ref().clone();
106                    t.try_merge(field)?;
107                    *e = Arc::new(t)
108                }
109            },
110            None => self.fields.push(field.clone()),
111        }
112        Ok(())
113    }
114
115    /// Consume this [`SchemaBuilder`] yielding the final [`Schema`]
116    pub fn finish(self) -> Schema {
117        Schema {
118            fields: self.fields.into(),
119            metadata: self.metadata,
120        }
121    }
122}
123
124impl From<&Fields> for SchemaBuilder {
125    fn from(value: &Fields) -> Self {
126        Self {
127            fields: value.to_vec(),
128            metadata: Default::default(),
129        }
130    }
131}
132
133impl From<Fields> for SchemaBuilder {
134    fn from(value: Fields) -> Self {
135        Self {
136            fields: value.to_vec(),
137            metadata: Default::default(),
138        }
139    }
140}
141
142impl From<&Schema> for SchemaBuilder {
143    fn from(value: &Schema) -> Self {
144        Self::from(value.clone())
145    }
146}
147
148impl From<Schema> for SchemaBuilder {
149    fn from(value: Schema) -> Self {
150        Self {
151            fields: value.fields.to_vec(),
152            metadata: value.metadata,
153        }
154    }
155}
156
157impl Extend<FieldRef> for SchemaBuilder {
158    fn extend<T: IntoIterator<Item = FieldRef>>(&mut self, iter: T) {
159        let iter = iter.into_iter();
160        self.fields.reserve(iter.size_hint().0);
161        for f in iter {
162            self.push(f)
163        }
164    }
165}
166
167impl Extend<Field> for SchemaBuilder {
168    fn extend<T: IntoIterator<Item = Field>>(&mut self, iter: T) {
169        let iter = iter.into_iter();
170        self.fields.reserve(iter.size_hint().0);
171        for f in iter {
172            self.push(f)
173        }
174    }
175}
176
177/// A reference-counted reference to a [`Schema`].
178pub type SchemaRef = Arc<Schema>;
179
180/// Describes the meta-data of an ordered sequence of relative types.
181///
182/// Note that this information is only part of the meta-data and not part of the physical
183/// memory layout.
184#[derive(Debug, Clone, PartialEq, Eq, Hash)]
185#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
186pub struct Schema {
187    /// A sequence of fields that describe the schema.
188    pub fields: Fields,
189    /// A map of key-value pairs containing additional metadata.
190    pub metadata: Metadata,
191}
192
193impl Schema {
194    /// Creates an empty `Schema`
195    pub fn empty() -> Self {
196        Self {
197            fields: Default::default(),
198            metadata: Default::default(),
199        }
200    }
201
202    /// Creates a new [`Schema`] from a sequence of [`Field`] values.
203    ///
204    /// # Example
205    ///
206    /// ```
207    /// # use arrow_schema::*;
208    /// let field_a = Field::new("a", DataType::Int64, false);
209    /// let field_b = Field::new("b", DataType::Boolean, false);
210    ///
211    /// let schema = Schema::new(vec![field_a, field_b]);
212    /// ```
213    pub fn new(fields: impl Into<Fields>) -> Self {
214        Self::new_with_metadata(fields, Metadata::new())
215    }
216
217    /// Creates a new [`Schema`] from a sequence of [`Field`] values
218    /// and adds additional metadata in form of key value pairs.
219    ///
220    /// # Example
221    ///
222    /// ```
223    /// # use arrow_schema::*;
224    /// let field_a = Field::new("a", DataType::Int64, false);
225    /// let field_b = Field::new("b", DataType::Boolean, false);
226    ///
227    /// let schema = Schema::new_with_metadata(vec![field_a, field_b], [("row_count", "100")]);
228    /// ```
229    #[inline]
230    pub fn new_with_metadata(fields: impl Into<Fields>, metadata: impl Into<Metadata>) -> Self {
231        Self {
232            fields: fields.into(),
233            metadata: metadata.into(),
234        }
235    }
236
237    /// Sets the metadata of this `Schema` to be `metadata` and returns self
238    pub fn with_metadata(mut self, metadata: impl Into<Metadata>) -> Self {
239        self.metadata = metadata.into();
240        self
241    }
242
243    /// Returns a new schema with only the specified columns in the new schema
244    /// This carries metadata from the parent schema over as well
245    pub fn project(&self, indices: &[usize]) -> Result<Schema, ArrowError> {
246        let new_fields = indices
247            .iter()
248            .map(|i| {
249                self.fields.get(*i).cloned().ok_or_else(|| {
250                    ArrowError::SchemaError(format!(
251                        "project index {} out of bounds, max field {}",
252                        i,
253                        self.fields().len()
254                    ))
255                })
256            })
257            .collect::<Result<Vec<_>, _>>()?;
258        Ok(Self::new_with_metadata(new_fields, self.metadata.clone()))
259    }
260
261    /// Merge schema into self if it is compatible. Struct fields will be merged recursively.
262    ///
263    /// Example:
264    ///
265    /// ```
266    /// # use arrow_schema::*;
267    ///
268    /// let merged = Schema::try_merge(vec![
269    ///     Schema::new(vec![
270    ///         Field::new("c1", DataType::Int64, false),
271    ///         Field::new("c2", DataType::Utf8, false),
272    ///     ]),
273    ///     Schema::new(vec![
274    ///         Field::new("c1", DataType::Int64, true),
275    ///         Field::new("c2", DataType::Utf8, false),
276    ///         Field::new("c3", DataType::Utf8, false),
277    ///     ]),
278    /// ]).unwrap();
279    ///
280    /// assert_eq!(
281    ///     merged,
282    ///     Schema::new(vec![
283    ///         Field::new("c1", DataType::Int64, true),
284    ///         Field::new("c2", DataType::Utf8, false),
285    ///         Field::new("c3", DataType::Utf8, false),
286    ///     ]),
287    /// );
288    /// ```
289    pub fn try_merge(schemas: impl IntoIterator<Item = Self>) -> Result<Self, ArrowError> {
290        let mut out_meta = Metadata::new();
291        let mut out_fields = SchemaBuilder::new();
292        for schema in schemas {
293            let Schema { metadata, fields } = schema;
294
295            // merge metadata
296            for (key, value) in metadata {
297                if let Some(old_val) = out_meta.get(&key)
298                    && old_val != &value
299                {
300                    return Err(ArrowError::SchemaError(format!(
301                        "Fail to merge schema due to conflicting metadata. \
302                                     Key '{key}' has different values '{old_val}' and '{value}'"
303                    )));
304                }
305                out_meta.insert(key, value);
306            }
307
308            // merge fields
309            fields.iter().try_for_each(|x| out_fields.try_merge(x))?
310        }
311
312        Ok(out_fields.finish().with_metadata(out_meta))
313    }
314
315    /// Returns an immutable reference of the vector of `Field` instances.
316    #[inline]
317    pub const fn fields(&self) -> &Fields {
318        &self.fields
319    }
320
321    /// Returns a vector with references to all fields (including nested fields)
322    ///
323    /// # Example
324    ///
325    /// ```
326    /// use std::sync::Arc;
327    /// use arrow_schema::{DataType, Field, Fields, Schema};
328    ///
329    /// let f1 = Arc::new(Field::new("a", DataType::Boolean, false));
330    ///
331    /// let f2_inner = Arc::new(Field::new("b_inner", DataType::Int8, false));
332    /// let f2 = Arc::new(Field::new("b", DataType::List(f2_inner.clone()), false));
333    ///
334    /// let f3_inner1 = Arc::new(Field::new("c_inner1", DataType::Int8, false));
335    /// let f3_inner2 = Arc::new(Field::new("c_inner2", DataType::Int8, false));
336    /// let f3 = Arc::new(Field::new(
337    ///     "c",
338    ///     DataType::Struct(vec![f3_inner1.clone(), f3_inner2.clone()].into()),
339    ///     false
340    /// ));
341    ///
342    /// let mut schema = Schema::new(vec![
343    ///   f1.clone(), f2.clone(), f3.clone()
344    /// ]);
345    /// assert_eq!(
346    ///     schema.flattened_fields(),
347    ///     vec![
348    ///         f1.as_ref(),
349    ///         f2.as_ref(),
350    ///         f2_inner.as_ref(),
351    ///         f3.as_ref(),
352    ///         f3_inner1.as_ref(),
353    ///         f3_inner2.as_ref()
354    ///    ]
355    /// );
356    /// ```
357    #[inline]
358    pub fn flattened_fields(&self) -> Vec<&Field> {
359        self.fields.iter().flat_map(|f| f.fields()).collect()
360    }
361
362    /// Returns an immutable reference of a specific [`Field`] instance selected using an
363    /// offset within the internal `fields` vector.
364    ///
365    /// # Panics
366    ///
367    /// Panics if index out of bounds
368    pub fn field(&self, i: usize) -> &Field {
369        &self.fields[i]
370    }
371
372    /// Returns an immutable reference of a specific [`Field`] instance selected by name.
373    pub fn field_with_name(&self, name: &str) -> Result<&Field, ArrowError> {
374        Ok(&self.fields[self.index_of(name)?])
375    }
376
377    /// Returns a vector of immutable references to all [`Field`] instances selected by
378    /// the dictionary ID they use.
379    #[deprecated(
380        since = "54.0.0",
381        note = "The ability to preserve dictionary IDs will be removed. With it, all functions related to it."
382    )]
383    pub fn fields_with_dict_id(&self, dict_id: i64) -> Vec<&Field> {
384        #[allow(deprecated)]
385        self.fields
386            .iter()
387            .flat_map(|f| f.fields_with_dict_id(dict_id))
388            .collect()
389    }
390
391    /// Find the index of the column with the given name.
392    pub fn index_of(&self, name: &str) -> Result<usize, ArrowError> {
393        let (idx, _) = self.fields().find(name).ok_or_else(|| {
394            let valid_fields: Vec<_> = self.fields.iter().map(|f| f.name()).collect();
395            ArrowError::SchemaError(format!(
396                "Unable to get field named \"{name}\". Valid fields: {valid_fields:?}"
397            ))
398        })?;
399        Ok(idx)
400    }
401
402    /// Returns an immutable reference to the Map of custom metadata key-value pairs.
403    #[inline]
404    pub const fn metadata(&self) -> &Metadata {
405        &self.metadata
406    }
407
408    /// Normalize a [`Schema`] into a flat table.
409    ///
410    /// Nested [`Field`]s will generate names separated by `separator`, up to a depth of `max_level`
411    /// (unlimited if `None`).
412    ///
413    /// e.g. given a [`Schema`]:
414    ///
415    /// ```text
416    ///     "foo": StructArray<"bar": Utf8>
417    /// ```
418    ///
419    /// A separator of `"."` would generate a batch with the schema:
420    ///
421    /// ```text
422    ///     "foo.bar": Utf8
423    /// ```
424    ///
425    /// Note that giving a depth of `Some(0)` to `max_level` is the same as passing in `None`;
426    /// it will be treated as unlimited.
427    ///
428    /// # Example
429    ///
430    /// ```
431    /// # use std::sync::Arc;
432    /// # use arrow_schema::{DataType, Field, Fields, Schema};
433    /// let schema = Schema::new(vec![
434    ///     Field::new(
435    ///         "a",
436    ///         DataType::Struct(Fields::from(vec![
437    ///             Arc::new(Field::new("animals", DataType::Utf8, true)),
438    ///             Arc::new(Field::new("n_legs", DataType::Int64, true)),
439    ///         ])),
440    ///         false,
441    ///     ),
442    /// ])
443    /// .normalize(".", None)
444    /// .expect("valid normalization");
445    /// let expected = Schema::new(vec![
446    ///     Field::new("a.animals", DataType::Utf8, true),
447    ///     Field::new("a.n_legs", DataType::Int64, true),
448    /// ]);
449    /// assert_eq!(schema, expected);
450    /// ```
451    pub fn normalize(&self, separator: &str, max_level: Option<usize>) -> Result<Self, ArrowError> {
452        let max_level = match max_level.unwrap_or(usize::MAX) {
453            0 => usize::MAX,
454            val => val,
455        };
456        let mut stack: Vec<(usize, Vec<&str>, &FieldRef)> = self
457            .fields()
458            .iter()
459            .rev()
460            .map(|f| {
461                let name_vec: Vec<&str> = vec![f.name()];
462                (0, name_vec, f)
463            })
464            .collect();
465        let mut fields: Vec<FieldRef> = Vec::new();
466
467        while let Some((depth, name, field_ref)) = stack.pop() {
468            match field_ref.data_type() {
469                DataType::Struct(ff) if depth < max_level => {
470                    // Need to zip these in reverse to maintain original order
471                    for fff in ff.into_iter().rev() {
472                        let mut name = name.clone();
473                        name.push(separator);
474                        name.push(fff.name());
475                        stack.push((depth + 1, name, fff))
476                    }
477                }
478                _ => {
479                    let updated_field = Field::new(
480                        name.concat(),
481                        field_ref.data_type().clone(),
482                        field_ref.is_nullable(),
483                    );
484                    fields.push(Arc::new(updated_field));
485                }
486            }
487        }
488        Ok(Schema::new(fields))
489    }
490
491    /// Look up a column by name and return a immutable reference to the column along with
492    /// its index.
493    pub fn column_with_name(&self, name: &str) -> Option<(usize, &Field)> {
494        let (idx, field) = self.fields.find(name)?;
495        Some((idx, field.as_ref()))
496    }
497
498    /// Check to see if `self` is a superset of `other` schema.
499    ///
500    /// In particular returns true if `self.metadata` is a superset of `other.metadata`
501    /// and [`Fields::contains`] for `self.fields` and `other.fields`
502    ///
503    /// In other words, any record that conforms to `other` should also conform to `self`.
504    pub fn contains(&self, other: &Schema) -> bool {
505        // make sure self.metadata is a superset of other.metadata
506        self.fields.contains(&other.fields)
507            && other
508                .metadata
509                .iter()
510                .all(|(k, v1)| self.metadata.get(k).is_some_and(|v2| v1 == v2))
511    }
512}
513
514impl fmt::Display for Schema {
515    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
516        f.write_str(
517            &self
518                .fields
519                .iter()
520                .map(|c| c.to_string())
521                .collect::<Vec<String>>()
522                .join(", "),
523        )
524    }
525}
526
527impl AsRef<Schema> for Schema {
528    fn as_ref(&self) -> &Schema {
529        self
530    }
531}
532
533#[cfg(test)]
534mod tests {
535    use crate::datatype::DataType;
536    use crate::{TimeUnit, UnionMode};
537    use std::collections::HashMap;
538
539    use super::*;
540
541    #[test]
542    #[expect(clippy::needless_borrows_for_generic_args)] // intentional to exercise various references
543    fn test_schema_as_ref() {
544        fn accept_ref(_: impl AsRef<Schema>) {}
545
546        let schema = Schema::new(vec![
547            Field::new("name", DataType::Utf8, false),
548            Field::new("address", DataType::Utf8, false),
549            Field::new("priority", DataType::UInt8, false),
550        ]);
551
552        accept_ref(schema.clone());
553        accept_ref(&schema.clone());
554        accept_ref(&&schema.clone());
555        accept_ref(Arc::new(schema.clone()));
556        accept_ref(&Arc::new(schema.clone()));
557        accept_ref(&&Arc::new(schema.clone()));
558    }
559
560    #[test]
561    #[cfg(feature = "serde")]
562    fn test_ser_de_metadata() {
563        // ser/de with empty metadata
564        let schema = Schema::new(vec![
565            Field::new("name", DataType::Utf8, false),
566            Field::new("address", DataType::Utf8, false),
567            Field::new("priority", DataType::UInt8, false),
568        ]);
569
570        let json = serde_json::to_string(&schema).unwrap();
571        let de_schema = serde_json::from_str(&json).unwrap();
572
573        assert_eq!(schema, de_schema);
574
575        // ser/de with non-empty metadata
576        let schema = schema.with_metadata([("key", "val")]);
577        let json = serde_json::to_string(&schema).unwrap();
578        let de_schema = serde_json::from_str(&json).unwrap();
579
580        assert_eq!(schema, de_schema);
581    }
582
583    #[test]
584    fn test_projection() {
585        let mut metadata = HashMap::new();
586        metadata.insert("meta".to_string(), "data".to_string());
587
588        let schema = Schema::new(vec![
589            Field::new("name", DataType::Utf8, false),
590            Field::new("address", DataType::Utf8, false),
591            Field::new("priority", DataType::UInt8, false),
592        ])
593        .with_metadata(metadata);
594
595        let projected: Schema = schema.project(&[0, 2]).unwrap();
596
597        assert_eq!(projected.fields().len(), 2);
598        assert_eq!(projected.fields()[0].name(), "name");
599        assert_eq!(projected.fields()[1].name(), "priority");
600        assert_eq!(projected.metadata.get("meta").unwrap(), "data")
601    }
602
603    #[test]
604    fn test_oob_projection() {
605        let mut metadata = HashMap::new();
606        metadata.insert("meta".to_string(), "data".to_string());
607
608        let schema = Schema::new(vec![
609            Field::new("name", DataType::Utf8, false),
610            Field::new("address", DataType::Utf8, false),
611            Field::new("priority", DataType::UInt8, false),
612        ])
613        .with_metadata(metadata);
614
615        let projected = schema.project(&[0, 3]);
616
617        assert!(projected.is_err());
618        if let Err(e) = projected {
619            assert_eq!(
620                e.to_string(),
621                "Schema error: project index 3 out of bounds, max field 3".to_string()
622            )
623        }
624    }
625
626    #[test]
627    fn test_schema_contains() {
628        let mut metadata1 = HashMap::new();
629        metadata1.insert("meta".to_string(), "data".to_string());
630
631        let schema1 = Schema::new(vec![
632            Field::new("name", DataType::Utf8, false),
633            Field::new("address", DataType::Utf8, false),
634            Field::new("priority", DataType::UInt8, false),
635        ])
636        .with_metadata(metadata1.clone());
637
638        let mut metadata2 = HashMap::new();
639        metadata2.insert("meta".to_string(), "data".to_string());
640        metadata2.insert("meta2".to_string(), "data".to_string());
641        let schema2 = Schema::new(vec![
642            Field::new("name", DataType::Utf8, false),
643            Field::new("address", DataType::Utf8, false),
644            Field::new("priority", DataType::UInt8, false),
645        ])
646        .with_metadata(metadata2);
647
648        // reflexivity
649        assert!(schema1.contains(&schema1));
650        assert!(schema2.contains(&schema2));
651
652        assert!(!schema1.contains(&schema2));
653        assert!(schema2.contains(&schema1));
654    }
655
656    #[test]
657    fn schema_equality() {
658        let schema1 = Schema::new(vec![
659            Field::new("c1", DataType::Utf8, false),
660            Field::new("c2", DataType::Float64, true),
661            Field::new("c3", DataType::LargeBinary, true),
662        ]);
663        let schema2 = Schema::new(vec![
664            Field::new("c1", DataType::Utf8, false),
665            Field::new("c2", DataType::Float64, true),
666            Field::new("c3", DataType::LargeBinary, true),
667        ]);
668
669        assert_eq!(schema1, schema2);
670
671        let schema3 = Schema::new(vec![
672            Field::new("c1", DataType::Utf8, false),
673            Field::new("c2", DataType::Float32, true),
674        ]);
675        let schema4 = Schema::new(vec![
676            Field::new("C1", DataType::Utf8, false),
677            Field::new("C2", DataType::Float64, true),
678        ]);
679
680        assert_ne!(schema1, schema3);
681        assert_ne!(schema1, schema4);
682        assert_ne!(schema2, schema3);
683        assert_ne!(schema2, schema4);
684        assert_ne!(schema3, schema4);
685
686        let f = Field::new("c1", DataType::Utf8, false).with_metadata([("foo", "bar")]);
687        let schema5 = Schema::new(vec![
688            f,
689            Field::new("c2", DataType::Float64, true),
690            Field::new("c3", DataType::LargeBinary, true),
691        ]);
692        assert_ne!(schema1, schema5);
693    }
694
695    #[test]
696    fn create_schema_string() {
697        let schema = person_schema();
698        assert_eq!(
699            schema.to_string(),
700            "Field { \"first_name\": Utf8, metadata: {\"k\": \"v\"} }, \
701             Field { \"last_name\": Utf8 }, \
702             Field { \"address\": Struct(\"street\": non-null Utf8, \"zip\": non-null UInt16) }, \
703             Field { \"interests\": nullable Dictionary(Int32, Utf8), dict_id: 123, dict_is_ordered }"
704        )
705    }
706
707    #[test]
708    fn schema_field_accessors() {
709        let schema = person_schema();
710
711        // test schema accessors
712        assert_eq!(schema.fields().len(), 4);
713
714        // test field accessors
715        let first_name = &schema.fields()[0];
716        assert_eq!(first_name.name(), "first_name");
717        assert_eq!(first_name.data_type(), &DataType::Utf8);
718        assert!(!first_name.is_nullable());
719        #[allow(deprecated)]
720        let dict_id = first_name.dict_id();
721        assert_eq!(dict_id, None);
722        assert_eq!(first_name.dict_is_ordered(), None);
723
724        let metadata = first_name.metadata();
725        assert!(!metadata.is_empty());
726        let md = &metadata;
727        assert_eq!(md.len(), 1);
728        let key = md.get("k");
729        assert!(key.is_some());
730        assert_eq!(key.unwrap(), "v");
731
732        let interests = &schema.fields()[3];
733        assert_eq!(interests.name(), "interests");
734        assert_eq!(
735            interests.data_type(),
736            &DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8))
737        );
738        #[allow(deprecated)]
739        let dict_id = interests.dict_id();
740        assert_eq!(dict_id, Some(123));
741        assert_eq!(interests.dict_is_ordered(), Some(true));
742    }
743
744    #[test]
745    #[should_panic(
746        expected = "Unable to get field named \\\"nickname\\\". Valid fields: [\\\"first_name\\\", \\\"last_name\\\", \\\"address\\\", \\\"interests\\\"]"
747    )]
748    fn schema_index_of() {
749        let schema = person_schema();
750        assert_eq!(schema.index_of("first_name").unwrap(), 0);
751        assert_eq!(schema.index_of("last_name").unwrap(), 1);
752        schema.index_of("nickname").unwrap();
753    }
754
755    #[test]
756    fn normalize_simple() {
757        let schema = Schema::new(vec![
758            Field::new(
759                "a",
760                DataType::Struct(Fields::from(vec![
761                    Arc::new(Field::new("animals", DataType::Utf8, true)),
762                    Arc::new(Field::new("n_legs", DataType::Int64, true)),
763                    Arc::new(Field::new("year", DataType::Int64, true)),
764                ])),
765                false,
766            ),
767            Field::new("month", DataType::Int64, true),
768        ])
769        .normalize(".", Some(0))
770        .expect("valid normalization");
771
772        let expected = Schema::new(vec![
773            Field::new("a.animals", DataType::Utf8, true),
774            Field::new("a.n_legs", DataType::Int64, true),
775            Field::new("a.year", DataType::Int64, true),
776            Field::new("month", DataType::Int64, true),
777        ]);
778
779        assert_eq!(schema, expected);
780
781        // Check that 0, None have the same result
782        let schema = Schema::new(vec![
783            Field::new(
784                "a",
785                DataType::Struct(Fields::from(vec![
786                    Arc::new(Field::new("animals", DataType::Utf8, true)),
787                    Arc::new(Field::new("n_legs", DataType::Int64, true)),
788                    Arc::new(Field::new("year", DataType::Int64, true)),
789                ])),
790                false,
791            ),
792            Field::new("month", DataType::Int64, true),
793        ])
794        .normalize(".", None)
795        .expect("valid normalization");
796
797        assert_eq!(schema, expected);
798    }
799
800    #[test]
801    fn normalize_nested() {
802        let a = Arc::new(Field::new("a", DataType::Utf8, true));
803        let b = Arc::new(Field::new("b", DataType::Int64, false));
804        let c = Arc::new(Field::new("c", DataType::Int64, true));
805
806        let d = Arc::new(Field::new("d", DataType::Utf8, true));
807        let e = Arc::new(Field::new("e", DataType::Int64, false));
808        let f = Arc::new(Field::new("f", DataType::Int64, true));
809
810        let one = Arc::new(Field::new(
811            "1",
812            DataType::Struct(Fields::from(vec![a.clone(), b.clone(), c.clone()])),
813            false,
814        ));
815        let two = Arc::new(Field::new(
816            "2",
817            DataType::Struct(Fields::from(vec![d.clone(), e.clone(), f.clone()])),
818            true,
819        ));
820
821        let exclamation = Arc::new(Field::new(
822            "!",
823            DataType::Struct(Fields::from(vec![one, two])),
824            false,
825        ));
826
827        let normalize_all = Schema::new(vec![exclamation.clone()])
828            .normalize(".", Some(0))
829            .expect("valid normalization");
830
831        let expected = Schema::new(vec![
832            Field::new("!.1.a", DataType::Utf8, true),
833            Field::new("!.1.b", DataType::Int64, false),
834            Field::new("!.1.c", DataType::Int64, true),
835            Field::new("!.2.d", DataType::Utf8, true),
836            Field::new("!.2.e", DataType::Int64, false),
837            Field::new("!.2.f", DataType::Int64, true),
838        ]);
839
840        assert_eq!(normalize_all, expected);
841
842        let normalize_depth_one = Schema::new(vec![exclamation])
843            .normalize(".", Some(1))
844            .expect("valid normalization");
845
846        let expected = Schema::new(vec![
847            Field::new("!.1", DataType::Struct(Fields::from(vec![a, b, c])), false),
848            Field::new("!.2", DataType::Struct(Fields::from(vec![d, e, f])), true),
849        ]);
850
851        assert_eq!(normalize_depth_one, expected);
852    }
853
854    #[test]
855    fn normalize_list() {
856        // Only the Struct type field should be unwrapped
857        let a = Arc::new(Field::new("a", DataType::Utf8, true));
858        let b = Arc::new(Field::new("b", DataType::Int64, false));
859        let c = Arc::new(Field::new("c", DataType::Int64, true));
860        let d = Arc::new(Field::new("d", DataType::Utf8, true));
861        let e = Arc::new(Field::new("e", DataType::Int64, false));
862        let f = Arc::new(Field::new("f", DataType::Int64, true));
863
864        let one = Arc::new(Field::new(
865            "1",
866            DataType::Struct(Fields::from(vec![a.clone(), b.clone(), c.clone()])),
867            true,
868        ));
869
870        let two = Arc::new(Field::new(
871            "2",
872            DataType::List(Arc::new(Field::new_list_field(
873                DataType::Struct(Fields::from(vec![d.clone(), e.clone(), f.clone()])),
874                true,
875            ))),
876            false,
877        ));
878
879        let exclamation = Arc::new(Field::new(
880            "!",
881            DataType::Struct(Fields::from(vec![one.clone(), two.clone()])),
882            false,
883        ));
884
885        let normalize_all = Schema::new(vec![exclamation.clone()])
886            .normalize(".", None)
887            .expect("valid normalization");
888
889        // List shouldn't be affected
890        let expected = Schema::new(vec![
891            Field::new("!.1.a", DataType::Utf8, true),
892            Field::new("!.1.b", DataType::Int64, false),
893            Field::new("!.1.c", DataType::Int64, true),
894            Field::new(
895                "!.2",
896                DataType::List(Arc::new(Field::new_list_field(
897                    DataType::Struct(Fields::from(vec![d.clone(), e.clone(), f.clone()])),
898                    true,
899                ))),
900                false,
901            ),
902        ]);
903
904        assert_eq!(normalize_all, expected);
905        assert_eq!(normalize_all.fields().len(), 4);
906
907        // FixedSizeList
908        let two = Arc::new(Field::new(
909            "2",
910            DataType::FixedSizeList(
911                Arc::new(Field::new_fixed_size_list(
912                    "3",
913                    Arc::new(Field::new_list_field(
914                        DataType::Struct(Fields::from(vec![d.clone(), e.clone(), f.clone()])),
915                        true,
916                    )),
917                    1,
918                    true,
919                )),
920                1,
921            ),
922            false,
923        ));
924
925        let exclamation = Arc::new(Field::new(
926            "!",
927            DataType::Struct(Fields::from(vec![one.clone(), two])),
928            false,
929        ));
930
931        let normalize_all = Schema::new(vec![exclamation.clone()])
932            .normalize(".", None)
933            .expect("valid normalization");
934
935        // FixedSizeList shouldn't be affected
936        let expected = Schema::new(vec![
937            Field::new("!.1.a", DataType::Utf8, true),
938            Field::new("!.1.b", DataType::Int64, false),
939            Field::new("!.1.c", DataType::Int64, true),
940            Field::new(
941                "!.2",
942                DataType::FixedSizeList(
943                    Arc::new(Field::new_fixed_size_list(
944                        "3",
945                        Arc::new(Field::new_list_field(
946                            DataType::Struct(Fields::from(vec![d.clone(), e.clone(), f.clone()])),
947                            true,
948                        )),
949                        1,
950                        true,
951                    )),
952                    1,
953                ),
954                false,
955            ),
956        ]);
957
958        assert_eq!(normalize_all, expected);
959        assert_eq!(normalize_all.fields().len(), 4);
960
961        // LargeList
962        let two = Arc::new(Field::new(
963            "2",
964            DataType::FixedSizeList(
965                Arc::new(Field::new_large_list(
966                    "3",
967                    Arc::new(Field::new_list_field(
968                        DataType::Struct(Fields::from(vec![d.clone(), e.clone(), f.clone()])),
969                        true,
970                    )),
971                    true,
972                )),
973                1,
974            ),
975            false,
976        ));
977
978        let exclamation = Arc::new(Field::new(
979            "!",
980            DataType::Struct(Fields::from(vec![one.clone(), two])),
981            false,
982        ));
983
984        let normalize_all = Schema::new(vec![exclamation.clone()])
985            .normalize(".", None)
986            .expect("valid normalization");
987
988        // LargeList shouldn't be affected
989        let expected = Schema::new(vec![
990            Field::new("!.1.a", DataType::Utf8, true),
991            Field::new("!.1.b", DataType::Int64, false),
992            Field::new("!.1.c", DataType::Int64, true),
993            Field::new(
994                "!.2",
995                DataType::FixedSizeList(
996                    Arc::new(Field::new_large_list(
997                        "3",
998                        Arc::new(Field::new_list_field(
999                            DataType::Struct(Fields::from(vec![d.clone(), e.clone(), f.clone()])),
1000                            true,
1001                        )),
1002                        true,
1003                    )),
1004                    1,
1005                ),
1006                false,
1007            ),
1008        ]);
1009
1010        assert_eq!(normalize_all, expected);
1011        assert_eq!(normalize_all.fields().len(), 4);
1012    }
1013
1014    #[test]
1015    fn normalize_deep_nested() {
1016        // No unwrapping expected
1017        let a = Arc::new(Field::new("a", DataType::Utf8, true));
1018        let b = Arc::new(Field::new("b", DataType::Int64, false));
1019        let c = Arc::new(Field::new("c", DataType::Int64, true));
1020        let d = Arc::new(Field::new("d", DataType::Utf8, true));
1021        let e = Arc::new(Field::new("e", DataType::Int64, false));
1022        let f = Arc::new(Field::new("f", DataType::Int64, true));
1023
1024        let one = Arc::new(Field::new(
1025            "1",
1026            DataType::Struct(Fields::from(vec![a.clone(), b.clone(), c.clone()])),
1027            true,
1028        ));
1029
1030        let two = Arc::new(Field::new(
1031            "2",
1032            DataType::List(Arc::new(Field::new_list_field(
1033                DataType::Struct(Fields::from(vec![d.clone(), e.clone(), f.clone()])),
1034                true,
1035            ))),
1036            false,
1037        ));
1038
1039        let l10 = Arc::new(Field::new(
1040            "l10",
1041            DataType::List(Arc::new(Field::new_list_field(
1042                DataType::Struct(Fields::from(vec![one, two])),
1043                true,
1044            ))),
1045            false,
1046        ));
1047
1048        let l9 = Arc::new(Field::new(
1049            "l9",
1050            DataType::List(Arc::new(Field::new_list_field(
1051                DataType::Struct(Fields::from(vec![l10])),
1052                true,
1053            ))),
1054            false,
1055        ));
1056
1057        let l8 = Arc::new(Field::new(
1058            "l8",
1059            DataType::List(Arc::new(Field::new_list_field(
1060                DataType::Struct(Fields::from(vec![l9])),
1061                true,
1062            ))),
1063            false,
1064        ));
1065        let l7 = Arc::new(Field::new(
1066            "l7",
1067            DataType::List(Arc::new(Field::new_list_field(
1068                DataType::Struct(Fields::from(vec![l8])),
1069                true,
1070            ))),
1071            false,
1072        ));
1073        let l6 = Arc::new(Field::new(
1074            "l6",
1075            DataType::List(Arc::new(Field::new_list_field(
1076                DataType::Struct(Fields::from(vec![l7])),
1077                true,
1078            ))),
1079            false,
1080        ));
1081        let l5 = Arc::new(Field::new(
1082            "l5",
1083            DataType::List(Arc::new(Field::new_list_field(
1084                DataType::Struct(Fields::from(vec![l6])),
1085                true,
1086            ))),
1087            false,
1088        ));
1089        let l4 = Arc::new(Field::new(
1090            "l4",
1091            DataType::List(Arc::new(Field::new_list_field(
1092                DataType::Struct(Fields::from(vec![l5])),
1093                true,
1094            ))),
1095            false,
1096        ));
1097        let l3 = Arc::new(Field::new(
1098            "l3",
1099            DataType::List(Arc::new(Field::new_list_field(
1100                DataType::Struct(Fields::from(vec![l4])),
1101                true,
1102            ))),
1103            false,
1104        ));
1105        let l2 = Arc::new(Field::new(
1106            "l2",
1107            DataType::List(Arc::new(Field::new_list_field(
1108                DataType::Struct(Fields::from(vec![l3])),
1109                true,
1110            ))),
1111            false,
1112        ));
1113        let l1 = Arc::new(Field::new(
1114            "l1",
1115            DataType::List(Arc::new(Field::new_list_field(
1116                DataType::Struct(Fields::from(vec![l2])),
1117                true,
1118            ))),
1119            false,
1120        ));
1121
1122        let normalize_all = Schema::new(vec![l1])
1123            .normalize(".", None)
1124            .expect("valid normalization");
1125
1126        assert_eq!(normalize_all.fields().len(), 1);
1127    }
1128
1129    #[test]
1130    fn normalize_dictionary() {
1131        let a = Arc::new(Field::new("a", DataType::Utf8, true));
1132        let b = Arc::new(Field::new("b", DataType::Int64, false));
1133
1134        let one = Arc::new(Field::new(
1135            "1",
1136            DataType::Dictionary(
1137                Box::new(DataType::Int32),
1138                Box::new(DataType::Struct(Fields::from(vec![a.clone(), b.clone()]))),
1139            ),
1140            false,
1141        ));
1142
1143        let normalize_all = Schema::new(vec![one.clone()])
1144            .normalize(".", None)
1145            .expect("valid normalization");
1146
1147        let expected = Schema::new(vec![Field::new(
1148            "1",
1149            DataType::Dictionary(
1150                Box::new(DataType::Int32),
1151                Box::new(DataType::Struct(Fields::from(vec![a.clone(), b.clone()]))),
1152            ),
1153            false,
1154        )]);
1155
1156        assert_eq!(normalize_all, expected);
1157    }
1158
1159    #[test]
1160    #[should_panic(
1161        expected = "Unable to get field named \\\"nickname\\\". Valid fields: [\\\"first_name\\\", \\\"last_name\\\", \\\"address\\\", \\\"interests\\\"]"
1162    )]
1163    fn schema_field_with_name() {
1164        let schema = person_schema();
1165        assert_eq!(
1166            schema.field_with_name("first_name").unwrap().name(),
1167            "first_name"
1168        );
1169        assert_eq!(
1170            schema.field_with_name("last_name").unwrap().name(),
1171            "last_name"
1172        );
1173        schema.field_with_name("nickname").unwrap();
1174    }
1175
1176    #[test]
1177    fn schema_field_with_dict_id() {
1178        let schema = person_schema();
1179
1180        #[allow(deprecated)]
1181        let fields_dict_123: Vec<_> = schema
1182            .fields_with_dict_id(123)
1183            .iter()
1184            .map(|f| f.name())
1185            .collect();
1186        assert_eq!(fields_dict_123, vec!["interests"]);
1187
1188        #[allow(deprecated)]
1189        let is_empty = schema.fields_with_dict_id(456).is_empty();
1190        assert!(is_empty);
1191    }
1192
1193    fn person_schema() -> Schema {
1194        let kv_array = [("k".to_string(), "v".to_string())];
1195        let field_metadata: HashMap<String, String> = kv_array.iter().cloned().collect();
1196        let first_name =
1197            Field::new("first_name", DataType::Utf8, false).with_metadata(field_metadata);
1198
1199        Schema::new(vec![
1200            first_name,
1201            Field::new("last_name", DataType::Utf8, false),
1202            Field::new(
1203                "address",
1204                DataType::Struct(Fields::from(vec![
1205                    Field::new("street", DataType::Utf8, false),
1206                    Field::new("zip", DataType::UInt16, false),
1207                ])),
1208                false,
1209            ),
1210            #[allow(deprecated)]
1211            Field::new_dict(
1212                "interests",
1213                DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)),
1214                true,
1215                123,
1216                true,
1217            ),
1218        ])
1219    }
1220
1221    #[test]
1222    fn test_try_merge_field_with_metadata() {
1223        // 1. Different values for the same key should cause error.
1224        let metadata1: HashMap<String, String> = [("foo".to_string(), "bar".to_string())]
1225            .iter()
1226            .cloned()
1227            .collect();
1228        let f1 = Field::new("first_name", DataType::Utf8, false).with_metadata(metadata1);
1229
1230        let metadata2: HashMap<String, String> = [("foo".to_string(), "baz".to_string())]
1231            .iter()
1232            .cloned()
1233            .collect();
1234        let f2 = Field::new("first_name", DataType::Utf8, false).with_metadata(metadata2);
1235
1236        assert!(Schema::try_merge(vec![Schema::new(vec![f1]), Schema::new(vec![f2])]).is_err());
1237
1238        // 2. None + Some
1239        let mut f1 = Field::new("first_name", DataType::Utf8, false);
1240        let metadata2: HashMap<String, String> = [("missing".to_string(), "value".to_string())]
1241            .iter()
1242            .cloned()
1243            .collect();
1244        let f2 = Field::new("first_name", DataType::Utf8, false).with_metadata(metadata2);
1245
1246        assert!(f1.try_merge(&f2).is_ok());
1247        assert!(!f1.metadata().is_empty());
1248        assert_eq!(f1.metadata(), f2.metadata());
1249
1250        // 3. Some + Some
1251        let mut f1 =
1252            Field::new("first_name", DataType::Utf8, false).with_metadata([("foo", "bar")]);
1253        let f2 = Field::new("first_name", DataType::Utf8, false).with_metadata([("foo2", "bar2")]);
1254
1255        assert!(f1.try_merge(&f2).is_ok());
1256        assert!(!f1.metadata().is_empty());
1257        assert_eq!(
1258            f1.metadata(),
1259            &Metadata::from([("foo", "bar"), ("foo2", "bar2")])
1260        );
1261
1262        // 4. Some + None.
1263        let mut f1 =
1264            Field::new("first_name", DataType::Utf8, false).with_metadata([("foo", "bar")]);
1265        let f2 = Field::new("first_name", DataType::Utf8, false);
1266        assert!(f1.try_merge(&f2).is_ok());
1267        assert!(!f1.metadata().is_empty());
1268        assert_eq!(f1.metadata(), &Metadata::from([("foo", "bar")]));
1269
1270        // 5. None + None.
1271        let mut f1 = Field::new("first_name", DataType::Utf8, false);
1272        let f2 = Field::new("first_name", DataType::Utf8, false);
1273        assert!(f1.try_merge(&f2).is_ok());
1274        assert!(f1.metadata().is_empty());
1275    }
1276
1277    #[test]
1278    fn test_schema_merge() {
1279        let merged = Schema::try_merge(vec![
1280            Schema::new(vec![
1281                Field::new("first_name", DataType::Utf8, false),
1282                Field::new("last_name", DataType::Utf8, false),
1283                Field::new(
1284                    "address",
1285                    DataType::Struct(vec![Field::new("zip", DataType::UInt16, false)].into()),
1286                    false,
1287                ),
1288            ]),
1289            Schema::new_with_metadata(
1290                vec![
1291                    // nullable merge
1292                    Field::new("last_name", DataType::Utf8, true),
1293                    Field::new(
1294                        "address",
1295                        DataType::Struct(Fields::from(vec![
1296                            // add new nested field
1297                            Field::new("street", DataType::Utf8, false),
1298                            // nullable merge on nested field
1299                            Field::new("zip", DataType::UInt16, true),
1300                        ])),
1301                        false,
1302                    ),
1303                    // new field
1304                    Field::new("number", DataType::Utf8, true),
1305                ],
1306                [("foo".to_string(), "bar".to_string())]
1307                    .iter()
1308                    .cloned()
1309                    .collect::<HashMap<String, String>>(),
1310            ),
1311        ])
1312        .unwrap();
1313
1314        assert_eq!(
1315            merged,
1316            Schema::new_with_metadata(
1317                vec![
1318                    Field::new("first_name", DataType::Utf8, false),
1319                    Field::new("last_name", DataType::Utf8, true),
1320                    Field::new(
1321                        "address",
1322                        DataType::Struct(Fields::from(vec![
1323                            Field::new("zip", DataType::UInt16, true),
1324                            Field::new("street", DataType::Utf8, false),
1325                        ])),
1326                        false,
1327                    ),
1328                    Field::new("number", DataType::Utf8, true),
1329                ],
1330                [("foo".to_string(), "bar".to_string())]
1331                    .iter()
1332                    .cloned()
1333                    .collect::<HashMap<String, String>>()
1334            )
1335        );
1336
1337        // support merge union fields
1338        assert_eq!(
1339            Schema::try_merge(vec![
1340                Schema::new(vec![Field::new_union(
1341                    "c1",
1342                    vec![0, 1],
1343                    vec![
1344                        Field::new("c11", DataType::Utf8, true),
1345                        Field::new("c12", DataType::Utf8, true),
1346                    ],
1347                    UnionMode::Dense
1348                ),]),
1349                Schema::new(vec![Field::new_union(
1350                    "c1",
1351                    vec![1, 2],
1352                    vec![
1353                        Field::new("c12", DataType::Utf8, true),
1354                        Field::new("c13", DataType::Time64(TimeUnit::Second), true),
1355                    ],
1356                    UnionMode::Dense
1357                ),])
1358            ])
1359            .unwrap(),
1360            Schema::new(vec![Field::new_union(
1361                "c1",
1362                vec![0, 1, 2],
1363                vec![
1364                    Field::new("c11", DataType::Utf8, true),
1365                    Field::new("c12", DataType::Utf8, true),
1366                    Field::new("c13", DataType::Time64(TimeUnit::Second), true),
1367                ],
1368                UnionMode::Dense
1369            ),]),
1370        );
1371
1372        // incompatible field should throw error
1373        assert!(
1374            Schema::try_merge(vec![
1375                Schema::new(vec![
1376                    Field::new("first_name", DataType::Utf8, false),
1377                    Field::new("last_name", DataType::Utf8, false),
1378                ]),
1379                Schema::new(vec![Field::new("last_name", DataType::Int64, false),])
1380            ])
1381            .is_err()
1382        );
1383
1384        // incompatible metadata should throw error
1385        let res = Schema::try_merge(vec![
1386            Schema::new_with_metadata(
1387                vec![Field::new("first_name", DataType::Utf8, false)],
1388                [("foo".to_string(), "bar".to_string())]
1389                    .iter()
1390                    .cloned()
1391                    .collect::<HashMap<String, String>>(),
1392            ),
1393            Schema::new_with_metadata(
1394                vec![Field::new("last_name", DataType::Utf8, false)],
1395                [("foo".to_string(), "baz".to_string())]
1396                    .iter()
1397                    .cloned()
1398                    .collect::<HashMap<String, String>>(),
1399            ),
1400        ])
1401        .unwrap_err();
1402
1403        let expected = "Fail to merge schema due to conflicting metadata. Key 'foo' has different values 'bar' and 'baz'";
1404        assert!(
1405            res.to_string().contains(expected),
1406            "Could not find expected string '{expected}' in '{res}'"
1407        );
1408    }
1409
1410    #[test]
1411    fn test_schema_builder_change_field() {
1412        let mut builder = SchemaBuilder::new();
1413        builder.push(Field::new("a", DataType::Int32, false));
1414        builder.push(Field::new("b", DataType::Utf8, false));
1415        *builder.field_mut(1) = Arc::new(Field::new("c", DataType::Int32, false));
1416        assert_eq!(
1417            builder.fields,
1418            vec![
1419                Arc::new(Field::new("a", DataType::Int32, false)),
1420                Arc::new(Field::new("c", DataType::Int32, false))
1421            ]
1422        );
1423    }
1424
1425    #[test]
1426    fn test_schema_builder_reverse() {
1427        let mut builder = SchemaBuilder::new();
1428        builder.push(Field::new("a", DataType::Int32, false));
1429        builder.push(Field::new("b", DataType::Utf8, true));
1430        builder.reverse();
1431        assert_eq!(
1432            builder.fields,
1433            vec![
1434                Arc::new(Field::new("b", DataType::Utf8, true)),
1435                Arc::new(Field::new("a", DataType::Int32, false))
1436            ]
1437        );
1438    }
1439
1440    #[test]
1441    fn test_schema_builder_metadata() {
1442        let mut metadata: HashMap<String, String> = HashMap::with_capacity(1);
1443        metadata.insert("key".to_string(), "value".to_string());
1444
1445        let fields = vec![Field::new("test", DataType::Int8, true)];
1446        let mut builder: SchemaBuilder = Schema::new(fields).with_metadata(metadata).into();
1447        builder.metadata_mut().insert("k", "v");
1448        let out = builder.finish();
1449        assert_eq!(out.metadata.len(), 2);
1450        assert_eq!(out.metadata["k"], "v");
1451        assert_eq!(out.metadata["key"], "value");
1452    }
1453}