0

I am writing a web application in Rust and I'm trying to find a way to provide universal access of the database connection pool to all services in my database module without requiring passing a reference to every function in the module. In other languages, this is can be accomplished by creating a singleton that contains the database connection pool, however I'm having a difficult time doing this in Rust.

Here is the code I'm trying to use to accomplish this functionality:

mod.rs for the database module:

use diesel::MysqlConnection;
use diesel::r2d2::{ConnectionManager, PooledConnection, Pool};
use dotenvy::dotenv;
use std::env;


pub struct DbConn {
    pub pool: Option<Pool<ConnectionManager<MysqlConnection>>>
}

impl DbConn {
    fn get_connection_pool() -> Pool<ConnectionManager<MysqlConnection>> {
        dotenv().ok();

        let url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
        let manager = ConnectionManager::<MysqlConnection>::new(url);

        Pool::builder()
            .test_on_check_out(true)
            .build(manager)
            .expect("Could not build connection pool")
    }
}

static mut DB_CONN_POOL: DbConn = DbConn {
    pool: Some(DbConn::get_connection_pool())
};

post.rs (service for retrieving posts from the database):

use diesel::prelude::*;
use diesel::result::Error;
use serde::{Deserialize, Serialize};
use axum::response::{Json, IntoResponse, Response};
use http::StatusCode;

use crate::database::schema::posts;
use crate::database::schema::posts::dsl::*;


#[derive(Deserialize, Serialize, Queryable, Insertable)]
#[diesel(table_name = posts)]
pub struct Post {
    pub id: i32,
    pub title: String,
    pub body: String,
    pub published: bool,
}

impl Post {
    pub async fn get_posts() -> impl IntoResponse {
        let connection = &mut crate::database::DB_CONN_POOL.pool.unwrap().clone().get().unwrap();

        let results: Vec<Post> = match posts.load::<Post>(connection) {
            Ok(s) => s,
            Err(_e) => Vec::<Post>::new()
        };

        (StatusCode::OK, Json(results))
    }
}

Upon attempting to compile, I receive the following error:

error[E0507]: cannot move out of DB_CONN_POOL.pool as DB_CONN_POOL is a static item

let connection = &mut crate::database::DB_CONN_POOL.pool.unwrap().get().unwrap();

move occurs because DB_CONN_POOL.pool has typestd::option::Option<Pool<ConnectionManager<diesel::MysqlConnection>>>, which does not implement the Copy trait

I understand why Rust can't move the connection pool from a static struct and that the error is suggesting I implement a trait to copy the object, but copying doesn't seem like an appropriate option for a database connection pool. Is there some other way I can create a connection pool once in my application and provide access to that pool for every service in my database module without having to pass it around through every function in the call stack?

0 Answers0