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