sea_query/query/condition.rs
1use crate::{ExprTrait, expr::Expr, types::LogicalChainOper};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum ConditionType {
5 Any,
6 All,
7}
8
9/// Represents the value of an [`Condition::any`] or [`Condition::all`]: a set of disjunctive or conjunctive conditions.
10#[derive(Debug, Clone, PartialEq)]
11pub struct Condition {
12 pub(crate) negate: bool,
13 pub(crate) condition_type: ConditionType,
14 pub(crate) conditions: Vec<ConditionExpression>,
15}
16
17pub type Cond = Condition;
18
19impl From<Expr> for Condition {
20 fn from(expr: Expr) -> Self {
21 Condition {
22 negate: false,
23 condition_type: ConditionType::All,
24 conditions: vec![ConditionExpression::Expr(expr)],
25 }
26 }
27}
28
29impl From<ConditionExpression> for Condition {
30 fn from(ce: ConditionExpression) -> Self {
31 Condition {
32 negate: false,
33 condition_type: ConditionType::All,
34 conditions: vec![ce],
35 }
36 }
37}
38
39/// A helper trait.
40///
41/// You shouldn't implement this manually.
42pub trait IntoCondition: Into<Condition> {
43 #[inline(always)]
44 fn into_condition(self) -> Condition {
45 self.into()
46 }
47}
48
49impl<T> IntoCondition for T where T: Into<Condition> {}
50
51/// An internal representation of conditions, either an expression or a nested condition.
52///
53/// It used to be in the public interface of [`Condition::add`] and [`Condition::add_option`],
54/// in order to accept anything resembling a condition or an expression.
55/// Nowadays, we achieve that with traits.
56#[derive(Debug, Clone, PartialEq)]
57pub(crate) enum ConditionExpression {
58 Condition(Condition),
59 Expr(Expr),
60}
61
62#[derive(Default, Debug, Clone, PartialEq)]
63pub enum ConditionHolderContents {
64 #[default]
65 Empty,
66 Chain(Vec<LogicalChainOper>),
67 Condition(Condition),
68}
69
70#[derive(Default, Debug, Clone, PartialEq)]
71pub struct ConditionHolder {
72 pub contents: ConditionHolderContents,
73}
74
75impl Condition {
76 /// Add a condition to the set.
77 ///
78 /// If it's an [`Condition::any`], it will be separated from the others by an `" OR "` in the query. If it's
79 /// an [`Condition::all`], it will be separated by an `" AND "`.
80 ///
81 /// ```
82 /// use sea_query::{tests_cfg::*, *};
83 ///
84 /// let statement = Query::select()
85 /// .column(Glyph::Id)
86 /// .from(Glyph::Table)
87 /// .cond_where(
88 /// Cond::all()
89 /// .add(Expr::col(Glyph::Aspect).eq(0).into_condition().not())
90 /// .add(Expr::col(Glyph::Id).eq(0).into_condition().not()),
91 /// )
92 /// .to_string(PostgresQueryBuilder);
93 /// assert_eq!(
94 /// statement,
95 /// r#"SELECT "id" FROM "glyph" WHERE (NOT "aspect" = 0) AND (NOT "id" = 0)"#
96 /// );
97 /// ```
98 #[allow(clippy::should_implement_trait)]
99 pub fn add<C>(mut self, condition: C) -> Self
100 where
101 C: Into<Condition>,
102 {
103 let condition: Condition = condition.into();
104 let condition: ConditionExpression = condition.into();
105 self.conditions.push(condition);
106 self
107 }
108
109 /// Add an optional condition to the set.
110 ///
111 /// Shorthand for `if o.is_some() { self.add(o) }`
112 ///
113 /// # Examples
114 ///
115 /// ```
116 /// use sea_query::{tests_cfg::*, *};
117 ///
118 /// let query = Query::select()
119 /// .column(Glyph::Image)
120 /// .from(Glyph::Table)
121 /// .cond_where(
122 /// Cond::all()
123 /// .add_option(Some(Expr::col((Glyph::Table, Glyph::Image)).like("A%")))
124 /// .add_option(None::<Expr>),
125 /// )
126 /// .to_owned();
127 ///
128 /// assert_eq!(
129 /// query.to_string(MysqlQueryBuilder),
130 /// r#"SELECT `image` FROM `glyph` WHERE `glyph`.`image` LIKE 'A%'"#
131 /// );
132 /// ```
133 #[allow(clippy::should_implement_trait)]
134 pub fn add_option<C>(self, other: Option<C>) -> Self
135 where
136 C: Into<Condition>,
137 {
138 if let Some(other) = other {
139 self.add(other)
140 } else {
141 self
142 }
143 }
144
145 /// Create a condition that is true if any of the conditions is true.
146 ///
147 /// # Examples
148 ///
149 /// ```
150 /// use sea_query::{*, tests_cfg::*};
151 ///
152 /// let query = Query::select()
153 /// .column(Glyph::Image)
154 /// .from(Glyph::Table)
155 /// .cond_where(
156 /// Cond::any()
157 /// .add(Expr::col((Glyph::Table, Glyph::Aspect)).is_in([3, 4]))
158 /// .add(Expr::col((Glyph::Table, Glyph::Image)).like("A%"))
159 /// )
160 /// .to_owned();
161 ///
162 /// assert_eq!(
163 /// query.to_string(MysqlQueryBuilder),
164 /// r#"SELECT `image` FROM `glyph` WHERE `glyph`.`aspect` IN (3, 4) OR `glyph`.`image` LIKE 'A%'"#
165 /// );
166 /// ```
167 pub fn any() -> Condition {
168 Condition {
169 negate: false,
170 condition_type: ConditionType::Any,
171 conditions: Vec::new(),
172 }
173 }
174
175 /// Create a condition that is false if any of the conditions is false.
176 ///
177 /// # Examples
178 ///
179 /// ```
180 /// use sea_query::{*, tests_cfg::*};
181 ///
182 /// let query = Query::select()
183 /// .column(Glyph::Image)
184 /// .from(Glyph::Table)
185 /// .cond_where(
186 /// Cond::all()
187 /// .add(Expr::col((Glyph::Table, Glyph::Aspect)).is_in([3, 4]))
188 /// .add(Expr::col((Glyph::Table, Glyph::Image)).like("A%"))
189 /// )
190 /// .to_owned();
191 ///
192 /// assert_eq!(
193 /// query.to_string(MysqlQueryBuilder),
194 /// r#"SELECT `image` FROM `glyph` WHERE `glyph`.`aspect` IN (3, 4) AND `glyph`.`image` LIKE 'A%'"#
195 /// );
196 /// ```
197 pub fn all() -> Condition {
198 Condition {
199 negate: false,
200 condition_type: ConditionType::All,
201 conditions: Vec::new(),
202 }
203 }
204
205 /// Negates a condition.
206 ///
207 /// # Examples
208 ///
209 /// ```
210 /// use sea_query::{tests_cfg::*, *};
211 ///
212 /// let query = Query::select()
213 /// .column(Glyph::Image)
214 /// .from(Glyph::Table)
215 /// .cond_where(
216 /// Cond::all()
217 /// .not()
218 /// .add(Expr::col((Glyph::Table, Glyph::Aspect)).is_in([3, 4]))
219 /// .add(Expr::col((Glyph::Table, Glyph::Image)).like("A%"))
220 /// )
221 /// .to_owned();
222 ///
223 /// assert_eq!(
224 /// query.to_string(MysqlQueryBuilder),
225 /// r#"SELECT `image` FROM `glyph` WHERE NOT (`glyph`.`aspect` IN (3, 4) AND `glyph`.`image` LIKE 'A%')"#
226 /// );
227 /// ```
228 ///
229 /// # More Examples
230 ///
231 /// ```
232 /// use sea_query::{tests_cfg::*, *};
233 ///
234 /// let query = Query::select()
235 /// .column(Glyph::Id)
236 /// .cond_where(
237 /// Cond::all()
238 /// .add(
239 /// Cond::all()
240 /// .not()
241 /// .add(Expr::val(1).eq(1))
242 /// .add(Expr::val(2).eq(2)),
243 /// )
244 /// .add(Cond::any().add(Expr::val(3).eq(3)).add(Expr::val(4).eq(4))),
245 /// )
246 /// .to_owned();
247 ///
248 /// assert_eq!(
249 /// query.to_string(MysqlQueryBuilder),
250 /// r#"SELECT `id` WHERE (NOT (1 = 1 AND 2 = 2)) AND (3 = 3 OR 4 = 4)"#
251 /// );
252 /// ```
253 #[allow(clippy::should_implement_trait)]
254 pub fn not(mut self) -> Self {
255 self.negate = !self.negate;
256 self
257 }
258
259 /// Whether or not any condition has been added
260 ///
261 /// # Examples
262 ///
263 /// ```
264 /// use sea_query::{tests_cfg::*, *};
265 ///
266 /// let is_empty = Cond::all().is_empty();
267 ///
268 /// assert!(is_empty);
269 /// ```
270 pub fn is_empty(&self) -> bool {
271 self.conditions.is_empty()
272 }
273
274 /// How many conditions were added
275 ///
276 /// # Examples
277 ///
278 /// ```
279 /// use sea_query::{tests_cfg::*, *};
280 ///
281 /// let len = Cond::all().len();
282 ///
283 /// assert_eq!(len, 0);
284 /// ```
285 pub fn len(&self) -> usize {
286 self.conditions.len()
287 }
288}
289
290impl From<Condition> for Expr {
291 fn from(cond: Condition) -> Self {
292 let mut inner_exprs = vec![];
293 for ce in cond.conditions {
294 inner_exprs.push(match ce {
295 ConditionExpression::Condition(c) => c.into(),
296 ConditionExpression::Expr(e) => e,
297 });
298 }
299 let mut inner_exprs_into_iter = inner_exprs.into_iter();
300 let expr = if let Some(first_expr) = inner_exprs_into_iter.next() {
301 let mut out_expr = first_expr;
302 for e in inner_exprs_into_iter {
303 out_expr = match cond.condition_type {
304 ConditionType::Any => out_expr.or(e),
305 ConditionType::All => out_expr.and(e),
306 };
307 }
308 out_expr
309 } else {
310 Expr::Constant(match cond.condition_type {
311 ConditionType::Any => false.into(),
312 ConditionType::All => true.into(),
313 })
314 };
315 if cond.negate { expr.not() } else { expr }
316 }
317}
318
319impl From<ConditionExpression> for Expr {
320 fn from(ce: ConditionExpression) -> Self {
321 match ce {
322 ConditionExpression::Condition(c) => c.into(),
323 ConditionExpression::Expr(e) => e,
324 }
325 }
326}
327
328impl From<Condition> for ConditionExpression {
329 fn from(condition: Condition) -> Self {
330 ConditionExpression::Condition(condition)
331 }
332}
333
334impl From<Expr> for ConditionExpression {
335 fn from(condition: Expr) -> Self {
336 ConditionExpression::Expr(condition)
337 }
338}
339
340/// Macro to easily create an [`Condition::any`].
341///
342/// # Examples
343///
344/// ```
345/// use sea_query::{*, tests_cfg::*};
346///
347/// let query = Query::select()
348/// .column(Glyph::Image)
349/// .from(Glyph::Table)
350/// .cond_where(
351/// any![
352/// Expr::col((Glyph::Table, Glyph::Aspect)).is_in([3, 4]),
353/// Expr::col((Glyph::Table, Glyph::Image)).like("A%")
354/// ]
355/// )
356/// .to_owned();
357///
358/// assert_eq!(
359/// query.to_string(MysqlQueryBuilder),
360/// r#"SELECT `image` FROM `glyph` WHERE `glyph`.`aspect` IN (3, 4) OR `glyph`.`image` LIKE 'A%'"#
361/// );
362/// ```
363#[macro_export]
364macro_rules! any {
365 ( $( $x:expr ),* $(,)?) => {
366 {
367 let mut tmp = $crate::Condition::any();
368 $(
369 tmp = tmp.add($x);
370 )*
371 tmp
372 }
373 };
374}
375
376/// Macro to easily create an [`Condition::all`].
377///
378/// # Examples
379///
380/// ```
381/// use sea_query::{*, tests_cfg::*};
382///
383/// let query = Query::select()
384/// .column(Glyph::Image)
385/// .from(Glyph::Table)
386/// .cond_where(
387/// all![
388/// Expr::col((Glyph::Table, Glyph::Aspect)).is_in([3, 4]),
389/// Expr::col((Glyph::Table, Glyph::Image)).like("A%")
390/// ]
391/// )
392/// .to_owned();
393///
394/// assert_eq!(
395/// query.to_string(MysqlQueryBuilder),
396/// r#"SELECT `image` FROM `glyph` WHERE `glyph`.`aspect` IN (3, 4) AND `glyph`.`image` LIKE 'A%'"#
397/// );
398#[macro_export]
399macro_rules! all {
400 ( $( $x:expr ),* $(,)?) => {
401 {
402 let mut tmp = $crate::Condition::all();
403 $(
404 tmp = tmp.add($x);
405 )*
406 tmp
407 }
408 };
409}
410
411pub trait ConditionalStatement {
412 /// And where condition.
413 /// Calling `or_where` after `and_where` will panic.
414 ///
415 /// # Examples
416 ///
417 /// ```
418 /// use sea_query::{*, tests_cfg::*};
419 ///
420 /// let query = Query::select()
421 /// .column(Glyph::Image)
422 /// .from(Glyph::Table)
423 /// .and_where(Expr::col((Glyph::Table, Glyph::Aspect)).is_in([3, 4]))
424 /// .and_where(Expr::col((Glyph::Table, Glyph::Image)).like("A%"))
425 /// .to_owned();
426 ///
427 /// assert_eq!(
428 /// query.to_string(MysqlQueryBuilder),
429 /// r#"SELECT `image` FROM `glyph` WHERE `glyph`.`aspect` IN (3, 4) AND `glyph`.`image` LIKE 'A%'"#
430 /// );
431 /// ```
432 fn and_where(&mut self, other: Expr) -> &mut Self {
433 self.cond_where(other)
434 }
435
436 /// Optional and where, short hand for `if c.is_some() q.and_where(c)`.
437 ///
438 /// ```
439 /// use sea_query::{tests_cfg::*, *};
440 ///
441 /// let query = Query::select()
442 /// .column(Glyph::Image)
443 /// .from(Glyph::Table)
444 /// .and_where(Expr::col(Glyph::Aspect).is_in([3, 4]))
445 /// .and_where_option(Some(Expr::col(Glyph::Image).like("A%")))
446 /// .and_where_option(None)
447 /// .to_owned();
448 ///
449 /// assert_eq!(
450 /// query.to_string(MysqlQueryBuilder),
451 /// r#"SELECT `image` FROM `glyph` WHERE `aspect` IN (3, 4) AND `image` LIKE 'A%'"#
452 /// );
453 /// ```
454 fn and_where_option(&mut self, other: Option<Expr>) -> &mut Self {
455 if let Some(other) = other {
456 self.and_where(other);
457 }
458 self
459 }
460
461 #[doc(hidden)]
462 // Trait implementation.
463 fn and_or_where(&mut self, condition: LogicalChainOper) -> &mut Self;
464
465 /// Where condition, expressed with `any` and `all`.
466 /// Calling `cond_where` multiple times will conjoin them.
467 /// Calling `or_where` after `cond_where` will panic.
468 ///
469 /// # Examples
470 ///
471 /// ```
472 /// use sea_query::{*, tests_cfg::*};
473 ///
474 /// let query = Query::select()
475 /// .column(Glyph::Image)
476 /// .from(Glyph::Table)
477 /// .cond_where(
478 /// Cond::all()
479 /// .add(Expr::col((Glyph::Table, Glyph::Aspect)).is_in([3, 4]))
480 /// .add(Cond::any()
481 /// .add(Expr::col((Glyph::Table, Glyph::Image)).like("A%"))
482 /// .add(Expr::col((Glyph::Table, Glyph::Image)).like("B%"))
483 /// )
484 /// )
485 /// .to_owned();
486 ///
487 /// assert_eq!(
488 /// query.to_string(PostgresQueryBuilder),
489 /// r#"SELECT "image" FROM "glyph" WHERE "glyph"."aspect" IN (3, 4) AND ("glyph"."image" LIKE 'A%' OR "glyph"."image" LIKE 'B%')"#
490 /// );
491 /// ```
492 ///
493 /// When used with [`crate::IndexCreateStatement`], this condition is a partial
494 /// index filter. MySQL does not support partial indexes; SeaQuery still
495 /// emits the `WHERE` clause so a MySQL database rejects the statement
496 /// instead of silently creating an index with different semantics. See
497 /// [#1066](https://github.com/SeaQL/sea-query/issues/1066).
498 ///
499 /// ```
500 /// use sea_query::{*, tests_cfg::*};
501 ///
502 /// assert_eq!(
503 /// Index::create()
504 /// .unique()
505 /// .name("idx-glyph-image-primary")
506 /// .table(Glyph::Table)
507 /// .col(Glyph::Image)
508 /// .cond_where(Expr::col(Glyph::Aspect).is_not_null())
509 /// .to_string(MysqlQueryBuilder),
510 /// r#"CREATE UNIQUE INDEX `idx-glyph-image-primary` ON `glyph` (`image`) WHERE `aspect` IS NOT NULL"#
511 /// );
512 /// ```
513 ///
514 /// Using macro
515 ///
516 /// ```
517 /// use sea_query::{*, tests_cfg::*};
518 ///
519 /// let query = Query::select()
520 /// .column(Glyph::Image)
521 /// .from(Glyph::Table)
522 /// .cond_where(
523 /// all![
524 /// Expr::col((Glyph::Table, Glyph::Aspect)).is_in([3, 4]),
525 /// any![
526 /// Expr::col((Glyph::Table, Glyph::Image)).like("A%"),
527 /// Expr::col((Glyph::Table, Glyph::Image)).like("B%"),
528 /// ]
529 /// ])
530 /// .to_owned();
531 ///
532 /// assert_eq!(
533 /// query.to_string(PostgresQueryBuilder),
534 /// r#"SELECT "image" FROM "glyph" WHERE "glyph"."aspect" IN (3, 4) AND ("glyph"."image" LIKE 'A%' OR "glyph"."image" LIKE 'B%')"#
535 /// );
536 /// ```
537 ///
538 /// Calling multiple times; the following two are equivalent:
539 ///
540 /// ```
541 /// use sea_query::{tests_cfg::*, *};
542 ///
543 /// assert_eq!(
544 /// Query::select()
545 /// .column(Glyph::Id)
546 /// .from(Glyph::Table)
547 /// .cond_where(Expr::col(Glyph::Id).eq(1))
548 /// .cond_where(any![Expr::col(Glyph::Id).eq(2), Expr::col(Glyph::Id).eq(3)])
549 /// .to_owned()
550 /// .to_string(PostgresQueryBuilder),
551 /// r#"SELECT "id" FROM "glyph" WHERE "id" = 1 AND ("id" = 2 OR "id" = 3)"#
552 /// );
553 ///
554 /// assert_eq!(
555 /// Query::select()
556 /// .column(Glyph::Id)
557 /// .from(Glyph::Table)
558 /// .cond_where(any![Expr::col(Glyph::Id).eq(2), Expr::col(Glyph::Id).eq(3)])
559 /// .cond_where(Expr::col(Glyph::Id).eq(1))
560 /// .to_owned()
561 /// .to_string(PostgresQueryBuilder),
562 /// r#"SELECT "id" FROM "glyph" WHERE ("id" = 2 OR "id" = 3) AND "id" = 1"#
563 /// );
564 /// ```
565 ///
566 /// Calling multiple times; will be ANDed togother
567 ///
568 /// ```
569 /// use sea_query::{tests_cfg::*, *};
570 ///
571 /// assert_eq!(
572 /// Query::select()
573 /// .column(Glyph::Id)
574 /// .from(Glyph::Table)
575 /// .cond_where(any![Expr::col(Glyph::Id).eq(1), Expr::col(Glyph::Id).eq(2)])
576 /// .cond_where(any![Expr::col(Glyph::Id).eq(3), Expr::col(Glyph::Id).eq(4)])
577 /// .to_owned()
578 /// .to_string(PostgresQueryBuilder),
579 /// r#"SELECT "id" FROM "glyph" WHERE ("id" = 1 OR "id" = 2) AND ("id" = 3 OR "id" = 4)"#
580 /// );
581 ///
582 /// assert_eq!(
583 /// Query::select()
584 /// .column(Glyph::Id)
585 /// .from(Glyph::Table)
586 /// .cond_where(all![Expr::col(Glyph::Id).eq(1), Expr::col(Glyph::Id).eq(2)])
587 /// .cond_where(all![Expr::col(Glyph::Id).eq(3), Expr::col(Glyph::Id).eq(4)])
588 /// .to_owned()
589 /// .to_string(PostgresQueryBuilder),
590 /// r#"SELECT "id" FROM "glyph" WHERE "id" = 1 AND "id" = 2 AND "id" = 3 AND "id" = 4"#
591 /// );
592 /// ```
593 ///
594 /// Some more test cases involving negation
595 ///
596 /// ```
597 /// use sea_query::{tests_cfg::*, *};
598 ///
599 /// assert_eq!(
600 /// Query::select()
601 /// .column(Glyph::Id)
602 /// .from(Glyph::Table)
603 /// .cond_where(
604 /// Cond::all()
605 /// .not()
606 /// .add(Expr::col(Glyph::Id).eq(1))
607 /// .add(Expr::col(Glyph::Id).eq(2)),
608 /// )
609 /// .cond_where(
610 /// Cond::all()
611 /// .add(Expr::col(Glyph::Id).eq(3))
612 /// .add(Expr::col(Glyph::Id).eq(4)),
613 /// )
614 /// .to_owned()
615 /// .to_string(PostgresQueryBuilder),
616 /// r#"SELECT "id" FROM "glyph" WHERE (NOT ("id" = 1 AND "id" = 2)) AND ("id" = 3 AND "id" = 4)"#
617 /// );
618 ///
619 /// assert_eq!(
620 /// Query::select()
621 /// .column(Glyph::Id)
622 /// .from(Glyph::Table)
623 /// .cond_where(
624 /// Cond::all()
625 /// .add(Expr::col(Glyph::Id).eq(3))
626 /// .add(Expr::col(Glyph::Id).eq(4)),
627 /// )
628 /// .cond_where(
629 /// Cond::all()
630 /// .not()
631 /// .add(Expr::col(Glyph::Id).eq(1))
632 /// .add(Expr::col(Glyph::Id).eq(2)),
633 /// )
634 /// .to_owned()
635 /// .to_string(PostgresQueryBuilder),
636 /// r#"SELECT "id" FROM "glyph" WHERE "id" = 3 AND "id" = 4 AND (NOT ("id" = 1 AND "id" = 2))"#
637 /// );
638 /// ```
639 fn cond_where<C>(&mut self, condition: C) -> &mut Self
640 where
641 C: IntoCondition;
642}
643
644impl ConditionHolder {
645 pub fn new() -> Self {
646 Self::default()
647 }
648
649 pub fn new_with_condition(condition: Condition) -> Self {
650 let contents = ConditionHolderContents::Condition(condition);
651 Self { contents }
652 }
653
654 pub fn is_empty(&self) -> bool {
655 match &self.contents {
656 ConditionHolderContents::Empty => true,
657 ConditionHolderContents::Chain(c) => c.is_empty(),
658 ConditionHolderContents::Condition(c) => c.conditions.is_empty(),
659 }
660 }
661
662 pub fn is_one(&self) -> bool {
663 match &self.contents {
664 ConditionHolderContents::Empty => true,
665 ConditionHolderContents::Chain(c) => c.len() == 1,
666 ConditionHolderContents::Condition(c) => c.conditions.len() == 1,
667 }
668 }
669
670 pub fn add_and_or(&mut self, condition: LogicalChainOper) {
671 match &mut self.contents {
672 ConditionHolderContents::Empty => {
673 self.contents = ConditionHolderContents::Chain(vec![condition])
674 }
675 ConditionHolderContents::Chain(c) => c.push(condition),
676 ConditionHolderContents::Condition(_) => {
677 panic!("Cannot mix `and_where`/`or_where` and `cond_where` in statements")
678 }
679 }
680 }
681
682 pub fn add_condition(&mut self, mut addition: Condition) {
683 match std::mem::take(&mut self.contents) {
684 ConditionHolderContents::Empty => {
685 self.contents = ConditionHolderContents::Condition(addition);
686 }
687 ConditionHolderContents::Condition(mut current) => {
688 if current.condition_type == ConditionType::All && !current.negate {
689 if addition.condition_type == ConditionType::All && !addition.negate {
690 current.conditions.append(&mut addition.conditions);
691 self.contents = ConditionHolderContents::Condition(current);
692 } else {
693 self.contents = ConditionHolderContents::Condition(current.add(addition));
694 }
695 } else {
696 self.contents = ConditionHolderContents::Condition(
697 Condition::all().add(current).add(addition),
698 );
699 }
700 }
701 ConditionHolderContents::Chain(_) => {
702 panic!("Cannot mix `and_where`/`or_where` and `cond_where` in statements")
703 }
704 }
705 }
706}
707
708#[cfg(test)]
709mod test {
710 use crate::{tests_cfg::*, *};
711 use pretty_assertions::assert_eq;
712
713 #[test]
714 #[cfg(feature = "backend-mysql")]
715 fn test_blank_condition() {
716 let query = Query::select()
717 .column(Glyph::Image)
718 .from(Glyph::Table)
719 .cond_where(Cond::all())
720 .cond_where(Expr::val(1).eq(1))
721 .cond_where(Expr::val(2).eq(2))
722 .cond_where(Cond::any().add(Expr::val(3).eq(3)).add(Expr::val(4).eq(4)))
723 .to_owned();
724
725 assert_eq!(
726 query.to_string(MysqlQueryBuilder),
727 "SELECT `image` FROM `glyph` WHERE 1 = 1 AND 2 = 2 AND (3 = 3 OR 4 = 4)"
728 );
729 }
730}