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:
- What am I missing?
- Should I swap Pool manager?
- Should I drop the diesel-async crate in favor of using "web::Block" feature?
Thank you for reading