Thanks, this is exactly the kick in the brainstem I needed. I ended up with this:
pub trait WithExecutor<'e> {
type Executor: Executor<'e, Database = sqlx::postgres::Postgres>;
fn executor(&'e mut self) -> Self::Executor;
}
impl<'p> WithExecutor<'p> for Repository<sqlx::postgres::PgPool> {
type Executor = &'p sqlx::postgres::PgPool;
fn executor(&'p mut self) -> Self::Executor {
&self.executor
}
}
impl<'t, 'c> WithExecutor<'t> for Repository<sqlx::Transaction<'c, sqlx::Postgres>>
where
'c: 't,
{
type Executor = &'t mut sqlx::Transaction<'c, sqlx::Postgres>;
fn executor(&'t mut self) -> Self::Executor {
&mut self.executor
}
}
impl<'e, T> Repository<T>
where
Self: WithExecutor<'e>,
{
pub async fn submit<R, N, O, I>(
&'e mut self,
submission: Submission<R, N, O, I>,
) -> Result<Filed<R, N, O, I>>
where
R: Submit + Unpin + Send,
N: Serialize + DeserializeOwned,
O: Serialize + DeserializeOwned,
I: Serialize + DeserializeOwned,
{
let submission = submission.into_storage()?;
let result = R::submit(submission).fetch_one(self.executor()).await?; // <-- the troublesome line from my original post
let result = result.into_app()?;
Ok(result)
}
}
It has some ergonomics issues, but nothing insurmountable. Thanks a ton for reminding me that this is an option.