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 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 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 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 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 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 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 pub fn new(query: DeleteStatement) -> Self {
88 Self { query }
89 }
90
91 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 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}