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)]
14pub struct OwnedPreparedStatement<V: SQLParam> {
15 pub text_segments: Box<[CompactString]>,
17 pub params: Box<[OwnedParam<V>]>,
19 pub sql: CompactString,
21}
22impl<V: SQLParam> core::fmt::Display for OwnedPreparedStatement<V> {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 write!(f, "{}", self.sql())
25 }
26}
27
28impl<'a, V: SQLParam> From<PreparedStatement<'a, V>> for OwnedPreparedStatement<V> {
29 fn from(prepared: PreparedStatement<'a, V>) -> Self {
30 Self {
31 text_segments: prepared.text_segments,
32 params: prepared
33 .params
34 .into_iter()
35 .map(core::convert::Into::into)
36 .collect(),
37 sql: prepared.sql,
38 }
39 }
40}
41
42impl<V: SQLParam> OwnedPreparedStatement<V> {
43 #[must_use]
47 pub fn external_param_count(&self) -> usize {
48 let mut named = HashMap::<&str, ()>::new();
49 let mut positional = 0usize;
50 for param in &self.params {
51 if param.value.is_some() {
52 continue;
53 }
54 match param.placeholder.name {
55 Some(name) if !name.is_empty() => {
56 named.entry(name).or_insert(());
57 }
58 _ => positional += 1,
59 }
60 }
61 named.len() + positional
62 }
63
64 pub fn bind<'a, T: SQLParam + Into<V>>(
72 &self,
73 param_binds: impl IntoIterator<Item = ParamBind<'a, T>>,
74 ) -> crate::error::Result<(&str, impl Iterator<Item = V>)> {
75 let bound_params = bind_values_internal(
76 &self.params,
77 param_binds,
78 |p| p.placeholder.name,
79 |p| p.value.as_ref(), )?;
81
82 Ok((self.sql.as_str(), bound_params.into_iter()))
83 }
84
85 #[must_use]
87 pub fn sql(&self) -> &str {
88 self.sql.as_str()
89 }
90}
91
92impl<'a, V: SQLParam> ToSQL<'a, V> for OwnedPreparedStatement<V> {
93 fn to_sql(&self) -> SQL<'a, V> {
94 let capacity = self.text_segments.len() + self.params.len();
96 let mut chunks = SmallVec::with_capacity(capacity);
97
98 let mut param_iter = self.params.iter();
101
102 for text_segment in &self.text_segments {
103 chunks.push(SQLChunk::Raw(Cow::Owned(text_segment.to_string())));
104
105 if let Some(param) = param_iter.next() {
107 chunks.push(SQLChunk::Param(param.clone().into()));
108 }
109 }
110
111 SQL { chunks }
112 }
113}