datafusion_functions/string/
lower.rs1use arrow::datatypes::DataType;
19use std::any::Any;
20
21use crate::string::common::to_lower;
22use crate::utils::utf8_to_str_type;
23use datafusion_common::types::logical_string;
24use datafusion_common::Result;
25use datafusion_expr::{
26 Coercion, ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl, Signature,
27 TypeSignatureClass, Volatility,
28};
29use datafusion_macros::user_doc;
30
31#[user_doc(
32 doc_section(label = "String Functions"),
33 description = "Converts a string to lower-case.",
34 syntax_example = "lower(str)",
35 sql_example = r#"```sql
36> select lower('Ångström');
37+-------------------------+
38| lower(Utf8("Ångström")) |
39+-------------------------+
40| ångström |
41+-------------------------+
42```"#,
43 standard_argument(name = "str", prefix = "String"),
44 related_udf(name = "initcap"),
45 related_udf(name = "upper")
46)]
47#[derive(Debug)]
48pub struct LowerFunc {
49 signature: Signature,
50}
51
52impl Default for LowerFunc {
53 fn default() -> Self {
54 Self::new()
55 }
56}
57
58impl LowerFunc {
59 pub fn new() -> Self {
60 Self {
61 signature: Signature::coercible(
62 vec![Coercion::new_exact(TypeSignatureClass::Native(
63 logical_string(),
64 ))],
65 Volatility::Immutable,
66 ),
67 }
68 }
69}
70
71impl ScalarUDFImpl for LowerFunc {
72 fn as_any(&self) -> &dyn Any {
73 self
74 }
75
76 fn name(&self) -> &str {
77 "lower"
78 }
79
80 fn signature(&self) -> &Signature {
81 &self.signature
82 }
83
84 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
85 utf8_to_str_type(&arg_types[0], "lower")
86 }
87
88 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
89 to_lower(&args.args, "lower")
90 }
91
92 fn documentation(&self) -> Option<&Documentation> {
93 self.doc()
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use arrow::array::{Array, ArrayRef, StringArray};
101 use arrow::datatypes::DataType::Utf8;
102 use arrow::datatypes::Field;
103 use std::sync::Arc;
104
105 fn to_lower(input: ArrayRef, expected: ArrayRef) -> Result<()> {
106 let func = LowerFunc::new();
107 let arg_fields = vec![Field::new("a", input.data_type().clone(), true).into()];
108
109 let args = ScalarFunctionArgs {
110 number_rows: input.len(),
111 args: vec![ColumnarValue::Array(input)],
112 arg_fields,
113 return_field: Field::new("f", Utf8, true).into(),
114 };
115
116 let result = match func.invoke_with_args(args)? {
117 ColumnarValue::Array(result) => result,
118 _ => unreachable!("lower"),
119 };
120 assert_eq!(&expected, &result);
121 Ok(())
122 }
123
124 #[test]
125 fn lower_maybe_optimization() -> Result<()> {
126 let input = Arc::new(StringArray::from(vec![
127 Some("农历新年"),
128 None,
129 Some("DATAFUSION"),
130 Some("0123456789"),
131 Some(""),
132 ])) as ArrayRef;
133
134 let expected = Arc::new(StringArray::from(vec![
135 Some("农历新年"),
136 None,
137 Some("datafusion"),
138 Some("0123456789"),
139 Some(""),
140 ])) as ArrayRef;
141
142 to_lower(input, expected)
143 }
144
145 #[test]
146 fn lower_full_optimization() -> Result<()> {
147 let input = Arc::new(StringArray::from(vec![
148 Some("ARROW"),
149 None,
150 Some("DATAFUSION"),
151 Some("0123456789"),
152 Some(""),
153 ])) as ArrayRef;
154
155 let expected = Arc::new(StringArray::from(vec![
156 Some("arrow"),
157 None,
158 Some("datafusion"),
159 Some("0123456789"),
160 Some(""),
161 ])) as ArrayRef;
162
163 to_lower(input, expected)
164 }
165
166 #[test]
167 fn lower_partial_optimization() -> Result<()> {
168 let input = Arc::new(StringArray::from(vec![
169 Some("ARROW"),
170 None,
171 Some("DATAFUSION"),
172 Some("@_"),
173 Some("0123456789"),
174 Some(""),
175 Some("\t\n"),
176 Some("ὈΔΥΣΣΕΎΣ"),
177 Some("TSCHÜSS"),
178 Some("Ⱦ"), Some("农历新年"),
180 ])) as ArrayRef;
181
182 let expected = Arc::new(StringArray::from(vec![
183 Some("arrow"),
184 None,
185 Some("datafusion"),
186 Some("@_"),
187 Some("0123456789"),
188 Some(""),
189 Some("\t\n"),
190 Some("ὀδυσσεύς"),
191 Some("tschüss"),
192 Some("ⱦ"),
193 Some("农历新年"),
194 ])) as ArrayRef;
195
196 to_lower(input, expected)
197 }
198}