Cedric Martens
Cedric Martens

Reputation: 1199

Rust how to select if table row exists in diesel?

My goal is to query the database and find if a user already exists with the giving email. Looking at the documentation, this appears the way to do so. The only difference is I want to query based on the email instead of the name of the user.

I have some code like this:

src/models.rs

use crate::schema::mailing_list;
use chrono::NaiveDateTime;
use diesel::prelude::*;
use diesel::Insertable;

#[derive(Queryable, Insertable)]
#[diesel(table_name = mailing_list)]
pub struct Subscriber {
    pub uuid: String,
    pub email: String,
    pub date_subscribed: NaiveDateTime,
    pub date_unsubscribed: Option<NaiveDateTime>,
}

and some logic here that has been shortened:

src/mail.rs

use chrono::Utc;
use diesel::prelude::*;
use diesel::dsl::select;
use diesel::dsl::exists;
use rocket::http::Status;
use uuid::Uuid;

use crate::db;
use crate::models::Subscriber;
use crate::schema::mailing_list::dsl::mailing_list;

#[get("/subscribe?<email>")]
pub fn subscribe(email: String) -> Status {
(...)
    let connection = &mut db::establish_connection();
(...)
    let email_exists = select(exists(mailing_list.filter(email.eq(&email))))
        .get_result(connection);
(...)
}
  Compiling rocket-website v0.1.0 (/home/cedric/Documents/Programming/personal-website/rocket-website)             
error[E0277]: the trait bound `bool: diesel::Expression` is not satisfied        
   --> src/mail.rs:27:58                                                                                            
    |                                                     
27  |     let email_exists = select(exists(mailing_list.filter(email.eq(&email))))                                  
    |                                                   ------ ^^^^^^^^^^^^^^^^ the trait `diesel::Expression` is no
t implemented for `bool`                                                                                            
    |                                                   |                                                           
    |                                                   required by a bound introduced by this call
    |                                                                                                               
    = help: the following other types implement trait `diesel::Expression`:                                         
              &'a T                                                                                                 
              (T0, T1)                                                                                              
              (T0, T1, T2)                                                                                          
              (T0, T1, T2, T3)                                                                                      
              (T0, T1, T2, T3, T4)                                                                                  
              (T0, T1, T2, T3, T4, T5)                                                                              
              (T0, T1, T2, T3, T4, T5, T6)                                                                          
              (T0, T1, T2, T3, T4, T5, T6, T7)                                                                      
            and 80 others                                                                                           
    = note: required for `SelectStatement<FromClause<table>>` to implement `FilterDsl<bool>`
    = note: 1 redundant requirement hidden                                                                          
    = note: required for `table` to implement `FilterDsl<bool>`
note: required by a bound in `diesel::QueryDsl::filter`                                                             
   --> /home/cedric/.cargo/registry/src/github.com-1ecc6299db9ec823/diesel-2.0.3/src/query_dsl/mod.rs:619:15        
    |                                                                                                               
619 |         Self: methods::FilterDsl<Predicate>,                                                                  
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `diesel::QueryDsl::filter`              

The error is quite longer than the snippet above, but in short it mentions that for line 27 (the line with the select and the exists these errors:

the trait `diesel::Expression` is not implemented for `bool`
the trait `ValidGrouping<()>` is not implemented for `bool`                                                                                                                                                                       
the trait `expression::subselect::ValidSubselect<NoFromClause>` is not implemented for
`SelectStatement<FromClause<table>, query_builder::select_clause::DefaultSelectClause<FromClause<table>>, 
query_builder::distinct_clause::NoDistinctClause, query_builder::where_cl
ause::WhereClause<bool>>`                                                                   
the trait `expression::subselect::ValidSubselect<NoFromClause>` is not implemented for
 `SelectStatement<FromClause<table>, query_builder::select_clause::DefaultSelectClause<FromClause<table>>,
 query_builder::distinct_clause::NoDistinctClause, query_builder::where_clause::WhereClause<bool>>`

Additionally, there's this other error:

error[E0277]: the trait bound `bool: QueryId` is not satisfied
    --> src/mail.rs:28:21
     |
28   |         .get_result(connection);
     |          ---------- ^^^^^^^^^^ the trait `QueryId` is not implemented for `bool`
     |          |
     |          required by a bound introduced by this call

where this line also triggers this version of the error:

the trait `QueryFragment<Mysql>` is not implemented for `bool`

Upvotes: 3

Views: 926

Answers (2)

David Huculak
David Huculak

Reputation: 322

The filter function expects a special type from diesel that comes from an auto-generated type in the crate::schema namespace.

This should do the trick:

let email_exists = select(exists(mailing_list.filter(self::schema::mailing_list::dsl::email.eq(&email))))
        .get_result::<bool>(connection);

Upvotes: 4

cafce25
cafce25

Reputation: 27437

The problem is that your parameter email happens to be the same name as one of the fields in the schema email. Just rename the parameter or the schema field:

#[get("/subscribe?<email>")]
pub fn subscribe(email: String) -> Status {
    // rename the schema field
    use crate::schema::mailing_list::dsl::email as email_q;
//(...)
    let connection = &mut db::establish_connection();
//(...)
    let email_exists = select(exists(mailing_list.filter(email_q.eq(&email))))
        .get_result(connection);
//(...)
}

Upvotes: 2

Related Questions