mirror of
https://github.com/diesel-rs/diesel.git
synced 2024-10-04 01:28:13 +03:00
Implement RETURNING
clause for DELETE
statements
This commit is contained in:
parent
332ba12617
commit
e48d8addce
@ -64,6 +64,9 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
|
||||
* Added support for the PostgreSQL `ALL` operator. See
|
||||
http://docs.diesel.rs/diesel/pg/expression/dsl/fn.all.html for details.
|
||||
|
||||
* Added support for `RETURNING` expressions in `DELETE` statements. Implicitly
|
||||
these queries will use `RETURNING *`.
|
||||
|
||||
### Changed
|
||||
|
||||
* Diesel now targets `nightly-2016-07-07`. Future releases will update to a
|
||||
|
@ -45,6 +45,13 @@ macro_rules! column {
|
||||
{
|
||||
}
|
||||
|
||||
impl<ST, Source, Predicate> SelectableExpression<
|
||||
$crate::query_source::filter::FilteredQuerySource<Source, Predicate>, ST>
|
||||
for $column_name where
|
||||
$column_name: SelectableExpression<Source, ST>
|
||||
{
|
||||
}
|
||||
|
||||
impl $crate::expression::NonAggregate for $column_name {}
|
||||
|
||||
impl $crate::query_source::Column for $column_name {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use backend::Backend;
|
||||
use backend::{Backend, SupportsReturningClause};
|
||||
use expression::{Expression, SelectableExpression, NonAggregate};
|
||||
use query_builder::*;
|
||||
use query_source::Table;
|
||||
use result::QueryResult;
|
||||
@ -44,3 +45,99 @@ impl<T, U, DB> QueryFragment<DB> for DeleteStatement<T, U> where
|
||||
}
|
||||
|
||||
impl_query_id!(noop: DeleteStatement<T, U>);
|
||||
|
||||
impl<T, U> AsQuery for DeleteStatement<T, U> where
|
||||
T: Table,
|
||||
<T as Table>::AllColumns: Expression + SelectableExpression<T>,
|
||||
DeleteQuery<<T as Table>::AllColumns, DeleteStatement<T, U>>: Query,
|
||||
{
|
||||
type SqlType = <Self::Query as Query>::SqlType;
|
||||
type Query = DeleteQuery<<T as Table>::AllColumns, DeleteStatement<T, U>>;
|
||||
|
||||
fn as_query(self) -> Self::Query {
|
||||
DeleteQuery {
|
||||
returning: T::all_columns(),
|
||||
statement: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> DeleteStatement<T, U> {
|
||||
/// Specify what expression is returned after execution of the `delete`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ### Deleting a record:
|
||||
///
|
||||
/// ```rust
|
||||
/// # #[macro_use] extern crate diesel;
|
||||
/// # include!("src/doctest_setup.rs");
|
||||
/// #
|
||||
/// # table! {
|
||||
/// # users {
|
||||
/// # id -> Integer,
|
||||
/// # name -> VarChar,
|
||||
/// # }
|
||||
/// # }
|
||||
/// #
|
||||
/// # #[cfg(feature = "postgres")]
|
||||
/// # fn main() {
|
||||
/// # use self::users::dsl::*;
|
||||
/// # let connection = establish_connection();
|
||||
/// let deleted_name = diesel::delete(users.filter(name.eq("Sean")))
|
||||
/// .returning(name)
|
||||
/// .get_result(&connection);
|
||||
/// assert_eq!(Ok("Sean".to_string()), deleted_name);
|
||||
/// # }
|
||||
/// # #[cfg(not(feature = "postgres"))]
|
||||
/// # fn main() {}
|
||||
/// ```
|
||||
pub fn returning<E>(self, returns: E) -> DeleteQuery<E, Self> where
|
||||
E: Expression + SelectableExpression<T>,
|
||||
DeleteQuery<E, Self>: Query,
|
||||
{
|
||||
DeleteQuery {
|
||||
returning: returns,
|
||||
statement: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct DeleteQuery<T, U> {
|
||||
returning: T,
|
||||
statement: U,
|
||||
}
|
||||
|
||||
impl<T, U> Query for DeleteQuery<T, U> where
|
||||
T: Expression + NonAggregate,
|
||||
{
|
||||
type SqlType = T::SqlType;
|
||||
}
|
||||
|
||||
impl<T, U, DB> QueryFragment<DB> for DeleteQuery<T, U> where
|
||||
DB: Backend + SupportsReturningClause,
|
||||
T: QueryFragment<DB>,
|
||||
U: QueryFragment<DB>,
|
||||
{
|
||||
fn to_sql(&self, out: &mut DB::QueryBuilder) -> BuildQueryResult {
|
||||
try!(self.statement.to_sql(out));
|
||||
out.push_sql(" RETURNING ");
|
||||
try!(self.returning.to_sql(out));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn collect_binds(&self, out: &mut DB::BindCollector) -> QueryResult<()> {
|
||||
try!(self.statement.collect_binds(out));
|
||||
try!(self.returning.collect_binds(out));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_safe_to_cache_prepared(&self) -> bool {
|
||||
self.statement.is_safe_to_cache_prepared() &&
|
||||
self.returning.is_safe_to_cache_prepared()
|
||||
}
|
||||
}
|
||||
|
||||
impl_query_id!(noop: DeleteQuery<T, U>);
|
||||
|
@ -0,0 +1,26 @@
|
||||
#[macro_use]
|
||||
extern crate diesel;
|
||||
|
||||
use diesel::*;
|
||||
use diesel::sqlite::SqliteConnection;
|
||||
|
||||
table! {
|
||||
users {
|
||||
id -> Integer,
|
||||
name -> VarChar,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
use self::users::dsl::*;
|
||||
let connection = SqliteConnection::establish(":memory:").unwrap();
|
||||
|
||||
delete(users.filter(name.eq("Bill")))
|
||||
.get_result(&connection);
|
||||
//~^ ERROR SupportsReturningClause
|
||||
|
||||
delete(users.filter(name.eq("Bill")))
|
||||
.returning(name)
|
||||
.get_result(&connection);
|
||||
//~^ ERROR SupportsReturningClause
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
#[macro_use]
|
||||
extern crate diesel;
|
||||
|
||||
use diesel::*;
|
||||
use diesel::pg::PgConnection;
|
||||
|
||||
table! {
|
||||
users {
|
||||
id -> Integer,
|
||||
name -> VarChar,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NewUser(String);
|
||||
|
||||
Insertable! {
|
||||
(users)
|
||||
pub struct NewUser(#[column_name(name)] String,);
|
||||
}
|
||||
|
||||
table! {
|
||||
non_users {
|
||||
id -> Integer,
|
||||
noname -> VarChar,
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let connection = PgConnection::establish("").unwrap();
|
||||
|
||||
delete(users::table.filter(users::columns::name.eq("Bill")))
|
||||
.returning(non_users::columns::noname);
|
||||
//~^ ERROR SelectableExpression
|
||||
|
||||
insert(&NewUser("Hello".into()))
|
||||
.into(users::table)
|
||||
.returning(non_users::columns::noname);
|
||||
//~^ ERROR SelectableExpression
|
||||
|
||||
update(users::table)
|
||||
.set(users::columns::name.eq("Bill"))
|
||||
.returning(non_users::columns::noname);
|
||||
//~^ ERROR SelectableExpression
|
||||
}
|
@ -27,3 +27,18 @@ fn delete_single_record() {
|
||||
|
||||
assert_eq!(Ok(vec![tess]), users.load(&connection));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(feature = "sqlite"))]
|
||||
fn return_deleted_records() {
|
||||
use schema::users::dsl::*;
|
||||
let connection = connection_with_sean_and_tess_in_users_table();
|
||||
|
||||
let deleted_name = delete(users.filter(name.eq("Sean")))
|
||||
.returning(name)
|
||||
.get_result(&connection);
|
||||
assert_eq!(Ok("Sean".to_string()), deleted_name);
|
||||
|
||||
let num_users = users.count().first(&connection);
|
||||
assert_eq!(Ok(1), num_users);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user