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