gluesql_core/ast/
function.rs

1use {
2    super::{DataType, DateTimeField, Expr, 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 => String::new(),
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::{
611            ast::{
612                Aggregate, CountArgExpr, DataType, DateTimeField, Expr, Function, Literal, ToSql,
613                TrimWhereField,
614            },
615            data::Value,
616        },
617        bigdecimal::BigDecimal,
618        std::str::FromStr,
619    };
620
621    #[test]
622    fn to_sql_function() {
623        assert_eq!(
624            r#"ABS("num")"#,
625            &Expr::Function(Box::new(Function::Abs(Expr::Identifier("num".to_owned())))).to_sql()
626        );
627
628        assert_eq!(
629            "LOWER('Bye')",
630            &Expr::Function(Box::new(Function::Lower(Expr::Literal(
631                Literal::QuotedString("Bye".to_owned())
632            ))))
633            .to_sql()
634        );
635
636        assert_eq!(
637            "INITCAP('Bye')",
638            &Expr::Function(Box::new(Function::Initcap(Expr::Literal(
639                Literal::QuotedString("Bye".to_owned())
640            ))))
641            .to_sql()
642        );
643
644        assert_eq!(
645            "UPPER('Hi')",
646            &Expr::Function(Box::new(Function::Upper(Expr::Literal(
647                Literal::QuotedString("Hi".to_owned())
648            ))))
649            .to_sql()
650        );
651
652        assert_eq!(
653            "LEFT('GlueSQL', 2)",
654            &Expr::Function(Box::new(Function::Left {
655                expr: Expr::Literal(Literal::QuotedString("GlueSQL".to_owned())),
656                size: Expr::Literal(Literal::Number(BigDecimal::from_str("2").unwrap()))
657            }))
658            .to_sql()
659        );
660
661        assert_eq!(
662            "RIGHT('GlueSQL', 3)",
663            &Expr::Function(Box::new(Function::Right {
664                expr: Expr::Literal(Literal::QuotedString("GlueSQL".to_owned())),
665                size: Expr::Literal(Literal::Number(BigDecimal::from_str("3").unwrap()))
666            }))
667            .to_sql()
668        );
669
670        assert_eq!(
671            "ASIN(2)",
672            &Expr::Function(Box::new(Function::Asin(Expr::Literal(Literal::Number(
673                BigDecimal::from_str("2").unwrap()
674            )))))
675            .to_sql()
676        );
677
678        assert_eq!(
679            "ACOS(2)",
680            &Expr::Function(Box::new(Function::Acos(Expr::Literal(Literal::Number(
681                BigDecimal::from_str("2").unwrap()
682            )))))
683            .to_sql()
684        );
685
686        assert_eq!(
687            "ATAN(2)",
688            &Expr::Function(Box::new(Function::Atan(Expr::Literal(Literal::Number(
689                BigDecimal::from_str("2").unwrap()
690            )))))
691            .to_sql()
692        );
693
694        assert_eq!(
695            "LPAD('GlueSQL', 2)",
696            &Expr::Function(Box::new(Function::Lpad {
697                expr: Expr::Literal(Literal::QuotedString("GlueSQL".to_owned())),
698                size: Expr::Literal(Literal::Number(BigDecimal::from_str("2").unwrap())),
699                fill: None
700            }))
701            .to_sql()
702        );
703
704        assert_eq!(
705            "LPAD('GlueSQL', 10, 'Go')",
706            &Expr::Function(Box::new(Function::Lpad {
707                expr: Expr::Literal(Literal::QuotedString("GlueSQL".to_owned())),
708                size: Expr::Literal(Literal::Number(BigDecimal::from_str("10").unwrap())),
709                fill: Some(Expr::Literal(Literal::QuotedString("Go".to_owned())))
710            }))
711            .to_sql()
712        );
713
714        assert_eq!(
715            "RPAD('GlueSQL', 10)",
716            &Expr::Function(Box::new(Function::Rpad {
717                expr: Expr::Literal(Literal::QuotedString("GlueSQL".to_owned())),
718                size: Expr::Literal(Literal::Number(BigDecimal::from_str("10").unwrap())),
719                fill: None
720            }))
721            .to_sql()
722        );
723
724        assert_eq!(
725            "RPAD('GlueSQL', 10, 'Go')",
726            &Expr::Function(Box::new(Function::Rpad {
727                expr: Expr::Literal(Literal::QuotedString("GlueSQL".to_owned())),
728                size: Expr::Literal(Literal::Number(BigDecimal::from_str("10").unwrap())),
729                fill: Some(Expr::Literal(Literal::QuotedString("Go".to_owned())))
730            }))
731            .to_sql()
732        );
733
734        assert_eq!(
735            "CAST(1.0 AS INT)",
736            &Expr::Function(Box::new(Function::Cast {
737                expr: Expr::Literal(Literal::Number(BigDecimal::from_str("1.0").unwrap())),
738                data_type: DataType::Int
739            }))
740            .to_sql()
741        );
742
743        assert_eq!(
744            r#"CEIL("num")"#,
745            &Expr::Function(Box::new(Function::Ceil(Expr::Identifier("num".to_owned())))).to_sql()
746        );
747
748        assert_eq!(
749            r#"CUSTOM_FUNC("Tic", 1, "num", 'abc')"#,
750            &Expr::Function(Box::new(Function::Custom {
751                name: "CUSTOM_FUNC".to_owned(),
752                exprs: vec![
753                    Expr::Identifier("Tic".to_owned()),
754                    Expr::Literal(Literal::Number(BigDecimal::from_str("1").unwrap())),
755                    Expr::Identifier("num".to_owned()),
756                    Expr::Literal(Literal::QuotedString("abc".to_owned()))
757                ]
758            }))
759            .to_sql()
760        );
761        assert_eq!(
762            r#"CUSTOM_FUNC("num")"#,
763            &Expr::Function(Box::new(Function::Custom {
764                name: "CUSTOM_FUNC".to_owned(),
765                exprs: vec![Expr::Identifier("num".to_owned())]
766            }))
767            .to_sql()
768        );
769        assert_eq!(
770            "CUSTOM_FUNC()",
771            &Expr::Function(Box::new(Function::Custom {
772                name: "CUSTOM_FUNC".to_owned(),
773                exprs: vec![]
774            }))
775            .to_sql()
776        );
777
778        assert_eq!(
779            r#"COALESCE("First", NULL, "Last")"#,
780            &Expr::Function(Box::new(Function::Coalesce(vec![
781                Expr::Identifier("First".to_owned()),
782                Expr::Value(Value::Null),
783                Expr::Identifier("Last".to_owned()),
784            ])))
785            .to_sql()
786        );
787
788        assert_eq!(
789            "CONCAT(\"Tic\", \"tac\", \"toe\")",
790            &Expr::Function(Box::new(Function::Concat(vec![
791                Expr::Identifier("Tic".to_owned()),
792                Expr::Identifier("tac".to_owned()),
793                Expr::Identifier("toe".to_owned())
794            ])))
795            .to_sql()
796        );
797
798        assert_eq!(
799            r#"CONCAT_WS('-', "Tic", "tac", "toe")"#,
800            &Expr::Function(Box::new(Function::ConcatWs {
801                separator: Expr::Literal(Literal::QuotedString("-".to_owned())),
802                exprs: vec![
803                    Expr::Identifier("Tic".to_owned()),
804                    Expr::Identifier("tac".to_owned()),
805                    Expr::Identifier("toe".to_owned())
806                ]
807            }))
808            .to_sql()
809        );
810
811        assert_eq!(
812            "REPLACE('Mticky GlueMQL','M','S')",
813            &Expr::Function(Box::new(Function::Replace {
814                expr: Expr::Literal(Literal::QuotedString("Mticky GlueMQL".to_owned())),
815                old: Expr::Literal(Literal::QuotedString("M".to_owned())),
816                new: Expr::Literal(Literal::QuotedString("S".to_owned()))
817            }))
818            .to_sql()
819        );
820        assert_eq!(
821            r#"IFNULL("updated_at", "created_at")"#,
822            &Expr::Function(Box::new(Function::IfNull {
823                expr: Expr::Identifier("updated_at".to_owned()),
824                then: Expr::Identifier("created_at".to_owned())
825            }))
826            .to_sql()
827        );
828
829        assert_eq!(
830            r#"NULLIF("updated_at", "created_at")"#,
831            &Expr::Function(Box::new(Function::NullIf {
832                expr1: Expr::Identifier("updated_at".to_owned()),
833                expr2: Expr::Identifier("created_at".to_owned())
834            }))
835            .to_sql()
836        );
837
838        assert_eq!(
839            "RAND()",
840            &Expr::Function(Box::new(Function::Rand(None))).to_sql()
841        );
842
843        assert_eq!(
844            r#"RAND("num")"#,
845            &Expr::Function(Box::new(Function::Rand(Some(Expr::Identifier(
846                "num".to_owned()
847            )))))
848            .to_sql()
849        );
850
851        assert_eq!(
852            r#"ROUND("num")"#,
853            &Expr::Function(Box::new(Function::Round(Expr::Identifier(
854                "num".to_owned()
855            ))))
856            .to_sql()
857        );
858
859        assert_eq!(
860            r#"TRUNC("num")"#,
861            &Expr::Function(Box::new(Function::Trunc(Expr::Identifier(
862                "num".to_owned()
863            ))))
864            .to_sql()
865        );
866
867        assert_eq!(
868            r#"FLOOR("num")"#,
869            &Expr::Function(Box::new(Function::Floor(Expr::Identifier(
870                "num".to_owned()
871            ))))
872            .to_sql()
873        );
874
875        assert_eq!(
876            r#"TRIM("name")"#,
877            &Expr::Function(Box::new(Function::Trim {
878                expr: Expr::Identifier("name".to_owned()),
879                filter_chars: None,
880                trim_where_field: None
881            }))
882            .to_sql()
883        );
884
885        assert_eq!(
886            r#"TRIM('*' FROM "name")"#,
887            &Expr::Function(Box::new(Function::Trim {
888                expr: Expr::Identifier("name".to_owned()),
889                filter_chars: Some(Expr::Literal(Literal::QuotedString("*".to_owned()))),
890                trim_where_field: None
891            }))
892            .to_sql()
893        );
894
895        assert_eq!(
896            r#"TRIM(BOTH '*' FROM "name")"#,
897            &Expr::Function(Box::new(Function::Trim {
898                expr: Expr::Identifier("name".to_owned()),
899                filter_chars: Some(Expr::Literal(Literal::QuotedString("*".to_owned()))),
900                trim_where_field: Some(TrimWhereField::Both)
901            }))
902            .to_sql()
903        );
904
905        assert_eq!(
906            r#"TRIM(LEADING '*' FROM "name")"#,
907            &Expr::Function(Box::new(Function::Trim {
908                expr: Expr::Identifier("name".to_owned()),
909                filter_chars: Some(Expr::Literal(Literal::QuotedString("*".to_owned()))),
910                trim_where_field: Some(TrimWhereField::Leading)
911            }))
912            .to_sql()
913        );
914
915        assert_eq!(
916            r#"TRIM(LEADING "name")"#,
917            &Expr::Function(Box::new(Function::Trim {
918                expr: Expr::Identifier("name".to_owned()),
919                filter_chars: None,
920                trim_where_field: Some(TrimWhereField::Leading)
921            }))
922            .to_sql()
923        );
924
925        assert_eq!(
926            "EXP(1)",
927            &Expr::Function(Box::new(Function::Exp(Expr::Literal(Literal::Number(
928                BigDecimal::from_str("1").unwrap()
929            )))))
930            .to_sql()
931        );
932
933        assert_eq!(
934            "LN(1)",
935            &Expr::Function(Box::new(Function::Ln(Expr::Literal(Literal::Number(
936                BigDecimal::from_str("1").unwrap()
937            )))))
938            .to_sql()
939        );
940
941        assert_eq!(
942            "LOG(64, 8)",
943            &Expr::Function(Box::new(Function::Log {
944                antilog: Expr::Literal(Literal::Number(BigDecimal::from_str("64").unwrap())),
945                base: Expr::Literal(Literal::Number(BigDecimal::from_str("8").unwrap()))
946            }))
947            .to_sql()
948        );
949
950        assert_eq!(
951            r#"LOG2("num")"#,
952            &Expr::Function(Box::new(Function::Log2(Expr::Identifier("num".to_owned())))).to_sql()
953        );
954
955        assert_eq!(
956            r#"LOG10("num")"#,
957            &Expr::Function(Box::new(Function::Log10(Expr::Identifier(
958                "num".to_owned()
959            ))))
960            .to_sql()
961        );
962
963        assert_eq!(
964            "DIV(64, 8)",
965            &Expr::Function(Box::new(Function::Div {
966                dividend: Expr::Literal(Literal::Number(BigDecimal::from_str("64").unwrap())),
967                divisor: Expr::Literal(Literal::Number(BigDecimal::from_str("8").unwrap()))
968            }))
969            .to_sql()
970        );
971
972        assert_eq!(
973            "MOD(64, 8)",
974            &Expr::Function(Box::new(Function::Mod {
975                dividend: Expr::Literal(Literal::Number(BigDecimal::from_str("64").unwrap())),
976                divisor: Expr::Literal(Literal::Number(BigDecimal::from_str("8").unwrap()))
977            }))
978            .to_sql()
979        );
980
981        assert_eq!(
982            "GCD(64, 8)",
983            &Expr::Function(Box::new(Function::Gcd {
984                left: Expr::Literal(Literal::Number(BigDecimal::from_str("64").unwrap())),
985                right: Expr::Literal(Literal::Number(BigDecimal::from_str("8").unwrap()))
986            }))
987            .to_sql()
988        );
989
990        assert_eq!(
991            "LCM(64, 8)",
992            &Expr::Function(Box::new(Function::Lcm {
993                left: Expr::Literal(Literal::Number(BigDecimal::from_str("64").unwrap())),
994                right: Expr::Literal(Literal::Number(BigDecimal::from_str("8").unwrap()))
995            }))
996            .to_sql()
997        );
998
999        assert_eq!(
1000            "SIN(2)",
1001            &Expr::Function(Box::new(Function::Sin(Expr::Literal(Literal::Number(
1002                BigDecimal::from_str("2").unwrap()
1003            )))))
1004            .to_sql()
1005        );
1006
1007        assert_eq!(
1008            "COS(2)",
1009            &Expr::Function(Box::new(Function::Cos(Expr::Literal(Literal::Number(
1010                BigDecimal::from_str("2").unwrap()
1011            )))))
1012            .to_sql()
1013        );
1014
1015        assert_eq!(
1016            "TAN(2)",
1017            &Expr::Function(Box::new(Function::Tan(Expr::Literal(Literal::Number(
1018                BigDecimal::from_str("2").unwrap()
1019            )))))
1020            .to_sql()
1021        );
1022
1023        assert_eq!(
1024            "SQRT(2)",
1025            &Expr::Function(Box::new(Function::Sqrt(Expr::Literal(Literal::Number(
1026                BigDecimal::from_str("2").unwrap()
1027            )))))
1028            .to_sql()
1029        );
1030
1031        assert_eq!(
1032            "POWER(2, 10)",
1033            &Expr::Function(Box::new(Function::Power {
1034                expr: Expr::Literal(Literal::Number(BigDecimal::from_str("2").unwrap())),
1035                power: Expr::Literal(Literal::Number(BigDecimal::from_str("10").unwrap())),
1036            }))
1037            .to_sql()
1038        );
1039
1040        assert_eq!(
1041            "RADIANS(1)",
1042            &Expr::Function(Box::new(Function::Radians(Expr::Literal(Literal::Number(
1043                BigDecimal::from_str("1").unwrap()
1044            )))))
1045            .to_sql()
1046        );
1047
1048        assert_eq!(
1049            "DEGREES(1)",
1050            &Expr::Function(Box::new(Function::Degrees(Expr::Literal(Literal::Number(
1051                BigDecimal::from_str("1").unwrap()
1052            )))))
1053            .to_sql()
1054        );
1055
1056        assert_eq!("NOW()", &Expr::Function(Box::new(Function::Now())).to_sql());
1057        assert_eq!(
1058            "CURRENT_DATE()",
1059            &Expr::Function(Box::new(Function::CurrentDate())).to_sql()
1060        );
1061        assert_eq!(
1062            "CURRENT_TIME()",
1063            &Expr::Function(Box::new(Function::CurrentTime())).to_sql()
1064        );
1065        assert_eq!(
1066            "CURRENT_TIMESTAMP()",
1067            &Expr::Function(Box::new(Function::CurrentTimestamp())).to_sql()
1068        );
1069
1070        assert_eq!("PI()", &Expr::Function(Box::new(Function::Pi())).to_sql());
1071
1072        assert_eq!(
1073            "LTRIM('   HI ')",
1074            &Expr::Function(Box::new(Function::Ltrim {
1075                expr: Expr::Literal(Literal::QuotedString("   HI ".to_owned())),
1076                chars: None
1077            }))
1078            .to_sql()
1079        );
1080
1081        assert_eq!(
1082            "LTRIM('*IMPORTANT', '*')",
1083            &Expr::Function(Box::new(Function::Ltrim {
1084                expr: Expr::Literal(Literal::QuotedString("*IMPORTANT".to_owned())),
1085                chars: Some(Expr::Literal(Literal::QuotedString("*".to_owned()))),
1086            }))
1087            .to_sql()
1088        );
1089
1090        assert_eq!(
1091            "RTRIM('   HI ')",
1092            &Expr::Function(Box::new(Function::Rtrim {
1093                expr: Expr::Literal(Literal::QuotedString("   HI ".to_owned())),
1094                chars: None
1095            }))
1096            .to_sql()
1097        );
1098
1099        assert_eq!(
1100            "RTRIM('IMPORTANT*', '*')",
1101            &Expr::Function(Box::new(Function::Rtrim {
1102                expr: Expr::Literal(Literal::QuotedString("IMPORTANT*".to_owned())),
1103                chars: Some(Expr::Literal(Literal::QuotedString("*".to_owned()))),
1104            }))
1105            .to_sql()
1106        );
1107
1108        assert_eq!(
1109            r#"REVERSE("name")"#,
1110            &Expr::Function(Box::new(Function::Reverse(Expr::Identifier(
1111                "name".to_owned()
1112            ))))
1113            .to_sql()
1114        );
1115
1116        assert_eq!(
1117            "REPEAT('Ha', 8)",
1118            &Expr::Function(Box::new(Function::Repeat {
1119                expr: Expr::Literal(Literal::QuotedString("Ha".to_owned())),
1120                num: Expr::Literal(Literal::Number(BigDecimal::from_str("8").unwrap()))
1121            }))
1122            .to_sql()
1123        );
1124
1125        assert_eq!(
1126            "SIGN(1.0)",
1127            &Expr::Function(Box::new(Function::Sign(Expr::Literal(Literal::Number(
1128                BigDecimal::from_str("1.0").unwrap()
1129            )))))
1130            .to_sql()
1131        );
1132
1133        assert_eq!(
1134            "SUBSTR('GlueSQL', 2)",
1135            &Expr::Function(Box::new(Function::Substr {
1136                expr: Expr::Literal(Literal::QuotedString("GlueSQL".to_owned())),
1137                start: Expr::Literal(Literal::Number(BigDecimal::from_str("2").unwrap())),
1138                count: None
1139            }))
1140            .to_sql()
1141        );
1142
1143        assert_eq!(
1144            "SUBSTR('GlueSQL', 1, 3)",
1145            &Expr::Function(Box::new(Function::Substr {
1146                expr: Expr::Literal(Literal::QuotedString("GlueSQL".to_owned())),
1147                start: Expr::Literal(Literal::Number(BigDecimal::from_str("1").unwrap())),
1148                count: Some(Expr::Literal(Literal::Number(
1149                    BigDecimal::from_str("3").unwrap()
1150                )))
1151            }))
1152            .to_sql()
1153        );
1154
1155        assert_eq!(
1156            r#"UNWRAP("nested", 'a.foo')"#,
1157            &Expr::Function(Box::new(Function::Unwrap {
1158                expr: Expr::Identifier("nested".to_owned()),
1159                selector: Expr::Literal(Literal::QuotedString("a.foo".to_owned()))
1160            }))
1161            .to_sql()
1162        );
1163
1164        assert_eq!(
1165            "GENERATE_UUID()",
1166            &Expr::Function(Box::new(Function::GenerateUuid())).to_sql()
1167        );
1168        assert_eq!(
1169            "ADD_MONTH('2023-06-15',1)",
1170            &Expr::Function(Box::new(Function::AddMonth {
1171                expr: Expr::Literal(Literal::QuotedString("2023-06-15".to_owned())),
1172                size: Expr::Literal(Literal::Number(BigDecimal::from_str("1").unwrap()))
1173            }))
1174            .to_sql()
1175        );
1176
1177        assert_eq!(
1178            "GREATEST(16, 9, 7)",
1179            &Expr::Function(Box::new(Function::Greatest(vec![
1180                Expr::Literal(Literal::Number(BigDecimal::from_str("16").unwrap())),
1181                Expr::Literal(Literal::Number(BigDecimal::from_str("9").unwrap())),
1182                Expr::Literal(Literal::Number(BigDecimal::from_str("7").unwrap()))
1183            ])))
1184            .to_sql()
1185        );
1186
1187        assert_eq!(
1188            "FORMAT(DATE '2022-10-12', '%Y-%m')",
1189            &Expr::Function(Box::new(Function::Format {
1190                expr: Expr::TypedString {
1191                    data_type: DataType::Date,
1192                    value: "2022-10-12".to_owned()
1193                },
1194                format: Expr::Literal(Literal::QuotedString("%Y-%m".to_owned()))
1195            }))
1196            .to_sql()
1197        );
1198
1199        assert_eq!(
1200            "LAST_DAY(DATE '2022-10-12')",
1201            &Expr::Function(Box::new(Function::LastDay(Expr::TypedString {
1202                data_type: DataType::Date,
1203                value: "2022-10-12".to_owned()
1204            })))
1205            .to_sql()
1206        );
1207
1208        assert_eq!(
1209            "TO_DATE('2022-10-12', '%Y-%m-%d')",
1210            &Expr::Function(Box::new(Function::ToDate {
1211                expr: Expr::Literal(Literal::QuotedString("2022-10-12".to_owned())),
1212                format: Expr::Literal(Literal::QuotedString("%Y-%m-%d".to_owned()))
1213            }))
1214            .to_sql()
1215        );
1216
1217        assert_eq!(
1218            "TO_TIMESTAMP('2022-10-12 00:34:23', '%Y-%m-%d %H:%M:%S')",
1219            &Expr::Function(Box::new(Function::ToTimestamp {
1220                expr: Expr::Literal(Literal::QuotedString("2022-10-12 00:34:23".to_owned())),
1221                format: Expr::Literal(Literal::QuotedString("%Y-%m-%d %H:%M:%S".to_owned()))
1222            }))
1223            .to_sql()
1224        );
1225
1226        assert_eq!(
1227            "TO_TIME('00:34:23', '%H:%M:%S')",
1228            &Expr::Function(Box::new(Function::ToTime {
1229                expr: Expr::Literal(Literal::QuotedString("00:34:23".to_owned())),
1230                format: Expr::Literal(Literal::QuotedString("%H:%M:%S".to_owned()))
1231            }))
1232            .to_sql()
1233        );
1234
1235        assert_eq!(
1236            "POSITION('cup' IN 'cupcake')",
1237            &Expr::Function(Box::new(Function::Position {
1238                from_expr: Expr::Literal(Literal::QuotedString("cupcake".to_owned())),
1239                sub_expr: Expr::Literal(Literal::QuotedString("cup".to_owned())),
1240            }))
1241            .to_sql()
1242        );
1243
1244        assert_eq!(
1245            "FIND_IDX('noodle', 'o', 2)",
1246            &Expr::Function(Box::new(Function::FindIdx {
1247                from_expr: Expr::Literal(Literal::QuotedString("noodle".to_owned())),
1248                sub_expr: Expr::Literal(Literal::QuotedString("o".to_owned())),
1249                start: Some(Expr::Literal(Literal::Number(
1250                    BigDecimal::from_str("2").unwrap()
1251                )))
1252            }))
1253            .to_sql()
1254        );
1255
1256        assert_eq!(
1257            "FIND_IDX('goat cheese', 'goat')",
1258            &Expr::Function(Box::new(Function::FindIdx {
1259                from_expr: Expr::Literal(Literal::QuotedString("goat cheese".to_owned())),
1260                sub_expr: Expr::Literal(Literal::QuotedString("goat".to_owned())),
1261                start: None
1262            }))
1263            .to_sql()
1264        );
1265
1266        assert_eq!(
1267            "ASCII('H')",
1268            &Expr::Function(Box::new(Function::Ascii(Expr::Literal(
1269                Literal::QuotedString("H".to_owned())
1270            ))))
1271            .to_sql()
1272        );
1273
1274        assert_eq!(
1275            r"CHR(72)",
1276            &Expr::Function(Box::new(Function::Chr(Expr::Literal(Literal::Number(
1277                BigDecimal::from_str("72").unwrap()
1278            )))))
1279            .to_sql()
1280        );
1281
1282        assert_eq!(
1283            "MD5('GlueSQL')",
1284            &Expr::Function(Box::new(Function::Md5(Expr::Literal(
1285                Literal::QuotedString("GlueSQL".to_owned())
1286            ))))
1287            .to_sql()
1288        );
1289
1290        assert_eq!(
1291            "HEX(228)",
1292            &Expr::Function(Box::new(Function::Hex(Expr::Literal(Literal::Number(
1293                BigDecimal::from(228)
1294            )))))
1295            .to_sql()
1296        );
1297
1298        assert_eq!(
1299            "HEX('GlueSQL')",
1300            &Expr::Function(Box::new(Function::Hex(Expr::Literal(
1301                Literal::QuotedString("GlueSQL".to_owned())
1302            ))))
1303            .to_sql()
1304        );
1305
1306        assert_eq!(
1307            r"EXTRACT(MINUTE FROM '2022-05-05 01:02:03')",
1308            &Expr::Function(Box::new(Function::Extract {
1309                field: DateTimeField::Minute,
1310                expr: Expr::Literal(Literal::QuotedString("2022-05-05 01:02:03".to_owned()))
1311            }))
1312            .to_sql()
1313        );
1314
1315        assert_eq!(
1316            r#"APPEND("list", "value")"#,
1317            &Expr::Function(Box::new(Function::Append {
1318                expr: Expr::Identifier("list".to_owned()),
1319                value: Expr::Identifier("value".to_owned())
1320            }))
1321            .to_sql()
1322        );
1323
1324        assert_eq!(
1325            r#"PREPEND("list", "value")"#,
1326            &Expr::Function(Box::new(Function::Prepend {
1327                expr: Expr::Identifier("list".to_owned()),
1328                value: Expr::Identifier("value".to_owned())
1329            }))
1330            .to_sql()
1331        );
1332
1333        assert_eq!(
1334            r#"SKIP("list", 2)"#,
1335            &Expr::Function(Box::new(Function::Skip {
1336                expr: Expr::Identifier("list".to_owned()),
1337                size: Expr::Literal(Literal::Number(BigDecimal::from_str("2").unwrap()))
1338            }))
1339            .to_sql()
1340        );
1341
1342        assert_eq!(
1343            r#"SORT("list")"#,
1344            &Expr::Function(Box::new(Function::Sort {
1345                expr: Expr::Identifier("list".to_owned()),
1346                order: None
1347            }))
1348            .to_sql()
1349        );
1350
1351        assert_eq!(
1352            r#"SORT("list", 'ASC')"#,
1353            &Expr::Function(Box::new(Function::Sort {
1354                expr: Expr::Identifier("list".to_owned()),
1355                order: Some(Expr::Literal(Literal::QuotedString("ASC".to_owned())))
1356            }))
1357            .to_sql()
1358        );
1359
1360        assert_eq!(
1361            r#"SLICE("list", 1, 2)"#,
1362            &Expr::Function(Box::new(Function::Slice {
1363                expr: (Expr::Identifier("list".to_owned())),
1364                start: (Expr::Literal(Literal::Number(BigDecimal::from_str("1").unwrap()))),
1365                length: (Expr::Literal(Literal::Number(BigDecimal::from_str("2").unwrap())))
1366            }))
1367            .to_sql()
1368        );
1369
1370        assert_eq!(
1371            r#"TAKE("list", 3)"#,
1372            &Expr::Function(Box::new(Function::Take {
1373                expr: Expr::Identifier("list".to_owned()),
1374                size: Expr::Literal(Literal::Number(BigDecimal::from_str("3").unwrap()))
1375            }))
1376            .to_sql()
1377        );
1378
1379        assert_eq!(
1380            "GET_X(\"point\")",
1381            &Expr::Function(Box::new(Function::GetX(Expr::Identifier(
1382                "point".to_owned()
1383            ))))
1384            .to_sql()
1385        );
1386
1387        assert_eq!(
1388            "GET_Y(\"point\")",
1389            &Expr::Function(Box::new(Function::GetY(Expr::Identifier(
1390                "point".to_owned()
1391            ))))
1392            .to_sql()
1393        );
1394
1395        assert_eq!(
1396            "POINT(0.1, 0.2)",
1397            &Expr::Function(Box::new(Function::Point {
1398                x: Expr::Literal(Literal::Number(BigDecimal::from_str("0.1").unwrap())),
1399                y: Expr::Literal(Literal::Number(BigDecimal::from_str("0.2").unwrap()))
1400            }))
1401            .to_sql()
1402        );
1403
1404        assert_eq!(
1405            "CALC_DISTANCE(POINT(1.1, 2.3), POINT(1.4, 3.6))",
1406            &Expr::Function(Box::new(Function::CalcDistance {
1407                geometry1: Expr::Function(Box::new(Function::Point {
1408                    x: Expr::Literal(Literal::Number(BigDecimal::from_str("1.1").unwrap())),
1409                    y: Expr::Literal(Literal::Number(BigDecimal::from_str("2.3").unwrap()))
1410                })),
1411                geometry2: Expr::Function(Box::new(Function::Point {
1412                    x: Expr::Literal(Literal::Number(BigDecimal::from_str("1.4").unwrap())),
1413                    y: Expr::Literal(Literal::Number(BigDecimal::from_str("3.6").unwrap()))
1414                }))
1415            }))
1416            .to_sql()
1417        );
1418
1419        assert_eq!(
1420            r#"IS_EMPTY("list")"#,
1421            &Expr::Function(Box::new(Function::IsEmpty(Expr::Identifier(
1422                "list".to_owned()
1423            ))))
1424            .to_sql()
1425        );
1426
1427        assert_eq!(
1428            r#"LENGTH("GlueSQL")"#,
1429            &Expr::Function(Box::new(Function::Length(Expr::Identifier(
1430                "GlueSQL".to_owned()
1431            ))))
1432            .to_sql()
1433        );
1434
1435        assert_eq!(
1436            r#"ENTRIES("map")"#,
1437            &Expr::Function(Box::new(Function::Entries(Expr::Identifier(
1438                "map".to_owned()
1439            ))))
1440            .to_sql()
1441        );
1442
1443        assert_eq!(
1444            r#"KEYS("map")"#,
1445            &Expr::Function(Box::new(Function::Keys(Expr::Identifier("map".to_owned())))).to_sql()
1446        );
1447
1448        assert_eq!(
1449            r#"VALUES("map")"#,
1450            &Expr::Function(Box::new(Function::Values(Expr::Identifier(
1451                "map".to_owned()
1452            ))))
1453            .to_sql()
1454        );
1455
1456        assert_eq!(
1457            r#"SPLICE("list", 2, 4)"#,
1458            &Expr::Function(Box::new(Function::Splice {
1459                list_data: Expr::Identifier("list".to_owned()),
1460                begin_index: Expr::Literal(Literal::Number(BigDecimal::from_str("2").unwrap())),
1461                end_index: Expr::Literal(Literal::Number(BigDecimal::from_str("4").unwrap())),
1462                values: None
1463            }))
1464            .to_sql()
1465        );
1466
1467        assert_eq!(
1468            r#"SPLICE("list", 2, 4, "values")"#,
1469            &Expr::Function(Box::new(Function::Splice {
1470                list_data: Expr::Identifier("list".to_owned()),
1471                begin_index: Expr::Literal(Literal::Number(BigDecimal::from_str("2").unwrap())),
1472                end_index: Expr::Literal(Literal::Number(BigDecimal::from_str("4").unwrap())),
1473                values: Some(Expr::Identifier("values".to_owned()))
1474            }))
1475            .to_sql()
1476        );
1477
1478        assert_eq!(
1479            r#"DEDUP("list")"#,
1480            &Expr::Function(Box::new(Function::Dedup(Expr::Identifier(
1481                "list".to_owned()
1482            ))))
1483            .to_sql(),
1484        );
1485    }
1486
1487    #[test]
1488    fn to_sql_aggregate() {
1489        assert_eq!(
1490            r#"MAX("id")"#,
1491            Expr::Aggregate(Box::new(Aggregate::max(
1492                Expr::Identifier("id".to_owned()),
1493                false
1494            )))
1495            .to_sql()
1496        );
1497
1498        assert_eq!(
1499            r#"MAX(DISTINCT "id")"#,
1500            Expr::Aggregate(Box::new(Aggregate::max(
1501                Expr::Identifier("id".to_owned()),
1502                true
1503            )))
1504            .to_sql()
1505        );
1506
1507        assert_eq!(
1508            "COUNT(*)",
1509            Expr::Aggregate(Box::new(Aggregate::count(CountArgExpr::Wildcard, false))).to_sql()
1510        );
1511
1512        assert_eq!(
1513            "COUNT(DISTINCT *)",
1514            Expr::Aggregate(Box::new(Aggregate::count(CountArgExpr::Wildcard, true))).to_sql()
1515        );
1516
1517        assert_eq!(
1518            r#"COUNT(DISTINCT "id")"#,
1519            Expr::Aggregate(Box::new(Aggregate::count(
1520                CountArgExpr::Expr(Expr::Identifier("id".to_owned())),
1521                true
1522            )))
1523            .to_sql()
1524        );
1525
1526        assert_eq!(
1527            r#"MIN("id")"#,
1528            Expr::Aggregate(Box::new(Aggregate::min(
1529                Expr::Identifier("id".to_owned()),
1530                false
1531            )))
1532            .to_sql()
1533        );
1534
1535        assert_eq!(
1536            r#"MIN(DISTINCT "id")"#,
1537            Expr::Aggregate(Box::new(Aggregate::min(
1538                Expr::Identifier("id".to_owned()),
1539                true
1540            )))
1541            .to_sql()
1542        );
1543
1544        assert_eq!(
1545            r#"SUM("price")"#,
1546            Expr::Aggregate(Box::new(Aggregate::sum(
1547                Expr::Identifier("price".to_owned()),
1548                false
1549            )))
1550            .to_sql()
1551        );
1552
1553        assert_eq!(
1554            r#"SUM(DISTINCT "price")"#,
1555            Expr::Aggregate(Box::new(Aggregate::sum(
1556                Expr::Identifier("price".to_owned()),
1557                true
1558            )))
1559            .to_sql()
1560        );
1561
1562        assert_eq!(
1563            r#"AVG("pay")"#,
1564            Expr::Aggregate(Box::new(Aggregate::avg(
1565                Expr::Identifier("pay".to_owned()),
1566                false
1567            )))
1568            .to_sql()
1569        );
1570
1571        assert_eq!(
1572            r#"AVG(DISTINCT "pay")"#,
1573            Expr::Aggregate(Box::new(Aggregate::avg(
1574                Expr::Identifier("pay".to_owned()),
1575                true
1576            )))
1577            .to_sql()
1578        );
1579
1580        assert_eq!(
1581            r#"VARIANCE("pay")"#,
1582            Expr::Aggregate(Box::new(Aggregate::variance(
1583                Expr::Identifier("pay".to_owned()),
1584                false
1585            )))
1586            .to_sql()
1587        );
1588
1589        assert_eq!(
1590            r#"VARIANCE(DISTINCT "pay")"#,
1591            Expr::Aggregate(Box::new(Aggregate::variance(
1592                Expr::Identifier("pay".to_owned()),
1593                true
1594            )))
1595            .to_sql()
1596        );
1597
1598        assert_eq!(
1599            r#"STDEV("total")"#,
1600            Expr::Aggregate(Box::new(Aggregate::stdev(
1601                Expr::Identifier("total".to_owned()),
1602                false
1603            )))
1604            .to_sql()
1605        );
1606
1607        assert_eq!(
1608            r#"STDEV(DISTINCT "total")"#,
1609            Expr::Aggregate(Box::new(Aggregate::stdev(
1610                Expr::Identifier("total".to_owned()),
1611                true
1612            )))
1613            .to_sql()
1614        );
1615    }
1616}