Skip to content

Commit

Permalink
Merge pull request #534 from diesel-rs/sg-exists
Browse files Browse the repository at this point in the history
Add a function for SQL `EXISTS` expressions.
  • Loading branch information
sgrif authored Dec 8, 2016
2 parents 47d1196 + 0c52e53 commit 9819ed4
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/

[insert]: http://docs.diesel.rs/diesel/fn.insert.html

* Added a function for SQL `EXISTS` expressions. See
[`diesel::expression::dsl::exists`][exists] for details.

[exists]: http://docs.diesel.rs/diesel/expression/dsl/fn.sql.html

### Changed

* All macros with the same name as traits we can derive (e.g. `Queryable!`) have
Expand Down
81 changes: 81 additions & 0 deletions diesel/src/expression/exists.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use backend::Backend;
use expression::{Expression, SelectableExpression, NonAggregate};
use query_builder::*;
use result::QueryResult;
use types::Bool;

/// Creates a SQL `EXISTS` expression.
///
/// The argument must be a complete SQL query. The result of this could in
/// theory be passed to `.filter`, but since the query cannot reference columns
/// from the outer query, this is of limited usefulness.
///
/// # Example
///
/// ```rust
/// # #[macro_use] extern crate diesel;
/// # include!("src/doctest_setup.rs");
/// #
/// # table! {
/// # users {
/// # id -> Integer,
/// # name -> VarChar,
/// # }
/// # }
/// #
/// # fn main() {
/// # use self::users::dsl::*;
/// # use diesel::select;
/// # use diesel::expression::dsl::exists;
/// # let connection = establish_connection();
/// let sean_exists = select(exists(users.filter(name.eq("Sean"))))
/// .get_result(&connection);
/// let jim_exists = select(exists(users.filter(name.eq("Jim"))))
/// .get_result(&connection);
/// assert_eq!(Ok(true), sean_exists);
/// assert_eq!(Ok(false), jim_exists);
/// # }
/// ```
pub fn exists<T: AsQuery>(query: T) -> Exists<T::Query> {
Exists(query.as_query())
}

#[derive(Debug, Clone, Copy)]
pub struct Exists<T>(T);

impl<T> Expression for Exists<T> where
T: Query,
{
type SqlType = Bool;
}

impl<T, QS> SelectableExpression<QS> for Exists<T> where
Exists<T>: Expression,
{
}

impl<T> NonAggregate for Exists<T> {
}

impl<T, DB> QueryFragment<DB> for Exists<T> where
DB: Backend,
T: QueryFragment<DB>,
{
fn to_sql(&self, out: &mut DB::QueryBuilder) -> BuildQueryResult {
out.push_sql("EXISTS (");
try!(self.0.to_sql(out));
out.push_sql(")");
Ok(())
}

fn collect_binds(&self, out: &mut DB::BindCollector) -> QueryResult<()> {
try!(self.0.collect_binds(out));
Ok(())
}

fn is_safe_to_cache_prepared(&self) -> bool {
self.0.is_safe_to_cache_prepared()
}
}

impl_query_id!(Exists<T>);
3 changes: 3 additions & 0 deletions diesel/src/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ pub mod array_comparison;
pub mod bound;
#[doc(hidden)]
pub mod count;
#[doc(hidden)]
pub mod exists;
pub mod expression_methods;
#[doc(hidden)]
pub mod functions;
Expand All @@ -47,6 +49,7 @@ pub mod dsl {
#[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;

#[cfg(feature = "postgres")]
pub use pg::expression::dsl::*;
Expand Down

0 comments on commit 9819ed4

Please sign in to comment.