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