Description
Sometimes I find it easier to start with how this should look to the user:
// async fn foo(executor: impl Executor<'_, Database = Postgres>) -> anyhow::Result<()> {
async fn foo(executor: impl PgExecutor<'_>) -> anyhow::Result<()> {
assert!(executor.fetch_one("SELECT 2").await?.get(0) == 2_i32);
assert!(executor.fetch_one("SELECT 5").await?.get(0) == 5_i32);
Ok(())
}
Anything goes, no matter ugly it makes the SQLx side look as long as it doesn't cause the compiler to ICE if you look at it funny (so try to avoid too many HRTBs).
I can think of a few different ways to do this given full access to the nightly compiler (GATs, arbitrary self types) but we do need this to work on stable.
The key issue is fetch_one
is defined as fetch_one(self, query: impl Execute)
. Executor
is then implemented for &Pool
and &mut PgConnection
, &mut MssqlConnection
, etc.
Note that this example works if instead of the generic argument it is &mut PgConnection
or &Pool
. This works because of the implicit re-borrowing that happens outside of a generic context. I'm reasonably sure we can't mimic re-borrowing in the trait system due to lack of GATs.