diesel/query_builder/
bind_collector.rs1use crate::backend::Backend;
4use crate::result::Error::SerializationError;
5use crate::result::QueryResult;
6use crate::serialize::{IsNull, Output, ToSql};
7use crate::sql_types::{HasSqlType, TypeMetadata};
8
9#[doc(inline)]
10#[diesel_derives::__diesel_public_if(
11 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
12)]
13pub(crate) use self::private::ByteWrapper;
14
15pub trait BindCollector<'a, DB: TypeMetadata>: Sized {
23 type Buffer;
25
26 fn push_bound_value<T, U>(
28 &mut self,
29 bind: &'a U,
30 metadata_lookup: &mut DB::MetadataLookup,
31 ) -> QueryResult<()>
32 where
33 DB: Backend + HasSqlType<T>,
34 U: ToSql<T, DB> + ?Sized + 'a;
35
36 #[diesel_derives::__diesel_public_if(
42 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
43 )]
44 fn push_null_value(&mut self, _metadata: DB::TypeMetadata) -> QueryResult<()> {
45 Ok(())
46 }
47}
48
49#[diesel_derives::__diesel_public_if(
53 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
54)]
55pub trait MoveableBindCollector<DB: TypeMetadata> {
56 type BindData: Send + 'static;
58
59 fn moveable(&self) -> Self::BindData;
61
62 fn append_bind_data(&mut self, from: &Self::BindData);
64}
65
66#[derive(Debug)]
67#[diesel_derives::__diesel_public_if(
73 feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
74 public_fields(metadata, binds)
75)]
76pub struct RawBytesBindCollector<DB: Backend + TypeMetadata> {
77 pub(crate) metadata: Vec<DB::TypeMetadata>,
81 pub(crate) binds: Vec<Option<Vec<u8>>>,
85}
86
87impl<DB: Backend + TypeMetadata> Default for RawBytesBindCollector<DB> {
88 fn default() -> Self {
89 Self::new()
90 }
91}
92
93#[allow(clippy::new_without_default)]
94impl<DB: Backend + TypeMetadata> RawBytesBindCollector<DB> {
95 pub fn new() -> Self {
97 RawBytesBindCollector {
98 metadata: Vec::new(),
99 binds: Vec::new(),
100 }
101 }
102
103 pub(crate) fn reborrow_buffer<'a: 'b, 'b>(b: &'b mut ByteWrapper<'a>) -> ByteWrapper<'b> {
104 ByteWrapper(b.0)
105 }
106}
107
108impl<'a, DB> BindCollector<'a, DB> for RawBytesBindCollector<DB>
109where
110 for<'b> DB: Backend<BindCollector<'b> = Self> + TypeMetadata,
111{
112 type Buffer = ByteWrapper<'a>;
113
114 fn push_bound_value<T, U>(
115 &mut self,
116 bind: &U,
117 metadata_lookup: &mut DB::MetadataLookup,
118 ) -> QueryResult<()>
119 where
120 DB: HasSqlType<T>,
121 U: ToSql<T, DB> + ?Sized,
122 {
123 let mut bytes = Vec::new();
124 let is_null = {
125 let mut to_sql_output = Output::new(ByteWrapper(&mut bytes), metadata_lookup);
126 bind.to_sql(&mut to_sql_output)
127 .map_err(SerializationError)?
128 };
129 let metadata = <DB as HasSqlType<T>>::metadata(metadata_lookup);
130 match is_null {
131 IsNull::No => self.binds.push(Some(bytes)),
132 IsNull::Yes => self.binds.push(None),
133 }
134 self.metadata.push(metadata);
135 Ok(())
136 }
137
138 fn push_null_value(&mut self, metadata: DB::TypeMetadata) -> QueryResult<()> {
139 self.metadata.push(metadata);
140 self.binds.push(None);
141 Ok(())
142 }
143}
144
145impl<DB> MoveableBindCollector<DB> for RawBytesBindCollector<DB>
146where
147 for<'a> DB: Backend<BindCollector<'a> = Self> + TypeMetadata + 'static,
148 <DB as TypeMetadata>::TypeMetadata: Clone + Send,
149{
150 type BindData = Self;
151
152 fn moveable(&self) -> Self::BindData {
153 RawBytesBindCollector {
154 binds: self.binds.clone(),
155 metadata: self.metadata.clone(),
156 }
157 }
158
159 fn append_bind_data(&mut self, from: &Self::BindData) {
160 self.binds.extend(from.binds.iter().cloned());
161 self.metadata.extend(from.metadata.clone());
162 }
163}
164
165mod private {
168 #[derive(Debug)]
170 pub struct ByteWrapper<'a>(pub(crate) &'a mut Vec<u8>);
171}