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