1
1
//! The [`LiteralExpressionTransform`] is a [`SchemaTransform`] that transforms a [`Schema`] and an
2
2
//! ordered list of leaf values (scalars) into an [`Expression`] with a literal value for each leaf.
3
3
4
- use std:: borrow:: Cow ;
5
- use std:: ops:: Deref as _;
6
-
7
- use tracing:: debug;
8
-
9
4
use crate :: expressions:: { Expression , Scalar } ;
10
- use crate :: schema:: {
11
- ArrayType , DataType , MapType , PrimitiveType , SchemaTransform , StructField , StructType ,
12
- } ;
13
-
14
- /// [`SchemaTransform`] that will transform a [`Schema`] and an ordered list of leaf values
15
- /// (Scalars) into an Expression with a [`Literal`] expr for each leaf.
16
- #[ derive( Debug ) ]
17
- pub ( crate ) struct LiteralExpressionTransform < ' a , T : Iterator < Item = & ' a Scalar > > {
18
- /// Leaf values to insert in schema order.
19
- scalars : T ,
20
- /// A stack of built Expressions. After visiting children, we pop them off to
21
- /// build the parent container, then push the parent back on.
22
- stack : Vec < Expression > ,
23
- /// Since schema transforms are infallible we keep track of errors here
24
- error : Result < ( ) , Error > ,
25
- }
5
+ use crate :: schema:: { ArrayType , DataType , MapType , PrimitiveType , StructField , StructType } ;
6
+ use crate :: DeltaResult ;
26
7
27
8
/// Any error for [`LiteralExpressionTransform`]
28
9
#[ derive( thiserror:: Error , Debug ) ]
@@ -48,97 +29,71 @@ pub enum Error {
48
29
Unsupported ( String ) ,
49
30
}
50
31
32
+ #[ derive( Debug , Default ) ]
33
+ pub ( crate ) struct LiteralExpressionTransform < ' a , T : Iterator < Item = & ' a Scalar > > {
34
+ /// Leaf values to insert in schema order.
35
+ scalars : T ,
36
+ }
37
+
51
38
impl < ' a , I : Iterator < Item = & ' a Scalar > > LiteralExpressionTransform < ' a , I > {
52
39
pub ( crate ) fn new ( scalars : impl IntoIterator < IntoIter = I > ) -> Self {
53
40
Self {
54
41
scalars : scalars. into_iter ( ) ,
55
- stack : Vec :: new ( ) ,
56
- error : Ok ( ( ) ) ,
57
42
}
58
43
}
59
44
60
- /// return the Expression we just built (or propagate Error). the top of `stack` should be our
61
- /// final Expression
62
- pub ( crate ) fn try_into_expr ( mut self ) -> Result < Expression , Error > {
63
- self . error ?;
45
+ /// Bind the visitor to a StructType and produce an Expression
46
+ pub ( crate ) fn bind ( & mut self , struct_type : & StructType ) -> DeltaResult < Expression > {
47
+ use crate :: schema :: visitor :: visit_struct ;
48
+ let result = visit_struct ( struct_type , self ) ?;
64
49
65
- if let Some ( s) = self . scalars . next ( ) {
66
- return Err ( Error :: ExcessScalars ( s. clone ( ) ) ) ;
50
+ // Check for excess scalars after visiting
51
+ if let Some ( scalar) = self . scalars . next ( ) {
52
+ return Err ( Error :: ExcessScalars ( scalar. clone ( ) ) . into ( ) ) ;
67
53
}
68
54
69
- self . stack . pop ( ) . ok_or ( Error :: EmptyStack )
70
- }
71
-
72
- fn set_error ( & mut self , error : Error ) {
73
- // Only set when the error not yet set
74
- if let Err ( ref existing_error) = self . error {
75
- debug ! ( "Trying to overwrite an existing error: {existing_error:?} with {error:?}" ) ;
76
- } else {
77
- self . error = Err ( error) ;
78
- }
55
+ Ok ( result)
79
56
}
80
- }
81
-
82
- // All leaf types (primitive, array, map) share the same "shape" of transformation logic
83
- macro_rules! transform_leaf {
84
- ( $self: ident, $type_variant: path, $type: ident) => { {
85
- // first always check error to terminate early if possible
86
- $self. error. as_ref( ) . ok( ) ?;
87
57
88
- let Some ( scalar ) = $self . scalars . next ( ) else {
89
- $ self. set_error ( Error :: InsufficientScalars ) ;
90
- return None ;
58
+ fn visit_leaf ( & mut self , schema_type : & DataType ) -> DeltaResult < Expression > {
59
+ let Some ( scalar ) = self . scalars . next ( ) else {
60
+ return Err ( Error :: InsufficientScalars . into ( ) ) ;
91
61
} ;
92
62
93
- // NOTE: Grab a reference here so code below can leverage the blanket impl<T> Deref for &T
94
- let $type_variant( ref scalar_type) = scalar. data_type( ) else {
95
- $self. set_error( Error :: Schema ( format!(
96
- "Mismatched scalar type while creating Expression: expected {}({:?}), got {:?}" ,
97
- stringify!( $type_variant) ,
98
- $type,
63
+ if schema_type. clone ( ) != scalar. data_type ( ) {
64
+ return Err ( Error :: Schema ( format ! (
65
+ "Mismatched scalar type while creating Expression: expected {:?}, got {:?}" ,
66
+ schema_type,
99
67
scalar. data_type( )
100
- ) ) ) ;
101
- return None ;
68
+ ) )
69
+ . into ( ) ) ;
102
70
} ;
103
71
104
- // NOTE: &T and &Box<T> both deref to &T
105
- if scalar_type. deref( ) != $type {
106
- $self. set_error( Error :: Schema ( format!(
107
- "Mismatched scalar type while creating Expression: expected {:?}, got {:?}" ,
108
- $type, scalar_type
109
- ) ) ) ;
110
- return None ;
111
- }
112
-
113
- $self. stack. push( Expression :: Literal ( scalar. clone( ) ) ) ;
114
- None
115
- } } ;
72
+ Ok ( Expression :: Literal ( scalar. clone ( ) ) )
73
+ }
116
74
}
117
75
118
- impl < ' a , T : Iterator < Item = & ' a Scalar > > SchemaTransform < ' a > for LiteralExpressionTransform < ' a , T > {
119
- fn transform_primitive (
120
- & mut self ,
121
- prim_type : & ' a PrimitiveType ,
122
- ) -> Option < Cow < ' a , PrimitiveType > > {
123
- transform_leaf ! ( self , DataType :: Primitive , prim_type)
76
+ impl < ' a , I : Iterator < Item = & ' a Scalar > > delta_kernel:: schema:: visitor:: SchemaVisitor
77
+ for LiteralExpressionTransform < ' a , I >
78
+ {
79
+ type T = Expression ;
80
+
81
+ fn field ( & mut self , field : & StructField , value : Self :: T ) -> DeltaResult < Self :: T > {
82
+ match & field. data_type {
83
+ DataType :: Struct ( _) => Ok ( value) ,
84
+ DataType :: Primitive ( _) => self . visit_leaf ( & field. data_type ) ,
85
+ DataType :: Array ( _) => self . visit_leaf ( & field. data_type ) ,
86
+ DataType :: Map ( _) => self . visit_leaf ( & field. data_type ) ,
87
+ DataType :: Variant ( _) => self . visit_leaf ( & field. data_type ) ,
88
+ }
124
89
}
125
90
126
- fn transform_struct ( & mut self , struct_type : & ' a StructType ) -> Option < Cow < ' a , StructType > > {
127
- // first always check error to terminate early if possible
128
- self . error . as_ref ( ) . ok ( ) ?;
129
-
130
- // Only consume newly-added entries (if any). There could be fewer than expected if
131
- // the recursion encountered an error.
132
- let mark = self . stack . len ( ) ;
133
- self . recurse_into_struct ( struct_type) ?;
134
- let field_exprs = self . stack . split_off ( mark) ;
135
-
91
+ fn r#struct (
92
+ & mut self ,
93
+ struct_type : & StructType ,
94
+ field_exprs : Vec < Self :: T > ,
95
+ ) -> DeltaResult < Self :: T > {
136
96
let fields = struct_type. fields ( ) ;
137
- if field_exprs. len ( ) != fields. len ( ) {
138
- self . set_error ( Error :: InsufficientScalars ) ;
139
- return None ;
140
- }
141
-
142
97
let mut found_non_nullable_null = false ;
143
98
let mut all_null = true ;
144
99
for ( field, expr) in fields. zip ( & field_exprs) {
@@ -154,36 +109,42 @@ impl<'a, T: Iterator<Item = &'a Scalar>> SchemaTransform<'a> for LiteralExpressi
154
109
let struct_expr = if found_non_nullable_null {
155
110
if !all_null {
156
111
// we found a non_nullable NULL, but other siblings are non-null: error
157
- self . set_error ( Error :: Schema (
112
+ return Err ( Error :: Schema (
158
113
"NULL value for non-nullable struct field with non-NULL siblings" . to_string ( ) ,
159
- ) ) ;
160
- return None ;
114
+ )
115
+ . into ( ) ) ;
161
116
}
162
117
Expression :: null_literal ( struct_type. clone ( ) . into ( ) )
163
118
} else {
164
119
Expression :: struct_from ( field_exprs)
165
120
} ;
166
121
167
- self . stack . push ( struct_expr) ;
168
- None
122
+ Ok ( struct_expr)
169
123
}
170
124
171
- fn transform_struct_field ( & mut self , field : & ' a StructField ) -> Option < Cow < ' a , StructField > > {
172
- // first always check error to terminate early if possible
173
- self . error . as_ref ( ) . ok ( ) ?;
125
+ fn list ( & mut self , _list : & ArrayType , _value : Self :: T ) -> DeltaResult < Self :: T > {
126
+ // Everything is handled on the field level
127
+ Ok ( Expression :: Unknown ( "Should not happen" . to_string ( ) ) )
128
+ }
174
129
175
- self . recurse_into_struct_field ( field) ;
176
- Some ( Cow :: Borrowed ( field) )
130
+ fn map (
131
+ & mut self ,
132
+ _map : & MapType ,
133
+ _key_value : Self :: T ,
134
+ _value : Self :: T ,
135
+ ) -> DeltaResult < Self :: T > {
136
+ // Everything is handled on the field level
137
+ Ok ( Expression :: Unknown ( "Should not happen" . to_string ( ) ) )
177
138
}
178
139
179
- // arrays treated as leaves
180
- fn transform_array ( & mut self , array_type : & ' a ArrayType ) -> Option < Cow < ' a , ArrayType > > {
181
- transform_leaf ! ( self , DataType :: Array , array_type )
140
+ fn primitive ( & mut self , _p : & PrimitiveType ) -> DeltaResult < Self :: T > {
141
+ // Everything is handled on the field level
142
+ Ok ( Expression :: Unknown ( "Should not happen" . to_string ( ) ) )
182
143
}
183
144
184
- // maps treated as leaves
185
- fn transform_map ( & mut self , map_type : & ' a MapType ) -> Option < Cow < ' a , MapType > > {
186
- transform_leaf ! ( self , DataType :: Map , map_type )
145
+ fn variant ( & mut self , _struct : & StructType ) -> DeltaResult < Self :: T > {
146
+ // Everything is handled on the field level
147
+ Ok ( Expression :: Unknown ( "Should not happen" . to_string ( ) ) )
187
148
}
188
149
}
189
150
@@ -208,18 +169,15 @@ mod tests {
208
169
schema : SchemaRef ,
209
170
expected : Result < Expr , ( ) > ,
210
171
) {
211
- let mut schema_transform = LiteralExpressionTransform :: new ( values) ;
212
- let datatype = schema. into ( ) ;
213
- let _transformed = schema_transform. transform ( & datatype) ;
172
+ let actual = LiteralExpressionTransform :: new ( values) . bind ( & schema) ;
214
173
match expected {
215
174
Ok ( expected_expr) => {
216
- let actual_expr = schema_transform. try_into_expr ( ) . unwrap ( ) ;
217
175
// TODO: we can't compare NULLs so we convert with .to_string to workaround
218
- // see: https://github.com/delta-io/delta-kernel-rs/pull/677
219
- assert_eq ! ( expected_expr. to_string( ) , actual_expr . to_string( ) ) ;
176
+ // see: https://github.com/delta-io/delta-kernel-rs/pull/1267
177
+ assert_eq ! ( expected_expr. to_string( ) , actual . unwrap ( ) . to_string( ) ) ;
220
178
}
221
179
Err ( ( ) ) => {
222
- assert ! ( schema_transform . try_into_expr ( ) . is_err( ) ) ;
180
+ assert ! ( actual . is_err( ) ) ;
223
181
}
224
182
}
225
183
}
0 commit comments