我正在尝试设置 sqlx 来生成具有通用数据库类型的特征的
Pool
,但是遇到了问题。我确实想尽可能避免使用 AnyPool
,因为以下回复中提出了多个要点:https://stackoverflow.com/a/70573732/14896203
我当前的特征实现:
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)
}
}
我尝试将 DB 用作数据库的“通用类型”,因为我看到它实现了 Postgres、SQLite 等,但是,我觉得我错过了重要的逻辑点,因为我收到的错误是预期的:
sqlx::Pool<DB>
发现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)
}
}
问题在于您如何定义
connect
函数:
async fn connect<DB: Database>(&self) -> Result<Pool<DB>, Error>
这允许函数的 caller 决定
DB
应该是什么具体类型 - 但在你的情况下,是 implementation 做出这个选择。 connect
的 impl DatabaseTraits for PostgresConnection
实现将 always 返回 sqlx::Pool<Postgres>
,并且调用者无法更改它。
当您的特征需要以这种方式实现定义的占位符类型时,正确使用的工具是关联类型:
pub trait DatabaseTraits {
type DB: Database;
async fn connect(&self) -> Result<Pool<Self::DB>, Error>;
// ...
}
然后您可以在实现中设置类型,如下所示:
impl DatabaseTraits for PostgresConnection {
type DB = Postgres;
// ...
}