@@ -41,8 +41,8 @@ pub enum FunctionArgument {
41
41
/// Used for type arguments.
42
42
Type ( data:: Type ) ,
43
43
44
- /// Used for enum option arguments.
45
- Enum ( Option < String > ) ,
44
+ /// Used for enum arguments.
45
+ Enum ( String ) ,
46
46
}
47
47
48
48
impl Default for FunctionArgument {
@@ -61,8 +61,7 @@ impl Describe for FunctionArgument {
61
61
FunctionArgument :: Unresolved => write ! ( f, "!" ) ,
62
62
FunctionArgument :: Value ( _, e) => e. describe ( f, limit) ,
63
63
FunctionArgument :: Type ( t) => t. describe ( f, limit) ,
64
- FunctionArgument :: Enum ( Some ( s) ) => util:: string:: describe_identifier ( f, s, limit) ,
65
- FunctionArgument :: Enum ( None ) => write ! ( f, "-" ) ,
64
+ FunctionArgument :: Enum ( s) => util:: string:: describe_identifier ( f, s, limit) ,
66
65
}
67
66
}
68
67
}
@@ -73,6 +72,16 @@ impl std::fmt::Display for FunctionArgument {
73
72
}
74
73
}
75
74
75
+ /// An optional function argument. Typically used for specifying behavior in
76
+ /// invalid or corner cases.
77
+ #[ derive( Clone , Debug ) ]
78
+ pub struct FunctionOption {
79
+ /// Name of the option to set.
80
+ pub name : String ,
81
+ /// List of behavior options allowed by the producer.
82
+ pub preference : Vec < String > ,
83
+ }
84
+
76
85
/// Information about the context in which a function is being called.
77
86
#[ derive( Clone , Debug ) ]
78
87
pub struct FunctionContext {
@@ -82,6 +91,9 @@ pub struct FunctionContext {
82
91
/// The list of arguments bound to the function.
83
92
pub arguments : Vec < FunctionArgument > ,
84
93
94
+ /// The list of optional function arguments.
95
+ pub options : Vec < FunctionOption > ,
96
+
85
97
/// If known, the expected return type of the function. If not known this
86
98
/// can just be set to unresolved.
87
99
pub return_type : data:: Type ,
@@ -101,17 +113,16 @@ pub struct FunctionBinding {
101
113
}
102
114
103
115
impl FunctionBinding {
104
- /// Try to bind one of the provided function implementations to the
105
- /// provided function context.
116
+ /// Try to bind one of the provided function implementations to the provided
117
+ /// function context.
106
118
///
107
119
/// This is purely a validator thing. For valid plans, there should only
108
120
/// ever be one implementation after name resolution, and the return type
109
- /// should already have been specified. Much more intelligence was thrown
110
- /// in here just to help people find and correct mistakes efficiently.
111
- /// Common misconceptions and mistakes, like using the simple function name
112
- /// vs. the compound name, not specifying optional arguments, or not
113
- /// specifying the (correct) return type should yield more than just a
114
- /// generic error message here!
121
+ /// should already have been specified. Much more intelligence was thrown in
122
+ /// here just to help people find and correct mistakes efficiently. Common
123
+ /// misconceptions and mistakes, like using the simple function name vs. the
124
+ /// compound name. or not specifying the (correct) return type should yield
125
+ /// more than just a generic error message here!
115
126
pub fn new (
116
127
functions : Option < & extension:: simple:: function:: ResolutionResult > ,
117
128
function_context : & FunctionContext ,
@@ -154,36 +165,13 @@ impl FunctionBinding {
154
165
}
155
166
}
156
167
157
- /// Parse an enum option argument type.
158
- fn parse_enum_type (
159
- x : & substrait:: function_argument:: r#enum:: EnumKind ,
160
- _y : & mut context:: Context ,
161
- ) -> diagnostic:: Result < Option < String > > {
162
- match x {
163
- substrait:: function_argument:: r#enum:: EnumKind :: Specified ( x) => Ok ( Some ( x. clone ( ) ) ) ,
164
- substrait:: function_argument:: r#enum:: EnumKind :: Unspecified ( _) => Ok ( None ) ,
165
- }
166
- }
167
-
168
- /// Parse an enum option argument.
169
- fn parse_enum (
170
- x : & substrait:: function_argument:: Enum ,
171
- y : & mut context:: Context ,
172
- ) -> diagnostic:: Result < Option < String > > {
173
- Ok ( proto_required_field ! ( x, y, enum_kind, parse_enum_type)
174
- . 1
175
- . flatten ( ) )
176
- }
177
-
178
168
/// Parse a 0.3.0+ function argument type.
179
169
fn parse_function_argument_type (
180
170
x : & substrait:: function_argument:: ArgType ,
181
171
y : & mut context:: Context ,
182
172
) -> diagnostic:: Result < FunctionArgument > {
183
173
match x {
184
- substrait:: function_argument:: ArgType :: Enum ( x) => {
185
- Ok ( FunctionArgument :: Enum ( parse_enum ( x, y) ?) )
186
- }
174
+ substrait:: function_argument:: ArgType :: Enum ( x) => Ok ( FunctionArgument :: Enum ( x. to_string ( ) ) ) ,
187
175
substrait:: function_argument:: ArgType :: Type ( x) => {
188
176
types:: parse_type ( x, y) ?;
189
177
Ok ( FunctionArgument :: Type ( y. data_type ( ) ) )
@@ -207,14 +195,48 @@ fn parse_function_argument(
207
195
)
208
196
}
209
197
198
+ fn parse_function_option (
199
+ x : & substrait:: FunctionOption ,
200
+ y : & mut context:: Context ,
201
+ ) -> diagnostic:: Result < FunctionOption > {
202
+ proto_primitive_field ! ( x, y, name) ;
203
+ proto_required_repeated_field ! ( x, y, preference) ;
204
+
205
+ if x. preference . is_empty ( ) {
206
+ let err = cause ! ( IllegalValue , "at least one option must be specified" ) ;
207
+ diagnostic ! ( y, Error , err. clone( ) ) ;
208
+ comment ! (
209
+ y,
210
+ "To leave an option unspecified, simply don't add an entry to `options`"
211
+ ) ;
212
+ Err ( err)
213
+ } else {
214
+ Ok ( FunctionOption {
215
+ name : x. name . clone ( ) ,
216
+ preference : x. preference . clone ( ) ,
217
+ } )
218
+ }
219
+ }
220
+
210
221
/// Parse a pre-0.3.0 function argument expression.
211
222
fn parse_legacy_function_argument (
212
223
x : & substrait:: Expression ,
213
224
y : & mut context:: Context ,
214
225
) -> diagnostic:: Result < FunctionArgument > {
215
226
expressions:: parse_legacy_function_argument ( x, y) . map ( |x| match x {
216
227
expressions:: ExpressionOrEnum :: Value ( x) => FunctionArgument :: Value ( y. data_type ( ) , x) ,
217
- expressions:: ExpressionOrEnum :: Enum ( x) => FunctionArgument :: Enum ( x) ,
228
+ expressions:: ExpressionOrEnum :: Enum ( x) => match x {
229
+ Some ( x) => FunctionArgument :: Enum ( x) ,
230
+ None => {
231
+ diagnostic ! (
232
+ y,
233
+ Error ,
234
+ Deprecation ,
235
+ "support for optional enum arguments was removed in Substrait 0.20.0 (#342)"
236
+ ) ;
237
+ FunctionArgument :: Unresolved
238
+ }
239
+ } ,
218
240
} )
219
241
}
220
242
@@ -279,6 +301,11 @@ pub fn parse_scalar_function(
279
301
. into_iter ( )
280
302
. map ( |x| x. unwrap_or_default ( ) )
281
303
. collect ( ) ;
304
+ let options = proto_repeated_field ! ( x, y, options, parse_function_option)
305
+ . 1
306
+ . into_iter ( )
307
+ . flatten ( )
308
+ . collect ( ) ;
282
309
let return_type = proto_required_field ! ( x, y, output_type, types:: parse_type)
283
310
. 0
284
311
. data_type ( ) ;
@@ -288,6 +315,7 @@ pub fn parse_scalar_function(
288
315
let context = FunctionContext {
289
316
function_type : FunctionType :: Scalar ,
290
317
arguments,
318
+ options,
291
319
return_type,
292
320
} ;
293
321
let binding = FunctionBinding :: new ( functions. as_ref ( ) , & context, y) ;
@@ -341,6 +369,11 @@ pub fn parse_window_function(
341
369
. into_iter ( )
342
370
. map ( |x| x. unwrap_or_default ( ) )
343
371
. collect ( ) ;
372
+ let options = proto_repeated_field ! ( x, y, options, parse_function_option)
373
+ . 1
374
+ . into_iter ( )
375
+ . flatten ( )
376
+ . collect ( ) ;
344
377
let return_type = proto_required_field ! ( x, y, output_type, types:: parse_type)
345
378
. 0
346
379
. data_type ( ) ;
@@ -359,6 +392,7 @@ pub fn parse_window_function(
359
392
let context = FunctionContext {
360
393
function_type : FunctionType :: Window ,
361
394
arguments,
395
+ options,
362
396
return_type,
363
397
} ;
364
398
let binding = FunctionBinding :: new ( functions. as_ref ( ) , & context, y) ;
@@ -395,6 +429,11 @@ pub fn parse_aggregate_function(
395
429
. into_iter ( )
396
430
. map ( |x| x. unwrap_or_default ( ) )
397
431
. collect ( ) ;
432
+ let options = proto_repeated_field ! ( x, y, options, parse_function_option)
433
+ . 1
434
+ . into_iter ( )
435
+ . flatten ( )
436
+ . collect ( ) ;
398
437
let return_type = proto_required_field ! ( x, y, output_type, types:: parse_type)
399
438
. 0
400
439
. data_type ( ) ;
@@ -416,6 +455,7 @@ pub fn parse_aggregate_function(
416
455
let context = FunctionContext {
417
456
function_type : FunctionType :: Aggregate ,
418
457
arguments,
458
+ options,
419
459
return_type,
420
460
} ;
421
461
let binding = FunctionBinding :: new ( functions. as_ref ( ) , & context, y) ;
0 commit comments