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#[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 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 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}