From 21c99a1677bc5378f7c509eb97abe67baf6372a2 Mon Sep 17 00:00:00 2001 From: Simon Bruder Date: Sun, 7 Jul 2024 14:55:05 +0200 Subject: [PATCH] Use diesel-async This simplifies running queries, as it avoids having to use web::block for everything. --- Cargo.lock | 394 +++++++++++++++++++++++++++++++++---- Cargo.toml | 3 +- src/api/v1/item.rs | 31 ++- src/api/v1/item_class.rs | 35 ++-- src/frontend/item.rs | 41 ++-- src/frontend/item_class.rs | 46 ++--- src/lib.rs | 6 +- src/main.rs | 31 ++- src/manage/item.rs | 42 ++-- src/manage/item_class.rs | 42 ++-- 10 files changed, 508 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a518402..9a147ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f7b0a21988c1bf877cf4759ef5ddaac04c1c9fe808c9142ecb78ba97d97a28a" dependencies = [ - "bitflags", + "bitflags 2.5.0", "bytes", "futures-core", "futures-sink", @@ -29,7 +29,7 @@ dependencies = [ "actix-service", "actix-utils", "actix-web", - "bitflags", + "bitflags 2.5.0", "bytes", "derive_more", "futures-core", @@ -53,8 +53,8 @@ dependencies = [ "actix-service", "actix-utils", "ahash", - "base64", - "bitflags", + "base64 0.22.1", + "bitflags 2.5.0", "brotli", "bytes", "bytestring", @@ -362,6 +362,17 @@ dependencies = [ "nom", ] +[[package]] +name = "async-trait" +version = "0.1.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.3.0" @@ -383,6 +394,12 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "base64" version = "0.22.1" @@ -398,6 +415,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bitflags" version = "2.5.0" @@ -434,6 +457,12 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + [[package]] name = "byteorder" version = "1.5.0" @@ -558,6 +587,23 @@ dependencies = [ "syn", ] +[[package]] +name = "deadpool" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6541a3916932fe57768d4be0b1ffb5ec7cbf74ca8c903fdfd5c0fe8aa958f0ed" +dependencies = [ + "deadpool-runtime", + "num_cpus", + "tokio", +] + +[[package]] +name = "deadpool-runtime" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" + [[package]] name = "deranged" version = "0.3.11" @@ -586,15 +632,27 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62d6dcd069e7b5fe49a302411f759d4cf1cf2c27fe798ef46fb8baefc053dd2b" dependencies = [ - "bitflags", + "bitflags 2.5.0", "byteorder", "diesel_derives", "itoa", - "pq-sys", - "r2d2", "uuid", ] +[[package]] +name = "diesel-async" +version = "0.4.1" +source = "git+https://github.com/weiznich/diesel_async.git#d2fc97dfd4c1a2b54ae07ee115a219be9993103b" +dependencies = [ + "async-trait", + "deadpool", + "diesel", + "futures-util", + "scoped-futures", + "tokio", + "tokio-postgres", +] + [[package]] name = "diesel-derive-enum" version = "2.1.0" @@ -648,6 +706,7 @@ checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", + "subtle", ] [[package]] @@ -666,9 +725,9 @@ dependencies = [ [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encoding_rs" @@ -708,6 +767,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + [[package]] name = "flate2" version = "1.0.30" @@ -733,12 +798,33 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + [[package]] name = "futures-core" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.30" @@ -758,9 +844,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-core", + "futures-macro", + "futures-sink", "futures-task", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -827,6 +916,21 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "http" version = "0.2.12" @@ -918,6 +1022,15 @@ dependencies = [ "libc", ] +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "language-tags" version = "0.3.2" @@ -933,6 +1046,7 @@ dependencies = [ "askama", "askama_actix", "diesel", + "diesel-async", "diesel-derive-enum", "diesel_migrations", "env_logger", @@ -986,6 +1100,16 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.4" @@ -1081,6 +1205,16 @@ dependencies = [ "autocfg", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "object" version = "0.36.0" @@ -1114,7 +1248,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.2", "smallvec", "windows-targets 0.52.5", ] @@ -1131,6 +1265,24 @@ version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher", +] + [[package]] name = "pin-project-lite" version = "0.2.14" @@ -1149,6 +1301,35 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +[[package]] +name = "postgres-protocol" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b6c5ef183cd3ab4ba005f1ca64c21e8bd97ce4699cfea9e8d9a2c4958ca520" +dependencies = [ + "base64 0.21.7", + "byteorder", + "bytes", + "fallible-iterator", + "hmac", + "md-5", + "memchr", + "rand", + "sha2", + "stringprep", +] + +[[package]] +name = "postgres-types" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d2234cdee9408b523530a9b6d2d6b373d1db34f6a8e51dc03ded1828d7fb67c" +dependencies = [ + "bytes", + "fallible-iterator", + "postgres-protocol", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1161,15 +1342,6 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" -[[package]] -name = "pq-sys" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a24ff9e4cf6945c988f0db7005d87747bf72864965c3529d259ad155ac41d584" -dependencies = [ - "vcpkg", -] - [[package]] name = "proc-macro2" version = "1.0.86" @@ -1188,17 +1360,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r2d2" -version = "0.8.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51de85fb3fb6524929c8a2eb85e6b6d363de4e8c48f9e2c2eac4944abc181c93" -dependencies = [ - "log", - "parking_lot", - "scheduled-thread-pool", -] - [[package]] name = "rand" version = "0.8.5" @@ -1229,13 +1390,22 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ - "bitflags", + "bitflags 2.5.0", ] [[package]] @@ -1295,12 +1465,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] -name = "scheduled-thread-pool" -version = "0.2.7" +name = "scoped-futures" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cbc66816425a074528352f5789333ecff06ca41b36b0b0efdfbb29edc391a19" +checksum = "b1473e24c637950c9bd38763220bea91ec3e095a89f672bbd7a10d03e77ba467" dependencies = [ - "parking_lot", + "cfg-if", + "pin-utils", ] [[package]] @@ -1378,6 +1549,17 @@ dependencies = [ "digest", ] +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "signal-hook-registry" version = "1.4.2" @@ -1387,6 +1569,12 @@ dependencies = [ "libc", ] +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + [[package]] name = "slab" version = "0.4.9" @@ -1412,12 +1600,29 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.68" @@ -1492,6 +1697,32 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "tokio-postgres" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d340244b32d920260ae7448cb72b6e238bddc3d4f7603394e7dd46ed8e48f5b8" +dependencies = [ + "async-trait", + "byteorder", + "bytes", + "fallible-iterator", + "futures-channel", + "futures-util", + "log", + "parking_lot", + "percent-encoding", + "phf", + "pin-project-lite", + "postgres-protocol", + "postgres-types", + "rand", + "socket2", + "tokio", + "tokio-util", + "whoami", +] + [[package]] name = "tokio-util" version = "0.7.11" @@ -1595,6 +1826,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-properties" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291" + [[package]] name = "url" version = "2.5.2" @@ -1628,12 +1865,6 @@ version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e8257fbc510f0a46eb602c10215901938b5c2a7d5e70fc11483b1d3c9b5b18c" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" @@ -1646,6 +1877,87 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "whoami" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +dependencies = [ + "redox_syscall 0.4.1", + "wasite", + "web-sys", +] + [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 7e07b2e..b20ce1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,8 @@ actix-files = "0.6.6" actix-web = "4.8.0" askama = { version = "0.12.1", features = ["with-actix-web"] } askama_actix = "0.14.0" -diesel = { version = "2.2.1", features = ["postgres", "r2d2", "uuid"] } +diesel = { version = "2.2.1", features = ["uuid"] } +diesel-async = { git = "https://github.com/weiznich/diesel_async.git", version = "0.4.1", features = ["postgres", "deadpool", "async-connection-wrapper"] } diesel-derive-enum = { version = "2.1.0", features = ["postgres"] } diesel_migrations = { version = "2.2.0", features = ["postgres"] } env_logger = "0.11.3" diff --git a/src/api/v1/item.rs b/src/api/v1/item.rs index e7c07c8..6eb74b8 100644 --- a/src/api/v1/item.rs +++ b/src/api/v1/item.rs @@ -28,18 +28,17 @@ async fn add( // This is not easily possible as getting a connection from a pool returns an r2d2 error // type, while the databse action returns a diesel error type, which are incompatible. // This also affects other functions below. - let item = - web::block(move || manage::item::add(&mut pool.get().unwrap(), new_item.into_inner())) - .await? - .map_err(error::ErrorInternalServerError)?; + let item = manage::item::add(&mut pool.get().await.unwrap(), new_item.into_inner()) + .await + .map_err(error::ErrorInternalServerError)?; Ok(HttpResponse::Ok().json(item)) } #[get("/item")] async fn list(pool: web::Data) -> actix_web::Result { - let items = web::block(move || manage::item::get_all(&mut pool.get().unwrap())) - .await? + let items = manage::item::get_all(&mut pool.get().await.unwrap()) + .await .map_err(error::ErrorInternalServerError)?; Ok(HttpResponse::Ok().json(items)) @@ -49,8 +48,8 @@ async fn list(pool: web::Data) -> actix_web::Result { async fn show(pool: web::Data, path: web::Path) -> actix_web::Result { let id = path.into_inner(); - let item = web::block(move || manage::item::get(&mut pool.get().unwrap(), id)) - .await? + let item = manage::item::get(&mut pool.get().await.unwrap(), id) + .await .map_err(error::ErrorInternalServerError)?; Ok(HttpResponse::Ok().json(item)) @@ -64,11 +63,9 @@ async fn update( ) -> actix_web::Result { let id = path.into_inner(); - let item = web::block(move || { - manage::item::update(&mut pool.get().unwrap(), id, new_item.into_inner()) - }) - .await? - .map_err(error::ErrorInternalServerError)?; + let item = manage::item::update(&mut pool.get().await.unwrap(), id, new_item.into_inner()) + .await + .map_err(error::ErrorInternalServerError)?; Ok(HttpResponse::Ok().json(item)) } @@ -80,8 +77,8 @@ async fn delete( ) -> actix_web::Result { let id = path.into_inner(); - web::block(move || manage::item::delete(&mut pool.get().unwrap(), id)) - .await? + manage::item::delete(&mut pool.get().await.unwrap(), id) + .await .map_err(error::ErrorInternalServerError)?; Ok(HttpResponse::Ok()) @@ -94,8 +91,8 @@ async fn parents( ) -> actix_web::Result { let id = path.into_inner(); - let parents = web::block(move || manage::item::get_parents(&mut pool.get().unwrap(), id)) - .await? + let parents = manage::item::get_parents(&mut pool.get().await.unwrap(), id) + .await .map_err(error::ErrorInternalServerError)?; Ok(HttpResponse::Ok().json(parents)) diff --git a/src/api/v1/item_class.rs b/src/api/v1/item_class.rs index 64fb9ec..22c9314 100644 --- a/src/api/v1/item_class.rs +++ b/src/api/v1/item_class.rs @@ -23,19 +23,18 @@ async fn add( pool: web::Data, new_item_class: web::Json, ) -> actix_web::Result { - let item_class = web::block(move || { - manage::item_class::add(&mut pool.get().unwrap(), new_item_class.into_inner()) - }) - .await? - .map_err(error::ErrorInternalServerError)?; + let item_class = + manage::item_class::add(&mut pool.get().await.unwrap(), new_item_class.into_inner()) + .await + .map_err(error::ErrorInternalServerError)?; Ok(HttpResponse::Ok().json(item_class)) } #[get("/item-class")] async fn list(pool: web::Data) -> actix_web::Result { - let item_classes = web::block(move || manage::item_class::get_all(&mut pool.get().unwrap())) - .await? + let item_classes = manage::item_class::get_all(&mut pool.get().await.unwrap()) + .await .map_err(error::ErrorInternalServerError)?; Ok(HttpResponse::Ok().json(item_classes)) @@ -45,8 +44,8 @@ async fn list(pool: web::Data) -> actix_web::Result { async fn show(pool: web::Data, path: web::Path) -> actix_web::Result { let id = path.into_inner(); - let item_class = web::block(move || manage::item_class::get(&mut pool.get().unwrap(), id)) - .await? + let item_class = manage::item_class::get(&mut pool.get().await.unwrap(), id) + .await .map_err(error::ErrorInternalServerError)?; Ok(HttpResponse::Ok().json(item_class)) @@ -59,8 +58,8 @@ async fn items( ) -> actix_web::Result { let id = path.into_inner(); - let items = web::block(move || manage::item_class::items(&mut pool.get().unwrap(), id)) - .await? + let items = manage::item_class::items(&mut pool.get().await.unwrap(), id) + .await .map_err(error::ErrorInternalServerError)?; Ok(HttpResponse::Ok().json(items)) @@ -74,10 +73,12 @@ async fn update( ) -> actix_web::Result { let id = path.into_inner(); - let item_class = web::block(move || { - manage::item_class::update(&mut pool.get().unwrap(), id, new_item_class.into_inner()) - }) - .await? + let item_class = manage::item_class::update( + &mut pool.get().await.unwrap(), + id, + new_item_class.into_inner(), + ) + .await .map_err(error::ErrorInternalServerError)?; Ok(HttpResponse::Ok().json(item_class)) @@ -90,8 +91,8 @@ async fn delete( ) -> actix_web::Result { let id = path.into_inner(); - web::block(move || manage::item_class::delete(&mut pool.get().unwrap(), id)) - .await? + manage::item_class::delete(&mut pool.get().await.unwrap(), id) + .await .map_err(error::ErrorInternalServerError)?; Ok(HttpResponse::Ok()) diff --git a/src/frontend/item.rs b/src/frontend/item.rs index 4085beb..4515010 100644 --- a/src/frontend/item.rs +++ b/src/frontend/item.rs @@ -37,16 +37,13 @@ async fn show_item( ) -> actix_web::Result { let id = path.into_inner(); - let mut conn = pool.get().unwrap(); - - let item = web::block(move || manage::item::get(&mut conn, id)) - .await? + let item = manage::item::get(&mut pool.get().await.unwrap(), id) + .await .map_err(error::ErrorInternalServerError)?; - let item_class = - web::block(move || manage::item_class::get(&mut pool.get().unwrap(), item.class)) - .await? - .map_err(error::ErrorInternalServerError)?; + let item_class = manage::item_class::get(&mut pool.get().await.unwrap(), item.class) + .await + .map_err(error::ErrorInternalServerError)?; Ok(ItemDetails { req, @@ -68,16 +65,13 @@ async fn list_items( req: HttpRequest, pool: web::Data, ) -> actix_web::Result { - let mut conn = pool.get().unwrap(); - - let items = web::block(move || manage::item::get_all(&mut conn)) - .await? + let items = manage::item::get_all(&mut pool.get().await.unwrap()) + .await .map_err(error::ErrorInternalServerError)?; - let item_classes = - web::block(move || manage::item_class::get_all_as_map(&mut pool.get().unwrap())) - .await? - .map_err(error::ErrorInternalServerError)?; + let item_classes = manage::item_class::get_all_as_map(&mut pool.get().await.unwrap()) + .await + .map_err(error::ErrorInternalServerError)?; Ok(ItemList { req, @@ -103,8 +97,8 @@ async fn add_item_post( data: web::Form, pool: web::Data, ) -> actix_web::Result { - let item = web::block(move || manage::item::add(&mut pool.get().unwrap(), data.into_inner())) - .await? + let item = manage::item::add(&mut pool.get().await.unwrap(), data.into_inner()) + .await .map_err(error::ErrorInternalServerError)?; Ok(web::Redirect::to("/item/".to_owned() + &item.id.to_string()).see_other()) } @@ -124,8 +118,8 @@ async fn edit_item( ) -> actix_web::Result { let id = path.into_inner(); - let item = web::block(move || manage::item::get(&mut pool.get().unwrap(), id)) - .await? + let item = manage::item::get(&mut pool.get().await.unwrap(), id) + .await .map_err(error::ErrorInternalServerError)?; Ok(ItemEditForm { req, item }) @@ -139,10 +133,9 @@ async fn edit_item_post( ) -> actix_web::Result { let id = path.into_inner(); - let item = - web::block(move || manage::item::update(&mut pool.get().unwrap(), id, data.into_inner())) - .await? - .map_err(error::ErrorInternalServerError)?; + let item = manage::item::update(&mut pool.get().await.unwrap(), id, data.into_inner()) + .await + .map_err(error::ErrorInternalServerError)?; Ok(web::Redirect::to("/item/".to_owned() + &item.id.to_string()).see_other()) } diff --git a/src/frontend/item_class.rs b/src/frontend/item_class.rs index c78e8c6..662ef4d 100644 --- a/src/frontend/item_class.rs +++ b/src/frontend/item_class.rs @@ -35,20 +35,18 @@ async fn show_item_class( ) -> actix_web::Result { let id = path.into_inner(); - // FIXME hack - let pool_ = pool.clone(); - - let item_class = web::block(move || manage::item_class::get(&mut pool.get().unwrap(), id)) - .await? + let item_class = manage::item_class::get(&mut pool.clone().get().await.unwrap(), id) + .await .map_err(error::ErrorInternalServerError)?; - let parent = web::block(move || { - item_class.parent.map_or(Ok(None), |id| { - manage::item_class::get(&mut pool_.get().unwrap(), id).map(Some) - }) - }) - .await? - .map_err(error::ErrorInternalServerError)?; + // TODO: Once async closures are stable, use map_or on item_class.parent instead + let parent = match item_class.parent { + Some(id) => manage::item_class::get(&mut pool.get().await.unwrap(), id) + .await + .map(Some) + .map_err(error::ErrorInternalServerError)?, + None => None, + }; Ok(ItemClassDetails { req, @@ -69,8 +67,8 @@ async fn list_item_classes( req: HttpRequest, pool: web::Data, ) -> actix_web::Result { - let item_classes = web::block(move || manage::item_class::get_all(&mut pool.get().unwrap())) - .await? + let item_classes = manage::item_class::get_all(&mut pool.get().await.unwrap()) + .await .map_err(error::ErrorInternalServerError)?; Ok(ItemClassList { req, item_classes }) @@ -93,10 +91,9 @@ async fn add_item_class_post( data: web::Form, pool: web::Data, ) -> actix_web::Result { - let item = - web::block(move || manage::item_class::add(&mut pool.get().unwrap(), data.into_inner())) - .await? - .map_err(error::ErrorInternalServerError)?; + let item = manage::item_class::add(&mut pool.get().await.unwrap(), data.into_inner()) + .await + .map_err(error::ErrorInternalServerError)?; Ok(web::Redirect::to("/item-class/".to_owned() + &item.id.to_string()).see_other()) } @@ -115,8 +112,8 @@ async fn edit_item_class( ) -> actix_web::Result { let id = path.into_inner(); - let item_class = web::block(move || manage::item_class::get(&mut pool.get().unwrap(), id)) - .await? + let item_class = manage::item_class::get(&mut pool.get().await.unwrap(), id) + .await .map_err(error::ErrorInternalServerError)?; Ok(ItemClassEditForm { req, item_class }) @@ -130,11 +127,10 @@ async fn edit_item_class_post( ) -> actix_web::Result { let id = path.into_inner(); - let item_class = web::block(move || { - manage::item_class::update(&mut pool.get().unwrap(), id, data.into_inner()) - }) - .await? - .map_err(error::ErrorInternalServerError)?; + let item_class = + manage::item_class::update(&mut pool.get().await.unwrap(), id, data.into_inner()) + .await + .map_err(error::ErrorInternalServerError)?; Ok(web::Redirect::to("/item-class/".to_owned() + &item_class.id.to_string()).see_other()) } diff --git a/src/lib.rs b/src/lib.rs index 7c33e03..1f834a9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ pub mod manage; pub mod models; pub mod schema; -use diesel::pg::PgConnection; -use diesel::r2d2; +use diesel_async::pg::AsyncPgConnection; +use diesel_async::pooled_connection::deadpool::Pool; -type DbPool = r2d2::Pool>; +type DbPool = Pool; diff --git a/src/main.rs b/src/main.rs index efb4536..2d2a4cd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,28 +5,41 @@ use std::env; use actix_web::{web, App, HttpServer}; -use diesel::prelude::*; -use diesel::r2d2; +use diesel::pg::Pg; +use diesel_async::async_connection_wrapper::AsyncConnectionWrapper; +use diesel_async::pg::AsyncPgConnection; +use diesel_async::pooled_connection::deadpool::Pool; +use diesel_async::pooled_connection::AsyncDieselConnectionManager; +use diesel_async::AsyncConnection; use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; use log::{debug, info}; pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!(); +// adapted from https://github.com/weiznich/diesel_async/blob/002c67e4d09acd9b38d0fb08ff0efc24954b2558/examples/sync-wrapper/src/main.rs#L36-L48 +async fn run_migrations + 'static>(async_connection: A) { + let mut async_wrapper: AsyncConnectionWrapper = + AsyncConnectionWrapper::from(async_connection); + + web::block(move || { + async_wrapper.run_pending_migrations(MIGRATIONS).unwrap(); + }) + .await + .expect("failed to run migrations"); +} + #[actix_web::main] async fn main() -> std::io::Result<()> { env_logger::init(); - let manager = r2d2::ConnectionManager::::new( + let manager = AsyncDieselConnectionManager::::new( env::var("DATABASE_URL").expect("DATABASE_URL must be set"), ); - let pool = r2d2::Pool::builder() - .build(manager) + let pool: Pool = Pool::builder(manager) + .build() .expect("database URL must be valid"); - pool.get() - .expect("couldn’t get db connection from pool") - .run_pending_migrations(MIGRATIONS) - .expect("failed to run migrations"); + run_migrations(pool.get().await.unwrap()).await; let address = env::var("LISTEN_ADDRESS").unwrap_or("::1".to_string()); let port = env::var("LISTEN_PORT").map_or(8080, |s| { diff --git a/src/manage/item.rs b/src/manage/item.rs index 5ddda42..8f439bf 100644 --- a/src/manage/item.rs +++ b/src/manage/item.rs @@ -4,32 +4,41 @@ use std::collections::HashMap; -use diesel::pg::PgConnection; use diesel::prelude::*; +use diesel_async::pg::AsyncPgConnection; +use diesel_async::RunQueryDsl; use uuid::Uuid; use crate::{models::*, schema}; -pub fn add(conn: &mut PgConnection, new_item: NewItem) -> Result { +pub async fn add( + conn: &mut AsyncPgConnection, + new_item: NewItem, +) -> Result { diesel::insert_into(schema::items::table) .values(new_item) .returning(Item::as_returning()) .get_result(conn) + .await } -pub fn get(conn: &mut PgConnection, id: Uuid) -> Result { +pub async fn get(conn: &mut AsyncPgConnection, id: Uuid) -> Result { schema::items::table .filter(schema::items::id.eq(id)) .select(Item::as_select()) .first(conn) + .await } -pub fn get_all(conn: &mut PgConnection) -> Result, diesel::result::Error> { - schema::items::table.select(Item::as_select()).load(conn) +pub async fn get_all(conn: &mut AsyncPgConnection) -> Result, diesel::result::Error> { + schema::items::table + .select(Item::as_select()) + .load(conn) + .await } -pub fn update( - conn: &mut PgConnection, +pub async fn update( + conn: &mut AsyncPgConnection, id: Uuid, modified_item: NewItem, ) -> Result { @@ -37,11 +46,13 @@ pub fn update( .set(modified_item) .returning(Item::as_returning()) .get_result(conn) + .await } -pub fn delete(conn: &mut PgConnection, id: Uuid) -> Result<(), diesel::result::Error> { - let num_deleted = - diesel::delete(schema::items::table.filter(schema::items::id.eq(id))).execute(conn)?; +pub async fn delete(conn: &mut AsyncPgConnection, id: Uuid) -> Result<(), diesel::result::Error> { + let num_deleted = diesel::delete(schema::items::table.filter(schema::items::id.eq(id))) + .execute(conn) + .await?; assert_eq!(num_deleted, 1); Ok(()) } @@ -55,20 +66,25 @@ struct ItemTreeMapping { pub parents: Vec, } -pub fn get_parents(conn: &mut PgConnection, id: Uuid) -> Result, diesel::result::Error> { +pub async fn get_parents( + conn: &mut AsyncPgConnection, + id: Uuid, +) -> Result, diesel::result::Error> { schema::item_tree::table .filter(schema::item_tree::id.eq(id)) .select(ItemTreeMapping::as_select()) .first(conn) + .await .map(|itm| itm.parents) } -pub fn get_all_parents( - conn: &mut PgConnection, +pub async fn get_all_parents( + conn: &mut AsyncPgConnection, ) -> Result>, diesel::result::Error> { schema::item_tree::table .select(ItemTreeMapping::as_select()) .load(conn) + .await .map(|itms| { itms.into_iter() .map(|ItemTreeMapping { id, parents }| (id, parents)) diff --git a/src/manage/item_class.rs b/src/manage/item_class.rs index 12017d3..0fa3c7b 100644 --- a/src/manage/item_class.rs +++ b/src/manage/item_class.rs @@ -4,46 +4,56 @@ use std::collections::HashMap; -use diesel::pg::PgConnection; use diesel::prelude::*; +use diesel_async::pg::AsyncPgConnection; +use diesel_async::RunQueryDsl; use uuid::Uuid; use crate::{models::*, schema}; -pub fn add( - conn: &mut PgConnection, +pub async fn add( + conn: &mut AsyncPgConnection, new_item_class: NewItemClass, ) -> Result { diesel::insert_into(schema::item_classes::table) .values(new_item_class) .returning(ItemClass::as_returning()) .get_result(conn) + .await } -pub fn get(conn: &mut PgConnection, id: Uuid) -> Result { +pub async fn get( + conn: &mut AsyncPgConnection, + id: Uuid, +) -> Result { schema::item_classes::table .filter(schema::item_classes::id.eq(id)) .select(ItemClass::as_select()) .first(conn) + .await } -pub fn get_all(conn: &mut PgConnection) -> Result, diesel::result::Error> { +pub async fn get_all( + conn: &mut AsyncPgConnection, +) -> Result, diesel::result::Error> { schema::item_classes::table .select(ItemClass::as_select()) .load(conn) + .await } -pub fn get_all_as_map( - conn: &mut PgConnection, +pub async fn get_all_as_map( + conn: &mut AsyncPgConnection, ) -> Result, diesel::result::Error> { - Ok(get_all(conn)? + Ok(get_all(conn) + .await? .into_iter() .map(|ic| (ic.id, ic)) .collect()) } -pub fn update( - conn: &mut PgConnection, +pub async fn update( + conn: &mut AsyncPgConnection, id: Uuid, modified_item_class: NewItemClass, ) -> Result { @@ -51,19 +61,25 @@ pub fn update( .set(modified_item_class) .returning(ItemClass::as_returning()) .get_result(conn) + .await } -pub fn items(conn: &mut PgConnection, id: Uuid) -> Result, diesel::result::Error> { +pub async fn items( + conn: &mut AsyncPgConnection, + id: Uuid, +) -> Result, diesel::result::Error> { schema::items::table .filter(schema::items::class.eq(id)) .select(Item::as_select()) .load(conn) + .await } -pub fn delete(conn: &mut PgConnection, id: Uuid) -> Result<(), diesel::result::Error> { +pub async fn delete(conn: &mut AsyncPgConnection, id: Uuid) -> Result<(), diesel::result::Error> { let num_deleted = diesel::delete(schema::item_classes::table.filter(schema::item_classes::id.eq(id))) - .execute(conn)?; + .execute(conn) + .await?; assert_eq!(num_deleted, 1); Ok(()) }