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<E: EntityTrait>(pub(crate) Result<ValidatedDeleteOne<E>, DbErr>);
22
23#[derive(Clone, Debug)]
26pub struct ValidatedDeleteOne<E: EntityTrait> {
27 pub(crate) query: DeleteStatement,
28 pub(crate) entity: PhantomData<E>,
29}
30
31impl<E: EntityTrait> TryFrom<DeleteOne<E>> for ValidatedDeleteOne<E> {
32 type Error = DbErr;
33
34 fn try_from(value: DeleteOne<E>) -> Result<Self, Self::Error> {
35 value.0
36 }
37}
38
39impl<E: EntityTrait> DeleteOne<E> {
40 pub fn validate(self) -> Result<ValidatedDeleteOne<E>, 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<E>
96 where
97 E: EntityTrait,
98 A: ActiveModelTrait<Entity = E>,
99 M: IntoActiveModel<A>,
100 {
101 let model = model.into_active_model();
102 let mut myself = ValidatedDeleteOne {
103 query: DeleteStatement::new()
104 .from_table(A::Entity::default().table_ref())
105 .to_owned(),
106 entity: PhantomData,
107 };
108 for key in <A::Entity as EntityTrait>::PrimaryKey::iter() {
110 let col = key.into_column();
111 let av = model.get(col);
112 match av {
113 ActiveValue::Set(value) | ActiveValue::Unchanged(value) => {
114 myself = myself.filter(col.eq(value));
115 }
116 ActiveValue::NotSet => {
117 return DeleteOne(Err(DbErr::PrimaryKeyNotSet { ctx: "DeleteOne" }));
118 }
119 }
120 }
121 DeleteOne(Ok(myself))
122 }
123
124 #[doc(hidden)]
125 pub fn _one_only_for_use_by_model_ex<E: EntityTrait>(entity: E) -> ValidatedDeleteOne<E> {
126 ValidatedDeleteOne {
127 query: DeleteStatement::new()
128 .from_table(entity.table_ref())
129 .to_owned(),
130 entity: PhantomData,
131 }
132 }
133
134 pub fn many<E>(entity: E) -> DeleteMany<E>
148 where
149 E: EntityTrait,
150 {
151 DeleteMany {
152 query: DeleteStatement::new()
153 .from_table(entity.table_ref())
154 .to_owned(),
155 entity: PhantomData,
156 }
157 }
158}
159
160impl<E> QueryFilter for ValidatedDeleteOne<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<E> QueryFilter for DeleteMany<E>
172where
173 E: EntityTrait,
174{
175 type QueryStatement = DeleteStatement;
176
177 fn query(&mut self) -> &mut DeleteStatement {
178 &mut self.query
179 }
180}
181
182impl<E> QueryTrait for ValidatedDeleteOne<E>
183where
184 E: EntityTrait,
185{
186 type QueryStatement = DeleteStatement;
187
188 fn query(&mut self) -> &mut DeleteStatement {
189 &mut self.query
190 }
191
192 fn as_query(&self) -> &DeleteStatement {
193 &self.query
194 }
195
196 fn into_query(self) -> DeleteStatement {
197 self.query
198 }
199}
200
201impl<E> QueryTrait for DeleteMany<E>
202where
203 E: EntityTrait,
204{
205 type QueryStatement = DeleteStatement;
206
207 fn query(&mut self) -> &mut DeleteStatement {
208 &mut self.query
209 }
210
211 fn as_query(&self) -> &DeleteStatement {
212 &self.query
213 }
214
215 fn into_query(self) -> DeleteStatement {
216 self.query
217 }
218}
219
220#[cfg(test)]
221mod tests {
222 use crate::tests_cfg::{cake, fruit};
223 use crate::{DbBackend, entity::*, query::*};
224
225 #[test]
226 fn delete_1() {
227 assert_eq!(
228 Delete::one(cake::Model {
229 id: 1,
230 name: "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 assert_eq!(
239 Delete::one(cake::ActiveModel {
240 id: ActiveValue::set(1),
241 name: ActiveValue::set("Apple Pie".to_owned()),
242 })
243 .validate()
244 .unwrap()
245 .build(DbBackend::Postgres)
246 .to_string(),
247 r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
248 );
249 }
250
251 #[test]
252 fn delete_2() {
253 assert_eq!(
254 Delete::many(fruit::Entity)
255 .filter(fruit::Column::Name.contains("Cheese"))
256 .build(DbBackend::Postgres)
257 .to_string(),
258 r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE '%Cheese%'"#,
259 );
260 }
261}