Skip to main content

drizzle_sqlite/builder/
prepared.rs

1use crate::prelude::*;
2
3use drizzle_core::{
4    OwnedParam, Param,
5    prepared::{
6        OwnedPreparedStatement as CoreOwnedPreparedStatement,
7        PreparedStatement as CorePreparedStatement,
8    },
9};
10
11use crate::values::{OwnedSQLiteValue, SQLiteValue};
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
30/// # mod drizzle {
31/// #     pub mod core { pub use drizzle_core::*; }
32/// #     pub mod error { pub use drizzle_core::error::*; }
33/// #     pub mod types { pub use drizzle_types::*; }
34/// #     pub mod migrations { pub use drizzle_migrations::*; }
35/// #     pub use drizzle_types::Dialect;
36/// #     pub use drizzle_types as ddl;
37/// #     pub mod sqlite {
38/// #         pub use drizzle_sqlite::*;
39/// #         pub mod prelude {
40/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
41/// #             pub use drizzle_sqlite::{*, attrs::*};
42/// #             pub use drizzle_core::*;
43/// #         }
44/// #     }
45/// # }
46/// # use drizzle::sqlite::prelude::*;
47/// # use drizzle::sqlite::builder::QueryBuilder;
48/// # use drizzle::core::expr::eq;
49/// #
50/// # #[SQLiteTable(name = "users")]
51/// # struct User {
52/// #     #[column(primary)]
53/// #     id: i32,
54/// #     name: String,
55/// # }
56/// #
57/// # #[derive(SQLiteSchema)]
58/// # struct Schema {
59/// #     user: User,
60/// # }
61/// #
62/// # let builder = QueryBuilder::new::<Schema>();
63/// # let Schema { user } = Schema::new();
64/// // Build query that will become a prepared statement
65/// let query = builder
66///     .select(user.name)
67///     .from(user)
68///     .r#where(eq(user.id, Placeholder::anonymous()));
69///
70/// // Convert to SQL
71/// let sql = query.to_sql();
72/// println!("SQL: {}", sql.sql());
73/// ```
74///
75/// ## Lifetime Management
76///
77/// The prepared statement can be converted between borrowed and owned forms:
78///
79/// - `PreparedStatement<'a>` - Borrows data with lifetime 'a
80/// - `OwnedPreparedStatement` - Owns all data, no lifetime constraints
81///
82/// This allows for flexible usage patterns depending on whether you need to
83/// store the prepared statement long-term or use it immediately.
84#[derive(Debug, Clone)]
85pub struct PreparedStatement<'a> {
86    pub(crate) inner: CorePreparedStatement<'a, SQLiteValue<'a>>,
87}
88
89impl PreparedStatement<'_> {
90    /// Converts this borrowed prepared statement into an owned one.
91    ///
92    /// This method clones all the internal data to create an `OwnedPreparedStatement`
93    /// that doesn't have any lifetime constraints. This is useful when you need to
94    /// store the prepared statement beyond the lifetime of the original query builder.
95    ///
96    /// # Examples
97    ///
98    /// ```rust
99    /// # mod drizzle {
100    /// #     pub mod core { pub use drizzle_core::*; }
101    /// #     pub mod error { pub use drizzle_core::error::*; }
102    /// #     pub mod types { pub use drizzle_types::*; }
103    /// #     pub mod migrations { pub use drizzle_migrations::*; }
104    /// #     pub use drizzle_types::Dialect;
105    /// #     pub use drizzle_types as ddl;
106    /// #     pub mod sqlite {
107    /// #         pub use drizzle_sqlite::*;
108    /// #         pub mod prelude {
109    /// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
110    /// #             pub use drizzle_sqlite::{*, attrs::*};
111    /// #             pub use drizzle_core::*;
112    /// #         }
113    /// #     }
114    /// # }
115    /// # fn example(prepared: drizzle::sqlite::builder::prepared::PreparedStatement<'_>) {
116    /// // Convert borrowed to owned for long-term storage
117    /// let owned = prepared.into_owned();
118    ///
119    /// // Now `owned` can be stored without lifetime constraints
120    /// # }
121    /// ```
122    #[must_use]
123    pub fn into_owned(&self) -> OwnedPreparedStatement {
124        let owned_params = self.inner.params.iter().map(|p| OwnedParam {
125            placeholder: p.placeholder,
126            value: p
127                .value
128                .clone()
129                .map(|v| OwnedSQLiteValue::from(v.into_owned())),
130        });
131
132        let inner = CoreOwnedPreparedStatement {
133            text_segments: self.inner.text_segments.clone(),
134            params: owned_params.collect::<Box<[_]>>(),
135            sql: self.inner.sql.clone(),
136        };
137
138        OwnedPreparedStatement { inner }
139    }
140}
141
142/// Owned `SQLite` prepared statement wrapper.
143///
144/// This is the owned counterpart to [`PreparedStatement`] that doesn't have any lifetime
145/// constraints. All data is owned by this struct, making it suitable for long-term storage,
146/// caching, or passing across thread boundaries.
147///
148/// ## Use Cases
149///
150/// - **Caching**: Store prepared statements in a cache for reuse
151/// - **Multi-threading**: Pass prepared statements between threads
152/// - **Long-term storage**: Keep prepared statements in application state
153/// - **Serialization**: Convert to/from persistent storage (when serialization is implemented)
154///
155/// ## Examples
156///
157/// ```rust
158/// # mod drizzle {
159/// #     pub mod core { pub use drizzle_core::*; }
160/// #     pub mod error { pub use drizzle_core::error::*; }
161/// #     pub mod types { pub use drizzle_types::*; }
162/// #     pub mod migrations { pub use drizzle_migrations::*; }
163/// #     pub use drizzle_types::Dialect;
164/// #     pub use drizzle_types as ddl;
165/// #     pub mod sqlite {
166/// #         pub use drizzle_sqlite::*;
167/// #         pub mod prelude {
168/// #             pub use drizzle_macros::{SQLiteTable, SQLiteSchema};
169/// #             pub use drizzle_sqlite::{*, attrs::*};
170/// #             pub use drizzle_core::*;
171/// #         }
172/// #     }
173/// # }
174/// use drizzle::sqlite::prelude::*;
175/// use drizzle::sqlite::builder::QueryBuilder;
176///
177/// #[SQLiteTable(name = "users")]
178/// struct User {
179///     #[column(primary)]
180///     id: i32,
181///     name: String,
182/// }
183///
184/// #[derive(SQLiteSchema)]
185/// struct Schema {
186///     user: User,
187/// }
188///
189/// let builder = QueryBuilder::new::<Schema>();
190/// let Schema { user } = Schema::new();
191///
192/// // Create a query and convert to SQL
193/// let query = builder.select(user.name).from(user);
194/// let sql = query.to_sql();
195///
196/// // In practice, the driver creates a PreparedStatement from the SQL
197/// // let prepared: PreparedStatement = driver.prepare(sql)?;
198/// // let owned: OwnedPreparedStatement = prepared.into_owned();
199/// ```
200///
201/// ## Conversion
202///
203/// You can convert between borrowed and owned forms:
204/// - `PreparedStatement::into_owned()` → `OwnedPreparedStatement`
205/// - `OwnedPreparedStatement` → `PreparedStatement` (via `From` trait)
206#[derive(Debug, Clone)]
207pub struct OwnedPreparedStatement {
208    pub(crate) inner: CoreOwnedPreparedStatement<crate::values::OwnedSQLiteValue>,
209}
210impl<'a> From<PreparedStatement<'a>> for OwnedPreparedStatement {
211    fn from(value: PreparedStatement<'a>) -> Self {
212        let owned_params = value.inner.params.iter().map(|p| OwnedParam {
213            placeholder: p.placeholder,
214            value: p
215                .value
216                .clone()
217                .map(|v| OwnedSQLiteValue::from(v.into_owned())),
218        });
219        let inner = CoreOwnedPreparedStatement {
220            text_segments: value.inner.text_segments,
221            params: owned_params.collect::<Box<[_]>>(),
222            sql: value.inner.sql,
223        };
224        Self { inner }
225    }
226}
227
228impl From<OwnedPreparedStatement> for PreparedStatement<'_> {
229    fn from(value: OwnedPreparedStatement) -> Self {
230        let sqlitevalue = value.inner.params.iter().map(|v| {
231            Param::new(
232                v.placeholder,
233                v.value.clone().map(|v| Cow::Owned(SQLiteValue::from(v))),
234            )
235        });
236        let inner = CorePreparedStatement {
237            text_segments: value.inner.text_segments,
238            params: sqlitevalue.collect::<Box<[_]>>(),
239            sql: value.inner.sql,
240        };
241        PreparedStatement { inner }
242    }
243}
244
245impl OwnedPreparedStatement {}
246
247impl core::fmt::Display for PreparedStatement<'_> {
248    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
249        write!(f, "{}", self.inner)
250    }
251}
252
253impl core::fmt::Display for OwnedPreparedStatement {
254    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
255        write!(f, "{}", self.inner)
256    }
257}
258
259#[cfg(test)]
260mod tests {
261    use super::*;
262    use crate::values::SQLiteValue;
263    use drizzle_core::{SQL, ToSQL, prepared::prepare_render};
264
265    #[test]
266    fn test_prepare_render_basic() {
267        // Test the basic prepare_render functionality for SQLite
268        let sql: SQL<'_, SQLiteValue<'_>> = SQL::raw("SELECT * FROM users WHERE id = ")
269            .append(drizzle_core::Placeholder::named("user_id").to_sql())
270            .append(SQL::raw(" AND name = "))
271            .append(drizzle_core::Placeholder::named("user_name").to_sql());
272
273        let prepared = prepare_render(&sql);
274
275        // Should have 3 text segments: before first param, between params, after last param
276        assert_eq!(prepared.text_segments.len(), 3);
277        assert_eq!(prepared.params.len(), 2);
278
279        // Verify text segments contain expected content
280        assert!(prepared.text_segments[0].contains("SELECT * FROM users WHERE id"));
281        assert!(prepared.text_segments[1].contains("AND name"));
282    }
283
284    #[test]
285    fn test_prepare_with_no_parameters() {
286        // Test preparing SQL with no parameters
287        let sql: SQL<'_, SQLiteValue<'_>> = SQL::raw("SELECT COUNT(*) FROM users");
288        let prepared = prepare_render(&sql);
289
290        assert_eq!(prepared.text_segments.len(), 1);
291        assert_eq!(prepared.params.len(), 0);
292        assert_eq!(prepared.text_segments[0], "SELECT COUNT(*) FROM users");
293    }
294
295    #[test]
296    fn test_prepared_statement_display() {
297        let sql: SQL<'_, SQLiteValue<'_>> = SQL::raw("SELECT * FROM users")
298            .append(SQL::raw(" WHERE id = "))
299            .append(drizzle_core::Placeholder::named("id").to_sql());
300
301        let prepared = prepare_render(&sql);
302        let display = format!("{}", prepared);
303
304        assert!(display.contains("SELECT * FROM users"));
305        assert!(display.contains("WHERE id"));
306    }
307
308    #[test]
309    fn test_owned_conversion_roundtrip() {
310        let sql: SQL<'_, SQLiteValue<'_>> = SQL::raw("SELECT name FROM users WHERE id = ")
311            .append(drizzle_core::Placeholder::named("id").to_sql());
312
313        let prepared = prepare_render(&sql);
314        let core_prepared = PreparedStatement { inner: prepared };
315
316        // Convert to owned
317        let owned = core_prepared.into_owned();
318
319        // Convert back to borrowed
320        let borrowed: PreparedStatement<'_> = owned.into();
321
322        // Verify structure is preserved
323        assert_eq!(borrowed.inner.text_segments.len(), 2);
324        assert_eq!(borrowed.inner.params.len(), 1);
325    }
326}