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