1use super::{ReturningSelector, SelectModel};
2use crate::{
3 ColumnTrait, ConnectionTrait, DeleteMany, DeleteOne, EntityTrait, Iterable, ValidatedDeleteOne,
4 error::*,
5};
6use sea_query::{DeleteStatement, Query};
7
8#[derive(Clone, Debug)]
10pub struct Deleter {
11 query: DeleteStatement,
12}
13
14#[derive(Clone, Debug, PartialEq, Eq)]
16pub struct DeleteResult {
17 pub rows_affected: u64,
19}
20
21impl<E> ValidatedDeleteOne<E>
22where
23 E: EntityTrait,
24{
25 pub fn exec<C>(self, db: &C) -> Result<DeleteResult, DbErr>
27 where
28 C: ConnectionTrait,
29 {
30 exec_delete_only(self.query, db)
31 }
32
33 pub 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)
39 }
40}
41
42impl<E> DeleteOne<E>
43where
44 E: EntityTrait,
45{
46 pub fn exec<C>(self, db: &C) -> Result<DeleteResult, DbErr>
48 where
49 C: ConnectionTrait,
50 {
51 self.0?.exec(db)
52 }
53
54 pub 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)
60 }
61}
62
63impl<'a, E> DeleteMany<E>
64where
65 E: EntityTrait,
66{
67 pub fn exec<C>(self, db: &'a C) -> Result<DeleteResult, DbErr>
69 where
70 C: ConnectionTrait,
71 {
72 exec_delete_only(self.query, db)
73 }
74
75 pub 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)
82 }
83}
84
85impl Deleter {
86 pub fn new(query: DeleteStatement) -> Self {
88 Self { query }
89 }
90
91 pub fn exec<C>(self, db: &C) -> Result<DeleteResult, DbErr>
93 where
94 C: ConnectionTrait,
95 {
96 exec_delete(self.query, db)
97 }
98
99 pub 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)
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
121fn exec_delete_only<C>(query: DeleteStatement, db: &C) -> Result<DeleteResult, DbErr>
122where
123 C: ConnectionTrait,
124{
125 Deleter::new(query).exec(db)
126}
127
128fn exec_delete<C>(query: DeleteStatement, db: &C) -> Result<DeleteResult, DbErr>
129where
130 C: ConnectionTrait,
131{
132 let result = db.execute(&query)?;
133 Ok(DeleteResult {
134 rows_affected: result.rows_affected(),
135 })
136}
137
138fn 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).one(db)
154 }
155 false => Err(DbErr::BackendNotSupported {
156 db: db_backend.as_str(),
157 ctx: "DELETE RETURNING",
158 }),
159 }
160}
161
162fn exec_delete_with_returning_many<E, C>(
163 mut query: DeleteStatement,
164 db: &C,
165) -> Result<Vec<E::Model>, DbErr>
166where
167 E: EntityTrait,
168 C: ConnectionTrait,
169{
170 let db_backend = db.get_database_backend();
171 match db.support_returning() {
172 true => {
173 let returning = Query::returning().exprs(
174 E::Column::iter().map(|c| c.select_enum_as(c.into_returning_expr(db_backend))),
175 );
176 query.returning(returning);
177 ReturningSelector::<SelectModel<<E>::Model>, _>::from_query(query).all(db)
178 }
179 false => Err(DbErr::BackendNotSupported {
180 db: db_backend.as_str(),
181 ctx: "DELETE RETURNING",
182 }),
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use crate::tests_cfg::cake;
189
190 #[test]
191 fn delete_error() {
192 use crate::{DbBackend, DbErr, Delete, EntityTrait, MockDatabase};
193
194 let db = MockDatabase::new(DbBackend::MySql).into_connection();
195
196 assert!(matches!(
197 Delete::one(cake::ActiveModel {
198 ..Default::default()
199 })
200 .exec(&db),
201 Err(DbErr::PrimaryKeyNotSet { .. })
202 ));
203
204 assert!(matches!(
205 cake::Entity::delete(cake::ActiveModel::default()).exec(&db),
206 Err(DbErr::PrimaryKeyNotSet { .. })
207 ));
208 }
209}