drizzle_sqlite/builder/delete.rs
1use crate::values::SQLiteValue;
2use drizzle_core::{SQL, 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/// use drizzle_sqlite::builder::QueryBuilder;
55/// use drizzle_macros::{SQLiteTable, SQLiteSchema};
56/// use drizzle_core::{ToSQL, expressions::conditions::{eq, lt}};
57///
58/// #[SQLiteTable(name = "users")]
59/// struct User {
60/// #[integer(primary)]
61/// id: i32,
62/// #[text]
63/// name: String,
64/// #[text]
65/// email: Option<String>,
66/// }
67///
68/// #[derive(SQLiteSchema)]
69/// struct Schema {
70/// user: User,
71/// }
72///
73/// let builder = QueryBuilder::new::<Schema>();
74/// let Schema { user } = Schema::new();
75///
76/// // Delete specific row
77/// let query = builder
78/// .delete(user)
79/// .r#where(eq(user.id, 1));
80/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
81///
82/// // Delete multiple rows
83/// let query = builder
84/// .delete(user)
85/// .r#where(lt(user.id, 100));
86/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" < ?"#);
87/// ```
88///
89/// ## Advanced Deletions
90///
91/// ### DELETE with RETURNING
92/// ```rust
93/// # use drizzle_sqlite::builder::QueryBuilder;
94/// # use drizzle_macros::{SQLiteTable, SQLiteSchema};
95/// # use drizzle_core::{ToSQL, expressions::conditions::eq};
96/// # #[SQLiteTable(name = "users")] struct User { #[integer(primary)] id: i32, #[text] name: String }
97/// # #[derive(SQLiteSchema)] struct Schema { user: User }
98/// # let builder = QueryBuilder::new::<Schema>();
99/// # let Schema { user } = Schema::new();
100/// let query = builder
101/// .delete(user)
102/// .r#where(eq(user.id, 1))
103/// .returning((user.id, user.name));
104/// assert_eq!(
105/// query.to_sql().sql(),
106/// r#"DELETE FROM "users" WHERE "users"."id" = ? RETURNING "users"."id", "users"."name""#
107/// );
108/// ```
109///
110/// ### DELETE all rows (use with caution!)
111/// ```rust
112/// # use drizzle_sqlite::builder::QueryBuilder;
113/// # use drizzle_macros::{SQLiteTable, SQLiteSchema};
114/// # use drizzle_core::ToSQL;
115/// # #[SQLiteTable(name = "logs")] struct Log { #[integer(primary)] id: i32, #[text] message: String }
116/// # #[derive(SQLiteSchema)] struct Schema { log: Log }
117/// # let builder = QueryBuilder::new::<Schema>();
118/// # let Schema { log } = Schema::new();
119/// // This deletes ALL rows - be careful!
120/// let query = builder.delete(log);
121/// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "logs""#);
122/// ```
123pub type DeleteBuilder<'a, Schema, State, Table> = super::QueryBuilder<'a, Schema, State, Table>;
124
125//------------------------------------------------------------------------------
126// Initial State Implementation
127//------------------------------------------------------------------------------
128
129impl<'a, S, T> DeleteBuilder<'a, S, DeleteInitial, T> {
130 /// Adds a WHERE clause to specify which rows to delete.
131 ///
132 /// **Warning**: Without a WHERE clause, ALL rows in the table will be deleted!
133 /// Always use this method unless you specifically intend to truncate the entire table.
134 ///
135 /// # Examples
136 ///
137 /// ```rust
138 /// # use drizzle_sqlite::builder::QueryBuilder;
139 /// # use drizzle_macros::{SQLiteTable, SQLiteSchema};
140 /// # use drizzle_core::{ToSQL, expressions::conditions::{eq, gt, and, or}};
141 /// # #[SQLiteTable(name = "users")] struct User { #[integer(primary)] id: i32, #[text] name: String, #[integer] age: Option<i32> }
142 /// # #[derive(SQLiteSchema)] struct Schema { user: User }
143 /// # let builder = QueryBuilder::new::<Schema>();
144 /// # let Schema { user } = Schema::new();
145 /// // Delete specific row by ID
146 /// let query = builder
147 /// .delete(user)
148 /// .r#where(eq(user.id, 1));
149 /// assert_eq!(query.to_sql().sql(), r#"DELETE FROM "users" WHERE "users"."id" = ?"#);
150 ///
151 /// // Delete with complex conditions
152 /// let query = builder
153 /// .delete(user)
154 /// .r#where(and([
155 /// gt(user.id, 100),
156 /// or([eq(user.name, "test"), eq(user.age, 0)])
157 /// ]));
158 /// ```
159 #[inline]
160 pub fn r#where(
161 self,
162 condition: SQL<'a, SQLiteValue<'a>>,
163 ) -> DeleteBuilder<'a, S, DeleteWhereSet, T> {
164 let where_sql = crate::helpers::r#where(condition);
165 DeleteBuilder {
166 sql: self.sql.append(where_sql),
167 schema: PhantomData,
168 state: PhantomData,
169 table: PhantomData,
170 }
171 }
172
173 /// Adds a RETURNING clause to the query
174 #[inline]
175 pub fn returning(
176 self,
177 columns: impl ToSQL<'a, SQLiteValue<'a>>,
178 ) -> DeleteBuilder<'a, S, DeleteReturningSet, T> {
179 let returning_sql = crate::helpers::returning(columns);
180 DeleteBuilder {
181 sql: self.sql.append(returning_sql),
182 schema: PhantomData,
183 state: PhantomData,
184 table: PhantomData,
185 }
186 }
187}
188
189//------------------------------------------------------------------------------
190// Post-WHERE Implementation
191//------------------------------------------------------------------------------
192
193impl<'a, S, T> DeleteBuilder<'a, S, DeleteWhereSet, T> {
194 /// Adds a RETURNING clause after WHERE
195 #[inline]
196 pub fn returning(
197 self,
198 columns: impl ToSQL<'a, SQLiteValue<'a>>,
199 ) -> DeleteBuilder<'a, S, DeleteReturningSet, T> {
200 let returning_sql = crate::helpers::returning(columns);
201 DeleteBuilder {
202 sql: self.sql.append(returning_sql),
203 schema: PhantomData,
204 state: PhantomData,
205 table: PhantomData,
206 }
207 }
208}