drizzle_sqlite/builder/
delete.rs

1use crate::values::SQLiteValue;
2use drizzle_core::ToSQL;
3use std::fmt::Debug;
4use std::marker::PhantomData;
5
6// Import the ExecutableState trait
7use super::ExecutableState;
8
9//------------------------------------------------------------------------------
10// Type State Markers
11//------------------------------------------------------------------------------
12
13/// Marker for the initial state of DeleteBuilder
14#[derive(Debug, Clone, Copy, Default)]
15pub struct DeleteInitial;
16
17/// Marker for the state after WHERE clause
18#[derive(Debug, Clone, Copy, Default)]
19pub struct DeleteWhereSet;
20
21/// Marker for the state after RETURNING clause
22#[derive(Debug, Clone, Copy, Default)]
23pub struct DeleteReturningSet;
24
25// Mark states that can execute delete queries
26impl ExecutableState for DeleteInitial {}
27impl ExecutableState for DeleteWhereSet {}
28impl ExecutableState for DeleteReturningSet {}
29
30//------------------------------------------------------------------------------
31// DeleteBuilder Definition
32//------------------------------------------------------------------------------
33
34/// Builds a DELETE query specifically for SQLite.
35///
36/// `DeleteBuilder` provides a type-safe, fluent API for constructing DELETE statements
37/// with support for conditional deletions and returning clauses.
38///
39/// ## Type Parameters
40///
41/// - `Schema`: The database schema type, ensuring only valid tables can be referenced
42/// - `State`: The current builder state, enforcing proper query construction order
43/// - `Table`: The table being deleted from
44///
45/// ## Query Building Flow
46///
47/// 1. Start with `QueryBuilder::delete(table)` to specify the target table
48/// 2. Optionally add `where()` to specify which rows to delete
49/// 3. Optionally add `returning()` to get deleted values back
50///
51/// ## Basic Usage
52///
53/// ```rust
54/// # mod drizzle {
55/// #     pub mod core { pub use drizzle_core::*; }
56/// #     pub mod error { pub use drizzle_core::error::*; }
57/// #     pub mod types { pub use drizzle_types::*; }
58/// #     pub mod migrations { pub use drizzle_migrations::*; }
59/// #     pub use drizzle_types::Dialect;
60/// #     pub use drizzle_types as ddl;
61/// #     pub mod sqlite {
62/// #             pub use drizzle_sqlite::{*, attrs::*};
63/// #         pub mod prelude {
64/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
65/// #             pub use drizzle_sqlite::{*, attrs::*};
66/// #             pub use drizzle_core::*;
67/// #         }
68/// #     }
69/// # }
70/// use drizzle::sqlite::prelude::*;
71/// use drizzle::core::expr::{eq, lt};
72/// use drizzle::sqlite::builder::QueryBuilder;
73///
74/// #[SQLiteTable(name = "users")]
75/// struct User {
76///     #[column(primary)]
77///     id: i32,
78///     name: String,
79///     email: Option<String>,
80/// }
81///
82/// #[derive(SQLiteSchema)]
83/// struct Schema {
84///     user: User,
85/// }
86///
87/// let builder = QueryBuilder::new::<Schema>();
88/// let Schema { user } = Schema::new();
89///
90/// // Delete specific row
91/// let query = builder
92///     .delete(user)
93///     .r#where(eq(user.id, 1));
94/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
95///
96/// // Delete multiple rows
97/// let query = builder
98///     .delete(user)
99///     .r#where(lt(user.id, 100));
100/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" < ?"#);
101/// ```
102///
103/// ## Advanced Deletions
104///
105/// ### DELETE with RETURNING
106/// ```rust
107/// # mod drizzle {
108/// #     pub mod core { pub use drizzle_core::*; }
109/// #     pub mod error { pub use drizzle_core::error::*; }
110/// #     pub mod types { pub use drizzle_types::*; }
111/// #     pub mod migrations { pub use drizzle_migrations::*; }
112/// #     pub use drizzle_types::Dialect;
113/// #     pub use drizzle_types as ddl;
114/// #     pub mod sqlite {
115/// #             pub use drizzle_sqlite::{*, attrs::*};
116/// #         pub mod prelude {
117/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
118/// #             pub use drizzle_sqlite::{*, attrs::*};
119/// #             pub use drizzle_core::*;
120/// #         }
121/// #     }
122/// # }
123/// # use drizzle::sqlite::prelude::*;
124/// # use drizzle::core::expr::eq;
125/// # use drizzle::sqlite::builder::QueryBuilder;
126/// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String }
127/// # #[derive(SQLiteSchema)] struct Schema { user: User }
128/// # let builder = QueryBuilder::new::<Schema>();
129/// # let Schema { user } = Schema::new();
130/// let query = builder
131///     .delete(user)
132///     .r#where(eq(user.id, 1))
133///     .returning((user.id, user.name));
134/// assert_eq!(
135///     query.to_sql().sql(),
136///     r#"DELETE FROM "users" WHERE "users"."id" = ? RETURNING "users"."id", "users"."name""#
137/// );
138/// ```
139///
140/// ### DELETE all rows (use with caution!)
141/// ```rust
142/// # mod drizzle {
143/// #     pub mod core { pub use drizzle_core::*; }
144/// #     pub mod error { pub use drizzle_core::error::*; }
145/// #     pub mod types { pub use drizzle_types::*; }
146/// #     pub mod migrations { pub use drizzle_migrations::*; }
147/// #     pub use drizzle_types::Dialect;
148/// #     pub use drizzle_types as ddl;
149/// #     pub mod sqlite {
150/// #             pub use drizzle_sqlite::{*, attrs::*};
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/// // This deletes ALL rows - be careful!
165/// let query = builder.delete(log);
166/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "logs""#);
167/// ```
168pub type DeleteBuilder<'a, Schema, State, Table> = super::QueryBuilder<'a, Schema, State, Table>;
169
170//------------------------------------------------------------------------------
171// Initial State Implementation
172//------------------------------------------------------------------------------
173
174impl<'a, S, T> DeleteBuilder<'a, S, DeleteInitial, T> {
175    /// Adds a WHERE clause to specify which rows to delete.
176    ///
177    /// **Warning**: Without a WHERE clause, ALL rows in the table will be deleted!
178    /// Always use this method unless you specifically intend to truncate the entire table.
179    ///
180    /// # Examples
181    ///
182    /// ```rust
183    /// # mod drizzle {
184    /// #     pub mod core { pub use drizzle_core::*; }
185    /// #     pub mod error { pub use drizzle_core::error::*; }
186    /// #     pub mod types { pub use drizzle_types::*; }
187    /// #     pub mod migrations { pub use drizzle_migrations::*; }
188    /// #     pub use drizzle_types::Dialect;
189    /// #     pub use drizzle_types as ddl;
190    /// #     pub mod sqlite {
191    /// #         pub use drizzle_sqlite::*;
192    /// #         pub mod prelude {
193    /// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
194    /// #             pub use drizzle_sqlite::{*, attrs::*};
195    /// #             pub use drizzle_core::*;
196    /// #         }
197    /// #     }
198    /// # }
199    /// # use drizzle::sqlite::prelude::*;
200    /// # use drizzle::core::expr::{eq, gt, and, or};
201    /// # use drizzle::sqlite::builder::QueryBuilder;
202    /// # #[SQLiteTable(name = "users")] struct User { #[column(primary)] id: i32, name: String, age: Option<i32> }
203    /// # #[derive(SQLiteSchema)] struct Schema { user: User }
204    /// # let builder = QueryBuilder::new::<Schema>();
205    /// # let Schema { user } = Schema::new();
206    /// // Delete specific row by ID
207    /// let query = builder
208    ///     .delete(user)
209    ///     .r#where(eq(user.id, 1));
210    /// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
211    ///
212    /// // Delete with complex conditions
213    /// let query = builder
214    ///     .delete(user)
215    ///     .r#where(and([
216    ///         gt(user.id, 100),
217    ///         or([eq(user.name, "test"), eq(user.age, 0)])
218    ///     ]));
219    /// ```
220    #[inline]
221    pub fn r#where(
222        self,
223        condition: impl ToSQL<'a, SQLiteValue<'a>>,
224    ) -> DeleteBuilder<'a, S, DeleteWhereSet, T> {
225        let where_sql = crate::helpers::r#where(condition);
226        DeleteBuilder {
227            sql: self.sql.append(where_sql),
228            schema: PhantomData,
229            state: PhantomData,
230            table: PhantomData,
231        }
232    }
233
234    /// Adds a RETURNING clause to the query
235    #[inline]
236    pub fn returning(
237        self,
238        columns: impl ToSQL<'a, SQLiteValue<'a>>,
239    ) -> DeleteBuilder<'a, S, DeleteReturningSet, T> {
240        let returning_sql = crate::helpers::returning(columns);
241        DeleteBuilder {
242            sql: self.sql.append(returning_sql),
243            schema: PhantomData,
244            state: PhantomData,
245            table: PhantomData,
246        }
247    }
248}
249
250//------------------------------------------------------------------------------
251// Post-WHERE Implementation
252//------------------------------------------------------------------------------
253
254impl<'a, S, T> DeleteBuilder<'a, S, DeleteWhereSet, T> {
255    /// Adds a RETURNING clause after WHERE
256    #[inline]
257    pub fn returning(
258        self,
259        columns: impl ToSQL<'a, SQLiteValue<'a>>,
260    ) -> DeleteBuilder<'a, S, DeleteReturningSet, T> {
261        let returning_sql = crate::helpers::returning(columns);
262        DeleteBuilder {
263            sql: self.sql.append(returning_sql),
264            schema: PhantomData,
265            state: PhantomData,
266            table: PhantomData,
267        }
268    }
269}