drizzle_postgres/builder/delete.rs
1//! `DELETE` builder states and clause methods.
2//!
3//! [`DeleteBuilder`] is the builder returned by `QueryBuilder::delete`.
4//! `WHERE` and `RETURNING` may only read the table being deleted from; this
5//! is checked at the method call.
6
7use crate::values::PostgresValue;
8use core::marker::PhantomData;
9use drizzle_core::ToSQL;
10
11//------------------------------------------------------------------------------
12// Type State Markers
13//------------------------------------------------------------------------------
14
15pub use drizzle_core::builder::{DeleteInitial, DeleteReturningSet, DeleteWhereSet};
16
17//------------------------------------------------------------------------------
18// DeleteBuilder Definition
19//------------------------------------------------------------------------------
20
21/// A `PostgreSQL` `DELETE` being built: a [`QueryBuilder`](super::QueryBuilder)
22/// in one of the `Delete*` states.
23///
24/// Optionally add `WHERE`, then `RETURNING`. Without `WHERE`, every row is
25/// deleted.
26///
27/// # Examples
28///
29/// ```rust
30/// # extern crate self as drizzle;
31/// # mod _drizzle {
32/// # pub mod core { pub use drizzle_core::*; }
33/// # pub mod error { pub use drizzle_core::error::*; }
34/// # pub mod types { pub use drizzle_types::*; }
35/// # pub mod migrations { pub use drizzle_migrations::*; }
36/// # pub use drizzle_types::Dialect;
37/// # pub use drizzle_types as ddl;
38/// # pub mod postgres {
39/// # pub mod values { pub use drizzle_postgres::values::*; }
40/// # pub mod traits { pub use drizzle_postgres::traits::*; }
41/// # pub mod common { pub use drizzle_postgres::common::*; }
42/// # pub mod attrs { pub use drizzle_postgres::attrs::*; }
43/// # pub mod builder { pub use drizzle_postgres::builder::*; }
44/// # pub mod helpers { pub use drizzle_postgres::helpers::*; }
45/// # pub mod expr { pub use drizzle_postgres::expr::*; }
46/// # pub mod types { pub use drizzle_postgres::types::*; }
47/// # #[cfg(feature = "aws-data-api")]
48/// # pub mod aws_data_api { pub use drizzle_postgres::aws_data_api::*; }
49/// # pub struct Row;
50/// # impl Row {
51/// # pub fn get<'a, I, T>(&'a self, _: I) -> T { unimplemented!() }
52/// # pub fn try_get<'a, I, T>(&'a self, _: I) -> Result<T, Box<dyn std::error::Error + Sync + Send>> { unimplemented!() }
53/// # }
54/// # pub mod prelude {
55/// # pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
56/// # pub use drizzle_postgres::attrs::*;
57/// # pub use drizzle_postgres::common::PostgresSchemaType;
58/// # pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
59/// # pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
60/// # pub use drizzle_core::*;
61/// # }
62/// # }
63/// # }
64/// # pub use _drizzle::*;
65/// # pub use const_format;
66/// # fn main() {
67/// # use drizzle::postgres::prelude::*;
68/// # use drizzle::postgres::builder::QueryBuilder;
69/// # #[PostgresTable(name = "users")]
70/// # struct User {
71/// # #[column(serial, primary)]
72/// # id: i32,
73/// # name: String,
74/// # email: Option<String>,
75/// # }
76/// # #[PostgresTable(name = "posts")]
77/// # struct Post {
78/// # #[column(serial, primary)]
79/// # id: i32,
80/// # #[column(references = User::id)]
81/// # author_id: i32,
82/// # title: String,
83/// # }
84/// # #[derive(PostgresSchema)]
85/// # struct Schema {
86/// # user: User,
87/// # post: Post,
88/// # }
89/// # let db = QueryBuilder::new::<Schema>();
90/// # let Schema { user, post } = Schema::new();
91/// use drizzle::core::expr::gt;
92///
93/// let query = db
94/// .delete(user)
95/// .r#where(gt(user.id, 10))
96/// .returning(user.id);
97/// assert_eq!(
98/// query.to_sql().sql(),
99/// r#"DELETE FROM "users" WHERE "users"."id" > $1 RETURNING "users"."id""#
100/// );
101/// # }
102/// ```
103pub type DeleteBuilder<'a, Schema, State, Table, Marker = (), Row = ()> =
104 super::QueryBuilder<'a, Schema, State, Table, Marker, Row>;
105
106type ReturningMarker<Table, Columns> = drizzle_core::Scoped<
107 <Columns as drizzle_core::IntoSelectTarget>::Marker,
108 drizzle_core::Cons<Table, drizzle_core::Nil>,
109>;
110
111type ReturningRow<Table, Columns> =
112 <<Columns as drizzle_core::IntoSelectTarget>::Marker as drizzle_core::ResolveRow<Table>>::Row;
113
114type ReturningBuilder<'a, S, T, Columns> = DeleteBuilder<
115 'a,
116 S,
117 DeleteReturningSet,
118 T,
119 ReturningMarker<T, Columns>,
120 ReturningRow<T, Columns>,
121>;
122
123//------------------------------------------------------------------------------
124// Initial State Implementation
125//------------------------------------------------------------------------------
126
127impl<'a, S, T> DeleteBuilder<'a, S, DeleteInitial, T> {
128 /// Adds a `WHERE` condition; only matching rows are deleted.
129 ///
130 /// # Compile-time checks
131 ///
132 /// The condition may only use columns of the table being deleted from.
133 ///
134 /// ```compile_fail
135 /// # extern crate self as drizzle;
136 /// # mod _drizzle {
137 /// # pub mod core { pub use drizzle_core::*; }
138 /// # pub mod error { pub use drizzle_core::error::*; }
139 /// # pub mod types { pub use drizzle_types::*; }
140 /// # pub mod migrations { pub use drizzle_migrations::*; }
141 /// # pub use drizzle_types::Dialect;
142 /// # pub use drizzle_types as ddl;
143 /// # pub mod postgres {
144 /// # pub mod values { pub use drizzle_postgres::values::*; }
145 /// # pub mod traits { pub use drizzle_postgres::traits::*; }
146 /// # pub mod common { pub use drizzle_postgres::common::*; }
147 /// # pub mod attrs { pub use drizzle_postgres::attrs::*; }
148 /// # pub mod builder { pub use drizzle_postgres::builder::*; }
149 /// # pub mod helpers { pub use drizzle_postgres::helpers::*; }
150 /// # pub mod expr { pub use drizzle_postgres::expr::*; }
151 /// # pub mod types { pub use drizzle_postgres::types::*; }
152 /// # #[cfg(feature = "aws-data-api")]
153 /// # pub mod aws_data_api { pub use drizzle_postgres::aws_data_api::*; }
154 /// # pub struct Row;
155 /// # impl Row {
156 /// # pub fn get<'a, I, T>(&'a self, _: I) -> T { unimplemented!() }
157 /// # pub fn try_get<'a, I, T>(&'a self, _: I) -> Result<T, Box<dyn std::error::Error + Sync + Send>> { unimplemented!() }
158 /// # }
159 /// # pub mod prelude {
160 /// # pub use drizzle_macros::{PostgresTable, PostgresSchema, PostgresIndex};
161 /// # pub use drizzle_postgres::attrs::*;
162 /// # pub use drizzle_postgres::common::PostgresSchemaType;
163 /// # pub use drizzle_postgres::traits::{PostgresColumn, PostgresTable};
164 /// # pub use drizzle_postgres::values::{PostgresInsertValue, PostgresUpdateValue, PostgresValue};
165 /// # pub use drizzle_core::*;
166 /// # }
167 /// # }
168 /// # }
169 /// # pub use _drizzle::*;
170 /// # pub use const_format;
171 /// # fn main() {
172 /// # use drizzle::postgres::prelude::*;
173 /// # use drizzle::postgres::builder::QueryBuilder;
174 /// # #[PostgresTable(name = "users")]
175 /// # struct User {
176 /// # #[column(serial, primary)]
177 /// # id: i32,
178 /// # name: String,
179 /// # email: Option<String>,
180 /// # }
181 /// # #[PostgresTable(name = "posts")]
182 /// # struct Post {
183 /// # #[column(serial, primary)]
184 /// # id: i32,
185 /// # #[column(references = User::id)]
186 /// # author_id: i32,
187 /// # title: String,
188 /// # }
189 /// # #[derive(PostgresSchema)]
190 /// # struct Schema {
191 /// # user: User,
192 /// # post: Post,
193 /// # }
194 /// # let db = QueryBuilder::new::<Schema>();
195 /// # let Schema { user, post } = Schema::new();
196 /// use drizzle::core::expr::eq;
197 ///
198 /// // `posts` is not part of this statement.
199 /// let query = db.delete(user).r#where(eq(post.id, 1));
200 /// # }
201 /// ```
202 #[inline]
203 pub fn r#where<E, ScopeProof>(self, condition: E) -> DeleteBuilder<'a, S, DeleteWhereSet, T>
204 where
205 E: drizzle_core::expr::ExprSources,
206 E::Sources:
207 drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
208 E: drizzle_core::expr::Expr<'a, PostgresValue<'a>>,
209 E::SQLType: drizzle_core::types::BooleanLike,
210 {
211 let where_sql = crate::helpers::r#where(condition);
212 DeleteBuilder {
213 sql: self.sql.append(where_sql),
214 schema: PhantomData,
215 state: PhantomData,
216 table: PhantomData,
217 marker: PhantomData,
218 row: PhantomData,
219 grouped: PhantomData,
220 }
221 }
222
223 /// Adds `RETURNING columns`, so the statement returns the deleted rows.
224 #[inline]
225 pub fn returning<Columns, ScopeProof>(
226 self,
227 columns: Columns,
228 ) -> ReturningBuilder<'a, S, T, Columns>
229 where
230 Columns: drizzle_core::expr::ExprSources,
231 Columns::Sources:
232 drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
233 Columns: ToSQL<'a, PostgresValue<'a>> + drizzle_core::IntoSelectTarget,
234 Columns::Marker: drizzle_core::ResolveRow<T>,
235 {
236 let returning_sql = crate::helpers::returning(columns);
237 DeleteBuilder {
238 sql: self.sql.append(returning_sql),
239 schema: PhantomData,
240 state: PhantomData,
241 table: PhantomData,
242 marker: PhantomData,
243 row: PhantomData,
244 grouped: PhantomData,
245 }
246 }
247}
248
249//------------------------------------------------------------------------------
250// Post-WHERE Implementation
251//------------------------------------------------------------------------------
252
253impl<'a, S, T> DeleteBuilder<'a, S, DeleteWhereSet, T> {
254 /// Adds `RETURNING columns` after `WHERE`.
255 #[inline]
256 pub fn returning<Columns, ScopeProof>(
257 self,
258 columns: Columns,
259 ) -> ReturningBuilder<'a, S, T, Columns>
260 where
261 Columns: drizzle_core::expr::ExprSources,
262 Columns::Sources:
263 drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
264 Columns: ToSQL<'a, PostgresValue<'a>> + drizzle_core::IntoSelectTarget,
265 Columns::Marker: drizzle_core::ResolveRow<T>,
266 {
267 let returning_sql = crate::helpers::returning(columns);
268 DeleteBuilder {
269 sql: self.sql.append(returning_sql),
270 schema: PhantomData,
271 state: PhantomData,
272 table: PhantomData,
273 marker: PhantomData,
274 row: PhantomData,
275 grouped: PhantomData,
276 }
277 }
278}
279
280#[cfg(test)]
281mod tests {
282 use super::*;
283 use drizzle_core::{SQL, ToSQL};
284
285 #[test]
286 fn test_delete_builder_creation() {
287 let builder = DeleteBuilder::<(), DeleteInitial, ()> {
288 sql: SQL::raw("DELETE FROM test"),
289 schema: PhantomData,
290 state: PhantomData,
291 table: PhantomData,
292 marker: PhantomData,
293 row: PhantomData,
294 grouped: PhantomData,
295 };
296
297 assert_eq!(builder.to_sql().sql(), "DELETE FROM test");
298 }
299}