1use {
2 crate::ast::{Expr, Function},
3 std::iter::{empty, once},
4};
5
6impl Function {
7 pub fn as_exprs(&self) -> impl Iterator<Item = &Expr> {
8 #[derive(iter_enum::Iterator)]
9 enum Exprs<I0, I1, I2, I3, I4, I5, I6> {
10 Empty(I0),
11 Single(I1),
12 Double(I2),
13 Triple(I3),
14 VariableArgs(I4),
15 VariableArgsWithSingle(I5),
16 Quadruple(I6),
17 }
18
19 match self {
20 Self::Now()
21 | Function::Pi()
22 | Function::GenerateUuid()
23 | Self::Rand(None)
24 | Function::CurrentDate()
25 | Function::CurrentTime()
26 | Function::CurrentTimestamp() => Exprs::Empty(empty()),
27 Self::Lower(expr)
28 | Self::Length(expr)
29 | Self::Initcap(expr)
30 | Self::Upper(expr)
31 | Self::Sin(expr)
32 | Self::Cos(expr)
33 | Self::Tan(expr)
34 | Self::Asin(expr)
35 | Self::Acos(expr)
36 | Self::Atan(expr)
37 | Self::Radians(expr)
38 | Self::Degrees(expr)
39 | Self::Ceil(expr)
40 | Self::Rand(Some(expr))
41 | Self::Round(expr)
42 | Self::Trunc(expr)
43 | Self::Floor(expr)
44 | Self::Exp(expr)
45 | Self::Ln(expr)
46 | Self::Log2(expr)
47 | Self::Log10(expr)
48 | Self::Sqrt(expr)
49 | Self::Abs(expr)
50 | Self::Sign(expr)
51 | Self::Ascii(expr)
52 | Self::Chr(expr)
53 | Self::Md5(expr)
54 | Self::Hex(expr)
55 | Self::LastDay(expr)
56 | Self::Ltrim { expr, chars: None }
57 | Self::Rtrim { expr, chars: None }
58 | Self::Trim {
59 expr,
60 filter_chars: None,
61 ..
62 }
63 | Self::Reverse(expr)
64 | Self::Cast { expr, .. }
65 | Self::Extract { expr, .. }
66 | Self::GetX(expr)
67 | Self::GetY(expr)
68 | Self::IsEmpty(expr)
69 | Self::Sort { expr, order: None }
70 | Self::Dedup(expr)
71 | Self::Entries(expr)
72 | Self::Keys(expr)
73 | Self::Values(expr) => Exprs::Single([expr].into_iter()),
74 Self::Left { expr, size: expr2 }
75 | Self::Right { expr, size: expr2 }
76 | Self::Lpad {
77 expr,
78 size: expr2,
79 fill: None,
80 }
81 | Self::Rpad {
82 expr,
83 size: expr2,
84 fill: None,
85 }
86 | Self::Trim {
87 expr,
88 filter_chars: Some(expr2),
89 ..
90 }
91 | Self::Log {
92 antilog: expr,
93 base: expr2,
94 }
95 | Self::Div {
96 dividend: expr,
97 divisor: expr2,
98 }
99 | Self::Mod {
100 dividend: expr,
101 divisor: expr2,
102 }
103 | Self::Gcd {
104 left: expr,
105 right: expr2,
106 }
107 | Self::Lcm {
108 left: expr,
109 right: expr2,
110 }
111 | Self::Format {
112 expr,
113 format: expr2,
114 }
115 | Self::ToDate {
116 expr,
117 format: expr2,
118 }
119 | Self::ToTimestamp {
120 expr,
121 format: expr2,
122 }
123 | Self::ToTime {
124 expr,
125 format: expr2,
126 }
127 | Self::Power { expr, power: expr2 }
128 | Self::Ltrim {
129 expr,
130 chars: Some(expr2),
131 }
132 | Self::Rtrim {
133 expr,
134 chars: Some(expr2),
135 }
136 | Self::Repeat { expr, num: expr2 }
137 | Self::Substr {
138 expr,
139 start: expr2,
140 count: None,
141 }
142 | Self::IfNull { expr, then: expr2 }
143 | Self::NullIf { expr1: expr, expr2 }
144 | Self::Unwrap {
145 expr,
146 selector: expr2,
147 }
148 | Self::Position {
149 from_expr: expr2,
150 sub_expr: expr,
151 }
152 | Self::FindIdx {
153 from_expr: expr,
154 sub_expr: expr2,
155 start: None,
156 }
157 | Self::Append { expr, value: expr2 }
158 | Self::Prepend { expr, value: expr2 }
159 | Self::Skip { expr, size: expr2 }
160 | Self::Sort {
161 expr,
162 order: Some(expr2),
163 }
164 | Self::Take { expr, size: expr2 }
165 | Self::Point { x: expr, y: expr2 }
166 | Self::CalcDistance {
167 geometry1: expr,
168 geometry2: expr2,
169 }
170 | Self::AddMonth { expr, size: expr2 } => Exprs::Double([expr, expr2].into_iter()),
171
172 Self::Lpad {
173 expr,
174 size: expr2,
175 fill: Some(expr3),
176 }
177 | Self::Rpad {
178 expr,
179 size: expr2,
180 fill: Some(expr3),
181 }
182 | Self::Substr {
183 expr,
184 start: expr2,
185 count: Some(expr3),
186 }
187 | Self::Replace {
188 expr,
189 old: expr2,
190 new: expr3,
191 }
192 | Self::Slice {
193 expr,
194 start: expr2,
195 length: expr3,
196 }
197 | Self::FindIdx {
198 from_expr: expr,
199 sub_expr: expr2,
200 start: Some(expr3),
201 }
202 | Self::Splice {
203 list_data: expr,
204 begin_index: expr2,
205 end_index: expr3,
206 values: None,
207 } => Exprs::Triple([expr, expr2, expr3].into_iter()),
208 Self::Custom { name: _, exprs } => Exprs::VariableArgs(exprs.iter()),
209 Self::Coalesce(exprs) => Exprs::VariableArgs(exprs.iter()),
210 Self::Concat(exprs) => Exprs::VariableArgs(exprs.iter()),
211 Self::ConcatWs { separator, exprs } => {
212 Exprs::VariableArgsWithSingle(once(separator).chain(exprs.iter()))
213 }
214 Self::Greatest(exprs) => Exprs::VariableArgs(exprs.iter()),
215 Self::Splice {
216 list_data: expr,
217 begin_index: expr2,
218 end_index: expr3,
219 values: Some(expr4),
220 } => Exprs::Quadruple([expr, expr2, expr3, expr4].into_iter()),
221 }
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use crate::{ast::Expr, parse_sql::parse_expr, translate::translate_expr};
228
229 fn expr(sql: &str) -> Expr {
230 let parsed = parse_expr(sql).expect(sql);
231
232 translate_expr(&parsed).expect(sql)
233 }
234
235 fn test(sql: &str, expected: &[&str]) {
236 let function = match expr(sql) {
237 Expr::Function(function) => *function,
238 _ => unreachable!("only for function tests"),
239 };
240 let actual = function.as_exprs();
241 let actual = actual.collect::<Vec<_>>();
242
243 assert_eq!(actual.len(), expected.len(), "{sql}");
244
245 for (expected, actual) in expected.iter().zip(actual.into_iter()) {
246 assert_eq!(actual, &expr(expected), "{sql}");
247 }
248 }
249
250 #[test]
251 fn as_exprs() {
252 test("NOW()", &[]);
254 test("CURRENT_DATE()", &[]);
255 test("CURRENT_TIME()", &[]);
256 test("CURRENT_TIMESTAMP()", &[]);
257 test("PI()", &[]);
258 test("GENERATE_UUID()", &[]);
259 test("RAND()", &[]);
260 test("CUSTOM_FUNC()", &[]);
261
262 test("LOWER(id)", &["id"]);
264 test("INITCAP(id)", &["id"]);
265 test(r#"UPPER("Hello")"#, &[r#""Hello""#]);
266 test("SIN(3.14)", &["3.14"]);
267 test("COS(3.14)", &["3.14"]);
268 test("TAN(3.14)", &["3.14"]);
269 test("ASIN(3.14)", &["3.14"]);
270 test("ACOS(3.14)", &["3.14"]);
271 test("ATAN(3.14)", &["3.14"]);
272 test("RADIANS(180)", &["180"]);
273 test("DEGREES(3.14)", &["3.14"]);
274 test("CEIL(1.23)", &["1.23"]);
275 test("Rand(1.23)", &["1.23"]);
276 test("ROUND(1.23)", &["1.23"]);
277 test("TRUNC(1.23)", &["1.23"]);
278 test("FLOOR(1.23)", &["1.23"]);
279 test("EXP(1.23)", &["1.23"]);
280 test("LN(col + 1)", &["col + 1"]);
281 test("LOG2(16)", &["16"]);
282 test("LOG10(150 - 50)", &["150 - 50"]);
283 test("SQRT(144)", &["144"]);
284 test("LASTDAY(DATE '2020-01-01')", &[r#"DATE '2020-01-01'"#]);
285 test(r#"LTRIM(" hello")"#, &[r#"" hello""#]);
286 test(r#"RTRIM("world ")"#, &[r#""world ""#]);
287 test(r#"TRIM(" rust ")"#, &[r#"" rust ""#]);
288 test(r#"REVERSE("abcde")"#, &[r#""abcde""#]);
289 test(r#"CAST(1 AS BOOLEAN)"#, &["1"]);
290 test(r#"IS_EMPTY(col)"#, &["col"]);
291 test(r#"VALUES(col)"#, &["col"]);
292 test(r#"HEX(10)"#, &["10"]);
293
294 test(r#"ABS(1)"#, &["1"]);
295 test(r#"ABS(-1)"#, &["-1"]);
296 test(r#"ABS(2)"#, &["2"]);
297 test(r#"ABS(-2)"#, &["-2"]);
298 test(r#"ABS(3.0)"#, &["3.0"]);
299 test(r#"ABS(-3.0)"#, &["-3.0"]);
300
301 test(r#"SIGN(1)"#, &["1"]);
302 test(r#"SIGN(-1)"#, &["-1"]);
303 test(r#"SIGN(2)"#, &["2"]);
304 test(r#"SIGN(-2)"#, &["-2"]);
305 test(r#"SIGN(3.0)"#, &["3.0"]);
306 test(r#"SIGN(-3.0)"#, &["-3.0"]);
307
308 test(r#"DEDUP(list)"#, &["list"]);
309
310 test(r#"LEFT("hello", 2)"#, &[r#""hello""#, "2"]);
312 test(r#"RIGHT("hello", 2)"#, &[r#""hello""#, "2"]);
313 test(r#"FIND_IDX("Calzone", "zone")"#, &[r#"Calzone"#, r#"zone"#]);
314 test(r#"TAKE(list, 3)"#, &[r#"list"#, r#"3"#]);
315 test(r#"LPAD(value, 5)"#, &["value", "5"]);
316 test(r#"RPAD(value, 5)"#, &["value", "5"]);
317 test(
318 r#"TRIM(LEADING "_" FROM "__hello")"#,
319 &[r#""__hello""#, r#""_""#],
320 );
321 test("LOG(rate, 2)", &["rate", "2"]);
322 test("DIV(6, 2)", &["6", "2"]);
323 test("MOD(6, 2)", &["6", "2"]);
324 test("GCD(6, 2)", &["6", "2"]);
325 test("LCM(6, 2)", &["6", "2"]);
326 test("POWER(base, 10)", &["base", "10"]);
327 test(r#"LTRIM(name, "xyz")"#, &["name", r#""xyz""#]);
328 test(r#"RTRIM(name, "xyz")"#, &["name", r#""xyz""#]);
329 test("REPEAT(col || col2, 3)", &["col || col2", "3"]);
330 test("REPEAT(column, 2)", &["column", "2"]);
331 test(r#"UNWRAP(field, "foo.1")"#, &["field", r#""foo.1""#]);
332 test(r#"SKIP(list, 2)"#, &[r#""list""#, r#"2"#]);
333
334 test(
336 r#"LPAD(name, 20, '>")++++<')"#,
337 &["name", "20", r#"'>")++++<'"#],
338 );
339 test(
340 r#"RPAD(name, 20, '>")++++<')"#,
341 &["name", "20", r#"'>")++++<'"#],
342 );
343 test(
344 r#"SUBSTR(' >++++("< ', 3, 11)"#,
345 &[r#"' >++++("< '"#, "3", "11"],
346 );
347 test(r#"SPLICE(list, 2, 4)"#, &["list", "2", "4"]);
348
349 test(
351 r#"SPLICE(list, 3, 5, values)"#,
352 &["list", "3", "5", "values"],
353 );
354
355 test(r#"COALESCE("test")"#, &[r#""test""#]);
357
358 test(r#"COALESCE(NULL, "test")"#, &["NULL", r#""test""#]);
359
360 test(r#"CONCAT("abc")"#, &[r#""abc""#]);
361
362 test(r#"CONCAT("abc", "123")"#, &[r#""abc""#, r#""123""#]);
363
364 test(r#"CONCAT("a", "b", "c")"#, &[r#""a""#, r#""b""#, r#""c""#]);
365
366 test(
367 r#"CUSTOM_FUNC("a", "b", "c")"#,
368 &[r#""a""#, r#""b""#, r#""c""#],
369 );
370
371 test(
372 r#"CONCAT("gluesql", " ", "is", " ", "cool")"#,
373 &[r#""gluesql""#, r#"" ""#, r#""is""#, r#"" ""#, r#""cool""#],
374 );
375
376 test(r#"POSITION("men" IN "ramen")"#, &[r#""men""#, r#""ramen""#]);
377 test(r#"POSITION("men" IN ramen)"#, &[r#""men""#, "ramen"]);
378
379 test(
381 r#"CONCAT_WS(",", "gluesql", "is", "cool")"#,
382 &[r#"",""#, r#""gluesql""#, r#""is""#, r#""cool""#],
383 );
384 }
385}