sea_orm/executor/
delete.rs

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