drizzle_sqlite/builder/delete.rs
1//! The DELETE builder: [`DeleteBuilder`] and its states.
2//!
3//! Start a DELETE with [`QueryBuilder::delete`](super::QueryBuilder::delete).
4
5use crate::values::SQLiteValue;
6use core::marker::PhantomData;
7use drizzle_core::ToSQL;
8
9//------------------------------------------------------------------------------
10// Type State Markers
11//------------------------------------------------------------------------------
12
13pub use drizzle_core::builder::{DeleteInitial, DeleteReturningSet, DeleteWhereSet};
14
15//------------------------------------------------------------------------------
16// DeleteBuilder Definition
17//------------------------------------------------------------------------------
18
19/// A DELETE query being built for `SQLite`.
20///
21/// This is [`QueryBuilder`](super::QueryBuilder) in one of the `Delete*`
22/// states. Start it with [`QueryBuilder::delete`](super::QueryBuilder::delete).
23///
24/// # Clause order
25///
26/// 1. Optionally `where`. Without it, every row is deleted.
27/// 2. Optionally [`returning`](Self::returning).
28///
29/// The WHERE condition and the RETURNING columns may only reference the
30/// table being deleted from; other tables do not compile.
31///
32/// # Examples
33///
34/// ```rust
35/// # mod drizzle {
36/// # pub mod core { pub use drizzle_core::*; }
37/// # pub mod error { pub use drizzle_core::error::*; }
38/// # pub mod types { pub use drizzle_types::*; }
39/// # pub mod migrations { pub use drizzle_migrations::*; }
40/// # pub use drizzle_types::Dialect;
41/// # pub use drizzle_types as ddl;
42/// # pub mod sqlite {
43/// # pub use drizzle_sqlite::{*, attrs::*};
44/// # #[cfg(feature = "rusqlite")]
45/// # pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
46/// # #[cfg(feature = "libsql")]
47/// # pub mod libsql { pub use ::libsql::{Row, Value}; }
48/// # #[cfg(feature = "turso")]
49/// # pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
50/// # pub mod prelude {
51/// # pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
52/// # pub use drizzle_sqlite::{*, attrs::*};
53/// # pub use drizzle_core::*;
54/// # }
55/// # }
56/// # }
57/// use drizzle::sqlite::prelude::*;
58/// use drizzle::core::expr::{eq, lt};
59/// use drizzle::sqlite::builder::QueryBuilder;
60///
61/// #[SQLiteTable(name = "users")]
62/// struct User {
63/// #[column(primary)]
64/// id: i32,
65/// name: String,
66/// email: Option<String>,
67/// }
68///
69/// #[derive(SQLiteSchema)]
70/// struct Schema {
71/// user: User,
72/// }
73///
74/// let builder = QueryBuilder::new::<Schema>();
75/// let Schema { user } = Schema::new();
76///
77/// // Delete specific row
78/// let query = builder
79/// .delete(user)
80/// .r#where(eq(user.id, 1));
81/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
82///
83/// // Delete multiple rows
84/// let query = builder
85/// .delete(user)
86/// .r#where(lt(user.id, 100));
87/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" < ?"#);
88/// ```
89///
90/// With RETURNING:
91///
92/// ```rust
93/// # mod drizzle {
94/// # pub mod core { pub use drizzle_core::*; }
95/// # pub mod error { pub use drizzle_core::error::*; }
96/// # pub mod types { pub use drizzle_types::*; }
97/// # pub mod migrations { pub use drizzle_migrations::*; }
98/// # pub use drizzle_types::Dialect;
99/// # pub use drizzle_types as ddl;
100/// # pub mod sqlite {
101/// # pub use drizzle_sqlite::{*, attrs::*};
102/// # #[cfg(feature = "rusqlite")]
103/// # pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
104/// # #[cfg(feature = "libsql")]
105/// # pub mod libsql { pub use ::libsql::{Row, Value}; }
106/// # #[cfg(feature = "turso")]
107/// # pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
108/// # pub mod prelude {
109/// # pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
110/// # pub use drizzle_sqlite::{*, attrs::*};
111/// # pub use drizzle_core::*;
112/// # }
113/// # }
114/// # }
115/// # use drizzle::sqlite::prelude::*;
116/// # use drizzle::core::expr::eq;
117/// # use drizzle::sqlite::builder::QueryBuilder;
118/// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String }
119/// # #[derive(SQLiteSchema)] struct Schema { user: User }
120/// # let builder = QueryBuilder::new::<Schema>();
121/// # let Schema { user } = Schema::new();
122/// let query = builder
123/// .delete(user)
124/// .r#where(eq(user.id, 1))
125/// .returning((user.id, user.name));
126/// assert_eq!(
127/// query.to_sql().sql(),
128/// r#"DELETE FROM "users" WHERE "users"."id" = ? RETURNING "users"."id", "users"."name""#
129/// );
130/// ```
131///
132/// Without WHERE, every row is deleted:
133///
134/// ```rust
135/// # mod drizzle {
136/// # pub mod core { pub use drizzle_core::*; }
137/// # pub mod error { pub use drizzle_core::error::*; }
138/// # pub mod types { pub use drizzle_types::*; }
139/// # pub mod migrations { pub use drizzle_migrations::*; }
140/// # pub use drizzle_types::Dialect;
141/// # pub use drizzle_types as ddl;
142/// # pub mod sqlite {
143/// # pub use drizzle_sqlite::{*, attrs::*};
144/// # #[cfg(feature = "rusqlite")]
145/// # pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
146/// # #[cfg(feature = "libsql")]
147/// # pub mod libsql { pub use ::libsql::{Row, Value}; }
148/// # #[cfg(feature = "turso")]
149/// # pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
150/// # pub mod prelude {
151/// # pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
152/// # pub use drizzle_sqlite::{*, attrs::*};
153/// # pub use drizzle_core::*;
154/// # }
155/// # }
156/// # }
157/// # use drizzle::sqlite::prelude::*;
158/// # use drizzle::sqlite::builder::QueryBuilder;
159/// # #[SQLiteTable(name = "logs")] struct Log { #[column(primary)] id: i32, message: String }
160/// # #[derive(SQLiteSchema)] struct Schema { log: Log }
161/// # let builder = QueryBuilder::new::<Schema>();
162/// # let Schema { log } = Schema::new();
163/// let query = builder.delete(log);
164/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "logs""#);
165/// ```
166pub type DeleteBuilder<'a, Schema, State, Table, Marker = (), Row = ()> =
167 super::QueryBuilder<'a, Schema, State, Table, Marker, Row>;
168
169type ReturningMarker<Table, Columns> = drizzle_core::Scoped<
170 <Columns as drizzle_core::IntoSelectTarget>::Marker,
171 drizzle_core::Cons<Table, drizzle_core::Nil>,
172>;
173
174type ReturningRow<Table, Columns> =
175 <<Columns as drizzle_core::IntoSelectTarget>::Marker as drizzle_core::ResolveRow<Table>>::Row;
176
177type ReturningBuilder<'a, S, T, Columns> = DeleteBuilder<
178 'a,
179 S,
180 DeleteReturningSet,
181 T,
182 ReturningMarker<T, Columns>,
183 ReturningRow<T, Columns>,
184>;
185
186//------------------------------------------------------------------------------
187// Initial State Implementation
188//------------------------------------------------------------------------------
189
190impl<'a, S, T> DeleteBuilder<'a, S, DeleteInitial, T> {
191 /// Adds a WHERE clause that picks the rows to delete.
192 ///
193 /// Without it, every row in the table is deleted. The condition must be a
194 /// boolean expression over the target table's columns.
195 ///
196 /// # Examples
197 ///
198 /// ```rust
199 /// # mod drizzle {
200 /// # pub mod core { pub use drizzle_core::*; }
201 /// # pub mod error { pub use drizzle_core::error::*; }
202 /// # pub mod types { pub use drizzle_types::*; }
203 /// # pub mod migrations { pub use drizzle_migrations::*; }
204 /// # pub use drizzle_types::Dialect;
205 /// # pub use drizzle_types as ddl;
206 /// # pub mod sqlite {
207 /// # pub use drizzle_sqlite::*;
208 /// # #[cfg(feature = "rusqlite")]
209 /// # pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
210 /// # #[cfg(feature = "libsql")]
211 /// # pub mod libsql { pub use ::libsql::{Row, Value}; }
212 /// # #[cfg(feature = "turso")]
213 /// # pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
214 /// # pub mod prelude {
215 /// # pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
216 /// # pub use drizzle_sqlite::{*, attrs::*};
217 /// # pub use drizzle_core::*;
218 /// # }
219 /// # }
220 /// # }
221 /// # use drizzle::sqlite::prelude::*;
222 /// # use drizzle::core::expr::{eq, gt, and, or};
223 /// # use drizzle::sqlite::builder::QueryBuilder;
224 /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String, age: Option<i32> }
225 /// # #[derive(SQLiteSchema)] struct Schema { user: User }
226 /// # let builder = QueryBuilder::new::<Schema>();
227 /// # let Schema { user } = Schema::new();
228 /// // Delete specific row by ID
229 /// let query = builder
230 /// .delete(user)
231 /// .r#where(eq(user.id, 1));
232 /// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
233 ///
234 /// // Delete with complex conditions
235 /// let query = builder
236 /// .delete(user)
237 /// .r#where(and(
238 /// gt(user.id, 100),
239 /// or(eq(user.name, "test"), eq(user.age, 0))
240 /// ));
241 /// assert_eq!(
242 /// query.to_sql().sql(),
243 /// r#"DELETE FROM "users" WHERE ("users"."id" > ? AND ("users"."name" = ? OR "users"."age" = ?))"#
244 /// );
245 /// ```
246 #[inline]
247 pub fn r#where<E, ScopeProof>(self, condition: E) -> DeleteBuilder<'a, S, DeleteWhereSet, T>
248 where
249 E: drizzle_core::expr::ExprSources,
250 E::Sources:
251 drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
252 E: drizzle_core::expr::Expr<'a, SQLiteValue<'a>>,
253 E::SQLType: drizzle_core::types::BooleanLike,
254 {
255 let where_sql = crate::helpers::r#where(condition);
256 DeleteBuilder {
257 sql: self.sql.append(where_sql),
258 schema: PhantomData,
259 state: PhantomData,
260 table: PhantomData,
261 marker: PhantomData,
262 row: PhantomData,
263 grouped: PhantomData,
264 }
265 }
266
267 /// Adds a RETURNING clause that reads columns of the deleted rows.
268 ///
269 /// Pass one column or expression, a tuple, or `()` for every column.
270 /// Only columns of the target table may be used.
271 #[inline]
272 pub fn returning<Columns, ScopeProof>(
273 self,
274 columns: Columns,
275 ) -> ReturningBuilder<'a, S, T, Columns>
276 where
277 Columns: drizzle_core::expr::ExprSources,
278 Columns::Sources:
279 drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
280 Columns: ToSQL<'a, SQLiteValue<'a>> + drizzle_core::IntoSelectTarget,
281 Columns::Marker: drizzle_core::ResolveRow<T>,
282 {
283 let returning_sql = crate::helpers::returning(columns);
284 DeleteBuilder {
285 sql: self.sql.append(returning_sql),
286 schema: PhantomData,
287 state: PhantomData,
288 table: PhantomData,
289 marker: PhantomData,
290 row: PhantomData,
291 grouped: PhantomData,
292 }
293 }
294}
295
296//------------------------------------------------------------------------------
297// Post-WHERE Implementation
298//------------------------------------------------------------------------------
299
300impl<'a, S, T> DeleteBuilder<'a, S, DeleteWhereSet, T> {
301 /// Adds a RETURNING clause after WHERE. See
302 /// [`returning`](DeleteBuilder::returning).
303 #[inline]
304 pub fn returning<Columns, ScopeProof>(
305 self,
306 columns: Columns,
307 ) -> ReturningBuilder<'a, S, T, Columns>
308 where
309 Columns: drizzle_core::expr::ExprSources,
310 Columns::Sources:
311 drizzle_core::scope::SourcesIn<drizzle_core::Cons<T, drizzle_core::Nil>, ScopeProof>,
312 Columns: ToSQL<'a, SQLiteValue<'a>> + drizzle_core::IntoSelectTarget,
313 Columns::Marker: drizzle_core::ResolveRow<T>,
314 {
315 let returning_sql = crate::helpers::returning(columns);
316 DeleteBuilder {
317 sql: self.sql.append(returning_sql),
318 schema: PhantomData,
319 state: PhantomData,
320 table: PhantomData,
321 marker: PhantomData,
322 row: PhantomData,
323 grouped: PhantomData,
324 }
325 }
326}