@@ -462,7 +462,9 @@ impl Unparser<'_> {
462462 match func_name {
463463 "make_array" => self . make_array_to_sql ( args) ,
464464 "array_element" => self . array_element_to_sql ( args) ,
465- // TODO: support for the construct and access functions of the `map` and `struct` types
465+ "named_struct" => self . named_struct_to_sql ( args) ,
466+ "get_field" => self . get_field_to_sql ( args) ,
467+ // TODO: support for the construct and access functions of the `map` type
466468 _ => self . scalar_function_to_sql_internal ( func_name, args) ,
467469 }
468470 }
@@ -514,6 +516,57 @@ impl Unparser<'_> {
514516 } )
515517 }
516518
519+ fn named_struct_to_sql ( & self , args : & [ Expr ] ) -> Result < ast:: Expr > {
520+ if args. len ( ) % 2 != 0 {
521+ return internal_err ! ( "named_struct must have an even number of arguments" ) ;
522+ }
523+
524+ let args = args
525+ . chunks_exact ( 2 )
526+ . map ( |chunk| {
527+ let key = match & chunk[ 0 ] {
528+ Expr :: Literal ( ScalarValue :: Utf8 ( Some ( s) ) ) => self . new_ident_quoted_if_needs ( s. to_string ( ) ) ,
529+ _ => return internal_err ! ( "named_struct expects even arguments to be strings, but received: {:?}" , & chunk[ 0 ] )
530+ } ;
531+
532+ Ok ( ast:: DictionaryField {
533+ key,
534+ value : Box :: new ( self . expr_to_sql ( & chunk[ 1 ] ) ?) ,
535+ } )
536+ } )
537+ . collect :: < Result < Vec < _ > > > ( ) ?;
538+
539+ Ok ( ast:: Expr :: Dictionary ( args) )
540+ }
541+
542+ fn get_field_to_sql ( & self , args : & [ Expr ] ) -> Result < ast:: Expr > {
543+ if args. len ( ) != 2 {
544+ return internal_err ! ( "get_field must have exactly 2 arguments" ) ;
545+ }
546+
547+ let mut id = match & args[ 0 ] {
548+ Expr :: Column ( col) => match self . col_to_sql ( col) ? {
549+ ast:: Expr :: Identifier ( ident) => vec ! [ ident] ,
550+ ast:: Expr :: CompoundIdentifier ( idents) => idents,
551+ other => return internal_err ! ( "expected col_to_sql to return an Identifier or CompoundIdentifier, but received: {:?}" , other) ,
552+ } ,
553+ _ => return internal_err ! ( "get_field expects first argument to be column, but received: {:?}" , & args[ 0 ] ) ,
554+ } ;
555+
556+ let field = match & args[ 1 ] {
557+ Expr :: Literal ( lit) => self . new_ident_quoted_if_needs ( lit. to_string ( ) ) ,
558+ _ => {
559+ return internal_err ! (
560+ "get_field expects second argument to be a string, but received: {:?}" ,
561+ & args[ 0 ]
562+ )
563+ }
564+ } ;
565+ id. push ( field) ;
566+
567+ Ok ( ast:: Expr :: CompoundIdentifier ( id) )
568+ }
569+
517570 pub fn sort_to_sql ( & self , sort : & Sort ) -> Result < ast:: OrderByExpr > {
518571 let Sort {
519572 expr,
@@ -1524,6 +1577,7 @@ mod tests {
15241577 Signature , Volatility , WindowFrame , WindowFunctionDefinition ,
15251578 } ;
15261579 use datafusion_expr:: { interval_month_day_nano_lit, ExprFunctionExt } ;
1580+ use datafusion_functions:: expr_fn:: { get_field, named_struct} ;
15271581 use datafusion_functions_aggregate:: count:: count_udaf;
15281582 use datafusion_functions_aggregate:: expr_fn:: sum;
15291583 use datafusion_functions_nested:: expr_fn:: { array_element, make_array} ;
@@ -1937,6 +1991,11 @@ mod tests {
19371991 array_element( make_array( vec![ lit( 1 ) , lit( 2 ) , lit( 3 ) ] ) , lit( 1 ) ) ,
19381992 "[1, 2, 3][1]" ,
19391993 ) ,
1994+ (
1995+ named_struct( vec![ lit( "a" ) , lit( "1" ) , lit( "b" ) , lit( 2 ) ] ) ,
1996+ "{a: '1', b: 2}" ,
1997+ ) ,
1998+ ( get_field( col( "a.b" ) , "c" ) , "a.b.c" ) ,
19401999 ] ;
19412000
19422001 for ( expr, expected) in tests {
0 commit comments