sea_orm/executor/
delete.rs

1use super::{ReturningSelector, SelectModel};
2use crate::{
3    ActiveModelTrait, ColumnTrait, ConnectionTrait, DeleteMany, DeleteOne, EntityTrait, Iterable,
4    ValidatedDeleteOne, error::*,
5};
6use sea_query::{DeleteStatement, Query};
7use std::future::Future;
8
9/// Handles DELETE operations in a ActiveModel using [DeleteStatement]
10#[derive(Clone, Debug)]
11pub struct Deleter {
12    query: DeleteStatement,
13}
14
15/// The result of a DELETE operation
16#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct DeleteResult {
18    /// The number of rows affected by the DELETE operation
19    pub rows_affected: u64,
20}
21
22impl<A> ValidatedDeleteOne<A>
23where
24    A: ActiveModelTrait,
25{
26    /// Execute a DELETE operation on one ActiveModel
27    pub async fn exec<C>(self, db: &C) -> Result<DeleteResult, DbErr>
28    where
29        C: ConnectionTrait,
30    {
31        exec_delete_only(self.query, db).await
32    }
33
34    /// Execute an delete operation and return the deleted model
35    pub async fn exec_with_returning<C>(
36        self,
37        db: &C,
38    ) -> Result<Option<<A::Entity as EntityTrait>::Model>, DbErr>
39    where
40        C: ConnectionTrait,
41    {
42        exec_delete_with_returning_one::<A::Entity, _>(self.query, db).await
43    }
44}
45
46impl<A> DeleteOne<A>
47where
48    A: ActiveModelTrait,
49{
50    /// Execute a DELETE operation on one ActiveModel
51    pub async fn exec<C>(self, db: &C) -> Result<DeleteResult, DbErr>
52    where
53        C: ConnectionTrait,
54    {
55        self.0?.exec(db).await
56    }
57
58    /// Execute an delete operation and return the deleted model
59    pub async fn exec_with_returning<C>(
60        self,
61        db: &C,
62    ) -> Result<Option<<A::Entity as EntityTrait>::Model>, DbErr>
63    where
64        C: ConnectionTrait,
65    {
66        self.0?.exec_with_returning(db).await
67    }
68}
69
70impl<'a, E> DeleteMany<E>
71where
72    E: EntityTrait,
73{
74    /// Execute a DELETE operation on many ActiveModels
75    pub fn exec<C>(self, db: &'a C) -> impl Future<Output = Result<DeleteResult, DbErr>> + 'a
76    where
77        C: ConnectionTrait,
78    {
79        // so that self is dropped before entering await
80        exec_delete_only(self.query, db)
81    }
82
83    /// Execute an delete operation and return the deleted model
84    pub fn exec_with_returning<C>(
85        self,
86        db: &C,
87    ) -> impl Future<Output = Result<Vec<E::Model>, DbErr>> + '_
88    where
89        E: EntityTrait,
90        C: ConnectionTrait,
91    {
92        exec_delete_with_returning_many::<E, _>(self.query, db)
93    }
94}
95
96impl Deleter {
97    /// Instantiate a new [Deleter] by passing it a [DeleteStatement]
98    pub fn new(query: DeleteStatement) -> Self {
99        Self { query }
100    }
101
102    /// Execute a DELETE operation
103    pub fn exec<C>(self, db: &C) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_
104    where
105        C: ConnectionTrait,
106    {
107        exec_delete(self.query, db)
108    }
109
110    /// Execute an delete operation and return the deleted model
111    pub fn exec_with_returning<E, C>(
112        self,
113        db: &C,
114    ) -> impl Future<Output = Result<Vec<E::Model>, DbErr>> + '_
115    where
116        E: EntityTrait,
117        C: ConnectionTrait,
118    {
119        exec_delete_with_returning_many::<E, _>(self.query, db)
120    }
121}
122
123async fn exec_delete_only<C>(query: DeleteStatement, db: &C) -> Result<DeleteResult, DbErr>
124where
125    C: ConnectionTrait,
126{
127    Deleter::new(query).exec(db).await
128}
129
130async fn exec_delete<C>(query: DeleteStatement, db: &C) -> Result<DeleteResult, DbErr>
131where
132    C: ConnectionTrait,
133{
134    let result = db.execute(&query).await?;
135    Ok(DeleteResult {
136        rows_affected: result.rows_affected(),
137    })
138}
139
140async fn exec_delete_with_returning_one<E, C>(
141    mut query: DeleteStatement,
142    db: &C,
143) -> Result<Option<E::Model>, DbErr>
144where
145    E: EntityTrait,
146    C: ConnectionTrait,
147{
148    let db_backend = db.get_database_backend();
149    match db.support_returning() {
150        true => {
151            query.returning_all();
152            ReturningSelector::<SelectModel<<E>::Model>, _>::from_query(query)
153                .one(db)
154                .await
155        }
156        false => Err(DbErr::BackendNotSupported {
157            db: db_backend.as_str(),
158            ctx: "DELETE RETURNING",
159        }),
160    }
161}
162
163async fn exec_delete_with_returning_many<E, C>(
164    mut query: DeleteStatement,
165    db: &C,
166) -> Result<Vec<E::Model>, DbErr>
167where
168    E: EntityTrait,
169    C: ConnectionTrait,
170{
171    let db_backend = db.get_database_backend();
172    match db.support_returning() {
173        true => {
174            let returning = Query::returning().exprs(
175                E::Column::iter().map(|c| c.select_enum_as(c.into_returning_expr(db_backend))),
176            );
177            query.returning(returning);
178            ReturningSelector::<SelectModel<<E>::Model>, _>::from_query(query)
179                .all(db)
180                .await
181        }
182        false => Err(DbErr::BackendNotSupported {
183            db: db_backend.as_str(),
184            ctx: "DELETE RETURNING",
185        }),
186    }
187}
188
189#[cfg(test)]
190mod tests {
191    use crate::tests_cfg::cake;
192
193    #[smol_potat::test]
194    async fn delete_error() {
195        use crate::{DbBackend, DbErr, Delete, EntityTrait, MockDatabase};
196
197        let db = MockDatabase::new(DbBackend::MySql).into_connection();
198
199        assert!(matches!(
200            Delete::one(cake::ActiveModel {
201                ..Default::default()
202            })
203            .exec(&db)
204            .await,
205            Err(DbErr::PrimaryKeyNotSet { .. })
206        ));
207
208        assert!(matches!(
209            cake::Entity::delete(cake::ActiveModel::default())
210                .exec(&db)
211                .await,
212            Err(DbErr::PrimaryKeyNotSet { .. })
213        ));
214    }
215}