1use {
2 super::{DataType, DateTimeField, Expr, ast_literal::TrimWhereField},
3 crate::ast::ToSql,
4 serde::{Deserialize, Serialize},
5 strum_macros::Display,
6};
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Display)]
9#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
10pub enum Function {
11 Abs(Expr),
12 AddMonth {
13 expr: Expr,
14 size: Expr,
15 },
16 Lower(Expr),
17 Initcap(Expr),
18 Upper(Expr),
19 Left {
20 expr: Expr,
21 size: Expr,
22 },
23 Right {
24 expr: Expr,
25 size: Expr,
26 },
27 Asin(Expr),
28 Acos(Expr),
29 Atan(Expr),
30 Lpad {
31 expr: Expr,
32 size: Expr,
33 fill: Option<Expr>,
34 },
35 Rpad {
36 expr: Expr,
37 size: Expr,
38 fill: Option<Expr>,
39 },
40 Replace {
41 expr: Expr,
42 old: Expr,
43 new: Expr,
44 },
45 Cast {
46 expr: Expr,
47 data_type: DataType,
48 },
49 Ceil(Expr),
50 Coalesce(Vec<Expr>),
51 Concat(Vec<Expr>),
52 ConcatWs {
53 separator: Expr,
54 exprs: Vec<Expr>,
55 },
56 Custom {
57 name: String,
58 exprs: Vec<Expr>,
59 },
60 IfNull {
61 expr: Expr,
62 then: Expr,
63 },
64 NullIf {
65 expr1: Expr,
66 expr2: Expr,
67 },
68 Rand(Option<Expr>),
69 Round(Expr),
70 Trunc(Expr),
71 Floor(Expr),
72 Trim {
73 expr: Expr,
74 filter_chars: Option<Expr>,
75 trim_where_field: Option<TrimWhereField>,
76 },
77 Exp(Expr),
78 Extract {
79 field: DateTimeField,
80 expr: Expr,
81 },
82 Ln(Expr),
83 Log {
84 antilog: Expr,
85 base: Expr,
86 },
87 Log2(Expr),
88 Log10(Expr),
89 Div {
90 dividend: Expr,
91 divisor: Expr,
92 },
93 Mod {
94 dividend: Expr,
95 divisor: Expr,
96 },
97 Gcd {
98 left: Expr,
99 right: Expr,
100 },
101 Lcm {
102 left: Expr,
103 right: Expr,
104 },
105 Sin(Expr),
106 Cos(Expr),
107 Tan(Expr),
108 Sqrt(Expr),
109 Power {
110 expr: Expr,
111 power: Expr,
112 },
113 Radians(Expr),
114 Degrees(Expr),
115 Now(),
116 CurrentDate(),
117 CurrentTime(),
118 CurrentTimestamp(),
119 Pi(),
120 LastDay(Expr),
121 Ltrim {
122 expr: Expr,
123 chars: Option<Expr>,
124 },
125 Rtrim {
126 expr: Expr,
127 chars: Option<Expr>,
128 },
129 Reverse(Expr),
130 Repeat {
131 expr: Expr,
132 num: Expr,
133 },
134 Sign(Expr),
135 Substr {
136 expr: Expr,
137 start: Expr,
138 count: Option<Expr>,
139 },
140 Unwrap {
141 expr: Expr,
142 selector: Expr,
143 },
144 GenerateUuid(),
145 Greatest(Vec<Expr>),
146 Format {
147 expr: Expr,
148 format: Expr,
149 },
150 ToDate {
151 expr: Expr,
152 format: Expr,
153 },
154 ToTimestamp {
155 expr: Expr,
156 format: Expr,
157 },
158 ToTime {
159 expr: Expr,
160 format: Expr,
161 },
162 Position {
163 from_expr: Expr,
164 sub_expr: Expr,
165 },
166 FindIdx {
167 from_expr: Expr,
168 sub_expr: Expr,
169 start: Option<Expr>,
170 },
171 Ascii(Expr),
172 Chr(Expr),
173 Md5(Expr),
174 Hex(Expr),
175 Append {
176 expr: Expr,
177 value: Expr,
178 },
179 Sort {
180 expr: Expr,
181 order: Option<Expr>,
182 },
183 Slice {
184 expr: Expr,
185 start: Expr,
186 length: Expr,
187 },
188 Prepend {
189 expr: Expr,
190 value: Expr,
191 },
192 Skip {
193 expr: Expr,
194 size: Expr,
195 },
196 Take {
197 expr: Expr,
198 size: Expr,
199 },
200 GetX(Expr),
201 GetY(Expr),
202 Point {
203 x: Expr,
204 y: Expr,
205 },
206 CalcDistance {
207 geometry1: Expr,
208 geometry2: Expr,
209 },
210 IsEmpty(Expr),
211 Length(Expr),
212 Entries(Expr),
213 Keys(Expr),
214 Values(Expr),
215 Splice {
216 list_data: Expr,
217 begin_index: Expr,
218 end_index: Expr,
219 values: Option<Expr>,
220 },
221 Dedup(Expr),
222}
223
224impl ToSql for Function {
225 fn to_sql(&self) -> String {
226 match self {
227 Function::Abs(e) => format!("ABS({})", e.to_sql()),
228 Function::AddMonth { expr, size } => {
229 format!("ADD_MONTH({},{})", expr.to_sql(), size.to_sql())
230 }
231 Function::Initcap(e) => format!("INITCAP({})", e.to_sql()),
232 Function::Lower(e) => format!("LOWER({})", e.to_sql()),
233 Function::Upper(e) => format!("UPPER({})", e.to_sql()),
234 Function::Left { expr, size } => format!("LEFT({}, {})", expr.to_sql(), size.to_sql()),
235 Function::Right { expr, size } => {
236 format!("RIGHT({}, {})", expr.to_sql(), size.to_sql())
237 }
238 Function::Asin(e) => format!("ASIN({})", e.to_sql()),
239 Function::Acos(e) => format!("ACOS({})", e.to_sql()),
240 Function::Atan(e) => format!("ATAN({})", e.to_sql()),
241 Function::Lpad { expr, size, fill } => match fill {
242 None => format!("LPAD({}, {})", expr.to_sql(), size.to_sql()),
243 Some(fill) => format!(
244 "LPAD({}, {}, {})",
245 expr.to_sql(),
246 size.to_sql(),
247 fill.to_sql()
248 ),
249 },
250 Function::Rpad { expr, size, fill } => match fill {
251 None => format!("RPAD({}, {})", expr.to_sql(), size.to_sql()),
252 Some(fill) => format!(
253 "RPAD({}, {}, {})",
254 expr.to_sql(),
255 size.to_sql(),
256 fill.to_sql()
257 ),
258 },
259 Function::Cast { expr, data_type } => {
260 format!("CAST({} AS {data_type})", expr.to_sql())
261 }
262 Function::Ceil(e) => format!("CEIL({})", e.to_sql()),
263 Function::Coalesce(items) => {
264 let items = items
265 .iter()
266 .map(ToSql::to_sql)
267 .collect::<Vec<_>>()
268 .join(", ");
269 format!("COALESCE({items})")
270 }
271 Function::Concat(items) => {
272 let items = items
273 .iter()
274 .map(ToSql::to_sql)
275 .collect::<Vec<_>>()
276 .join(", ");
277 format!("CONCAT({items})")
278 }
279 Function::Custom { name, exprs } => {
280 let exprs = exprs
281 .iter()
282 .map(ToSql::to_sql)
283 .collect::<Vec<_>>()
284 .join(", ");
285 format!("{name}({exprs})")
286 }
287 Function::ConcatWs { separator, exprs } => {
288 let exprs = exprs
289 .iter()
290 .map(ToSql::to_sql)
291 .collect::<Vec<_>>()
292 .join(", ");
293 format!("CONCAT_WS({}, {})", separator.to_sql(), exprs)
294 }
295 Function::IfNull { expr, then } => {
296 format!("IFNULL({}, {})", expr.to_sql(), then.to_sql())
297 }
298 Function::NullIf { expr1, expr2 } => {
299 format!("NULLIF({}, {})", expr1.to_sql(), expr2.to_sql())
300 }
301 Function::Rand(e) => match e {
302 Some(v) => format!("RAND({})", v.to_sql()),
303 None => "RAND()".to_owned(),
304 },
305 Function::Round(e) => format!("ROUND({})", e.to_sql()),
306 Function::Trunc(e) => format!("TRUNC({})", e.to_sql()),
307 Function::Floor(e) => format!("FLOOR({})", e.to_sql()),
308 Function::Trim {
309 expr,
310 filter_chars,
311 trim_where_field,
312 } => {
313 let trim_where_field = match trim_where_field {
314 None => "".to_owned(),
315 Some(t) => format!("{t} "),
316 };
317
318 match filter_chars {
319 None => format!("TRIM({}{})", trim_where_field, expr.to_sql()),
320 Some(filter_chars) => format!(
321 "TRIM({}{} FROM {})",
322 trim_where_field,
323 filter_chars.to_sql(),
324 expr.to_sql()
325 ),
326 }
327 }
328 Function::Exp(e) => format!("EXP({})", e.to_sql()),
329 Function::Ln(e) => format!("LN({})", e.to_sql()),
330 Function::Log { antilog, base } => {
331 format!("LOG({}, {})", antilog.to_sql(), base.to_sql())
332 }
333 Function::Log2(e) => format!("LOG2({})", e.to_sql()),
334 Function::Log10(e) => format!("LOG10({})", e.to_sql()),
335 Function::Div { dividend, divisor } => {
336 format!("DIV({}, {})", dividend.to_sql(), divisor.to_sql())
337 }
338 Function::Mod { dividend, divisor } => {
339 format!("MOD({}, {})", dividend.to_sql(), divisor.to_sql())
340 }
341 Function::Gcd { left, right } => format!("GCD({}, {})", left.to_sql(), right.to_sql()),
342 Function::Lcm { left, right } => format!("LCM({}, {})", left.to_sql(), right.to_sql()),
343 Function::Sin(e) => format!("SIN({})", e.to_sql()),
344 Function::Cos(e) => format!("COS({})", e.to_sql()),
345 Function::Tan(e) => format!("TAN({})", e.to_sql()),
346 Function::Sqrt(e) => format!("SQRT({})", e.to_sql()),
347 Function::Power { expr, power } => {
348 format!("POWER({}, {})", expr.to_sql(), power.to_sql())
349 }
350 Function::Radians(e) => format!("RADIANS({})", e.to_sql()),
351 Function::Degrees(e) => format!("DEGREES({})", e.to_sql()),
352 Function::Now() => "NOW()".to_owned(),
353 Function::CurrentDate() => "CURRENT_DATE()".to_owned(),
354 Function::CurrentTime() => "CURRENT_TIME()".to_owned(),
355 Function::CurrentTimestamp() => "CURRENT_TIMESTAMP()".to_owned(),
356 Function::Pi() => "PI()".to_owned(),
357 Function::LastDay(expr) => format!("LAST_DAY({})", expr.to_sql()),
358 Function::Ltrim { expr, chars } => match chars {
359 None => format!("LTRIM({})", expr.to_sql()),
360 Some(chars) => format!("LTRIM({}, {})", expr.to_sql(), chars.to_sql()),
361 },
362 Function::Rtrim { expr, chars } => match chars {
363 None => format!("RTRIM({})", expr.to_sql()),
364 Some(chars) => format!("RTRIM({}, {})", expr.to_sql(), chars.to_sql()),
365 },
366 Function::Reverse(e) => format!("REVERSE({})", e.to_sql()),
367 Function::Repeat { expr, num } => {
368 format!("REPEAT({}, {})", expr.to_sql(), num.to_sql())
369 }
370 Function::Replace { expr, old, new } => format!(
371 "REPLACE({},{},{})",
372 expr.to_sql(),
373 old.to_sql(),
374 new.to_sql()
375 ),
376
377 Function::Sign(e) => format!("SIGN({})", e.to_sql()),
378 Function::Substr { expr, start, count } => match count {
379 None => format!("SUBSTR({}, {})", expr.to_sql(), start.to_sql()),
380 Some(count) => format!(
381 "SUBSTR({}, {}, {})",
382 expr.to_sql(),
383 start.to_sql(),
384 count.to_sql()
385 ),
386 },
387 Function::Unwrap { expr, selector } => {
388 format!("UNWRAP({}, {})", expr.to_sql(), selector.to_sql())
389 }
390 Function::GenerateUuid() => "GENERATE_UUID()".to_owned(),
391 Function::Greatest(items) => {
392 let items = items
393 .iter()
394 .map(ToSql::to_sql)
395 .collect::<Vec<_>>()
396 .join(", ");
397 format!("GREATEST({items})")
398 }
399 Function::Format { expr, format } => {
400 format!("FORMAT({}, {})", expr.to_sql(), format.to_sql())
401 }
402 Function::ToDate { expr, format } => {
403 format!("TO_DATE({}, {})", expr.to_sql(), format.to_sql())
404 }
405 Function::ToTimestamp { expr, format } => {
406 format!("TO_TIMESTAMP({}, {})", expr.to_sql(), format.to_sql())
407 }
408 Function::ToTime { expr, format } => {
409 format!("TO_TIME({}, {})", expr.to_sql(), format.to_sql())
410 }
411 Function::Position {
412 from_expr,
413 sub_expr,
414 } => format!("POSITION({} IN {})", sub_expr.to_sql(), from_expr.to_sql()),
415 Function::FindIdx {
416 from_expr,
417 sub_expr,
418 start,
419 } => match start {
420 None => format!("FIND_IDX({}, {})", from_expr.to_sql(), sub_expr.to_sql()),
421 Some(start_expr) => format!(
422 "FIND_IDX({}, {}, {})",
423 from_expr.to_sql(),
424 sub_expr.to_sql(),
425 start_expr.to_sql()
426 ),
427 },
428 Function::Extract { field, expr } => {
429 format!("EXTRACT({field} FROM {})", expr.to_sql())
430 }
431 Function::Ascii(e) => format!("ASCII({})", e.to_sql()),
432 Function::Chr(e) => format!("CHR({})", e.to_sql()),
433 Function::Md5(e) => format!("MD5({})", e.to_sql()),
434 Function::Hex(e) => format!("HEX({})", e.to_sql()),
435 Function::Append { expr, value } => {
436 format!(
437 "APPEND({items}, {value})",
438 items = expr.to_sql(),
439 value = value.to_sql()
440 )
441 }
442 Function::Prepend { expr, value } => {
443 format! {
444 "PREPEND({items}, {value})",
445 items = expr.to_sql(),
446 value = value.to_sql()
447 }
448 }
449 Function::Skip { expr, size } => {
450 format!("SKIP({}, {})", expr.to_sql(), size.to_sql())
451 }
452 Function::Sort { expr, order } => match order {
453 None => format!("SORT({})", expr.to_sql()),
454 Some(order) => {
455 format!("SORT({}, {})", expr.to_sql(), order.to_sql())
456 }
457 },
458 Function::Slice {
459 expr,
460 start,
461 length,
462 } => {
463 format!(
464 "SLICE({}, {}, {})",
465 expr.to_sql(),
466 start.to_sql(),
467 length.to_sql()
468 )
469 }
470 Function::Take { expr, size } => {
471 format!("TAKE({}, {})", expr.to_sql(), size.to_sql())
472 }
473 Function::GetX(e) => format!("GET_X({})", e.to_sql()),
474 Function::GetY(e) => format!("GET_Y({})", e.to_sql()),
475 Function::Point { x, y } => format!("POINT({}, {})", x.to_sql(), y.to_sql()),
476 Function::CalcDistance {
477 geometry1,
478 geometry2,
479 } => {
480 format!(
481 "CALC_DISTANCE({}, {})",
482 geometry1.to_sql(),
483 geometry2.to_sql()
484 )
485 }
486 Function::IsEmpty(e) => format!("IS_EMPTY({})", e.to_sql()),
487 Function::Length(e) => format!("LENGTH({})", e.to_sql()),
488 Function::Entries(e) => format!("ENTRIES({})", e.to_sql()),
489 Function::Keys(e) => format!("KEYS({})", e.to_sql()),
490 Function::Values(e) => format!("VALUES({})", e.to_sql()),
491 Function::Splice {
492 list_data,
493 begin_index,
494 end_index,
495 values,
496 } => match values {
497 Some(v) => format!(
498 "SPLICE({}, {}, {}, {})",
499 list_data.to_sql(),
500 begin_index.to_sql(),
501 end_index.to_sql(),
502 v.to_sql()
503 ),
504 None => format!(
505 "SPLICE({}, {}, {})",
506 list_data.to_sql(),
507 begin_index.to_sql(),
508 end_index.to_sql(),
509 ),
510 },
511 Function::Dedup(list) => format!("DEDUP({})", list.to_sql()),
512 }
513 }
514}
515
516#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
517pub enum AggregateFunction {
518 Count(CountArgExpr),
519 Sum(Expr),
520 Max(Expr),
521 Min(Expr),
522 Avg(Expr),
523 Variance(Expr),
524 Stdev(Expr),
525}
526
527#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
528pub struct Aggregate {
529 pub func: AggregateFunction,
530 pub distinct: bool,
531}
532
533impl Aggregate {
534 pub fn new(func: AggregateFunction, distinct: bool) -> Self {
535 Self { func, distinct }
536 }
537
538 pub fn count(expr: CountArgExpr, distinct: bool) -> Self {
539 Self::new(AggregateFunction::Count(expr), distinct)
540 }
541
542 pub fn sum(expr: Expr, distinct: bool) -> Self {
543 Self::new(AggregateFunction::Sum(expr), distinct)
544 }
545
546 pub fn max(expr: Expr, distinct: bool) -> Self {
547 Self::new(AggregateFunction::Max(expr), distinct)
548 }
549
550 pub fn min(expr: Expr, distinct: bool) -> Self {
551 Self::new(AggregateFunction::Min(expr), distinct)
552 }
553
554 pub fn avg(expr: Expr, distinct: bool) -> Self {
555 Self::new(AggregateFunction::Avg(expr), distinct)
556 }
557
558 pub fn variance(expr: Expr, distinct: bool) -> Self {
559 Self::new(AggregateFunction::Variance(expr), distinct)
560 }
561
562 pub fn stdev(expr: Expr, distinct: bool) -> Self {
563 Self::new(AggregateFunction::Stdev(expr), distinct)
564 }
565}
566
567impl AggregateFunction {
568 fn to_sql_with_distinct(&self, distinct: bool) -> String {
569 let (name, arg) = match self {
570 AggregateFunction::Count(expr) => ("COUNT", expr.to_sql()),
571 AggregateFunction::Sum(expr) => ("SUM", expr.to_sql()),
572 AggregateFunction::Max(expr) => ("MAX", expr.to_sql()),
573 AggregateFunction::Min(expr) => ("MIN", expr.to_sql()),
574 AggregateFunction::Avg(expr) => ("AVG", expr.to_sql()),
575 AggregateFunction::Variance(expr) => ("VARIANCE", expr.to_sql()),
576 AggregateFunction::Stdev(expr) => ("STDEV", expr.to_sql()),
577 };
578 if distinct {
579 format!("{name}(DISTINCT {arg})")
580 } else {
581 format!("{name}({arg})")
582 }
583 }
584}
585
586impl ToSql for Aggregate {
587 fn to_sql(&self) -> String {
588 self.func.to_sql_with_distinct(self.distinct)
589 }
590}
591
592#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
593pub enum CountArgExpr {
594 Expr(Expr),
595 Wildcard,
596}
597
598impl ToSql for CountArgExpr {
599 fn to_sql(&self) -> String {
600 match self {
601 CountArgExpr::Expr(e) => e.to_sql(),
602 CountArgExpr::Wildcard => "*".to_owned(),
603 }
604 }
605}
606
607#[cfg(test)]
608mod tests {
609 use {
610 crate::ast::{
611 Aggregate, AstLiteral, CountArgExpr, DataType, DateTimeField, Expr, Function, ToSql,
612 TrimWhereField,
613 },
614 bigdecimal::BigDecimal,
615 std::str::FromStr,
616 };
617
618 #[test]
619 fn to_sql_function() {
620 assert_eq!(
621 r#"ABS("num")"#,
622 &Expr::Function(Box::new(Function::Abs(Expr::Identifier("num".to_owned())))).to_sql()
623 );
624
625 assert_eq!(
626 "LOWER('Bye')",
627 &Expr::Function(Box::new(Function::Lower(Expr::Literal(
628 AstLiteral::QuotedString("Bye".to_owned())
629 ))))
630 .to_sql()
631 );
632
633 assert_eq!(
634 "INITCAP('Bye')",
635 &Expr::Function(Box::new(Function::Initcap(Expr::Literal(
636 AstLiteral::QuotedString("Bye".to_owned())
637 ))))
638 .to_sql()
639 );
640
641 assert_eq!(
642 "UPPER('Hi')",
643 &Expr::Function(Box::new(Function::Upper(Expr::Literal(
644 AstLiteral::QuotedString("Hi".to_owned())
645 ))))
646 .to_sql()
647 );
648
649 assert_eq!(
650 "LEFT('GlueSQL', 2)",
651 &Expr::Function(Box::new(Function::Left {
652 expr: Expr::Literal(AstLiteral::QuotedString("GlueSQL".to_owned())),
653 size: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("2").unwrap()))
654 }))
655 .to_sql()
656 );
657
658 assert_eq!(
659 "RIGHT('GlueSQL', 3)",
660 &Expr::Function(Box::new(Function::Right {
661 expr: Expr::Literal(AstLiteral::QuotedString("GlueSQL".to_owned())),
662 size: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("3").unwrap()))
663 }))
664 .to_sql()
665 );
666
667 assert_eq!(
668 "ASIN(2)",
669 &Expr::Function(Box::new(Function::Asin(Expr::Literal(AstLiteral::Number(
670 BigDecimal::from_str("2").unwrap()
671 )))))
672 .to_sql()
673 );
674
675 assert_eq!(
676 "ACOS(2)",
677 &Expr::Function(Box::new(Function::Acos(Expr::Literal(AstLiteral::Number(
678 BigDecimal::from_str("2").unwrap()
679 )))))
680 .to_sql()
681 );
682
683 assert_eq!(
684 "ATAN(2)",
685 &Expr::Function(Box::new(Function::Atan(Expr::Literal(AstLiteral::Number(
686 BigDecimal::from_str("2").unwrap()
687 )))))
688 .to_sql()
689 );
690
691 assert_eq!(
692 "LPAD('GlueSQL', 2)",
693 &Expr::Function(Box::new(Function::Lpad {
694 expr: Expr::Literal(AstLiteral::QuotedString("GlueSQL".to_owned())),
695 size: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("2").unwrap())),
696 fill: None
697 }))
698 .to_sql()
699 );
700
701 assert_eq!(
702 "LPAD('GlueSQL', 10, 'Go')",
703 &Expr::Function(Box::new(Function::Lpad {
704 expr: Expr::Literal(AstLiteral::QuotedString("GlueSQL".to_owned())),
705 size: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("10").unwrap())),
706 fill: Some(Expr::Literal(AstLiteral::QuotedString("Go".to_owned())))
707 }))
708 .to_sql()
709 );
710
711 assert_eq!(
712 "RPAD('GlueSQL', 10)",
713 &Expr::Function(Box::new(Function::Rpad {
714 expr: Expr::Literal(AstLiteral::QuotedString("GlueSQL".to_owned())),
715 size: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("10").unwrap())),
716 fill: None
717 }))
718 .to_sql()
719 );
720
721 assert_eq!(
722 "RPAD('GlueSQL', 10, 'Go')",
723 &Expr::Function(Box::new(Function::Rpad {
724 expr: Expr::Literal(AstLiteral::QuotedString("GlueSQL".to_owned())),
725 size: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("10").unwrap())),
726 fill: Some(Expr::Literal(AstLiteral::QuotedString("Go".to_owned())))
727 }))
728 .to_sql()
729 );
730
731 assert_eq!(
732 "CAST(1.0 AS INT)",
733 &Expr::Function(Box::new(Function::Cast {
734 expr: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("1.0").unwrap())),
735 data_type: DataType::Int
736 }))
737 .to_sql()
738 );
739
740 assert_eq!(
741 r#"CEIL("num")"#,
742 &Expr::Function(Box::new(Function::Ceil(Expr::Identifier("num".to_owned())))).to_sql()
743 );
744
745 assert_eq!(
746 r#"CUSTOM_FUNC("Tic", 1, "num", 'abc')"#,
747 &Expr::Function(Box::new(Function::Custom {
748 name: "CUSTOM_FUNC".to_owned(),
749 exprs: vec![
750 Expr::Identifier("Tic".to_owned()),
751 Expr::Literal(AstLiteral::Number(BigDecimal::from_str("1").unwrap())),
752 Expr::Identifier("num".to_owned()),
753 Expr::Literal(AstLiteral::QuotedString("abc".to_owned()))
754 ]
755 }))
756 .to_sql()
757 );
758 assert_eq!(
759 r#"CUSTOM_FUNC("num")"#,
760 &Expr::Function(Box::new(Function::Custom {
761 name: "CUSTOM_FUNC".to_owned(),
762 exprs: vec![Expr::Identifier("num".to_owned())]
763 }))
764 .to_sql()
765 );
766 assert_eq!(
767 "CUSTOM_FUNC()",
768 &Expr::Function(Box::new(Function::Custom {
769 name: "CUSTOM_FUNC".to_owned(),
770 exprs: vec![]
771 }))
772 .to_sql()
773 );
774
775 assert_eq!(
776 r#"COALESCE("First", NULL, "Last")"#,
777 &Expr::Function(Box::new(Function::Coalesce(vec![
778 Expr::Identifier("First".to_owned()),
779 Expr::Literal(AstLiteral::Null),
780 Expr::Identifier("Last".to_owned()),
781 ])))
782 .to_sql()
783 );
784
785 assert_eq!(
786 "CONCAT(\"Tic\", \"tac\", \"toe\")",
787 &Expr::Function(Box::new(Function::Concat(vec![
788 Expr::Identifier("Tic".to_owned()),
789 Expr::Identifier("tac".to_owned()),
790 Expr::Identifier("toe".to_owned())
791 ])))
792 .to_sql()
793 );
794
795 assert_eq!(
796 r#"CONCAT_WS('-', "Tic", "tac", "toe")"#,
797 &Expr::Function(Box::new(Function::ConcatWs {
798 separator: Expr::Literal(AstLiteral::QuotedString("-".to_owned())),
799 exprs: vec![
800 Expr::Identifier("Tic".to_owned()),
801 Expr::Identifier("tac".to_owned()),
802 Expr::Identifier("toe".to_owned())
803 ]
804 }))
805 .to_sql()
806 );
807
808 assert_eq!(
809 "REPLACE('Mticky GlueMQL','M','S')",
810 &Expr::Function(Box::new(Function::Replace {
811 expr: Expr::Literal(AstLiteral::QuotedString("Mticky GlueMQL".to_owned())),
812 old: Expr::Literal(AstLiteral::QuotedString("M".to_owned())),
813 new: Expr::Literal(AstLiteral::QuotedString("S".to_owned()))
814 }))
815 .to_sql()
816 );
817 assert_eq!(
818 r#"IFNULL("updated_at", "created_at")"#,
819 &Expr::Function(Box::new(Function::IfNull {
820 expr: Expr::Identifier("updated_at".to_owned()),
821 then: Expr::Identifier("created_at".to_owned())
822 }))
823 .to_sql()
824 );
825
826 assert_eq!(
827 r#"NULLIF("updated_at", "created_at")"#,
828 &Expr::Function(Box::new(Function::NullIf {
829 expr1: Expr::Identifier("updated_at".to_owned()),
830 expr2: Expr::Identifier("created_at".to_owned())
831 }))
832 .to_sql()
833 );
834
835 assert_eq!(
836 "RAND()",
837 &Expr::Function(Box::new(Function::Rand(None))).to_sql()
838 );
839
840 assert_eq!(
841 r#"RAND("num")"#,
842 &Expr::Function(Box::new(Function::Rand(Some(Expr::Identifier(
843 "num".to_owned()
844 )))))
845 .to_sql()
846 );
847
848 assert_eq!(
849 r#"ROUND("num")"#,
850 &Expr::Function(Box::new(Function::Round(Expr::Identifier(
851 "num".to_owned()
852 ))))
853 .to_sql()
854 );
855
856 assert_eq!(
857 r#"TRUNC("num")"#,
858 &Expr::Function(Box::new(Function::Trunc(Expr::Identifier(
859 "num".to_owned()
860 ))))
861 .to_sql()
862 );
863
864 assert_eq!(
865 r#"FLOOR("num")"#,
866 &Expr::Function(Box::new(Function::Floor(Expr::Identifier(
867 "num".to_owned()
868 ))))
869 .to_sql()
870 );
871
872 assert_eq!(
873 r#"TRIM("name")"#,
874 &Expr::Function(Box::new(Function::Trim {
875 expr: Expr::Identifier("name".to_owned()),
876 filter_chars: None,
877 trim_where_field: None
878 }))
879 .to_sql()
880 );
881
882 assert_eq!(
883 r#"TRIM('*' FROM "name")"#,
884 &Expr::Function(Box::new(Function::Trim {
885 expr: Expr::Identifier("name".to_owned()),
886 filter_chars: Some(Expr::Literal(AstLiteral::QuotedString("*".to_owned()))),
887 trim_where_field: None
888 }))
889 .to_sql()
890 );
891
892 assert_eq!(
893 r#"TRIM(BOTH '*' FROM "name")"#,
894 &Expr::Function(Box::new(Function::Trim {
895 expr: Expr::Identifier("name".to_owned()),
896 filter_chars: Some(Expr::Literal(AstLiteral::QuotedString("*".to_owned()))),
897 trim_where_field: Some(TrimWhereField::Both)
898 }))
899 .to_sql()
900 );
901
902 assert_eq!(
903 r#"TRIM(LEADING '*' FROM "name")"#,
904 &Expr::Function(Box::new(Function::Trim {
905 expr: Expr::Identifier("name".to_owned()),
906 filter_chars: Some(Expr::Literal(AstLiteral::QuotedString("*".to_owned()))),
907 trim_where_field: Some(TrimWhereField::Leading)
908 }))
909 .to_sql()
910 );
911
912 assert_eq!(
913 r#"TRIM(LEADING "name")"#,
914 &Expr::Function(Box::new(Function::Trim {
915 expr: Expr::Identifier("name".to_owned()),
916 filter_chars: None,
917 trim_where_field: Some(TrimWhereField::Leading)
918 }))
919 .to_sql()
920 );
921
922 assert_eq!(
923 "EXP(1)",
924 &Expr::Function(Box::new(Function::Exp(Expr::Literal(AstLiteral::Number(
925 BigDecimal::from_str("1").unwrap()
926 )))))
927 .to_sql()
928 );
929
930 assert_eq!(
931 "LN(1)",
932 &Expr::Function(Box::new(Function::Ln(Expr::Literal(AstLiteral::Number(
933 BigDecimal::from_str("1").unwrap()
934 )))))
935 .to_sql()
936 );
937
938 assert_eq!(
939 "LOG(64, 8)",
940 &Expr::Function(Box::new(Function::Log {
941 antilog: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("64").unwrap())),
942 base: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("8").unwrap()))
943 }))
944 .to_sql()
945 );
946
947 assert_eq!(
948 r#"LOG2("num")"#,
949 &Expr::Function(Box::new(Function::Log2(Expr::Identifier("num".to_owned())))).to_sql()
950 );
951
952 assert_eq!(
953 r#"LOG10("num")"#,
954 &Expr::Function(Box::new(Function::Log10(Expr::Identifier(
955 "num".to_owned()
956 ))))
957 .to_sql()
958 );
959
960 assert_eq!(
961 "DIV(64, 8)",
962 &Expr::Function(Box::new(Function::Div {
963 dividend: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("64").unwrap())),
964 divisor: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("8").unwrap()))
965 }))
966 .to_sql()
967 );
968
969 assert_eq!(
970 "MOD(64, 8)",
971 &Expr::Function(Box::new(Function::Mod {
972 dividend: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("64").unwrap())),
973 divisor: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("8").unwrap()))
974 }))
975 .to_sql()
976 );
977
978 assert_eq!(
979 "GCD(64, 8)",
980 &Expr::Function(Box::new(Function::Gcd {
981 left: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("64").unwrap())),
982 right: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("8").unwrap()))
983 }))
984 .to_sql()
985 );
986
987 assert_eq!(
988 "LCM(64, 8)",
989 &Expr::Function(Box::new(Function::Lcm {
990 left: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("64").unwrap())),
991 right: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("8").unwrap()))
992 }))
993 .to_sql()
994 );
995
996 assert_eq!(
997 "SIN(2)",
998 &Expr::Function(Box::new(Function::Sin(Expr::Literal(AstLiteral::Number(
999 BigDecimal::from_str("2").unwrap()
1000 )))))
1001 .to_sql()
1002 );
1003
1004 assert_eq!(
1005 "COS(2)",
1006 &Expr::Function(Box::new(Function::Cos(Expr::Literal(AstLiteral::Number(
1007 BigDecimal::from_str("2").unwrap()
1008 )))))
1009 .to_sql()
1010 );
1011
1012 assert_eq!(
1013 "TAN(2)",
1014 &Expr::Function(Box::new(Function::Tan(Expr::Literal(AstLiteral::Number(
1015 BigDecimal::from_str("2").unwrap()
1016 )))))
1017 .to_sql()
1018 );
1019
1020 assert_eq!(
1021 "SQRT(2)",
1022 &Expr::Function(Box::new(Function::Sqrt(Expr::Literal(AstLiteral::Number(
1023 BigDecimal::from_str("2").unwrap()
1024 )))))
1025 .to_sql()
1026 );
1027
1028 assert_eq!(
1029 "POWER(2, 10)",
1030 &Expr::Function(Box::new(Function::Power {
1031 expr: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("2").unwrap())),
1032 power: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("10").unwrap())),
1033 }))
1034 .to_sql()
1035 );
1036
1037 assert_eq!(
1038 "RADIANS(1)",
1039 &Expr::Function(Box::new(Function::Radians(Expr::Literal(
1040 AstLiteral::Number(BigDecimal::from_str("1").unwrap())
1041 ))))
1042 .to_sql()
1043 );
1044
1045 assert_eq!(
1046 "DEGREES(1)",
1047 &Expr::Function(Box::new(Function::Degrees(Expr::Literal(
1048 AstLiteral::Number(BigDecimal::from_str("1").unwrap())
1049 ))))
1050 .to_sql()
1051 );
1052
1053 assert_eq!("NOW()", &Expr::Function(Box::new(Function::Now())).to_sql());
1054 assert_eq!(
1055 "CURRENT_DATE()",
1056 &Expr::Function(Box::new(Function::CurrentDate())).to_sql()
1057 );
1058 assert_eq!(
1059 "CURRENT_TIME()",
1060 &Expr::Function(Box::new(Function::CurrentTime())).to_sql()
1061 );
1062 assert_eq!(
1063 "CURRENT_TIMESTAMP()",
1064 &Expr::Function(Box::new(Function::CurrentTimestamp())).to_sql()
1065 );
1066
1067 assert_eq!("PI()", &Expr::Function(Box::new(Function::Pi())).to_sql());
1068
1069 assert_eq!(
1070 "LTRIM(' HI ')",
1071 &Expr::Function(Box::new(Function::Ltrim {
1072 expr: Expr::Literal(AstLiteral::QuotedString(" HI ".to_owned())),
1073 chars: None
1074 }))
1075 .to_sql()
1076 );
1077
1078 assert_eq!(
1079 "LTRIM('*IMPORTANT', '*')",
1080 &Expr::Function(Box::new(Function::Ltrim {
1081 expr: Expr::Literal(AstLiteral::QuotedString("*IMPORTANT".to_owned())),
1082 chars: Some(Expr::Literal(AstLiteral::QuotedString("*".to_owned()))),
1083 }))
1084 .to_sql()
1085 );
1086
1087 assert_eq!(
1088 "RTRIM(' HI ')",
1089 &Expr::Function(Box::new(Function::Rtrim {
1090 expr: Expr::Literal(AstLiteral::QuotedString(" HI ".to_owned())),
1091 chars: None
1092 }))
1093 .to_sql()
1094 );
1095
1096 assert_eq!(
1097 "RTRIM('IMPORTANT*', '*')",
1098 &Expr::Function(Box::new(Function::Rtrim {
1099 expr: Expr::Literal(AstLiteral::QuotedString("IMPORTANT*".to_owned())),
1100 chars: Some(Expr::Literal(AstLiteral::QuotedString("*".to_owned()))),
1101 }))
1102 .to_sql()
1103 );
1104
1105 assert_eq!(
1106 r#"REVERSE("name")"#,
1107 &Expr::Function(Box::new(Function::Reverse(Expr::Identifier(
1108 "name".to_owned()
1109 ))))
1110 .to_sql()
1111 );
1112
1113 assert_eq!(
1114 "REPEAT('Ha', 8)",
1115 &Expr::Function(Box::new(Function::Repeat {
1116 expr: Expr::Literal(AstLiteral::QuotedString("Ha".to_owned())),
1117 num: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("8").unwrap()))
1118 }))
1119 .to_sql()
1120 );
1121
1122 assert_eq!(
1123 "SIGN(1.0)",
1124 &Expr::Function(Box::new(Function::Sign(Expr::Literal(AstLiteral::Number(
1125 BigDecimal::from_str("1.0").unwrap()
1126 )))))
1127 .to_sql()
1128 );
1129
1130 assert_eq!(
1131 "SUBSTR('GlueSQL', 2)",
1132 &Expr::Function(Box::new(Function::Substr {
1133 expr: Expr::Literal(AstLiteral::QuotedString("GlueSQL".to_owned())),
1134 start: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("2").unwrap())),
1135 count: None
1136 }))
1137 .to_sql()
1138 );
1139
1140 assert_eq!(
1141 "SUBSTR('GlueSQL', 1, 3)",
1142 &Expr::Function(Box::new(Function::Substr {
1143 expr: Expr::Literal(AstLiteral::QuotedString("GlueSQL".to_owned())),
1144 start: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("1").unwrap())),
1145 count: Some(Expr::Literal(AstLiteral::Number(
1146 BigDecimal::from_str("3").unwrap()
1147 )))
1148 }))
1149 .to_sql()
1150 );
1151
1152 assert_eq!(
1153 r#"UNWRAP("nested", 'a.foo')"#,
1154 &Expr::Function(Box::new(Function::Unwrap {
1155 expr: Expr::Identifier("nested".to_owned()),
1156 selector: Expr::Literal(AstLiteral::QuotedString("a.foo".to_owned()))
1157 }))
1158 .to_sql()
1159 );
1160
1161 assert_eq!(
1162 "GENERATE_UUID()",
1163 &Expr::Function(Box::new(Function::GenerateUuid())).to_sql()
1164 );
1165 assert_eq!(
1166 "ADD_MONTH('2023-06-15',1)",
1167 &Expr::Function(Box::new(Function::AddMonth {
1168 expr: Expr::Literal(AstLiteral::QuotedString("2023-06-15".to_owned())),
1169 size: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("1").unwrap()))
1170 }))
1171 .to_sql()
1172 );
1173
1174 assert_eq!(
1175 "GREATEST(16, 9, 7)",
1176 &Expr::Function(Box::new(Function::Greatest(vec![
1177 Expr::Literal(AstLiteral::Number(BigDecimal::from_str("16").unwrap())),
1178 Expr::Literal(AstLiteral::Number(BigDecimal::from_str("9").unwrap())),
1179 Expr::Literal(AstLiteral::Number(BigDecimal::from_str("7").unwrap()))
1180 ])))
1181 .to_sql()
1182 );
1183
1184 assert_eq!(
1185 "FORMAT(DATE '2022-10-12', '%Y-%m')",
1186 &Expr::Function(Box::new(Function::Format {
1187 expr: Expr::TypedString {
1188 data_type: DataType::Date,
1189 value: "2022-10-12".to_owned()
1190 },
1191 format: Expr::Literal(AstLiteral::QuotedString("%Y-%m".to_owned()))
1192 }))
1193 .to_sql()
1194 );
1195
1196 assert_eq!(
1197 "LAST_DAY(DATE '2022-10-12')",
1198 &Expr::Function(Box::new(Function::LastDay(Expr::TypedString {
1199 data_type: DataType::Date,
1200 value: "2022-10-12".to_owned()
1201 })))
1202 .to_sql()
1203 );
1204
1205 assert_eq!(
1206 "TO_DATE('2022-10-12', '%Y-%m-%d')",
1207 &Expr::Function(Box::new(Function::ToDate {
1208 expr: Expr::Literal(AstLiteral::QuotedString("2022-10-12".to_owned())),
1209 format: Expr::Literal(AstLiteral::QuotedString("%Y-%m-%d".to_owned()))
1210 }))
1211 .to_sql()
1212 );
1213
1214 assert_eq!(
1215 "TO_TIMESTAMP('2022-10-12 00:34:23', '%Y-%m-%d %H:%M:%S')",
1216 &Expr::Function(Box::new(Function::ToTimestamp {
1217 expr: Expr::Literal(AstLiteral::QuotedString("2022-10-12 00:34:23".to_owned())),
1218 format: Expr::Literal(AstLiteral::QuotedString("%Y-%m-%d %H:%M:%S".to_owned()))
1219 }))
1220 .to_sql()
1221 );
1222
1223 assert_eq!(
1224 "TO_TIME('00:34:23', '%H:%M:%S')",
1225 &Expr::Function(Box::new(Function::ToTime {
1226 expr: Expr::Literal(AstLiteral::QuotedString("00:34:23".to_owned())),
1227 format: Expr::Literal(AstLiteral::QuotedString("%H:%M:%S".to_owned()))
1228 }))
1229 .to_sql()
1230 );
1231
1232 assert_eq!(
1233 "POSITION('cup' IN 'cupcake')",
1234 &Expr::Function(Box::new(Function::Position {
1235 from_expr: Expr::Literal(AstLiteral::QuotedString("cupcake".to_owned())),
1236 sub_expr: Expr::Literal(AstLiteral::QuotedString("cup".to_owned())),
1237 }))
1238 .to_sql()
1239 );
1240
1241 assert_eq!(
1242 "FIND_IDX('noodle', 'o', 2)",
1243 &Expr::Function(Box::new(Function::FindIdx {
1244 from_expr: Expr::Literal(AstLiteral::QuotedString("noodle".to_owned())),
1245 sub_expr: Expr::Literal(AstLiteral::QuotedString("o".to_owned())),
1246 start: Some(Expr::Literal(AstLiteral::Number(
1247 BigDecimal::from_str("2").unwrap()
1248 )))
1249 }))
1250 .to_sql()
1251 );
1252
1253 assert_eq!(
1254 "FIND_IDX('goat cheese', 'goat')",
1255 &Expr::Function(Box::new(Function::FindIdx {
1256 from_expr: Expr::Literal(AstLiteral::QuotedString("goat cheese".to_owned())),
1257 sub_expr: Expr::Literal(AstLiteral::QuotedString("goat".to_owned())),
1258 start: None
1259 }))
1260 .to_sql()
1261 );
1262
1263 assert_eq!(
1264 "ASCII('H')",
1265 &Expr::Function(Box::new(Function::Ascii(Expr::Literal(
1266 AstLiteral::QuotedString("H".to_owned())
1267 ))))
1268 .to_sql()
1269 );
1270
1271 assert_eq!(
1272 r#"CHR(72)"#,
1273 &Expr::Function(Box::new(Function::Chr(Expr::Literal(AstLiteral::Number(
1274 BigDecimal::from_str("72").unwrap()
1275 )))))
1276 .to_sql()
1277 );
1278
1279 assert_eq!(
1280 "MD5('GlueSQL')",
1281 &Expr::Function(Box::new(Function::Md5(Expr::Literal(
1282 AstLiteral::QuotedString("GlueSQL".to_owned())
1283 ))))
1284 .to_sql()
1285 );
1286
1287 assert_eq!(
1288 "HEX(228)",
1289 &Expr::Function(Box::new(Function::Hex(Expr::Literal(AstLiteral::Number(
1290 BigDecimal::from(228)
1291 )))))
1292 .to_sql()
1293 );
1294
1295 assert_eq!(
1296 "HEX('GlueSQL')",
1297 &Expr::Function(Box::new(Function::Hex(Expr::Literal(
1298 AstLiteral::QuotedString("GlueSQL".to_owned())
1299 ))))
1300 .to_sql()
1301 );
1302
1303 assert_eq!(
1304 r#"EXTRACT(MINUTE FROM '2022-05-05 01:02:03')"#,
1305 &Expr::Function(Box::new(Function::Extract {
1306 field: DateTimeField::Minute,
1307 expr: Expr::Literal(AstLiteral::QuotedString("2022-05-05 01:02:03".to_owned()))
1308 }))
1309 .to_sql()
1310 );
1311
1312 assert_eq!(
1313 r#"APPEND("list", "value")"#,
1314 &Expr::Function(Box::new(Function::Append {
1315 expr: Expr::Identifier("list".to_owned()),
1316 value: Expr::Identifier("value".to_owned())
1317 }))
1318 .to_sql()
1319 );
1320
1321 assert_eq!(
1322 r#"PREPEND("list", "value")"#,
1323 &Expr::Function(Box::new(Function::Prepend {
1324 expr: Expr::Identifier("list".to_owned()),
1325 value: Expr::Identifier("value".to_owned())
1326 }))
1327 .to_sql()
1328 );
1329
1330 assert_eq!(
1331 r#"SKIP("list", 2)"#,
1332 &Expr::Function(Box::new(Function::Skip {
1333 expr: Expr::Identifier("list".to_owned()),
1334 size: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("2").unwrap()))
1335 }))
1336 .to_sql()
1337 );
1338
1339 assert_eq!(
1340 r#"SORT("list")"#,
1341 &Expr::Function(Box::new(Function::Sort {
1342 expr: Expr::Identifier("list".to_owned()),
1343 order: None
1344 }))
1345 .to_sql()
1346 );
1347
1348 assert_eq!(
1349 r#"SORT("list", 'ASC')"#,
1350 &Expr::Function(Box::new(Function::Sort {
1351 expr: Expr::Identifier("list".to_owned()),
1352 order: Some(Expr::Literal(AstLiteral::QuotedString("ASC".to_owned())))
1353 }))
1354 .to_sql()
1355 );
1356
1357 assert_eq!(
1358 r#"SLICE("list", 1, 2)"#,
1359 &Expr::Function(Box::new(Function::Slice {
1360 expr: (Expr::Identifier("list".to_owned())),
1361 start: (Expr::Literal(AstLiteral::Number(BigDecimal::from_str("1").unwrap()))),
1362 length: (Expr::Literal(AstLiteral::Number(BigDecimal::from_str("2").unwrap())))
1363 }))
1364 .to_sql()
1365 );
1366
1367 assert_eq!(
1368 r#"TAKE("list", 3)"#,
1369 &Expr::Function(Box::new(Function::Take {
1370 expr: Expr::Identifier("list".to_owned()),
1371 size: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("3").unwrap()))
1372 }))
1373 .to_sql()
1374 );
1375
1376 assert_eq!(
1377 "GET_X(\"point\")",
1378 &Expr::Function(Box::new(Function::GetX(Expr::Identifier(
1379 "point".to_owned()
1380 ))))
1381 .to_sql()
1382 );
1383
1384 assert_eq!(
1385 "GET_Y(\"point\")",
1386 &Expr::Function(Box::new(Function::GetY(Expr::Identifier(
1387 "point".to_owned()
1388 ))))
1389 .to_sql()
1390 );
1391
1392 assert_eq!(
1393 "POINT(0.1, 0.2)",
1394 &Expr::Function(Box::new(Function::Point {
1395 x: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("0.1").unwrap())),
1396 y: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("0.2").unwrap()))
1397 }))
1398 .to_sql()
1399 );
1400
1401 assert_eq!(
1402 "CALC_DISTANCE(POINT(1.1, 2.3), POINT(1.4, 3.6))",
1403 &Expr::Function(Box::new(Function::CalcDistance {
1404 geometry1: Expr::Function(Box::new(Function::Point {
1405 x: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("1.1").unwrap())),
1406 y: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("2.3").unwrap()))
1407 })),
1408 geometry2: Expr::Function(Box::new(Function::Point {
1409 x: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("1.4").unwrap())),
1410 y: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("3.6").unwrap()))
1411 }))
1412 }))
1413 .to_sql()
1414 );
1415
1416 assert_eq!(
1417 r#"IS_EMPTY("list")"#,
1418 &Expr::Function(Box::new(Function::IsEmpty(Expr::Identifier(
1419 "list".to_owned()
1420 ))))
1421 .to_sql()
1422 );
1423
1424 assert_eq!(
1425 r#"LENGTH("GlueSQL")"#,
1426 &Expr::Function(Box::new(Function::Length(Expr::Identifier(
1427 "GlueSQL".to_owned()
1428 ))))
1429 .to_sql()
1430 );
1431
1432 assert_eq!(
1433 r#"ENTRIES("map")"#,
1434 &Expr::Function(Box::new(Function::Entries(Expr::Identifier(
1435 "map".to_owned()
1436 ))))
1437 .to_sql()
1438 );
1439
1440 assert_eq!(
1441 r#"KEYS("map")"#,
1442 &Expr::Function(Box::new(Function::Keys(Expr::Identifier("map".to_owned())))).to_sql()
1443 );
1444
1445 assert_eq!(
1446 r#"VALUES("map")"#,
1447 &Expr::Function(Box::new(Function::Values(Expr::Identifier(
1448 "map".to_owned()
1449 ))))
1450 .to_sql()
1451 );
1452
1453 assert_eq!(
1454 r#"SPLICE("list", 2, 4)"#,
1455 &Expr::Function(Box::new(Function::Splice {
1456 list_data: Expr::Identifier("list".to_owned()),
1457 begin_index: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("2").unwrap())),
1458 end_index: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("4").unwrap())),
1459 values: None
1460 }))
1461 .to_sql()
1462 );
1463
1464 assert_eq!(
1465 r#"SPLICE("list", 2, 4, "values")"#,
1466 &Expr::Function(Box::new(Function::Splice {
1467 list_data: Expr::Identifier("list".to_owned()),
1468 begin_index: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("2").unwrap())),
1469 end_index: Expr::Literal(AstLiteral::Number(BigDecimal::from_str("4").unwrap())),
1470 values: Some(Expr::Identifier("values".to_owned()))
1471 }))
1472 .to_sql()
1473 );
1474
1475 assert_eq!(
1476 r#"DEDUP("list")"#,
1477 &Expr::Function(Box::new(Function::Dedup(Expr::Identifier(
1478 "list".to_owned()
1479 ))))
1480 .to_sql(),
1481 )
1482 }
1483
1484 #[test]
1485 fn to_sql_aggregate() {
1486 assert_eq!(
1487 r#"MAX("id")"#,
1488 Expr::Aggregate(Box::new(Aggregate::max(
1489 Expr::Identifier("id".to_owned()),
1490 false
1491 )))
1492 .to_sql()
1493 );
1494
1495 assert_eq!(
1496 r#"MAX(DISTINCT "id")"#,
1497 Expr::Aggregate(Box::new(Aggregate::max(
1498 Expr::Identifier("id".to_owned()),
1499 true
1500 )))
1501 .to_sql()
1502 );
1503
1504 assert_eq!(
1505 "COUNT(*)",
1506 Expr::Aggregate(Box::new(Aggregate::count(CountArgExpr::Wildcard, false))).to_sql()
1507 );
1508
1509 assert_eq!(
1510 "COUNT(DISTINCT *)",
1511 Expr::Aggregate(Box::new(Aggregate::count(CountArgExpr::Wildcard, true))).to_sql()
1512 );
1513
1514 assert_eq!(
1515 r#"COUNT(DISTINCT "id")"#,
1516 Expr::Aggregate(Box::new(Aggregate::count(
1517 CountArgExpr::Expr(Expr::Identifier("id".to_owned())),
1518 true
1519 )))
1520 .to_sql()
1521 );
1522
1523 assert_eq!(
1524 r#"MIN("id")"#,
1525 Expr::Aggregate(Box::new(Aggregate::min(
1526 Expr::Identifier("id".to_owned()),
1527 false
1528 )))
1529 .to_sql()
1530 );
1531
1532 assert_eq!(
1533 r#"MIN(DISTINCT "id")"#,
1534 Expr::Aggregate(Box::new(Aggregate::min(
1535 Expr::Identifier("id".to_owned()),
1536 true
1537 )))
1538 .to_sql()
1539 );
1540
1541 assert_eq!(
1542 r#"SUM("price")"#,
1543 Expr::Aggregate(Box::new(Aggregate::sum(
1544 Expr::Identifier("price".to_owned()),
1545 false
1546 )))
1547 .to_sql()
1548 );
1549
1550 assert_eq!(
1551 r#"SUM(DISTINCT "price")"#,
1552 Expr::Aggregate(Box::new(Aggregate::sum(
1553 Expr::Identifier("price".to_owned()),
1554 true
1555 )))
1556 .to_sql()
1557 );
1558
1559 assert_eq!(
1560 r#"AVG("pay")"#,
1561 Expr::Aggregate(Box::new(Aggregate::avg(
1562 Expr::Identifier("pay".to_owned()),
1563 false
1564 )))
1565 .to_sql()
1566 );
1567
1568 assert_eq!(
1569 r#"AVG(DISTINCT "pay")"#,
1570 Expr::Aggregate(Box::new(Aggregate::avg(
1571 Expr::Identifier("pay".to_owned()),
1572 true
1573 )))
1574 .to_sql()
1575 );
1576
1577 assert_eq!(
1578 r#"VARIANCE("pay")"#,
1579 Expr::Aggregate(Box::new(Aggregate::variance(
1580 Expr::Identifier("pay".to_owned()),
1581 false
1582 )))
1583 .to_sql()
1584 );
1585
1586 assert_eq!(
1587 r#"VARIANCE(DISTINCT "pay")"#,
1588 Expr::Aggregate(Box::new(Aggregate::variance(
1589 Expr::Identifier("pay".to_owned()),
1590 true
1591 )))
1592 .to_sql()
1593 );
1594
1595 assert_eq!(
1596 r#"STDEV("total")"#,
1597 Expr::Aggregate(Box::new(Aggregate::stdev(
1598 Expr::Identifier("total".to_owned()),
1599 false
1600 )))
1601 .to_sql()
1602 );
1603
1604 assert_eq!(
1605 r#"STDEV(DISTINCT "total")"#,
1606 Expr::Aggregate(Box::new(Aggregate::stdev(
1607 Expr::Identifier("total".to_owned()),
1608 true
1609 )))
1610 .to_sql()
1611 );
1612 }
1613}