rorm/crud/delete.rs
1//! Delete builder and macro
2
3use std::marker::PhantomData;
4
5use rorm_db::database;
6use rorm_db::error::Error;
7use rorm_db::executor::Executor;
8
9use crate::conditions::{Condition, DynamicCollection};
10use crate::crud::selector::Selector;
11use crate::internal::patch::{IntoPatchCow, PatchCow};
12use crate::internal::query_context::QueryContext;
13use crate::model::{Identifiable, Model};
14use crate::Patch;
15
16/// Create a DELETE query.
17///
18/// # Usage
19/// ```no_run
20/// # use rorm::{Model, Patch, Database, delete};
21/// # #[derive(Model)] pub struct User { #[rorm(id)] id: i64, age: i32, }
22/// # #[derive(Patch)] #[rorm(model = "User")] pub struct UserPatch { id: i64, }
23/// pub async fn delete_single_user(db: &Database, user: &UserPatch) {
24/// delete(db, User)
25/// .single(user)
26/// .await
27/// .unwrap();
28/// }
29/// pub async fn delete_many_users(db: &Database, users: &[UserPatch]) {
30/// delete(db, User)
31/// .bulk(users)
32/// .await
33/// .unwrap();
34/// }
35/// pub async fn delete_underage(db: &Database) {
36/// let num_deleted: u64 = delete(db, User)
37/// .condition(User.age.less_equals(18))
38/// .await
39/// .unwrap();
40/// }
41///```
42///
43/// Like every crud macro `delete!` starts a [builder](DeleteBuilder) which is consumed to execute the query.
44///
45/// `delete!`'s first argument is a reference to the [`Database`](crate::Database).
46/// Its second is the [`Model`] type of whose table you want to delete columns from.
47///
48/// To specify what rows to delete use the following methods,
49/// which will consume the builder and execute the query:
50/// - [`single`](DeleteBuilder::single): Delete a single row identified by a patch instance
51/// - [`bulk`](DeleteBuilder::bulk): Delete a bulk of rows identified by patch instances
52/// - [`condition`](DeleteBuilder::condition): Delete all rows matching a condition
53/// - [`all`](DeleteBuilder::all): Unconditionally delete all rows
54pub fn delete<'ex, E, S>(executor: E, _: S) -> DeleteBuilder<E, S::Model>
55where
56 E: Executor<'ex>,
57 S: Selector<Model: Patch<ValueSpaceImpl = S>>,
58{
59 DeleteBuilder {
60 executor,
61
62 _phantom: PhantomData,
63 }
64}
65
66/// Builder for delete queries
67///
68/// To create a builder use [`delete`]
69///
70/// ## Generics
71/// - `E`: [`Executor`]
72///
73/// The executor to query with.
74///
75/// - `M`: [`Model`]
76///
77/// The model from whose table to delete rows.
78///
79#[must_use]
80pub struct DeleteBuilder<E, M> {
81 executor: E,
82
83 _phantom: PhantomData<M>,
84}
85
86impl<'ex, E, M> DeleteBuilder<E, M>
87where
88 E: Executor<'ex>,
89 M: Model,
90{
91 /// Delete a single row identified by a patch instance
92 ///
93 /// Note: The patch only provides the primary key, its other values will be ignored.
94 pub async fn single<P>(self, patch: &P) -> Result<u64, Error>
95 where
96 P: Patch<Model = M> + Identifiable,
97 {
98 self.condition(patch.as_condition()).await
99 }
100
101 /// Delete a bulk of rows identified by patch instances
102 ///
103 /// Note: The patches only provide the primary key, their other values will be ignored.
104 ///
105 /// # Argument
106 /// This method accepts anything which can be used to iterate
107 /// over instances or references of your [`Patch`].
108 ///
109 /// **Examples**: (where `P` is your patch)
110 /// - `Vec<P>`
111 /// - `&[P]`
112 /// - A [`map`](Iterator::map) iterator yielding `P` or `&P`
113 pub async fn bulk<'p, I, P>(self, patches: I) -> Result<u64, Error>
114 where
115 I: IntoIterator,
116 I::Item: IntoPatchCow<'p, Patch = P>,
117 P: Patch<Model = M> + Identifiable,
118 {
119 let mut owned = Vec::new();
120 let mut conditions = Vec::new();
121 for patch in patches {
122 match patch.into_patch_cow() {
123 PatchCow::Borrowed(patch) => conditions.push(patch.as_condition()),
124 PatchCow::Owned(patch) => owned.push(patch),
125 }
126 }
127 for patch in &owned {
128 conditions.push(patch.as_condition());
129 }
130 if let Some(condition) = DynamicCollection::or(conditions) {
131 self.condition(condition).await
132 } else {
133 Ok(0)
134 }
135 }
136
137 /// Delete all rows matching a condition
138 pub async fn condition<'c, C: Condition<'c>>(self, condition: C) -> Result<u64, Error> {
139 let mut context = QueryContext::new();
140 let condition_index = context.add_condition(&condition);
141 database::delete(
142 self.executor,
143 M::TABLE,
144 Some(&context.get_condition(condition_index)),
145 )
146 .await
147 }
148
149 /// Delete all rows
150 pub async fn all(self) -> Result<u64, Error> {
151 database::delete(self.executor, M::TABLE, None).await
152 }
153}