15
15
//! StructField::new("value", DataType::STRING, true),
16
16
//! StructField::new("year", DataType::INTEGER, true),
17
17
//! ]);
18
- //! // Schemas are compatible since the `year` value is nullable
18
+ //! // Schemas are compatible since the `read_schema` adds a nullable column `year`
19
19
//! assert!(schema.can_read_as(&read_schema).is_ok());
20
20
//! ````
21
21
//!
@@ -26,6 +26,12 @@ use crate::utils::require;
26
26
27
27
use super :: { DataType , StructField , StructType } ;
28
28
29
+ /// The nullability flag of a schema's field. This can be compared with a read schema field's
30
+ /// nullability flag using [`Nullable::can_read_as`].
31
+ #[ allow( unused) ]
32
+ #[ derive( Clone , Copy ) ]
33
+ pub ( crate ) struct Nullable ( bool ) ;
34
+
29
35
/// Represents the ways a schema comparison can fail.
30
36
#[ derive( Debug , thiserror:: Error ) ]
31
37
pub ( crate ) enum Error {
@@ -49,20 +55,17 @@ pub(crate) type SchemaComparisonResult = Result<(), Error>;
49
55
50
56
/// Represents a schema compatibility check for the type. If `self` can be read as `read_type`,
51
57
/// this function returns `Ok(())`. Otherwise, this function returns `Err`.
58
+ ///
59
+ /// TODO (Oussama): Remove the `allow(unsued)` once this is used in CDF.
52
60
#[ allow( unused) ]
53
61
pub ( crate ) trait SchemaComparison {
54
62
fn can_read_as ( & self , read_type : & Self ) -> SchemaComparisonResult ;
55
63
}
56
64
57
- /// The nullability flag of a schema's field. This can be compared with a read schema field's
58
- /// nullability flag using [`NullabilityFlag::can_read_as`].
59
- #[ allow( unused) ]
60
- pub ( crate ) struct NullabilityFlag ( bool ) ;
61
-
62
- impl SchemaComparison for NullabilityFlag {
65
+ impl SchemaComparison for Nullable {
63
66
/// Represents a nullability comparison between two schemas' fields. Returns true if the
64
67
/// read nullability is the same or wider than the nullability of self.
65
- fn can_read_as ( & self , read_nullable : & NullabilityFlag ) -> SchemaComparisonResult {
68
+ fn can_read_as ( & self , read_nullable : & Nullable ) -> SchemaComparisonResult {
66
69
// The case to avoid is when the column is nullable, but the read schema specifies the
67
70
// column as non-nullable. So we avoid the case where !read_nullable && nullable
68
71
// Hence we check that !(!read_nullable && existing_nullable)
@@ -79,7 +82,7 @@ impl SchemaComparison for StructField {
79
82
/// 2. The both this field and `read_field` must have the same name.
80
83
/// 3. You can read this data type as the `read_field`'s data type.
81
84
fn can_read_as ( & self , read_field : & Self ) -> SchemaComparisonResult {
82
- NullabilityFlag ( self . nullable ) . can_read_as ( & NullabilityFlag ( read_field. nullable ) ) ?;
85
+ Nullable ( self . nullable ) . can_read_as ( & Nullable ( read_field. nullable ) ) ?;
83
86
require ! ( self . name( ) == read_field. name( ) , Error :: FieldNameMismatch ) ;
84
87
self . data_type ( ) . can_read_as ( read_field. data_type ( ) ) ?;
85
88
Ok ( ( ) )
@@ -113,18 +116,18 @@ impl SchemaComparison for StructType {
113
116
) ;
114
117
115
118
// Check that the field names are a subset of the read fields.
116
- if ! lowercase_field_map
119
+ if lowercase_field_map
117
120
. keys ( )
118
- . all ( |name| lowercase_read_field_names. contains ( name) )
121
+ . any ( |name| ! lowercase_read_field_names. contains ( name) )
119
122
{
120
123
return Err ( Error :: MissingColumn ) ;
121
124
}
122
125
for read_field in read_type. fields ( ) {
123
126
match lowercase_field_map. get ( & read_field. name ( ) . to_lowercase ( ) ) {
124
127
Some ( existing_field) => existing_field. can_read_as ( read_field) ?,
125
128
None => {
126
- // Note: Delta spark does not perform the following check. Hence it ignores fields
127
- // that exist in the read schema that aren't in this schema.
129
+ // Note: Delta spark does not perform the following check. Hence it ignores
130
+ // non-null fields that exist in the read schema that aren't in this schema.
128
131
require ! ( read_field. is_nullable( ) , Error :: NewNonNullableColumn ) ;
129
132
}
130
133
}
@@ -139,14 +142,14 @@ impl SchemaComparison for DataType {
139
142
/// compatible data types with type widening. See issue [`#623`]
140
143
/// 2. For complex data types, the nested types must be compatible as defined by [`SchemaComparison`]
141
144
/// 3. For array data types, the nullability may not be tightened in the `read_type`. See
142
- /// [`NullabilityFlag ::can_read_as`]
145
+ /// [`Nullable ::can_read_as`]
143
146
///
144
147
/// [`#623`]: <https://github.com/delta-io/delta-kernel-rs/issues/623>
145
148
fn can_read_as ( & self , read_type : & Self ) -> SchemaComparisonResult {
146
149
match ( self , read_type) {
147
150
( Self :: Array ( self_array) , Self :: Array ( read_array) ) => {
148
- NullabilityFlag ( self_array. contains_null ( ) )
149
- . can_read_as ( & NullabilityFlag ( read_array. contains_null ( ) ) ) ?;
151
+ Nullable ( self_array. contains_null ( ) )
152
+ . can_read_as ( & Nullable ( read_array. contains_null ( ) ) ) ?;
150
153
self_array
151
154
. element_type ( )
152
155
. can_read_as ( read_array. element_type ( ) ) ?;
@@ -155,8 +158,8 @@ impl SchemaComparison for DataType {
155
158
self_struct. can_read_as ( read_struct) ?
156
159
}
157
160
( Self :: Map ( self_map) , Self :: Map ( read_map) ) => {
158
- NullabilityFlag ( self_map. value_contains_null ( ) )
159
- . can_read_as ( & NullabilityFlag ( read_map. value_contains_null ( ) ) ) ?;
161
+ Nullable ( self_map. value_contains_null ( ) )
162
+ . can_read_as ( & Nullable ( read_map. value_contains_null ( ) ) ) ?;
160
163
self_map. key_type ( ) . can_read_as ( read_map. key_type ( ) ) ?;
161
164
self_map. value_type ( ) . can_read_as ( read_map. value_type ( ) ) ?;
162
165
}
@@ -172,7 +175,7 @@ impl SchemaComparison for DataType {
172
175
173
176
#[ cfg( test) ]
174
177
mod tests {
175
- use crate :: schema:: schema_compare :: { Error , SchemaComparison } ;
178
+ use crate :: schema:: compare :: { Error , SchemaComparison } ;
176
179
use crate :: schema:: { ArrayType , DataType , MapType , StructField , StructType } ;
177
180
178
181
#[ test]
0 commit comments