2017-11-19 12 views
2

データベース接続パラメータが一般的なデータベースにタイプを挿入し、複数のバックエンドで動作できるようにする関数を記述します。ディーゼルの形質バウンドエラーの理解

私は、一般的な接続を使用してオブジェクトを挿入するには、以下の機能を思い付いた:

pub fn create_label<C>(connection: &C, label: &model::Label) 
where 
    C: Connection, 
    C::Backend: diesel::backend::Backend, 
    C::Backend: diesel::backend::SupportsDefaultKeyword, 
{ 
    diesel::insert(&label) 
     .into(schema::label::table) 
     .execute(connection); 
} 

私はSupportsDefaultKeyword制約が含まれていない場合は、関数がコンパイルされません。接続パラメータとしてSqliteConnectionでそれを呼び出すとき、私は次のエラーを取得する:

database::create_label(&db_conn, &label); ^^^^^^^^^^^^^^^^^^^^^^ the trait 'diesel::backend::SupportsDefaultKeyword' is not implemented for 'diesel::sqlite::Sqlite'

これはSqliteConnectionにデータを挿入すると、動作しないことを意味します。それは明らかにそうではありません。さらに、create_labelを変更すると、SqliteConnectionという名前がそのまま正しく動作します。

pub fn create_label(connection: &SqliteConnection, label: &model::Label) { 
    diesel::insert(&label) 
     .into(schema::label::table) 
     .execute(connection); 
} 

なぜそれが一般的な機能はSupportsDefaultKeyword制約を必要としSqliteConnectionを取る機能がないということでしょうか?

ここには、問題を示すminimal exampleがあります。ライン61は、コンパイルないのに対し、コメント通り、ラインmain.rs 60は、上記のエラーでコンパイルされません:executeが複数の具体的な実装を有する

#[macro_use] 
extern crate diesel; 
#[macro_use] 
extern crate diesel_codegen; 

mod schema { 
    table! { 
     labels { 
      id -> Integer, 
      name -> VarChar, 
     } 
    } 
} 

mod model { 
    use schema::labels; 

    #[derive(Debug, Identifiable, Insertable)] 
    #[table_name = "labels"] 
    pub struct Label { 
     pub id: i32, 
     pub name: String, 
    } 
} 

use diesel::ExecuteDsl; 
use diesel::Connection; 
use diesel::prelude::*; 
use diesel::sqlite::SqliteConnection; 

pub fn create_label<C>(connection: &C, label: &model::Label) 
where 
    C: Connection, 
    C::Backend: diesel::backend::Backend, 
    C::Backend: diesel::backend::SupportsDefaultKeyword, 
{ 
    diesel::insert(label) 
     .into(schema::labels::table) 
     .execute(connection) 
     .expect("nope"); 
} 

pub fn create_label_sqlite(connection: &SqliteConnection, label: &model::Label) { 
    diesel::insert(label) 
     .into(schema::labels::table) 
     .execute(connection) 
     .expect("nope"); 
} 

pub fn establish_connection() -> SqliteConnection { 
    let url = "test.db"; 
    SqliteConnection::establish(&url).expect(&format!("Error connecting to {}", url)) 
} 

fn main() { 
    let label = model::Label { 
     id: 1, 
     name: String::from("test"), 
    }; 
    let conn = establish_connection(); 

    create_label(&conn, &label); /* Does not compile */ 
    create_label_sqlite(&conn, &label); /*Compiles */ 
} 
[dependencies] 
diesel = { version = "0.16.0", features = ["sqlite"] } 
diesel_codegen = "0.16.0" 

答えて

1

ディーゼル機能。ここに関連している二人は、次のとおりです。あなたはこれら2からわかるように、SQLiteのための実装は、特殊ケースに入れている

impl<'a, T, U, Op, Ret, Conn, DB> ExecuteDsl<Conn, DB> for BatchInsertStatement<T, &'a [U], Op, Ret> 
where 
    Conn: Connection<Backend = DB>, 
    DB: Backend + SupportsDefaultKeyword, 
    InsertStatement<T, &'a [U], Op, Ret>: ExecuteDsl<Conn>, 
impl<'a, T, U, Op, Ret> ExecuteDsl<SqliteConnection> for BatchInsertStatement<T, &'a [U], Op, Ret> 
where 
    InsertStatement<T, &'a U, Op, Ret>: ExecuteDsl<SqliteConnection>, 
    T: Copy, 
    Op: Copy, 
    Ret: Copy, 

。なぜディーゼルの詳細について知っているのか分かりませんが、SQLiteにデフォルトのキーワードがないと思います。

あなたは代わりにその特定のステートメントで動作する任意の接続のための要件を再定式ことができます。

use diesel::query_builder::insert_statement::InsertStatement; 

pub fn create_label<C>(connection: &C, label: &model::Label) 
where 
    C: Connection, 
    for<'a> InsertStatement<schema::labels::table, &'a model::Label>: ExecuteDsl<C>, 
{ 
    diesel::insert(label) 
     .into(schema::labels::table) 
     .execute(connection) 
     .expect("nope"); 
}