use crate::backend::Backend;
use crate::result::Error::SerializationError;
use crate::result::QueryResult;
use crate::serialize::{IsNull, Output, ToSql};
use crate::sql_types::{HasSqlType, TypeMetadata};
#[doc(inline)]
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
pub(crate) use self::private::ByteWrapper;
pub trait BindCollector<'a, DB: TypeMetadata>: Sized {
type Buffer;
fn push_bound_value<T, U>(
&mut self,
bind: &'a U,
metadata_lookup: &mut DB::MetadataLookup,
) -> QueryResult<()>
where
DB: Backend + HasSqlType<T>,
U: ToSql<T, DB> + ?Sized + 'a;
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
fn push_null_value(&mut self, _metadata: DB::TypeMetadata) -> QueryResult<()> {
Ok(())
}
}
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes"
)]
pub trait MoveableBindCollector<DB: TypeMetadata> {
type BindData: Send + 'static;
fn moveable(&self) -> Self::BindData;
fn append_bind_data(&mut self, from: &Self::BindData);
}
#[derive(Debug)]
#[diesel_derives::__diesel_public_if(
feature = "i-implement-a-third-party-backend-and-opt-into-breaking-changes",
public_fields(metadata, binds)
)]
pub struct RawBytesBindCollector<DB: Backend + TypeMetadata> {
pub(crate) metadata: Vec<DB::TypeMetadata>,
pub(crate) binds: Vec<Option<Vec<u8>>>,
}
impl<DB: Backend + TypeMetadata> Default for RawBytesBindCollector<DB> {
fn default() -> Self {
Self::new()
}
}
#[allow(clippy::new_without_default)]
impl<DB: Backend + TypeMetadata> RawBytesBindCollector<DB> {
pub fn new() -> Self {
RawBytesBindCollector {
metadata: Vec::new(),
binds: Vec::new(),
}
}
pub(crate) fn reborrow_buffer<'a: 'b, 'b>(b: &'b mut ByteWrapper<'a>) -> ByteWrapper<'b> {
ByteWrapper(b.0)
}
}
impl<'a, DB> BindCollector<'a, DB> for RawBytesBindCollector<DB>
where
for<'b> DB: Backend<BindCollector<'b> = Self> + TypeMetadata,
{
type Buffer = ByteWrapper<'a>;
fn push_bound_value<T, U>(
&mut self,
bind: &U,
metadata_lookup: &mut DB::MetadataLookup,
) -> QueryResult<()>
where
DB: HasSqlType<T>,
U: ToSql<T, DB> + ?Sized,
{
let mut bytes = Vec::new();
let is_null = {
let mut to_sql_output = Output::new(ByteWrapper(&mut bytes), metadata_lookup);
bind.to_sql(&mut to_sql_output)
.map_err(SerializationError)?
};
let metadata = <DB as HasSqlType<T>>::metadata(metadata_lookup);
match is_null {
IsNull::No => self.binds.push(Some(bytes)),
IsNull::Yes => self.binds.push(None),
}
self.metadata.push(metadata);
Ok(())
}
fn push_null_value(&mut self, metadata: DB::TypeMetadata) -> QueryResult<()> {
self.metadata.push(metadata);
self.binds.push(None);
Ok(())
}
}
impl<DB> MoveableBindCollector<DB> for RawBytesBindCollector<DB>
where
for<'a> DB: Backend<BindCollector<'a> = Self> + TypeMetadata + 'static,
<DB as TypeMetadata>::TypeMetadata: Clone + Send,
{
type BindData = Self;
fn moveable(&self) -> Self::BindData {
RawBytesBindCollector {
binds: self.binds.clone(),
metadata: self.metadata.clone(),
}
}
fn append_bind_data(&mut self, from: &Self::BindData) {
self.binds.extend(from.binds.iter().cloned());
self.metadata.extend(from.metadata.clone());
}
}
mod private {
#[derive(Debug)]
pub struct ByteWrapper<'a>(pub(crate) &'a mut Vec<u8>);
}