1use crate::{
2 ActiveModelTrait, ActiveValue, ColumnTrait, DbBackend, DbErr, EntityTrait, IntoActiveModel,
3 Iterable, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryTrait,
4 query::column_tuple_in_condition,
5 sea_query::{IntoValueTuple, ValueTuple},
6};
7use core::marker::PhantomData;
8use sea_query::DeleteStatement;
9
10#[derive(Clone, Debug)]
15pub struct Delete;
16
17#[derive(Clone, Debug)]
26pub struct DeleteOne<E: EntityTrait>(pub(crate) Result<ValidatedDeleteOne<E>, DbErr>);
27
28#[derive(Clone, Debug)]
31pub struct ValidatedDeleteOne<E: EntityTrait> {
32 pub(crate) query: DeleteStatement,
33 pub(crate) entity: PhantomData<E>,
34}
35
36impl<E: EntityTrait> TryFrom<DeleteOne<E>> for ValidatedDeleteOne<E> {
37 type Error = DbErr;
38
39 fn try_from(value: DeleteOne<E>) -> Result<Self, Self::Error> {
40 value.0
41 }
42}
43
44impl<E: EntityTrait> DeleteOne<E> {
45 pub fn validate(self) -> Result<ValidatedDeleteOne<E>, DbErr> {
47 self.try_into()
48 }
49}
50
51#[derive(Clone, Debug)]
55pub struct DeleteMany<E>
56where
57 E: EntityTrait,
58{
59 pub(crate) query: DeleteStatement,
60 pub(crate) entity: PhantomData<E>,
61}
62
63impl Delete {
64 pub fn one<E, A, M>(model: M) -> DeleteOne<E>
103 where
104 E: EntityTrait,
105 A: ActiveModelTrait<Entity = E>,
106 M: IntoActiveModel<A>,
107 {
108 let model = model.into_active_model();
109 let mut myself = ValidatedDeleteOne {
110 query: DeleteStatement::new()
111 .from_table(A::Entity::default().table_ref())
112 .to_owned(),
113 entity: PhantomData,
114 };
115 for key in <A::Entity as EntityTrait>::PrimaryKey::iter() {
117 let col = key.into_column();
118 let av = model.get(col);
119 match av {
120 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => {
121 myself = myself.filter(col.eq(value));
122 }
123 ActiveValue::NotSet => {
124 return DeleteOne(Err(DbErr::PrimaryKeyNotSet { ctx: "DeleteOne" }));
125 }
126 }
127 }
128 DeleteOne(Ok(myself))
129 }
130
131 #[doc(hidden)]
132 pub fn _one_only_for_use_by_model_ex<E: EntityTrait>(entity: E) -> ValidatedDeleteOne<E> {
133 ValidatedDeleteOne {
134 query: DeleteStatement::new()
135 .from_table(entity.table_ref())
136 .to_owned(),
137 entity: PhantomData,
138 }
139 }
140
141 pub fn many<E>(entity: E) -> DeleteMany<E>
155 where
156 E: EntityTrait,
157 {
158 DeleteMany {
159 query: DeleteStatement::new()
160 .from_table(entity.table_ref())
161 .to_owned(),
162 entity: PhantomData,
163 }
164 }
165}
166
167impl<E> QueryFilter for ValidatedDeleteOne<E>
168where
169 E: EntityTrait,
170{
171 type QueryStatement = DeleteStatement;
172
173 fn query(&mut self) -> &mut DeleteStatement {
174 &mut self.query
175 }
176}
177
178impl<E> QueryFilter for DeleteMany<E>
179where
180 E: EntityTrait,
181{
182 type QueryStatement = DeleteStatement;
183
184 fn query(&mut self) -> &mut DeleteStatement {
185 &mut self.query
186 }
187}
188
189impl<E> DeleteMany<E>
190where
191 E: EntityTrait,
192{
193 pub fn filter_by_ids<I>(mut self, values: I) -> Self
199 where
200 I: IntoIterator<Item = <E::PrimaryKey as PrimaryKeyTrait>::ValueType>,
201 {
202 self.query.cond_where(
203 column_tuple_in_condition(
204 &E::default().table_ref(),
205 &E::primary_key_identity(),
206 &values
207 .into_iter()
208 .map(|v| v.into_value_tuple())
209 .collect::<Vec<_>>(),
210 DbBackend::Sqlite,
211 )
212 .expect("trait bound ensured arity"),
213 );
214 self
215 }
216
217 #[doc(hidden)]
218 pub fn filter_by_value_tuples(mut self, values: &[ValueTuple], db_backend: DbBackend) -> Self {
222 self.query.cond_where(
223 column_tuple_in_condition(
224 &E::default().table_ref(),
225 &E::primary_key_identity(),
226 values,
227 db_backend,
228 )
229 .expect(""),
230 );
231 self
232 }
233}
234
235impl<E> QueryTrait for ValidatedDeleteOne<E>
236where
237 E: EntityTrait,
238{
239 type QueryStatement = DeleteStatement;
240
241 fn query(&mut self) -> &mut DeleteStatement {
242 &mut self.query
243 }
244
245 fn as_query(&self) -> &DeleteStatement {
246 &self.query
247 }
248
249 fn into_query(self) -> DeleteStatement {
250 self.query
251 }
252}
253
254impl<E> QueryTrait for DeleteMany<E>
255where
256 E: EntityTrait,
257{
258 type QueryStatement = DeleteStatement;
259
260 fn query(&mut self) -> &mut DeleteStatement {
261 &mut self.query
262 }
263
264 fn as_query(&self) -> &DeleteStatement {
265 &self.query
266 }
267
268 fn into_query(self) -> DeleteStatement {
269 self.query
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use crate::tests_cfg::{cake, fruit};
276 use crate::{DbBackend, entity::*, query::*};
277
278 #[test]
279 fn delete_1() {
280 assert_eq!(
281 Delete::one(cake::Model {
282 id: 1,
283 name: "Apple Pie".to_owned(),
284 })
285 .validate()
286 .unwrap()
287 .build(DbBackend::Postgres)
288 .to_string(),
289 r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
290 );
291 assert_eq!(
292 Delete::one(cake::ActiveModel {
293 id: ActiveValue::set(1),
294 name: ActiveValue::set("Apple Pie".to_owned()),
295 })
296 .validate()
297 .unwrap()
298 .build(DbBackend::Postgres)
299 .to_string(),
300 r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
301 );
302 }
303
304 #[test]
305 fn delete_2() {
306 assert_eq!(
307 Delete::many(fruit::Entity)
308 .filter(fruit::Column::Name.contains("Cheese"))
309 .build(DbBackend::Postgres)
310 .to_string(),
311 r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE '%Cheese%'"#,
312 );
313 }
314}