use mysql_common::row::convert::FromRowError;
use std::{convert::TryInto, result::Result as StdResult};
use crate::{
conn::{queryable::AsStatement, ConnMut},
from_row, from_row_opt,
prelude::FromRow,
Binary, Error, Params, QueryResult, Result, Text,
};
pub trait TextQuery: Sized {
fn run<'a, 'b, 'c, C>(self, conn: C) -> Result<QueryResult<'a, 'b, 'c, Text>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>;
fn first<'a, 'b, 'c: 'b, T, C>(self, conn: C) -> Result<Option<T>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
{
self.run(conn)?
.next()
.map(|row| row.map(from_row))
.transpose()
}
fn first_opt<'a, 'b, 'c: 'b, T, C>(self, conn: C) -> Result<Option<StdResult<T, FromRowError>>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
{
self.run(conn)?
.next()
.map(|row| row.map(from_row_opt))
.transpose()
}
fn fetch<'a, 'b, 'c: 'b, T, C>(self, conn: C) -> Result<Vec<T>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
{
self.run(conn)?.map(|rrow| rrow.map(from_row)).collect()
}
fn fetch_opt<'a, 'b, 'c: 'b, T, C>(self, conn: C) -> Result<Vec<StdResult<T, FromRowError>>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
{
self.run(conn)?.map(|rrow| rrow.map(from_row_opt)).collect()
}
fn fold<'a, 'b, 'c: 'b, T, U, F, C>(self, conn: C, mut init: U, mut next: F) -> Result<U>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
F: FnMut(U, T) -> U,
{
for row in self.run(conn)? {
init = next(init, from_row(row?));
}
Ok(init)
}
fn fold_opt<'a, 'b, 'c: 'b, T, U, F, C>(self, conn: C, mut init: U, mut next: F) -> Result<U>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
F: FnMut(U, StdResult<T, FromRowError>) -> U,
{
for row in self.run(conn)? {
init = next(init, from_row_opt(row?));
}
Ok(init)
}
fn map<'a, 'b, 'c: 'b, T, U, F, C>(self, conn: C, mut map: F) -> Result<Vec<U>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
F: FnMut(T) -> U,
{
self.fold(conn, Vec::new(), |mut acc, row: T| {
acc.push(map(row));
acc
})
}
fn map_opt<'a, 'b, 'c: 'b, T, U, F, C>(self, conn: C, mut map: F) -> Result<Vec<U>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
F: FnMut(StdResult<T, FromRowError>) -> U,
{
self.fold_opt(
conn,
Vec::new(),
|mut acc, row: StdResult<T, FromRowError>| {
acc.push(map(row));
acc
},
)
}
}
impl<Q: AsRef<str>> TextQuery for Q {
fn run<'a, 'b, 'c, C>(self, conn: C) -> Result<QueryResult<'a, 'b, 'c, Text>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
{
let mut conn = conn.try_into()?;
let meta = conn._query(self.as_ref())?;
Ok(QueryResult::new(conn, meta))
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QueryWithParams<Q, P> {
pub query: Q,
pub params: P,
}
pub trait WithParams: Sized {
fn with<P>(self, params: P) -> QueryWithParams<Self, P>;
}
impl<T: AsRef<str>> WithParams for T {
fn with<P>(self, params: P) -> QueryWithParams<Self, P> {
QueryWithParams {
query: self,
params,
}
}
}
pub trait BinQuery: Sized {
fn run<'a, 'b, 'c, C>(self, conn: C) -> Result<QueryResult<'a, 'b, 'c, Binary>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>;
fn first<'a, 'b, 'c: 'b, T, C>(self, conn: C) -> Result<Option<T>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
{
self.run(conn)?
.next()
.map(|row| row.map(from_row))
.transpose()
}
fn first_opt<'a, 'b, 'c: 'b, T, C>(self, conn: C) -> Result<Option<StdResult<T, FromRowError>>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
{
self.run(conn)?
.next()
.map(|row| row.map(from_row_opt))
.transpose()
}
fn fetch<'a, 'b, 'c: 'b, T, C>(self, conn: C) -> Result<Vec<T>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
{
self.run(conn)?.map(|rrow| rrow.map(from_row)).collect()
}
fn fetch_opt<'a, 'b, 'c: 'b, T, C>(self, conn: C) -> Result<Vec<StdResult<T, FromRowError>>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
{
self.run(conn)?.map(|rrow| rrow.map(from_row_opt)).collect()
}
fn fold<'a, 'b, 'c: 'b, T, U, F, C>(self, conn: C, mut init: U, mut next: F) -> Result<U>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
F: FnMut(U, T) -> U,
{
for row in self.run(conn)? {
init = next(init, from_row(row?));
}
Ok(init)
}
fn fold_opt<'a, 'b, 'c: 'b, T, U, F, C>(self, conn: C, mut init: U, mut next: F) -> Result<U>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
F: FnMut(U, StdResult<T, FromRowError>) -> U,
{
for row in self.run(conn)? {
init = next(init, from_row_opt(row?));
}
Ok(init)
}
fn map<'a, 'b, 'c: 'b, T, U, F, C>(self, conn: C, mut map: F) -> Result<Vec<U>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
F: FnMut(T) -> U,
{
self.fold(conn, Vec::new(), |mut acc, row: T| {
acc.push(map(row));
acc
})
}
fn map_opt<'a, 'b, 'c: 'b, T, U, F, C>(self, conn: C, mut map: F) -> Result<Vec<U>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
T: FromRow,
F: FnMut(StdResult<T, FromRowError>) -> U,
{
self.fold_opt(
conn,
Vec::new(),
|mut acc, row: StdResult<T, FromRowError>| {
acc.push(map(row));
acc
},
)
}
}
impl<Q, P> BinQuery for QueryWithParams<Q, P>
where
Q: AsStatement,
P: Into<Params>,
{
fn run<'a, 'b, 'c, C>(self, conn: C) -> Result<QueryResult<'a, 'b, 'c, Binary>>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
{
let mut conn = conn.try_into()?;
let statement = self.query.as_statement(&mut *conn)?;
let meta = conn._execute(&*statement, self.params.into())?;
Ok(QueryResult::new(conn, meta))
}
}
pub trait BatchQuery {
fn batch<'a, 'b, 'c: 'b, C>(self, conn: C) -> Result<()>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>;
}
impl<Q, I, P> BatchQuery for QueryWithParams<Q, I>
where
Q: AsStatement,
I: IntoIterator<Item = P>,
P: Into<Params>,
{
fn batch<'a, 'b, 'c: 'b, C>(self, conn: C) -> Result<()>
where
C: TryInto<ConnMut<'a, 'b, 'c>>,
Error: From<<C as TryInto<ConnMut<'a, 'b, 'c>>>::Error>,
{
let mut conn = conn.try_into()?;
let statement = self.query.as_statement(&mut *conn)?;
for params in self.params {
let params = params.into();
let meta = conn._execute(&*statement, params)?;
let mut query_result = QueryResult::<Binary>::new((&mut *conn).into(), meta);
while let Some(result_set) = query_result.next_set() {
for row in result_set? {
row?;
}
}
}
Ok(())
}
}