I'm trying to setup sqlx to produce a Pool
with a generic Database type for traits, however, running into issues. I do want to avoid as much as possible using AnyPool
, due to multiple points raised in the following reply: https://stackoverflow.com/a/70573732/14896203
My current traits implementation:
use sqlx::postgres::PgRow;
use sqlx::{Database, Error, Pool, Postgres};
pub trait DatabaseTraits {
fn get_address(&self) -> String;
async fn connect<DB: Database>(&self) -> Result<Pool<DB>, Error>;
async fn read(&self, schema: String, table: String) -> Result<PgRow, Error> {
let conn = self.connect().await?;
let query_string = format!("SELECT * FROM {}.{}", schema, table);
let rows = sqlx::query(&query_string).fetch_one(&conn).await?;
Ok(rows)
}
}
I have attempted to use DB as a "generic type" with Database as I saw it implements Postgres, SQLite and others, however, I feel like I'm missing significant logical points, since the error I am getting is expected: sqlx::Pool<DB>
found sqlx::Pool<Postgres>
:
impl DatabaseTraits for PostgresConnection {
fn get_address(&self) -> String {
self.address.to_string()
}
async fn connect<DB: Database>(&self) -> Result<Pool<DB>, Error>
{
let conn: Pool<DB> = PgPoolOptions::new()
.max_connections(5)
.connect(&self.get_address())
.await?.into();
Ok(conn)
}
}
full code: https://hastebin.com/share/yiwemedome.rust
The problem lies with how you've defined the connect
function:
async fn connect<DB: Database>(&self) -> Result<Pool<DB>, Error>
This allows the caller of the function to decide what concrete type DB
should be - but in your case, it's the implementation that's making this choice. The connect
implementation for impl DatabaseTraits for PostgresConnection
will always return a sqlx::Pool<Postgres>
, and the caller can't change that.
When your trait needs an implementation-defined placeholder type in this way, the correct tool to use is an associated type:
pub trait DatabaseTraits {
type DB: Database;
async fn connect(&self) -> Result<Pool<Self::DB>, Error>;
// ...
}
You would then set the type in your implementation like this:
impl DatabaseTraits for PostgresConnection {
type DB = Postgres;
// ...
}