Actix with diesel async - LoadConnection is not satisfied

Hi!

So I was experimenting with Actix and Diesel and realized that I actually need the Diesel query to be an async call.

To do so I picked up the diesel-async package: diesel_async - Rust

After some reading I came up with this factory function here to help be build a new Pool manager:

use diesel::{ConnectionError, sqlite::SqliteConnection};
use diesel_async::{
    AsyncConnection,
    pooled_connection::{
        AsyncDieselConnectionManager,
        deadpool::{BuildError, Pool},
    },
    sync_connection_wrapper::SyncConnectionWrapper,
};

use dotenvy::dotenv;
use std::env;

pub type DatabaseConnection = SyncConnectionWrapper<SqliteConnection>;
pub type DatabaseConnectionError = ConnectionError;
pub type DatabaseConnectionPool = Pool<SyncConnectionWrapper<SqliteConnection>>;
pub type DatabaseConnectionPoolError = BuildError;

pub async fn build_db_conn_pool() -> Result<DatabaseConnectionPool, DatabaseConnectionPoolError> {
    dotenv().ok();

    let db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let manager = AsyncDieselConnectionManager::<DatabaseConnection>::new(db_url);
    DatabaseConnectionPool::builder(manager).build()
}

So far so good. Now I updated the main function to inject it the web::Data object:

use actix_web::{App, HttpResponse, HttpServer, Responder, get, web::Data};
use maud::{Markup, html};

use todo_mash_v2::controllers::{database::build_db_conn_pool, pages::home};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let db_pool = build_db_conn_pool()
        .await
        .expect("Failed to create database pool");

    // Start Actix server
    HttpServer::new(move || {
        App::new()
            .app_data(Data::new(db_pool.clone()))
            .service(hello)
            .service(home)
        //.route("/", web::get().to(hello))
    })
    .bind("0.0.0.0:8080")?
    .run()
    .await
}

So far so good. Then I proceed to update the controller function signature:

use actix_web::{HttpResponse, Responder, get, web::Data};
use maud::{Markup, html};

use super::database::DatabaseConnectionPool;

#[get("/")]
async fn home(db_pool: Data<DatabaseConnectionPool>) -> impl Responder {
    let mut obj_conn = db_pool.get().await.unwrap();
    // Fetching Data
    /// ...
    // Rendering Data
    let content: Markup = html! {
        h1 { "Todo App" }
    };
    HttpResponse::Ok().body(content.into_string())
}

Here is where I got stuck. As far as I can tell I should be able Fetch the data with:

let todo_lists: Vec<TodoList> = todo_list::table()
        .select(TodoList::as_select())
        .load::<TodoList>(&mut obj_conn)
        .await?.unwrap();

But the compiler is throwing:

the trait bound `SyncConnectionWrapper<SqliteConnection>: LoadConnection` is not satisfied
the trait `LoadConnection` is implemented for `SqliteConnection`
required for `SelectStatement<FromClause<table>, SelectClause<SelectBy<..., ...>>>` to implement `diesel::query_dsl::LoadQuery<'_, SyncConnectionWrapper<SqliteConnection>, TodoList>`
the full name for the type has been written to '/home/debian-user/Projects/personal/todo-mash-v2/target/debug/deps/todo_mash_v2-af117dbb16e6a223.long-type-2082051071945310070.txt'
consider using `--verbose` to print the full type name to the console

All the examples that I've read seems to assume that the result from the pool.get will return a struct that can used as a connection struct. But clearly that's not the case.

Questions:

  1. What am I missing?
  2. Should I swap Pool manager?
  3. Should I drop the diesel-async crate in favor of using "web::Block" feature?

Thank you for reading :slight_smile:

Based on the error message it seems like you imported diesel::RunQueryDsl which is the sync version of that trait. If you want to use a connection from diesel_async you need to use the async version (diesel_async::RunQueryDsl) instead. It's hard to be 100% sure about that as that import is not shown in the code you provided and also not part of the truncated error message.

As for your question 2 and 3: I think that really depends on what exactly you want to do. There is no one fit's all answer there, that's why these options exist.

@weiznich thank you for the reply! I will be checking the imports shortly :slight_smile: