Skip to main content

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