1use crate::error::ArrowError;
19use std::cmp::Ordering;
20use std::collections::HashMap;
21use std::hash::{Hash, Hasher};
22use std::sync::Arc;
23
24use crate::datatype::DataType;
25#[cfg(feature = "canonical_extension_types")]
26use crate::extension::CanonicalExtensionType;
27use crate::schema::SchemaBuilder;
28use crate::{
29 Fields, UnionFields, UnionMode,
30 extension::{EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_NAME_KEY, ExtensionType},
31};
32
33pub type FieldRef = Arc<Field>;
35
36#[derive(Clone)]
48#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
49pub struct Field {
50 name: String,
51 data_type: DataType,
52 nullable: bool,
53 #[deprecated(
54 since = "54.0.0",
55 note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
56 )]
57 dict_id: i64,
58 dict_is_ordered: bool,
59 metadata: HashMap<String, String>,
61}
62
63impl std::fmt::Debug for Field {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 #![expect(deprecated)] let Self {
67 name,
68 data_type,
69 nullable,
70 dict_id,
71 dict_is_ordered,
72 metadata,
73 } = self;
74
75 let mut s = f.debug_struct("Field");
76
77 if name != "item" {
78 s.field("name", name);
80 }
81
82 s.field("data_type", data_type);
83
84 if *nullable {
85 s.field("nullable", nullable);
86 }
87
88 if *dict_id != 0 {
89 s.field("dict_id", dict_id);
90 }
91
92 if *dict_is_ordered {
93 s.field("dict_is_ordered", dict_is_ordered);
94 }
95
96 if !metadata.is_empty() {
97 s.field("metadata", metadata);
98 }
99 s.finish()
100 }
101}
102
103impl PartialEq for Field {
109 fn eq(&self, other: &Self) -> bool {
110 self.name == other.name
111 && self.data_type == other.data_type
112 && self.nullable == other.nullable
113 && self.metadata == other.metadata
114 }
115}
116
117impl Eq for Field {}
118
119impl PartialOrd for Field {
120 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
121 Some(self.cmp(other))
122 }
123}
124
125impl Ord for Field {
126 fn cmp(&self, other: &Self) -> Ordering {
127 self.name
128 .cmp(other.name())
129 .then_with(|| self.data_type.cmp(other.data_type()))
130 .then_with(|| self.nullable.cmp(&other.nullable))
131 .then_with(|| {
132 let mut keys: Vec<&String> =
134 self.metadata.keys().chain(other.metadata.keys()).collect();
135 keys.sort();
136 for k in keys {
137 match (self.metadata.get(k), other.metadata.get(k)) {
138 (None, None) => {}
139 (Some(_), None) => {
140 return Ordering::Less;
141 }
142 (None, Some(_)) => {
143 return Ordering::Greater;
144 }
145 (Some(v1), Some(v2)) => match v1.cmp(v2) {
146 Ordering::Equal => {}
147 other => {
148 return other;
149 }
150 },
151 }
152 }
153
154 Ordering::Equal
155 })
156 }
157}
158
159impl Hash for Field {
160 fn hash<H: Hasher>(&self, state: &mut H) {
161 self.name.hash(state);
162 self.data_type.hash(state);
163 self.nullable.hash(state);
164
165 let mut keys: Vec<&String> = self.metadata.keys().collect();
167 keys.sort();
168 for k in keys {
169 k.hash(state);
170 self.metadata.get(k).expect("key valid").hash(state);
171 }
172 }
173}
174
175impl AsRef<Field> for Field {
176 fn as_ref(&self) -> &Field {
177 self
178 }
179}
180
181impl Field {
182 pub const LIST_FIELD_DEFAULT_NAME: &'static str = "item";
184 pub const MAP_ENTRIES_FIELD_DEFAULT_NAME: &'static str = "entries";
188 pub const MAP_KEY_FIELD_DEFAULT_NAME: &'static str = "key";
192 pub const MAP_VALUE_FIELD_DEFAULT_NAME: &'static str = "value";
196
197 pub fn new(name: impl Into<String>, data_type: DataType, nullable: bool) -> Self {
205 #[allow(deprecated)]
206 Field {
207 name: name.into(),
208 data_type,
209 nullable,
210 dict_id: 0,
211 dict_is_ordered: false,
212 metadata: HashMap::default(),
213 }
214 }
215
216 pub fn new_list_field(data_type: DataType, nullable: bool) -> Self {
231 Self::new(Self::LIST_FIELD_DEFAULT_NAME, data_type, nullable)
232 }
233
234 #[deprecated(
236 since = "54.0.0",
237 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."
238 )]
239 pub fn new_dict(
240 name: impl Into<String>,
241 data_type: DataType,
242 nullable: bool,
243 dict_id: i64,
244 dict_is_ordered: bool,
245 ) -> Self {
246 #[allow(deprecated)]
247 Field {
248 name: name.into(),
249 data_type,
250 nullable,
251 dict_id,
252 dict_is_ordered,
253 metadata: HashMap::default(),
254 }
255 }
256
257 pub fn new_dictionary(
265 name: impl Into<String>,
266 key: DataType,
267 value: DataType,
268 nullable: bool,
269 ) -> Self {
270 assert!(
271 key.is_dictionary_key_type(),
272 "{key} is not a valid dictionary key"
273 );
274 let data_type = DataType::Dictionary(Box::new(key), Box::new(value));
275 Self::new(name, data_type, nullable)
276 }
277
278 pub fn new_struct(name: impl Into<String>, fields: impl Into<Fields>, nullable: bool) -> Self {
284 Self::new(name, DataType::Struct(fields.into()), nullable)
285 }
286
287 pub fn new_list(name: impl Into<String>, value: impl Into<FieldRef>, nullable: bool) -> Self {
293 Self::new(name, DataType::List(value.into()), nullable)
294 }
295
296 pub fn new_large_list(
302 name: impl Into<String>,
303 value: impl Into<FieldRef>,
304 nullable: bool,
305 ) -> Self {
306 Self::new(name, DataType::LargeList(value.into()), nullable)
307 }
308
309 pub fn new_fixed_size_list(
316 name: impl Into<String>,
317 value: impl Into<FieldRef>,
318 size: i32,
319 nullable: bool,
320 ) -> Self {
321 Self::new(name, DataType::FixedSizeList(value.into(), size), nullable)
322 }
323
324 pub fn new_map(
333 name: impl Into<String>,
334 entries: impl Into<String>,
335 keys: impl Into<FieldRef>,
336 values: impl Into<FieldRef>,
337 sorted: bool,
338 nullable: bool,
339 ) -> Self {
340 let data_type = DataType::Map(
341 Arc::new(Field::new(
342 entries.into(),
343 DataType::Struct(Fields::from([keys.into(), values.into()])),
344 false, )),
346 sorted,
347 );
348 Self::new(name, data_type, nullable)
349 }
350
351 pub fn new_union<S, F, T>(name: S, type_ids: T, fields: F, mode: UnionMode) -> Self
365 where
366 S: Into<String>,
367 F: IntoIterator,
368 F::Item: Into<FieldRef>,
369 T: IntoIterator<Item = i8>,
370 {
371 Self::new(
372 name,
373 DataType::Union(
374 UnionFields::try_new(type_ids, fields).expect("Invalid UnionField"),
375 mode,
376 ),
377 false, )
379 }
380
381 #[inline]
383 pub fn set_metadata(&mut self, metadata: HashMap<String, String>) {
384 self.metadata = metadata;
385 }
386
387 pub fn with_metadata(mut self, metadata: HashMap<String, String>) -> Self {
389 self.set_metadata(metadata);
390 self
391 }
392
393 #[inline]
395 pub const fn metadata(&self) -> &HashMap<String, String> {
396 &self.metadata
397 }
398
399 #[inline]
401 pub fn metadata_mut(&mut self) -> &mut HashMap<String, String> {
402 &mut self.metadata
403 }
404
405 #[inline]
407 pub const fn name(&self) -> &String {
408 &self.name
409 }
410
411 #[inline]
413 pub fn set_name(&mut self, name: impl Into<String>) {
414 self.name = name.into();
415 }
416
417 pub fn with_name(mut self, name: impl Into<String>) -> Self {
427 self.set_name(name);
428 self
429 }
430
431 #[inline]
433 pub const fn data_type(&self) -> &DataType {
434 &self.data_type
435 }
436
437 #[inline]
447 pub fn set_data_type(&mut self, data_type: DataType) {
448 self.data_type = data_type;
449 }
450
451 pub fn with_data_type(mut self, data_type: DataType) -> Self {
461 self.set_data_type(data_type);
462 self
463 }
464
465 pub fn extension_type_name(&self) -> Option<&str> {
487 self.metadata()
488 .get(EXTENSION_TYPE_NAME_KEY)
489 .map(String::as_ref)
490 }
491
492 pub fn extension_type_metadata(&self) -> Option<&str> {
514 self.metadata()
515 .get(EXTENSION_TYPE_METADATA_KEY)
516 .map(String::as_ref)
517 }
518
519 #[inline]
528 pub fn has_valid_extension_type<E: ExtensionType>(&self) -> bool {
529 if self.extension_type_name() != Some(E::NAME) {
530 return false;
531 }
532
533 let ext_metadata = self
534 .metadata()
535 .get(EXTENSION_TYPE_METADATA_KEY)
536 .map(|s| s.as_str());
537
538 E::deserialize_metadata(ext_metadata)
539 .and_then(|metadata| E::validate(self.data_type(), metadata))
540 .is_ok()
541 }
542
543 pub fn try_extension_type<E: ExtensionType>(&self) -> Result<E, ArrowError> {
588 E::try_new_from_field_metadata(self.data_type(), self.metadata())
589 }
590
591 pub fn extension_type<E: ExtensionType>(&self) -> E {
599 self.try_extension_type::<E>()
600 .unwrap_or_else(|e| panic!("{e}"))
601 }
602
603 pub fn try_with_extension_type<E: ExtensionType>(
616 &mut self,
617 extension_type: E,
618 ) -> Result<(), ArrowError> {
619 extension_type.supports_data_type(&self.data_type)?;
621
622 self.metadata
623 .insert(EXTENSION_TYPE_NAME_KEY.to_owned(), E::NAME.to_owned());
624 match extension_type.serialize_metadata() {
625 Some(metadata) => self
626 .metadata
627 .insert(EXTENSION_TYPE_METADATA_KEY.to_owned(), metadata),
628 None => self.metadata.remove(EXTENSION_TYPE_METADATA_KEY),
631 };
632
633 Ok(())
634 }
635
636 pub fn with_extension_type<E: ExtensionType>(mut self, extension_type: E) -> Self {
644 self.try_with_extension_type(extension_type)
645 .unwrap_or_else(|e| panic!("{e}"));
646 self
647 }
648
649 #[cfg(feature = "canonical_extension_types")]
658 pub fn try_canonical_extension_type(&self) -> Result<CanonicalExtensionType, ArrowError> {
659 CanonicalExtensionType::try_from(self)
660 }
661
662 #[inline]
666 pub const fn is_nullable(&self) -> bool {
667 self.nullable
668 }
669
670 #[inline]
680 pub fn set_nullable(&mut self, nullable: bool) {
681 self.nullable = nullable;
682 }
683
684 pub fn with_nullable(mut self, nullable: bool) -> Self {
694 self.set_nullable(nullable);
695 self
696 }
697
698 pub(crate) fn fields(&self) -> Vec<&Field> {
701 let mut collected_fields = vec![self];
702 collected_fields.append(&mut Field::_fields(&self.data_type));
703
704 collected_fields
705 }
706
707 fn _fields(dt: &DataType) -> Vec<&Field> {
708 match dt {
709 DataType::Struct(fields) => fields.iter().flat_map(|f| f.fields()).collect(),
710 DataType::Union(fields, _) => fields.iter().flat_map(|(_, f)| f.fields()).collect(),
711 DataType::List(field)
712 | DataType::LargeList(field)
713 | DataType::ListView(field)
714 | DataType::LargeListView(field)
715 | DataType::FixedSizeList(field, _)
716 | DataType::Map(field, _) => field.fields(),
717 DataType::Dictionary(_, value_field) => Field::_fields(value_field.as_ref()),
718 DataType::RunEndEncoded(_, field) => field.fields(),
719 _ => vec![],
720 }
721 }
722
723 #[inline]
726 #[deprecated(
727 since = "54.0.0",
728 note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
729 )]
730 pub(crate) fn fields_with_dict_id(&self, id: i64) -> Vec<&Field> {
731 self.fields()
732 .into_iter()
733 .filter(|&field| {
734 #[allow(deprecated)]
735 let matching_dict_id = field.dict_id == id;
736 matches!(field.data_type(), DataType::Dictionary(_, _)) && matching_dict_id
737 })
738 .collect()
739 }
740
741 #[inline]
743 #[deprecated(
744 since = "54.0.0",
745 note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
746 )]
747 pub const fn dict_id(&self) -> Option<i64> {
748 match self.data_type {
749 #[allow(deprecated)]
750 DataType::Dictionary(_, _) => Some(self.dict_id),
751 _ => None,
752 }
753 }
754
755 #[inline]
770 pub const fn dict_is_ordered(&self) -> Option<bool> {
771 match self.data_type {
772 DataType::Dictionary(_, _) => Some(self.dict_is_ordered),
773 _ => None,
774 }
775 }
776
777 pub fn with_dict_is_ordered(mut self, dict_is_ordered: bool) -> Self {
783 if matches!(self.data_type, DataType::Dictionary(_, _)) {
784 self.dict_is_ordered = dict_is_ordered;
785 };
786 self
787 }
788
789 pub fn try_merge(&mut self, from: &Field) -> Result<(), ArrowError> {
804 if from.dict_is_ordered != self.dict_is_ordered {
805 return Err(ArrowError::SchemaError(format!(
806 "Fail to merge schema field '{}' because from dict_is_ordered = {} does not match {}",
807 self.name, from.dict_is_ordered, self.dict_is_ordered
808 )));
809 }
810 match (self.metadata().is_empty(), from.metadata().is_empty()) {
812 (false, false) => {
813 let mut merged = self.metadata().clone();
814 for (key, from_value) in from.metadata() {
815 if let Some(self_value) = self.metadata.get(key) {
816 if self_value != from_value {
817 return Err(ArrowError::SchemaError(format!(
818 "Fail to merge field '{}' due to conflicting metadata data value for key {}.
819 From value = {} does not match {}", self.name, key, from_value, self_value),
820 ));
821 }
822 } else {
823 merged.insert(key.clone(), from_value.clone());
824 }
825 }
826 self.set_metadata(merged);
827 }
828 (true, false) => {
829 self.set_metadata(from.metadata().clone());
830 }
831 _ => {}
832 }
833 match &mut self.data_type {
834 DataType::Struct(nested_fields) => match &from.data_type {
835 DataType::Struct(from_nested_fields) => {
836 let mut builder = SchemaBuilder::new();
837 nested_fields
838 .iter()
839 .chain(from_nested_fields)
840 .try_for_each(|f| builder.try_merge(f))?;
841 *nested_fields = builder.finish().fields;
842 }
843 DataType::Null => {
844 self.nullable = true;
845 }
846 _ => {
847 return Err(ArrowError::SchemaError(format!(
848 "Fail to merge schema field '{}' because the from data_type = {} is not DataType::Struct",
849 self.name, from.data_type
850 )));
851 }
852 },
853 DataType::Union(nested_fields, _) => match &from.data_type {
854 DataType::Union(from_nested_fields, _) => {
855 nested_fields.try_merge(from_nested_fields)?
856 }
857 DataType::Null => {
858 self.nullable = true;
859 }
860 _ => {
861 return Err(ArrowError::SchemaError(format!(
862 "Fail to merge schema field '{}' because the from data_type = {} is not DataType::Union",
863 self.name, from.data_type
864 )));
865 }
866 },
867 DataType::List(field) => match &from.data_type {
868 DataType::List(from_field) => {
869 let mut f = (**field).clone();
870 f.try_merge(from_field)?;
871 (*field) = Arc::new(f);
872 }
873 DataType::Null => {
874 self.nullable = true;
875 }
876 _ => {
877 return Err(ArrowError::SchemaError(format!(
878 "Fail to merge schema field '{}' because the from data_type = {} is not DataType::List",
879 self.name, from.data_type
880 )));
881 }
882 },
883 DataType::LargeList(field) => match &from.data_type {
884 DataType::LargeList(from_field) => {
885 let mut f = (**field).clone();
886 f.try_merge(from_field)?;
887 (*field) = Arc::new(f);
888 }
889 DataType::Null => {
890 self.nullable = true;
891 }
892 _ => {
893 return Err(ArrowError::SchemaError(format!(
894 "Fail to merge schema field '{}' because the from data_type = {} is not DataType::LargeList",
895 self.name, from.data_type
896 )));
897 }
898 },
899 DataType::Null => {
900 self.nullable = true;
901 self.data_type = from.data_type.clone();
902 }
903 DataType::Boolean
904 | DataType::Int8
905 | DataType::Int16
906 | DataType::Int32
907 | DataType::Int64
908 | DataType::UInt8
909 | DataType::UInt16
910 | DataType::UInt32
911 | DataType::UInt64
912 | DataType::Float16
913 | DataType::Float32
914 | DataType::Float64
915 | DataType::Timestamp(_, _)
916 | DataType::Date32
917 | DataType::Date64
918 | DataType::Time32(_)
919 | DataType::Time64(_)
920 | DataType::Duration(_)
921 | DataType::Binary
922 | DataType::LargeBinary
923 | DataType::BinaryView
924 | DataType::Interval(_)
925 | DataType::LargeListView(_)
926 | DataType::ListView(_)
927 | DataType::Map(_, _)
928 | DataType::Dictionary(_, _)
929 | DataType::RunEndEncoded(_, _)
930 | DataType::FixedSizeList(_, _)
931 | DataType::FixedSizeBinary(_)
932 | DataType::Utf8
933 | DataType::LargeUtf8
934 | DataType::Utf8View
935 | DataType::Decimal32(_, _)
936 | DataType::Decimal64(_, _)
937 | DataType::Decimal128(_, _)
938 | DataType::Decimal256(_, _) => {
939 if from.data_type == DataType::Null {
940 self.nullable = true;
941 } else if self.data_type != from.data_type {
942 return Err(ArrowError::SchemaError(format!(
943 "Fail to merge schema field '{}' because the from data_type = {} does not equal {}",
944 self.name, from.data_type, self.data_type
945 )));
946 }
947 }
948 }
949 self.nullable |= from.nullable;
950
951 Ok(())
952 }
953
954 pub fn contains(&self, other: &Field) -> bool {
960 self.name == other.name
961 && self.data_type.contains(&other.data_type)
962 && self.dict_is_ordered == other.dict_is_ordered
963 && (self.nullable || !other.nullable)
965 && other.metadata.iter().all(|(k, v1)| {
967 self.metadata.get(k).map(|v2| v1 == v2).unwrap_or_default()
968 })
969 }
970
971 pub fn size(&self) -> usize {
975 std::mem::size_of_val(self) - std::mem::size_of_val(&self.data_type)
976 + self.data_type.size()
977 + self.name.capacity()
978 + (std::mem::size_of::<(String, String)>() * self.metadata.capacity())
979 + self
980 .metadata
981 .iter()
982 .map(|(k, v)| k.capacity() + v.capacity())
983 .sum::<usize>()
984 }
985}
986
987impl std::fmt::Display for Field {
988 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
989 #![expect(deprecated)] let Self {
991 name,
992 data_type,
993 nullable,
994 dict_id,
995 dict_is_ordered,
996 metadata,
997 } = self;
998 let maybe_nullable = if *nullable { "nullable " } else { "" };
999 let metadata_str = if metadata.is_empty() {
1000 String::new()
1001 } else {
1002 format!(", metadata: {metadata:?}")
1003 };
1004 let dict_id_str = if dict_id == &0 {
1005 String::new()
1006 } else {
1007 format!(", dict_id: {dict_id}")
1008 };
1009 let dict_is_ordered_str = if *dict_is_ordered {
1010 ", dict_is_ordered"
1011 } else {
1012 ""
1013 };
1014 write!(
1015 f,
1016 "Field {{ {name:?}: {maybe_nullable}{data_type}{dict_id_str}{dict_is_ordered_str}{metadata_str} }}"
1017 )
1018 }
1019}
1020
1021#[cfg(test)]
1022mod test {
1023 use super::*;
1024 use std::collections::hash_map::DefaultHasher;
1025
1026 #[derive(Debug, Clone, Copy)]
1027 struct TestExtensionType;
1028
1029 impl ExtensionType for TestExtensionType {
1030 const NAME: &'static str = "test.extension";
1031 type Metadata = ();
1032
1033 fn metadata(&self) -> &Self::Metadata {
1034 &()
1035 }
1036
1037 fn serialize_metadata(&self) -> Option<String> {
1038 None
1039 }
1040
1041 fn deserialize_metadata(metadata: Option<&str>) -> Result<Self::Metadata, ArrowError> {
1042 metadata.map_or(Ok(()), |_| {
1043 Err(ArrowError::InvalidArgumentError(
1044 "TestExtensionType expects no metadata".to_owned(),
1045 ))
1046 })
1047 }
1048
1049 fn supports_data_type(&self, _data_type: &DataType) -> Result<(), ArrowError> {
1050 Ok(())
1051 }
1052
1053 fn try_new(_data_type: &DataType, _metadata: Self::Metadata) -> Result<Self, ArrowError> {
1054 Ok(Self)
1055 }
1056 }
1057
1058 #[test]
1059 fn test_has_valid_extension_type() {
1060 let no_extension = Field::new("f", DataType::Null, false);
1061 assert!(!no_extension.has_valid_extension_type::<TestExtensionType>());
1062
1063 let matching_name = Field::new("f", DataType::Null, false).with_metadata(
1064 [(
1065 EXTENSION_TYPE_NAME_KEY.to_owned(),
1066 TestExtensionType::NAME.to_owned(),
1067 )]
1068 .into_iter()
1069 .collect(),
1070 );
1071 assert!(matching_name.has_valid_extension_type::<TestExtensionType>());
1072
1073 let matching_name_with_invalid_metadata = Field::new("f", DataType::Null, false)
1074 .with_metadata(
1075 [
1076 (
1077 EXTENSION_TYPE_NAME_KEY.to_owned(),
1078 TestExtensionType::NAME.to_owned(),
1079 ),
1080 (EXTENSION_TYPE_METADATA_KEY.to_owned(), "invalid".to_owned()),
1081 ]
1082 .into_iter()
1083 .collect(),
1084 );
1085 assert!(
1086 !matching_name_with_invalid_metadata.has_valid_extension_type::<TestExtensionType>()
1087 );
1088
1089 let different_name = Field::new("f", DataType::Null, false).with_metadata(
1090 [(
1091 EXTENSION_TYPE_NAME_KEY.to_owned(),
1092 "some.other_extension".to_owned(),
1093 )]
1094 .into_iter()
1095 .collect(),
1096 );
1097 assert!(!different_name.has_valid_extension_type::<TestExtensionType>());
1098 }
1099
1100 #[test]
1101 fn test_new_with_string() {
1102 let s = "c1";
1104 Field::new(s, DataType::Int64, false);
1105 }
1106
1107 #[test]
1108 fn test_new_dict_with_string() {
1109 let s = "c1";
1111 #[allow(deprecated)]
1112 Field::new_dict(s, DataType::Int64, false, 4, false);
1113 }
1114
1115 #[test]
1116 #[cfg_attr(miri, ignore)] fn test_debug_format_field() {
1118 insta::assert_debug_snapshot!(Field::new("item", DataType::UInt8, false), @r"
1120 Field {
1121 data_type: UInt8,
1122 }
1123 ");
1124 insta::assert_debug_snapshot!(Field::new("column", DataType::LargeUtf8, true), @r#"
1125 Field {
1126 name: "column",
1127 data_type: LargeUtf8,
1128 nullable: true,
1129 }
1130 "#);
1131 }
1132
1133 #[test]
1134 fn test_merge_incompatible_types() {
1135 let mut field = Field::new("c1", DataType::Int64, false);
1136 let result = field
1137 .try_merge(&Field::new("c1", DataType::Float32, true))
1138 .expect_err("should fail")
1139 .to_string();
1140 assert_eq!(
1141 "Schema error: Fail to merge schema field 'c1' because the from data_type = Float32 does not equal Int64",
1142 result
1143 );
1144 }
1145
1146 #[test]
1147 fn test_merge_with_null() {
1148 let mut field1 = Field::new("c1", DataType::Null, true);
1149 field1
1150 .try_merge(&Field::new("c1", DataType::Float32, false))
1151 .expect("should widen type to nullable float");
1152 assert_eq!(Field::new("c1", DataType::Float32, true), field1);
1153
1154 let mut field2 = Field::new("c2", DataType::Utf8, false);
1155 field2
1156 .try_merge(&Field::new("c2", DataType::Null, true))
1157 .expect("should widen type to nullable utf8");
1158 assert_eq!(Field::new("c2", DataType::Utf8, true), field2);
1159 }
1160
1161 #[test]
1162 fn test_merge_with_nested_null() {
1163 let mut struct1 = Field::new(
1164 "s1",
1165 DataType::Struct(Fields::from(vec![Field::new(
1166 "inner",
1167 DataType::Float32,
1168 false,
1169 )])),
1170 false,
1171 );
1172
1173 let struct2 = Field::new(
1174 "s2",
1175 DataType::Struct(Fields::from(vec![Field::new(
1176 "inner",
1177 DataType::Null,
1178 false,
1179 )])),
1180 true,
1181 );
1182
1183 struct1
1184 .try_merge(&struct2)
1185 .expect("should widen inner field's type to nullable float");
1186 assert_eq!(
1187 Field::new(
1188 "s1",
1189 DataType::Struct(Fields::from(vec![Field::new(
1190 "inner",
1191 DataType::Float32,
1192 true,
1193 )])),
1194 true,
1195 ),
1196 struct1
1197 );
1198
1199 let mut list1 = Field::new(
1200 "l1",
1201 DataType::List(Field::new("inner", DataType::Float32, false).into()),
1202 false,
1203 );
1204
1205 let list2 = Field::new(
1206 "l2",
1207 DataType::List(Field::new("inner", DataType::Null, false).into()),
1208 true,
1209 );
1210
1211 list1
1212 .try_merge(&list2)
1213 .expect("should widen inner field's type to nullable float");
1214 assert_eq!(
1215 Field::new(
1216 "l1",
1217 DataType::List(Field::new("inner", DataType::Float32, true).into()),
1218 true,
1219 ),
1220 list1
1221 );
1222
1223 let mut large_list1 = Field::new(
1224 "ll1",
1225 DataType::LargeList(Field::new("inner", DataType::Float32, false).into()),
1226 false,
1227 );
1228
1229 let large_list2 = Field::new(
1230 "ll2",
1231 DataType::LargeList(Field::new("inner", DataType::Null, false).into()),
1232 true,
1233 );
1234
1235 large_list1
1236 .try_merge(&large_list2)
1237 .expect("should widen inner field's type to nullable float");
1238 assert_eq!(
1239 Field::new(
1240 "ll1",
1241 DataType::LargeList(Field::new("inner", DataType::Float32, true).into()),
1242 true,
1243 ),
1244 large_list1
1245 );
1246 }
1247
1248 #[test]
1249 fn test_fields_with_dict_id() {
1250 #[allow(deprecated)]
1251 let dict1 = Field::new_dict(
1252 "dict1",
1253 DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1254 false,
1255 10,
1256 false,
1257 );
1258 #[allow(deprecated)]
1259 let dict2 = Field::new_dict(
1260 "dict2",
1261 DataType::Dictionary(DataType::Int32.into(), DataType::Int8.into()),
1262 false,
1263 20,
1264 false,
1265 );
1266
1267 let field = Field::new(
1268 "struct<dict1, list[struct<dict2, list[struct<dict1]>]>",
1269 DataType::Struct(Fields::from(vec![
1270 dict1.clone(),
1271 Field::new(
1272 "list[struct<dict1, list[struct<dict2>]>]",
1273 DataType::List(Arc::new(Field::new(
1274 "struct<dict1, list[struct<dict2>]>",
1275 DataType::Struct(Fields::from(vec![
1276 dict1.clone(),
1277 Field::new(
1278 "list[struct<dict2>]",
1279 DataType::List(Arc::new(Field::new(
1280 "struct<dict2>",
1281 DataType::Struct(vec![dict2.clone()].into()),
1282 false,
1283 ))),
1284 false,
1285 ),
1286 ])),
1287 false,
1288 ))),
1289 false,
1290 ),
1291 ])),
1292 false,
1293 );
1294
1295 #[allow(deprecated)]
1296 for field in field.fields_with_dict_id(10) {
1297 assert_eq!(dict1, *field);
1298 }
1299 #[allow(deprecated)]
1300 for field in field.fields_with_dict_id(20) {
1301 assert_eq!(dict2, *field);
1302 }
1303 }
1304
1305 fn get_field_hash(field: &Field) -> u64 {
1306 let mut s = DefaultHasher::new();
1307 field.hash(&mut s);
1308 s.finish()
1309 }
1310
1311 #[test]
1312 fn test_field_comparison_case() {
1313 #[allow(deprecated)]
1315 let dict1 = Field::new_dict(
1316 "dict1",
1317 DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1318 false,
1319 10,
1320 false,
1321 );
1322 #[allow(deprecated)]
1323 let dict2 = Field::new_dict(
1324 "dict1",
1325 DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1326 false,
1327 20,
1328 false,
1329 );
1330
1331 assert_eq!(dict1, dict2);
1332 assert_eq!(get_field_hash(&dict1), get_field_hash(&dict2));
1333
1334 #[allow(deprecated)]
1335 let dict1 = Field::new_dict(
1336 "dict0",
1337 DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1338 false,
1339 10,
1340 false,
1341 );
1342
1343 assert_ne!(dict1, dict2);
1344 assert_ne!(get_field_hash(&dict1), get_field_hash(&dict2));
1345 }
1346
1347 #[test]
1348 fn test_field_comparison_metadata() {
1349 let f1 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1350 (String::from("k1"), String::from("v1")),
1351 (String::from("k2"), String::from("v2")),
1352 ]));
1353 let f2 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1354 (String::from("k1"), String::from("v1")),
1355 (String::from("k3"), String::from("v3")),
1356 ]));
1357 let f3 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1358 (String::from("k1"), String::from("v1")),
1359 (String::from("k3"), String::from("v4")),
1360 ]));
1361
1362 assert!(f1.cmp(&f2).is_lt());
1363 assert!(f2.cmp(&f3).is_lt());
1364 assert!(f1.cmp(&f3).is_lt());
1365 }
1366
1367 #[test]
1368 #[expect(clippy::needless_borrows_for_generic_args)] fn test_field_as_ref() {
1370 let field = || Field::new("x", DataType::Binary, false);
1371
1372 fn accept_ref(_: impl AsRef<Field>) {}
1375
1376 accept_ref(field());
1377 accept_ref(&field());
1378 accept_ref(&&field());
1379 accept_ref(Arc::new(field()));
1380 accept_ref(&Arc::new(field()));
1381 accept_ref(&&Arc::new(field()));
1382
1383 fn accept_refs(_: impl IntoIterator<Item: AsRef<Field>>) {}
1386
1387 accept_refs(vec![field()]);
1388 accept_refs(vec![&field()]);
1389 accept_refs(vec![Arc::new(field())]);
1390 accept_refs(vec![&Arc::new(field())]);
1391 accept_refs(&vec![field()]);
1392 accept_refs(&vec![&field()]);
1393 accept_refs(&vec![Arc::new(field())]);
1394 accept_refs(&vec![&Arc::new(field())]);
1395 }
1396
1397 #[test]
1398 fn test_contains_reflexivity() {
1399 let mut field = Field::new("field1", DataType::Float16, false);
1400 field.set_metadata(HashMap::from([
1401 (String::from("k0"), String::from("v0")),
1402 (String::from("k1"), String::from("v1")),
1403 ]));
1404 assert!(field.contains(&field))
1405 }
1406
1407 #[test]
1408 fn test_contains_transitivity() {
1409 let child_field = Field::new("child1", DataType::Float16, false);
1410
1411 let mut field1 = Field::new(
1412 "field1",
1413 DataType::Struct(Fields::from(vec![child_field])),
1414 false,
1415 );
1416 field1.set_metadata(HashMap::from([(String::from("k1"), String::from("v1"))]));
1417
1418 let mut field2 = Field::new("field1", DataType::Struct(Fields::default()), true);
1419 field2.set_metadata(HashMap::from([(String::from("k2"), String::from("v2"))]));
1420 field2.try_merge(&field1).unwrap();
1421
1422 let mut field3 = Field::new("field1", DataType::Struct(Fields::default()), false);
1423 field3.set_metadata(HashMap::from([(String::from("k3"), String::from("v3"))]));
1424 field3.try_merge(&field2).unwrap();
1425
1426 assert!(field2.contains(&field1));
1427 assert!(field3.contains(&field2));
1428 assert!(field3.contains(&field1));
1429
1430 assert!(!field1.contains(&field2));
1431 assert!(!field1.contains(&field3));
1432 assert!(!field2.contains(&field3));
1433 }
1434
1435 #[test]
1436 fn test_contains_nullable() {
1437 let field1 = Field::new("field1", DataType::Boolean, true);
1438 let field2 = Field::new("field1", DataType::Boolean, false);
1439 assert!(field1.contains(&field2));
1440 assert!(!field2.contains(&field1));
1441 }
1442
1443 #[test]
1444 fn test_contains_must_have_same_fields() {
1445 let child_field1 = Field::new("child1", DataType::Float16, false);
1446 let child_field2 = Field::new("child2", DataType::Float16, false);
1447
1448 let field1 = Field::new(
1449 "field1",
1450 DataType::Struct(vec![child_field1.clone()].into()),
1451 true,
1452 );
1453 let field2 = Field::new(
1454 "field1",
1455 DataType::Struct(vec![child_field1, child_field2].into()),
1456 true,
1457 );
1458
1459 assert!(!field1.contains(&field2));
1460 assert!(!field2.contains(&field1));
1461
1462 let field1 = Field::new(
1464 "field1",
1465 DataType::Union(
1466 UnionFields::try_new(
1467 vec![1, 2],
1468 vec![
1469 Field::new("field1", DataType::UInt8, true),
1470 Field::new("field3", DataType::Utf8, false),
1471 ],
1472 )
1473 .unwrap(),
1474 UnionMode::Dense,
1475 ),
1476 true,
1477 );
1478 let field2 = Field::new(
1479 "field1",
1480 DataType::Union(
1481 UnionFields::try_new(
1482 vec![1, 3],
1483 vec![
1484 Field::new("field1", DataType::UInt8, false),
1485 Field::new("field3", DataType::Utf8, false),
1486 ],
1487 )
1488 .unwrap(),
1489 UnionMode::Dense,
1490 ),
1491 true,
1492 );
1493 assert!(!field1.contains(&field2));
1494
1495 let field1 = Field::new(
1497 "field1",
1498 DataType::Union(
1499 UnionFields::try_new(
1500 vec![1, 2],
1501 vec![
1502 Field::new("field1", DataType::UInt8, true),
1503 Field::new("field3", DataType::Utf8, false),
1504 ],
1505 )
1506 .unwrap(),
1507 UnionMode::Dense,
1508 ),
1509 true,
1510 );
1511 let field2 = Field::new(
1512 "field1",
1513 DataType::Union(
1514 UnionFields::try_new(
1515 vec![1, 2],
1516 vec![
1517 Field::new("field1", DataType::UInt8, false),
1518 Field::new("field3", DataType::Utf8, false),
1519 ],
1520 )
1521 .unwrap(),
1522 UnionMode::Dense,
1523 ),
1524 true,
1525 );
1526 assert!(field1.contains(&field2));
1527 }
1528
1529 #[cfg(feature = "serde")]
1530 fn assert_binary_serde_round_trip(field: Field) {
1531 let serialized = postcard::to_stdvec(&field).unwrap();
1532 let deserialized: Field = postcard::from_bytes(&serialized).unwrap();
1533 assert_eq!(field, deserialized)
1534 }
1535
1536 #[cfg(feature = "serde")]
1537 #[test]
1538 fn test_field_without_metadata_serde() {
1539 let field = Field::new("name", DataType::Boolean, true);
1540 assert_binary_serde_round_trip(field)
1541 }
1542
1543 #[cfg(feature = "serde")]
1544 #[test]
1545 fn test_field_with_empty_metadata_serde() {
1546 let field = Field::new("name", DataType::Boolean, false).with_metadata(HashMap::new());
1547
1548 assert_binary_serde_round_trip(field)
1549 }
1550
1551 #[cfg(feature = "serde")]
1552 #[test]
1553 fn test_field_with_nonempty_metadata_serde() {
1554 let mut metadata = HashMap::new();
1555 metadata.insert("hi".to_owned(), "".to_owned());
1556 let field = Field::new("name", DataType::Boolean, false).with_metadata(metadata);
1557
1558 assert_binary_serde_round_trip(field)
1559 }
1560
1561 #[test]
1562 fn test_merge_compound_with_null() {
1563 let mut field = Field::new(
1565 "s",
1566 DataType::Struct(Fields::from(vec![Field::new("a", DataType::Int32, false)])),
1567 false,
1568 );
1569 field
1570 .try_merge(&Field::new("s", DataType::Null, true))
1571 .expect("Struct should merge with Null");
1572 assert!(field.is_nullable());
1573 assert!(matches!(field.data_type(), DataType::Struct(_)));
1574
1575 let mut field = Field::new(
1577 "l",
1578 DataType::List(Field::new("item", DataType::Utf8, false).into()),
1579 false,
1580 );
1581 field
1582 .try_merge(&Field::new("l", DataType::Null, true))
1583 .expect("List should merge with Null");
1584 assert!(field.is_nullable());
1585 assert!(matches!(field.data_type(), DataType::List(_)));
1586
1587 let mut field = Field::new(
1589 "ll",
1590 DataType::LargeList(Field::new("item", DataType::Utf8, false).into()),
1591 false,
1592 );
1593 field
1594 .try_merge(&Field::new("ll", DataType::Null, true))
1595 .expect("LargeList should merge with Null");
1596 assert!(field.is_nullable());
1597 assert!(matches!(field.data_type(), DataType::LargeList(_)));
1598
1599 let mut field = Field::new(
1601 "u",
1602 DataType::Union(
1603 UnionFields::try_new(vec![0], vec![Field::new("f", DataType::Int32, false)])
1604 .unwrap(),
1605 UnionMode::Dense,
1606 ),
1607 false,
1608 );
1609 field
1610 .try_merge(&Field::new("u", DataType::Null, true))
1611 .expect("Union should merge with Null");
1612 assert!(matches!(field.data_type(), DataType::Union(_, _)));
1613 }
1614}