Search code examples
postgresqlrustrust-diesel

the trait `LoadConnection` is not implemented for `&diesel::PgConnection`


I want to create a rest api with rust and can't make it work.

My relevant code so far:

In the main.rs:

#[actix_web::main]
async fn main() -> std::io::Result<()> {
// Loading .env into environment variable.
dotenv::dotenv().ok();

env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));

// set up database connection pool
let database_url = std::env::var("DATABASE_URL").expect("DATABASE_URL");
let manager = ConnectionManager::<PgConnection>::new(database_url);
let pool: DbPool = r2d2::Pool::builder()
    .test_on_check_out(true)
    .build(manager)
    .expect("Could not build connection pool");
let port = std::env::var("PORT").expect("$PORT is not set.");
HttpServer::new(move || {
    App::new()
        .app_data(web::Data::new(pool.clone()))
        .wrap(middleware::Logger::default())
        .route("/", web::get().to(|| async { "Actix REST API" }))
        .service(handlers::common::houses::index)
})
.bind(("0.0.0.0", port.parse().unwrap()))?
.run()
.await
}

The schema:

diesel::table! {
  houses (id) {
    id -> Int4,
    user_id -> Varchar,
    street -> Varchar,
    figure -> Varchar,
    floor -> Varchar,
    create_date -> Timestamp,
    update_date -> Timestamp,
    is_deleted -> Bool,
  }
}

The model:

#[derive(Debug, Serialize, Deserialize, Queryable)]
  pub struct House {
  pub id: i32,
  pub user_id: String,
  pub street: String,
  pub figure: String,
  pub floor: String,
  pub create_date: chrono::NaiveDateTime,
  pub update_date: chrono::NaiveDateTime,
  pub is_deleted: bool,
}

The handler:

#[get("/houses")]
async fn index(pool: web::Data<DbPool>) -> Result<HttpResponse, Error> {
  let houses = web::block(move || {
    let conn = &pool.get()?;
    find_all(&conn)
  })
  .await?
  .map_err(actix_web::error::ErrorInternalServerError)?;

  Ok(HttpResponse::Ok().json(houses))
}

fn find_all(conn: &PgConnection) -> Result<Vec<House>, DbError> {
   use crate::schemas::common::houses::houses::dsl::*;

   let items =houses.load::<House>(&mut conn)?;
   Ok(items)
}

The dependencies are:

[dependencies]
actix-web = "4"
chrono = { version = "0.4.19", features = ["serde"] }
diesel = { version = "2.0.3", features = ["postgres", "r2d2", "chrono"] }
dotenv = "0.15.0"
env_logger = "0.10.0"
serde = { version = "1.0.136", features = ["derive"] }
serde_json = "1.0"`

It keeps giving an error, and I don't understand why. The error is:

`error[E0277]: the trait bound `&diesel::PgConnection: LoadConnection` is not satisfied src\handlers\common\houses.rs:25:37
     | 25   |     let items =houses.load::<House>(&mut conn)?;
     |                       ----          -^^^^^^^^
     |                       |             | the trait `LoadConnection` is not implemented for `&diesel::PgConnection` help: consider removing the leading `&`-reference required by a bound introduced by this call
     | note: required for `table` to implement `LoadQuery<'_, &diesel::PgConnection, House>` note: required by a bound in `diesel::RunQueryDsl::load`

I've seen a similar error with the diesel version 1.4, but I think that this version is different. Plus I'm starting with rust and I'm a little lost in general at the moment.

I was hopping someone knows what the problem is and how to fix it.


Solution

  • PgConnection implements LoadConnection but &PgConnection does not (note the extra &).

    Make conn mutable and pass as a mutable reference:

    #[get("/houses")]
    async fn index(pool: web::Data<DbPool>) -> Result<HttpResponse, Error> {
        let houses = web::block(move || {
            let mut conn = pool.get()?; // <------------
            find_all(&mut conn)         // <------------
        })
        .await?
        .map_err(actix_web::error::ErrorInternalServerError)?;
    
        Ok(HttpResponse::Ok().json(houses))
    }
    
    fn find_all(conn: &mut PgConnection) -> Result<Vec<House>, DbError> {
                    // ^^^ <------------
        use crate::schemas::common::houses::houses::dsl::*;
    
        let items = houses.load::<House>(conn)?; // <------------
        Ok(items)
    }