Skip to main content

drizzle_sqlite/builder/
delete.rs

1use crate::values::SQLiteValue;
2use core::marker::PhantomData;
3use drizzle_core::ToSQL;
4
5//------------------------------------------------------------------------------
6// Type State Markers
7//------------------------------------------------------------------------------
8
9pub use drizzle_core::builder::{DeleteInitial, DeleteReturningSet, DeleteWhereSet};
10
11//------------------------------------------------------------------------------
12// DeleteBuilder Definition
13//------------------------------------------------------------------------------
14
15/// Builds a DELETE query specifically for `SQLite`.
16///
17/// `DeleteBuilder` provides a type-safe, fluent API for constructing DELETE statements
18/// with support for conditional deletions and returning clauses.
19///
20/// ## Type Parameters
21///
22/// - `Schema`: The database schema type, ensuring only valid tables can be referenced
23/// - `State`: The current builder state, enforcing proper query construction order
24/// - `Table`: The table being deleted from
25///
26/// ## Query Building Flow
27///
28/// 1. Start with `QueryBuilder::delete(table)` to specify the target table
29/// 2. Optionally add `where()` to specify which rows to delete
30/// 3. Optionally add `returning()` to get deleted values back
31///
32/// ## Basic Usage
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/// ## Advanced Deletions
91///
92/// ### DELETE with RETURNING
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/// ### DELETE all rows (use with caution!)
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/// // This deletes ALL rows - be careful!
164/// let query = builder.delete(log);
165/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "logs""#);
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 to specify which rows to delete.
193    ///
194    /// **Warning**: Without a WHERE clause, ALL rows in the table will be deleted!
195    /// Always use this method unless you specifically intend to truncate the entire table.
196    ///
197    /// # Examples
198    ///
199    /// ```rust
200    /// # mod drizzle {
201    /// #     pub mod core { pub use drizzle_core::*; }
202    /// #     pub mod error { pub use drizzle_core::error::*; }
203    /// #     pub mod types { pub use drizzle_types::*; }
204    /// #     pub mod migrations { pub use drizzle_migrations::*; }
205    /// #     pub use drizzle_types::Dialect;
206    /// #     pub use drizzle_types as ddl;
207    /// #     pub mod sqlite {
208    /// #         pub use drizzle_sqlite::*;
209    /// #         #[cfg(feature = "rusqlite")]
210    /// #         pub mod rusqlite { pub use ::rusqlite::{Error, Result, Row, types}; }
211    /// #         #[cfg(feature = "libsql")]
212    /// #         pub mod libsql { pub use ::libsql::{Row, Value}; }
213    /// #         #[cfg(feature = "turso")]
214    /// #         pub mod turso { pub use ::turso::{Error, IntoValue, Result, Row, Value}; }
215    /// #         pub mod prelude {
216    /// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
217    /// #             pub use drizzle_sqlite::{*, attrs::*};
218    /// #             pub use drizzle_core::*;
219    /// #         }
220    /// #     }
221    /// # }
222    /// # use drizzle::sqlite::prelude::*;
223    /// # use drizzle::core::expr::{eq, gt, and, or};
224    /// # use drizzle::sqlite::builder::QueryBuilder;
225    /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String, age: Option<i32> }
226    /// # #[derive(SQLiteSchema)] struct Schema { user: User }
227    /// # let builder = QueryBuilder::new::<Schema>();
228    /// # let Schema { user } = Schema::new();
229    /// // Delete specific row by ID
230    /// let query = builder
231    ///     .delete(user)
232    ///     .r#where(eq(user.id, 1));
233    /// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
234    ///
235    /// // Delete with complex conditions
236    /// let query = builder
237    ///     .delete(user)
238    ///     .r#where(and(
239    ///         gt(user.id, 100),
240    ///         or(eq(user.name, "test"), eq(user.age, 0))
241    ///     ));
242    /// ```
243    #[inline]
244    pub fn r#where<E>(self, condition: E) -> DeleteBuilder<'a, S, DeleteWhereSet, T>
245    where
246        E: drizzle_core::expr::Expr<'a, SQLiteValue<'a>>,
247        E::SQLType: drizzle_core::types::BooleanLike,
248    {
249        let where_sql = crate::helpers::r#where(condition);
250        DeleteBuilder {
251            sql: self.sql.append(where_sql),
252            schema: PhantomData,
253            state: PhantomData,
254            table: PhantomData,
255            marker: PhantomData,
256            row: PhantomData,
257            grouped: PhantomData,
258        }
259    }
260
261    /// Adds a RETURNING clause to the query
262    #[inline]
263    pub fn returning<Columns>(self, columns: Columns) -> ReturningBuilder<'a, S, T, Columns>
264    where
265        Columns: ToSQL<'a, SQLiteValue<'a>> + drizzle_core::IntoSelectTarget,
266        Columns::Marker: drizzle_core::ResolveRow<T>,
267    {
268        let returning_sql = crate::helpers::returning(columns);
269        DeleteBuilder {
270            sql: self.sql.append(returning_sql),
271            schema: PhantomData,
272            state: PhantomData,
273            table: PhantomData,
274            marker: PhantomData,
275            row: PhantomData,
276            grouped: PhantomData,
277        }
278    }
279}
280
281//------------------------------------------------------------------------------
282// Post-WHERE Implementation
283//------------------------------------------------------------------------------
284
285impl<'a, S, T> DeleteBuilder<'a, S, DeleteWhereSet, T> {
286    /// Adds a RETURNING clause after WHERE
287    #[inline]
288    pub fn returning<Columns>(self, columns: Columns) -> ReturningBuilder<'a, S, T, Columns>
289    where
290        Columns: ToSQL<'a, SQLiteValue<'a>> + drizzle_core::IntoSelectTarget,
291        Columns::Marker: drizzle_core::ResolveRow<T>,
292    {
293        let returning_sql = crate::helpers::returning(columns);
294        DeleteBuilder {
295            sql: self.sql.append(returning_sql),
296            schema: PhantomData,
297            state: PhantomData,
298            table: PhantomData,
299            marker: PhantomData,
300            row: PhantomData,
301            grouped: PhantomData,
302        }
303    }
304}