datafusion_spark/function/string/
ilike.rs1use arrow::array::ArrayRef;
19use arrow::compute::ilike;
20use arrow::datatypes::DataType;
21use datafusion_common::{exec_err, Result};
22use datafusion_expr::ColumnarValue;
23use datafusion_expr::{ScalarFunctionArgs, ScalarUDFImpl, Signature, Volatility};
24use datafusion_functions::utils::make_scalar_function;
25use std::any::Any;
26use std::sync::Arc;
27
28#[derive(Debug, PartialEq, Eq, Hash)]
31pub struct SparkILike {
32 signature: Signature,
33}
34
35impl Default for SparkILike {
36 fn default() -> Self {
37 Self::new()
38 }
39}
40
41impl SparkILike {
42 pub fn new() -> Self {
43 Self {
44 signature: Signature::string(2, Volatility::Immutable),
45 }
46 }
47}
48
49impl ScalarUDFImpl for SparkILike {
50 fn as_any(&self) -> &dyn Any {
51 self
52 }
53
54 fn name(&self) -> &str {
55 "ilike"
56 }
57
58 fn signature(&self) -> &Signature {
59 &self.signature
60 }
61
62 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
63 Ok(DataType::Boolean)
64 }
65
66 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
67 make_scalar_function(spark_ilike, vec![])(&args.args)
68 }
69}
70
71pub fn spark_ilike(args: &[ArrayRef]) -> Result<ArrayRef> {
73 if args.len() != 2 {
74 return exec_err!("ilike function requires exactly 2 arguments");
75 }
76
77 let result = ilike(&args[0], &args[1])?;
78 Ok(Arc::new(result))
79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84 use crate::function::utils::test::test_scalar_function;
85 use arrow::array::{Array, BooleanArray};
86 use arrow::datatypes::DataType::Boolean;
87 use datafusion_common::{Result, ScalarValue};
88 use datafusion_expr::{ColumnarValue, ScalarUDFImpl};
89
90 macro_rules! test_ilike_string_invoke {
91 ($INPUT1:expr, $INPUT2:expr, $EXPECTED:expr) => {
92 test_scalar_function!(
93 SparkILike::new(),
94 vec![
95 ColumnarValue::Scalar(ScalarValue::Utf8($INPUT1)),
96 ColumnarValue::Scalar(ScalarValue::Utf8($INPUT2))
97 ],
98 $EXPECTED,
99 bool,
100 Boolean,
101 BooleanArray
102 );
103
104 test_scalar_function!(
105 SparkILike::new(),
106 vec![
107 ColumnarValue::Scalar(ScalarValue::LargeUtf8($INPUT1)),
108 ColumnarValue::Scalar(ScalarValue::LargeUtf8($INPUT2))
109 ],
110 $EXPECTED,
111 bool,
112 Boolean,
113 BooleanArray
114 );
115
116 test_scalar_function!(
117 SparkILike::new(),
118 vec![
119 ColumnarValue::Scalar(ScalarValue::Utf8View($INPUT1)),
120 ColumnarValue::Scalar(ScalarValue::Utf8View($INPUT2))
121 ],
122 $EXPECTED,
123 bool,
124 Boolean,
125 BooleanArray
126 );
127 };
128 }
129
130 #[test]
131 fn test_ilike_invoke() -> Result<()> {
132 test_ilike_string_invoke!(
133 Some(String::from("Spark")),
134 Some(String::from("_park")),
135 Ok(Some(true))
136 );
137 test_ilike_string_invoke!(
138 Some(String::from("Spark")),
139 Some(String::from("_PARK")),
140 Ok(Some(true))
141 );
142 test_ilike_string_invoke!(
143 Some(String::from("SPARK")),
144 Some(String::from("_park")),
145 Ok(Some(true))
146 );
147 test_ilike_string_invoke!(
148 Some(String::from("Spark")),
149 Some(String::from("sp%")),
150 Ok(Some(true))
151 );
152 test_ilike_string_invoke!(
153 Some(String::from("Spark")),
154 Some(String::from("SP%")),
155 Ok(Some(true))
156 );
157 test_ilike_string_invoke!(
158 Some(String::from("Spark")),
159 Some(String::from("%ARK")),
160 Ok(Some(true))
161 );
162 test_ilike_string_invoke!(
163 Some(String::from("Spark")),
164 Some(String::from("xyz")),
165 Ok(Some(false))
166 );
167 test_ilike_string_invoke!(None, Some(String::from("_park")), Ok(None));
168 test_ilike_string_invoke!(Some(String::from("Spark")), None, Ok(None));
169 test_ilike_string_invoke!(None, None, Ok(None));
170
171 Ok(())
172 }
173}