From 9a9cd76c0121f46765ff0df9ef81e36563a2a31f Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Fri, 9 Jun 2023 16:46:24 -0700 Subject: [PATCH] Add support for 'diesel-async' to 'db_pools'. --- contrib/db_pools/lib/Cargo.toml | 13 ++ contrib/db_pools/lib/src/diesel.rs | 149 ++++++++++++++++++ contrib/db_pools/lib/src/lib.rs | 34 ++-- contrib/db_pools/lib/src/pool.rs | 17 ++ contrib/sync_db_pools/codegen/Cargo.toml | 3 +- .../ui-fail-nightly/database-syntax.stderr | 50 +++--- .../ui-fail-nightly/database-types.stderr | 4 - .../ui-fail-stable/database-syntax.stderr | 50 +++--- .../ui-fail-stable/database-types.stderr | 4 - .../codegen/tests/ui-fail/database-syntax.rs | 35 +++- contrib/sync_db_pools/lib/src/poolable.rs | 1 + .../tests/ui-fail-stable/async-entry.stderr | 5 +- examples/databases/Cargo.toml | 6 +- examples/databases/Rocket.toml | 3 + .../down.sql | 1 + .../20210329150332_create_posts_table/up.sql | 6 + examples/databases/src/diesel_mysql.rs | 97 ++++++++++++ examples/databases/src/diesel_sqlite.rs | 4 +- examples/databases/src/main.rs | 10 ++ scripts/test.sh | 2 + 20 files changed, 410 insertions(+), 84 deletions(-) create mode 100644 contrib/db_pools/lib/src/diesel.rs create mode 100644 examples/databases/db/diesel/mysql-migrations/20210329150332_create_posts_table/down.sql create mode 100644 examples/databases/db/diesel/mysql-migrations/20210329150332_create_posts_table/up.sql create mode 100644 examples/databases/src/diesel_mysql.rs diff --git a/contrib/db_pools/lib/Cargo.toml b/contrib/db_pools/lib/Cargo.toml index 19ad8b23f1..af9efca2fb 100644 --- a/contrib/db_pools/lib/Cargo.toml +++ b/contrib/db_pools/lib/Cargo.toml @@ -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] @@ -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 diff --git a/contrib/db_pools/lib/src/diesel.rs b/contrib/db_pools/lib/src/diesel.rs new file mode 100644 index 0000000000..89c606be97 --- /dev/null +++ b/contrib/db_pools/lib/src/diesel.rs @@ -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) -> QueryResult { +//! let post_ids: Vec = 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> = Result; + +/// 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) { +/// /* .. */ +/// } +/// # } +/// ``` +#[cfg(feature = "diesel_mysql")] +pub type MysqlPool = Pool; + +/// 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) { +/// /* .. */ +/// } +/// # } +/// ``` +#[cfg(feature = "diesel_postgres")] +pub type PgPool = Pool; diff --git a/contrib/db_pools/lib/src/lib.rs b/contrib/db_pools/lib/src/lib.rs index 5130097d45..d79fa4ea05 100644 --- a/contrib/db_pools/lib/src/lib.rs +++ b/contrib/db_pools/lib/src/lib.rs @@ -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) //! @@ -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`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html -//! [`sqlx::PoolConnection`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html -//! [`sqlx::PoolConnection`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html -//! [`sqlx::PoolConnection`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html +//! [`sqlx::pool::PoolConnection`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html +//! [`sqlx::pool::PoolConnection`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html +//! [`sqlx::pool::PoolConnection`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html +//! [`sqlx::pool::PoolConnection`]: https://docs.rs/sqlx/0.6/sqlx/pool/struct.PoolConnection.html //! //! On shutdown, new connections are denied. Shutdown waits for connections to //! be returned. @@ -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 @@ -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 @@ -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; diff --git a/contrib/db_pools/lib/src/pool.rs b/contrib/db_pools/lib/src/pool.rs index d07a0f13ff..49d298cba1 100644 --- a/contrib/db_pools/lib/src/pool.rs +++ b/contrib/db_pools/lib/src/pool.rs @@ -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; } @@ -175,6 +178,20 @@ mod deadpool_postgres { } } + #[cfg(feature = "diesel_postgres")] + impl DeadManager for AsyncDieselConnectionManager { + fn new(config: &Config) -> Result { + Ok(Self::new(config.url.as_str())) + } + } + + #[cfg(feature = "diesel_mysql")] + impl DeadManager for AsyncDieselConnectionManager { + fn new(config: &Config) -> Result { + Ok(Self::new(config.url.as_str())) + } + } + #[rocket::async_trait] impl>> crate::Pool for Pool where M::Type: Send, C: Send + Sync + 'static, M::Error: std::error::Error diff --git a/contrib/sync_db_pools/codegen/Cargo.toml b/contrib/sync_db_pools/codegen/Cargo.toml index ad6a9818d9..cee6a484ef 100644 --- a/contrib/sync_db_pools/codegen/Cargo.toml +++ b/contrib/sync_db_pools/codegen/Cargo.toml @@ -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" } diff --git a/contrib/sync_db_pools/codegen/tests/ui-fail-nightly/database-syntax.stderr b/contrib/sync_db_pools/codegen/tests/ui-fail-nightly/database-syntax.stderr index e89220bded..1528e2a77f 100644 --- a/contrib/sync_db_pools/codegen/tests/ui-fail-nightly/database-syntax.stderr +++ b/contrib/sync_db_pools/codegen/tests/ui-fail-nightly/database-syntax.stderr @@ -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); +52 | struct F(T); | ^^^ diff --git a/contrib/sync_db_pools/codegen/tests/ui-fail-nightly/database-types.stderr b/contrib/sync_db_pools/codegen/tests/ui-fail-nightly/database-types.stderr index 1e4e92ac8d..64be8774fe 100644 --- a/contrib/sync_db_pools/codegen/tests/ui-fail-nightly/database-types.stderr +++ b/contrib/sync_db_pools/codegen/tests/ui-fail-nightly/database-types.stderr @@ -4,7 +4,6 @@ error[E0277]: the trait bound `Unknown: Poolable` is not satisfied 6 | struct A(Unknown); | ^^^^^^^ the trait `Poolable` is not implemented for `Unknown` | - = help: the trait `Poolable` is implemented for `SqliteConnection` note: required by a bound in `rocket_sync_db_pools::Connection` --> $WORKSPACE/contrib/sync_db_pools/lib/src/connection.rs | @@ -17,7 +16,6 @@ error[E0277]: the trait bound `Vec: Poolable` is not satisfied 9 | struct B(Vec); | ^^^^^^^^ the trait `Poolable` is not implemented for `Vec` | - = help: the trait `Poolable` is implemented for `SqliteConnection` note: required by a bound in `rocket_sync_db_pools::Connection` --> $WORKSPACE/contrib/sync_db_pools/lib/src/connection.rs | @@ -30,7 +28,6 @@ error[E0277]: the trait bound `Unknown: Poolable` is not satisfied 6 | struct A(Unknown); | ^^^^^^^ the trait `Poolable` is not implemented for `Unknown` | - = help: the trait `Poolable` is implemented for `SqliteConnection` note: required by a bound in `ConnectionPool` --> $WORKSPACE/contrib/sync_db_pools/lib/src/connection.rs | @@ -43,7 +40,6 @@ error[E0277]: the trait bound `Vec: Poolable` is not satisfied 9 | struct B(Vec); | ^^^^^^^^ the trait `Poolable` is not implemented for `Vec` | - = help: the trait `Poolable` is implemented for `SqliteConnection` note: required by a bound in `ConnectionPool` --> $WORKSPACE/contrib/sync_db_pools/lib/src/connection.rs | diff --git a/contrib/sync_db_pools/codegen/tests/ui-fail-stable/database-syntax.stderr b/contrib/sync_db_pools/codegen/tests/ui-fail-stable/database-syntax.stderr index 6e5323157d..9523d0ca86 100644 --- a/contrib/sync_db_pools/codegen/tests/ui-fail-stable/database-syntax.stderr +++ b/contrib/sync_db_pools/codegen/tests/ui-fail-stable/database-syntax.stderr @@ -1,56 +1,56 @@ error: unexpected end of input, expected string literal - --> tests/ui-fail-stable/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-stable/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-stable/database-syntax.rs:9:12 - | -9 | #[database(1)] - | ^ + --> tests/ui-fail-stable/database-syntax.rs:30:12 + | +30 | #[database(1)] + | ^ error: expected string literal - --> tests/ui-fail-stable/database-syntax.rs:12:12 + --> tests/ui-fail-stable/database-syntax.rs:33:12 | -12 | #[database(123)] +33 | #[database(123)] | ^^^ error: unexpected token - --> tests/ui-fail-stable/database-syntax.rs:15:20 + --> tests/ui-fail-stable/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-stable/database-syntax.rs:19:1 + --> tests/ui-fail-stable/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 --- help: example: `struct MyDatabase(diesel::SqliteConnection);` - --> tests/ui-fail-stable/database-syntax.rs:22:11 + --> tests/ui-fail-stable/database-syntax.rs:43:11 | -22 | struct Bar(diesel::SqliteConnection, diesel::SqliteConnection); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +43 | struct Bar(Connection, Connection); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `database` attribute can only be used on structs - --> tests/ui-fail-stable/database-syntax.rs:25:1 + --> tests/ui-fail-stable/database-syntax.rs:46:1 | -25 | union Baz { } +46 | union Baz { } | ^^^^^ error: `database` attribute cannot be applied to structs with generics - --> tests/ui-fail-stable/database-syntax.rs:28:9 + --> tests/ui-fail-stable/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-stable/database-syntax.rs:31:9 + --> tests/ui-fail-stable/database-syntax.rs:52:9 | -31 | struct F(T); +52 | struct F(T); | ^ diff --git a/contrib/sync_db_pools/codegen/tests/ui-fail-stable/database-types.stderr b/contrib/sync_db_pools/codegen/tests/ui-fail-stable/database-types.stderr index 7a4cead305..c699597e88 100644 --- a/contrib/sync_db_pools/codegen/tests/ui-fail-stable/database-types.stderr +++ b/contrib/sync_db_pools/codegen/tests/ui-fail-stable/database-types.stderr @@ -4,7 +4,6 @@ error[E0277]: the trait bound `Unknown: Poolable` is not satisfied 6 | struct A(Unknown); | ^^^^^^^ the trait `Poolable` is not implemented for `Unknown` | - = help: the trait `Poolable` is implemented for `SqliteConnection` note: required by a bound in `rocket_sync_db_pools::Connection` --> $WORKSPACE/contrib/sync_db_pools/lib/src/connection.rs | @@ -17,7 +16,6 @@ error[E0277]: the trait bound `Vec: Poolable` is not satisfied 9 | struct B(Vec); | ^^^ the trait `Poolable` is not implemented for `Vec` | - = help: the trait `Poolable` is implemented for `SqliteConnection` note: required by a bound in `rocket_sync_db_pools::Connection` --> $WORKSPACE/contrib/sync_db_pools/lib/src/connection.rs | @@ -30,7 +28,6 @@ error[E0277]: the trait bound `Unknown: Poolable` is not satisfied 6 | struct A(Unknown); | ^^^^^^^ the trait `Poolable` is not implemented for `Unknown` | - = help: the trait `Poolable` is implemented for `SqliteConnection` note: required by a bound in `ConnectionPool` --> $WORKSPACE/contrib/sync_db_pools/lib/src/connection.rs | @@ -43,7 +40,6 @@ error[E0277]: the trait bound `Vec: Poolable` is not satisfied 9 | struct B(Vec); | ^^^ the trait `Poolable` is not implemented for `Vec` | - = help: the trait `Poolable` is implemented for `SqliteConnection` note: required by a bound in `ConnectionPool` --> $WORKSPACE/contrib/sync_db_pools/lib/src/connection.rs | diff --git a/contrib/sync_db_pools/codegen/tests/ui-fail/database-syntax.rs b/contrib/sync_db_pools/codegen/tests/ui-fail/database-syntax.rs index 20af9ee185..1add1d0d6c 100644 --- a/contrib/sync_db_pools/codegen/tests/ui-fail/database-syntax.rs +++ b/contrib/sync_db_pools/codegen/tests/ui-fail/database-syntax.rs @@ -1,25 +1,46 @@ use rocket_sync_db_pools::database; -#[allow(unused_imports)] -use rocket_sync_db_pools::diesel; +struct Connection; +struct Manager; + +use rocket::{Rocket, Build}; +use rocket_sync_db_pools::{r2d2, Poolable, PoolResult}; + +impl r2d2::ManageConnection for Manager { + type Connection = Connection; + type Error = std::convert::Infallible; + + fn connect(&self) -> Result { Ok(Connection) } + fn is_valid(&self, conn: &mut Self::Connection) -> Result<(), Self::Error> { Ok(()) } + fn has_broken(&self, conn: &mut Self::Connection) -> bool { true } +} + +impl Poolable for Connection { + type Manager = Manager; + type Error = std::convert::Infallible; + + fn pool(db_name: &str, rocket: &Rocket) -> PoolResult { + todo!() + } +} #[database] -struct A(diesel::SqliteConnection); +struct A(Connection); #[database(1)] -struct B(diesel::SqliteConnection); +struct B(Connection); #[database(123)] -struct C(diesel::SqliteConnection); +struct C(Connection); #[database("hello" "hi")] -struct D(diesel::SqliteConnection); +struct D(Connection); #[database("test")] enum Foo { } #[database("test")] -struct Bar(diesel::SqliteConnection, diesel::SqliteConnection); +struct Bar(Connection, Connection); #[database("test")] union Baz { } diff --git a/contrib/sync_db_pools/lib/src/poolable.rs b/contrib/sync_db_pools/lib/src/poolable.rs index 4e7a34c1a9..0451de60bb 100644 --- a/contrib/sync_db_pools/lib/src/poolable.rs +++ b/contrib/sync_db_pools/lib/src/poolable.rs @@ -1,3 +1,4 @@ +#[allow(unused)] use std::time::Duration; use r2d2::ManageConnection; diff --git a/core/codegen/tests/ui-fail-stable/async-entry.stderr b/core/codegen/tests/ui-fail-stable/async-entry.stderr index d7467aca76..dc1d54d2f2 100644 --- a/core/codegen/tests/ui-fail-stable/async-entry.stderr +++ b/core/codegen/tests/ui-fail-stable/async-entry.stderr @@ -135,8 +135,9 @@ error[E0308]: mismatched types --> tests/ui-fail-stable/async-entry.rs:24:21 | 24 | async fn main() { - | ^ expected `()` because of default return type - | _____________________| + | ^ + | | + | _____________________expected `()` because of default return type | | 25 | | rocket::build() 26 | | } diff --git a/examples/databases/Cargo.toml b/examples/databases/Cargo.toml index 927f64d344..926105d2e8 100644 --- a/examples/databases/Cargo.toml +++ b/examples/databases/Cargo.toml @@ -7,8 +7,8 @@ publish = false [dependencies] rocket = { path = "../../core/lib", features = ["json"] } -diesel = { version = "2.0.0", features = ["sqlite", "r2d2"] } -diesel_migrations = "2.0.0" +diesel = "2" +diesel_migrations = "2" [dependencies.sqlx] version = "0.6.0" @@ -17,7 +17,7 @@ features = ["macros", "offline", "migrate"] [dependencies.rocket_db_pools] path = "../../contrib/db_pools/lib/" -features = ["sqlx_sqlite"] +features = ["sqlx_sqlite", "diesel_mysql"] [dependencies.rocket_sync_db_pools] path = "../../contrib/sync_db_pools/lib/" diff --git a/examples/databases/Rocket.toml b/examples/databases/Rocket.toml index 1409c8841d..278fdbd997 100644 --- a/examples/databases/Rocket.toml +++ b/examples/databases/Rocket.toml @@ -7,3 +7,6 @@ url = "db/sqlx/db.sqlite" [default.databases.diesel] url = "db/diesel/db.sqlite" timeout = 10 + +[default.databases.diesel_mysql] +url = "mysql://user:password@127.0.0.1/database" diff --git a/examples/databases/db/diesel/mysql-migrations/20210329150332_create_posts_table/down.sql b/examples/databases/db/diesel/mysql-migrations/20210329150332_create_posts_table/down.sql new file mode 100644 index 0000000000..1651d89549 --- /dev/null +++ b/examples/databases/db/diesel/mysql-migrations/20210329150332_create_posts_table/down.sql @@ -0,0 +1 @@ +DROP TABLE posts; diff --git a/examples/databases/db/diesel/mysql-migrations/20210329150332_create_posts_table/up.sql b/examples/databases/db/diesel/mysql-migrations/20210329150332_create_posts_table/up.sql new file mode 100644 index 0000000000..005109e20e --- /dev/null +++ b/examples/databases/db/diesel/mysql-migrations/20210329150332_create_posts_table/up.sql @@ -0,0 +1,6 @@ +CREATE TABLE posts ( + id INTEGER AUTO_INCREMENT PRIMARY KEY, + title VARCHAR(255) NOT NULL, + text TEXT NOT NULL, + published BOOLEAN NOT NULL DEFAULT FALSE +); diff --git a/examples/databases/src/diesel_mysql.rs b/examples/databases/src/diesel_mysql.rs new file mode 100644 index 0000000000..6c6c7751f0 --- /dev/null +++ b/examples/databases/src/diesel_mysql.rs @@ -0,0 +1,97 @@ +use rocket::fairing::AdHoc; +use rocket::response::{Debug, status::Created}; +use rocket::serde::{Serialize, Deserialize, json::Json}; + +use rocket_db_pools::{Database, Connection}; +use rocket_db_pools::diesel::{MysqlPool, prelude::*}; + +type Result> = std::result::Result; + +#[derive(Database)] +#[database("diesel_mysql")] +struct Db(MysqlPool); + +#[derive(Debug, Clone, Deserialize, Serialize, Queryable, Insertable)] +#[serde(crate = "rocket::serde")] +#[diesel(table_name = posts)] +struct Post { + #[serde(skip_deserializing)] + id: Option, + title: String, + text: String, + #[serde(skip_deserializing)] + published: bool, +} + +diesel::table! { + posts (id) { + id -> Nullable, + title -> Text, + text -> Text, + published -> Bool, + } +} + +#[post("/", data = "")] +async fn create(mut db: Connection, mut post: Json) -> Result>> { + diesel::sql_function!(fn last_insert_id() -> BigInt); + + let post = db.transaction(|mut conn| Box::pin(async move { + diesel::insert_into(posts::table) + .values(&*post) + .execute(&mut conn) + .await?; + + post.id = Some(posts::table + .select(last_insert_id()) + .first(&mut conn) + .await?); + + Ok::<_, diesel::result::Error>(post) + })).await?; + + Ok(Created::new("/").body(post)) +} + +#[get("/")] +async fn list(mut db: Connection) -> Result>>> { + let ids = posts::table + .select(posts::id) + .load(&mut db) + .await?; + + Ok(Json(ids)) +} + +#[get("/")] +async fn read(mut db: Connection, id: i64) -> Option> { + posts::table + .filter(posts::id.eq(id)) + .first(&mut db) + .await + .map(Json) + .ok() +} + +#[delete("/")] +async fn delete(mut db: Connection, id: i64) -> Result> { + let affected = diesel::delete(posts::table) + .filter(posts::id.eq(id)) + .execute(&mut db) + .await?; + + Ok((affected == 1).then(|| ())) +} + +#[delete("/")] +async fn destroy(mut db: Connection) -> Result<()> { + diesel::delete(posts::table).execute(&mut db).await?; + Ok(()) +} + +pub fn stage() -> AdHoc { + AdHoc::on_ignite("Diesel SQLite Stage", |rocket| async { + rocket.attach(Db::init()) + .mount("/diesel-async/", routes![list, read, create, delete, destroy]) + }) +} diff --git a/examples/databases/src/diesel_sqlite.rs b/examples/databases/src/diesel_sqlite.rs index c64d8edf6a..1427729a27 100644 --- a/examples/databases/src/diesel_sqlite.rs +++ b/examples/databases/src/diesel_sqlite.rs @@ -3,9 +3,7 @@ use rocket::fairing::AdHoc; use rocket::response::{Debug, status::Created}; use rocket::serde::{Serialize, Deserialize, json::Json}; -use rocket_sync_db_pools::diesel; - -use self::diesel::prelude::*; +use diesel::prelude::*; #[database("diesel")] struct Db(diesel::SqliteConnection); diff --git a/examples/databases/src/main.rs b/examples/databases/src/main.rs index 8748f22d1c..8491e01bb1 100644 --- a/examples/databases/src/main.rs +++ b/examples/databases/src/main.rs @@ -5,12 +5,22 @@ mod sqlx; mod diesel_sqlite; +mod diesel_mysql; mod rusqlite; +use rocket::response::Redirect; + +#[get("/")] +fn index() -> Redirect { + Redirect::to(uri!("/sqlx", sqlx::list())) +} + #[launch] fn rocket() -> _ { rocket::build() + .mount("/", routes![index]) .attach(sqlx::stage()) .attach(rusqlite::stage()) .attach(diesel_sqlite::stage()) + .attach(diesel_mysql::stage()) } diff --git a/scripts/test.sh b/scripts/test.sh index b691dab980..1532ee47c3 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -82,6 +82,8 @@ function test_contrib() { sqlx_sqlite sqlx_mssql mongodb + diesel_mysql + diesel_postgres ) SYNC_DB_POOLS_FEATURES=(