Skip to content

Commit 990adb6

Browse files
tyt2y3hjarraya
authored andcommitted
Add exec_with_returning to delete SeaQL#2432
1 parent 038c874 commit 990adb6

File tree

2 files changed

+182
-2
lines changed

2 files changed

+182
-2
lines changed

src/executor/delete.rs

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
use crate::{error::*, ActiveModelTrait, ConnectionTrait, DeleteMany, DeleteOne, EntityTrait};
2-
use sea_query::DeleteStatement;
1+
use crate::{
2+
error::*, ActiveModelTrait, ColumnTrait, ConnectionTrait, DeleteMany, DeleteOne, EntityTrait,
3+
Iterable,
4+
};
5+
use sea_query::{DeleteStatement, Query};
36
use std::future::Future;
47

8+
use super::{SelectModel, SelectorRaw};
9+
510
/// Handles DELETE operations in a ActiveModel using [DeleteStatement]
611
#[derive(Clone, Debug)]
712
pub struct Deleter {
@@ -27,6 +32,17 @@ where
2732
// so that self is dropped before entering await
2833
exec_delete_only(self.query, db)
2934
}
35+
36+
/// Execute an delete operation and return the deleted model (use `RETURNING` syntax if supported)
37+
pub fn exec_with_returning<C>(
38+
self,
39+
db: &'a C,
40+
) -> impl Future<Output = Result<Option<<A::Entity as EntityTrait>::Model>, DbErr>> + '_
41+
where
42+
C: ConnectionTrait,
43+
{
44+
exec_delete_with_returning_one::<A::Entity, _>(self.query, db)
45+
}
3046
}
3147

3248
impl<'a, E> DeleteMany<E>
@@ -41,6 +57,18 @@ where
4157
// so that self is dropped before entering await
4258
exec_delete_only(self.query, db)
4359
}
60+
61+
/// Execute an delete operation and return the deleted model (use `RETURNING` syntax if supported)
62+
pub fn exec_with_returning<C>(
63+
self,
64+
db: &C,
65+
) -> impl Future<Output = Result<Vec<E::Model>, DbErr>> + '_
66+
where
67+
E: EntityTrait,
68+
C: ConnectionTrait,
69+
{
70+
exec_delete_with_returning_many::<E, _>(self.query, db)
71+
}
4472
}
4573

4674
impl Deleter {
@@ -56,6 +84,18 @@ impl Deleter {
5684
{
5785
exec_delete(self.query, db)
5886
}
87+
88+
/// Execute an delete operation and return the deleted model (use `RETURNING` syntax if supported)
89+
pub fn exec_with_returning<E, C>(
90+
self,
91+
db: &C,
92+
) -> impl Future<Output = Result<Vec<E::Model>, DbErr>> + '_
93+
where
94+
E: EntityTrait,
95+
C: ConnectionTrait,
96+
{
97+
exec_delete_with_returning_many::<E, _>(self.query, db)
98+
}
5999
}
60100

61101
async fn exec_delete_only<C>(query: DeleteStatement, db: &C) -> Result<DeleteResult, DbErr>
@@ -77,3 +117,49 @@ where
77117
rows_affected: result.rows_affected(),
78118
})
79119
}
120+
121+
async fn exec_delete_with_returning_one<E, C>(
122+
mut query: DeleteStatement,
123+
db: &C,
124+
) -> Result<Option<E::Model>, DbErr>
125+
where
126+
E: EntityTrait,
127+
C: ConnectionTrait,
128+
{
129+
let models = match db.support_returning() {
130+
true => {
131+
let db_backend = db.get_database_backend();
132+
let delete_statement = db_backend.build(&query.returning_all().to_owned());
133+
SelectorRaw::<SelectModel<<E>::Model>>::from_statement(delete_statement)
134+
.one(db)
135+
.await?
136+
}
137+
false => unimplemented!("Database backend doesn't support RETURNING"),
138+
};
139+
Ok(models)
140+
}
141+
142+
async fn exec_delete_with_returning_many<E, C>(
143+
mut query: DeleteStatement,
144+
db: &C,
145+
) -> Result<Vec<E::Model>, DbErr>
146+
where
147+
E: EntityTrait,
148+
C: ConnectionTrait,
149+
{
150+
let models = match db.support_returning() {
151+
true => {
152+
let db_backend = db.get_database_backend();
153+
let returning = Query::returning().exprs(
154+
E::Column::iter().map(|c| c.select_enum_as(c.into_returning_expr(db_backend))),
155+
);
156+
let query = query.returning(returning);
157+
let delete_statement = db_backend.build(&query.to_owned());
158+
SelectorRaw::<SelectModel<<E>::Model>>::from_statement(delete_statement)
159+
.all(db)
160+
.await?
161+
}
162+
false => unimplemented!("Database backend doesn't support RETURNING"),
163+
};
164+
Ok(models)
165+
}

tests/returning_tests.rs

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,3 +351,97 @@ async fn update_many() {
351351

352352
run().await.unwrap();
353353
}
354+
355+
#[sea_orm_macros::test]
356+
#[cfg_attr(
357+
any(
358+
feature = "sqlx-mysql",
359+
all(
360+
feature = "sqlx-sqlite",
361+
not(feature = "sqlite-use-returning-for-3_35")
362+
)
363+
),
364+
should_panic(expected = "Database backend doesn't support RETURNING")
365+
)]
366+
async fn delete_many() {
367+
pub use common::{features::*, TestContext};
368+
use edit_log::*;
369+
370+
let run = || async {
371+
let ctx = TestContext::new("returning_tests_delete_many").await;
372+
let db = &ctx.db;
373+
374+
create_tables(db).await?;
375+
376+
let inserted_models = [
377+
Model {
378+
id: 1,
379+
action: "before_save".to_string(),
380+
values: json!({ "id": "unique-id-001" }),
381+
},
382+
Model {
383+
id: 2,
384+
action: "before_save".to_string(),
385+
values: json!({ "id": "unique-id-002" }),
386+
},
387+
];
388+
// Delete many with returning
389+
assert_eq!(
390+
Entity::insert_many(vec![
391+
ActiveModel {
392+
id: NotSet,
393+
action: Set("before_save".to_string()),
394+
values: Set(json!({ "id": "unique-id-001" })),
395+
},
396+
ActiveModel {
397+
id: NotSet,
398+
action: Set("before_save".to_string()),
399+
values: Set(json!({ "id": "unique-id-002" })),
400+
},
401+
])
402+
.exec_with_returning_many(db)
403+
.await?,
404+
inserted_models
405+
);
406+
407+
assert_eq!(
408+
Entity::delete_many()
409+
.filter(Column::Action.eq("before_save"))
410+
.exec_with_returning(db)
411+
.await?,
412+
inserted_models
413+
);
414+
415+
let inserted_model_3 = Model {
416+
id: 3,
417+
action: "before_save".to_string(),
418+
values: json!({ "id": "unique-id-003" }),
419+
};
420+
421+
Entity::insert(ActiveModel {
422+
id: NotSet,
423+
action: Set("before_save".to_string()),
424+
values: Set(json!({ "id": "unique-id-003" })),
425+
})
426+
.exec(db)
427+
.await?;
428+
429+
// One
430+
assert_eq!(
431+
Entity::delete(ActiveModel {
432+
id: Set(3),
433+
..Default::default()
434+
})
435+
.exec_with_returning(db)
436+
.await?,
437+
Some(inserted_model_3)
438+
);
439+
440+
// No-op
441+
assert_eq!(Entity::delete_many().exec_with_returning(db).await?, []);
442+
443+
Result::<(), DbErr>::Ok(())
444+
};
445+
446+
run().await.unwrap();
447+
}

0 commit comments

Comments
 (0)