First baby steps with Diesel & R2D2

Hi there. I try to use and understand diesel and r2d2. Here is my code so far :slight_smile:

extern crate diesel;
use diesel::prelude::*;
use diesel::r2d2::ConnectionManager;
use dotenv::dotenv;
use std::env;

fn main() {
    dotenv().ok();
    let database_url    = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let manager         = ConnectionManager::<PgConnection>::new(database_url);
    let pool            = r2d2::Pool::new(manager).unwrap();
    let conn            = pool.get();
}

I already have some questions...

First: where do i specify the size of the pool?

Second: how do i return the conn to the pool once i don't need it anymore?

Third: how do i share the pool with other modules so these modules can also ask for a connection and return it to the pool after use ? I come from java where i would simply declare a public static method on some object "DbUtils.getConnection()" but here in Rust i'm a bit lost

Last one: see diesel - Rust. The documentation talks about macro infer_schema! but i don't see it in the list of macro. Is it something wrong in the documentation?

Tx guys
PS: another question.

So.. first of all, please, format code using ```

extern crate diesel;
use diesel::prelude::*;
use diesel::r2d2::ConnectionManager;
use dotenv::dotenv;
use std::env;

fn main() {
    dotenv().ok();
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let manager = ConnectionManager::::new(database_url);
    let pool = r2d2::Pool::new(manager).unwrap();
    let conn = pool.get();
}

Now the answers.

First : where do i specify the size of the pool?

You can use builder, like in the example below:

let pool = r2d2::Pool::builder()
        .max_size(15)
        .build(manager)
        .unwrap();

Second : how do i return the conn to the pool once i don't need it anymore ?

According to Readme file in project:

// use the connection
// it will be returned to the pool when it falls out of scope.

So, if you would write:

fn main() {
    dotenv().ok();
    let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let manager = ConnectionManager::::new(database_url);
    let pool = r2d2::Pool::new(manager).unwrap();
    {
        let conn = pool.get();
    } // connection goes back to pool here
}

Third : how do i share the pool with other modules so these modules can also ask for a connection and return it to the pool after use ? I come from java where i would simply declare a public static method on some object "DbUtils.getConnection()" but here in RUST i'm a bit lost

I am not an expert, but you can do it same way like in Readme file, so creating a new thread and cloning pool. You can also add pool as argument of the method when needed.

If you write code in Java with Spring framework, then you may have a @Bean which represents a connection pool. You can then pass it as constructor argument. You can do similar in Rust I believe. I hope other people here will elaborate about it. Like I said, I am not an expert in Rust.

Third : how do i share the pool with other modules so these modules can also ask for a connection and return it to the pool after use ? I come from java where i would simply declare a public static method on some object "DbUtils.getConnection()" but here in RUST i'm a bit lost

i did something like this

// utils.rs
use lazy_static;
use diesel::{
    r2d2::{Pool, ConnectionManager},
    pg::PgConnection
};

type PgPool = Pool<ConnectionManager<PgConnection>>;

pub struct Values<'a> {
    pub db_connection: PgPool,
}

lazy_static! {
    pub static ref VALUES: Values<'static> = {
        Values {
            db_connection: PgPool::builder()
                .max_size(8)
                .build(ConnectionManager::new("yourconnectionstring"))
                .expect("failed to create db connection_pool")
        }
    };
}

then you can access it thus

use super::utils;
pub fn can_connect() -> bool {
    utils::VALUES.db_connection.get().is_ok()
}

Thank you so much guys. I didn't know for the formating ``` ! Will use it :cowboy_hat_face:

That doesn't compile my friend....

   Compiling r2d2 v0.1.0 (C:\0 - dvt\2 - projects\r2d2)
error[E0432]: unresolved import `lazy_static`
 --> src\main.rs:9:5
  |
9 | use lazy_static;
  |     ^^^^^^^^^^^ no `lazy_static` external crate

error: cannot determine resolution for the macro `lazy_static`
  --> src\main.rs:21:1
   |
21 | lazy_static! {
   | ^^^^^^^^^^^
   |
   = note: import resolution is stuck, try simplifying macro imports

warning: unused import: `dotenv::dotenv`
 --> src\main.rs:7:5
  |
7 | use dotenv::dotenv;
  |     ^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unused import: `std::env`
 --> src\main.rs:8:5
  |
8 | use std::env;
  |     ^^^^^^^^

error[E0392]: parameter `'a` is never used
  --> src\main.rs:17:19
   |
17 | pub struct Values<'a> {
   |                   ^^ unused parameter
   |
   = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData`

I would also recommend it for errors :slight_smile:.

Did you read the error message? It says it couldn't find the crate lazy_static, so you would have to add it as a dependency to your library in the Cargo.toml file.

1 Like

Should i ? He creates it himself :

lazy_static! {
    pub static ref VALUES: Values<'static> = {
        Values {
            db_connection: PgPool::builder()
                .max_size(8)
                .build(ConnectionManager::new("yourconnectionstring"))
                .expect("failed to create db connection_pool")
        }
    };
}
lazy_static! {
    pub static ref VALUES: Values<'static> = {
        Values {
            db_connection: PgPool::builder()
                .max_size(8)
                .build(ConnectionManager::new("yourconnectionstring"))
                .expect("failed to create db connection_pool")
        }
    };
}

:roll_eyes:

They didn't create the lazy_static! macro, but just used it. Note also that there's an edit post feature.

1 Like

Sorry to be such a newbie. lazy_static! is ok now but that doesn't compile because in the struct Values<'a> { pub db_connection: 'a PgPool,} 'a is not used

pub struct Values<'a> {
  |                   ^^ unused parameter
  |
  = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData`

I don't know why they put the lifetime on it. Just remove it.

1 Like

Still that doesn't compile. The provided piece of code is probably not well written...

 Values {
25 |  |             db_connection: PgPool::builder()
   |  |_____________________________-
26 | ||                 .max_size(8)
27 | ||                 .build(ConnectionManager::new("yourconnectionstring"))
28 | ||                 .expect("failed to create db connection_pool")
   | ||______________________________________________________________- temporary value created here
29 |  |         }
   |  |_________^ returns a value referencing data owned by the current function

It is impossible to find a clean simple example on how to use Diesel & Postgres with a connection pool :grimacing:.

Can you post more context?

Yes for sure. This is the code provided by copsevane. That doesn't compile

// utils.rs
use lazy_static;
use diesel::{
   r2d2::{Pool, ConnectionManager},
   pg::PgConnection
};

type PgPool = Pool<ConnectionManager<PgConnection>>;

pub struct Values<'a> {
   pub db_connection: PgPool,
}

lazy_static! {
   pub static ref VALUES: Values<'static> = {
       Values {
           db_connection: PgPool::builder()
               .max_size(8)
               .build(ConnectionManager::new("yourconnectionstring"))
               .expect("failed to create db connection_pool")
       }
   };
} 

I am worry to see how hard it is to find proper documentation for such a simple thing. I would like to insert/retrieve one record in one simple table using Diesel-Postgres-R2D2 but everywhere i find documentation on the internet it is too old (i have found things like infer_table! that doesn't exist anymore see diesel - Rust. The documentation talks about macro infer_schema! but i don't see it in the list of macro). Then i find r2d2-diesel but it is written : THIS CRATE HAS BEEN DEPRECATED, USE THE r2d2 MODULE IN DIESEL INSTEAD

This compiles for me:

[package]
name = "dieseltest"
version = "0.1.0"
authors = ["Alice Ryhl <alice@ryhl.io>"]
edition = "2018"

[dependencies]
diesel = { version = "1.0.0", features = ["postgres", "r2d2"] }
lazy_static = "1.4.0"

and rust code:

use lazy_static::lazy_static;
use diesel::{
   r2d2::{Pool, ConnectionManager},
   pg::PgConnection
};

type PgPool = Pool<ConnectionManager<PgConnection>>;

pub struct Values {
   pub db_connection: PgPool,
}

lazy_static! {
   pub static ref VALUES: Values = {
       Values {
           db_connection: PgPool::builder()
               .max_size(8)
               .build(ConnectionManager::new("yourconnectionstring"))
               .expect("failed to create db connection_pool")
       }
   };
}

Are you aware of the diesel.rs website? It might not have anything on r2d2, but it has a bunch of guides.

4 Likes

good catch! forgot to remove it, thanks
in my actual code i have some &str members in the values struct which need a lifetime

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.