gluesql_core/ast/
function.rs

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}