Reputation: 714
I am using Rust with sqlx and postgres to build a REST API. I am trying to build a Database
struct which has a generic connection param in it.
struct Database<T>
where
T: Sync + Send,
for<'a> &'a T: sqlx::Executor<'a, Database = Postgres>,
{
conn: T
}
T
would be owned by the struct, and &T
is expected to implement Executor
trait.
I am able to use Pool<Postgres>
as T
, since &Pool<Postgres>
implements the Executor
.
What I want is (and this is the reason I made the conn
a generic type) to be able to use Transaction<Postgres>
as T
. But the problem is that &Transaction<Postgres>
does not implement the Executor
trait, but &mut Transaction<Postgres>
does.
The reason I want to do this is there are CRUD functions that I want to be able to use with both a transaction and a pool connection. And I don't want to write duplicate code. How can I achieve this?
Upvotes: 0
Views: 187
Reputation: 170815
Maybe someone has a better idea, but it seems the following could work.
use std::marker::PhantomData;
use sqlx::{Pool, Transaction, Postgres};
trait Connection<'a>: Sync + Send {
type Executor: sqlx::Executor<'a>;
fn executor(&'a mut self) -> Self::Executor;
}
impl <'a> Connection<'a> for Pool<Postgres> {
type Executor = &'a Self;
fn executor(&'a mut self) -> Self::Executor {
&*self
}
}
impl <'c> Connection<'c> for Transaction<'c, Postgres> {
type Executor = &'c mut Self;
fn executor(&'c mut self) -> Self::Executor {
self
}
}
struct Database<'a, T: Connection<'a>>
{
conn: T,
phantom: PhantomData<&'a T>
}
impl <'a, T: Connection<'a>> Database<'a, T> {
fn q(&'a mut self) {
let _: T::Executor = self.conn.executor();
// sqlx::query!("Some query").execute(self.conn.executor())
}
}
At the very least it compiles :)
Upvotes: 0