Skip to content

Commit

Permalink
Add support for 'diesel-async' to 'db_pools'.
Browse files Browse the repository at this point in the history
  • Loading branch information
SergioBenitez committed Jun 9, 2023
1 parent 792bab2 commit 9a9cd76
Show file tree
Hide file tree
Showing 20 changed files with 410 additions and 84 deletions.
13 changes: 13 additions & 0 deletions contrib/db_pools/lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ sqlx_postgres = ["sqlx", "sqlx/postgres"]
sqlx_sqlite = ["sqlx", "sqlx/sqlite"]
sqlx_mssql = ["sqlx", "sqlx/mssql"]
sqlx_macros = ["sqlx/macros"]
# diesel features
diesel_postgres = ["diesel-async/postgres", "diesel-async/deadpool", "diesel", "deadpool"]
diesel_mysql = ["diesel-async/mysql", "diesel-async/deadpool", "diesel", "deadpool"]
# implicit features: mongodb

[dependencies.rocket]
Expand Down Expand Up @@ -58,6 +61,16 @@ default-features = false
features = ["tokio-runtime"]
optional = true

[dependencies.diesel-async]
version = "0.3.1"
default-features = false
optional = true

[dependencies.diesel]
version = "2.1"
default-features = false
optional = true

[dependencies.sqlx]
version = "0.6"
default-features = false
Expand Down
149 changes: 149 additions & 0 deletions contrib/db_pools/lib/src/diesel.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
//! Re-export of [`diesel`] with prelude types overridden with `async` variants
//! from [`diesel_async`].
//!
//! # Usage
//!
//! To use `async` `diesel` support provided here, enable the following
//! dependencies in your `Cargo.toml`:
//!
//! ```toml
//! [dependencies]
//! rocket = "=0.5.0-rc.3"
//! diesel = "2"
//!
//! [dependencies.rocket_db_pools]
//! version = "=0.1.0-rc.3"
//! features = ["diesel_mysql"]
//! ```
//!
//! Then, import `rocket_db_pools::diesel::prelude::*` as well as the
//! appropriate pool type and, optionally, [`QueryResult`]. To use macros or
//! `diesel` functions, use `diesel::` directly. That is, _do not_ import
//! `rocket_db_pools::diesel`. Doing so will, by design, cause import errors.
//!
//! # Example
//!
//! ```rust
//! # #[macro_use] extern crate rocket;
//! # #[cfg(feature = "diesel_mysql")] {
//! use rocket_db_pools::{Database, Connection};
//! use rocket_db_pools::diesel::{QueryResult, MysqlPool, prelude::*};
//!
//! #[derive(Database)]
//! #[database("diesel_mysql")]
//! struct Db(MysqlPool);
//!
//! #[derive(Queryable, Insertable)]
//! #[diesel(table_name = posts)]
//! struct Post {
//! id: i64,
//! title: String,
//! published: bool,
//! }
//!
//! diesel::table! {
//! posts (id) {
//! id -> BigInt,
//! title -> Text,
//! published -> Bool,
//! }
//! }
//!
//! #[get("/")]
//! async fn list(mut db: Connection<Db>) -> QueryResult<String> {
//! let post_ids: Vec<i64> = posts::table
//! .select(posts::id)
//! .load(&mut db)
//! .await?;
//!
//! Ok(format!("{post_ids:?}"))
//! }
//! # }
//! ```

/// The [`diesel`] prelude with `sync`-only traits replaced with their
/// [`diesel_async`] variants.
pub mod prelude {
#[doc(inline)]
pub use diesel::prelude::*;

#[doc(inline)]
pub use diesel_async::{AsyncConnection, RunQueryDsl, SaveChangesDsl};
}

#[doc(hidden)]
pub use diesel::*;

#[doc(hidden)]
pub use diesel_async::{RunQueryDsl, SaveChangesDsl, *};

#[doc(hidden)]
#[cfg(feature = "diesel_postgres")]
pub use diesel_async::pg;

#[doc(inline)]
pub use diesel_async::pooled_connection::deadpool::Pool;

#[doc(inline)]
#[cfg(feature = "diesel_mysql")]
pub use diesel_async::AsyncMysqlConnection;

#[doc(inline)]
#[cfg(feature = "diesel_postgres")]
pub use diesel_async::AsyncPgConnection;

/// Alias of a `Result` with an error type of [`Debug`] for a `diesel::Error`.
///
/// `QueryResult` is a [`Responder`](rocket::response::Responder) when `T` (the
/// `Ok` value) is a `Responder`. By using this alias as a route handler's
/// return type, the `?` operator can be applied to fallible `diesel` functions
/// in the route handler while still providing a valid `Responder` return type.
///
/// See the [module level docs](self#example) for a usage example.
///
/// [`Debug`]: rocket::response::Debug
pub type QueryResult<T, E = rocket::response::Debug<diesel::result::Error>> = Result<T, E>;

/// Type alias for an `async` pool of MySQL connections for `async` [diesel].
///
/// ```rust
/// # extern crate rocket;
/// # #[cfg(feature = "diesel_mysql")] {
/// # use rocket::get;
/// use rocket_db_pools::{Database, Connection};
/// use rocket_db_pools::diesel::{MysqlPool, prelude::*};
///
/// #[derive(Database)]
/// #[database("my_mysql_db_name")]
/// struct Db(MysqlPool);
///
/// #[get("/")]
/// async fn use_db(mut db: Connection<Db>) {
/// /* .. */
/// }
/// # }
/// ```
#[cfg(feature = "diesel_mysql")]
pub type MysqlPool = Pool<AsyncMysqlConnection>;

/// Type alias for an `async` pool of Postgres connections for `async` [diesel].
///
/// ```rust
/// # extern crate rocket;
/// # #[cfg(feature = "diesel_postgres")] {
/// # use rocket::get;
/// use rocket_db_pools::{Database, Connection};
/// use rocket_db_pools::diesel::{PgPool, prelude::*};
///
/// #[derive(Database)]
/// #[database("my_pg_db_name")]
/// struct Db(PgPool);
///
/// #[get("/")]
/// async fn use_db(mut db: Connection<Db>) {
/// /* .. */
/// }
/// # }
/// ```
#[cfg(feature = "diesel_postgres")]
pub type PgPool = Pool<AsyncPgConnection>;
34 changes: 24 additions & 10 deletions contrib/db_pools/lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@
//!
//! # Supported Drivers
//!
//! At present, this crate supports _three_ drivers: [`deadpool`], [`sqlx`], and
//! [`mongodb`]. Each driver may support multiple databases. Drivers have a
//! varying degree of support for graceful shutdown, affected by the
//! `Type::init()` fairing on Rocket shutdown.
//! At present, this crate supports _four_ drivers: [`deadpool`], [`sqlx`],
//! [`mongodb`], and [`diesel`]. Each driver may support multiple databases.
//! Drivers have a varying degree of support for graceful shutdown, affected by
//! the `Type::init()` fairing on Rocket shutdown.
//!
//! ## `deadpool` (v0.9)
//!
Expand All @@ -126,10 +126,10 @@
//! [`sqlx::MySqlPool`]: https://docs.rs/sqlx/0.6/sqlx/type.MySqlPool.html
//! [`sqlx::SqlitePool`]: https://docs.rs/sqlx/0.6/sqlx/type.SqlitePool.html
//! [`sqlx::MssqlPool`]: https://docs.rs/sqlx/0.6/sqlx/type.MssqlPool.html
//! [`sqlx::PoolConnection<Postgres>`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html
//! [`sqlx::PoolConnection<MySql>`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html
//! [`sqlx::PoolConnection<Sqlite>`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html
//! [`sqlx::PoolConnection<Mssql>`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html
//! [`sqlx::pool::PoolConnection<Postgres>`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html
//! [`sqlx::pool::PoolConnection<MySql>`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html
//! [`sqlx::pool::PoolConnection<Sqlite>`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html
//! [`sqlx::pool::PoolConnection<Mssql>`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html
//!
//! On shutdown, new connections are denied. Shutdown waits for connections to
//! be returned.
Expand All @@ -142,6 +142,18 @@
//!
//! Graceful shutdown is not supported.
//!
//! ## `diesel` (v2)
//!
//! | Database | Feature | [`Pool`] Type | [`Connection`] Deref |
//! |----------|-------------------|-----------------------|----------------------------------|
//! | Postgres | `diesel_postgres` | [`diesel::PgPool`] | [`diesel::AsyncPgConnection`] |
//! | MySQL | `diesel_mysql` | [`diesel::MysqlPool`] | [`diesel::AsyncMysqlConnection`] | //!
//!
//! See [`diesel`] for usage details.
//!
//! On shutdown, new connections are denied. Shutdown _does not_ wait for
//! connections to be returned.
//!
//! ## Enabling Additional Driver Features
//!
//! Only the minimal features for each driver crate are enabled by
Expand Down Expand Up @@ -186,7 +198,7 @@
//!
//! See [`Config`] for details on configuration parameters.
//!
//! **Note:** `deadpool` drivers do not support and thus ignore the
//! **Note:** `deadpool` and `diesel` drivers do not support and thus ignore the
//! `min_connections` value.
//!
//! ## Driver Defaults
Expand Down Expand Up @@ -225,11 +237,13 @@

#![deny(missing_docs)]

pub use rocket;

/// Re-export of the `figment` crate.
#[doc(inline)]
pub use rocket::figment;

pub use rocket;
#[cfg(any(feature = "diesel_postgres", feature = "diesel_mysql"))] pub mod diesel;
#[cfg(feature = "deadpool_postgres")] pub use deadpool_postgres;
#[cfg(feature = "deadpool_redis")] pub use deadpool_redis;
#[cfg(feature = "mongodb")] pub use mongodb;
Expand Down
17 changes: 17 additions & 0 deletions contrib/db_pools/lib/src/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ mod deadpool_postgres {
use deadpool::{managed::{Manager, Pool, PoolError, Object, BuildError}, Runtime};
use super::{Duration, Error, Config, Figment};

#[cfg(any(feature = "diesel_postgres", feature = "diesel_mysql"))]
use diesel_async::pooled_connection::AsyncDieselConnectionManager;

pub trait DeadManager: Manager + Sized + Send + Sync + 'static {
fn new(config: &Config) -> Result<Self, Self::Error>;
}
Expand All @@ -175,6 +178,20 @@ mod deadpool_postgres {
}
}

#[cfg(feature = "diesel_postgres")]
impl DeadManager for AsyncDieselConnectionManager<diesel_async::AsyncPgConnection> {
fn new(config: &Config) -> Result<Self, Self::Error> {
Ok(Self::new(config.url.as_str()))
}
}

#[cfg(feature = "diesel_mysql")]
impl DeadManager for AsyncDieselConnectionManager<diesel_async::AsyncMysqlConnection> {
fn new(config: &Config) -> Result<Self, Self::Error> {
Ok(Self::new(config.url.as_str()))
}
}

#[rocket::async_trait]
impl<M: DeadManager, C: From<Object<M>>> crate::Pool for Pool<M, C>
where M::Type: Send, C: Send + Sync + 'static, M::Error: std::error::Error
Expand Down
3 changes: 2 additions & 1 deletion contrib/sync_db_pools/codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,5 @@ devise = "0.4"
[dev-dependencies]
version_check = "0.9"
trybuild = "1.0"
rocket_sync_db_pools = { path = "../lib", features = ["diesel_sqlite_pool"] }
rocket_sync_db_pools = { path = "../lib" }
rocket = { path = "../../../core/lib" }
Original file line number Diff line number Diff line change
@@ -1,57 +1,57 @@
error: unexpected end of input, expected string literal
--> tests/ui-fail-nightly/database-syntax.rs:6:1
|
6 | #[database]
| ^^^^^^^^^^^
|
= note: this error originates in the attribute macro `database` (in Nightly builds, run with -Z macro-backtrace for more info)
--> tests/ui-fail-nightly/database-syntax.rs:27:1
|
27 | #[database]
| ^^^^^^^^^^^
|
= note: this error originates in the attribute macro `database` (in Nightly builds, run with -Z macro-backtrace for more info)

error: expected string literal
--> tests/ui-fail-nightly/database-syntax.rs:9:12
|
9 | #[database(1)]
| ^
--> tests/ui-fail-nightly/database-syntax.rs:30:12
|
30 | #[database(1)]
| ^

error: expected string literal
--> tests/ui-fail-nightly/database-syntax.rs:12:12
--> tests/ui-fail-nightly/database-syntax.rs:33:12
|
12 | #[database(123)]
33 | #[database(123)]
| ^^^

error: unexpected token
--> tests/ui-fail-nightly/database-syntax.rs:15:20
--> tests/ui-fail-nightly/database-syntax.rs:36:20
|
15 | #[database("hello" "hi")]
36 | #[database("hello" "hi")]
| ^^^^

error: `database` attribute can only be used on structs
--> tests/ui-fail-nightly/database-syntax.rs:19:1
--> tests/ui-fail-nightly/database-syntax.rs:40:1
|
19 | enum Foo { }
40 | enum Foo { }
| ^^^^^^^^^^^^^

error: `database` attribute can only be applied to structs with exactly one unnamed field
--> tests/ui-fail-nightly/database-syntax.rs:22:11
--> tests/ui-fail-nightly/database-syntax.rs:43:11
|
22 | struct Bar(diesel::SqliteConnection, diesel::SqliteConnection);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
43 | struct Bar(Connection, Connection);
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: example: `struct MyDatabase(diesel::SqliteConnection);`

error: `database` attribute can only be used on structs
--> tests/ui-fail-nightly/database-syntax.rs:25:1
--> tests/ui-fail-nightly/database-syntax.rs:46:1
|
25 | union Baz { }
46 | union Baz { }
| ^^^^^^^^^^^^^^

error: `database` attribute cannot be applied to structs with generics
--> tests/ui-fail-nightly/database-syntax.rs:28:9
--> tests/ui-fail-nightly/database-syntax.rs:49:9
|
28 | struct E<'r>(&'r str);
49 | struct E<'r>(&'r str);
| ^^^^

error: `database` attribute cannot be applied to structs with generics
--> tests/ui-fail-nightly/database-syntax.rs:31:9
--> tests/ui-fail-nightly/database-syntax.rs:52:9
|
31 | struct F<T>(T);
52 | struct F<T>(T);
| ^^^
Loading

0 comments on commit 9a9cd76

Please sign in to comment.