mirror of
https://github.com/diesel-rs/diesel.git
synced 2024-10-04 01:28:13 +03:00
Add a general purpose NOT
function
I was rather surprised that we didn't already have this. I didn't stick this in `expression/predicates.rs`, as we didn't already have a macro for prefix operators, and I want to refactor that to add it later. I may move this to that macro in the future, and just have the return type be `Not<Grouped<T::Expression>>` to reduce the amount of required code here. We need parenthesis in the resulting SQL to ensure that it always applies to its arguments. `not(true.and(false))` should return `true`. However, `NOT true AND false` is equivalent to `(NOT true) AND false`. Fixes #944.
This commit is contained in:
parent
f5fdd8cb0f
commit
2701c1c675
@ -4,6 +4,15 @@ All user visible changes to this project will be documented in this file.
|
||||
This project adheres to [Semantic Versioning](http://semver.org/), as described
|
||||
for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/text/1105-api-evolution.md)
|
||||
|
||||
## Unreleased
|
||||
|
||||
### Added
|
||||
|
||||
* Added a function which maps to SQL `NOT`. See [the docs][not-0.14.0] for more
|
||||
details.
|
||||
|
||||
[not-0.14.0]: http://docs.diesel.rs/diesel/expression/dsl/fn.not.html
|
||||
|
||||
## [0.13.0] - 2017-05-15
|
||||
|
||||
### Added
|
||||
|
@ -35,6 +35,8 @@ pub type Between<Lhs, Rhs> = super::predicates::Between<Lhs,
|
||||
super::predicates::And<AsExpr<Rhs, Lhs>, AsExpr<Rhs, Lhs>>>;
|
||||
pub type NotBetween<Lhs, Rhs> = super::predicates::NotBetween<Lhs,
|
||||
super::predicates::And<AsExpr<Rhs, Lhs>, AsExpr<Rhs, Lhs>>>;
|
||||
/// The return type of `not(expr)`
|
||||
pub type Not<Expr> = super::not::Not<AsExprOf<Expr, types::Bool>>;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use super::predicates::{IsNull, IsNotNull, Asc, Desc};
|
||||
|
@ -34,6 +34,7 @@ pub mod functions;
|
||||
pub mod grouped;
|
||||
#[macro_use]
|
||||
pub mod helper_types;
|
||||
mod not;
|
||||
#[doc(hidden)]
|
||||
pub mod nullable;
|
||||
#[doc(hidden)]
|
||||
@ -47,11 +48,12 @@ mod unchecked_bind;
|
||||
/// in functions where you need them.
|
||||
pub mod dsl {
|
||||
#[doc(inline)] pub use super::count::{count, count_star};
|
||||
#[doc(inline)] pub use super::functions::date_and_time::*;
|
||||
#[doc(inline)] pub use super::functions::aggregate_ordering::*;
|
||||
#[doc(inline)] pub use super::functions::aggregate_folding::*;
|
||||
#[doc(inline)] pub use super::sql_literal::sql;
|
||||
#[doc(inline)] pub use super::exists::exists;
|
||||
#[doc(inline)] pub use super::functions::aggregate_folding::*;
|
||||
#[doc(inline)] pub use super::functions::aggregate_ordering::*;
|
||||
#[doc(inline)] pub use super::functions::date_and_time::*;
|
||||
#[doc(inline)] pub use super::not::not;
|
||||
#[doc(inline)] pub use super::sql_literal::sql;
|
||||
|
||||
#[cfg(feature = "postgres")]
|
||||
pub use pg::expression::dsl::*;
|
||||
|
72
diesel/src/expression/not.rs
Normal file
72
diesel/src/expression/not.rs
Normal file
@ -0,0 +1,72 @@
|
||||
use expression::*;
|
||||
use query_builder::*;
|
||||
use result::QueryResult;
|
||||
use types::Bool;
|
||||
|
||||
/// Creates a SQL `NOT` expression
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate diesel;
|
||||
/// # include!("src/doctest_setup.rs");
|
||||
/// #
|
||||
/// # table! {
|
||||
/// # users {
|
||||
/// # id -> Integer,
|
||||
/// # name -> VarChar,
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// # fn main() {
|
||||
/// # use self::users::dsl::*;
|
||||
/// # let connection = establish_connection();
|
||||
/// use diesel::expression::not;
|
||||
///
|
||||
/// let users_with_name = users.select(id).filter(name.eq("Sean"));
|
||||
/// let users_not_with_name = users.select(id).filter(
|
||||
/// not(name.eq("Sean")));
|
||||
///
|
||||
/// assert_eq!(Ok(1), users_with_name.first(&connection));
|
||||
/// assert_eq!(Ok(2), users_not_with_name.first(&connection));
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn not<T: AsExpression<Bool>>(expr: T) -> Not<T::Expression> {
|
||||
Not(expr.as_expression())
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Not<T>(T);
|
||||
|
||||
impl<T: Expression<SqlType=Bool>> Expression for Not<T> {
|
||||
type SqlType = Bool;
|
||||
}
|
||||
|
||||
impl<T, QS> AppearsOnTable<QS> for Not<T> where
|
||||
T: AppearsOnTable<QS>,
|
||||
Not<T>: Expression,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T, QS> SelectableExpression<QS> for Not<T> where
|
||||
T: SelectableExpression<QS>,
|
||||
Not<T>: AppearsOnTable<QS>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<T: NonAggregate> NonAggregate for Not<T> {}
|
||||
|
||||
impl<T, DB> QueryFragment<DB> for Not<T> where
|
||||
DB: Backend,
|
||||
T: QueryFragment<DB>,
|
||||
{
|
||||
fn walk_ast(&self, mut out: AstPass<DB>) -> QueryResult<()> {
|
||||
out.push_sql("NOT (");
|
||||
self.0.walk_ast(out.reborrow())?;
|
||||
out.push_sql(")");
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl_query_id!(Not<T>);
|
@ -268,6 +268,33 @@ fn or_doesnt_mess_with_precidence_of_previous_statements() {
|
||||
assert_eq!(Ok(0), count);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_does_not_affect_expressions_other_than_those_passed_to_it() {
|
||||
use schema::users::dsl::*;
|
||||
use diesel::expression::dsl::not;
|
||||
|
||||
let connection = connection_with_sean_and_tess_in_users_table();
|
||||
let count = users.filter(not(name.eq("Tess")))
|
||||
.filter(id.eq(1))
|
||||
.count()
|
||||
.get_result(&connection);
|
||||
|
||||
assert_eq!(Ok(1), count);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_affects_arguments_passed_when_they_contain_higher_operator_precedence() {
|
||||
use schema::users::dsl::*;
|
||||
use diesel::expression::dsl::not;
|
||||
|
||||
let connection = connection_with_sean_and_tess_in_users_table();
|
||||
let count = users.filter(not(name.eq("Tess").and(id.eq(1))))
|
||||
.count()
|
||||
.get_result(&connection);
|
||||
|
||||
assert_eq!(Ok(2), count);
|
||||
}
|
||||
|
||||
use diesel::types::VarChar;
|
||||
sql_function!(lower, lower_t, (x: VarChar) -> VarChar);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user