1use crate::{
2 ActiveModelTrait, ActiveValue, ColumnTrait, DbErr, EntityTrait, IntoActiveModel, Iterable,
3 PrimaryKeyToColumn, QueryFilter, QueryTrait,
4};
5use core::marker::PhantomData;
6use sea_query::DeleteStatement;
7
8#[derive(Clone, Debug)]
10pub struct Delete;
11
12#[derive(Clone, Debug)]
21pub struct DeleteOne<A: ActiveModelTrait>(pub(crate) Result<ValidatedDeleteOne<A>, DbErr>);
22
23#[derive(Clone, Debug)]
26pub struct ValidatedDeleteOne<A: ActiveModelTrait> {
27 pub(crate) query: DeleteStatement,
28 pub(crate) model: A,
29}
30
31impl<A: ActiveModelTrait> TryFrom<DeleteOne<A>> for ValidatedDeleteOne<A> {
32 type Error = DbErr;
33
34 fn try_from(value: DeleteOne<A>) -> Result<Self, Self::Error> {
35 value.0
36 }
37}
38
39impl<A: ActiveModelTrait> DeleteOne<A> {
40 pub fn validate(self) -> Result<ValidatedDeleteOne<A>, DbErr> {
42 self.try_into()
43 }
44}
45
46#[derive(Clone, Debug)]
48pub struct DeleteMany<E>
49where
50 E: EntityTrait,
51{
52 pub(crate) query: DeleteStatement,
53 pub(crate) entity: PhantomData<E>,
54}
55
56impl Delete {
57 pub fn one<E, A, M>(model: M) -> DeleteOne<A>
96 where
97 E: EntityTrait,
98 A: ActiveModelTrait<Entity = E>,
99 M: IntoActiveModel<A>,
100 {
101 let mut myself = ValidatedDeleteOne {
102 query: DeleteStatement::new()
103 .from_table(A::Entity::default().table_ref())
104 .to_owned(),
105 model: model.into_active_model(),
106 };
107 for key in <A::Entity as EntityTrait>::PrimaryKey::iter() {
109 let col = key.into_column();
110 let av = myself.model.get(col);
111 match av {
112 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => {
113 myself = myself.filter(col.eq(value));
114 }
115 ActiveValue::NotSet => {
116 return DeleteOne(Err(DbErr::PrimaryKeyNotSet { ctx: "DeleteOne" }));
117 }
118 }
119 }
120 DeleteOne(Ok(myself))
121 }
122
123 pub fn many<E>(entity: E) -> DeleteMany<E>
137 where
138 E: EntityTrait,
139 {
140 DeleteMany {
141 query: DeleteStatement::new()
142 .from_table(entity.table_ref())
143 .to_owned(),
144 entity: PhantomData,
145 }
146 }
147}
148
149impl<A> QueryFilter for ValidatedDeleteOne<A>
150where
151 A: ActiveModelTrait,
152{
153 type QueryStatement = DeleteStatement;
154
155 fn query(&mut self) -> &mut DeleteStatement {
156 &mut self.query
157 }
158}
159
160impl<E> QueryFilter for DeleteMany<E>
161where
162 E: EntityTrait,
163{
164 type QueryStatement = DeleteStatement;
165
166 fn query(&mut self) -> &mut DeleteStatement {
167 &mut self.query
168 }
169}
170
171impl<A> QueryTrait for ValidatedDeleteOne<A>
172where
173 A: ActiveModelTrait,
174{
175 type QueryStatement = DeleteStatement;
176
177 fn query(&mut self) -> &mut DeleteStatement {
178 &mut self.query
179 }
180
181 fn as_query(&self) -> &DeleteStatement {
182 &self.query
183 }
184
185 fn into_query(self) -> DeleteStatement {
186 self.query
187 }
188}
189
190impl<E> QueryTrait for DeleteMany<E>
191where
192 E: EntityTrait,
193{
194 type QueryStatement = DeleteStatement;
195
196 fn query(&mut self) -> &mut DeleteStatement {
197 &mut self.query
198 }
199
200 fn as_query(&self) -> &DeleteStatement {
201 &self.query
202 }
203
204 fn into_query(self) -> DeleteStatement {
205 self.query
206 }
207}
208
209#[cfg(test)]
210mod tests {
211 use crate::tests_cfg::{cake, fruit};
212 use crate::{DbBackend, entity::*, query::*};
213
214 #[test]
215 fn delete_1() {
216 assert_eq!(
217 Delete::one(cake::Model {
218 id: 1,
219 name: "Apple Pie".to_owned(),
220 })
221 .validate()
222 .unwrap()
223 .build(DbBackend::Postgres)
224 .to_string(),
225 r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
226 );
227 assert_eq!(
228 Delete::one(cake::ActiveModel {
229 id: ActiveValue::set(1),
230 name: ActiveValue::set("Apple Pie".to_owned()),
231 })
232 .validate()
233 .unwrap()
234 .build(DbBackend::Postgres)
235 .to_string(),
236 r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
237 );
238 }
239
240 #[test]
241 fn delete_2() {
242 assert_eq!(
243 Delete::many(fruit::Entity)
244 .filter(fruit::Column::Name.contains("Cheese"))
245 .build(DbBackend::Postgres)
246 .to_string(),
247 r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE '%Cheese%'"#,
248 );
249 }
250}