use std::future::Future;
use rorm_sql::value::Value;
use rorm_sql::DBImpl;
use tracing::debug;
use crate::futures_util::BoxFuture;
use crate::transaction::{Transaction, TransactionGuard};
use crate::{internal, Database, Error};
pub struct Nothing;
impl QueryStrategy for Nothing {}
pub struct AffectedRows;
impl QueryStrategy for AffectedRows {}
pub struct One;
impl QueryStrategy for One {}
pub struct Optional;
impl QueryStrategy for Optional {}
pub struct All;
impl QueryStrategy for All {}
pub struct Stream;
impl QueryStrategy for Stream {}
pub trait QueryStrategy: QueryStrategyResult + internal::executor::QueryStrategyImpl {}
#[doc(hidden)]
pub trait QueryStrategyResult {
type Result<'result>;
}
pub trait Executor<'executor> {
fn execute<'data, 'result, Q>(
self,
query: String,
values: Vec<Value<'data>>,
) -> Q::Result<'result>
where
'executor: 'result,
'data: 'result,
Q: QueryStrategy;
fn dialect(&self) -> DBImpl;
fn into_dyn(self) -> DynamicExecutor<'executor>;
type EnsureTransactionFuture: Future<Output = Result<TransactionGuard<'executor>, Error>> + Send;
fn ensure_transaction(self)
-> BoxFuture<'executor, Result<TransactionGuard<'executor>, Error>>;
}
pub enum DynamicExecutor<'executor> {
Database(&'executor Database),
Transaction(&'executor mut Transaction),
}
impl<'executor> Executor<'executor> for DynamicExecutor<'executor> {
fn execute<'data, 'result, Q>(
self,
query: String,
values: Vec<Value<'data>>,
) -> Q::Result<'result>
where
'executor: 'result,
'data: 'result,
Q: QueryStrategy,
{
debug!(
target: "rorm_db::executor",
sql = query,
values.len = values.len(),
"Executing statement"
);
match self {
DynamicExecutor::Database(db) => db.execute::<Q>(query, values),
DynamicExecutor::Transaction(tr) => tr.execute::<Q>(query, values),
}
}
fn dialect(&self) -> DBImpl {
match self {
DynamicExecutor::Database(db) => db.dialect(),
DynamicExecutor::Transaction(tr) => tr.dialect(),
}
}
fn into_dyn(self) -> DynamicExecutor<'executor> {
self
}
type EnsureTransactionFuture = BoxFuture<'executor, Result<TransactionGuard<'executor>, Error>>;
fn ensure_transaction(self) -> Self::EnsureTransactionFuture {
match self {
DynamicExecutor::Database(db) => db.ensure_transaction(),
DynamicExecutor::Transaction(tr) => Box::pin(tr.ensure_transaction()),
}
}
}