Skip to main content

gluesql_core/query_builder/
expr.rs

1mod binary_op;
2mod case;
3mod exists;
4mod is_null;
5mod like;
6mod nested;
7mod order_by;
8mod regex;
9mod unary_op;
10
11pub mod aggregate;
12pub mod alias_as;
13pub mod between;
14pub mod function;
15pub mod in_list;
16pub mod numeric;
17
18use {
19    crate::{
20        ast::{BinaryOperator, Expr, Literal, UnaryOperator},
21        data::Value,
22        parse_sql::{parse_comma_separated_exprs, parse_expr, parse_query},
23        plan::{ExprPlan, QueryPlan},
24        prelude::DataType,
25        query_builder::QueryNode,
26        result::Result,
27        translate::{NO_PARAMS, translate_expr, translate_query},
28    },
29    aggregate::AggregateNode,
30    bigdecimal::BigDecimal,
31    function::FunctionNode,
32    in_list::InListNode,
33    numeric::NumericNode,
34    std::borrow::Cow,
35};
36pub use {
37    case::case,
38    exists::{exists, not_exists},
39    nested::nested,
40    unary_op::{bitwise_not, factorial, minus, not, plus},
41};
42
43#[derive(Clone, Debug)]
44pub enum ExprNode<'a> {
45    Expr(Cow<'a, Expr>),
46    SqlExpr(Cow<'a, str>),
47    Identifier(Cow<'a, str>),
48    Numeric(NumericNode<'a>),
49    QuotedString(Cow<'a, str>),
50    TypedString {
51        data_type: DataType,
52        value: Cow<'a, str>,
53    },
54    Between {
55        expr: Box<ExprNode<'a>>,
56        negated: bool,
57        low: Box<ExprNode<'a>>,
58        high: Box<ExprNode<'a>>,
59    },
60    Like {
61        expr: Box<ExprNode<'a>>,
62        negated: bool,
63        pattern: Box<ExprNode<'a>>,
64    },
65    ILike {
66        expr: Box<ExprNode<'a>>,
67        negated: bool,
68        pattern: Box<ExprNode<'a>>,
69    },
70    Regex {
71        expr: Box<ExprNode<'a>>,
72        negated: bool,
73        pattern: Box<ExprNode<'a>>,
74        case_sensitive: bool,
75    },
76    BinaryOp {
77        left: Box<ExprNode<'a>>,
78        op: BinaryOperator,
79        right: Box<ExprNode<'a>>,
80    },
81    UnaryOp {
82        op: UnaryOperator,
83        expr: Box<ExprNode<'a>>,
84    },
85    IsNull(Box<ExprNode<'a>>),
86    IsNotNull(Box<ExprNode<'a>>),
87    InList {
88        expr: Box<ExprNode<'a>>,
89        list: Box<InListNode<'a>>,
90        negated: bool,
91    },
92    Nested(Box<ExprNode<'a>>),
93    Function(Box<FunctionNode<'a>>),
94    Aggregate(Box<AggregateNode<'a>>),
95    Exists {
96        subquery: Box<QueryNode<'a>>,
97        negated: bool,
98    },
99    Subquery(Box<QueryNode<'a>>),
100    Case {
101        operand: Option<Box<ExprNode<'a>>>,
102        when_then: Vec<(ExprNode<'a>, ExprNode<'a>)>,
103        else_result: Option<Box<ExprNode<'a>>>,
104    },
105}
106
107impl ExprNode<'_> {
108    pub(super) fn build_expr_plan(self) -> Result<ExprPlan> {
109        match self {
110            ExprNode::Expr(expr) => Ok(expr.into_owned().into()),
111            ExprNode::SqlExpr(expr) => {
112                let expr = parse_expr(expr)?;
113
114                translate_expr(&expr, NO_PARAMS).map(Into::into)
115            }
116            ExprNode::Identifier(value) => {
117                let idents = value.as_ref().split('.').collect::<Vec<_>>();
118
119                Ok(match idents.as_slice() {
120                    [alias, ident] => ExprPlan::CompoundIdentifier {
121                        alias: (*alias).to_owned(),
122                        ident: (*ident).to_owned(),
123                    },
124                    _ => ExprPlan::Identifier(value.into_owned()),
125                })
126            }
127            ExprNode::Numeric(node) => node.try_into().map(ExprPlan::Literal),
128            ExprNode::QuotedString(value) => {
129                let value = value.into_owned();
130
131                Ok(ExprPlan::Literal(Literal::QuotedString(value)))
132            }
133            ExprNode::TypedString { data_type, value } => Ok(ExprPlan::TypedString {
134                data_type,
135                value: value.into_owned(),
136            }),
137            ExprNode::Between {
138                expr,
139                negated,
140                low,
141                high,
142            } => {
143                let expr = (*expr).build_expr_plan().map(Box::new)?;
144                let low = (*low).build_expr_plan().map(Box::new)?;
145                let high = (*high).build_expr_plan().map(Box::new)?;
146
147                Ok(ExprPlan::Between {
148                    expr,
149                    negated,
150                    low,
151                    high,
152                })
153            }
154            ExprNode::Like {
155                expr,
156                negated,
157                pattern,
158            } => {
159                let expr = (*expr).build_expr_plan().map(Box::new)?;
160                let pattern = (*pattern).build_expr_plan().map(Box::new)?;
161
162                Ok(ExprPlan::Like {
163                    expr,
164                    negated,
165                    pattern,
166                })
167            }
168            ExprNode::ILike {
169                expr,
170                negated,
171                pattern,
172            } => {
173                let expr = (*expr).build_expr_plan().map(Box::new)?;
174                let pattern = (*pattern).build_expr_plan().map(Box::new)?;
175
176                Ok(ExprPlan::ILike {
177                    expr,
178                    negated,
179                    pattern,
180                })
181            }
182            ExprNode::Regex {
183                expr,
184                negated,
185                pattern,
186                case_sensitive,
187            } => {
188                let expr = (*expr).build_expr_plan().map(Box::new)?;
189                let pattern = (*pattern).build_expr_plan().map(Box::new)?;
190
191                Ok(ExprPlan::Regex {
192                    expr,
193                    negated,
194                    pattern,
195                    case_sensitive,
196                })
197            }
198            ExprNode::BinaryOp { left, op, right } => {
199                let left = (*left).build_expr_plan().map(Box::new)?;
200                let right = (*right).build_expr_plan().map(Box::new)?;
201
202                Ok(ExprPlan::BinaryOp { left, op, right })
203            }
204            ExprNode::UnaryOp { op, expr } => {
205                let expr = (*expr).build_expr_plan().map(Box::new)?;
206                Ok(ExprPlan::UnaryOp { op, expr })
207            }
208            ExprNode::IsNull(expr) => (*expr)
209                .build_expr_plan()
210                .map(Box::new)
211                .map(ExprPlan::IsNull),
212            ExprNode::IsNotNull(expr) => (*expr)
213                .build_expr_plan()
214                .map(Box::new)
215                .map(ExprPlan::IsNotNull),
216            ExprNode::InList {
217                expr,
218                list,
219                negated,
220            } => {
221                let expr = (*expr).build_expr_plan().map(Box::new)?;
222
223                match *list {
224                    InListNode::InList(list) => {
225                        let list = list
226                            .into_iter()
227                            .map(ExprNode::build_expr_plan)
228                            .collect::<Result<Vec<_>>>()?;
229                        Ok(ExprPlan::InList {
230                            expr,
231                            list,
232                            negated,
233                        })
234                    }
235                    InListNode::Query(subquery) => {
236                        let subquery = subquery.build_query_plan().map(Box::new)?;
237                        Ok(ExprPlan::InSubquery {
238                            expr,
239                            subquery,
240                            negated,
241                        })
242                    }
243                    InListNode::Text(value) => {
244                        let subquery = parse_query(value.clone())
245                            .and_then(|item| translate_query(&item, NO_PARAMS))
246                            .map(QueryPlan::from)
247                            .map(Box::new);
248
249                        if let Ok(subquery) = subquery {
250                            return Ok(ExprPlan::InSubquery {
251                                expr,
252                                subquery,
253                                negated,
254                            });
255                        }
256
257                        parse_comma_separated_exprs(&*value)?
258                            .iter()
259                            .map(|expr| translate_expr(expr, NO_PARAMS).map(Into::into))
260                            .collect::<Result<Vec<_>>>()
261                            .map(|list| ExprPlan::InList {
262                                expr,
263                                list,
264                                negated,
265                            })
266                    }
267                }
268            }
269            ExprNode::Nested(expr) => (*expr)
270                .build_expr_plan()
271                .map(Box::new)
272                .map(ExprPlan::Nested),
273            ExprNode::Function(func_expr) => (*func_expr)
274                .build_function_expr_plan()
275                .map(Box::new)
276                .map(ExprPlan::Function),
277            ExprNode::Aggregate(aggr_expr) => (*aggr_expr)
278                .build_aggregate_expr_plan()
279                .map(Box::new)
280                .map(ExprPlan::Aggregate),
281            ExprNode::Exists { subquery, negated } => (*subquery)
282                .build_query_plan()
283                .map(Box::new)
284                .map(|subquery| ExprPlan::Exists { subquery, negated }),
285            ExprNode::Subquery(subquery) => (*subquery)
286                .build_query_plan()
287                .map(Box::new)
288                .map(ExprPlan::Subquery),
289            ExprNode::Case {
290                operand,
291                when_then,
292                else_result,
293            } => {
294                let operand = operand
295                    .map(|expr| (*expr).build_expr_plan())
296                    .transpose()?
297                    .map(Box::new);
298                let when_then = when_then
299                    .into_iter()
300                    .map(|(when, then)| {
301                        let when = when.build_expr_plan()?;
302                        let then = then.build_expr_plan()?;
303                        Ok((when, then))
304                    })
305                    .collect::<Result<Vec<_>>>()?;
306
307                let else_result = else_result
308                    .map(|expr| (*expr).build_expr_plan())
309                    .transpose()?
310                    .map(Box::new);
311                Ok(ExprPlan::Case {
312                    operand,
313                    when_then,
314                    else_result,
315                })
316            }
317        }
318    }
319}
320
321impl ExprNode<'_> {
322    pub(super) fn build_expr(self) -> Result<Expr> {
323        match self {
324            ExprNode::Expr(expr) => Ok(expr.into_owned()),
325            ExprNode::SqlExpr(expr) => {
326                let expr = parse_expr(expr)?;
327
328                translate_expr(&expr, NO_PARAMS)
329            }
330            ExprNode::Identifier(value) => {
331                let idents = value.as_ref().split('.').collect::<Vec<_>>();
332
333                Ok(match idents.as_slice() {
334                    [alias, ident] => Expr::CompoundIdentifier {
335                        alias: (*alias).to_owned(),
336                        ident: (*ident).to_owned(),
337                    },
338                    _ => Expr::Identifier(value.into_owned()),
339                })
340            }
341            ExprNode::Numeric(node) => node.try_into().map(Expr::Literal),
342            ExprNode::QuotedString(value) => {
343                let value = value.into_owned();
344
345                Ok(Expr::Literal(Literal::QuotedString(value)))
346            }
347            ExprNode::TypedString { data_type, value } => Ok(Expr::TypedString {
348                data_type,
349                value: value.into_owned(),
350            }),
351            ExprNode::Between {
352                expr,
353                negated,
354                low,
355                high,
356            } => {
357                let expr = expr.build_expr().map(Box::new)?;
358                let low = low.build_expr().map(Box::new)?;
359                let high = high.build_expr().map(Box::new)?;
360
361                Ok(Expr::Between {
362                    expr,
363                    negated,
364                    low,
365                    high,
366                })
367            }
368            ExprNode::Like {
369                expr,
370                negated,
371                pattern,
372            } => {
373                let expr = expr.build_expr().map(Box::new)?;
374                let pattern = pattern.build_expr().map(Box::new)?;
375
376                Ok(Expr::Like {
377                    expr,
378                    negated,
379                    pattern,
380                })
381            }
382            ExprNode::ILike {
383                expr,
384                negated,
385                pattern,
386            } => {
387                let expr = expr.build_expr().map(Box::new)?;
388                let pattern = pattern.build_expr().map(Box::new)?;
389
390                Ok(Expr::ILike {
391                    expr,
392                    negated,
393                    pattern,
394                })
395            }
396            ExprNode::Regex {
397                expr,
398                negated,
399                pattern,
400                case_sensitive,
401            } => {
402                let expr = expr.build_expr().map(Box::new)?;
403                let pattern = pattern.build_expr().map(Box::new)?;
404
405                Ok(Expr::Regex {
406                    expr,
407                    negated,
408                    pattern,
409                    case_sensitive,
410                })
411            }
412            ExprNode::BinaryOp { left, op, right } => {
413                let left = left.build_expr().map(Box::new)?;
414                let right = right.build_expr().map(Box::new)?;
415
416                Ok(Expr::BinaryOp { left, op, right })
417            }
418            ExprNode::UnaryOp { op, expr } => {
419                let expr = expr.build_expr().map(Box::new)?;
420                Ok(Expr::UnaryOp { op, expr })
421            }
422            ExprNode::IsNull(expr) => expr.build_expr().map(Box::new).map(Expr::IsNull),
423            ExprNode::IsNotNull(expr) => expr.build_expr().map(Box::new).map(Expr::IsNotNull),
424            ExprNode::InList {
425                expr,
426                list,
427                negated,
428            } => {
429                let expr = expr.build_expr().map(Box::new)?;
430
431                match *list {
432                    InListNode::InList(list) => {
433                        let list = list
434                            .into_iter()
435                            .map(ExprNode::build_expr)
436                            .collect::<Result<Vec<_>>>()?;
437                        Ok(Expr::InList {
438                            expr,
439                            list,
440                            negated,
441                        })
442                    }
443                    InListNode::Text(value) => {
444                        let subquery = parse_query(value.clone())
445                            .and_then(|item| translate_query(&item, NO_PARAMS))
446                            .map(Box::new);
447
448                        if let Ok(subquery) = subquery {
449                            return Ok(Expr::InSubquery {
450                                expr,
451                                subquery,
452                                negated,
453                            });
454                        }
455
456                        parse_comma_separated_exprs(&value)?
457                            .iter()
458                            .map(|expr| translate_expr(expr, NO_PARAMS))
459                            .collect::<Result<Vec<_>>>()
460                            .map(|list| Expr::InList {
461                                expr,
462                                list,
463                                negated,
464                            })
465                    }
466                    InListNode::Query(subquery) => {
467                        let subquery = (*subquery).build_query().map(Box::new)?;
468                        Ok(Expr::InSubquery {
469                            expr,
470                            subquery,
471                            negated,
472                        })
473                    }
474                }
475            }
476            ExprNode::Nested(expr) => expr.build_expr().map(Box::new).map(Expr::Nested),
477            ExprNode::Function(func_expr) => {
478                func_expr.build_function().map(Box::new).map(Expr::Function)
479            }
480            ExprNode::Aggregate(aggr_expr) => aggr_expr
481                .build_aggregate()
482                .map(Box::new)
483                .map(Expr::Aggregate),
484            ExprNode::Exists { subquery, negated } => (*subquery)
485                .build_query()
486                .map(Box::new)
487                .map(|subquery| Expr::Exists { subquery, negated }),
488            ExprNode::Subquery(subquery) => {
489                (*subquery).build_query().map(Box::new).map(Expr::Subquery)
490            }
491            ExprNode::Case {
492                operand,
493                when_then,
494                else_result,
495            } => {
496                let operand = operand
497                    .map(|expr| expr.build_expr())
498                    .transpose()?
499                    .map(Box::new);
500                let when_then = when_then
501                    .into_iter()
502                    .map(|(when, then)| {
503                        let when = when.build_expr()?;
504                        let then = then.build_expr()?;
505                        Ok((when, then))
506                    })
507                    .collect::<Result<Vec<_>>>()?;
508
509                let else_result = else_result
510                    .map(|expr| expr.build_expr())
511                    .transpose()?
512                    .map(Box::new);
513                Ok(Expr::Case {
514                    operand,
515                    when_then,
516                    else_result,
517                })
518            }
519        }
520    }
521}
522
523impl<'a> From<&'a str> for ExprNode<'a> {
524    fn from(expr: &'a str) -> Self {
525        ExprNode::SqlExpr(Cow::Borrowed(expr))
526    }
527}
528
529impl From<String> for ExprNode<'_> {
530    fn from(expr: String) -> Self {
531        ExprNode::SqlExpr(Cow::Owned(expr))
532    }
533}
534
535impl From<i64> for ExprNode<'_> {
536    fn from(n: i64) -> Self {
537        ExprNode::Expr(Cow::Owned(Expr::Literal(Literal::Number(
538            BigDecimal::from(n),
539        ))))
540    }
541}
542
543impl From<bool> for ExprNode<'_> {
544    fn from(b: bool) -> Self {
545        ExprNode::Expr(Cow::Owned(Expr::Value(Value::Bool(b))))
546    }
547}
548
549impl<'a> From<QueryNode<'a>> for ExprNode<'a> {
550    fn from(node: QueryNode<'a>) -> Self {
551        ExprNode::Subquery(Box::new(node))
552    }
553}
554
555impl From<Expr> for ExprNode<'_> {
556    fn from(expr: Expr) -> Self {
557        ExprNode::Expr(Cow::Owned(expr))
558    }
559}
560
561impl<'a> From<&'a Expr> for ExprNode<'a> {
562    fn from(expr: &'a Expr) -> Self {
563        ExprNode::Expr(Cow::Borrowed(expr))
564    }
565}
566
567impl From<Value> for ExprNode<'_> {
568    fn from(v: Value) -> Self {
569        ExprNode::Expr(Cow::Owned(Expr::Value(v)))
570    }
571}
572
573pub fn expr<'a, T: Into<Cow<'a, str>>>(value: T) -> ExprNode<'a> {
574    ExprNode::SqlExpr(value.into())
575}
576
577pub fn col<'a, T: Into<Cow<'a, str>>>(value: T) -> ExprNode<'a> {
578    ExprNode::Identifier(value.into())
579}
580
581pub fn num<'a, T: Into<NumericNode<'a>>>(value: T) -> ExprNode<'a> {
582    ExprNode::Numeric(value.into())
583}
584
585pub fn text<'a, T: Into<Cow<'a, str>>>(value: T) -> ExprNode<'a> {
586    ExprNode::QuotedString(value.into())
587}
588
589pub fn date<'a, T: Into<Cow<'a, str>>>(date: T) -> ExprNode<'a> {
590    ExprNode::TypedString {
591        data_type: DataType::Date,
592        value: date.into(),
593    }
594}
595
596pub fn timestamp<'a, T: Into<Cow<'a, str>>>(timestamp: T) -> ExprNode<'a> {
597    ExprNode::TypedString {
598        data_type: DataType::Timestamp,
599        value: timestamp.into(),
600    }
601}
602
603pub fn time<'a, T: Into<Cow<'a, str>>>(time: T) -> ExprNode<'a> {
604    ExprNode::TypedString {
605        data_type: DataType::Time,
606        value: time.into(),
607    }
608}
609
610pub fn uuid<'a, T: Into<Cow<'a, str>>>(uuid: T) -> ExprNode<'a> {
611    ExprNode::TypedString {
612        data_type: DataType::Uuid,
613        value: uuid.into(),
614    }
615}
616
617/// Returns an AST `ExprNode` containing the provided `Bytea`.
618///
619/// # Arguments
620/// * `bytea` - A byte array to be converted to a Bytea AST node.
621///
622pub fn bytea<'a, T: AsRef<[u8]>>(bytea: T) -> ExprNode<'a> {
623    ExprNode::Expr(Cow::Owned(Expr::Value(Value::Bytea(
624        bytea.as_ref().to_vec(),
625    ))))
626}
627
628pub fn subquery<'a, T: Into<QueryNode<'a>>>(query_node: T) -> ExprNode<'a> {
629    ExprNode::Subquery(Box::new(query_node.into()))
630}
631
632pub fn null() -> ExprNode<'static> {
633    ExprNode::Expr(Cow::Owned(Expr::Value(Value::Null)))
634}
635
636pub fn value(v: Value) -> ExprNode<'static> {
637    ExprNode::Expr(Cow::Owned(Expr::Value(v)))
638}
639
640#[cfg(test)]
641mod tests {
642    use {
643        super::ExprNode,
644        crate::{
645            ast::Expr,
646            data::Value,
647            plan::ExprPlan,
648            query_builder::{
649                QueryNode, bytea, col, date, expr, null, num, subquery, table, test_expr, text,
650                time, timestamp, uuid, value,
651            },
652        },
653    };
654
655    #[test]
656    fn into_expr_node() {
657        let actual: ExprNode = "id IS NOT NULL".into();
658        let expected = "id IS NOT NULL";
659        test_expr(actual, expected);
660
661        let actual: ExprNode = String::from("1 + 10)").into();
662        let expected = "1 + 10";
663        test_expr(actual, expected);
664
665        let actual: ExprNode = 1024.into();
666        let expected = "1024";
667        test_expr(actual, expected);
668
669        let actual: ExprNode = true.into();
670        let expected = "True";
671        test_expr(actual, expected);
672
673        let actual: ExprNode = QueryNode::from(table("Foo").select().project("id")).into();
674        let expected = "(SELECT id FROM Foo)";
675        test_expr(actual, expected);
676
677        let expr = Expr::Identifier("id".to_owned());
678        let actual: ExprNode = (&expr).into();
679        let expected = "id";
680        test_expr(actual, expected);
681
682        let actual: ExprNode = expr.into();
683        test_expr(actual, expected);
684    }
685
686    #[test]
687    fn syntactic_sugar() {
688        let actual = expr("col1 > 10");
689        let expected = "col1 > 10";
690        test_expr(actual, expected);
691
692        let actual = col("id");
693        let expected = "id";
694        test_expr(actual, expected);
695
696        let actual = col("Foo.id");
697        let expected = "Foo.id";
698        test_expr(actual, expected);
699
700        let actual = num(2048);
701        let expected = "2048";
702        test_expr(actual, expected);
703
704        let actual = num(6.5);
705        let expected = "6.5";
706        test_expr(actual, expected);
707
708        let actual = num("123.456");
709        let expected = "123.456";
710        test_expr(actual, expected);
711
712        let actual = text("hello world");
713        let expected = "'hello world'";
714        test_expr(actual, expected);
715
716        let actual = date("2022-10-11");
717        let expected = "DATE '2022-10-11'";
718        test_expr(actual, expected);
719
720        let actual = timestamp("2022-10-11 13:34:49");
721        let expected = "TIMESTAMP '2022-10-11 13:34:49'";
722        test_expr(actual, expected);
723
724        let actual = time("15:00:07");
725        let expected = "TIME '15:00:07'";
726        test_expr(actual, expected);
727
728        let actual = uuid("936DA01F9ABD4d9d80C702AF85C822A8");
729        let expected = "UUID '936DA01F9ABD4d9d80C702AF85C822A8'";
730        test_expr(actual, expected);
731
732        let actual = bytea(b"hello world");
733        let expected = "X'68656c6c6f20776f726c64'";
734        test_expr(actual, expected);
735
736        let actual = subquery(table("Foo").select().filter("id IS NOT NULL"));
737        let expected = "(SELECT * FROM Foo WHERE id IS NOT NULL)";
738        test_expr(actual, expected);
739
740        let actual = subquery(
741            table("Foo")
742                .select()
743                .project("id")
744                .order_by("id")
745                .distinct(),
746        );
747        let expected = "(SELECT DISTINCT id FROM Foo ORDER BY id)";
748        test_expr(actual, expected);
749
750        let actual = null();
751        let expected = "NULL";
752        test_expr(actual, expected);
753    }
754
755    #[test]
756    fn value_injection() {
757        let test = |actual: ExprNode, expected: ExprPlan| {
758            pretty_assertions::assert_eq!(actual.build_expr_plan(), Ok(expected));
759        };
760
761        test(Value::I64(42).into(), ExprPlan::Value(Value::I64(42)));
762        test(
763            Value::Str("hello".to_owned()).into(),
764            ExprPlan::Value(Value::Str("hello".to_owned())),
765        );
766        test(value(Value::I64(100)), ExprPlan::Value(Value::I64(100)));
767        test(value(Value::Bool(true)), ExprPlan::Value(Value::Bool(true)));
768    }
769}