diesel-async 0.8.0

An async extension for Diesel the safe, extensible ORM and Query Builder
Documentation
use diesel::mysql::data_types::MysqlTime;
use diesel::mysql::MysqlType;
use diesel::mysql::MysqlValue;
use diesel::QueryResult;
use mysql_async::{Params, Value};
use std::convert::TryInto;

pub(super) struct ToSqlHelper {
    pub(super) metadata: Vec<MysqlType>,
    pub(super) binds: Vec<Option<Vec<u8>>>,
}

fn to_value((metadata, bind): (MysqlType, Option<Vec<u8>>)) -> QueryResult<Value> {
    let cast_helper = |e| diesel::result::Error::SerializationError(Box::new(e));
    let v = match bind {
        Some(bind) => match metadata {
            MysqlType::Tiny => Value::Int(i8::from_be_bytes([bind[0]]) as i64),
            MysqlType::Short => Value::Int(i16::from_ne_bytes(bind.try_into().unwrap()) as _),
            MysqlType::Long => Value::Int(i32::from_ne_bytes(bind.try_into().unwrap()) as _),
            MysqlType::LongLong => Value::Int(i64::from_ne_bytes(bind.try_into().unwrap())),

            MysqlType::UnsignedTiny => Value::UInt(bind[0] as _),
            MysqlType::UnsignedShort => {
                Value::UInt(u16::from_ne_bytes(bind.try_into().unwrap()) as _)
            }
            MysqlType::UnsignedLong => {
                Value::UInt(u32::from_ne_bytes(bind.try_into().unwrap()) as _)
            }
            MysqlType::UnsignedLongLong => {
                Value::UInt(u64::from_ne_bytes(bind.try_into().unwrap()))
            }
            MysqlType::Float => Value::Float(f32::from_ne_bytes(bind.try_into().unwrap())),
            MysqlType::Double => Value::Double(f64::from_ne_bytes(bind.try_into().unwrap())),

            MysqlType::Time => {
                let time: MysqlTime = diesel::deserialize::FromSql::<
                    diesel::sql_types::Time,
                    diesel::mysql::Mysql,
                >::from_sql(MysqlValue::new(&bind, metadata))
                .expect("This does not fail");
                Value::Time(
                    time.neg,
                    time.day,
                    time.hour.try_into().map_err(cast_helper)?,
                    time.minute.try_into().map_err(cast_helper)?,
                    time.second.try_into().map_err(cast_helper)?,
                    time.second_part.try_into().expect("Cast does not fail"),
                )
            }
            MysqlType::Date | MysqlType::DateTime | MysqlType::Timestamp => {
                let time: MysqlTime = diesel::deserialize::FromSql::<
                    diesel::sql_types::Timestamp,
                    diesel::mysql::Mysql,
                >::from_sql(MysqlValue::new(&bind, metadata))
                .expect("This does not fail");
                Value::Date(
                    time.year.try_into().map_err(cast_helper)?,
                    time.month.try_into().map_err(cast_helper)?,
                    time.day.try_into().map_err(cast_helper)?,
                    time.hour.try_into().map_err(cast_helper)?,
                    time.minute.try_into().map_err(cast_helper)?,
                    time.second.try_into().map_err(cast_helper)?,
                    time.second_part.try_into().expect("Cast does not fail"),
                )
            }
            MysqlType::Numeric
            | MysqlType::Set
            | MysqlType::Enum
            | MysqlType::String
            | MysqlType::Blob => Value::Bytes(bind),
            MysqlType::Bit => unimplemented!(),
            _ => unreachable!(),
        },
        None => Value::NULL,
    };
    Ok(v)
}

impl TryFrom<ToSqlHelper> for Params {
    type Error = diesel::result::Error;

    fn try_from(ToSqlHelper { metadata, binds }: ToSqlHelper) -> Result<Self, Self::Error> {
        let values = metadata
            .into_iter()
            .zip(binds)
            .map(to_value)
            .collect::<Result<Vec<_>, Self::Error>>()?;
        Ok(Params::Positional(values))
    }
}