2016-06-23 6 views
1

テストを書く際に、リクエストに接続を挿入して、テストケース全体をトランザクションにラップすることができるようにしたいと思います。テストケースの要求)。ディーゼル接続をIronミドルウェアに注入する

私は、次のような、接続を挿入するために、私は私のテストケースにリンクすることができBeforeMiddlewareを使用してこれを実行しようとしました:

pub type DatabaseConnection = PooledConnection<ConnectionManager<PgConnection>>; 

pub struct DatabaseOverride { 
    conn: DatabaseConnection, 
} 

impl BeforeMiddleware for DatabaseOverride { 
    fn before(&self, req: &mut Request) -> IronResult<()> { 
     req.extensions_mut().entry::<DatabaseOverride>().or_insert(self.conn); 
     Ok(()) 
    } 
} 

しかし、私がやろうとしてコンパイルエラーに遭遇していますこの:

error: the trait bound `std::rc::Rc<diesel::pg::connection::raw::RawConnection>: std::marker::Sync` is not satisfied [E0277] 
impl BeforeMiddleware for DatabaseOverride { 
    ^~~~~~~~~~~~~~~~ 
help: run `rustc --explain E0277` to see a detailed explanation 
note: `std::rc::Rc<diesel::pg::connection::raw::RawConnection>` cannot be shared between threads safely 
note: required because it appears within the type `diesel::pg::PgConnection` 
note: required because it appears within the type `r2d2::Conn<diesel::pg::PgConnection>` 
note: required because it appears within the type `std::option::Option<r2d2::Conn<diesel::pg::PgConnection>>` 
note: required because it appears within the type `r2d2::PooledConnection<r2d2_diesel::ConnectionManager<diesel::pg::PgConnection>>` 
note: required because it appears within the type `utility::db::DatabaseOverride` 
note: required by `iron::BeforeMiddleware` 

error: the trait bound `std::cell::Cell<i32>: std::marker::Sync` is not satisfied [E0277] 
impl BeforeMiddleware for DatabaseOverride { 
    ^~~~~~~~~~~~~~~~ 
help: run `rustc --explain E0277` to see a detailed explanation 
note: `std::cell::Cell<i32>` cannot be shared between threads safely 
note: required because it appears within the type `diesel::pg::PgConnection` 
note: required because it appears within the type `r2d2::Conn<diesel::pg::PgConnection>` 
note: required because it appears within the type `std::option::Option<r2d2::Conn<diesel::pg::PgConnection>>` 
note: required because it appears within the type `r2d2::PooledConnection<r2d2_diesel::ConnectionManager<diesel::pg::PgConnection>>` 
note: required because it appears within the type `utility::db::DatabaseOverride` 
note: required by `iron::BeforeMiddleware` 

ディーゼルの接続でこれを回避する方法はありますか?私はpg木箱を使ってGithubにいくつかの例を見つけましたが、私はディーゼルを使い続けたいと思います。

+0

私は間違っているかもしれませんが(私は自分のRust環境atm近くではありません)、あなたは 'typemap'のような特性を実装する必要はありませんか? –

+0

はい、私は実装しました(私は簡潔さのためにここに掲載しませんでした)。ここでの問題は、 'PgConnection'が' Sync'を実装していないため、 'BeforeMiddleware'を' diesel :: pg :: PgConnection'で初期化できないことです。私は誰かがこの制限の回避策を知っていることを期待していました。 – NeuroXc

+0

自分で「ディーゼル」を使っていないのは分かりません。しかし、 'Cell'型のいずれか、あるいは' Rc'のような非同期型スマートポインタを使用していると、自動的に 'Sync'を実装する能力に失敗します。 –

答えて

2

私はあなたの問題を再現するために提供十分なコードが存在しないので、私はこの作った:

use std::cell::Cell; 

trait Middleware: Sync {} 

struct Unsharable(Cell<bool>); 

impl Middleware for Unsharable {} 

fn main() {} 

同じエラーを持っている:

error: the trait bound `std::cell::Cell<bool>: std::marker::Sync` is not satisfied [E0277] 
impl Middleware for Unsharable {} 
    ^~~~~~~~~~ 
help: run `rustc --explain E0277` to see a detailed explanation 
note: `std::cell::Cell<bool>` cannot be shared between threads safely 
note: required because it appears within the type `Unsharable` 
note: required by `Middleware` 

をあなたは問題を解決することができますタイプを変更してクロススレッド互換にしてください:

use std::sync::Mutex; 

struct Sharable(Mutex<Unsharable>); 

impl Middleware for Sharable {} 

錆は非常に良いこと:安全でないタイプを複数のスレッドで使用することができませんでした。


In writing my tests, I'd like to be able to inject a connection into the request so that I can wrap the entire test case in a transaction (even if there is more than one request in the test case).

私はそれはアーキテクチャの変更をしても良いだろう可能だということをお勧めしたいです。 "Webフレームワーク"のドメインを "データベース"から分離します。このスタイルは、Growing Object-Oriented Software, Guided by Tests(非常にお勧めの本)の著者たちが主唱しています。

トランザクションを開始/終了できるタイプを受け入れ、興味深いものを書き込んだり、完全にテストしたりする方法があるように、コードを引き離してください。次に、トランザクションオブジェクトを作成するために十分なグルーコードをWebレイヤーに配置し、次のレイヤーを呼び出します。

5

This answerは確かに問題を解決しますが、それは間違いありません。前述したように、スレッドセーフではないので、そのような単一の接続を共有する必要はありません。しかし、あなたはMutexにそれをラップしたくありません。接続プールを使用したいとします。

これはr2d2r2d2-dieselクレートで実行できます。これにより、必要に応じて複数の接続が確立され、可能な場合はスレッドセーフな方法で再利用されます。

関連する問題