use crate::{
codec::CodecController,
collection::TryExtend,
database::{Database, DatabaseError, RecordValues, Records, StmtCmd},
misc::ConnectionState,
};
pub trait Executor {
type Database: Database;
fn connection_state(&self) -> ConnectionState;
fn execute_ignored(
&mut self,
cmd: &str,
) -> impl Future<Output = Result<(), <Self::Database as CodecController>::Error>> {
const fn nothing() -> &'static mut () {
static mut NOTHING: &mut () = &mut ();
unsafe { NOTHING }
}
self.execute_many(nothing(), cmd, |_| Ok(()))
}
fn execute_many<'this, B>(
&'this mut self,
buffer: &mut B,
cmd: &str,
cb: impl FnMut(
<Self::Database as Database>::Record<'_>,
) -> Result<(), <Self::Database as CodecController>::Error>,
) -> impl Future<Output = Result<(), <Self::Database as CodecController>::Error>>
where
B: TryExtend<[<Self::Database as Database>::Records<'this>; 1]>;
fn execute_none(
&mut self,
cmd: &str,
) -> impl Future<Output = Result<(), <Self::Database as CodecController>::Error>> {
async {
let mut buffer = None;
self.execute_many(&mut buffer, cmd, |_| Ok(())).await?;
if buffer.is_some() {
return Err(From::from(DatabaseError::UnexpectedRecords.into()));
}
Ok(())
}
}
fn execute_optional(
&mut self,
cmd: &str,
) -> impl Future<
Output = Result<
Option<<Self::Database as Database>::Record<'_>>,
<Self::Database as CodecController>::Error,
>,
> {
async {
let mut buffer = None;
self.execute_many(&mut buffer, cmd, |_| Ok(())).await?;
let Some(records) = buffer else {
return Err(From::from(DatabaseError::ExpectedAtMostOneRecord.into()));
};
if records.len() > 1 {
return Err(From::from(DatabaseError::ExpectedAtMostOneRecord.into()));
};
Ok(records.get(0))
}
}
fn execute_single(
&mut self,
cmd: &str,
) -> impl Future<
Output = Result<
<Self::Database as Database>::Record<'_>,
<Self::Database as CodecController>::Error,
>,
> {
async {
let mut buffer = None;
self.execute_many(&mut buffer, cmd, |_| Ok(())).await?;
let Some(records) = buffer else {
return Err(From::from(DatabaseError::MissingSingleRecord.into()));
};
let (1, Some(record)) = (records.len(), records.get(0)) else {
return Err(From::from(DatabaseError::MissingSingleRecord.into()));
};
Ok(record)
}
}
fn execute_stmt_ignored<SC, RV>(
&mut self,
sc: SC,
rv: RV,
) -> impl Future<Output = Result<(), <Self::Database as CodecController>::Error>>
where
RV: RecordValues<Self::Database>,
SC: StmtCmd,
{
async {
let _records = self.execute_stmt_many(sc, rv, |_| Ok(())).await?;
Ok(())
}
}
fn execute_stmt_many<SC, RV>(
&mut self,
sc: SC,
rv: RV,
cb: impl FnMut(
<Self::Database as Database>::Record<'_>,
) -> Result<(), <Self::Database as CodecController>::Error>,
) -> impl Future<
Output = Result<
<Self::Database as Database>::Records<'_>,
<Self::Database as CodecController>::Error,
>,
>
where
RV: RecordValues<Self::Database>,
SC: StmtCmd;
fn execute_stmt_none<SC, RV>(
&mut self,
sc: SC,
rv: RV,
) -> impl Future<Output = Result<(), <Self::Database as CodecController>::Error>>
where
RV: RecordValues<Self::Database>,
SC: StmtCmd,
{
async {
let records = self.execute_stmt_many(sc, rv, |_| Ok(())).await?;
if records.len() > 0 {
Err(From::from(DatabaseError::UnexpectedRecords.into()))
} else {
Ok(())
}
}
}
fn execute_stmt_optional<SC, RV>(
&mut self,
sc: SC,
rv: RV,
) -> impl Future<
Output = Result<
Option<<Self::Database as Database>::Record<'_>>,
<Self::Database as CodecController>::Error,
>,
>
where
RV: RecordValues<Self::Database>,
SC: StmtCmd,
{
async {
let records = self.execute_stmt_many(sc, rv, |_| Ok(())).await?;
if records.len() > 1 {
return Err(From::from(DatabaseError::MissingSingleRecord.into()));
};
Ok(records.get(0))
}
}
fn execute_stmt_single<SC, RV>(
&mut self,
sc: SC,
rv: RV,
) -> impl Future<
Output = Result<
<Self::Database as Database>::Record<'_>,
<Self::Database as CodecController>::Error,
>,
>
where
RV: RecordValues<Self::Database>,
SC: StmtCmd,
{
async {
let records = self.execute_stmt_many(sc, rv, |_| Ok(())).await?;
let (1, Some(record)) = (records.len(), records.get(0)) else {
return Err(From::from(DatabaseError::MissingSingleRecord.into()));
};
Ok(record)
}
}
fn ping(
&mut self,
) -> impl Future<Output = Result<(), <Self::Database as CodecController>::Error>>;
fn prepare(
&mut self,
cmd: &str,
) -> impl Future<Output = Result<u64, <Self::Database as CodecController>::Error>>;
fn transaction<'this, F, R>(
&'this mut self,
fun: impl FnOnce(&'this mut Self) -> F,
) -> impl Future<Output = Result<R, <Self::Database as CodecController>::Error>>
where
F: Future<Output = Result<(R, &'this mut Self), <Self::Database as CodecController>::Error>>,
{
async move {
self.execute_ignored("BEGIN").await?;
let (rslt, this) = fun(self).await?;
this.execute_ignored("COMMIT").await?;
Ok(rslt)
}
}
}
impl<T> Executor for &mut T
where
T: Executor,
{
type Database = T::Database;
#[inline]
fn connection_state(&self) -> ConnectionState {
(**self).connection_state()
}
#[inline]
async fn execute_many<'this, B>(
&'this mut self,
buffer: &mut B,
cmd: &str,
cb: impl FnMut(
<Self::Database as Database>::Record<'_>,
) -> Result<(), <Self::Database as CodecController>::Error>,
) -> Result<(), <Self::Database as CodecController>::Error>
where
B: TryExtend<[<Self::Database as Database>::Records<'this>; 1]>,
{
(**self).execute_many(buffer, cmd, cb).await
}
#[inline]
async fn execute_stmt_many<SC, RV>(
&mut self,
sc: SC,
rv: RV,
cb: impl FnMut(
<Self::Database as Database>::Record<'_>,
) -> Result<(), <Self::Database as CodecController>::Error>,
) -> Result<<Self::Database as Database>::Records<'_>, <Self::Database as CodecController>::Error>
where
RV: RecordValues<Self::Database>,
SC: StmtCmd,
{
(**self).execute_stmt_many(sc, rv, cb).await
}
#[inline]
async fn ping(&mut self) -> Result<(), <Self::Database as CodecController>::Error> {
(**self).ping().await
}
#[inline]
async fn prepare(
&mut self,
cmd: &str,
) -> Result<u64, <Self::Database as CodecController>::Error> {
(**self).prepare(cmd).await
}
}
impl Executor for () {
type Database = ();
#[inline]
fn connection_state(&self) -> ConnectionState {
ConnectionState::Closed
}
#[inline]
async fn execute_many<'this, B>(
&'this mut self,
_: &mut B,
_: &str,
_: impl FnMut(
<Self::Database as Database>::Record<'_>,
) -> Result<(), <Self::Database as CodecController>::Error>,
) -> Result<(), <Self::Database as CodecController>::Error>
where
B: TryExtend<[<Self::Database as Database>::Records<'this>; 1]>,
{
Ok(())
}
#[inline]
async fn execute_stmt_many<SC, RV>(
&mut self,
_: SC,
_: RV,
_: impl FnMut(
<Self::Database as Database>::Record<'_>,
) -> Result<(), <Self::Database as CodecController>::Error>,
) -> Result<<Self::Database as Database>::Records<'_>, <Self::Database as CodecController>::Error>
where
RV: RecordValues<Self::Database>,
SC: StmtCmd,
{
Ok(())
}
#[inline]
async fn ping(&mut self) -> Result<(), <Self::Database as CodecController>::Error> {
Ok(())
}
#[inline]
async fn prepare(&mut self, _: &str) -> Result<u64, <Self::Database as CodecController>::Error> {
Ok(0)
}
}