use crate::sql_ext::{RelationalSqlExt, RelationalTxSqlExt, Sql};
use crate::{Dialect, RelError, RelationalBackend, RelationalTx, Row, Value};
use std::future::Future;
pub trait Runner {
fn run_query<'a>(
&'a mut self,
sql: &'a Sql,
params: &'a [Value],
) -> impl Future<Output = Result<Vec<Row>, RelError>> + Send + 'a;
fn run_execute<'a>(
&'a mut self,
sql: &'a Sql,
params: &'a [Value],
) -> impl Future<Output = Result<u64, RelError>> + Send + 'a;
}
impl<B: RelationalBackend + ?Sized> Runner for &B {
fn run_query<'a>(
&'a mut self,
sql: &'a Sql,
params: &'a [Value],
) -> impl Future<Output = Result<Vec<Row>, RelError>> + Send + 'a {
let backend: &'a B = self;
backend.query_sql(sql, params)
}
fn run_execute<'a>(
&'a mut self,
sql: &'a Sql,
params: &'a [Value],
) -> impl Future<Output = Result<u64, RelError>> + Send + 'a {
let backend: &'a B = self;
backend.execute_sql(sql, params)
}
}
pub struct InTx<'t, T: ?Sized> {
tx: &'t mut T,
dialect: Dialect,
}
impl<'t, T: RelationalTx + ?Sized> InTx<'t, T> {
pub fn new(tx: &'t mut T, dialect: Dialect) -> Self {
Self { tx, dialect }
}
}
impl<T: RelationalTx + ?Sized> Runner for InTx<'_, T> {
fn run_query<'a>(
&'a mut self,
sql: &'a Sql,
params: &'a [Value],
) -> impl Future<Output = Result<Vec<Row>, RelError>> + Send + 'a {
let Self { tx, dialect } = self;
tx.query_sql(dialect, sql, params)
}
fn run_execute<'a>(
&'a mut self,
sql: &'a Sql,
params: &'a [Value],
) -> impl Future<Output = Result<u64, RelError>> + Send + 'a {
let Self { tx, dialect } = self;
tx.execute_sql(dialect, sql, params)
}
}
pub struct Bound<R> {
sql: Sql,
params: Vec<Value>,
decode: fn(&Row) -> Result<R, RelError>,
}
impl<R> Bound<R> {
pub fn new(sql: Sql, params: Vec<Value>, decode: fn(&Row) -> Result<R, RelError>) -> Self {
Self {
sql,
params,
decode,
}
}
pub async fn fetch_all<E: Runner>(self, mut on: E) -> Result<Vec<R>, RelError> {
let rows = on.run_query(&self.sql, &self.params).await?;
rows.iter().map(self.decode).collect()
}
pub async fn fetch_one<E: Runner>(self, on: E) -> Result<R, RelError> {
self.fetch_optional(on).await?.ok_or_else(|| {
RelError::Backend("no rows returned by a query that expected one".into())
})
}
pub async fn fetch_optional<E: Runner>(self, mut on: E) -> Result<Option<R>, RelError> {
let rows = on.run_query(&self.sql, &self.params).await?;
rows.first().map(self.decode).transpose()
}
pub async fn execute<E: Runner>(self, mut on: E) -> Result<u64, RelError> {
on.run_execute(&self.sql, &self.params).await
}
}