diesel-oci 0.2.0

A oci database adapter for diesel
Documentation
use crate::oracle::types::OciTypeMetadata;
use crate::oracle::OciDataType;
use crate::oracle::Oracle;
use diesel::query_builder::BindCollector;
use diesel::sql_types::HasSqlType;
use std::ops::Deref;

#[derive(Default)]
pub struct OracleBindCollector<'a> {
    pub(crate) binds: Vec<(String, BindValue<'a>)>,
}

pub enum BindValue<'a> {
    Owned(Box<dyn oracle::sql_type::ToSql>),
    Borrowed(&'a dyn oracle::sql_type::ToSql),
    NotSet(OciDataType),
}

impl<'a> Deref for BindValue<'a> {
    type Target = dyn oracle::sql_type::ToSql + 'a;

    fn deref(&self) -> &Self::Target {
        match self {
            BindValue::Owned(b) => &**b,
            BindValue::Borrowed(b) => *b,
            BindValue::NotSet(d) => default_value(d),
        }
    }
}

fn default_value(d: &'_ OciDataType) -> &'static dyn oracle::sql_type::ToSql {
    match d {
        OciDataType::Bool | OciDataType::SmallInt | OciDataType::Integer | OciDataType::BigInt => {
            &oracle::sql_type::OracleType::Number(0, 0)
        }
        OciDataType::Float => &oracle::sql_type::OracleType::BinaryFloat,
        OciDataType::Double => &oracle::sql_type::OracleType::BinaryDouble,
        OciDataType::Text => &oracle::sql_type::OracleType::Varchar2(0),
        OciDataType::Binary => &oracle::sql_type::OracleType::BLOB,
        OciDataType::Date => &oracle::sql_type::OracleType::Date,
        OciDataType::Time => unimplemented!("No time support in the oracle crate yet"),
        OciDataType::Timestamp => &oracle::sql_type::OracleType::Timestamp(0),
    }
}

impl<'a> BindCollector<'a, Oracle> for OracleBindCollector<'a> {
    type Buffer = BindValue<'a>;

    fn push_bound_value<T, U>(
        &mut self,
        bind: &'a U,
        metadata_lookup: &mut (),
    ) -> diesel::QueryResult<()>
    where
        Oracle: HasSqlType<T>,
        U: diesel::serialize::ToSql<T, Oracle> + ?Sized + 'a,
    {
        let OciTypeMetadata { tpe: ty } = Oracle::metadata(metadata_lookup);

        let out = {
            let out = BindValue::NotSet(ty);
            let mut out = diesel::serialize::Output::<Oracle>::new(out, metadata_lookup);

            bind.to_sql(&mut out).unwrap();
            out.into_inner()
        };
        let len = self.binds.len();

        self.binds.push((format!("in{}", len), out));

        Ok(())
    }
}

impl<'a, T> From<T> for BindValue<'a>
where
    T: oracle::sql_type::ToSql + 'static,
{
    fn from(t: T) -> Self {
        Self::Owned(Box::new(t))
    }
}