Hi all,
I'm trying to create an abstraction over r2d2 pools for Postgres connections: I need it as the setup when running locally differs from the setup in staging/prod. For that reason, I need two different kinds of r2d2 pools, even though they both return a smart pointer to a Postgres connection when called.
As I'm rather new to Rust, this lead me down a rabbit hole trying to get the type checker happy. I ended up boxing the smart pointers, but wonder if this is optimal. Does this code look sensible, or is there a better way to pass things that deref(mut) to the same thing?
use std::ops::DerefMut;
// imports to get make the r2d2_postgres impl happy
use postgres::tls::{MakeTlsConnect, TlsConnect};
use r2d2_postgres::PostgresConnectionManager;
use tokio_postgres::Socket;
pub type PGDerefConn = DerefMut<Target = postgres::Client>;
pub trait PostgresPool {
fn get_conn(&self) -> Result<Box<PGDerefConn>, r2d2::Error>;
}
impl<T> PostgresPool for r2d2::Pool<PostgresConnectionManager<T>>
where
T: MakeTlsConnect<Socket> + Clone + 'static + Sync + Send,
T::TlsConnect: Send,
T::Stream: Send,
<T::TlsConnect as TlsConnect<Socket>>::Future: Send,
{
fn get_conn(&self) -> Result<Box<PGDerefConn>, r2d2::Error> {
self.get().map(|x| Box::new(x) as Box<PGDerefConn>)
}
}
pub fn test(pool: &PostgresPool) {
let mut client = pool.get_conn().unwrap();
client
.execute("INSERT INTO foo (bar) VALUES ($1)", &[&1])
.unwrap();
}
I don't worry too much about dynamic dispatch here; I'd rather have PostgresPool
as a trait, even though I know an enum could be slightly faster.