sqlparser_mysql/base/
condition.rs

1use std::collections::{HashSet, VecDeque};
2use std::fmt;
3use std::str;
4
5use nom::branch::alt;
6use nom::bytes::complete::{tag, tag_no_case};
7use nom::character::complete::{multispace0, multispace1};
8use nom::combinator::{map, opt};
9use nom::sequence::{delimited, pair, preceded, separated_pair, terminated, tuple};
10use nom::IResult;
11
12use base::arithmetic::ArithmeticExpression;
13use base::column::Column;
14use base::error::ParseSQLError;
15use base::{Literal, Operator};
16use dms::{BetweenAndClause, SelectStatement};
17
18#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
19pub enum ConditionBase {
20    Field(Column),
21    Literal(Literal),
22    LiteralList(Vec<Literal>),
23    NestedSelect(Box<SelectStatement>),
24}
25
26impl fmt::Display for ConditionBase {
27    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28        match *self {
29            ConditionBase::Field(ref col) => write!(f, "{}", col),
30            ConditionBase::Literal(ref literal) => write!(f, "{}", literal),
31            ConditionBase::LiteralList(ref ll) => write!(
32                f,
33                "({})",
34                ll.iter()
35                    .map(|l| l.to_string())
36                    .collect::<Vec<_>>()
37                    .join(", ")
38            ),
39            ConditionBase::NestedSelect(ref select) => write!(f, "{}", select),
40        }
41    }
42}
43
44#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
45pub struct ConditionTree {
46    pub operator: Operator,
47    pub left: Box<ConditionExpression>,
48    pub right: Box<ConditionExpression>,
49}
50
51impl<'a> ConditionTree {
52    pub fn contained_columns(&'a self) -> HashSet<&'a Column> {
53        let mut s = HashSet::new();
54        let mut q = VecDeque::<&'a ConditionTree>::new();
55        q.push_back(self);
56        while let Some(ct) = q.pop_front() {
57            match *ct.left.as_ref() {
58                ConditionExpression::Base(ConditionBase::Field(ref c)) => {
59                    s.insert(c);
60                }
61                ConditionExpression::LogicalOp(ref ct)
62                | ConditionExpression::ComparisonOp(ref ct) => q.push_back(ct),
63                _ => (),
64            }
65            match *ct.right.as_ref() {
66                ConditionExpression::Base(ConditionBase::Field(ref c)) => {
67                    s.insert(c);
68                }
69                ConditionExpression::LogicalOp(ref ct)
70                | ConditionExpression::ComparisonOp(ref ct) => q.push_back(ct),
71                _ => (),
72            }
73        }
74        s
75    }
76}
77
78impl fmt::Display for ConditionTree {
79    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80        write!(f, "{}", self.left)?;
81        write!(f, " {} ", self.operator)?;
82        write!(f, "{}", self.right)
83    }
84}
85
86/// WHERE CLAUSE
87#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
88pub enum ConditionExpression {
89    ComparisonOp(ConditionTree),
90    LogicalOp(ConditionTree),
91    NegationOp(Box<ConditionExpression>),
92    ExistsOp(Box<SelectStatement>),
93    Base(ConditionBase),
94    Arithmetic(Box<ArithmeticExpression>),
95    Bracketed(Box<ConditionExpression>),
96    BetweenAnd(BetweenAndClause),
97}
98
99impl ConditionExpression {
100    pub fn parse(i: &str) -> IResult<&str, ConditionExpression, ParseSQLError<&str>> {
101        let (remaining_input, (_, _, _, where_condition)) = tuple((
102            multispace0,
103            tag_no_case("WHERE"),
104            multispace1,
105            Self::condition_expr,
106        ))(i)?;
107
108        Ok((remaining_input, where_condition))
109    }
110
111    pub fn having_clause(i: &str) -> IResult<&str, ConditionExpression, ParseSQLError<&str>> {
112        let (remaining_input, (_, _, _, ce)) = tuple((
113            multispace0,
114            tag_no_case("HAVING"),
115            multispace1,
116            Self::condition_expr,
117        ))(i)?;
118
119        Ok((remaining_input, ce))
120    }
121
122    // Parse a conditional expression into a condition tree structure
123    pub fn condition_expr(i: &str) -> IResult<&str, ConditionExpression, ParseSQLError<&str>> {
124        let cond = map(
125            separated_pair(
126                Self::and_expr,
127                delimited(multispace0, tag_no_case("OR"), multispace1),
128                Self::condition_expr,
129            ),
130            |p| {
131                ConditionExpression::LogicalOp(ConditionTree {
132                    operator: Operator::Or,
133                    left: Box::new(p.0),
134                    right: Box::new(p.1),
135                })
136            },
137        );
138
139        alt((cond, Self::and_expr))(i)
140    }
141
142    fn and_expr(i: &str) -> IResult<&str, ConditionExpression, ParseSQLError<&str>> {
143        let cond = map(
144            separated_pair(
145                Self::parenthetical_expr,
146                delimited(multispace0, tag_no_case("AND"), multispace1),
147                Self::and_expr,
148            ),
149            |p| {
150                ConditionExpression::LogicalOp(ConditionTree {
151                    operator: Operator::And,
152                    left: Box::new(p.0),
153                    right: Box::new(p.1),
154                })
155            },
156        );
157
158        alt((cond, Self::parenthetical_expr))(i)
159    }
160
161    fn parenthetical_expr_helper(
162        i: &str,
163    ) -> IResult<&str, ConditionExpression, ParseSQLError<&str>> {
164        let (remaining_input, (_, _, left_expr, _, _, _, operator, _, right_expr)) = tuple((
165            tag("("),
166            multispace0,
167            Self::simple_expr,
168            multispace0,
169            tag(")"),
170            multispace0,
171            Operator::parse,
172            multispace0,
173            Self::simple_expr,
174        ))(i)?;
175
176        let left = Box::new(ConditionExpression::Bracketed(Box::new(left_expr)));
177        let right = Box::new(right_expr);
178        let cond = ConditionExpression::ComparisonOp(ConditionTree {
179            operator,
180            left,
181            right,
182        });
183
184        Ok((remaining_input, cond))
185    }
186
187    pub fn parenthetical_expr(i: &str) -> IResult<&str, ConditionExpression, ParseSQLError<&str>> {
188        alt((
189            Self::parenthetical_expr_helper,
190            map(
191                delimited(
192                    terminated(tag("("), multispace0),
193                    ConditionExpression::condition_expr,
194                    delimited(multispace0, tag(")"), multispace0),
195                ),
196                |inner| ConditionExpression::Bracketed(Box::new(inner)),
197            ),
198            Self::not_expr,
199        ))(i)
200    }
201
202    fn not_expr(i: &str) -> IResult<&str, ConditionExpression, ParseSQLError<&str>> {
203        alt((
204            map(
205                preceded(
206                    pair(tag_no_case("NOT"), multispace1),
207                    Self::parenthetical_expr,
208                ),
209                |right| ConditionExpression::NegationOp(Box::new(right)),
210            ),
211            Self::boolean_primary,
212        ))(i)
213    }
214
215    fn is_null(i: &str) -> IResult<&str, (Operator, ConditionExpression), ParseSQLError<&str>> {
216        let (remaining_input, (_, _, not, _, _)) = tuple((
217            tag_no_case("IS"),
218            multispace0,
219            opt(tag_no_case("NOT")),
220            multispace0,
221            tag_no_case("NULL"),
222        ))(i)?;
223
224        // XXX(malte): bit of a hack; would consumers ever need to know
225        // about "IS NULL" vs. "= NULL"?
226        Ok((
227            remaining_input,
228            (
229                if not.is_some() {
230                    Operator::NotEqual
231                } else {
232                    Operator::Equal
233                },
234                ConditionExpression::Base(ConditionBase::Literal(Literal::Null)),
235            ),
236        ))
237    }
238
239    fn in_operation(
240        i: &str,
241    ) -> IResult<&str, (Operator, ConditionExpression), ParseSQLError<&str>> {
242        map(
243            separated_pair(
244                opt(terminated(tag_no_case("NOT"), multispace1)),
245                terminated(tag_no_case("IN"), multispace0),
246                alt((
247                    map(
248                        delimited(tag("("), SelectStatement::nested_selection, tag(")")),
249                        |s| ConditionBase::NestedSelect(Box::new(s)),
250                    ),
251                    map(delimited(tag("("), Literal::value_list, tag(")")), |vs| {
252                        ConditionBase::LiteralList(vs)
253                    }),
254                )),
255            ),
256            |p| {
257                let nested = ConditionExpression::Base(p.1);
258                if (p.0).is_some() {
259                    (Operator::NotIn, nested)
260                } else {
261                    (Operator::In, nested)
262                }
263            },
264        )(i)
265    }
266
267    fn boolean_primary_rest(
268        i: &str,
269    ) -> IResult<&str, (Operator, ConditionExpression), ParseSQLError<&str>> {
270        alt((
271            Self::is_null,
272            Self::in_operation,
273            separated_pair(Operator::parse, multispace0, Self::predicate),
274        ))(i)
275    }
276
277    fn boolean_primary(i: &str) -> IResult<&str, ConditionExpression, ParseSQLError<&str>> {
278        alt((
279            map(
280                separated_pair(Self::predicate, multispace0, Self::boolean_primary_rest),
281                |e: (ConditionExpression, (Operator, ConditionExpression))| {
282                    ConditionExpression::ComparisonOp(ConditionTree {
283                        operator: (e.1).0,
284                        left: Box::new(e.0),
285                        right: Box::new((e.1).1),
286                    })
287                },
288            ),
289            Self::predicate,
290        ))(i)
291    }
292
293    fn predicate(i: &str) -> IResult<&str, ConditionExpression, ParseSQLError<&str>> {
294        let nested_exists = map(
295            tuple((
296                opt(delimited(multispace0, tag_no_case("NOT"), multispace1)),
297                delimited(multispace0, tag_no_case("EXISTS"), multispace0),
298                delimited(
299                    pair(tag("("), multispace0),
300                    SelectStatement::nested_selection,
301                    pair(multispace0, tag(")")),
302                ),
303            )),
304            |p| {
305                let nested = ConditionExpression::ExistsOp(Box::new(p.2));
306                if (p.0).is_some() {
307                    ConditionExpression::NegationOp(Box::new(nested))
308                } else {
309                    nested
310                }
311            },
312        );
313
314        alt((Self::simple_expr, nested_exists))(i)
315    }
316
317    pub fn simple_expr(i: &str) -> IResult<&str, ConditionExpression, ParseSQLError<&str>> {
318        let simple_expr = alt((
319            map(
320                delimited(
321                    terminated(tag("("), multispace0),
322                    ArithmeticExpression::parse,
323                    preceded(multispace0, tag(")")),
324                ),
325                |e| {
326                    ConditionExpression::Bracketed(Box::new(ConditionExpression::Arithmetic(
327                        Box::new(e),
328                    )))
329                },
330            ),
331            map(ArithmeticExpression::parse, |e| {
332                ConditionExpression::Arithmetic(Box::new(e))
333            }),
334            map(Literal::parse, |lit| {
335                ConditionExpression::Base(ConditionBase::Literal(lit))
336            }),
337            map(Column::parse, |f| {
338                ConditionExpression::Base(ConditionBase::Field(f))
339            }),
340            map(
341                delimited(tag("("), SelectStatement::nested_selection, tag(")")),
342                |s| ConditionExpression::Base(ConditionBase::NestedSelect(Box::new(s))),
343            ),
344        ));
345
346        alt((Self::between_and, simple_expr))(i)
347    }
348
349    fn between_and(i: &str) -> IResult<&str, ConditionExpression, ParseSQLError<&str>> {
350        map(BetweenAndClause::parse, |x| {
351            ConditionExpression::BetweenAnd(x)
352        })(i)
353    }
354}
355
356impl fmt::Display for ConditionExpression {
357    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
358        match *self {
359            ConditionExpression::ComparisonOp(ref tree) => write!(f, "{}", tree),
360            ConditionExpression::LogicalOp(ref tree) => write!(f, "{}", tree),
361            ConditionExpression::NegationOp(ref expr) => write!(f, "NOT {}", expr),
362            ConditionExpression::ExistsOp(ref expr) => write!(f, "EXISTS {}", expr),
363            ConditionExpression::Bracketed(ref expr) => write!(f, "({})", expr),
364            ConditionExpression::Base(ref base) => write!(f, "{}", base),
365            ConditionExpression::Arithmetic(ref expr) => write!(f, "{}", expr),
366            ConditionExpression::BetweenAnd(ref expr) => write!(f, "{}", expr),
367        }
368    }
369}
370
371#[cfg(test)]
372mod tests {
373    use base::arithmetic::{ArithmeticBase, ArithmeticExpression, ArithmeticOperator};
374    use base::condition::ConditionBase::{Field, LiteralList, NestedSelect};
375    use base::condition::ConditionExpression::{
376        Base, Bracketed, ComparisonOp, LogicalOp, NegationOp,
377    };
378    use base::table::Table;
379    use base::{FieldDefinitionExpression, ItemPlaceholder};
380
381    use super::*;
382
383    fn flat_condition_tree(
384        op: Operator,
385        l: ConditionBase,
386        r: ConditionBase,
387    ) -> ConditionExpression {
388        ConditionExpression::ComparisonOp(ConditionTree {
389            operator: op,
390            left: Box::new(ConditionExpression::Base(l)),
391            right: Box::new(ConditionExpression::Base(r)),
392        })
393    }
394
395    #[test]
396    fn ct_contained_columns() {
397        use std::collections::HashSet;
398
399        let cond = "a.foo = ? and b.bar = 42";
400
401        let res = ConditionExpression::condition_expr(cond);
402        let c1 = Column::from("a.foo");
403        let c2 = Column::from("b.bar");
404        let mut expected_cols = HashSet::new();
405        expected_cols.insert(&c1);
406        expected_cols.insert(&c2);
407        match res.unwrap().1 {
408            ConditionExpression::LogicalOp(ct) => {
409                assert_eq!(ct.contained_columns(), expected_cols);
410            }
411            _ => panic!(),
412        }
413    }
414
415    #[test]
416    fn equality_placeholder() {
417        x_equality_variable_placeholder(
418            "foo = ?",
419            Literal::Placeholder(ItemPlaceholder::QuestionMark),
420        );
421    }
422
423    #[test]
424    fn equality_variable_placeholder() {
425        x_equality_variable_placeholder(
426            "foo = :12",
427            Literal::Placeholder(ItemPlaceholder::ColonNumber(12)),
428        );
429    }
430
431    #[test]
432    fn equality_variable_placeholder_with_dollar_sign() {
433        x_equality_variable_placeholder(
434            "foo = $12",
435            Literal::Placeholder(ItemPlaceholder::DollarNumber(12)),
436        );
437    }
438
439    fn x_equality_variable_placeholder(cond: &str, literal: Literal) {
440        let res = ConditionExpression::condition_expr(cond);
441        assert_eq!(
442            res.unwrap().1,
443            flat_condition_tree(
444                Operator::Equal,
445                ConditionBase::Field(Column::from("foo")),
446                ConditionBase::Literal(literal),
447            )
448        );
449    }
450
451    fn x_operator_value(op: ArithmeticOperator, value: Literal) -> ConditionExpression {
452        ConditionExpression::Arithmetic(Box::new(ArithmeticExpression::new(
453            op,
454            ArithmeticBase::Column(Column::from("x")),
455            ArithmeticBase::Scalar(value),
456            None,
457        )))
458    }
459
460    #[test]
461    fn simple_arithmetic_expression() {
462        let cond = "x + 3";
463
464        let res = ConditionExpression::simple_expr(cond);
465        assert_eq!(
466            res.unwrap().1,
467            x_operator_value(ArithmeticOperator::Add, 3.into())
468        );
469    }
470
471    #[test]
472    fn simple_arithmetic_expression_with_parenthesis() {
473        let cond = "( x - 2 )";
474
475        let res = ConditionExpression::simple_expr(cond);
476        assert_eq!(
477            res.unwrap().1,
478            ConditionExpression::Bracketed(Box::new(x_operator_value(
479                ArithmeticOperator::Subtract,
480                2.into(),
481            )))
482        );
483    }
484
485    #[test]
486    fn parenthetical_arithmetic_expression() {
487        let cond = "( x * 5 )";
488
489        let res = ConditionExpression::parenthetical_expr(cond);
490        assert_eq!(
491            res.unwrap().1,
492            ConditionExpression::Bracketed(Box::new(x_operator_value(
493                ArithmeticOperator::Multiply,
494                5.into(),
495            )))
496        );
497    }
498
499    #[test]
500    fn condition_expression_with_arithmetics() {
501        let cond = "x * 3 = 21";
502
503        let res = ConditionExpression::condition_expr(cond);
504        assert_eq!(
505            res.unwrap().1,
506            ConditionExpression::ComparisonOp(ConditionTree {
507                operator: Operator::Equal,
508                left: Box::new(x_operator_value(ArithmeticOperator::Multiply, 3.into())),
509                right: Box::new(ConditionExpression::Base(ConditionBase::Literal(21.into()))),
510            })
511        );
512    }
513
514    #[test]
515    fn condition_expression_with_arithmetics_and_parenthesis() {
516        let cond = "(x - 7 = 15)";
517
518        let res = ConditionExpression::condition_expr(cond);
519        assert_eq!(
520            res.unwrap().1,
521            ConditionExpression::Bracketed(Box::new(ConditionExpression::ComparisonOp(
522                ConditionTree {
523                    operator: Operator::Equal,
524                    left: Box::new(x_operator_value(ArithmeticOperator::Subtract, 7.into())),
525                    right: Box::new(ConditionExpression::Base(ConditionBase::Literal(15.into()))),
526                }
527            )))
528        );
529    }
530
531    #[test]
532    fn condition_expression_with_arithmetics_in_parenthesis() {
533        let cond = "( x + 2) = 15";
534
535        let res = ConditionExpression::condition_expr(cond);
536        assert_eq!(
537            res.unwrap().1,
538            ConditionExpression::ComparisonOp(ConditionTree {
539                operator: Operator::Equal,
540                left: Box::new(ConditionExpression::Bracketed(Box::new(x_operator_value(
541                    ArithmeticOperator::Add,
542                    2.into(),
543                )))),
544                right: Box::new(ConditionExpression::Base(ConditionBase::Literal(15.into()))),
545            })
546        );
547    }
548
549    #[test]
550    fn condition_expression_with_arithmetics_in_parenthesis_in_both_side() {
551        let cond = "( x + 2) =(x*3)";
552
553        let res = ConditionExpression::condition_expr(cond);
554        assert_eq!(
555            res.unwrap().1,
556            ConditionExpression::ComparisonOp(ConditionTree {
557                operator: Operator::Equal,
558                left: Box::new(ConditionExpression::Bracketed(Box::new(x_operator_value(
559                    ArithmeticOperator::Add,
560                    2.into(),
561                )))),
562                right: Box::new(ConditionExpression::Bracketed(Box::new(x_operator_value(
563                    ArithmeticOperator::Multiply,
564                    3.into(),
565                )))),
566            })
567        );
568    }
569
570    #[test]
571    fn equality_literals() {
572        let cond1 = "foo = 42";
573        let cond2 = "foo = \"hello\"";
574
575        let res1 = ConditionExpression::condition_expr(cond1);
576        assert_eq!(
577            res1.unwrap().1,
578            flat_condition_tree(
579                Operator::Equal,
580                ConditionBase::Field(Column::from("foo")),
581                ConditionBase::Literal(Literal::Integer(42)),
582            )
583        );
584
585        let res2 = ConditionExpression::condition_expr(cond2);
586        assert_eq!(
587            res2.unwrap().1,
588            flat_condition_tree(
589                Operator::Equal,
590                ConditionBase::Field(Column::from("foo")),
591                ConditionBase::Literal(Literal::String(String::from("hello"))),
592            )
593        );
594    }
595
596    #[test]
597    fn inequality_literals() {
598        let cond1 = "foo >= 42";
599        let cond2 = "foo <= 5";
600
601        let res1 = ConditionExpression::condition_expr(cond1);
602        assert_eq!(
603            res1.unwrap().1,
604            flat_condition_tree(
605                Operator::GreaterOrEqual,
606                ConditionBase::Field(Column::from("foo")),
607                ConditionBase::Literal(Literal::Integer(42)),
608            )
609        );
610
611        let res2 = ConditionExpression::condition_expr(cond2);
612        assert_eq!(
613            res2.unwrap().1,
614            flat_condition_tree(
615                Operator::LessOrEqual,
616                ConditionBase::Field(Column::from("foo")),
617                ConditionBase::Literal(Literal::Integer(5)),
618            )
619        );
620    }
621
622    #[test]
623    fn empty_string_literal() {
624        let cond = "foo = ''";
625
626        let res = ConditionExpression::condition_expr(cond);
627        assert_eq!(
628            res.unwrap().1,
629            flat_condition_tree(
630                Operator::Equal,
631                ConditionBase::Field(Column::from("foo")),
632                ConditionBase::Literal(Literal::String(String::from(""))),
633            )
634        );
635    }
636
637    #[test]
638    fn parenthesis() {
639        let cond = "(foo = ? or bar = 12) and foobar = 'a'";
640
641        let a = ComparisonOp(ConditionTree {
642            operator: Operator::Equal,
643            left: Box::new(Base(Field("foo".into()))),
644            right: Box::new(Base(ConditionBase::Literal(Literal::Placeholder(
645                ItemPlaceholder::QuestionMark,
646            )))),
647        });
648
649        let b = ComparisonOp(ConditionTree {
650            operator: Operator::Equal,
651            left: Box::new(Base(Field("bar".into()))),
652            right: Box::new(Base(ConditionBase::Literal(Literal::Integer(12.into())))),
653        });
654
655        let left = Bracketed(Box::new(LogicalOp(ConditionTree {
656            operator: Operator::Or,
657            left: Box::new(a),
658            right: Box::new(b),
659        })));
660
661        let right = ComparisonOp(ConditionTree {
662            operator: Operator::Equal,
663            left: Box::new(Base(Field("foobar".into()))),
664            right: Box::new(Base(ConditionBase::Literal(Literal::String("a".into())))),
665        });
666
667        let complete = LogicalOp(ConditionTree {
668            operator: Operator::And,
669            left: Box::new(left),
670            right: Box::new(right),
671        });
672
673        let res = ConditionExpression::condition_expr(cond);
674        assert_eq!(res.unwrap().1, complete);
675    }
676
677    #[test]
678    fn order_of_operations() {
679        let cond = "foo = ? and bar = 12 or foobar = 'a'";
680
681        let a = ComparisonOp(ConditionTree {
682            operator: Operator::Equal,
683            left: Box::new(Base(Field("foo".into()))),
684            right: Box::new(Base(ConditionBase::Literal(Literal::Placeholder(
685                ItemPlaceholder::QuestionMark,
686            )))),
687        });
688
689        let b = ComparisonOp(ConditionTree {
690            operator: Operator::Equal,
691            left: Box::new(Base(Field("bar".into()))),
692            right: Box::new(Base(ConditionBase::Literal(Literal::Integer(12.into())))),
693        });
694
695        let left = LogicalOp(ConditionTree {
696            operator: Operator::And,
697            left: Box::new(a),
698            right: Box::new(b),
699        });
700
701        let right = ComparisonOp(ConditionTree {
702            operator: Operator::Equal,
703            left: Box::new(Base(Field("foobar".into()))),
704            right: Box::new(Base(ConditionBase::Literal(Literal::String("a".into())))),
705        });
706
707        let complete = LogicalOp(ConditionTree {
708            operator: Operator::Or,
709            left: Box::new(left),
710            right: Box::new(right),
711        });
712
713        let res = ConditionExpression::condition_expr(cond);
714        assert_eq!(res.unwrap().1, complete);
715    }
716
717    #[test]
718    fn negation() {
719        let cond = "not bar = 12 or foobar = 'a'";
720        use base::Literal;
721
722        let left = NegationOp(Box::new(ComparisonOp(ConditionTree {
723            operator: Operator::Equal,
724            left: Box::new(Base(Field("bar".into()))),
725            right: Box::new(Base(ConditionBase::Literal(Literal::Integer(12.into())))),
726        })));
727
728        let right = ComparisonOp(ConditionTree {
729            operator: Operator::Equal,
730            left: Box::new(Base(Field("foobar".into()))),
731            right: Box::new(Base(ConditionBase::Literal(Literal::String("a".into())))),
732        });
733
734        let complete = LogicalOp(ConditionTree {
735            operator: Operator::Or,
736            left: Box::new(left),
737            right: Box::new(right),
738        });
739
740        let res = ConditionExpression::condition_expr(cond);
741        assert_eq!(res.unwrap().1, complete);
742    }
743
744    #[test]
745    fn nested_select() {
746        use std::default::Default;
747
748        let cond = "bar in (select col from foo)";
749
750        let res = ConditionExpression::condition_expr(cond);
751
752        let nested_select = Box::new(SelectStatement {
753            tables: vec![Table::from("foo")],
754            fields: FieldDefinitionExpression::from_column_str(&["col"]),
755            ..Default::default()
756        });
757
758        let expected = flat_condition_tree(
759            Operator::In,
760            Field("bar".into()),
761            NestedSelect(nested_select),
762        );
763
764        assert_eq!(res.unwrap().1, expected);
765    }
766
767    #[test]
768    fn exists_in_select() {
769        use base::table::Table;
770        use std::default::Default;
771
772        let cond = "exists (  select col from foo  )";
773
774        let res = ConditionExpression::condition_expr(cond);
775
776        let nested_select = Box::new(SelectStatement {
777            tables: vec![Table::from("foo")],
778            fields: FieldDefinitionExpression::from_column_str(&["col"]),
779            ..Default::default()
780        });
781
782        let expected = ConditionExpression::ExistsOp(nested_select);
783
784        assert_eq!(res.unwrap().1, expected);
785    }
786
787    #[test]
788    fn not_exists_in_select() {
789        use base::table::Table;
790        use std::default::Default;
791
792        let cond = "not exists (select col from foo)";
793
794        let res = ConditionExpression::condition_expr(cond);
795
796        let nested_select = Box::new(SelectStatement {
797            tables: vec![Table::from("foo")],
798            fields: FieldDefinitionExpression::from_column_str(&["col"]),
799            ..Default::default()
800        });
801
802        let expected =
803            ConditionExpression::NegationOp(Box::new(ConditionExpression::ExistsOp(nested_select)));
804
805        assert_eq!(res.unwrap().1, expected);
806    }
807
808    #[test]
809    fn and_with_nested_select() {
810        use base::table::Table;
811        use std::default::Default;
812
813        let cond = "paperId in (select paperId from PaperConflict) and size > 0";
814
815        let res = ConditionExpression::condition_expr(cond);
816
817        let nested_select = Box::new(SelectStatement {
818            tables: vec![Table::from("PaperConflict")],
819            fields: FieldDefinitionExpression::from_column_str(&["paperId"]),
820            ..Default::default()
821        });
822
823        let left = flat_condition_tree(
824            Operator::In,
825            Field("paperId".into()),
826            NestedSelect(nested_select),
827        );
828
829        let right = flat_condition_tree(
830            Operator::Greater,
831            Field("size".into()),
832            ConditionBase::Literal(0.into()),
833        );
834
835        let expected = ConditionExpression::LogicalOp(ConditionTree {
836            left: Box::new(left),
837            right: Box::new(right),
838            operator: Operator::And,
839        });
840
841        assert_eq!(res.unwrap().1, expected);
842    }
843
844    #[test]
845    fn in_list_of_values() {
846        let cond = "bar in (0)";
847
848        let res = ConditionExpression::condition_expr(cond);
849
850        let expected = flat_condition_tree(
851            Operator::In,
852            Field("bar".into()),
853            LiteralList(vec![0.into()]),
854        );
855
856        assert_eq!(res.unwrap().1, expected);
857    }
858
859    #[test]
860    fn is_null() {
861        use base::Literal;
862
863        let cond = "bar IS NULL";
864
865        let res = ConditionExpression::condition_expr(cond);
866        let expected = flat_condition_tree(
867            Operator::Equal,
868            Field("bar".into()),
869            ConditionBase::Literal(Literal::Null),
870        );
871        assert_eq!(res.unwrap().1, expected);
872
873        let cond = "bar IS NOT NULL";
874
875        let res = ConditionExpression::condition_expr(cond);
876        let expected = flat_condition_tree(
877            Operator::NotEqual,
878            Field("bar".into()),
879            ConditionBase::Literal(Literal::Null),
880        );
881        assert_eq!(res.unwrap().1, expected);
882    }
883
884    #[test]
885    fn complex_bracketing() {
886        use base::Literal;
887
888        let cond = "`read_ribbons`.`is_following` = 1 \
889                    AND `comments`.`user_id` <> `read_ribbons`.`user_id` \
890                    AND `saldo` >= 0 \
891                    AND ( `parent_comments`.`user_id` = `read_ribbons`.`user_id` \
892                    OR ( `parent_comments`.`user_id` IS NULL \
893                    AND `stories`.`user_id` = `read_ribbons`.`user_id` ) ) \
894                    AND ( `parent_comments`.`id` IS NULL \
895                    OR `saldo` >= 0 ) \
896                    AND `read_ribbons`.`user_id` = ?";
897
898        let res = ConditionExpression::condition_expr(cond);
899        let expected = ConditionExpression::LogicalOp(ConditionTree {
900            operator: Operator::And,
901            left: Box::new(flat_condition_tree(
902                Operator::Equal,
903                Field("read_ribbons.is_following".into()),
904                ConditionBase::Literal(Literal::Integer(1.into())),
905            )),
906            right: Box::new(ConditionExpression::LogicalOp(ConditionTree {
907                operator: Operator::And,
908                left: Box::new(flat_condition_tree(
909                    Operator::NotEqual,
910                    Field("comments.user_id".into()),
911                    Field("read_ribbons.user_id".into()),
912                )),
913                right: Box::new(ConditionExpression::LogicalOp(ConditionTree {
914                    operator: Operator::And,
915                    left: Box::new(flat_condition_tree(
916                        Operator::GreaterOrEqual,
917                        Field("saldo".into()),
918                        ConditionBase::Literal(Literal::Integer(0.into())),
919                    )),
920                    right: Box::new(ConditionExpression::LogicalOp(ConditionTree {
921                        operator: Operator::And,
922                        left: Box::new(ConditionExpression::Bracketed(Box::new(
923                            ConditionExpression::LogicalOp(ConditionTree {
924                                operator: Operator::Or,
925                                left: Box::new(flat_condition_tree(
926                                    Operator::Equal,
927                                    Field("parent_comments.user_id".into()),
928                                    Field("read_ribbons.user_id".into()),
929                                )),
930                                right: Box::new(ConditionExpression::Bracketed(Box::new(
931                                    ConditionExpression::LogicalOp(ConditionTree {
932                                        operator: Operator::And,
933                                        left: Box::new(flat_condition_tree(
934                                            Operator::Equal,
935                                            Field("parent_comments.user_id".into()),
936                                            ConditionBase::Literal(Literal::Null),
937                                        )),
938                                        right: Box::new(flat_condition_tree(
939                                            Operator::Equal,
940                                            Field("stories.user_id".into()),
941                                            Field("read_ribbons.user_id".into()),
942                                        )),
943                                    }),
944                                ))),
945                            }),
946                        ))),
947                        right: Box::new(ConditionExpression::LogicalOp(ConditionTree {
948                            operator: Operator::And,
949                            left: Box::new(ConditionExpression::Bracketed(Box::new(
950                                ConditionExpression::LogicalOp(ConditionTree {
951                                    operator: Operator::Or,
952                                    left: Box::new(flat_condition_tree(
953                                        Operator::Equal,
954                                        Field("parent_comments.id".into()),
955                                        ConditionBase::Literal(Literal::Null),
956                                    )),
957                                    right: Box::new(flat_condition_tree(
958                                        Operator::GreaterOrEqual,
959                                        Field("saldo".into()),
960                                        ConditionBase::Literal(Literal::Integer(0)),
961                                    )),
962                                }),
963                            ))),
964                            right: Box::new(flat_condition_tree(
965                                Operator::Equal,
966                                Field("read_ribbons.user_id".into()),
967                                ConditionBase::Literal(Literal::Placeholder(
968                                    ItemPlaceholder::QuestionMark,
969                                )),
970                            )),
971                        })),
972                    })),
973                })),
974            })),
975        });
976        let res = res.unwrap().1;
977        assert_eq!(res, expected);
978    }
979
980    #[test]
981    fn not_in_comparison() {
982        let qs1 = "id not in (1,2)";
983        let res1 = ConditionExpression::condition_expr(qs1);
984
985        let c1 = res1.unwrap().1;
986        let expected1 = flat_condition_tree(
987            Operator::NotIn,
988            Field("id".into()),
989            LiteralList(vec![1.into(), 2.into()]),
990        );
991        assert_eq!(c1, expected1);
992
993        let expected1 = "id NOT IN (1, 2)";
994        assert_eq!(format!("{}", c1), expected1);
995    }
996}