2017-12-18 14 views
-1

は、私は、次の2つの機能があります。ディーゼルを使用して複数の機能を抽象化して1つに結合するにはどうすればよいですか?

pub fn get_most_recent_eth_entry(conn: &SqliteConnection) -> Result<i32, Error> { 
    let res = types::ethereum::table 
     .order(types::ethereum::time.desc()) 
     .limit(1) 
     .load::<types::ETHRecord>(&*conn); 
    match res { 
     Ok(x) => { 
      if x.len() > 0 { 
       Ok(x.get(0).unwrap().time) 
      } else { 
       Ok(0) 
      } 
     } 
     Err(err) => Err(format_err!("Error here! {:?}", err)), 
    } 
} 

pub fn get_most_recent_btc_entry(conn: &SqliteConnection) -> Result<i32, Error> { 
    let res = types::bitcoin::table 
     .order(types::bitcoin::time.desc()) 
     .limit(1) 
     .load::<types::BTCRecord>(&*conn); 
    match res { 
     Ok(x) => { 
      if x.len() > 0 { 
       Ok(x.get(0).unwrap().time) 
      } else { 
       Ok(0) 
      } 
     } 
     Err(err) => Err(format_err!("Error here! {:?}", err)), 
    } 
} 

は、私は1つの関数に両方を結合したいです。私はいくつかの異なる方法を試してきたが、

  1. は私が
  2. ディーゼルは奇妙な種類を持っている(あるいは少なくともそれはそれはのように感じているものです)いくつかの方法にはどのようなものがあり

錆することは非常に新しいです:?これらは、私のデータベース構造体の定義(SQLスキーマが同等に定義されている)されている1つの統合機能get_most_recent_entryにのみフィールドtypes::ethereumETHRecordが異なるこの2つの機能(

をマージ

#[derive(Insertable, Queryable, Debug)] 
#[table_name="bitcoin"] 
pub struct BTCRecord { 
    pub time: i32, 
    pub market_cap: f32, 
    pub price_btc: f32, 
    pub price_usd: f32, 
    pub vol_usd: f32, 
} 

`types::ethereum::time` is `database::types::__diesel_infer_schema::infer_bitcoin::bitcoin::columns::time` 

の種類とまず

`types::ethereum::table` is 
`database::types::__diesel_infer_schema::infer_bitcoin::bitcoin::table` 
+1

pub fn get_most_recent_entry<'a, Tbl, Expr, Record>( conn: &SqliteConnection, table: Tbl, time: Expr, ) -> Result<i32, String> where Expr: diesel::ExpressionMethods, Tbl: OrderDsl<Desc<Expr>>, Order<Tbl, Desc<Expr>>: LimitDsl, Limit<Order<Tbl, Desc<Expr>>>: LoadQuery<SqliteConnection, Record>, Record: Time, 

その後、関数全体を短縮するためにディーゼルのfirst機能とResult Sコンビネータを利用することができます有用な答えは、 'bitcoin'と' ethereum'とそれに対応する型が何であるかを知るために十分なスキーマモジュールを含める必要があります。 – Shepmaster

+1

structフィールド( '.time'など)で現在抽象化できないと言うことができます。それは形質の方法に移行する必要があります。 – Shepmaster

+0

はFYI - [?どうやってオプションだけではなく1つのまたは0のレコードを返しディーゼルクエリからオプション>のを得るのですか](https://stackoverflow.com/q/46297867/155423) – Shepmaster

答えて

1

のタイプ、のMCVEから始めましょう。これは、プロのプログラマーが問題を理解しようとするときに使用するツールです。それは無関係の細部を取り除きますが、のための十分な詳細を提供し、状況を再現できるようにします。 あなたがを提供していなかったことをここにどのくらいのコードがあるかを比較してください。欠けている部分はそれぞれ、回答者が推測しなければならないものであり、あなたの時間と時間が生成されます。

[dependencies] 
diesel = { version = "1.0.0-beta", features = ["sqlite"] } 
#[macro_use] 
extern crate diesel; 

use diesel::prelude::*; 
use diesel::SqliteConnection; 

mod types { 
    table! { 
     bitcoin (time) { 
      time -> Int4, 
     } 
    } 

    table! { 
     ethereum (time) { 
      time -> Int4, 
     } 
    } 

    #[derive(Insertable, Queryable, Debug)] 
    #[table_name="bitcoin"] 
    pub struct BtcRecord { 
     pub time: i32, 
    } 

    #[derive(Insertable, Queryable, Debug)] 
    #[table_name="ethereum"] 
    pub struct EthRecord { 
     pub time: i32, 
    } 
} 

pub fn get_most_recent_eth_entry(conn: &SqliteConnection) -> Result<i32, String> { 
    let res = types::ethereum::table 
     .order(types::ethereum::time.desc()) 
     .limit(1) 
     .load::<types::EthRecord>(&*conn); 
    match res { 
     Ok(x) => { 
      if x.len() > 0 { 
       Ok(x.get(0).unwrap().time) 
      } else { 
       Ok(0) 
      } 
     } 
     Err(err) => Err(format!("Error here! {:?}", err)), 
    } 
} 

pub fn get_most_recent_btc_entry(conn: &SqliteConnection) -> Result<i32, String> { 
    let res = types::bitcoin::table 
     .order(types::bitcoin::time.desc()) 
     .limit(1) 
     .load::<types::BtcRecord>(&*conn); 
    match res { 
     Ok(x) => { 
      if x.len() > 0 { 
       Ok(x.get(0).unwrap().time) 
      } else { 
       Ok(0) 
      } 
     } 
     Err(err) => Err(format!("Error here! {:?}", err)), 
    } 
} 

次に、違いを識別するためのコードの二枚の間差分を行います。あなたは言った:

which differ in only the fields types::ethereum and ETHRecord

ただし、4つの場所が異なります。同じプレフィックスを持つものがあるからといって、プレフィックスを渡すことはできません。モジュールは、錆に実行時に存在した概念ではありません。

pub fn get_most_recent_eth_entry(conn: &SqliteConnection) -> Result<i32, String> { 
    // ^^^^^^^^^^^^^^^^^^^^^^^^^ 
    let res = types::ethereum::table 
    //    ^^^^^^^^ 
     .order(types::ethereum::time.desc()) 
    //    ^^^^^^^^ 
     .limit(1) 
     .load::<types::EthRecord>(&*conn); 
    //     ^^^^^^^^^ 

はのは、コピー&ペースト機能の一つにし、ダミーですべての一意の値を置き換えてみましょう:

pub fn get_most_recent_entry<'a, Tbl, Expr, Record>(
    conn: &SqliteConnection, 
    table: Tbl, 
    time: Expr, 
) -> Result<i32, String> { 
    let res = table 
     .order(time.desc()) 
     .limit(1) 
     .load::<Record>(&*conn); 
    // ... 

この次の部分はかなりありません。基本的にコンパイラは、1つ1つ満たされていないすべての特性境界を教えてくれます。あなたは「単なる」すべての制約を設定するために戻ってコードに各エラーをコピーします。

pub fn get_most_recent_entry<'a, Tbl, Expr, Record>(
    conn: &SqliteConnection, 
    table: Tbl, 
    time: Expr, 
) -> Result<i32, String> 
where 
    Expr: diesel::ExpressionMethods, 
    Tbl: OrderDsl<Desc<Expr>>, 
    <Tbl as OrderDsl<Desc<Expr>>>::Output: LimitDsl, 
    <<Tbl as OrderDsl<Desc<Expr>>>::Output as LimitDsl>::Output: RunQueryDsl<SqliteConnection> + Query, 
    Sqlite: HasSqlType<<<<Tbl as OrderDsl<Desc<Expr>>>::Output as LimitDsl>::Output as Query>::SqlType>, 
    <<Tbl as OrderDsl<Desc<Expr>>>::Output as LimitDsl>::Output: QueryFragment<Sqlite>, 
    <<Tbl as OrderDsl<Desc<Expr>>>::Output as LimitDsl>::Output: QueryId, 
    Record: Queryable<<<<Tbl as OrderDsl<Desc<Expr>>>::Output as LimitDsl>::Output as Query>::SqlType, Sqlite>, 

これは新しいエラーにつながる:

error[E0609]: no field `time` on type `&Record` 
    --> src/main.rs:64:38 
    | 
64 |     Ok(x.get(0).unwrap().time) 
    |          ^^^^ 

あなたはジェネリック型の任意のフィールドを想定することはできませんが、我々形質を必要とする:

pub trait Time { 
    fn time(&self) -> i32; 
} 

あなたは:

  • コンクリートの型の両方の形質を実装

一緒にすべての方法でRecord

  • コール.time()にバインドされ、この形質を追加します。

    #[macro_use] 
    extern crate diesel; 
    
    use diesel::prelude::*; 
    use diesel::SqliteConnection; 
    
    mod types { 
        table! { 
         bitcoin (time) { 
          time -> Int4, 
         } 
        } 
    
        table! { 
         ethereum (time) { 
          time -> Int4, 
         } 
        } 
    
        #[derive(Insertable, Queryable, Debug)] 
        #[table_name = "bitcoin"] 
        pub struct BtcRecord { 
         pub time: i32, 
        } 
    
        #[derive(Insertable, Queryable, Debug)] 
        #[table_name = "ethereum"] 
        pub struct EthRecord { 
         pub time: i32, 
        } 
    } 
    
    pub trait Time { 
        fn time(&self) -> i32; 
    } 
    
    impl Time for types::EthRecord { 
        fn time(&self) -> i32 { 
         self.time 
        } 
    } 
    
    impl Time for types::BtcRecord { 
        fn time(&self) -> i32 { 
         self.time 
        } 
    } 
    
    use diesel::sqlite::Sqlite; 
    use diesel::types::HasSqlType; 
    use diesel::query_dsl::methods::{LimitDsl, OrderDsl}; 
    use diesel::expression::operators::Desc; 
    use diesel::query_builder::{Query, QueryFragment, QueryId}; 
    use diesel::Queryable; 
    
    pub fn get_most_recent_entry<'a, Tbl, Expr, Record>(
        conn: &SqliteConnection, 
        table: Tbl, 
        time: Expr, 
    ) -> Result<i32, String> 
    where 
        Expr: diesel::ExpressionMethods, 
        Tbl: OrderDsl<Desc<Expr>>, 
        <Tbl as OrderDsl<Desc<Expr>>>::Output: LimitDsl, 
        <<Tbl as OrderDsl<Desc<Expr>>>::Output as LimitDsl>::Output: RunQueryDsl<SqliteConnection> + Query, 
        Sqlite: HasSqlType<<<<Tbl as OrderDsl<Desc<Expr>>>::Output as LimitDsl>::Output as Query>::SqlType>, 
        <<Tbl as OrderDsl<Desc<Expr>>>::Output as LimitDsl>::Output: QueryFragment<Sqlite>, 
        <<Tbl as OrderDsl<Desc<Expr>>>::Output as LimitDsl>::Output: QueryId, 
        Record: Queryable<<<<Tbl as OrderDsl<Desc<Expr>>>::Output as LimitDsl>::Output as Query>::SqlType, Sqlite> + Time, 
    { 
        let res = table.order(time.desc()).limit(1).load::<Record>(&*conn); 
        match res { 
         Ok(x) => { 
          if x.len() > 0 { 
           Ok(x.get(0).unwrap().time()) 
          } else { 
           Ok(0) 
          } 
         } 
         Err(err) => Err(format!("Error here! {:?}", err)), 
        } 
    } 
    
    pub fn get_most_recent_eth_entry(conn: &SqliteConnection) -> Result<i32, String> { 
        get_most_recent_entry::<_, _, types::EthRecord>(
         conn, 
         types::ethereum::table, 
         types::ethereum::time, 
        ) 
    } 
    
    pub fn get_most_recent_btc_entry(conn: &SqliteConnection) -> Result<i32, String> { 
        get_most_recent_entry::<_, _, types::BtcRecord>(
         conn, 
         types::bitcoin::table, 
         types::bitcoin::time, 
        ) 
    } 
    

    次のステップは、より深いが必要ですディーゼルに飛び込むhelper_types moduleは、私たちは境界を短縮できるようにするエイリアスを入力含まれていますLoadQuery

    pub fn get_most_recent_entry<'a, Tbl, Expr, Record>(
        conn: &SqliteConnection, 
        table: Tbl, 
        time: Expr, 
    ) -> Result<i32, String> 
    where 
        Expr: diesel::ExpressionMethods, 
        Tbl: OrderDsl<Desc<Expr>>, 
        Order<Tbl, Desc<Expr>>: LimitDsl, 
        Limit<Order<Tbl, Desc<Expr>>>: RunQueryDsl<SqliteConnection> 
         + Query 
         + QueryFragment<Sqlite> 
         + QueryId, 
        Sqlite: HasSqlType<<Limit<Order<Tbl, Desc<Expr>>> as Query>::SqlType>, 
        Record: Queryable<<Limit<Order<Tbl, Desc<Expr>>> as Query>::SqlType, Sqlite> + Time, 
    

    はすべてQuery*関連のsubtraitsを包み込む特性もあります。我々はそれを減らすことができ、という使い方:のいずれかの種類を取得するには

    use diesel::expression::operators::Desc; 
    use diesel::helper_types::{Limit, Order}; 
    use diesel::query_dsl::methods::{LimitDsl, OrderDsl}; 
    use diesel::query_dsl::LoadQuery; 
    
    pub fn get_most_recent_entry<'a, Tbl, Expr, Record>(
        conn: &SqliteConnection, 
        table: Tbl, 
        time: Expr, 
    ) -> Result<i32, String> 
    where 
        Expr: diesel::ExpressionMethods, 
        Tbl: OrderDsl<Desc<Expr>>, 
        Order<Tbl, Desc<Expr>>: LoadQuery<SqliteConnection, Record> + LimitDsl, 
        Limit<Order<Tbl, Desc<Expr>>>: LoadQuery<SqliteConnection, Record>, 
        Record: Time, 
    { 
        table 
         .order(time.desc()) 
         .first(conn) 
         .optional() 
         .map(|x| x.map_or(0, |x| x.time())) 
         .map_err(|e| format!("Error here! {:?}", e)) 
    } 
    
  • 関連する問題