This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new cb9da2b46f Add Expr->String for ScalarFunction and InList (#9759)
cb9da2b46f is described below

commit cb9da2b46f602f006bdd8902208817830a6fc2f1
Author: Junhao Liu <[email protected]>
AuthorDate: Sun Mar 24 12:15:34 2024 -0600

    Add Expr->String for ScalarFunction and InList (#9759)
    
    * add ScalarFunction and InList
    
    * cargo fmt
    
    * address comment
---
 datafusion/sql/src/unparser/expr.rs | 99 ++++++++++++++++++++++++++++++++++---
 1 file changed, 93 insertions(+), 6 deletions(-)

diff --git a/datafusion/sql/src/unparser/expr.rs 
b/datafusion/sql/src/unparser/expr.rs
index 8d25a607bb..d007d4a843 100644
--- a/datafusion/sql/src/unparser/expr.rs
+++ b/datafusion/sql/src/unparser/expr.rs
@@ -52,13 +52,48 @@ impl Unparser<'_> {
         match expr {
             Expr::InList(InList {
                 expr,
-                list: _,
-                negated: _,
+                list,
+                negated,
             }) => {
-                not_impl_err!("Unsupported expression: {expr:?}")
+                let list_expr = list
+                    .iter()
+                    .map(|e| self.expr_to_sql(e))
+                    .collect::<Result<Vec<_>>>()?;
+                Ok(ast::Expr::InList {
+                    expr: Box::new(self.expr_to_sql(expr)?),
+                    list: list_expr,
+                    negated: *negated,
+                })
             }
-            Expr::ScalarFunction(ScalarFunction { .. }) => {
-                not_impl_err!("Unsupported expression: {expr:?}")
+            Expr::ScalarFunction(ScalarFunction { func_def, args }) => {
+                let func_name = func_def.name();
+
+                let args = args
+                    .iter()
+                    .map(|e| {
+                        if matches!(e, Expr::Wildcard { qualifier: None }) {
+                            
Ok(FunctionArg::Unnamed(ast::FunctionArgExpr::Wildcard))
+                        } else {
+                            self.expr_to_sql(e).map(|e| {
+                                
FunctionArg::Unnamed(ast::FunctionArgExpr::Expr(e))
+                            })
+                        }
+                    })
+                    .collect::<Result<Vec<_>>>()?;
+
+                Ok(ast::Expr::Function(Function {
+                    name: ast::ObjectName(vec![Ident {
+                        value: func_name.to_string(),
+                        quote_style: None,
+                    }]),
+                    args,
+                    filter: None,
+                    null_treatment: None,
+                    over: None,
+                    distinct: false,
+                    special: false,
+                    order_by: vec![],
+                }))
             }
             Expr::Between(Between {
                 expr,
@@ -526,13 +561,53 @@ impl Unparser<'_> {
 
 #[cfg(test)]
 mod tests {
+    use std::any::Any;
+
     use datafusion_common::TableReference;
-    use datafusion_expr::{col, expr::AggregateFunction, lit};
+    use datafusion_expr::{
+        col, expr::AggregateFunction, lit, ColumnarValue, ScalarUDF, 
ScalarUDFImpl,
+        Signature, Volatility,
+    };
 
     use crate::unparser::dialect::CustomDialect;
 
     use super::*;
 
+    /// Mocked UDF
+    #[derive(Debug)]
+    struct DummyUDF {
+        signature: Signature,
+    }
+
+    impl DummyUDF {
+        fn new() -> Self {
+            Self {
+                signature: Signature::variadic_any(Volatility::Immutable),
+            }
+        }
+    }
+
+    impl ScalarUDFImpl for DummyUDF {
+        fn as_any(&self) -> &dyn Any {
+            self
+        }
+
+        fn name(&self) -> &str {
+            "dummy_udf"
+        }
+
+        fn signature(&self) -> &Signature {
+            &self.signature
+        }
+
+        fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
+            Ok(DataType::Int32)
+        }
+
+        fn invoke(&self, _args: &[ColumnarValue]) -> Result<ColumnarValue> {
+            unimplemented!("DummyUDF::invoke")
+        }
+    }
     // See sql::tests for E2E tests.
 
     #[test]
@@ -561,6 +636,18 @@ mod tests {
                 }),
                 r#"CAST("a" AS INTEGER UNSIGNED)"#,
             ),
+            (
+                col("a").in_list(vec![lit(1), lit(2), lit(3)], false),
+                r#""a" IN (1, 2, 3)"#,
+            ),
+            (
+                col("a").in_list(vec![lit(1), lit(2), lit(3)], true),
+                r#""a" NOT IN (1, 2, 3)"#,
+            ),
+            (
+                ScalarUDF::new_from_impl(DummyUDF::new()).call(vec![col("a"), 
col("b")]),
+                r#"dummy_udf("a", "b")"#,
+            ),
             (
                 Expr::Literal(ScalarValue::Date64(Some(0))),
                 r#"CAST('1970-01-01 00:00:00' AS DATETIME)"#,

Reply via email to