Search code examples
rusttraitsrust-dieselrust-rocket

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`

Solution

  • 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);