Skip to content

Commit 9819ed4

Browse files
authored
Merge pull request diesel-rs#534 from diesel-rs/sg-exists
Add a function for SQL `EXISTS` expressions.
2 parents 47d1196 + 0c52e53 commit 9819ed4

3 files changed

Lines changed: 89 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
3939

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

42+
* Added a function for SQL `EXISTS` expressions. See
43+
[`diesel::expression::dsl::exists`][exists] for details.
44+
45+
[exists]: http://docs.diesel.rs/diesel/expression/dsl/fn.sql.html
46+
4247
### Changed
4348

4449
* All macros with the same name as traits we can derive (e.g. `Queryable!`) have

diesel/src/expression/exists.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
use backend::Backend;
2+
use expression::{Expression, SelectableExpression, NonAggregate};
3+
use query_builder::*;
4+
use result::QueryResult;
5+
use types::Bool;
6+
7+
/// Creates a SQL `EXISTS` expression.
8+
///
9+
/// The argument must be a complete SQL query. The result of this could in
10+
/// theory be passed to `.filter`, but since the query cannot reference columns
11+
/// from the outer query, this is of limited usefulness.
12+
///
13+
/// # Example
14+
///
15+
/// ```rust
16+
/// # #[macro_use] extern crate diesel;
17+
/// # include!("src/doctest_setup.rs");
18+
/// #
19+
/// # table! {
20+
/// # users {
21+
/// # id -> Integer,
22+
/// # name -> VarChar,
23+
/// # }
24+
/// # }
25+
/// #
26+
/// # fn main() {
27+
/// # use self::users::dsl::*;
28+
/// # use diesel::select;
29+
/// # use diesel::expression::dsl::exists;
30+
/// # let connection = establish_connection();
31+
/// let sean_exists = select(exists(users.filter(name.eq("Sean"))))
32+
/// .get_result(&connection);
33+
/// let jim_exists = select(exists(users.filter(name.eq("Jim"))))
34+
/// .get_result(&connection);
35+
/// assert_eq!(Ok(true), sean_exists);
36+
/// assert_eq!(Ok(false), jim_exists);
37+
/// # }
38+
/// ```
39+
pub fn exists<T: AsQuery>(query: T) -> Exists<T::Query> {
40+
Exists(query.as_query())
41+
}
42+
43+
#[derive(Debug, Clone, Copy)]
44+
pub struct Exists<T>(T);
45+
46+
impl<T> Expression for Exists<T> where
47+
T: Query,
48+
{
49+
type SqlType = Bool;
50+
}
51+
52+
impl<T, QS> SelectableExpression<QS> for Exists<T> where
53+
Exists<T>: Expression,
54+
{
55+
}
56+
57+
impl<T> NonAggregate for Exists<T> {
58+
}
59+
60+
impl<T, DB> QueryFragment<DB> for Exists<T> where
61+
DB: Backend,
62+
T: QueryFragment<DB>,
63+
{
64+
fn to_sql(&self, out: &mut DB::QueryBuilder) -> BuildQueryResult {
65+
out.push_sql("EXISTS (");
66+
try!(self.0.to_sql(out));
67+
out.push_sql(")");
68+
Ok(())
69+
}
70+
71+
fn collect_binds(&self, out: &mut DB::BindCollector) -> QueryResult<()> {
72+
try!(self.0.collect_binds(out));
73+
Ok(())
74+
}
75+
76+
fn is_safe_to_cache_prepared(&self) -> bool {
77+
self.0.is_safe_to_cache_prepared()
78+
}
79+
}
80+
81+
impl_query_id!(Exists<T>);

diesel/src/expression/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ pub mod array_comparison;
2525
pub mod bound;
2626
#[doc(hidden)]
2727
pub mod count;
28+
#[doc(hidden)]
29+
pub mod exists;
2830
pub mod expression_methods;
2931
#[doc(hidden)]
3032
pub mod functions;
@@ -47,6 +49,7 @@ pub mod dsl {
4749
#[doc(inline)] pub use super::functions::aggregate_ordering::*;
4850
#[doc(inline)] pub use super::functions::aggregate_folding::*;
4951
#[doc(inline)] pub use super::sql_literal::sql;
52+
#[doc(inline)] pub use super::exists::exists;
5053

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

0 commit comments

Comments
 (0)