Skip to main content

arrow_schema/
field.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 crate::error::ArrowError;
19use std::cmp::Ordering;
20use std::hash::{Hash, Hasher};
21use std::sync::Arc;
22
23use crate::datatype::DataType;
24#[cfg(feature = "canonical_extension_types")]
25use crate::extension::CanonicalExtensionType;
26use crate::schema::SchemaBuilder;
27use crate::{
28    Fields, Metadata, UnionFields, UnionMode,
29    extension::{EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_NAME_KEY, ExtensionType},
30};
31
32/// A reference counted [`Field`]
33pub type FieldRef = Arc<Field>;
34
35/// Describes a single column in a [`Schema`](super::Schema).
36///
37/// A [`Schema`](super::Schema) is an ordered collection of
38/// [`Field`] objects. Fields contain:
39/// * `name`: the name of the field
40/// * `data_type`: the type of the field
41/// * `nullable`: if the field is nullable
42/// * `metadata`: a map of key-value pairs containing additional custom metadata
43///
44/// Arrow Extension types, are encoded in `Field`s metadata. See
45/// [`Self::try_extension_type`] to retrieve the [`ExtensionType`], if any.
46#[derive(Clone)]
47#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
48pub struct Field {
49    name: String,
50    data_type: DataType,
51    nullable: bool,
52    #[deprecated(
53        since = "54.0.0",
54        note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
55    )]
56    dict_id: i64,
57    dict_is_ordered: bool,
58    /// A map of key-value pairs containing additional custom meta data.
59    metadata: Metadata,
60}
61
62impl std::fmt::Debug for Field {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        #![expect(deprecated)] // Must still print dict_id, if set
65        let Self {
66            name,
67            data_type,
68            nullable,
69            dict_id,
70            dict_is_ordered,
71            metadata,
72        } = self;
73
74        let mut s = f.debug_struct("Field");
75
76        if name != "item" {
77            // Keep it short when debug-formatting `DataType::List`
78            s.field("name", name);
79        }
80
81        s.field("data_type", data_type);
82
83        if *nullable {
84            s.field("nullable", nullable);
85        }
86
87        if *dict_id != 0 {
88            s.field("dict_id", dict_id);
89        }
90
91        if *dict_is_ordered {
92            s.field("dict_is_ordered", dict_is_ordered);
93        }
94
95        if !metadata.is_empty() {
96            s.field("metadata", metadata);
97        }
98        s.finish()
99    }
100}
101
102// Auto-derive `PartialEq` traits will pull `dict_id` and `dict_is_ordered`
103// into comparison. However, these properties are only used in IPC context
104// for matching dictionary encoded data. They are not necessary to be same
105// to consider schema equality. For example, in C++ `Field` implementation,
106// it doesn't contain these dictionary properties too.
107impl PartialEq for Field {
108    fn eq(&self, other: &Self) -> bool {
109        self.name == other.name
110            && self.data_type == other.data_type
111            && self.nullable == other.nullable
112            && self.metadata == other.metadata
113    }
114}
115
116impl Eq for Field {}
117
118impl PartialOrd for Field {
119    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
120        Some(self.cmp(other))
121    }
122}
123
124impl Ord for Field {
125    fn cmp(&self, other: &Self) -> Ordering {
126        self.name
127            .cmp(other.name())
128            .then_with(|| self.data_type.cmp(other.data_type()))
129            .then_with(|| self.nullable.cmp(&other.nullable))
130            .then_with(|| self.metadata.cmp(&other.metadata))
131    }
132}
133
134impl Hash for Field {
135    fn hash<H: Hasher>(&self, state: &mut H) {
136        self.name.hash(state);
137        self.data_type.hash(state);
138        self.nullable.hash(state);
139        // `Metadata` iterates in deterministic (sorted) key order
140        self.metadata.hash(state);
141    }
142}
143
144impl AsRef<Field> for Field {
145    fn as_ref(&self) -> &Field {
146        self
147    }
148}
149
150impl Field {
151    /// Default list member field name
152    pub const LIST_FIELD_DEFAULT_NAME: &'static str = "item";
153    /// Default field name for the entries field for Map
154    ///
155    /// See [Arrow Spec](https://github.com/apache/arrow/blob/b19c4761b558ade94ae05743062d92aacedef10e/format/Schema.fbs#L127-L138))
156    pub const MAP_ENTRIES_FIELD_DEFAULT_NAME: &'static str = "entries";
157    /// Default field name for the key field for Map
158    ///
159    /// See [Arrow Spec](https://github.com/apache/arrow/blob/b19c4761b558ade94ae05743062d92aacedef10e/format/Schema.fbs#L127-L138))
160    pub const MAP_KEY_FIELD_DEFAULT_NAME: &'static str = "key";
161    /// Default field name for the value field for Map
162    ///
163    /// See [Arrow Spec](https://github.com/apache/arrow/blob/b19c4761b558ade94ae05743062d92aacedef10e/format/Schema.fbs#L127-L138))
164    pub const MAP_VALUE_FIELD_DEFAULT_NAME: &'static str = "value";
165
166    /// Creates a new field with the given name, data type, and nullability
167    ///
168    /// # Example
169    /// ```
170    /// # use arrow_schema::{Field, DataType};
171    /// Field::new("field_name", DataType::Int32, true);
172    /// ```
173    pub fn new(name: impl Into<String>, data_type: DataType, nullable: bool) -> Self {
174        #[allow(deprecated)]
175        Field {
176            name: name.into(),
177            data_type,
178            nullable,
179            dict_id: 0,
180            dict_is_ordered: false,
181            metadata: Default::default(),
182        }
183    }
184
185    /// Creates a new `Field` suitable for [`DataType::List`] and
186    /// [`DataType::LargeList`]
187    ///
188    /// While not required, this method follows the convention of naming the
189    /// `Field` `"item"`.
190    ///
191    /// # Example
192    /// ```
193    /// # use arrow_schema::{Field, DataType};
194    /// assert_eq!(
195    ///   Field::new("item", DataType::Int32, true),
196    ///   Field::new_list_field(DataType::Int32, true)
197    /// );
198    /// ```
199    pub fn new_list_field(data_type: DataType, nullable: bool) -> Self {
200        Self::new(Self::LIST_FIELD_DEFAULT_NAME, data_type, nullable)
201    }
202
203    /// Creates a new field that has additional dictionary information
204    #[deprecated(
205        since = "54.0.0",
206        note = "The ability to preserve dictionary IDs will be removed. With the dict_id field disappearing this function signature will change by removing the dict_id parameter."
207    )]
208    pub fn new_dict(
209        name: impl Into<String>,
210        data_type: DataType,
211        nullable: bool,
212        dict_id: i64,
213        dict_is_ordered: bool,
214    ) -> Self {
215        #[allow(deprecated)]
216        Field {
217            name: name.into(),
218            data_type,
219            nullable,
220            dict_id,
221            dict_is_ordered,
222            metadata: Default::default(),
223        }
224    }
225
226    /// Create a new [`Field`] with [`DataType::Dictionary`]
227    ///
228    /// Use [`Self::new_dict`] for more advanced dictionary options
229    ///
230    /// # Panics
231    ///
232    /// Panics if [`!key.is_dictionary_key_type`][DataType::is_dictionary_key_type]
233    pub fn new_dictionary(
234        name: impl Into<String>,
235        key: DataType,
236        value: DataType,
237        nullable: bool,
238    ) -> Self {
239        assert!(
240            key.is_dictionary_key_type(),
241            "{key} is not a valid dictionary key"
242        );
243        let data_type = DataType::Dictionary(Box::new(key), Box::new(value));
244        Self::new(name, data_type, nullable)
245    }
246
247    /// Create a new [`Field`] with [`DataType::Struct`]
248    ///
249    /// - `name`: the name of the [`DataType::Struct`] field
250    /// - `fields`: the description of each struct element
251    /// - `nullable`: if the [`DataType::Struct`] array is nullable
252    pub fn new_struct(name: impl Into<String>, fields: impl Into<Fields>, nullable: bool) -> Self {
253        Self::new(name, DataType::Struct(fields.into()), nullable)
254    }
255
256    /// Create a new [`Field`] with [`DataType::List`]
257    ///
258    /// - `name`: the name of the [`DataType::List`] field
259    /// - `value`: the description of each list element
260    /// - `nullable`: if the [`DataType::List`] array is nullable
261    pub fn new_list(name: impl Into<String>, value: impl Into<FieldRef>, nullable: bool) -> Self {
262        Self::new(name, DataType::List(value.into()), nullable)
263    }
264
265    /// Create a new [`Field`] with [`DataType::LargeList`]
266    ///
267    /// - `name`: the name of the [`DataType::LargeList`] field
268    /// - `value`: the description of each list element
269    /// - `nullable`: if the [`DataType::LargeList`] array is nullable
270    pub fn new_large_list(
271        name: impl Into<String>,
272        value: impl Into<FieldRef>,
273        nullable: bool,
274    ) -> Self {
275        Self::new(name, DataType::LargeList(value.into()), nullable)
276    }
277
278    /// Create a new [`Field`] with [`DataType::FixedSizeList`]
279    ///
280    /// - `name`: the name of the [`DataType::FixedSizeList`] field
281    /// - `value`: the description of each list element
282    /// - `size`: the size of the fixed size list
283    /// - `nullable`: if the [`DataType::FixedSizeList`] array is nullable
284    pub fn new_fixed_size_list(
285        name: impl Into<String>,
286        value: impl Into<FieldRef>,
287        size: i32,
288        nullable: bool,
289    ) -> Self {
290        Self::new(name, DataType::FixedSizeList(value.into(), size), nullable)
291    }
292
293    /// Create a new [`Field`] with [`DataType::Map`]
294    ///
295    /// - `name`: the name of the [`DataType::Map`] field
296    /// - `entries`: the name of the inner [`DataType::Struct`] field
297    /// - `keys`: the map keys
298    /// - `values`: the map values
299    /// - `sorted`: if the [`DataType::Map`] array is sorted
300    /// - `nullable`: if the [`DataType::Map`] array is nullable
301    pub fn new_map(
302        name: impl Into<String>,
303        entries: impl Into<String>,
304        keys: impl Into<FieldRef>,
305        values: impl Into<FieldRef>,
306        sorted: bool,
307        nullable: bool,
308    ) -> Self {
309        let data_type = DataType::Map(
310            Arc::new(Field::new(
311                entries.into(),
312                DataType::Struct(Fields::from([keys.into(), values.into()])),
313                false, // The inner map field is always non-nullable (#1697),
314            )),
315            sorted,
316        );
317        Self::new(name, data_type, nullable)
318    }
319
320    /// Create a new [`Field`] with [`DataType::Union`]
321    ///
322    /// - `name`: the name of the [`DataType::Union`] field
323    /// - `type_ids`: the union type ids
324    /// - `fields`: the union fields
325    /// - `mode`: the union mode
326    ///
327    /// # Panics
328    ///
329    /// Panics if:
330    /// - any type ID is negative
331    /// - type IDs contain duplicates
332    /// - the number of type IDs does not equal the number of fields
333    pub fn new_union<S, F, T>(name: S, type_ids: T, fields: F, mode: UnionMode) -> Self
334    where
335        S: Into<String>,
336        F: IntoIterator,
337        F::Item: Into<FieldRef>,
338        T: IntoIterator<Item = i8>,
339    {
340        Self::new(
341            name,
342            DataType::Union(
343                UnionFields::try_new(type_ids, fields).expect("Invalid UnionField"),
344                mode,
345            ),
346            false, // Unions cannot be nullable
347        )
348    }
349
350    /// Sets the `Field`'s optional custom metadata.
351    #[inline]
352    pub fn set_metadata(&mut self, metadata: impl Into<Metadata>) {
353        self.metadata = metadata.into();
354    }
355
356    /// Sets the metadata of this `Field` to be `metadata` and returns self
357    pub fn with_metadata(mut self, metadata: impl Into<Metadata>) -> Self {
358        self.set_metadata(metadata);
359        self
360    }
361
362    /// Returns the immutable reference to the `Field`'s optional custom metadata.
363    #[inline]
364    pub const fn metadata(&self) -> &Metadata {
365        &self.metadata
366    }
367
368    /// Returns a mutable reference to the `Field`'s optional custom metadata.
369    #[inline]
370    pub fn metadata_mut(&mut self) -> &mut Metadata {
371        &mut self.metadata
372    }
373
374    /// Returns an immutable reference to the `Field`'s name.
375    #[inline]
376    pub const fn name(&self) -> &String {
377        &self.name
378    }
379
380    /// Set the name of this [`Field`]
381    #[inline]
382    pub fn set_name(&mut self, name: impl Into<String>) {
383        self.name = name.into();
384    }
385
386    /// Set the name of the [`Field`] and returns self.
387    ///
388    /// ```
389    /// # use arrow_schema::*;
390    /// let field = Field::new("c1", DataType::Int64, false)
391    ///    .with_name("c2");
392    ///
393    /// assert_eq!(field.name(), "c2");
394    /// ```
395    pub fn with_name(mut self, name: impl Into<String>) -> Self {
396        self.set_name(name);
397        self
398    }
399
400    /// Returns an immutable reference to the [`Field`]'s  [`DataType`].
401    #[inline]
402    pub const fn data_type(&self) -> &DataType {
403        &self.data_type
404    }
405
406    /// Set [`DataType`] of the [`Field`]
407    ///
408    /// ```
409    /// # use arrow_schema::*;
410    /// let mut field = Field::new("c1", DataType::Int64, false);
411    /// field.set_data_type(DataType::Utf8);
412    ///
413    /// assert_eq!(field.data_type(), &DataType::Utf8);
414    /// ```
415    #[inline]
416    pub fn set_data_type(&mut self, data_type: DataType) {
417        self.data_type = data_type;
418    }
419
420    /// Set [`DataType`] of the [`Field`] and returns self.
421    ///
422    /// ```
423    /// # use arrow_schema::*;
424    /// let field = Field::new("c1", DataType::Int64, false)
425    ///    .with_data_type(DataType::Utf8);
426    ///
427    /// assert_eq!(field.data_type(), &DataType::Utf8);
428    /// ```
429    pub fn with_data_type(mut self, data_type: DataType) -> Self {
430        self.set_data_type(data_type);
431        self
432    }
433
434    /// Returns the extension type name of this [`Field`], if set.
435    ///
436    /// This returns the value of [`EXTENSION_TYPE_NAME_KEY`], if set in
437    /// [`Field::metadata`]. If the key is missing, there is no extension type
438    /// name and this returns `None`.
439    ///
440    /// # Example
441    ///
442    /// ```
443    /// # use arrow_schema::{DataType, extension::EXTENSION_TYPE_NAME_KEY, Field};
444    ///
445    /// let field = Field::new("", DataType::Null, false);
446    /// assert_eq!(field.extension_type_name(), None);
447    ///
448    /// let field = Field::new("", DataType::Null, false)
449    ///     .with_metadata([(EXTENSION_TYPE_NAME_KEY, "example")]);
450    /// assert_eq!(field.extension_type_name(), Some("example"));
451    /// ```
452    pub fn extension_type_name(&self) -> Option<&str> {
453        self.metadata()
454            .get(EXTENSION_TYPE_NAME_KEY)
455            .map(String::as_ref)
456    }
457
458    /// Returns the extension type metadata of this [`Field`], if set.
459    ///
460    /// This returns the value of [`EXTENSION_TYPE_METADATA_KEY`], if set in
461    /// [`Field::metadata`]. If the key is missing, there is no extension type
462    /// metadata and this returns `None`.
463    ///
464    /// # Example
465    ///
466    /// ```
467    /// # use arrow_schema::{DataType, extension::EXTENSION_TYPE_METADATA_KEY, Field};
468    ///
469    /// let field = Field::new("", DataType::Null, false);
470    /// assert_eq!(field.extension_type_metadata(), None);
471    ///
472    /// let field = Field::new("", DataType::Null, false)
473    ///     .with_metadata([(EXTENSION_TYPE_METADATA_KEY, "example")]);
474    /// assert_eq!(field.extension_type_metadata(), Some("example"));
475    /// ```
476    pub fn extension_type_metadata(&self) -> Option<&str> {
477        self.metadata()
478            .get(EXTENSION_TYPE_METADATA_KEY)
479            .map(String::as_ref)
480    }
481
482    /// Returns `true` if this [`Field`] has the given [`ExtensionType`] name
483    /// and can be successfully validated as that extension type.
484    ///
485    /// This first checks the extension type name and only calls
486    /// [`ExtensionType::validate`] when the name matches.
487    ///
488    /// This is useful when you only need a boolean validity check and do not
489    /// need to retrieve the extension type instance.
490    #[inline]
491    pub fn has_valid_extension_type<E: ExtensionType>(&self) -> bool {
492        if self.extension_type_name() != Some(E::NAME) {
493            return false;
494        }
495
496        let ext_metadata = self
497            .metadata()
498            .get(EXTENSION_TYPE_METADATA_KEY)
499            .map(|s| s.as_str());
500
501        E::deserialize_metadata(ext_metadata)
502            .and_then(|metadata| E::validate(self.data_type(), metadata))
503            .is_ok()
504    }
505
506    /// Returns an instance of the given [`ExtensionType`] of this [`Field`],
507    /// if set in the [`Field::metadata`].
508    ///
509    /// Note that using `try_extension_type` with an extension type that does
510    /// not match the name in the metadata will return an `ArrowError` which can
511    /// be slow due to string allocations. If you only want to check if a
512    /// [`Field`] has a specific [`ExtensionType`], first check
513    /// [`Field::extension_type_name`], or use [`Field::has_valid_extension_type`]
514    /// to also validate metadata and data type.
515    ///
516    /// # Errors
517    ///
518    /// Returns an error if
519    /// - this field does not have the name of this extension type
520    ///   ([`ExtensionType::NAME`]) in the [`Field::metadata`] (mismatch or
521    ///   missing)
522    /// - the deserialization of the metadata
523    ///   ([`ExtensionType::deserialize_metadata`]) fails
524    /// - the construction of the extension type ([`ExtensionType::try_new`])
525    ///   fail (for example when the [`Field::data_type`] is not supported by
526    ///   the extension type ([`ExtensionType::supports_data_type`]))
527    ///
528    /// # Example: Check and retrieve an extension type
529    /// You can use this to check if a [`Field`] has a specific
530    /// [`ExtensionType`] and retrieve it:
531    /// ```
532    /// # use arrow_schema::{DataType, Field, ArrowError};
533    /// # use arrow_schema::extension::ExtensionType;
534    /// # struct MyExtensionType;
535    /// # impl ExtensionType for MyExtensionType {
536    /// # const NAME: &'static str = "my_extension";
537    /// # type Metadata = String;
538    /// # fn supports_data_type(&self, data_type: &DataType) -> Result<(), ArrowError> { Ok(()) }
539    /// # fn try_new(data_type: &DataType, metadata: Self::Metadata) -> Result<Self, ArrowError> { Ok(Self) }
540    /// # fn serialize_metadata(&self) -> Option<String> { unimplemented!() }
541    /// # fn deserialize_metadata(s: Option<&str>) -> Result<Self::Metadata, ArrowError> { unimplemented!() }
542    /// # fn metadata(&self) -> &<Self as ExtensionType>::Metadata { todo!() }
543    /// # }
544    /// # fn get_field() -> Field { Field::new("field", DataType::Null, false) }
545    /// let field = get_field();
546    /// if let Ok(extension_type) = field.try_extension_type::<MyExtensionType>() {
547    ///   // do something with extension_type
548    /// }
549    /// ```
550    pub fn try_extension_type<E: ExtensionType>(&self) -> Result<E, ArrowError> {
551        E::try_new_from_field_metadata(self.data_type(), self.metadata())
552    }
553
554    /// Returns an instance of the given [`ExtensionType`] of this [`Field`],
555    /// panics if this [`Field`] does not have this extension type.
556    ///
557    /// # Panic
558    ///
559    /// This calls [`Field::try_extension_type`] and panics when it returns an
560    /// error.
561    pub fn extension_type<E: ExtensionType>(&self) -> E {
562        self.try_extension_type::<E>()
563            .unwrap_or_else(|e| panic!("{e}"))
564    }
565
566    /// Updates the metadata of this [`Field`] with the [`ExtensionType::NAME`]
567    /// and [`ExtensionType::metadata`] of the given [`ExtensionType`], if the
568    /// given extension type supports the [`Field::data_type`] of this field
569    /// ([`ExtensionType::supports_data_type`]).
570    ///
571    /// If the given extension type defines no metadata, a previously set
572    /// value of [`EXTENSION_TYPE_METADATA_KEY`] is cleared.
573    ///
574    /// # Error
575    ///
576    /// This functions returns an error if the data type of this field does not
577    /// match any of the supported storage types of the given extension type.
578    pub fn try_with_extension_type<E: ExtensionType>(
579        &mut self,
580        extension_type: E,
581    ) -> Result<(), ArrowError> {
582        // Make sure the data type of this field is supported
583        extension_type.supports_data_type(&self.data_type)?;
584
585        self.metadata
586            .insert(EXTENSION_TYPE_NAME_KEY.to_owned(), E::NAME.to_owned());
587        match extension_type.serialize_metadata() {
588            Some(metadata) => self
589                .metadata
590                .insert(EXTENSION_TYPE_METADATA_KEY.to_owned(), metadata),
591            // If this extension type has no metadata, we make sure to
592            // clear previously set metadata.
593            None => self.metadata.remove(EXTENSION_TYPE_METADATA_KEY),
594        };
595
596        Ok(())
597    }
598
599    /// Updates the metadata of this [`Field`] with the [`ExtensionType::NAME`]
600    /// and [`ExtensionType::metadata`] of the given [`ExtensionType`].
601    ///
602    /// # Panics
603    ///
604    /// This calls [`Field::try_with_extension_type`] and panics when it
605    /// returns an error.
606    pub fn with_extension_type<E: ExtensionType>(mut self, extension_type: E) -> Self {
607        self.try_with_extension_type(extension_type)
608            .unwrap_or_else(|e| panic!("{e}"));
609        self
610    }
611
612    /// Returns the [`CanonicalExtensionType`] of this [`Field`], if set.
613    ///
614    /// # Error
615    ///
616    /// Returns an error if
617    /// - this field does not have a canonical extension type (mismatch or missing)
618    /// - the canonical extension is not supported
619    /// - the construction of the extension type fails
620    #[cfg(feature = "canonical_extension_types")]
621    pub fn try_canonical_extension_type(&self) -> Result<CanonicalExtensionType, ArrowError> {
622        CanonicalExtensionType::try_from(self)
623    }
624
625    /// Indicates whether this [`Field`] supports null values.
626    ///
627    /// If true, the field *may* contain null values.
628    #[inline]
629    pub const fn is_nullable(&self) -> bool {
630        self.nullable
631    }
632
633    /// Set the `nullable` of this [`Field`].
634    ///
635    /// ```
636    /// # use arrow_schema::*;
637    /// let mut field = Field::new("c1", DataType::Int64, false);
638    /// field.set_nullable(true);
639    ///
640    /// assert_eq!(field.is_nullable(), true);
641    /// ```
642    #[inline]
643    pub fn set_nullable(&mut self, nullable: bool) {
644        self.nullable = nullable;
645    }
646
647    /// Set `nullable` of the [`Field`] and returns self.
648    ///
649    /// ```
650    /// # use arrow_schema::*;
651    /// let field = Field::new("c1", DataType::Int64, false)
652    ///    .with_nullable(true);
653    ///
654    /// assert_eq!(field.is_nullable(), true);
655    /// ```
656    pub fn with_nullable(mut self, nullable: bool) -> Self {
657        self.set_nullable(nullable);
658        self
659    }
660
661    /// Returns a (flattened) [`Vec`] containing all child [`Field`]s
662    /// within `self` contained within this field (including `self`)
663    pub(crate) fn fields(&self) -> Vec<&Field> {
664        let mut collected_fields = vec![self];
665        collected_fields.append(&mut Field::_fields(&self.data_type));
666
667        collected_fields
668    }
669
670    fn _fields(dt: &DataType) -> Vec<&Field> {
671        match dt {
672            DataType::Struct(fields) => fields.iter().flat_map(|f| f.fields()).collect(),
673            DataType::Union(fields, _) => fields.iter().flat_map(|(_, f)| f.fields()).collect(),
674            DataType::List(field)
675            | DataType::LargeList(field)
676            | DataType::ListView(field)
677            | DataType::LargeListView(field)
678            | DataType::FixedSizeList(field, _)
679            | DataType::Map(field, _) => field.fields(),
680            DataType::Dictionary(_, value_field) => Field::_fields(value_field.as_ref()),
681            DataType::RunEndEncoded(_, field) => field.fields(),
682            _ => vec![],
683        }
684    }
685
686    /// Returns a vector containing all (potentially nested) `Field` instances selected by the
687    /// dictionary ID they use
688    #[inline]
689    #[deprecated(
690        since = "54.0.0",
691        note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
692    )]
693    pub(crate) fn fields_with_dict_id(&self, id: i64) -> Vec<&Field> {
694        self.fields()
695            .into_iter()
696            .filter(|&field| {
697                #[allow(deprecated)]
698                let matching_dict_id = field.dict_id == id;
699                matches!(field.data_type(), DataType::Dictionary(_, _)) && matching_dict_id
700            })
701            .collect()
702    }
703
704    /// Returns the dictionary ID, if this is a dictionary type.
705    #[inline]
706    #[deprecated(
707        since = "54.0.0",
708        note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
709    )]
710    pub const fn dict_id(&self) -> Option<i64> {
711        match self.data_type {
712            #[allow(deprecated)]
713            DataType::Dictionary(_, _) => Some(self.dict_id),
714            _ => None,
715        }
716    }
717
718    /// Returns whether this `Field`'s dictionary is ordered, if this is a dictionary type.
719    ///
720    /// # Example
721    /// ```
722    /// # use arrow_schema::{DataType, Field};
723    /// // non dictionaries do not have a dict is ordered flat
724    /// let field = Field::new("c1", DataType::Int64, false);
725    /// assert_eq!(field.dict_is_ordered(), None);
726    /// // by default dictionary is not ordered
727    /// let field = Field::new("c1", DataType::Dictionary(Box::new(DataType::Int64), Box::new(DataType::Utf8)), false);
728    /// assert_eq!(field.dict_is_ordered(), Some(false));
729    /// let field = field.with_dict_is_ordered(true);
730    /// assert_eq!(field.dict_is_ordered(), Some(true));
731    /// ```
732    #[inline]
733    pub const fn dict_is_ordered(&self) -> Option<bool> {
734        match self.data_type {
735            DataType::Dictionary(_, _) => Some(self.dict_is_ordered),
736            _ => None,
737        }
738    }
739
740    /// Set the is ordered field for this `Field`, if it is a dictionary.
741    ///
742    /// Does nothing if this is not a dictionary type.
743    ///
744    /// See [`Field::dict_is_ordered`] for more information.
745    pub fn with_dict_is_ordered(mut self, dict_is_ordered: bool) -> Self {
746        if matches!(self.data_type, DataType::Dictionary(_, _)) {
747            self.dict_is_ordered = dict_is_ordered;
748        };
749        self
750    }
751
752    /// Merge this field into self if it is compatible.
753    ///
754    /// Struct fields are merged recursively.
755    ///
756    /// NOTE: `self` may be updated to a partial / unexpected state in case of merge failure.
757    ///
758    /// Example:
759    ///
760    /// ```
761    /// # use arrow_schema::*;
762    /// let mut field = Field::new("c1", DataType::Int64, false);
763    /// assert!(field.try_merge(&Field::new("c1", DataType::Int64, true)).is_ok());
764    /// assert!(field.is_nullable());
765    /// ```
766    pub fn try_merge(&mut self, from: &Field) -> Result<(), ArrowError> {
767        if from.dict_is_ordered != self.dict_is_ordered {
768            return Err(ArrowError::SchemaError(format!(
769                "Fail to merge schema field '{}' because from dict_is_ordered = {} does not match {}",
770                self.name, from.dict_is_ordered, self.dict_is_ordered
771            )));
772        }
773        // merge metadata
774        match (self.metadata().is_empty(), from.metadata().is_empty()) {
775            (false, false) => {
776                let mut merged = self.metadata().clone();
777                for (key, from_value) in from.metadata() {
778                    if let Some(self_value) = self.metadata.get(key) {
779                        if self_value != from_value {
780                            return Err(ArrowError::SchemaError(format!(
781                                "Fail to merge field '{}' due to conflicting metadata data value for key {}.
782                                    From value = {} does not match {}", self.name, key, from_value, self_value),
783                            ));
784                        }
785                    } else {
786                        merged.insert(key.clone(), from_value.clone());
787                    }
788                }
789                self.set_metadata(merged);
790            }
791            (true, false) => {
792                self.set_metadata(from.metadata().clone());
793            }
794            _ => {}
795        }
796        match &mut self.data_type {
797            DataType::Struct(nested_fields) => match &from.data_type {
798                DataType::Struct(from_nested_fields) => {
799                    let mut builder = SchemaBuilder::new();
800                    nested_fields
801                        .iter()
802                        .chain(from_nested_fields)
803                        .try_for_each(|f| builder.try_merge(f))?;
804                    *nested_fields = builder.finish().fields;
805                }
806                DataType::Null => {
807                    self.nullable = true;
808                }
809                _ => {
810                    return Err(ArrowError::SchemaError(format!(
811                        "Fail to merge schema field '{}' because the from data_type = {} is not DataType::Struct",
812                        self.name, from.data_type
813                    )));
814                }
815            },
816            DataType::Union(nested_fields, _) => match &from.data_type {
817                DataType::Union(from_nested_fields, _) => {
818                    nested_fields.try_merge(from_nested_fields)?
819                }
820                DataType::Null => {
821                    self.nullable = true;
822                }
823                _ => {
824                    return Err(ArrowError::SchemaError(format!(
825                        "Fail to merge schema field '{}' because the from data_type = {} is not DataType::Union",
826                        self.name, from.data_type
827                    )));
828                }
829            },
830            DataType::List(field) => match &from.data_type {
831                DataType::List(from_field) => {
832                    let mut f = (**field).clone();
833                    f.try_merge(from_field)?;
834                    (*field) = Arc::new(f);
835                }
836                DataType::Null => {
837                    self.nullable = true;
838                }
839                _ => {
840                    return Err(ArrowError::SchemaError(format!(
841                        "Fail to merge schema field '{}' because the from data_type = {} is not DataType::List",
842                        self.name, from.data_type
843                    )));
844                }
845            },
846            DataType::LargeList(field) => match &from.data_type {
847                DataType::LargeList(from_field) => {
848                    let mut f = (**field).clone();
849                    f.try_merge(from_field)?;
850                    (*field) = Arc::new(f);
851                }
852                DataType::Null => {
853                    self.nullable = true;
854                }
855                _ => {
856                    return Err(ArrowError::SchemaError(format!(
857                        "Fail to merge schema field '{}' because the from data_type = {} is not DataType::LargeList",
858                        self.name, from.data_type
859                    )));
860                }
861            },
862            DataType::Null => {
863                self.nullable = true;
864                self.data_type = from.data_type.clone();
865            }
866            DataType::Boolean
867            | DataType::Int8
868            | DataType::Int16
869            | DataType::Int32
870            | DataType::Int64
871            | DataType::UInt8
872            | DataType::UInt16
873            | DataType::UInt32
874            | DataType::UInt64
875            | DataType::Float16
876            | DataType::Float32
877            | DataType::Float64
878            | DataType::Timestamp(_, _)
879            | DataType::Date32
880            | DataType::Date64
881            | DataType::Time32(_)
882            | DataType::Time64(_)
883            | DataType::Duration(_)
884            | DataType::Binary
885            | DataType::LargeBinary
886            | DataType::BinaryView
887            | DataType::Interval(_)
888            | DataType::LargeListView(_)
889            | DataType::ListView(_)
890            | DataType::Map(_, _)
891            | DataType::Dictionary(_, _)
892            | DataType::RunEndEncoded(_, _)
893            | DataType::FixedSizeList(_, _)
894            | DataType::FixedSizeBinary(_)
895            | DataType::Utf8
896            | DataType::LargeUtf8
897            | DataType::Utf8View
898            | DataType::Decimal32(_, _)
899            | DataType::Decimal64(_, _)
900            | DataType::Decimal128(_, _)
901            | DataType::Decimal256(_, _) => {
902                if from.data_type == DataType::Null {
903                    self.nullable = true;
904                } else if self.data_type != from.data_type {
905                    return Err(ArrowError::SchemaError(format!(
906                        "Fail to merge schema field '{}' because the from data_type = {} does not equal {}",
907                        self.name, from.data_type, self.data_type
908                    )));
909                }
910            }
911        }
912        self.nullable |= from.nullable;
913
914        Ok(())
915    }
916
917    /// Check to see if `self` is a superset of `other` field. Superset is defined as:
918    ///
919    /// * if nullability doesn't match, self needs to be nullable
920    /// * self.metadata is a superset of other.metadata
921    /// * all other fields are equal
922    pub fn contains(&self, other: &Field) -> bool {
923        self.name == other.name
924        && self.data_type.contains(&other.data_type)
925        && self.dict_is_ordered == other.dict_is_ordered
926        // self need to be nullable or both of them are not nullable
927        && (self.nullable || !other.nullable)
928        // make sure self.metadata is a superset of other.metadata
929        && other.metadata.iter().all(|(k, v1)| {
930            self.metadata.get(k).map(|v2| v1 == v2).unwrap_or_default()
931        })
932    }
933
934    /// Return size of this instance in bytes.
935    ///
936    /// Includes the size of `Self`.
937    pub fn size(&self) -> usize {
938        std::mem::size_of_val(self) - std::mem::size_of_val(&self.data_type)
939            + self.data_type.size()
940            + self.name.capacity()
941            + (std::mem::size_of::<(String, String)>() * self.metadata.len())
942            + self
943                .metadata
944                .iter()
945                .map(|(k, v)| k.capacity() + v.capacity())
946                .sum::<usize>()
947    }
948}
949
950impl std::fmt::Display for Field {
951    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
952        #![expect(deprecated)] // Must still print dict_id, if set
953        let Self {
954            name,
955            data_type,
956            nullable,
957            dict_id,
958            dict_is_ordered,
959            metadata,
960        } = self;
961        let maybe_nullable = if *nullable { "nullable " } else { "" };
962        let metadata_str = if metadata.is_empty() {
963            String::new()
964        } else {
965            format!(", metadata: {metadata:?}")
966        };
967        let dict_id_str = if dict_id == &0 {
968            String::new()
969        } else {
970            format!(", dict_id: {dict_id}")
971        };
972        let dict_is_ordered_str = if *dict_is_ordered {
973            ", dict_is_ordered"
974        } else {
975            ""
976        };
977        write!(
978            f,
979            "Field {{ {name:?}: {maybe_nullable}{data_type}{dict_id_str}{dict_is_ordered_str}{metadata_str} }}"
980        )
981    }
982}
983
984#[cfg(test)]
985mod test {
986    use super::*;
987    use std::collections::HashMap;
988    use std::collections::hash_map::DefaultHasher;
989
990    #[derive(Debug, Clone, Copy)]
991    struct TestExtensionType;
992
993    impl ExtensionType for TestExtensionType {
994        const NAME: &'static str = "test.extension";
995        type Metadata = ();
996
997        fn metadata(&self) -> &Self::Metadata {
998            &()
999        }
1000
1001        fn serialize_metadata(&self) -> Option<String> {
1002            None
1003        }
1004
1005        fn deserialize_metadata(metadata: Option<&str>) -> Result<Self::Metadata, ArrowError> {
1006            metadata.map_or(Ok(()), |_| {
1007                Err(ArrowError::InvalidArgumentError(
1008                    "TestExtensionType expects no metadata".to_owned(),
1009                ))
1010            })
1011        }
1012
1013        fn supports_data_type(&self, _data_type: &DataType) -> Result<(), ArrowError> {
1014            Ok(())
1015        }
1016
1017        fn try_new(_data_type: &DataType, _metadata: Self::Metadata) -> Result<Self, ArrowError> {
1018            Ok(Self)
1019        }
1020    }
1021
1022    #[test]
1023    fn test_has_valid_extension_type() {
1024        let no_extension = Field::new("f", DataType::Null, false);
1025        assert!(!no_extension.has_valid_extension_type::<TestExtensionType>());
1026
1027        let matching_name = Field::new("f", DataType::Null, false)
1028            .with_metadata([(EXTENSION_TYPE_NAME_KEY, TestExtensionType::NAME)]);
1029        assert!(matching_name.has_valid_extension_type::<TestExtensionType>());
1030
1031        let matching_name_with_invalid_metadata = Field::new("f", DataType::Null, false)
1032            .with_metadata([
1033                (EXTENSION_TYPE_NAME_KEY, TestExtensionType::NAME),
1034                (EXTENSION_TYPE_METADATA_KEY, "invalid"),
1035            ]);
1036        assert!(
1037            !matching_name_with_invalid_metadata.has_valid_extension_type::<TestExtensionType>()
1038        );
1039
1040        let different_name = Field::new("f", DataType::Null, false)
1041            .with_metadata([(EXTENSION_TYPE_NAME_KEY, "some.other_extension")]);
1042        assert!(!different_name.has_valid_extension_type::<TestExtensionType>());
1043    }
1044
1045    #[test]
1046    fn test_new_with_string() {
1047        // Fields should allow owned Strings to support reuse
1048        let s = "c1";
1049        Field::new(s, DataType::Int64, false);
1050    }
1051
1052    #[test]
1053    fn test_new_dict_with_string() {
1054        // Fields should allow owned Strings to support reuse
1055        let s = "c1";
1056        #[allow(deprecated)]
1057        Field::new_dict(s, DataType::Int64, false, 4, false);
1058    }
1059
1060    #[test]
1061    #[cfg_attr(miri, ignore)] // Can't handle the inlined strings of the assert_debug_snapshot macro
1062    fn test_debug_format_field() {
1063        // Make sure the `Debug` formatting of `Field` is readable and not too long
1064        insta::assert_debug_snapshot!(Field::new("item", DataType::UInt8, false), @r"
1065        Field {
1066            data_type: UInt8,
1067        }
1068        ");
1069        insta::assert_debug_snapshot!(Field::new("column", DataType::LargeUtf8, true), @r#"
1070        Field {
1071            name: "column",
1072            data_type: LargeUtf8,
1073            nullable: true,
1074        }
1075        "#);
1076    }
1077
1078    #[test]
1079    fn test_merge_incompatible_types() {
1080        let mut field = Field::new("c1", DataType::Int64, false);
1081        let result = field
1082            .try_merge(&Field::new("c1", DataType::Float32, true))
1083            .expect_err("should fail")
1084            .to_string();
1085        assert_eq!(
1086            "Schema error: Fail to merge schema field 'c1' because the from data_type = Float32 does not equal Int64",
1087            result
1088        );
1089    }
1090
1091    #[test]
1092    fn test_merge_with_null() {
1093        let mut field1 = Field::new("c1", DataType::Null, true);
1094        field1
1095            .try_merge(&Field::new("c1", DataType::Float32, false))
1096            .expect("should widen type to nullable float");
1097        assert_eq!(Field::new("c1", DataType::Float32, true), field1);
1098
1099        let mut field2 = Field::new("c2", DataType::Utf8, false);
1100        field2
1101            .try_merge(&Field::new("c2", DataType::Null, true))
1102            .expect("should widen type to nullable utf8");
1103        assert_eq!(Field::new("c2", DataType::Utf8, true), field2);
1104    }
1105
1106    #[test]
1107    fn test_merge_with_nested_null() {
1108        let mut struct1 = Field::new(
1109            "s1",
1110            DataType::Struct(Fields::from(vec![Field::new(
1111                "inner",
1112                DataType::Float32,
1113                false,
1114            )])),
1115            false,
1116        );
1117
1118        let struct2 = Field::new(
1119            "s2",
1120            DataType::Struct(Fields::from(vec![Field::new(
1121                "inner",
1122                DataType::Null,
1123                false,
1124            )])),
1125            true,
1126        );
1127
1128        struct1
1129            .try_merge(&struct2)
1130            .expect("should widen inner field's type to nullable float");
1131        assert_eq!(
1132            Field::new(
1133                "s1",
1134                DataType::Struct(Fields::from(vec![Field::new(
1135                    "inner",
1136                    DataType::Float32,
1137                    true,
1138                )])),
1139                true,
1140            ),
1141            struct1
1142        );
1143
1144        let mut list1 = Field::new(
1145            "l1",
1146            DataType::List(Field::new("inner", DataType::Float32, false).into()),
1147            false,
1148        );
1149
1150        let list2 = Field::new(
1151            "l2",
1152            DataType::List(Field::new("inner", DataType::Null, false).into()),
1153            true,
1154        );
1155
1156        list1
1157            .try_merge(&list2)
1158            .expect("should widen inner field's type to nullable float");
1159        assert_eq!(
1160            Field::new(
1161                "l1",
1162                DataType::List(Field::new("inner", DataType::Float32, true).into()),
1163                true,
1164            ),
1165            list1
1166        );
1167
1168        let mut large_list1 = Field::new(
1169            "ll1",
1170            DataType::LargeList(Field::new("inner", DataType::Float32, false).into()),
1171            false,
1172        );
1173
1174        let large_list2 = Field::new(
1175            "ll2",
1176            DataType::LargeList(Field::new("inner", DataType::Null, false).into()),
1177            true,
1178        );
1179
1180        large_list1
1181            .try_merge(&large_list2)
1182            .expect("should widen inner field's type to nullable float");
1183        assert_eq!(
1184            Field::new(
1185                "ll1",
1186                DataType::LargeList(Field::new("inner", DataType::Float32, true).into()),
1187                true,
1188            ),
1189            large_list1
1190        );
1191    }
1192
1193    #[test]
1194    fn test_fields_with_dict_id() {
1195        #[allow(deprecated)]
1196        let dict1 = Field::new_dict(
1197            "dict1",
1198            DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1199            false,
1200            10,
1201            false,
1202        );
1203        #[allow(deprecated)]
1204        let dict2 = Field::new_dict(
1205            "dict2",
1206            DataType::Dictionary(DataType::Int32.into(), DataType::Int8.into()),
1207            false,
1208            20,
1209            false,
1210        );
1211
1212        let field = Field::new(
1213            "struct<dict1, list[struct<dict2, list[struct<dict1]>]>",
1214            DataType::Struct(Fields::from(vec![
1215                dict1.clone(),
1216                Field::new(
1217                    "list[struct<dict1, list[struct<dict2>]>]",
1218                    DataType::List(Arc::new(Field::new(
1219                        "struct<dict1, list[struct<dict2>]>",
1220                        DataType::Struct(Fields::from(vec![
1221                            dict1.clone(),
1222                            Field::new(
1223                                "list[struct<dict2>]",
1224                                DataType::List(Arc::new(Field::new(
1225                                    "struct<dict2>",
1226                                    DataType::Struct(vec![dict2.clone()].into()),
1227                                    false,
1228                                ))),
1229                                false,
1230                            ),
1231                        ])),
1232                        false,
1233                    ))),
1234                    false,
1235                ),
1236            ])),
1237            false,
1238        );
1239
1240        #[allow(deprecated)]
1241        for field in field.fields_with_dict_id(10) {
1242            assert_eq!(dict1, *field);
1243        }
1244        #[allow(deprecated)]
1245        for field in field.fields_with_dict_id(20) {
1246            assert_eq!(dict2, *field);
1247        }
1248    }
1249
1250    fn get_field_hash(field: &Field) -> u64 {
1251        let mut s = DefaultHasher::new();
1252        field.hash(&mut s);
1253        s.finish()
1254    }
1255
1256    #[test]
1257    fn test_field_comparison_case() {
1258        // dictionary-encoding properties not used for field comparison
1259        #[allow(deprecated)]
1260        let dict1 = Field::new_dict(
1261            "dict1",
1262            DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1263            false,
1264            10,
1265            false,
1266        );
1267        #[allow(deprecated)]
1268        let dict2 = Field::new_dict(
1269            "dict1",
1270            DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1271            false,
1272            20,
1273            false,
1274        );
1275
1276        assert_eq!(dict1, dict2);
1277        assert_eq!(get_field_hash(&dict1), get_field_hash(&dict2));
1278
1279        #[allow(deprecated)]
1280        let dict1 = Field::new_dict(
1281            "dict0",
1282            DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1283            false,
1284            10,
1285            false,
1286        );
1287
1288        assert_ne!(dict1, dict2);
1289        assert_ne!(get_field_hash(&dict1), get_field_hash(&dict2));
1290    }
1291
1292    #[test]
1293    fn test_field_comparison_metadata() {
1294        let f1 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1295            (String::from("k1"), String::from("v1")),
1296            (String::from("k2"), String::from("v2")),
1297        ]));
1298        let f2 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1299            (String::from("k1"), String::from("v1")),
1300            (String::from("k3"), String::from("v3")),
1301        ]));
1302        let f3 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1303            (String::from("k1"), String::from("v1")),
1304            (String::from("k3"), String::from("v4")),
1305        ]));
1306
1307        assert!(f1.cmp(&f2).is_lt());
1308        assert!(f2.cmp(&f3).is_lt());
1309        assert!(f1.cmp(&f3).is_lt());
1310    }
1311
1312    #[test]
1313    #[expect(clippy::needless_borrows_for_generic_args)] // intentional to exercise various references
1314    fn test_field_as_ref() {
1315        let field = || Field::new("x", DataType::Binary, false);
1316
1317        // AsRef can be used in a function accepting a field.
1318        // However, this case actually works a bit better when function takes `&Field`
1319        fn accept_ref(_: impl AsRef<Field>) {}
1320
1321        accept_ref(field());
1322        accept_ref(&field());
1323        accept_ref(&&field());
1324        accept_ref(Arc::new(field()));
1325        accept_ref(&Arc::new(field()));
1326        accept_ref(&&Arc::new(field()));
1327
1328        // AsRef can be used in a function accepting a collection of fields in any form,
1329        // such as &[Field], or &[Arc<Field>]
1330        fn accept_refs(_: impl IntoIterator<Item: AsRef<Field>>) {}
1331
1332        accept_refs(vec![field()]);
1333        accept_refs(vec![&field()]);
1334        accept_refs(vec![Arc::new(field())]);
1335        accept_refs(vec![&Arc::new(field())]);
1336        accept_refs(&vec![field()]);
1337        accept_refs(&vec![&field()]);
1338        accept_refs(&vec![Arc::new(field())]);
1339        accept_refs(&vec![&Arc::new(field())]);
1340    }
1341
1342    #[test]
1343    fn test_contains_reflexivity() {
1344        let mut field = Field::new("field1", DataType::Float16, false);
1345        field.set_metadata(HashMap::from([
1346            (String::from("k0"), String::from("v0")),
1347            (String::from("k1"), String::from("v1")),
1348        ]));
1349        assert!(field.contains(&field))
1350    }
1351
1352    #[test]
1353    fn test_contains_transitivity() {
1354        let child_field = Field::new("child1", DataType::Float16, false);
1355
1356        let mut field1 = Field::new(
1357            "field1",
1358            DataType::Struct(Fields::from(vec![child_field])),
1359            false,
1360        );
1361        field1.set_metadata(HashMap::from([(String::from("k1"), String::from("v1"))]));
1362
1363        let mut field2 = Field::new("field1", DataType::Struct(Fields::default()), true);
1364        field2.set_metadata(HashMap::from([(String::from("k2"), String::from("v2"))]));
1365        field2.try_merge(&field1).unwrap();
1366
1367        let mut field3 = Field::new("field1", DataType::Struct(Fields::default()), false);
1368        field3.set_metadata(HashMap::from([(String::from("k3"), String::from("v3"))]));
1369        field3.try_merge(&field2).unwrap();
1370
1371        assert!(field2.contains(&field1));
1372        assert!(field3.contains(&field2));
1373        assert!(field3.contains(&field1));
1374
1375        assert!(!field1.contains(&field2));
1376        assert!(!field1.contains(&field3));
1377        assert!(!field2.contains(&field3));
1378    }
1379
1380    #[test]
1381    fn test_contains_nullable() {
1382        let field1 = Field::new("field1", DataType::Boolean, true);
1383        let field2 = Field::new("field1", DataType::Boolean, false);
1384        assert!(field1.contains(&field2));
1385        assert!(!field2.contains(&field1));
1386    }
1387
1388    #[test]
1389    fn test_contains_must_have_same_fields() {
1390        let child_field1 = Field::new("child1", DataType::Float16, false);
1391        let child_field2 = Field::new("child2", DataType::Float16, false);
1392
1393        let field1 = Field::new(
1394            "field1",
1395            DataType::Struct(vec![child_field1.clone()].into()),
1396            true,
1397        );
1398        let field2 = Field::new(
1399            "field1",
1400            DataType::Struct(vec![child_field1, child_field2].into()),
1401            true,
1402        );
1403
1404        assert!(!field1.contains(&field2));
1405        assert!(!field2.contains(&field1));
1406
1407        // UnionFields with different type ID
1408        let field1 = Field::new(
1409            "field1",
1410            DataType::Union(
1411                UnionFields::try_new(
1412                    vec![1, 2],
1413                    vec![
1414                        Field::new("field1", DataType::UInt8, true),
1415                        Field::new("field3", DataType::Utf8, false),
1416                    ],
1417                )
1418                .unwrap(),
1419                UnionMode::Dense,
1420            ),
1421            true,
1422        );
1423        let field2 = Field::new(
1424            "field1",
1425            DataType::Union(
1426                UnionFields::try_new(
1427                    vec![1, 3],
1428                    vec![
1429                        Field::new("field1", DataType::UInt8, false),
1430                        Field::new("field3", DataType::Utf8, false),
1431                    ],
1432                )
1433                .unwrap(),
1434                UnionMode::Dense,
1435            ),
1436            true,
1437        );
1438        assert!(!field1.contains(&field2));
1439
1440        // UnionFields with same type ID
1441        let field1 = Field::new(
1442            "field1",
1443            DataType::Union(
1444                UnionFields::try_new(
1445                    vec![1, 2],
1446                    vec![
1447                        Field::new("field1", DataType::UInt8, true),
1448                        Field::new("field3", DataType::Utf8, false),
1449                    ],
1450                )
1451                .unwrap(),
1452                UnionMode::Dense,
1453            ),
1454            true,
1455        );
1456        let field2 = Field::new(
1457            "field1",
1458            DataType::Union(
1459                UnionFields::try_new(
1460                    vec![1, 2],
1461                    vec![
1462                        Field::new("field1", DataType::UInt8, false),
1463                        Field::new("field3", DataType::Utf8, false),
1464                    ],
1465                )
1466                .unwrap(),
1467                UnionMode::Dense,
1468            ),
1469            true,
1470        );
1471        assert!(field1.contains(&field2));
1472    }
1473
1474    #[cfg(feature = "serde")]
1475    fn assert_binary_serde_round_trip(field: Field) {
1476        let serialized = postcard::to_stdvec(&field).unwrap();
1477        let deserialized: Field = postcard::from_bytes(&serialized).unwrap();
1478        assert_eq!(field, deserialized)
1479    }
1480
1481    #[cfg(feature = "serde")]
1482    #[test]
1483    fn test_field_without_metadata_serde() {
1484        let field = Field::new("name", DataType::Boolean, true);
1485        assert_binary_serde_round_trip(field)
1486    }
1487
1488    #[cfg(feature = "serde")]
1489    #[test]
1490    fn test_field_with_empty_metadata_serde() {
1491        let field = Field::new("name", DataType::Boolean, false).with_metadata(HashMap::new());
1492
1493        assert_binary_serde_round_trip(field)
1494    }
1495
1496    #[cfg(feature = "serde")]
1497    #[test]
1498    fn test_field_with_nonempty_metadata_serde() {
1499        let mut metadata = HashMap::new();
1500        metadata.insert("hi".to_owned(), "".to_owned());
1501        let field = Field::new("name", DataType::Boolean, false).with_metadata(metadata);
1502
1503        assert_binary_serde_round_trip(field)
1504    }
1505
1506    #[test]
1507    fn test_merge_compound_with_null() {
1508        // Struct + Null
1509        let mut field = Field::new(
1510            "s",
1511            DataType::Struct(Fields::from(vec![Field::new("a", DataType::Int32, false)])),
1512            false,
1513        );
1514        field
1515            .try_merge(&Field::new("s", DataType::Null, true))
1516            .expect("Struct should merge with Null");
1517        assert!(field.is_nullable());
1518        assert!(matches!(field.data_type(), DataType::Struct(_)));
1519
1520        // List + Null
1521        let mut field = Field::new(
1522            "l",
1523            DataType::List(Field::new("item", DataType::Utf8, false).into()),
1524            false,
1525        );
1526        field
1527            .try_merge(&Field::new("l", DataType::Null, true))
1528            .expect("List should merge with Null");
1529        assert!(field.is_nullable());
1530        assert!(matches!(field.data_type(), DataType::List(_)));
1531
1532        // LargeList + Null
1533        let mut field = Field::new(
1534            "ll",
1535            DataType::LargeList(Field::new("item", DataType::Utf8, false).into()),
1536            false,
1537        );
1538        field
1539            .try_merge(&Field::new("ll", DataType::Null, true))
1540            .expect("LargeList should merge with Null");
1541        assert!(field.is_nullable());
1542        assert!(matches!(field.data_type(), DataType::LargeList(_)));
1543
1544        // Union + Null
1545        let mut field = Field::new(
1546            "u",
1547            DataType::Union(
1548                UnionFields::try_new(vec![0], vec![Field::new("f", DataType::Int32, false)])
1549                    .unwrap(),
1550                UnionMode::Dense,
1551            ),
1552            false,
1553        );
1554        field
1555            .try_merge(&Field::new("u", DataType::Null, true))
1556            .expect("Union should merge with Null");
1557        assert!(matches!(field.data_type(), DataType::Union(_, _)));
1558    }
1559}