delta_kernel/schema/
derive_macro_utils.rs1use std::collections::{HashMap, HashSet};
5
6use bytes::Bytes;
7use delta_kernel_derive::internal_api;
8
9use crate::error::add_scalar_path_context;
10use crate::expressions::{Scalar, StructData};
11use crate::schema::{ArrayType, DataType, MapType, StructField, StructType, ToSchema};
12use crate::utils::require;
13use crate::{DeltaResult, Error};
14
15#[internal_api]
28pub(crate) trait ToDataType {
29 fn to_data_type() -> DataType;
30}
31
32impl<T: ToSchema> ToDataType for T {
34 fn to_data_type() -> DataType {
35 T::to_schema().into()
36 }
37}
38
39macro_rules! impl_to_data_type {
41 ( $(($rust_type: ty, $data_type: expr)), * ) => {
42 $(
43 impl ToDataType for $rust_type {
44 fn to_data_type() -> DataType {
45 $data_type
46 }
47 }
48 )*
49 };
50}
51
52impl_to_data_type!(
53 (String, DataType::STRING),
54 (Bytes, DataType::BINARY),
55 (i64, DataType::LONG),
56 (i32, DataType::INTEGER),
57 (i16, DataType::SHORT),
58 (i8, DataType::BYTE),
59 (f32, DataType::FLOAT),
60 (f64, DataType::DOUBLE),
61 (bool, DataType::BOOLEAN)
62);
63
64impl<T: ToDataType> ToDataType for Vec<T> {
66 fn to_data_type() -> DataType {
67 ArrayType::new(T::to_data_type(), false).into()
68 }
69}
70
71impl<T: ToDataType> ToDataType for Vec<Option<T>> {
73 fn to_data_type() -> DataType {
74 ArrayType::new(T::to_data_type(), true).into()
75 }
76}
77
78impl<T: ToDataType> ToDataType for HashSet<T> {
80 fn to_data_type() -> DataType {
81 ArrayType::new(T::to_data_type(), false).into()
82 }
83}
84
85impl<K: ToDataType, V: ToDataType> ToDataType for HashMap<K, V> {
87 fn to_data_type() -> DataType {
88 MapType::new(K::to_data_type(), V::to_data_type(), false).into()
89 }
90}
91
92impl<K: ToDataType, V: ToDataType> ToDataType for HashMap<K, Option<V>> {
94 fn to_data_type() -> DataType {
95 MapType::new(K::to_data_type(), V::to_data_type(), true).into()
96 }
97}
98
99#[internal_api]
103pub(crate) trait GetStructField {
104 fn get_struct_field(name: impl Into<String>) -> StructField;
105}
106
107impl<T: ToDataType> GetStructField for T {
109 fn get_struct_field(name: impl Into<String>) -> StructField {
110 StructField::not_null(name, T::to_data_type())
111 }
112}
113
114impl<T: ToDataType> GetStructField for Option<T> {
116 fn get_struct_field(name: impl Into<String>) -> StructField {
117 StructField::nullable(name, T::to_data_type())
118 }
119}
120
121pub(crate) trait ToNullableContainerType {
125 fn to_nullable_container_type() -> DataType;
126}
127
128impl<K: ToDataType, V: ToDataType> ToNullableContainerType for HashMap<K, V> {
130 fn to_nullable_container_type() -> DataType {
131 MapType::new(K::to_data_type(), V::to_data_type(), true).into()
132 }
133}
134
135#[internal_api]
139pub(crate) trait GetNullableContainerStructField {
140 fn get_nullable_container_struct_field(name: impl Into<String>) -> StructField;
141}
142
143impl<T: ToNullableContainerType> GetNullableContainerStructField for T {
145 fn get_nullable_container_struct_field(name: impl Into<String>) -> StructField {
146 StructField::not_null(name, T::to_nullable_container_type())
147 }
148}
149
150impl<T: ToNullableContainerType> GetNullableContainerStructField for Option<T> {
152 fn get_nullable_container_struct_field(name: impl Into<String>) -> StructField {
153 StructField::nullable(name, T::to_nullable_container_type())
154 }
155}
156
157#[internal_api]
162pub(crate) struct StructDataFields {
163 expected: StructType,
164 fields: HashMap<String, (StructField, Scalar)>,
165}
166
167impl StructDataFields {
168 pub(crate) fn try_new(data: StructData, expected: StructType) -> DeltaResult<Self> {
169 let (actual_fields, values) = data.into_parts();
170 require!(
171 actual_fields.len() == values.len(),
172 Error::scalar_conversion(
173 format!("{} struct values", actual_fields.len()),
174 format!("{} struct values", values.len()),
175 )
176 );
177 require!(
178 actual_fields.len() == expected.num_fields(),
179 Error::scalar_conversion(
180 format!("struct with {} fields", expected.num_fields()),
181 format!("struct with {} fields", actual_fields.len()),
182 )
183 );
184 let mut fields = HashMap::with_capacity(actual_fields.len());
185 for (field, value) in actual_fields.into_iter().zip(values) {
186 let name = field.name().clone();
187 match fields.entry(name) {
188 std::collections::hash_map::Entry::Vacant(entry) => {
189 entry.insert((field, value));
190 }
191 std::collections::hash_map::Entry::Occupied(entry) => {
192 return Err(add_scalar_path_context(
193 Error::scalar_conversion("one field", "duplicate fields"),
194 entry.key().clone(),
195 ));
196 }
197 }
198 }
199 Ok(Self { expected, fields })
200 }
201
202 pub(crate) fn take_field<T: TryFrom<Scalar, Error = Error>>(
203 &mut self,
204 field_name: &str,
205 ) -> DeltaResult<T> {
206 let expected = self.expected.field(field_name).ok_or_else(|| {
207 Error::InternalError(format!(
208 "Derived schema does not contain generated field {field_name:?}"
209 ))
210 })?;
211 let (actual_field, value) = self.fields.remove(field_name).ok_or_else(|| {
212 add_scalar_path_context(
213 Error::scalar_conversion("present field", "missing field"),
214 field_name,
215 )
216 })?;
217 require!(
218 actual_field.is_nullable() == expected.is_nullable(),
219 add_scalar_path_context(
220 Error::scalar_conversion(
221 if expected.is_nullable() {
222 "nullable field"
223 } else {
224 "non-nullable field"
225 },
226 if actual_field.is_nullable() {
227 "nullable field"
228 } else {
229 "non-nullable field"
230 },
231 ),
232 field_name,
233 )
234 );
235
236 T::try_from(value).map_err(|error| add_scalar_path_context(error, field_name))
237 }
238
239 pub(crate) fn finish(self) -> DeltaResult<()> {
241 if self.fields.is_empty() {
242 return Ok(());
243 }
244 let mut extra: Vec<_> = self.fields.keys().collect();
245 extra.sort_unstable();
246 Err(Error::scalar_conversion(
247 "no additional fields",
248 format!("fields {extra:?}"),
249 ))
250 }
251}