drizzle_core/prepared/
owned.rs1use std::{borrow::Cow, fmt};
2
3use compact_str::CompactString;
4use smallvec::SmallVec;
5
6use crate::{
7 OwnedParam, ParamBind, SQL, SQLChunk, ToSQL, prepared::PreparedStatement, traits::SQLParam,
8};
9
10#[derive(Debug, Clone)]
12pub struct OwnedPreparedStatement<V: SQLParam> {
13 pub text_segments: Box<[CompactString]>,
15 pub params: Box<[OwnedParam<V>]>,
17}
18impl<V: SQLParam + std::fmt::Display + 'static> std::fmt::Display for OwnedPreparedStatement<V> {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 write!(f, "{}", self.to_sql())
21 }
22}
23
24impl<'a, V: SQLParam> From<PreparedStatement<'a, V>> for OwnedPreparedStatement<V> {
25 fn from(prepared: PreparedStatement<'a, V>) -> Self {
26 OwnedPreparedStatement {
27 text_segments: prepared.text_segments,
28 params: prepared.params.into_iter().map(|p| p.into()).collect(),
29 }
30 }
31}
32
33impl<V: SQLParam> OwnedPreparedStatement<V> {
34 pub fn bind<'a>(
36 self,
37 param_binds: impl IntoIterator<Item = ParamBind<'a, V>>,
38 ) -> (String, Vec<V>) {
39 let param_binds: Vec<_> = param_binds.into_iter().collect();
40 let mut bound_params = Vec::new();
41 let mut sql = String::new();
42
43 let param_map: std::collections::HashMap<_, _> = param_binds
45 .iter()
46 .map(|bind| (bind.name, &bind.value))
47 .collect();
48
49 let mut param_iter = self.params.iter();
50
51 for text_segment in self.text_segments.iter() {
52 sql.push_str(text_segment);
53
54 if let Some(owned_param) = param_iter.next() {
56 if let Some(name) = &owned_param.placeholder.name {
57 if let Some(value) = param_map.get(name) {
59 bound_params.push((*value).clone());
60 sql.push_str(&format!(":{}", name));
61 } else {
62 sql.push_str(&format!(":{}", name));
64 }
65 } else {
66 sql.push('?');
68 if let Some(bind) = param_binds.get(bound_params.len()) {
69 bound_params.push(bind.value.clone());
70 }
71 }
72 }
73 }
74
75 (sql, bound_params)
76 }
77}
78
79impl<'a, V: SQLParam> ToSQL<'a, V> for OwnedPreparedStatement<V> {
80 fn to_sql(&self) -> SQL<'a, V> {
81 let capacity = self.text_segments.len() + self.params.len();
83 let mut chunks = SmallVec::with_capacity(capacity);
84
85 let mut param_iter = self.params.iter();
88
89 for text_segment in &self.text_segments {
90 chunks.push(SQLChunk::Text(Cow::Owned(text_segment.clone())));
91
92 if let Some(param) = param_iter.next() {
94 chunks.push(SQLChunk::Param(param.clone().into()));
95 }
96 }
97
98 SQL { chunks }
99 }
100}