use crate::database::{Database, HasArguments, HasStatement};
use crate::describe::Describe;
use crate::error::Error;
use either::Either;
use futures_core::future::BoxFuture;
use futures_core::stream::BoxStream;
use futures_util::{future, FutureExt, StreamExt, TryFutureExt, TryStreamExt};
use std::fmt::Debug;
pub trait Executor<'c>: Send + Debug + Sized {
type Database: Database;
fn execute<'e, 'q: 'e, E: 'q>(
self,
query: E,
) -> BoxFuture<'e, Result<<Self::Database as Database>::Done, Error>>
where
'c: 'e,
E: Execute<'q, Self::Database>,
{
self.execute_many(query).try_collect().boxed()
}
fn execute_many<'e, 'q: 'e, E: 'q>(
self,
query: E,
) -> BoxStream<'e, Result<<Self::Database as Database>::Done, Error>>
where
'c: 'e,
E: Execute<'q, Self::Database>,
{
self.fetch_many(query)
.try_filter_map(|step| async move {
Ok(match step {
Either::Left(rows) => Some(rows),
Either::Right(_) => None,
})
})
.boxed()
}
fn fetch<'e, 'q: 'e, E: 'q>(
self,
query: E,
) -> BoxStream<'e, Result<<Self::Database as Database>::Row, Error>>
where
'c: 'e,
E: Execute<'q, Self::Database>,
{
self.fetch_many(query)
.try_filter_map(|step| async move {
Ok(match step {
Either::Left(_) => None,
Either::Right(row) => Some(row),
})
})
.boxed()
}
fn fetch_many<'e, 'q: 'e, E: 'q>(
self,
query: E,
) -> BoxStream<
'e,
Result<
Either<<Self::Database as Database>::Done, <Self::Database as Database>::Row>,
Error,
>,
>
where
'c: 'e,
E: Execute<'q, Self::Database>;
fn fetch_all<'e, 'q: 'e, E: 'q>(
self,
query: E,
) -> BoxFuture<'e, Result<Vec<<Self::Database as Database>::Row>, Error>>
where
'c: 'e,
E: Execute<'q, Self::Database>,
{
self.fetch(query).try_collect().boxed()
}
fn fetch_one<'e, 'q: 'e, E: 'q>(
self,
query: E,
) -> BoxFuture<'e, Result<<Self::Database as Database>::Row, Error>>
where
'c: 'e,
E: Execute<'q, Self::Database>,
{
self.fetch_optional(query)
.and_then(|row| match row {
Some(row) => future::ok(row),
None => future::err(Error::RowNotFound),
})
.boxed()
}
fn fetch_optional<'e, 'q: 'e, E: 'q>(
self,
query: E,
) -> BoxFuture<'e, Result<Option<<Self::Database as Database>::Row>, Error>>
where
'c: 'e,
E: Execute<'q, Self::Database>;
#[inline]
fn prepare<'e, 'q: 'e>(
self,
query: &'q str,
) -> BoxFuture<'e, Result<<Self::Database as HasStatement<'q>>::Statement, Error>>
where
'c: 'e,
{
self.prepare_with(query, &[])
}
fn prepare_with<'e, 'q: 'e>(
self,
sql: &'q str,
parameters: &'e [<Self::Database as Database>::TypeInfo],
) -> BoxFuture<'e, Result<<Self::Database as HasStatement<'q>>::Statement, Error>>
where
'c: 'e;
#[doc(hidden)]
fn describe<'e, 'q: 'e>(
self,
sql: &'q str,
) -> BoxFuture<'e, Result<Describe<Self::Database>, Error>>
where
'c: 'e;
}
pub trait Execute<'q, DB: Database>: Send + Sized {
fn sql(&self) -> &'q str;
fn statement(&self) -> Option<&<DB as HasStatement<'q>>::Statement>;
fn take_arguments(&mut self) -> Option<<DB as HasArguments<'q>>::Arguments>;
fn persistent(&self) -> bool;
}
impl<'q, DB: Database> Execute<'q, DB> for &'q str {
#[inline]
fn sql(&self) -> &'q str {
self
}
#[inline]
fn statement(&self) -> Option<&<DB as HasStatement<'q>>::Statement> {
None
}
#[inline]
fn take_arguments(&mut self) -> Option<<DB as HasArguments<'q>>::Arguments> {
None
}
#[inline]
fn persistent(&self) -> bool {
true
}
}
impl<'q, DB: Database> Execute<'q, DB> for (&'q str, Option<<DB as HasArguments<'q>>::Arguments>) {
#[inline]
fn sql(&self) -> &'q str {
self.0
}
#[inline]
fn statement(&self) -> Option<&<DB as HasStatement<'q>>::Statement> {
None
}
#[inline]
fn take_arguments(&mut self) -> Option<<DB as HasArguments<'q>>::Arguments> {
self.1.take()
}
#[inline]
fn persistent(&self) -> bool {
true
}
}