drizzle_core/prepared/
owned.rs1use crate::prelude::*;
2use crate::{
3 OwnedParam, ParamBind, SQL, SQLChunk, ToSQL,
4 prepared::{PreparedStatement, bind_values_internal},
5 traits::SQLParam,
6};
7use compact_str::CompactString;
8use core::fmt;
9use hashbrown::HashMap;
10use smallvec::SmallVec;
11
12#[derive(Debug, Clone)]
15pub struct OwnedPreparedStatement<V: SQLParam> {
16 pub text_segments: Box<[CompactString]>,
18 pub params: Box<[OwnedParam<V>]>,
20 pub sql: CompactString,
22}
23impl<V: SQLParam> core::fmt::Display for OwnedPreparedStatement<V> {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 write!(f, "{}", self.sql())
26 }
27}
28
29impl<'a, V: SQLParam> From<PreparedStatement<'a, V>> for OwnedPreparedStatement<V> {
30 fn from(prepared: PreparedStatement<'a, V>) -> Self {
31 Self {
32 text_segments: prepared.text_segments,
33 params: prepared
34 .params
35 .into_iter()
36 .map(core::convert::Into::into)
37 .collect(),
38 sql: prepared.sql,
39 }
40 }
41}
42
43impl<V: SQLParam> OwnedPreparedStatement<V> {
44 #[must_use]
49 pub fn external_param_count(&self) -> usize {
50 let mut named = HashMap::<&str, ()>::new();
51 let mut positional = 0usize;
52 for param in &self.params {
53 if param.value.is_some() {
54 continue;
55 }
56 match param.placeholder.name {
57 Some(name) if !name.is_empty() => {
58 named.entry(name).or_insert(());
59 }
60 _ => positional += 1,
61 }
62 }
63 named.len() + positional
64 }
65
66 pub fn bind<'a, T: SQLParam + Into<V>>(
75 &self,
76 param_binds: impl IntoIterator<Item = ParamBind<'a, T>>,
77 ) -> crate::error::Result<(&str, impl Iterator<Item = V>)> {
78 let bound_params = bind_values_internal(
79 &self.params,
80 param_binds,
81 |p| p.placeholder.name,
82 |p| p.value.as_ref(), )?;
84
85 Ok((self.sql.as_str(), bound_params.into_iter()))
86 }
87
88 #[must_use]
90 pub fn sql(&self) -> &str {
91 self.sql.as_str()
92 }
93}
94
95impl<'a, V: SQLParam> ToSQL<'a, V> for OwnedPreparedStatement<V> {
96 fn to_sql(&self) -> SQL<'a, V> {
97 let capacity = self.text_segments.len() + self.params.len();
99 let mut chunks = SmallVec::with_capacity(capacity);
100
101 let mut param_iter = self.params.iter();
104
105 for text_segment in &self.text_segments {
106 chunks.push(SQLChunk::Raw(Cow::Owned(text_segment.to_string())));
107
108 if let Some(param) = param_iter.next() {
110 chunks.push(SQLChunk::Param(param.clone().into()));
111 }
112 }
113
114 SQL { chunks }
115 }
116}