@@ -93,26 +93,7 @@ pub(super) fn translate_expr_kind(item: ExprKind, ctx: &mut Context) -> Result<s
93
93
94
94
sql_ast:: Expr :: Identifier ( sql_ast:: Ident :: new ( string) )
95
95
}
96
- ExprKind :: FString ( f_string_items) => {
97
- let args = f_string_items
98
- . into_iter ( )
99
- . map ( |item| match item {
100
- InterpolateItem :: String ( string) => {
101
- Ok ( sql_ast:: Expr :: Value ( Value :: SingleQuotedString ( string) ) )
102
- }
103
- InterpolateItem :: Expr ( node) => translate_expr_kind ( node. kind , ctx) ,
104
- } )
105
- . map ( |r| r. map ( |e| FunctionArg :: Unnamed ( FunctionArgExpr :: Expr ( e) ) ) )
106
- . collect :: < Result < Vec < _ > > > ( ) ?;
107
-
108
- sql_ast:: Expr :: Function ( Function {
109
- name : ObjectName ( vec ! [ sql_ast:: Ident :: new( "CONCAT" ) ] ) ,
110
- args,
111
- distinct : false ,
112
- over : None ,
113
- special : false ,
114
- } )
115
- }
96
+ ExprKind :: FString ( f_string_items) => translate_fstring ( f_string_items, ctx) ?,
116
97
ExprKind :: Literal ( l) => translate_literal ( l) ?,
117
98
ExprKind :: Switch ( mut cases) => {
118
99
let default = cases
@@ -352,6 +333,59 @@ pub(super) fn translate_query_sstring(
352
333
)
353
334
}
354
335
336
+ fn translate_fstring_with_concat_function (
337
+ items : Vec < InterpolateItem < Expr > > ,
338
+ ctx : & mut Context ,
339
+ ) -> Result < sql_ast:: Expr > {
340
+ let args = items
341
+ . into_iter ( )
342
+ . map ( |item| match item {
343
+ InterpolateItem :: String ( string) => {
344
+ Ok ( sql_ast:: Expr :: Value ( Value :: SingleQuotedString ( string) ) )
345
+ }
346
+ InterpolateItem :: Expr ( node) => translate_expr_kind ( node. kind , ctx) ,
347
+ } )
348
+ . map ( |r| r. map ( |e| FunctionArg :: Unnamed ( FunctionArgExpr :: Expr ( e) ) ) )
349
+ . collect :: < Result < Vec < _ > > > ( ) ?;
350
+
351
+ Ok ( sql_ast:: Expr :: Function ( Function {
352
+ name : ObjectName ( vec ! [ sql_ast:: Ident :: new( "CONCAT" ) ] ) ,
353
+ args,
354
+ distinct : false ,
355
+ over : None ,
356
+ special : false ,
357
+ } ) )
358
+ }
359
+
360
+ fn translate_fstring_with_concat_operator (
361
+ items : Vec < InterpolateItem < Expr > > ,
362
+ ctx : & mut Context ,
363
+ ) -> Result < sql_ast:: Expr > {
364
+ let string = items
365
+ . into_iter ( )
366
+ . map ( |f_string_item| match f_string_item {
367
+ InterpolateItem :: String ( string) => Ok ( Value :: SingleQuotedString ( string) . to_string ( ) ) ,
368
+ InterpolateItem :: Expr ( node) => {
369
+ translate_expr_kind ( node. kind , ctx) . map ( |expr| expr. to_string ( ) )
370
+ }
371
+ } )
372
+ . collect :: < Result < Vec < String > > > ( ) ?
373
+ . join ( "||" ) ;
374
+
375
+ Ok ( sql_ast:: Expr :: Identifier ( sql_ast:: Ident :: new ( string) ) )
376
+ }
377
+
378
+ pub ( super ) fn translate_fstring (
379
+ items : Vec < InterpolateItem < Expr > > ,
380
+ ctx : & mut Context ,
381
+ ) -> Result < sql_ast:: Expr > {
382
+ if ctx. dialect . has_concat_function ( ) {
383
+ translate_fstring_with_concat_function ( items, ctx)
384
+ } else {
385
+ translate_fstring_with_concat_operator ( items, ctx)
386
+ }
387
+ }
388
+
355
389
/// Aggregate several ordered ranges into one, computing the intersection.
356
390
///
357
391
/// Returns a tuple of `(start, end)`, where `end` is optional.
@@ -816,6 +850,10 @@ impl SQLExpression for UnaryOperator {
816
850
mod test {
817
851
use super :: * ;
818
852
use crate :: ast:: pl:: Range ;
853
+ use crate :: sql:: context:: AnchorContext ;
854
+ use crate :: {
855
+ parser:: parse, semantic:: resolve, sql:: dialect:: GenericDialect , sql:: dialect:: SQLiteDialect ,
856
+ } ;
819
857
use insta:: assert_yaml_snapshot;
820
858
821
859
#[ test]
@@ -903,4 +941,50 @@ mod test {
903
941
904
942
Ok ( ( ) )
905
943
}
944
+
945
+ #[ test]
946
+ fn test_translate_fstring ( ) -> Result < ( ) > {
947
+ let mut context_with_concat_function: Context ;
948
+ let mut context_without_concat_function: Context ;
949
+
950
+ {
951
+ let query = resolve ( parse ( "from foo" ) ?) ?;
952
+ let ( anchor, _) = AnchorContext :: of ( query) ;
953
+ context_with_concat_function = Context {
954
+ dialect : Box :: new ( GenericDialect { } ) ,
955
+ anchor,
956
+ omit_ident_prefix : false ,
957
+ pre_projection : false ,
958
+ } ;
959
+ }
960
+ {
961
+ let query = resolve ( parse ( "from foo" ) ?) ?;
962
+ let ( anchor, _) = AnchorContext :: of ( query) ;
963
+ context_without_concat_function = Context {
964
+ dialect : Box :: new ( SQLiteDialect { } ) ,
965
+ anchor,
966
+ omit_ident_prefix : false ,
967
+ pre_projection : false ,
968
+ } ;
969
+ }
970
+
971
+ fn str_lit ( s : & str ) -> InterpolateItem < Expr > {
972
+ InterpolateItem :: String ( s. to_string ( ) )
973
+ }
974
+
975
+ assert_yaml_snapshot ! ( translate_fstring( vec![
976
+ str_lit( "hello" ) ,
977
+ str_lit( "world" ) ,
978
+ ] , & mut context_with_concat_function) ?. to_string( ) , @r###"
979
+ ---
980
+ "CONCAT('hello', 'world')"
981
+ "### ) ;
982
+
983
+ assert_yaml_snapshot ! ( translate_fstring( vec![ str_lit( "hello" ) , str_lit( "world" ) ] , & mut context_without_concat_function) ?. to_string( ) , @r###"
984
+ ---
985
+ "'hello'||'world'"
986
+ "### ) ;
987
+
988
+ Ok ( ( ) )
989
+ }
906
990
}
0 commit comments