Skip to content

Commit

Permalink
Change cond_where semantics (#417)
Browse files Browse the repository at this point in the history
* Change `cond_where` semantics

* Change log

* More tests

* Update examples
  • Loading branch information
tyt2y3 authored Aug 13, 2022
1 parent 42f1473 commit 4b280a3
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 18 deletions.
41 changes: 40 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,46 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Breaking changes

* Removed `join_alias`
* Change `in_tuples` interface to accept `IntoValueTuple` https://github.com/SeaQL/sea-query/pull/386
* Changed `in_tuples` interface to accept `IntoValueTuple` https://github.com/SeaQL/sea-query/pull/386
* **Changed `cond_where` semantics**
```rust
// Before: will extend current Condition
assert_eq!(
Query::select()
.cond_where(any![Expr::col(Glyph::Id).eq(1), Expr::col(Glyph::Id).eq(2)])
.cond_where(Expr::col(Glyph::Id).eq(3))
.to_owned()
.to_string(PostgresQueryBuilder),
r#"SELECT WHERE "id" = 1 OR "id" = 2 OR "id" = 3"#
);
// Before: confusing, since it depends on the order of invocation:
assert_eq!(
Query::select()
.cond_where(Expr::col(Glyph::Id).eq(3))
.cond_where(any![Expr::col(Glyph::Id).eq(1), Expr::col(Glyph::Id).eq(2)])
.to_owned()
.to_string(PostgresQueryBuilder),
r#"SELECT WHERE "id" = 3 AND ("id" = 1 OR "id" = 2)"#
);
// Now: will always conjoin with `AND`
assert_eq!(
Query::select()
.cond_where(Expr::col(Glyph::Id).eq(1))
.cond_where(any![Expr::col(Glyph::Id).eq(2), Expr::col(Glyph::Id).eq(3)])
.to_owned()
.to_string(PostgresQueryBuilder),
r#"SELECT WHERE "id" = 1 AND ("id" = 2 OR "id" = 3)"#
);
// Now: so they are now equivalent
assert_eq!(
Query::select()
.cond_where(any![Expr::col(Glyph::Id).eq(2), Expr::col(Glyph::Id).eq(3)])
.cond_where(Expr::col(Glyph::Id).eq(1))
.to_owned()
.to_string(PostgresQueryBuilder),
r#"SELECT WHERE ("id" = 2 OR "id" = 3) AND "id" = 1"#
);
```

### Bug Fixes

Expand Down
100 changes: 83 additions & 17 deletions src/query/condition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,7 @@ pub trait ConditionalStatement {
/// Expr::tbl(Glyph::Table, Glyph::Aspect).is_in(vec![3, 4]),
/// any![
/// Expr::tbl(Glyph::Table, Glyph::Image).like("A%"),
/// Expr::tbl(Glyph::Table, Glyph::Image).like("B%")
/// Expr::tbl(Glyph::Table, Glyph::Image).like("B%"),
/// ]
/// ])
/// .to_owned();
Expand All @@ -463,39 +463,94 @@ pub trait ConditionalStatement {
/// r#"SELECT "image" FROM "glyph" WHERE "glyph"."aspect" IN (3, 4) AND ("glyph"."image" LIKE 'A%' OR "glyph"."image" LIKE 'B%')"#
/// );
/// ```
/// Calling multiple times
///
/// Calling multiple times; the following two are equivalent:
///
/// ```
/// use sea_query::{tests_cfg::*, *};
///
/// assert_eq!(
/// Query::select()
/// .cond_where(Cond::all().add(Expr::col(Glyph::Id).eq(1)))
/// .cond_where(
/// Cond::any()
/// .add(Expr::col(Glyph::Id).eq(2))
/// .add(Expr::col(Glyph::Id).eq(3)),
/// )
/// .cond_where(Expr::col(Glyph::Id).eq(1))
/// .cond_where(any![Expr::col(Glyph::Id).eq(2), Expr::col(Glyph::Id).eq(3)])
/// .to_owned()
/// .to_string(PostgresQueryBuilder),
/// r#"SELECT WHERE "id" = 1 AND ("id" = 2 OR "id" = 3)"#
/// );
///
/// assert_eq!(
/// Query::select()
/// .cond_where(any![Expr::col(Glyph::Id).eq(2), Expr::col(Glyph::Id).eq(3)])
/// .cond_where(Expr::col(Glyph::Id).eq(1))
/// .to_owned()
/// .to_string(PostgresQueryBuilder),
/// r#"SELECT WHERE ("id" = 2 OR "id" = 3) AND "id" = 1"#
/// );
/// ```
/// Calling multiple times
///
/// Calling multiple times; will be ANDed togother
///
/// ```
/// use sea_query::{tests_cfg::*, *};
///
/// assert_eq!(
/// Query::select()
/// .cond_where(any![Expr::col(Glyph::Id).eq(1), Expr::col(Glyph::Id).eq(2)])
/// .cond_where(any![Expr::col(Glyph::Id).eq(3), Expr::col(Glyph::Id).eq(4)])
/// .to_owned()
/// .to_string(PostgresQueryBuilder),
/// r#"SELECT WHERE ("id" = 1 OR "id" = 2) AND ("id" = 3 OR "id" = 4)"#
/// );
///
/// assert_eq!(
/// Query::select()
/// .cond_where(all![Expr::col(Glyph::Id).eq(1), Expr::col(Glyph::Id).eq(2)])
/// .cond_where(all![Expr::col(Glyph::Id).eq(3), Expr::col(Glyph::Id).eq(4)])
/// .to_owned()
/// .to_string(PostgresQueryBuilder),
/// r#"SELECT WHERE "id" = 1 AND "id" = 2 AND "id" = 3 AND "id" = 4"#
/// );
/// ```
///
/// Some more test cases involving negation
///
/// ```
/// use sea_query::{tests_cfg::*, *};
///
/// assert_eq!(
/// Query::select()
/// .cond_where(
/// Cond::all()
/// .not()
/// .add(Expr::col(Glyph::Id).eq(1))
/// .add(Expr::col(Glyph::Id).eq(2)),
/// )
/// .cond_where(
/// Cond::all()
/// .add(Expr::col(Glyph::Id).eq(3))
/// .add(Expr::col(Glyph::Id).eq(4)),
/// )
/// .to_owned()
/// .to_string(PostgresQueryBuilder),
/// r#"SELECT WHERE (NOT ("id" = 1 AND "id" = 2)) AND ("id" = 3 AND "id" = 4)"#
/// );
///
/// assert_eq!(
/// Query::select()
/// .cond_where(
/// Cond::all()
/// .add(Expr::col(Glyph::Id).eq(3))
/// .add(Expr::col(Glyph::Id).eq(4)),
/// )
/// .cond_where(
/// Cond::any()
/// Cond::all()
/// .not()
/// .add(Expr::col(Glyph::Id).eq(1))
/// .add(Expr::col(Glyph::Id).eq(2)),
/// )
/// .cond_where(Expr::col(Glyph::Id).eq(3))
/// .cond_where(Expr::col(Glyph::Id).eq(4))
/// .to_owned()
/// .to_string(PostgresQueryBuilder),
/// r#"SELECT WHERE "id" = 1 OR "id" = 2 OR "id" = 3 OR "id" = 4"#
/// r#"SELECT WHERE "id" = 3 AND "id" = 4 AND (NOT ("id" = 1 AND "id" = 2))"#
/// );
/// ```
fn cond_where<C>(&mut self, condition: C) -> &mut Self
Expand Down Expand Up @@ -568,13 +623,24 @@ impl ConditionHolder {
}
}

pub fn add_condition(&mut self, condition: Condition) {
pub fn add_condition(&mut self, mut addition: Condition) {
match std::mem::take(&mut self.contents) {
ConditionHolderContents::Empty => {
self.contents = ConditionHolderContents::Condition(condition);
self.contents = ConditionHolderContents::Condition(addition);
}
ConditionHolderContents::Condition(current) => {
self.contents = ConditionHolderContents::Condition(current.add(condition));
ConditionHolderContents::Condition(mut current) => {
if current.condition_type == ConditionType::All && !current.negate {
if addition.condition_type == ConditionType::All && !addition.negate {
current.conditions.append(&mut addition.conditions);
self.contents = ConditionHolderContents::Condition(current);
} else {
self.contents = ConditionHolderContents::Condition(current.add(addition));
}
} else {
self.contents = ConditionHolderContents::Condition(
Condition::all().add(current).add(addition),
);
}
}
ConditionHolderContents::Chain(_) => {
panic!("Cannot mix `and_where`/`or_where` and `cond_where` in statements")
Expand Down

0 comments on commit 4b280a3

Please sign in to comment.