use std::{fmt, mem};
use backend::Backend;
use query_builder::{BindCollector, QueryBuilder};
use result::QueryResult;
use serialize::ToSql;
use sql_types::HasSqlType;
#[allow(missing_debug_implementations)]
pub struct AstPass<'a, DB>
where
DB: Backend,
DB::QueryBuilder: 'a,
DB::BindCollector: 'a,
DB::MetadataLookup: 'a,
{
internals: AstPassInternals<'a, DB>,
}
impl<'a, DB> AstPass<'a, DB>
where
DB: Backend,
{
#[doc(hidden)]
#[allow(clippy::wrong_self_convention)]
pub fn to_sql(query_builder: &'a mut DB::QueryBuilder) -> Self {
AstPass {
internals: AstPassInternals::ToSql(query_builder),
}
}
#[doc(hidden)]
pub fn collect_binds(
collector: &'a mut DB::BindCollector,
metadata_lookup: &'a DB::MetadataLookup,
) -> Self {
AstPass {
internals: AstPassInternals::CollectBinds {
collector,
metadata_lookup,
},
}
}
#[doc(hidden)]
pub fn is_safe_to_cache_prepared(result: &'a mut bool) -> Self {
AstPass {
internals: AstPassInternals::IsSafeToCachePrepared(result),
}
}
#[doc(hidden)]
pub fn debug_binds(formatter: &'a mut fmt::DebugList<'a, 'a>) -> Self {
AstPass {
internals: AstPassInternals::DebugBinds(formatter),
}
}
pub(crate) fn is_noop(result: &'a mut bool) -> Self {
AstPass {
internals: AstPassInternals::IsNoop(result),
}
}
#[allow(clippy::transmute_ptr_to_ptr)]
pub fn reborrow(&mut self) -> AstPass<DB> {
use self::AstPassInternals::*;
let internals = match self.internals {
ToSql(ref mut builder) => ToSql(&mut **builder),
CollectBinds {
ref mut collector,
metadata_lookup,
} => CollectBinds {
collector: &mut **collector,
metadata_lookup: &*metadata_lookup,
},
IsSafeToCachePrepared(ref mut result) => IsSafeToCachePrepared(&mut **result),
DebugBinds(ref mut f) => {
let f_with_shorter_lifetime = unsafe { mem::transmute(&mut **f) };
DebugBinds(f_with_shorter_lifetime)
}
IsNoop(ref mut result) => IsNoop(&mut **result),
};
AstPass { internals }
}
pub fn unsafe_to_cache_prepared(&mut self) {
if let AstPassInternals::IsSafeToCachePrepared(ref mut result) = self.internals {
**result = false
}
}
pub fn push_sql(&mut self, sql: &str) {
match self.internals {
AstPassInternals::ToSql(ref mut builder) => builder.push_sql(sql),
AstPassInternals::IsNoop(ref mut result) => **result = false,
_ => {}
}
}
pub fn push_identifier(&mut self, identifier: &str) -> QueryResult<()> {
match self.internals {
AstPassInternals::ToSql(ref mut builder) => builder.push_identifier(identifier)?,
AstPassInternals::IsNoop(ref mut result) => **result = false,
_ => {}
}
Ok(())
}
pub fn push_bind_param<T, U>(&mut self, bind: &U) -> QueryResult<()>
where
DB: HasSqlType<T>,
U: ToSql<T, DB>,
{
use self::AstPassInternals::*;
match self.internals {
ToSql(ref mut out) => out.push_bind_param(),
CollectBinds {
ref mut collector,
metadata_lookup,
} => collector.push_bound_value(bind, metadata_lookup)?,
DebugBinds(ref mut f) => {
f.entry(bind);
}
IsNoop(ref mut result) => **result = false,
_ => {}
}
Ok(())
}
#[doc(hidden)]
pub fn push_bind_param_value_only<T, U>(&mut self, bind: &U) -> QueryResult<()>
where
DB: HasSqlType<T>,
U: ToSql<T, DB>,
{
use self::AstPassInternals::*;
match self.internals {
CollectBinds { .. } | DebugBinds(..) => self.push_bind_param(bind)?,
_ => {}
}
Ok(())
}
}
#[allow(missing_debug_implementations)]
enum AstPassInternals<'a, DB>
where
DB: Backend,
DB::QueryBuilder: 'a,
DB::BindCollector: 'a,
DB::MetadataLookup: 'a,
{
ToSql(&'a mut DB::QueryBuilder),
CollectBinds {
collector: &'a mut DB::BindCollector,
metadata_lookup: &'a DB::MetadataLookup,
},
IsSafeToCachePrepared(&'a mut bool),
DebugBinds(&'a mut fmt::DebugList<'a, 'a>),
IsNoop(&'a mut bool),
}