0

我对生锈/柴油很陌生。尝试通过 crate 柴油和 r2d2 实现具有默认特征 API 的数据库模块(避免重复代码工作)。

这是model.rs

use chrono::NaiveDate;
use diesel;
use diesel::Queryable;

#[derive(Queryable)]
pub struct NetWorthModel {
    pub fund_code: String,
    pub date: NaiveDate,
    pub create_time: i64,
    pub update_time: i64,
    pub payload: String,
}

这是database.rs

use diesel::connection::Connection;
use diesel::mysql::MysqlConnection;
use diesel::prelude::*;
use diesel::r2d2::{ConnectionManager, Pool};
use diesel::sqlite::SqliteConnection;
use once_cell::sync::Lazy;
use r2d2::PooledConnection;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use chrono::prelude::NaiveDate;

static MYSQL_POOL_MAP: Lazy<Mutex<HashMap<String, Pool<ConnectionManager<MysqlConnection>>>>> =
    Lazy::new(|| Mutex::new(HashMap::new()));

static SQLITE_POOL_MAP: Lazy<Mutex<HashMap<String, Pool<ConnectionManager<SqliteConnection>>>>> =
    Lazy::new(|| Mutex::new(HashMap::new()));

pub struct MysqlDatabase {
    pool: Pool<ConnectionManager<MysqlConnection>>,
}

pub struct SqliteDatabase {
    pool: Pool<ConnectionManager<SqliteConnection>>,
}

pub trait Database<Conn> {
  fn connection(&self) -> Conn; // MysqlDatabase and SqliteDatabase will ipmlement this api

  fn paged_query(&self, fund_code: &str, start_date: NaiveDate, end_date: NaiveDate) -> Vec<NetWorthModel> {
    use super::schema::tb_net_worth::dsl;
    dsl::tb_net_worth
         .filter(dsl::fund_code.eq(fund_code))
         .filter(dsl::date.ge(start_date))
         .filter(dsl::date.lt(end_date))
         .load::<NetWorthModel>(&self.connection()) // here we use the abstract API
         .unwrap()
  }
}

impl Database<PooledConnection<ConnectionManager<MysqlConnection>>> for MysqlDatabase {
    fn connection(&self) -> PooledConnection<ConnectionManager<MysqlConnection>> {
        self.pool.get().unwrap()
    }
}

impl Database<PooledConnection<ConnectionManager<SqliteConnection>>> for SqliteDatabase {
    fn connection(&self) -> PooledConnection<ConnectionManager<SqliteConnection>> {
        self.pool.get().unwrap()
    }
}

Databasetrait 将实现所有的 API,这应该适用于 mysql 和 sqlite。但这是编译错误:

error[E0277]: the trait bound `Conn: Connection` is not satisfied
   --> src/quant/common/persistence/database.rs:221:45
    |
221 |                 .load::<NetWorthQueryModel>(&self.connection())
    |                  ----                       ^^^^^^^^^^^^^^^^^^ the trait `Connection` is not implemented for `Conn`
    |                  |
    |                  required by a bound introduced by this call
    |
    = note: required because of the requirements on the impl of `LoadQuery<Conn, NetWorthQueryModel>` for `diesel::query_builder::SelectStatement<table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<And<And<diesel::expression::operators::Eq<columns::fund_code, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, GtEq<columns::date, diesel::expression::bound::Bound<diesel::sql_types::Date, NaiveDate>>>, Lt<columns::date, diesel::expression::bound::Bound<diesel::sql_types::Date, NaiveDate>>>>, diesel::query_builder::order_clause::OrderClause<Asc<columns::date>>, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>, diesel::query_builder::offset_clause::OffsetClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>`
help: consider restricting type parameter `Conn`
    |
147 | pub trait Database<Conn: diesel::Connection> {
    |                        ++++++++++++++++++++

按照编译器的建议,我添加pub trait Database<Conn: diesel::Connection>,编译器给了我另一个错误:

error[E0277]: the trait bound `NaiveDate: FromSql<diesel::sql_types::Date, <Conn as Connection>::Backend>` is not satisfied
   --> src/quant/common/persistence/database.rs:221:18
    |
221 |                 .load::<NetWorthQueryModel>(&self.connection())
    |                  ^^^^ the trait `FromSql<diesel::sql_types::Date, <Conn as Connection>::Backend>` is not implemented for `NaiveDate`
    |
    = note: required because of the requirements on the impl of `diesel::Queryable<diesel::sql_types::Date, <Conn as Connection>::Backend>` for `NaiveDate`
    = note: 2 redundant requirements hidden
    = note: required because of the requirements on the impl of `diesel::Queryable<(diesel::sql_types::Text, diesel::sql_types::Date, diesel::sql_types::BigInt, diesel::sql_types::BigInt, diesel::sql_types::Text), <Conn as Connection>::Backend>` for `NetWorthQueryModel`
    = note: required because of the requirements on the impl of `LoadQuery<Conn, NetWorthQueryModel>` for `diesel::query_builder::SelectStatement<table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<And<And<diesel::expression::operators::Eq<columns::fund_code, diesel::expression::bound::Bound<diesel::sql_types::Text, &str>>, GtEq<columns::date, diesel::expression::bound::Bound<diesel::sql_types::Date, NaiveDate>>>, Lt<columns::date, diesel::expression::bound::Bound<diesel::sql_types::Date, NaiveDate>>>>, diesel::query_builder::order_clause::OrderClause<Asc<columns::date>>, diesel::query_builder::limit_clause::LimitClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>, diesel::query_builder::offset_clause::OffsetClause<diesel::expression::bound::Bound<diesel::sql_types::BigInt, i64>>>`
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
    |
147 | pub trait Database<Conn: Connection> where NaiveDate: FromSql<diesel::sql_types::Date, <Conn as Connection>::Backend> {
    |                                      ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

似乎 rustc 无法检测BackendConnection. 但我不知道我应该如何解决这个问题。

请帮我解决这个问题。

4

1 回答 1

0

解决此问题的正确方法是遵循编译器错误消息并引入必要的特征界限。没有它们就行不通。作为一般建议:尝试使用给出的最后一个边界,required because of因为这样可以避免许多其他边界。

一般来说:如果您不熟悉柴油并且生锈,那么尝试编写尝试抽象柴油的通用代码可能是不可取的。这需要提前了解 rusts 特征系统 + 柴油 API。

于 2021-12-21T15:53:10.443 回答