Omega359 commented on code in PR #8886:
URL: https://github.com/apache/arrow-datafusion/pull/8886#discussion_r1459076364


##########
datafusion/physical-expr/src/datetime_expressions.rs:
##########
@@ -84,7 +172,96 @@ where
     array.iter().map(|x| x.map(&op).transpose()).collect()
 }
 
-// given an function that maps a `&str` to a arrow native type,
+/// given a function `op` that maps `&str`, `&str` to the first successful 
Result
+/// of an arrow native type, returns a `PrimitiveArray` after the application 
of the
+/// function to `args` and the subsequence application of the `op2` function 
to any
+/// successful result. This function calls the `op` function with the first 
and second
+/// argument and if not successful continues with first and third, first and 
fourth,
+/// etc until the result was successful or no more arguments are present.
+/// # Errors
+/// This function errors iff:
+/// * the number of arguments is not > 1 or
+/// * the array arguments are not castable to a `GenericStringArray` or
+/// * the function `op` errors for all input
+pub(crate) fn strings_to_primitive_function<'a, T, O, F, F2>(
+    args: &'a [ColumnarValue],
+    op: F,
+    op2: F2,
+    name: &str,
+) -> Result<PrimitiveArray<O>>
+where
+    O: ArrowPrimitiveType,
+    T: OffsetSizeTrait,
+    F: Fn(&'a str, &'a str) -> Result<O::Native>,
+    F2: Fn(O::Native) -> O::Native,
+{
+    if args.len() < 2 {
+        return internal_err!(
+            "{:?} args were supplied but {} takes 2 or more arguments",
+            args.len(),
+            name
+        );
+    }
+
+    // this will throw the error if any of the array args are not castable to 
GenericStringArray
+    let data = args
+        .iter()
+        .map(|a| match a {
+            ColumnarValue::Array(a) => {
+                Ok(Either::Left(as_generic_string_array::<T>(a.as_ref())?))
+            }
+            ColumnarValue::Scalar(s) => match s {
+                ScalarValue::Utf8(a) | ScalarValue::LargeUtf8(a) => 
Ok(Either::Right(a)),
+                other => internal_err!(
+                    "Unexpected scalar type encountered '{other}' for function 
'{name}'"
+                ),
+            },
+        })
+        .collect::<Result<Vec<Either<&GenericStringArray<T>, 
&Option<String>>>>>()?;
+
+    let first_arg = &data.first().unwrap().left().unwrap();
+
+    first_arg
+        .iter()
+        .enumerate()
+        .map(|(pos, x)| {
+            let mut val = None;
+
+            if let Some(x) = x {
+                let param_args = data.iter().skip(1);
+
+                // go through the args and find the first successful result. 
Only the last
+                // failure will be returned if no successful result was 
received.
+                for param_arg in param_args {
+                    // param_arg is an array, use the corresponding index into 
the array as the arg
+                    // we're currently parsing
+                    let p = *param_arg;
+                    let r = if p.is_left() {
+                        let p = p.left().unwrap();
+                        op(x, p.value(pos))
+                    }
+                    // args is a scalar, use it directly
+                    else if let Some(p) = p.right().unwrap() {
+                        op(x, p.as_str())
+                    } else {
+                        continue;
+                    };
+
+                    if r.is_ok() {

Review Comment:
   Sounds good.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to