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}