Search code examples
rustrust-diesel

How can diesel_async's get_results be wrappered?


I would like to build a query and then pass it off to a function wherein it will call diesel_async's get_results

I can't seem to get the trait constraints correct on the function parameters. I've chased my tail trying to add the trait constraints that Rust complains about, but so far have been unsuccessful.

My latest attempt has been:

use diesel::{debug_query, pg::Pg, BoolExpressionMethods, ExpressionMethods, QueryDsl,
    query_builder::QueryFragment, sql_types::SingleValue,
    query_builder::QueryId, Queryable, Identifiable
};
use diesel_async::{RunQueryDsl, AsyncPgConnection, AsyncConnection, methods::LoadQuery};
use serde::{Serialize, Deserialize};


type DB = diesel::pg::Pg;

diesel::table! {
    foo (id) {
        id -> Int4,
        label -> Nullable<Text>,
    }
}

#[derive(Queryable, Debug, Serialize, Deserialize, Identifiable)]
#[diesel(primary_key(id))]
#[diesel(table_name = foo)]
pub struct Foo {
    pub id: i32,
    pub label: Option<String>,
}


pub async fn get_results_wrapped<'query, 'conn, QueryType, ResultItemType>(
    qry: &QueryType,
    conn: & mut AsyncPgConnection
) -> Vec<ResultItemType>
where
    QueryType: LoadQuery<'query, AsyncPgConnection, ResultItemType> + 'query,
    ResultItemType: Send,

{
    qry.get_results::<ResultItemType>(conn).await.unwrap()
}

#[tokio::main]
async fn main() {

    let mut conn = AsyncPgConnection::establish(&std::env::var("DATABASE_URL").unwrap()).await.unwrap();

    let qry = foo::table.filter(foo::id.eq(foo::id));

    // works
    let query_str = debug_query::<DB,_>(&qry).to_string();
    let results = qry.get_results::<Foo>(& mut conn).await.unwrap();


    // doesn't work
    let results : Vec<Foo>= get_results_wrapped(&qry, & mut conn).await.unwrap();
}

With Cargo.toml dependencies:

diesel = { version = "2.2.6", features = ["chrono", "postgres", "uuid", "serde_json"] }
diesel-async = { version ="0.5.2", features = [ "deadpool", "postgres"] }
tokio = { version = "1.40", features = ["full"] }

Rust 1.84.0 complains:

error[E0277]: the trait bound `QueryType: Query` is not satisfied
  --> src/main.rs:36:9
   |
36 |     qry.get_results::<ResultItemType>(conn).await.unwrap()
   |         ^^^^^^^^^^^ the trait `Query` is not implemented for `QueryType`
   |
   = note: required for `&QueryType` to implement `Query`
   = note: required for `&QueryType` to implement `diesel_async::methods::LoadQuery<'_, _, ResultItemType>`
help: consider further restricting this bound
   |
32 |     QueryType: LoadQuery<'query, AsyncPgConnection, ResultItemType> + 'query + diesel::query_builder::Query,
   |                                                                              ++++++++++++++++++++++++++++++

error[E0277]: the trait bound `ResultItemType: FromSqlRow<_, _>` is not satisfied
  --> src/main.rs:36:9
   |
36 |     qry.get_results::<ResultItemType>(conn).await.unwrap()
   |         ^^^^^^^^^^^ the trait `FromSqlRow<_, _>` is not implemented for `ResultItemType`
   |
   = note: double check your type mappings via the documentation of `_`
   = note: `diesel::sql_query` requires the loading target to column names for loading values.
           You need to provide a type that explicitly derives `diesel::deserialize::QueryableByName`
   = help: the following other types implement trait `FromSqlRow<ST, DB>`:
             `T` implements `FromSqlRow<ST, DB>`
             `T` implements `FromSqlRow<Untyped, DB>`
   = note: required for `&QueryType` to implement `diesel_async::methods::LoadQuery<'_, _, ResultItemType>`

error[E0277]: `&QueryType` cannot be sent between threads safely
  --> src/main.rs:36:9
   |
36 |     qry.get_results::<ResultItemType>(conn).await.unwrap()
   |         ^^^^^^^^^^^ `&QueryType` cannot be sent between threads safely
   |
   = note: required for `&QueryType` to implement `Send`
   = note: required for `&QueryType` to implement `diesel_async::methods::LoadQuery<'_, _, ResultItemType>`
help: consider further restricting this bound
   |
32 |     QueryType: LoadQuery<'query, AsyncPgConnection, ResultItemType> + 'query + std::marker::Sync,
   |                                                                              +++++++++++++++++++

error[E0277]: `QueryType` is no valid SQL fragment for the `_` backend
  --> src/main.rs:36:9
   |
36 |     qry.get_results::<ResultItemType>(conn).await.unwrap()
   |         ^^^^^^^^^^^ the trait `QueryFragment<_>` is not implemented for `QueryType`
   |
   = note: this usually means that the `_` database system does not support 
           this SQL syntax
   = help: the trait `QueryFragment<_>` is not implemented for `QueryType`
           but it is implemented for `&_`
   = help: for that trait implementation, expected `&_`, found `QueryType`
   = note: required for `&QueryType` to implement `QueryFragment<_>`
   = note: required for `&QueryType` to implement `diesel_async::methods::LoadQuery<'_, _, ResultItemType>`

error[E0277]: the trait bound `QueryType: QueryId` is not satisfied
  --> src/main.rs:36:9
   |
36 |     qry.get_results::<ResultItemType>(conn).await.unwrap()
   |         ^^^^^^^^^^^ the trait `QueryId` is not implemented for `QueryType`
   |
   = note: required for `&QueryType` to implement `QueryId`
   = note: required for `&QueryType` to implement `diesel_async::methods::LoadQuery<'_, _, ResultItemType>`
help: consider further restricting this bound
   |
32 |     QueryType: LoadQuery<'query, AsyncPgConnection, ResultItemType> + 'query + diesel::query_builder::QueryId,
   |                                                                              ++++++++++++++++++++++++++++++++

error[E0277]: the trait bound `ResultItemType: FromSqlRow<_, _>` is not satisfied
   --> src/main.rs:36:39
    |
36  |     qry.get_results::<ResultItemType>(conn).await.unwrap()
    |         -----------                   ^^^^ the trait `FromSqlRow<_, _>` is not implemented for `ResultItemType`
    |         |
    |         required by a bound introduced by this call
    |
    = note: double check your type mappings via the documentation of `_`
    = note: `diesel::sql_query` requires the loading target to column names for loading values.
            You need to provide a type that explicitly derives `diesel::deserialize::QueryableByName`
    = help: the following other types implement trait `FromSqlRow<ST, DB>`:
              `T` implements `FromSqlRow<ST, DB>`
              `T` implements `FromSqlRow<Untyped, DB>`
    = note: required for `&QueryType` to implement `diesel_async::methods::LoadQuery<'_, _, ResultItemType>`
note: required by a bound in `diesel_async::RunQueryDsl::get_results`
   --> /home/ross/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-async-0.5.2/src/run_query_dsl/mod.rs:581:15
    |
574 |     fn get_results<'query, 'conn, U>(
    |        ----------- required by a bound in this associated function
...
581 |         Self: methods::LoadQuery<'query, Conn, U> + 'query,
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::get_results`

error[E0277]: the trait bound `&QueryType: diesel_async::methods::LoadQuery<'_, _, ResultItemType>` is not satisfied
   --> src/main.rs:36:39
    |
36  |     qry.get_results::<ResultItemType>(conn).await.unwrap()
    |         -----------                   ^^^^ the trait `QueryFragment<_>` is not implemented for `QueryType`
    |         |
    |         required by a bound introduced by this call
    |
    = help: the trait `QueryFragment<_>` is not implemented for `QueryType`
            but it is implemented for `&_`
    = help: for that trait implementation, expected `&_`, found `QueryType`
    = note: required for `&QueryType` to implement `QueryFragment<_>`
    = note: required for `&QueryType` to implement `diesel_async::methods::LoadQuery<'_, _, ResultItemType>`
note: required by a bound in `diesel_async::RunQueryDsl::get_results`
   --> /home/ross/.cargo/registry/src/index.crates.io-6f17d22bba15001f/diesel-async-0.5.2/src/run_query_dsl/mod.rs:581:15
    |
574 |     fn get_results<'query, 'conn, U>(
    |        ----------- required by a bound in this associated function
...
581 |         Self: methods::LoadQuery<'query, Conn, U> + 'query,
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `RunQueryDsl::get_results`

error[E0599]: no method named `unwrap` found for struct `Vec<_>` in the current scope
  --> src/main.rs:52:73
   |
52 |     let results : Vec<Foo>= get_results_wrapped(&qry, & mut conn).await.unwrap();
   |                                                                         ^^^^^^
   |
help: there is a method `swap` with a similar name, but with different arguments
  --> /rustc/9fc6b43126469e3858e2fe86cafb4f0fd5068869/library/core/src/slice/mod.rs:882:5

Question:

How can diesel_async's get_results be generically called within a function?


Solution

  • To flesh out @cafece25's comment that solved my problem, simply passing in the query rather than a reference solve my problem:

    pub async fn get_results_wrapped< 'query, QueryType, ResultItemType>(
        qry: QueryType,
        conn: & mut AsyncPgConnection
    ) -> Vec<ResultItemType>
    where
        QueryType: LoadQuery<'query, AsyncPgConnection, ResultItemType> + 'query,
        ResultItemType: Send,
    {
        qry.get_results::<ResultItemType>(conn).await.unwrap()
    }
    

    His other suggestion did not work for me. Trying to modify the reference to QueryType was a whole 'nother can of worms of chasing trait errors.