datafusion_functions/string/
ltrim.rs1use arrow::array::{ArrayRef, OffsetSizeTrait};
19use arrow::datatypes::DataType;
20use std::sync::Arc;
21
22use crate::string::common::*;
23use crate::utils::make_scalar_function;
24use datafusion_common::types::logical_string;
25use datafusion_common::{Result, exec_err};
26use datafusion_expr::function::Hint;
27use datafusion_expr::{
28 Coercion, ColumnarValue, Documentation, ScalarFunctionArgs, ScalarUDFImpl, Signature,
29 TypeSignature, TypeSignatureClass, Volatility,
30};
31use datafusion_macros::user_doc;
32
33fn ltrim<T: OffsetSizeTrait>(args: &[ArrayRef]) -> Result<ArrayRef> {
36 let use_string_view = args[0].data_type() == &DataType::Utf8View;
37 let args = if args.len() > 1 {
38 let arg1 = arrow::compute::kernels::cast::cast(&args[1], args[0].data_type())?;
39 vec![Arc::clone(&args[0]), arg1]
40 } else {
41 args.to_owned()
42 };
43 general_trim::<T, TrimLeft>(&args, use_string_view)
44}
45
46#[user_doc(
47 doc_section(label = "String Functions"),
48 description = "Trims the specified trim string from the beginning of a string. If no trim string is provided, spaces are removed from the start of the input string.",
49 syntax_example = "ltrim(str[, trim_str])",
50 sql_example = r#"```sql
51> select ltrim(' datafusion ');
52+-------------------------------+
53| ltrim(Utf8(" datafusion ")) |
54+-------------------------------+
55| datafusion |
56+-------------------------------+
57> select ltrim('___datafusion___', '_');
58+-------------------------------------------+
59| ltrim(Utf8("___datafusion___"),Utf8("_")) |
60+-------------------------------------------+
61| datafusion___ |
62+-------------------------------------------+
63```"#,
64 standard_argument(name = "str", prefix = "String"),
65 argument(
66 name = "trim_str",
67 description = r"String expression to trim from the beginning of the input string. Can be a constant, column, or function, and any combination of arithmetic operators. _Default is a space._"
68 ),
69 alternative_syntax = "trim(LEADING trim_str FROM str)",
70 related_udf(name = "btrim"),
71 related_udf(name = "rtrim")
72)]
73#[derive(Debug, PartialEq, Eq, Hash)]
74pub struct LtrimFunc {
75 signature: Signature,
76}
77
78impl Default for LtrimFunc {
79 fn default() -> Self {
80 Self::new()
81 }
82}
83
84impl LtrimFunc {
85 pub fn new() -> Self {
86 Self {
87 signature: Signature::one_of(
88 vec![
89 TypeSignature::Coercible(vec![
90 Coercion::new_exact(TypeSignatureClass::Native(logical_string())),
91 Coercion::new_exact(TypeSignatureClass::Native(logical_string())),
92 ]),
93 TypeSignature::Coercible(vec![Coercion::new_exact(
94 TypeSignatureClass::Native(logical_string()),
95 )]),
96 ],
97 Volatility::Immutable,
98 ),
99 }
100 }
101}
102
103impl ScalarUDFImpl for LtrimFunc {
104 fn name(&self) -> &str {
105 "ltrim"
106 }
107
108 fn signature(&self) -> &Signature {
109 &self.signature
110 }
111
112 fn return_type(&self, arg_types: &[DataType]) -> Result<DataType> {
113 Ok(arg_types[0].clone())
114 }
115
116 fn invoke_with_args(&self, args: ScalarFunctionArgs) -> Result<ColumnarValue> {
117 match args.args[0].data_type() {
118 DataType::Utf8 | DataType::Utf8View => make_scalar_function(
119 ltrim::<i32>,
120 vec![Hint::Pad, Hint::AcceptsSingular],
121 )(&args.args),
122 DataType::LargeUtf8 => make_scalar_function(
123 ltrim::<i64>,
124 vec![Hint::Pad, Hint::AcceptsSingular],
125 )(&args.args),
126 other => exec_err!(
127 "Unsupported data type {other:?} for function ltrim,\
128 expected Utf8, LargeUtf8 or Utf8View."
129 ),
130 }
131 }
132
133 fn documentation(&self) -> Option<&Documentation> {
134 self.doc()
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use arrow::array::{Array, StringArray, StringViewArray};
141 use arrow::datatypes::DataType::{Utf8, Utf8View};
142
143 use datafusion_common::{Result, ScalarValue};
144 use datafusion_expr::{ColumnarValue, ScalarUDFImpl};
145
146 use crate::string::ltrim::LtrimFunc;
147 use crate::utils::test::test_function;
148
149 #[test]
150 fn test_functions() {
151 test_function!(
153 LtrimFunc::new(),
154 vec![ColumnarValue::Scalar(ScalarValue::Utf8View(Some(
155 String::from("alphabet ")
156 ))),],
157 Ok(Some("alphabet ")),
158 &str,
159 Utf8View,
160 StringViewArray
161 );
162 test_function!(
163 LtrimFunc::new(),
164 vec![ColumnarValue::Scalar(ScalarValue::Utf8View(Some(
165 String::from(" alphabet ")
166 ))),],
167 Ok(Some("alphabet ")),
168 &str,
169 Utf8View,
170 StringViewArray
171 );
172 test_function!(
173 LtrimFunc::new(),
174 vec![
175 ColumnarValue::Scalar(ScalarValue::Utf8View(Some(String::from(
176 "alphabet"
177 )))),
178 ColumnarValue::Scalar(ScalarValue::Utf8View(Some(String::from("t")))),
179 ],
180 Ok(Some("alphabet")),
181 &str,
182 Utf8View,
183 StringViewArray
184 );
185 test_function!(
186 LtrimFunc::new(),
187 vec![
188 ColumnarValue::Scalar(ScalarValue::Utf8View(Some(String::from(
189 "alphabet"
190 )))),
191 ColumnarValue::Scalar(ScalarValue::Utf8View(Some(String::from(
192 "alphabe"
193 )))),
194 ],
195 Ok(Some("t")),
196 &str,
197 Utf8View,
198 StringViewArray
199 );
200 test_function!(
201 LtrimFunc::new(),
202 vec![
203 ColumnarValue::Scalar(ScalarValue::Utf8View(Some(String::from(
204 "alphabet"
205 )))),
206 ColumnarValue::Scalar(ScalarValue::Utf8View(None)),
207 ],
208 Ok(None),
209 &str,
210 Utf8View,
211 StringViewArray
212 );
213 test_function!(
215 LtrimFunc::new(),
216 vec![
217 ColumnarValue::Scalar(ScalarValue::Utf8View(Some(String::from(
218 "xxxalphabetalphabet"
219 )))),
220 ColumnarValue::Scalar(ScalarValue::Utf8View(Some(String::from("x")))),
221 ],
222 Ok(Some("alphabetalphabet")),
223 &str,
224 Utf8View,
225 StringViewArray
226 );
227 test_function!(
229 LtrimFunc::new(),
230 vec![ColumnarValue::Scalar(ScalarValue::Utf8(Some(
231 String::from("alphabet ")
232 ))),],
233 Ok(Some("alphabet ")),
234 &str,
235 Utf8,
236 StringArray
237 );
238 test_function!(
239 LtrimFunc::new(),
240 vec![ColumnarValue::Scalar(ScalarValue::Utf8(Some(
241 String::from("alphabet ")
242 ))),],
243 Ok(Some("alphabet ")),
244 &str,
245 Utf8,
246 StringArray
247 );
248 test_function!(
249 LtrimFunc::new(),
250 vec![
251 ColumnarValue::Scalar(ScalarValue::Utf8(Some(String::from("alphabet")))),
252 ColumnarValue::Scalar(ScalarValue::Utf8(Some(String::from("t")))),
253 ],
254 Ok(Some("alphabet")),
255 &str,
256 Utf8,
257 StringArray
258 );
259 test_function!(
260 LtrimFunc::new(),
261 vec![
262 ColumnarValue::Scalar(ScalarValue::Utf8(Some(String::from("alphabet")))),
263 ColumnarValue::Scalar(ScalarValue::Utf8(Some(String::from("alphabe")))),
264 ],
265 Ok(Some("t")),
266 &str,
267 Utf8,
268 StringArray
269 );
270 test_function!(
271 LtrimFunc::new(),
272 vec![
273 ColumnarValue::Scalar(ScalarValue::Utf8(Some(String::from("alphabet")))),
274 ColumnarValue::Scalar(ScalarValue::Utf8(None)),
275 ],
276 Ok(None),
277 &str,
278 Utf8,
279 StringArray
280 );
281 }
282}