@@ -17,12 +17,22 @@ use super::TypeError;
17
17
///
18
18
/// See [`SQL_FUNCTION_SIGNATURES`].
19
19
#[ derive( Debug ) ]
20
- pub ( crate ) struct SqlFunction ( CompoundIdent , FunctionSig ) ;
20
+ pub ( crate ) struct SqlFunction {
21
+ pub ( crate ) name : CompoundIdent ,
22
+ pub ( crate ) sig : FunctionSig ,
23
+ pub ( crate ) rewrite_rule : RewriteRule ,
24
+ }
25
+
26
+ #[ derive( Debug ) ]
27
+ pub ( crate ) enum RewriteRule {
28
+ Ignore ,
29
+ AsEqlFunction ,
30
+ }
21
31
22
32
/// A representation of the type of an argument or return type in a SQL function.
23
33
#[ derive( Debug , Clone , Copy , Eq , PartialEq ) ]
24
34
pub ( crate ) enum Kind {
25
- /// A type that mjust be a native type
35
+ /// A type that must be a native type
26
36
Native ,
27
37
28
38
/// A type that can be a native or EQL type. The `str` is the generic variable name.
@@ -178,8 +188,12 @@ fn get_function_arg_expr(fn_arg: &FunctionArg) -> &FunctionArgExpr {
178
188
}
179
189
180
190
impl SqlFunction {
181
- fn new ( ident : & str , sig : FunctionSig ) -> Self {
182
- Self ( CompoundIdent :: from ( ident) , sig)
191
+ fn new ( ident : & str , sig : FunctionSig , rewrite_rule : RewriteRule ) -> Self {
192
+ Self {
193
+ name : CompoundIdent :: from ( ident) ,
194
+ sig,
195
+ rewrite_rule,
196
+ }
183
197
}
184
198
}
185
199
@@ -202,38 +216,51 @@ impl From<&Vec<Ident>> for CompoundIdent {
202
216
}
203
217
204
218
/// SQL functions that are handled with special case type checking rules.
205
- static SQL_FUNCTION_SIGNATURES : LazyLock < HashMap < CompoundIdent , Vec < FunctionSig > > > =
206
- LazyLock :: new ( || {
207
- // Notation: a single uppercase letter denotes an unknown type. Matching letters in a signature will be assigned
208
- // *the same type variable* and thus must resolve to the same type. (🙏 Haskell)
209
- //
210
- // Eventually we should type check EQL types against their configured indexes instead of leaving that to the EQL
211
- // extension in the database. I can imagine supporting type bounds in signatures here, such as: `T: Eq`
212
- let sql_fns = vec ! [
213
- sql_fn!( count( T ) -> NATIVE ) ,
214
- sql_fn!( min( T ) -> T ) ,
215
- sql_fn!( max( T ) -> T ) ,
216
- sql_fn!( jsonb_path_query( T , T ) -> T ) ,
217
- sql_fn!( jsonb_path_query_first( T , T ) -> T ) ,
218
- sql_fn!( jsonb_path_exists( T , T ) -> T ) ,
219
- ] ;
220
-
221
- let mut sql_fns_by_name: HashMap < CompoundIdent , Vec < FunctionSig > > = HashMap :: new ( ) ;
222
-
223
- for ( key, chunk) in & sql_fns. into_iter ( ) . chunk_by ( |sql_fn| sql_fn. 0 . clone ( ) ) {
224
- sql_fns_by_name. insert (
225
- key. clone ( ) ,
226
- chunk. into_iter ( ) . map ( |sql_fn| sql_fn. 1 ) . collect ( ) ,
227
- ) ;
228
- }
219
+ static SQL_FUNCTIONS : LazyLock < HashMap < CompoundIdent , Vec < SqlFunction > > > = LazyLock :: new ( || {
220
+ // Notation: a single uppercase letter denotes an unknown type. Matching letters in a signature will be assigned
221
+ // *the same type variable* and thus must resolve to the same type. (🙏 Haskell)
222
+ //
223
+ // Eventually we should type check EQL types against their configured indexes instead of leaving that to the EQL
224
+ // extension in the database. I can imagine supporting type bounds in signatures here, such as: `T: Eq`
225
+ let sql_fns = vec ! [
226
+ // TODO: when search_path support is added to the resolver we should change these
227
+ // to their fully-qualified names.
228
+ sql_fn!( count( T ) -> NATIVE ) ,
229
+ sql_fn!( min( T ) -> T , rewrite) ,
230
+ sql_fn!( max( T ) -> T , rewrite) ,
231
+ sql_fn!( jsonb_path_query( T , T ) -> T , rewrite) ,
232
+ sql_fn!( jsonb_path_query_first( T , T ) -> T , rewrite) ,
233
+ sql_fn!( jsonb_path_exists( T , T ) -> T , rewrite) ,
234
+ sql_fn!( jsonb_array_length( T ) -> T , rewrite) ,
235
+ sql_fn!( jsonb_array_elements( T ) -> T , rewrite) ,
236
+ sql_fn!( jsonb_array_elements_text( T ) -> T , rewrite) ,
237
+ // These are typings for when customer SQL already contains references to EQL functions.
238
+ // They must be type checked but not rewritten.
239
+ sql_fn!( eql_v1. min( T ) -> T ) ,
240
+ sql_fn!( eql_v1. max( T ) -> T ) ,
241
+ sql_fn!( eql_v1. jsonb_path_query( T , T ) -> T ) ,
242
+ sql_fn!( eql_v1. jsonb_path_query_first( T , T ) -> T ) ,
243
+ sql_fn!( eql_v1. jsonb_path_exists( T , T ) -> T ) ,
244
+ sql_fn!( eql_v1. jsonb_array_length( T ) -> T ) ,
245
+ sql_fn!( eql_v1. jsonb_array_elements( T ) -> T ) ,
246
+ sql_fn!( eql_v1. jsonb_array_elements_text( T ) -> T ) ,
247
+ ] ;
248
+
249
+ let mut sql_fns_by_name: HashMap < CompoundIdent , Vec < SqlFunction > > = HashMap :: new ( ) ;
250
+
251
+ for ( key, chunk) in & sql_fns. into_iter ( ) . chunk_by ( |sql_fn| sql_fn. name . clone ( ) ) {
252
+ sql_fns_by_name. insert ( key. clone ( ) , chunk. into_iter ( ) . collect ( ) ) ;
253
+ }
229
254
230
- sql_fns_by_name
231
- } ) ;
255
+ sql_fns_by_name
256
+ } ) ;
232
257
233
- pub ( crate ) fn get_type_signature_for_special_cased_sql_function (
258
+ pub ( crate ) fn get_sql_function_def (
234
259
fn_name : & CompoundIdent ,
235
260
args : & FunctionArguments ,
236
- ) -> Option < & ' static FunctionSig > {
237
- let sigs = SQL_FUNCTION_SIGNATURES . get ( fn_name) ?;
238
- sigs. iter ( ) . find ( |sig| sig. is_applicable_to_args ( args) )
261
+ ) -> Option < & ' static SqlFunction > {
262
+ let sql_fns = SQL_FUNCTIONS . get ( fn_name) ?;
263
+ sql_fns
264
+ . iter ( )
265
+ . find ( |sql_fn| sql_fn. sig . is_applicable_to_args ( args) )
239
266
}
0 commit comments