use std::convert::identity;
use futures_util::{future::BoxFuture, FutureExt};
use mysql_async::{
prelude::{FromRow, FromValue, ToConnection, WithParams},
BinaryProtocol, Params, QueryResult, Value,
};
use mysql_common::row::ColumnIndex;
use crate::{query::Args, Query};
impl<'a> Into<Params> for Args<'a> {
fn into(self) -> Params {
Params::Positional(
self.0
.into_iter()
.map(|a| match a {
crate::Type::Bool(a) => a.into(),
crate::Type::Int8(a) => a.into(),
crate::Type::Int16(a) => a.into(),
crate::Type::Int32(a) => a.into(),
crate::Type::Int64(a) => a.into(),
crate::Type::Isize(a) => a.into(),
crate::Type::UInt8(a) => a.into(),
crate::Type::UInt16(a) => a.into(),
crate::Type::UInt32(a) => a.into(),
crate::Type::UInt64(a) => a.into(),
crate::Type::Usize(a) => a.into(),
crate::Type::Float(a) => a.into(),
crate::Type::Double(a) => a.into(),
crate::Type::Null => Value::NULL,
crate::Type::String(a) => a.as_ref().into(),
#[cfg(feature = "uuid")]
crate::Type::Uuid(a) => a.to_string().into(),
})
.collect(),
)
}
}
pub trait MysqlQueryExt<'a, 't: 'a>: Sized + Send + 'a {
fn get_raw<C>(
self,
con: C,
) -> BoxFuture<'a, Result<QueryResult<'a, 't, BinaryProtocol>, crate::Error>>
where
C: ToConnection<'a, 't> + 'a;
fn execute<C>(self, con: C) -> BoxFuture<'a, Result<u64, crate::Error>>
where
C: ToConnection<'a, 't> + 'a,
{
async move { Ok(self.get_raw(con).await?.affected_rows()) }.boxed()
}
fn get<C, T>(self, con: C) -> BoxFuture<'a, Result<Vec<T>, crate::Error>>
where
C: ToConnection<'a, 't> + 'a,
T: FromRow + Send,
{
async move { Ok(self.get_raw(con).await?.map(|r| T::from_row(r)).await?) }.boxed()
}
fn first<C, T>(self, con: C) -> BoxFuture<'a, Result<Option<T>, crate::Error>>
where
C: ToConnection<'a, 't> + 'a,
T: FromRow + Send,
{
async move { Ok(self.get(con).await?.into_iter().nth(0)) }.boxed()
}
fn pluck<C, T, I>(self, con: C, idx: I) -> BoxFuture<'a, Result<Vec<T>, crate::Error>>
where
C: ToConnection<'a, 't> + 'a,
I: ColumnIndex + ToOwned<Owned = I> + Send + Sync + 'a,
T: FromValue + Send,
{
async move {
Ok(self
.get_raw(con)
.await?
.map(|r| r.get::<T, I>(idx.to_owned()))
.await?
.into_iter()
.filter_map(identity)
.collect::<Vec<_>>())
}
.boxed()
}
fn all_values<C, T>(self, con: C) -> BoxFuture<'a, Result<Vec<T>, crate::Error>>
where
C: ToConnection<'a, 't> + 'a,
T: FromValue + Send,
{
async move { Ok(self.pluck(con, 0).await?) }.boxed()
}
fn value<C, T>(self, con: C) -> BoxFuture<'a, Result<Option<T>, crate::Error>>
where
C: ToConnection<'a, 't> + 'a,
T: FromValue + Send,
{
async move { Ok(self.all_values(con).await?.into_iter().nth(0)) }.boxed()
}
}
impl<'a, 't: 'a> MysqlQueryExt<'a, 't> for Query<'a> {
fn get_raw<C>(
self,
con: C,
) -> BoxFuture<'a, Result<QueryResult<'a, 't, BinaryProtocol>, crate::Error>>
where
C: ToConnection<'a, 't> + 'a,
{
async move {
Ok(mysql_async::prelude::Query::run(
self.build().map(|(query, args)| query.with(args))?,
con,
)
.await?)
}
.boxed()
}
}