drizzle_sqlite/builder/prepared.rs
1use std::borrow::Cow;
2
3use drizzle_core::{
4 OwnedParam, Param,
5 prepared::{
6 OwnedPreparedStatement as CoreOwnedPreparedStatement,
7 PreparedStatement as CorePreparedStatement,
8 },
9};
10
11use crate::{SQLiteValue, values::OwnedSQLiteValue};
12
13/// SQLite-specific prepared statement wrapper.
14///
15/// A prepared statement represents a compiled SQL query with placeholder parameters
16/// that can be executed multiple times with different parameter values. This wrapper
17/// provides SQLite-specific functionality while maintaining compatibility with the
18/// core Drizzle prepared statement infrastructure.
19///
20/// ## Features
21///
22/// - **Parameter Binding**: Safely bind values to SQL placeholders
23/// - **Reusable Execution**: Execute the same query multiple times efficiently
24/// - **Memory Management**: Automatic handling of borrowed/owned lifetimes
25/// - **Type Safety**: Compile-time verification of parameter types
26///
27/// ## Basic Usage
28///
29/// ```rust,ignore
30/// use drizzle_sqlite::builder::QueryBuilder;
31/// use drizzle_macros::{SQLiteTable, SQLiteSchema};
32/// use drizzle_core::{ToSQL, expressions::eq};
33///
34/// #[SQLiteTable(name = "users")]
35/// struct User {
36/// #[integer(primary)]
37/// id: i32,
38/// #[text]
39/// name: String,
40/// }
41///
42/// #[derive(SQLiteSchema)]
43/// struct Schema {
44/// user: User,
45/// }
46///
47/// let builder = QueryBuilder::new::<Schema>();
48/// let Schema { user } = Schema::new();
49///
50/// // Build query that will become a prepared statement
51/// let query = builder
52/// .select(user.name)
53/// .from(user)
54/// .r#where(eq(user.id, drizzle_core::Placeholder::question()));
55///
56/// // Convert to prepared statement (this would typically be done by the driver)
57/// let sql = query.to_sql();
58/// println!("SQL: {}", sql.sql()); // "SELECT "users"."name" FROM "users" WHERE "users"."id" = ?"
59/// ```
60///
61/// ## Lifetime Management
62///
63/// The prepared statement can be converted between borrowed and owned forms:
64///
65/// - `PreparedStatement<'a>` - Borrows data with lifetime 'a
66/// - `OwnedPreparedStatement` - Owns all data, no lifetime constraints
67///
68/// This allows for flexible usage patterns depending on whether you need to
69/// store the prepared statement long-term or use it immediately.
70#[derive(Debug, Clone)]
71pub struct PreparedStatement<'a> {
72 pub inner: CorePreparedStatement<'a, crate::SQLiteValue<'a>>,
73}
74
75impl<'a> PreparedStatement<'a> {
76 /// Converts this borrowed prepared statement into an owned one.
77 ///
78 /// This method clones all the internal data to create an `OwnedPreparedStatement`
79 /// that doesn't have any lifetime constraints. This is useful when you need to
80 /// store the prepared statement beyond the lifetime of the original query builder.
81 ///
82 /// # Examples
83 ///
84 /// ```rust,ignore
85 /// # use drizzle_sqlite::builder::PreparedStatement;
86 /// # let prepared_statement: PreparedStatement = todo!(); // Would come from driver
87 /// // Convert borrowed to owned for long-term storage
88 /// let owned = prepared_statement.into_owned();
89 ///
90 /// // Now `owned` can be stored without lifetime constraints
91 /// ```
92 pub fn into_owned(&self) -> OwnedPreparedStatement {
93 let owned_params = self.inner.params.iter().map(|p| OwnedParam {
94 placeholder: p.placeholder,
95 value: p
96 .value
97 .clone()
98 .map(|v| OwnedSQLiteValue::from(v.into_owned())),
99 });
100
101 let inner = CoreOwnedPreparedStatement {
102 text_segments: self.inner.text_segments.clone(),
103 params: owned_params.collect::<Box<[_]>>(),
104 sql: self.inner.sql.clone(),
105 };
106
107 OwnedPreparedStatement { inner }
108 }
109}
110
111/// Owned SQLite prepared statement wrapper.
112///
113/// This is the owned counterpart to [`PreparedStatement`] that doesn't have any lifetime
114/// constraints. All data is owned by this struct, making it suitable for long-term storage,
115/// caching, or passing across thread boundaries.
116///
117/// ## Use Cases
118///
119/// - **Caching**: Store prepared statements in a cache for reuse
120/// - **Multi-threading**: Pass prepared statements between threads
121/// - **Long-term storage**: Keep prepared statements in application state
122/// - **Serialization**: Convert to/from persistent storage (when serialization is implemented)
123///
124/// ## Examples
125///
126/// ```rust,ignore
127/// use drizzle_sqlite::builder::{QueryBuilder, PreparedStatement, OwnedPreparedStatement};
128/// use drizzle_macros::{SQLiteTable, SQLiteSchema};
129/// use drizzle_core::ToSQL;
130///
131/// #[SQLiteTable(name = "users")]
132/// struct User {
133/// #[integer(primary)]
134/// id: i32,
135/// #[text]
136/// name: String,
137/// }
138///
139/// #[derive(SQLiteSchema)]
140/// struct Schema {
141/// user: User,
142/// }
143///
144/// let builder = QueryBuilder::new::<Schema>();
145/// let Schema { user } = Schema::new();
146///
147/// // Create a prepared statement and convert to owned
148/// let query = builder.select(user.name).from(user);
149/// let sql = query.to_sql();
150///
151/// // In practice, this conversion would be handled by the database driver
152/// // let prepared: PreparedStatement = driver.prepare(sql)?;
153/// // let owned: OwnedPreparedStatement = prepared.into_owned();
154/// ```
155///
156/// ## Conversion
157///
158/// You can convert between borrowed and owned forms:
159/// - `PreparedStatement::into_owned()` → `OwnedPreparedStatement`
160/// - `OwnedPreparedStatement` → `PreparedStatement` (via `From` trait)
161#[derive(Debug, Clone)]
162pub struct OwnedPreparedStatement {
163 pub inner: CoreOwnedPreparedStatement<crate::values::OwnedSQLiteValue>,
164}
165impl<'a> From<PreparedStatement<'a>> for OwnedPreparedStatement {
166 fn from(value: PreparedStatement<'a>) -> Self {
167 let owned_params = value.inner.params.iter().map(|p| OwnedParam {
168 placeholder: p.placeholder,
169 value: p
170 .value
171 .clone()
172 .map(|v| OwnedSQLiteValue::from(v.into_owned())),
173 });
174 let inner = CoreOwnedPreparedStatement {
175 text_segments: value.inner.text_segments,
176 params: owned_params.collect::<Box<[_]>>(),
177 sql: value.inner.sql,
178 };
179 Self { inner }
180 }
181}
182
183impl From<OwnedPreparedStatement> for PreparedStatement<'_> {
184 fn from(value: OwnedPreparedStatement) -> Self {
185 let sqlitevalue = value.inner.params.iter().map(|v| {
186 Param::new(
187 v.placeholder,
188 v.value.clone().map(|v| Cow::Owned(SQLiteValue::from(v))),
189 )
190 });
191 let inner = CorePreparedStatement {
192 text_segments: value.inner.text_segments,
193 params: sqlitevalue.collect::<Box<[_]>>(),
194 sql: value.inner.sql,
195 };
196 PreparedStatement { inner }
197 }
198}
199
200impl OwnedPreparedStatement {}
201
202impl<'a> std::fmt::Display for PreparedStatement<'a> {
203 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
204 write!(f, "{}", self.inner)
205 }
206}
207
208impl std::fmt::Display for OwnedPreparedStatement {
209 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
210 write!(f, "{}", self.inner)
211 }
212}
213
214#[cfg(test)]
215mod tests {
216 use super::*;
217 use crate::SQLiteValue;
218 use drizzle_core::{SQL, prepared::prepare_render};
219
220 #[test]
221 fn test_prepare_render_basic() {
222 // Test the basic prepare_render functionality for SQLite
223 let sql: SQL<'_, SQLiteValue<'_>> = SQL::raw("SELECT * FROM users WHERE id = ")
224 .append(SQL::placeholder("user_id"))
225 .append(SQL::raw(" AND name = "))
226 .append(SQL::placeholder("user_name"));
227
228 let prepared = prepare_render(sql);
229
230 // Should have 3 text segments: before first param, between params, after last param
231 assert_eq!(prepared.text_segments.len(), 3);
232 assert_eq!(prepared.params.len(), 2);
233
234 // Verify text segments contain expected content
235 assert!(prepared.text_segments[0].contains("SELECT * FROM users WHERE id"));
236 assert!(prepared.text_segments[1].contains("AND name"));
237 }
238
239 #[test]
240 fn test_prepare_with_no_parameters() {
241 // Test preparing SQL with no parameters
242 let sql: SQL<'_, SQLiteValue<'_>> = SQL::raw("SELECT COUNT(*) FROM users");
243 let prepared = prepare_render(sql);
244
245 assert_eq!(prepared.text_segments.len(), 1);
246 assert_eq!(prepared.params.len(), 0);
247 assert_eq!(prepared.text_segments[0], "SELECT COUNT(*) FROM users");
248 }
249
250 #[test]
251 fn test_prepared_statement_display() {
252 let sql: SQL<'_, SQLiteValue<'_>> = SQL::raw("SELECT * FROM users")
253 .append(SQL::raw(" WHERE id = "))
254 .append(SQL::placeholder("id"));
255
256 let prepared = prepare_render(sql);
257 let display = format!("{}", prepared);
258
259 assert!(display.contains("SELECT * FROM users"));
260 assert!(display.contains("WHERE id"));
261 }
262
263 #[test]
264 fn test_owned_conversion_roundtrip() {
265 let sql: SQL<'_, SQLiteValue<'_>> =
266 SQL::raw("SELECT name FROM users WHERE id = ").append(SQL::placeholder("id"));
267
268 let prepared = prepare_render(sql);
269 let core_prepared = PreparedStatement { inner: prepared };
270
271 // Convert to owned
272 let owned = core_prepared.into_owned();
273
274 // Convert back to borrowed
275 let borrowed: PreparedStatement<'_> = owned.into();
276
277 // Verify structure is preserved
278 assert_eq!(borrowed.inner.text_segments.len(), 2);
279 assert_eq!(borrowed.inner.params.len(), 1);
280 }
281}