diesel/query_builder/
bind_collector.rs

1//! Types related to managing bind parameters during query construction.
2
3use backend::Backend;
4use result::Error::SerializationError;
5use result::QueryResult;
6use serialize::{IsNull, Output, ToSql};
7use sql_types::{HasSqlType, TypeMetadata};
8
9/// A type which manages serializing bind parameters during query construction.
10///
11/// The only reason you would ever need to interact with this trait is if you
12/// are adding support for a new backend to Diesel. Plugins which are extending
13/// the query builder will use [`AstPass::push_bind_param`] instead.
14///
15/// [`AstPass::push_bind_param`]: ../struct.AstPass.html#method.push_bind_param
16pub trait BindCollector<DB: Backend> {
17    /// Serializes the given bind value, and collects the result.
18    fn push_bound_value<T, U>(
19        &mut self,
20        bind: &U,
21        metadata_lookup: &DB::MetadataLookup,
22    ) -> QueryResult<()>
23    where
24        DB: HasSqlType<T>,
25        U: ToSql<T, DB>;
26}
27
28#[derive(Debug)]
29/// A bind collector used by backends which transmit bind parameters as an
30/// opaque blob of bytes.
31///
32/// For most backends, this is the concrete implementation of `BindCollector`
33/// that should be used.
34pub struct RawBytesBindCollector<DB: Backend + TypeMetadata> {
35    /// The metadata associated with each bind parameter.
36    ///
37    /// This vec is guaranteed to be the same length as `binds`.
38    pub metadata: Vec<DB::TypeMetadata>,
39    /// The serialized bytes for each bind parameter.
40    ///
41    /// This vec is guaranteed to be the same length as `metadata`.
42    pub binds: Vec<Option<Vec<u8>>>,
43}
44
45#[allow(clippy::new_without_default_derive)]
46impl<DB: Backend + TypeMetadata> RawBytesBindCollector<DB> {
47    /// Construct an empty `RawBytesBindCollector`
48    pub fn new() -> Self {
49        RawBytesBindCollector {
50            metadata: Vec::new(),
51            binds: Vec::new(),
52        }
53    }
54}
55
56impl<DB: Backend + TypeMetadata> BindCollector<DB> for RawBytesBindCollector<DB> {
57    fn push_bound_value<T, U>(
58        &mut self,
59        bind: &U,
60        metadata_lookup: &DB::MetadataLookup,
61    ) -> QueryResult<()>
62    where
63        DB: HasSqlType<T>,
64        U: ToSql<T, DB>,
65    {
66        let mut to_sql_output = Output::new(Vec::new(), metadata_lookup);
67        let is_null = bind
68            .to_sql(&mut to_sql_output)
69            .map_err(SerializationError)?;
70        let bytes = to_sql_output.into_inner();
71        let metadata = <DB as HasSqlType<T>>::metadata(metadata_lookup);
72        match is_null {
73            IsNull::No => self.binds.push(Some(bytes)),
74            IsNull::Yes => self.binds.push(None),
75        }
76        self.metadata.push(metadata);
77        Ok(())
78    }
79}