use crate::{db, operation::AtomicOperation};
pub struct OneTimeExecutor<'c, E>
where
E: sqlx::Executor<'c, Database = db::Db>,
{
now: Option<chrono::DateTime<chrono::Utc>>,
executor: E,
_phantom: std::marker::PhantomData<&'c ()>,
}
impl<'c, E> OneTimeExecutor<'c, E>
where
E: sqlx::Executor<'c, Database = db::Db>,
{
fn new(executor: E, now: Option<chrono::DateTime<chrono::Utc>>) -> Self {
OneTimeExecutor {
executor,
now,
_phantom: std::marker::PhantomData,
}
}
pub fn maybe_now(&self) -> Option<chrono::DateTime<chrono::Utc>> {
self.now
}
pub async fn fetch_one<'q, F, O, A>(
self,
query: sqlx::query::Map<'q, db::Db, F, A>,
) -> Result<O, sqlx::Error>
where
F: FnMut(db::Row) -> Result<O, sqlx::Error> + Send,
O: Send + Unpin,
A: 'q + Send + sqlx::IntoArguments<'q, db::Db>,
{
query.fetch_one(self.executor).await
}
pub async fn fetch_all<'q, F, O, A>(
self,
query: sqlx::query::Map<'q, sqlx::Postgres, F, A>,
) -> Result<Vec<O>, sqlx::Error>
where
F: FnMut(sqlx::postgres::PgRow) -> Result<O, sqlx::Error> + Send,
O: Send + Unpin,
A: 'q + Send + sqlx::IntoArguments<'q, sqlx::Postgres>,
{
query.fetch_all(self.executor).await
}
pub async fn fetch_optional<'q, F, O, A>(
self,
query: sqlx::query::Map<'q, sqlx::Postgres, F, A>,
) -> Result<Option<O>, sqlx::Error>
where
F: FnMut(sqlx::postgres::PgRow) -> Result<O, sqlx::Error> + Send,
O: Send + Unpin,
A: 'q + Send + sqlx::IntoArguments<'q, sqlx::Postgres>,
{
query.fetch_optional(self.executor).await
}
}
pub trait IntoOneTimeExecutor<'c>: IntoOneTimeExecutorAt<'c> + 'c {}
impl<'c, T> IntoOneTimeExecutor<'c> for T where T: IntoOneTimeExecutorAt<'c> + 'c {}
pub trait IntoOneTimeExecutorAt<'c> {
type Executor: sqlx::Executor<'c, Database = db::Db>;
fn into_executor(self) -> OneTimeExecutor<'c, Self::Executor>
where
Self: 'c;
}
impl<'c, E> IntoOneTimeExecutorAt<'c> for OneTimeExecutor<'c, E>
where
E: sqlx::Executor<'c, Database = db::Db> + 'c,
{
type Executor = E;
fn into_executor(self) -> OneTimeExecutor<'c, Self::Executor>
where
Self: 'c,
{
self
}
}
impl<'c> IntoOneTimeExecutorAt<'c> for &db::Pool {
type Executor = &'c db::Pool;
fn into_executor(self) -> OneTimeExecutor<'c, Self::Executor>
where
Self: 'c,
{
OneTimeExecutor::new(self, None)
}
}
impl<'c, O> IntoOneTimeExecutorAt<'c> for &mut O
where
O: AtomicOperation,
{
type Executor = &'c mut db::Connection;
fn into_executor(self) -> OneTimeExecutor<'c, Self::Executor>
where
Self: 'c,
{
let now = self.maybe_now();
OneTimeExecutor::new(self.as_executor(), now)
}
}