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