#gotham #database-access #diesel #connection-pool #web #async #http

gotham_middleware_diesel

A Gotham Middleware that provides access to a Diesel connection via an R2D2 pool to allow other Middleware and Handlers to interact with a database

7 releases (4 breaking)

0.5.1 Sep 12, 2023
0.5.0 Nov 6, 2022
0.4.0 Nov 12, 2021
0.3.1 Jul 12, 2021
0.1.0 Jul 27, 2019

#639 in HTTP server

Download history 62/week @ 2024-07-22 44/week @ 2024-07-29 15/week @ 2024-08-05 8/week @ 2024-08-12 9/week @ 2024-08-19 35/week @ 2024-08-26 17/week @ 2024-09-02 8/week @ 2024-09-09 75/week @ 2024-09-23 42/week @ 2024-09-30 32/week @ 2024-10-07 122/week @ 2024-10-14 33/week @ 2024-10-21 124/week @ 2024-10-28 108/week @ 2024-11-04

388 downloads per month
Used in gotham_restful

MIT/Apache

570KB
10K SLoC

Gotham Diesel Middleware

The gotham diesel middleware provides offers a convenient API for interacting with Diesel from Gotham.

Usage:

This middleware introduces a Repo struct, which is used as a layer between Diesel and Gotham to ensure that database interaction can be easily chained alongside other asynchronous operations. This structure is fairly straightfoward and offers an easy way to interact with Diesel from inside Gotham:

// create a new repo, in this case just using a SQLite setup
let repo: Repo<SqliteConnection> = Repo::new("products.db");

// create a middleware pipeline from our middleware
let pipeline = single_middleware(DieselMiddleware::new(repo));

// construct a basic chain from our pipeline
let (chain, pipelines) = single_pipeline(pipeline);

// build a router with the chain & pipeline
gotham::start("127.0.0.1:7878", build_router(chain, pipelines, |route| {
    route.get("/").to(say_hello);
}))

From there you gain simple access to Repo on the request state, just like when using other middlewares. You can then use the Repo to execute database calls:

// borrow the repo from the state
let repo = Repo::borrow_from(&state);

// execute database calls
repo.run(move |conn| {
    diesel::insert_into(products::table)
        .values(&product)
        .execute(&conn)
})

repo.run returns a Future, allowing you to seamlessly sprinkle your database calls amongst other asynchronous handler code. The Repo type manages the synchronous calls of the underlying connections using tokio::task::spawn_blocking, which allows blocking operations to run without blocking the tokio reactor. Although not true async, this allows multiple concurrent database requests to be handled, with a default of 100 concurrent blocking operations. For further details see tokio::task::spawn_blocking documentation.

For a complete example, see the example in the main repository.

Configuration

To customize aspects of the connection pool, you can construct a repo from an r2d2::Builder, setting any attributes available on there:

let repo = Repo::from_pool_builder(database_url,
    Pool::builder()
        .connection_timeout(Duration::from_secs(120))
        .max_size(100)

Isolated test transactions

When used in tests, the middleware can use isolated test transactions to allow tests to run in parallel. In test transactions, queries from separate connections do not interfere with each other and are rolled back when the connection is dropped at the end of each test.

#[test]
fn do_something() {
    let repo = Repo::with_test_transactions(DATABASE_URL);
    // Run some test code that accesses the repo.
    // This test will be isolated, and at the end the transaction rolled back.
}

See full example in the main repository linked above for more details.

Dependencies

~13–24MB
~335K SLoC