New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

filter parameter with T type #1746

Closed
loothood opened this Issue Jun 1, 2018 · 2 comments

Comments

Projects
None yet
2 participants
@loothood

loothood commented Jun 1, 2018

Versions

  • Rust: 1.26.1 stable
  • Diesel: diesel = { version = "1.3.0", features = ["postgres"] }
  • Database: postgresql
  • Operating System macos high sierra 10.13.4

Feature Flags

  • diesel: postgres

Problem Description

Hi, to get data from db, I use diesel:
schema:

table! {
    users (id) {
        id -> Int4,
        username -> Varchar,
    }
}

model:

#[derive(Queryable, Debug)]
pub struct Users {
    pub id : i32,
    pub username : String,
}

get data function:

pub fn get_user(conn : &PgConnection, id : &i32, name : &str) -> Option<Users> {

    let query = users::table
        .filter(users::id.eq(id)
            .or(users::username.eq(name)));

    let user = query.load::<Users>(conn);

    match user {
        Ok(mut user) => user.pop(),
        Err(_) => None,
    }
}

I call the function:

let user = dbimpl::get_user(&connection, &0, &"Jan");

or

let user = dbimpl::get_user(&connection, &1, &String::new()[..]);

or

let user = dbimpl::get_user(&connection, &1, &"Jan");

Ok. This is works fine.
At a certain stage, I know the username or the user ID.
So, I want use only one parameter in the function.
I try:

use diesel::sql_types::{ Integer, Text };
use diesel::expression::AsExpression;

pub fn get_u<T>(conn : &PgConnection, param : T) -> Option<Users>
    where T : diesel::Expression + AsExpression<Integer> + AsExpression<Text>
{

    let query = users::table
        .filter(users::id.eq(param.as_expression())
            .or(users::username.eq(param.as_expression())));

    let user = query.load::<Users>(conn);

    match user {
        Ok(mut user) => user.pop(),
        Err(_) => None,
    }
}

I got the error:

error[E0284]: type annotations required: cannot resolve `<_ as diesel::expression::AsExpression<diesel::sql_types::Integer>>::Expression == _`
  --> src/database/dbimpl.rs:99:27
   |
99 |         .filter(users::id.eq(param.as_expression())
   |                           ^^

error: aborting due to previous error

I try the IntoSql trait:

pub fn get_u<T>(conn : &PgConnection, param : T) -> Option<Users>
    where T : diesel::Expression + diesel::IntoSql
{

    let query = users::table
        .filter(users::id.eq(param.into_sql())
            .or(users::username.eq(param.into_sql())));

    let user = query.load::<Users>(conn);

    match user {
        Ok(mut user) => user.pop(),
        Err(_) => None,
    }
}

I got the errors:

error[E0271]: type mismatch resolving `<T as diesel::Expression>::SqlType == diesel::sql_types::Integer`
  --> src/database/dbimpl.rs:99:27
   |
99 |         .filter(users::id.eq(param.into_sql())
   |                           ^^ expected associated type, found struct `diesel::sql_types::Integer`
   |
   = note: expected type `<T as diesel::Expression>::SqlType`
              found type `diesel::sql_types::Integer`

error[E0271]: type mismatch resolving `<T as diesel::Expression>::SqlType == diesel::sql_types::Text`
   --> src/database/dbimpl.rs:100:33
    |
100 |             .or(users::username.eq(param.into_sql())));
    |                                 ^^ expected associated type, found struct `diesel::sql_types::Text`
    |
    = note: expected type `<T as diesel::Expression>::SqlType`
               found type `diesel::sql_types::Text`

error[E0277]: the trait bound `T: diesel::expression::NonAggregate` is not satisfied
  --> src/database/dbimpl.rs:99:10
   |
99 |         .filter(users::id.eq(param.into_sql())
   |          ^^^^^^ the trait `diesel::expression::NonAggregate` is not implemented for `T`
   |
   = help: consider adding a `where T: diesel::expression::NonAggregate` bound
   = note: required because of the requirements on the impl of `diesel::expression::NonAggregate` for `diesel::expression::operators::Eq<database::schema::users::columns::id, T>`
   = note: required because of the requirements on the impl of `diesel::expression::NonAggregate` for `diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>`
   = note: required because of the requirements on the impl of `diesel::expression::NonAggregate` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>`
   = note: required because of the requirements on the impl of `diesel::query_dsl::filter_dsl::FilterDsl<diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>>` for `diesel::query_builder::SelectStatement<database::schema::users::table>`

error[E0277]: the trait bound `T: diesel::AppearsOnTable<database::schema::users::table>` is not satisfied
   --> src/database/dbimpl.rs:102:22
    |
102 |     let user = query.load::<Users>(conn);
    |                      ^^^^ the trait `diesel::AppearsOnTable<database::schema::users::table>` is not implemented for `T`
    |
    = help: consider adding a `where T: diesel::AppearsOnTable<database::schema::users::table>` bound
    = note: required because of the requirements on the impl of `diesel::AppearsOnTable<database::schema::users::table>` for `diesel::expression::operators::Eq<database::schema::users::columns::id, T>`
    = note: required because of the requirements on the impl of `diesel::AppearsOnTable<database::schema::users::table>` for `diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>`
    = note: required because of the requirements on the impl of `diesel::AppearsOnTable<database::schema::users::table>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::where_clause::ValidWhereClause<database::schema::users::table>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::Query` for `diesel::query_builder::SelectStatement<database::schema::users::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>>>`
    = note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<_, database::models::users::Users>` for `diesel::query_builder::SelectStatement<database::schema::users::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>>>`

error[E0277]: the trait bound `T: diesel::query_builder::QueryFragment<_>` is not satisfied
   --> src/database/dbimpl.rs:102:22
    |
102 |     let user = query.load::<Users>(conn);
    |                      ^^^^ the trait `diesel::query_builder::QueryFragment<_>` is not implemented for `T`
    |
    = help: the following implementations were found:
              <&'a T as diesel::query_builder::QueryFragment<DB>>
    = note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::expression::operators::Eq<database::schema::users::columns::id, T>`
    = note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::QueryFragment<_>` for `diesel::query_builder::SelectStatement<database::schema::users::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>>>`
    = note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<_, database::models::users::Users>` for `diesel::query_builder::SelectStatement<database::schema::users::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>>>`

error[E0277]: the trait bound `T: diesel::query_builder::QueryId` is not satisfied
   --> src/database/dbimpl.rs:102:22
    |
102 |     let user = query.load::<Users>(conn);
    |                      ^^^^ the trait `diesel::query_builder::QueryId` is not implemented for `T`
    |
    = help: consider adding a `where T: diesel::query_builder::QueryId` bound
    = note: required because of the requirements on the impl of `diesel::query_builder::QueryId` for `diesel::expression::operators::Eq<database::schema::users::columns::id, T>`
    = note: required because of the requirements on the impl of `diesel::query_builder::QueryId` for `diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::QueryId` for `diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::QueryId` for `diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>>`
    = note: required because of the requirements on the impl of `diesel::query_builder::QueryId` for `diesel::query_builder::SelectStatement<database::schema::users::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>>>`
    = note: required because of the requirements on the impl of `diesel::query_dsl::LoadQuery<_, database::models::users::Users>` for `diesel::query_builder::SelectStatement<database::schema::users::table, diesel::query_builder::select_clause::DefaultSelectClause, diesel::query_builder::distinct_clause::NoDistinctClause, diesel::query_builder::where_clause::WhereClause<diesel::expression::grouped::Grouped<diesel::expression::operators::Or<diesel::expression::operators::Eq<database::schema::users::columns::id, T>, diesel::expression::operators::Eq<database::schema::users::columns::username, T>>>>>`

error: aborting due to 6 previous errors

Could you help me please? What Im doing wrong?

@weiznich

This comment has been minimized.

Contributor

weiznich commented Jun 1, 2018

Short version: This wont work in that way.

Long version:

Both columns on your user table have different SqlTypes. (In detail, id has the type Integer, name has the type Text). Each SqlType is compatible with certain rust types. (Again in detail Integer is compatible with i32, Text with &str and String.) Those types are a compile time thing, that means you cannot switch/match at runtime on them.
Now you are trying to construct a function that accepts a type T that is compatible to the both SqlTypes. While in theroy such an type could exist, in pratice there is no such type provided by diesel.
(To fix this function compiling you need to change param.as_expression() into <_ AsExpression<Text>>::as_expression(param) for the name filed and <_ AsExpression<Integer>>::as_expression(param) for the id field, but as written abvoe as soon as you throw in a i32 or a string into that function you will get a unfixable compiler error)

@weiznich weiznich closed this Jun 1, 2018

@loothood

This comment has been minimized.

loothood commented Jun 1, 2018

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment