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