diff --git a/.env b/.env index 6075b6a..77e3b5d 100644 --- a/.env +++ b/.env @@ -1 +1 @@ -DATABASE_URL=emgauwa-core.sqlite +DATABASE_URL=sqlite://emgauwa-core.sqlite diff --git a/.gitignore b/.gitignore index 746d5d5..13b0cab 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ emgauwa-core.conf.d emgauwa-core.sqlite +emgauwa-core.sqlite-* # Added by cargo diff --git a/Cargo.lock b/Cargo.lock index 5229765..769c3b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,7 +103,7 @@ dependencies = [ "futures-core", "futures-util", "mio", - "socket2", + "socket2 0.5.5", "tokio", "tracing", ] @@ -164,7 +164,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "smallvec", - "socket2", + "socket2 0.5.5", "time", "url", ] @@ -244,6 +244,12 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + [[package]] name = "android-tzdata" version = "0.1.1" @@ -259,6 +265,131 @@ dependencies = [ "libc", ] +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d37875bd9915b7d67c2f117ea2c30a0989874d0b2cb694fe25403c85763c0c9e" +dependencies = [ + "concurrent-queue", + "event-listener 3.1.0", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc5ea910c42e5ab19012bab31f53cb4d63d54c3a27730f9a833a88efcf4bb52d" +dependencies = [ + "async-lock 3.1.1", + "async-task", + "concurrent-queue", + "fastrand 2.0.1", + "futures-lite 2.0.1", + "slab", +] + +[[package]] +name = "async-global-executor" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776" +dependencies = [ + "async-channel 1.9.0", + "async-executor", + "async-io", + "async-lock 2.8.0", + "blocking", + "futures-lite 1.13.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling", + "rustix 0.37.27", + "slab", + "socket2 0.4.10", + "waker-fn", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "655b9c7fe787d3b25cc0f804a1a8401790f0c5bc395beb5a64dc77d8de079105" +dependencies = [ + "event-listener 3.1.0", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io", + "async-lock 2.8.0", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 1.13.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4eb2cdb97421e01129ccb49169d8279ed21e829929144f4a22a6e54ac549ca1" + [[package]] name = "async-trait" version = "0.1.74" @@ -270,6 +401,21 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.1.0" @@ -303,6 +449,12 @@ version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "1.3.2" @@ -314,6 +466,9 @@ name = "bitflags" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" +dependencies = [ + "serde", +] [[package]] name = "block-buffer" @@ -324,6 +479,22 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blocking" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118" +dependencies = [ + "async-channel 2.1.0", + "async-lock 3.1.1", + "async-task", + "fastrand 2.0.1", + "futures-io", + "futures-lite 2.0.1", + "piper", + "tracing", +] + [[package]] name = "brotli" version = "3.4.0" @@ -351,6 +522,12 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes" version = "1.5.0" @@ -408,6 +585,15 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "concurrent-queue" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f057a694a54f12365049b0958a1685bb52d567f5593b355fbf685838e873d400" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "config" version = "0.13.3" @@ -423,10 +609,16 @@ dependencies = [ "rust-ini", "serde", "serde_json", - "toml 0.5.11", + "toml", "yaml-rust", ] +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + [[package]] name = "convert_case" version = "0.4.0" @@ -459,6 +651,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.3.2" @@ -468,6 +675,25 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -478,6 +704,17 @@ dependencies = [ "typenum", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.9" @@ -500,50 +737,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "diesel" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2268a214a6f118fce1838edba3d1561cf0e78d8de785475957a580a7f8c69d33" -dependencies = [ - "diesel_derives", - "libsqlite3-sys", - "time", - "uuid", -] - -[[package]] -name = "diesel_derives" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8337737574f55a468005a83499da720f20c65586241ffea339db9ecdfd2b44" -dependencies = [ - "diesel_table_macro_syntax", - "proc-macro2", - "quote", - "syn 2.0.38", -] - -[[package]] -name = "diesel_migrations" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6036b3f0120c5961381b570ee20a02432d7e2d27ea60de9578799cf9156914ac" -dependencies = [ - "diesel", - "migrations_internals", - "migrations_macros", -] - -[[package]] -name = "diesel_table_macro_syntax" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc5557efc453706fed5e4fa85006fe9817c224c3f480a34c7e5959fd700921c5" -dependencies = [ - "syn 2.0.38", -] - [[package]] name = "digest" version = "0.10.7" @@ -551,7 +744,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -566,6 +761,21 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +dependencies = [ + "serde", +] + [[package]] name = "emgauwa-core" version = "0.1.0" @@ -573,9 +783,8 @@ dependencies = [ "actix-web", "chrono", "config", - "diesel", - "diesel_migrations", "dotenv", + "futures", "lazy_static", "libsqlite3-sys", "log", @@ -583,6 +792,7 @@ dependencies = [ "serde_derive", "serde_json", "simple_logger", + "sqlx", "uuid", ] @@ -611,6 +821,65 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d93877bcde0eb80ca09131a08d23f0a5c18a620b01db137dba666d18cd9b30c2" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96b852f1345da36d551b9473fa1e2b1eb5c5195585c6c018118bc92a8d91160" +dependencies = [ + "event-listener 3.1.0", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" + [[package]] name = "flate2" version = "1.0.28" @@ -621,6 +890,17 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -636,12 +916,105 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "futures" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" +dependencies = [ + "futures-core", + "futures-sink", +] + [[package]] name = "futures-core" version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" +[[package]] +name = "futures-executor" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[package]] +name = "futures-io" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3831c2651acb5177cbd83943f3d9c8912c5ad03c76afcc0e9511ba568ec5ebb" +dependencies = [ + "fastrand 2.0.1", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "futures-sink" version = "0.3.29" @@ -660,10 +1033,16 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] @@ -693,6 +1072,18 @@ version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "h2" version = "0.3.21" @@ -726,6 +1117,28 @@ name = "hashbrown" version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +dependencies = [ + "ahash 0.8.6", + "allocator-api2", +] + +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown 0.14.2", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] [[package]] name = "hermit-abi" @@ -733,6 +1146,39 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + [[package]] name = "http" version = "0.2.9" @@ -809,6 +1255,26 @@ dependencies = [ "hashbrown 0.14.2", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "is-terminal" version = "0.4.9" @@ -816,10 +1282,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ "hermit-abi", - "rustix", + "rustix 0.38.21", "windows-sys 0.48.0", ] +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -855,6 +1330,15 @@ dependencies = [ "serde", ] +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + [[package]] name = "language-tags" version = "0.3.2" @@ -866,6 +1350,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "libc" @@ -873,6 +1360,12 @@ version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libsqlite3-sys" version = "0.26.0" @@ -890,6 +1383,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "linux-raw-sys" version = "0.4.10" @@ -928,6 +1427,19 @@ name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +dependencies = [ + "value-bag", +] + +[[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" @@ -935,27 +1447,6 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" -[[package]] -name = "migrations_internals" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f23f71580015254b020e856feac3df5878c2c7a8812297edd6c0a485ac9dada" -dependencies = [ - "serde", - "toml 0.7.8", -] - -[[package]] -name = "migrations_macros" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cce3325ac70e67bbab5bd837a31cae01f1a6db64e0e744a33cb03a543469ef08" -dependencies = [ - "migrations_internals", - "proc-macro2", - "quote", -] - [[package]] name = "mime" version = "0.3.17" @@ -999,6 +1490,44 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -1006,6 +1535,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1042,6 +1572,12 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot" version = "0.12.1" @@ -1077,6 +1613,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.0" @@ -1140,12 +1685,60 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "piper" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "668d31b1c4eba19242f2088b2bf3316b82ca31082a8335764db4e083db7485d4" +dependencies = [ + "atomic-waker", + "fastrand 2.0.1", + "futures-io", +] + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1255,6 +1848,26 @@ dependencies = [ "serde", ] +[[package]] +name = "rsa" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ef35bf3e7fe15a53c4ab08a998e42271eab13eb0db224126bc7bc4c4bad96d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rust-ini" version = "0.18.0" @@ -1280,6 +1893,20 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + [[package]] name = "rustix" version = "0.38.21" @@ -1289,7 +1916,7 @@ dependencies = [ "bitflags 2.4.1", "errno", "libc", - "linux-raw-sys", + "linux-raw-sys 0.4.10", "windows-sys 0.48.0", ] @@ -1342,15 +1969,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_spanned" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" -dependencies = [ - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1394,6 +2012,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "simple_logger" version = "4.2.0" @@ -1421,6 +2049,16 @@ version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "socket2" version = "0.5.5" @@ -1431,6 +2069,258 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlformat" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85" +dependencies = [ + "itertools", + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e50c216e3624ec8e7ecd14c6a6a6370aad6ee5d8cfc3ab30b5162eeeef2ed33" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d6753e460c998bbd4cd8c6f0ed9a64346fcca0723d6e75e52fdc351c5d2169d" +dependencies = [ + "ahash 0.8.6", + "async-io", + "async-std", + "atoi", + "byteorder", + "bytes", + "chrono", + "crc", + "crossbeam-queue", + "dotenvy", + "either", + "event-listener 2.5.3", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashlink", + "hex", + "indexmap 2.0.2", + "log", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlformat", + "thiserror", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a793bb3ba331ec8359c1853bd39eed32cdd7baaf22c35ccf5c92a7e8d1189ec" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a4ee1e104e00dedb6aa5ffdd1343107b0a4702e862a84320ee7cc74782d96fc" +dependencies = [ + "async-std", + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 1.0.109", + "tempfile", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db" +dependencies = [ + "atoi", + "base64 0.21.5", + "bitflags 2.4.1", + "byteorder", + "bytes", + "chrono", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624" +dependencies = [ + "atoi", + "base64 0.21.5", + "bitflags 2.4.1", + "byteorder", + "chrono", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand", + "serde", + "serde_json", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59dc83cf45d89c555a577694534fcd1b55c545a816c816ce51f20bbe56a4f3f" +dependencies = [ + "atoi", + "chrono", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", +] + +[[package]] +name = "stringprep" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +dependencies = [ + "finl_unicode", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "1.0.109" @@ -1453,6 +2343,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand 2.0.1", + "redox_syscall", + "rustix 0.38.21", + "windows-sys 0.48.0", +] + [[package]] name = "thiserror" version = "1.0.50" @@ -1521,9 +2424,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.33.0" +version = "1.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" +checksum = "d0c014766411e834f7af5b8f4cf46257aab4036ca95e9d2c144a10f59ad6f5b9" dependencies = [ "backtrace", "bytes", @@ -1532,7 +2435,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.5", "windows-sys 0.48.0", ] @@ -1559,40 +2462,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] - -[[package]] -name = "toml_datetime" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.0.2", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - [[package]] name = "tracing" version = "0.1.40" @@ -1601,9 +2470,21 @@ checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "log", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "tracing-core" version = "0.1.32" @@ -1646,6 +2527,18 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + [[package]] name = "url" version = "2.4.1" @@ -1667,6 +2560,12 @@ dependencies = [ "serde", ] +[[package]] +name = "value-bag" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a72e1902dde2bd6441347de2b70b7f5d59bf157c6c62f0c44572607a1d55bbe" + [[package]] name = "vcpkg" version = "0.2.15" @@ -1679,6 +2578,12 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "waker-fn" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3c4517f54858c779bbcbf228f4fca63d121bf85fbecb2dc578cdf4a39395690" + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1710,6 +2615,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.87" @@ -1739,6 +2656,44 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +[[package]] +name = "web-sys" +version = "0.3.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "whoami" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22fc3756b8a9133049b26c7f61ab35416c130e8c09b660f5b3958b446f52cc50" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + [[package]] name = "windows-core" version = "0.51.1" @@ -1871,15 +2826,6 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" -[[package]] -name = "winnow" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176b6138793677221d420fd2f0aeeced263f197688b36484660da767bca2fa32" -dependencies = [ - "memchr", -] - [[package]] name = "yaml-rust" version = "0.4.5" @@ -1909,6 +2855,12 @@ dependencies = [ "syn 2.0.38", ] +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + [[package]] name = "zstd" version = "0.12.4" diff --git a/Cargo.toml b/Cargo.toml index bc91bd0..fa180c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,7 @@ authors = ["Tobias Reisinger <tobias@msrg.cc>"] [dependencies] actix-web = "4.4" -diesel = { version = "2.1", features = ["uuid", "sqlite"] } -diesel_migrations = "2.1" +sqlx = { version = "0.7", features = ["sqlite", "runtime-async-std", "macros", "chrono"] } dotenv = "0.15" config = "0.13" @@ -30,3 +29,5 @@ serde_json = "1.0" serde_derive = "1.0" libsqlite3-sys = { version = "*", features = ["bundled"] } + +futures = "0.3.29" diff --git a/diesel.toml b/diesel.toml deleted file mode 100644 index 71215db..0000000 --- a/diesel.toml +++ /dev/null @@ -1,5 +0,0 @@ -# For documentation on how to configure this file, -# see diesel.rs/guides/configuring-diesel-cli - -[print_schema] -file = "src/db/schema.rs" diff --git a/migrations/2021-10-13-000000_init/down.sql b/migrations/20231120000000_init.down.sql similarity index 100% rename from migrations/2021-10-13-000000_init/down.sql rename to migrations/20231120000000_init.down.sql diff --git a/migrations/2021-10-13-000000_init/up.sql b/migrations/20231120000000_init.up.sql similarity index 100% rename from migrations/2021-10-13-000000_init/up.sql rename to migrations/20231120000000_init.up.sql diff --git a/src/db.rs b/src/db.rs index 970a207..7960693 100644 --- a/src/db.rs +++ b/src/db.rs @@ -1,73 +1,80 @@ -use std::env; +use log::{info, trace}; +use sqlx::migrate::Migrator; +use sqlx::{Pool, Sqlite}; +use sqlx::sqlite::SqlitePoolOptions; use crate::db::errors::DatabaseError; use crate::db::model_utils::Period; -use crate::db::models::{NewSchedule, Periods}; +use crate::db::models::{Schedule, Periods}; use crate::types::EmgauwaUid; -use diesel::prelude::*; -use diesel_migrations::{embed_migrations, EmbeddedMigrations, MigrationHarness}; -use dotenv::dotenv; -use log::{info, trace}; pub mod errors; pub mod models; pub mod schedules; -pub mod schema; pub mod tag; mod model_utils; -pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations"); +static MIGRATOR: Migrator = sqlx::migrate!(); // defaults to "./migrations" -fn get_connection() -> SqliteConnection { - dotenv().ok(); - - let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set"); - SqliteConnection::establish(&database_url) - .unwrap_or_else(|_| panic!("Error connecting to {}", database_url)) -} - -pub fn run_migrations() { +pub async fn run_migrations(pool: &Pool<Sqlite>) { info!("Running migrations"); - let mut connection = get_connection(); - connection - .run_pending_migrations(MIGRATIONS) + MIGRATOR + .run(pool) + .await .expect("Failed to run migrations."); } -fn init_schedule(schedule: &NewSchedule) -> Result<(), DatabaseError> { - trace!("Initializing schedule {:?}", schedule.name); - match schedules::get_schedule_by_uid(schedule.uid.clone()) { +async fn init_schedule(pool: &Pool<Sqlite>, uid: &EmgauwaUid, name: &str, periods: Periods) -> Result<(), DatabaseError> { + trace!("Initializing schedule {:?}", name); + match schedules::get_schedule_by_uid(pool, uid).await { Ok(_) => Ok(()), Err(err) => match err { DatabaseError::NotFound => { - trace!("Schedule {:?} not found, inserting", schedule.name); - let mut connection = get_connection(); - diesel::insert_into(schema::schedules::table) - .values(schedule) - .execute(&mut connection) + trace!("Schedule {:?} not found, inserting", name); + sqlx::query_as!(Schedule, "INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *", + uid, + name, + periods, + ) + .fetch_optional(pool) + .await? + .ok_or(DatabaseError::InsertGetError) .map(|_| ()) - .map_err(DatabaseError::InsertError) } _ => Err(err), }, } } -pub fn init(db: &str) { - run_migrations(); - init_schedule(&NewSchedule { - uid: &EmgauwaUid::Off, - name: "Off", - periods: &Periods(vec![]), - }) - .expect("Error initializing schedule Off"); +pub async fn init(db: &str) -> Pool<Sqlite> { + let pool: Pool<Sqlite> = SqlitePoolOptions::new() + .acquire_timeout(std::time::Duration::from_secs(1)) + .max_connections(5) + .connect(db) + .await + .expect("Error connecting to database."); - init_schedule(&NewSchedule { - uid: &EmgauwaUid::On, - name: "On", - periods: &Periods(vec![Period::new_on()]), - }) - .expect("Error initializing schedule On"); + run_migrations(&pool).await; + + init_schedule( + &pool, + &EmgauwaUid::Off, + "Off", + Periods(vec![]) + ) + .await + .expect("Error initializing schedule Off"); + + init_schedule( + &pool, + &EmgauwaUid::On, + "On", + Periods(vec![Period::new_on()]) + ) + .await + .expect("Error initializing schedule On"); + + pool } diff --git a/src/db/errors.rs b/src/db/errors.rs index af36c6d..8ba2fc7 100644 --- a/src/db/errors.rs +++ b/src/db/errors.rs @@ -2,15 +2,16 @@ use actix_web::http::StatusCode; use actix_web::HttpResponse; use serde::ser::SerializeStruct; use serde::{Serialize, Serializer}; +use sqlx::Error; #[derive(Debug)] pub enum DatabaseError { DeleteError, - InsertError(diesel::result::Error), + InsertError, InsertGetError, NotFound, Protected, - UpdateError(diesel::result::Error), + UpdateError, Unknown, } @@ -40,14 +41,14 @@ impl Serialize for DatabaseError { impl From<&DatabaseError> for String { fn from(err: &DatabaseError) -> Self { match err { - DatabaseError::InsertError(_) => String::from("error on inserting into database"), + DatabaseError::InsertError => String::from("error on inserting into database"), DatabaseError::InsertGetError => { String::from("error on retrieving new entry from database (your entry was saved)") } DatabaseError::NotFound => String::from("model was not found in database"), DatabaseError::DeleteError => String::from("error on deleting from database"), DatabaseError::Protected => String::from("model is protected"), - DatabaseError::UpdateError(_) => String::from("error on updating the model"), + DatabaseError::UpdateError => String::from("error on updating the model"), DatabaseError::Unknown => String::from("unknown error"), } } @@ -58,3 +59,12 @@ impl From<DatabaseError> for HttpResponse { HttpResponse::build(err.get_code()).json(err) } } + +impl From<Error> for DatabaseError { + fn from(value: Error) -> Self { + match value { + Error::RowNotFound => DatabaseError::NotFound, + _ => DatabaseError::Unknown, + } + } +} \ No newline at end of file diff --git a/src/db/model_utils.rs b/src/db/model_utils.rs index 0d15068..28679d1 100644 --- a/src/db/model_utils.rs +++ b/src/db/model_utils.rs @@ -1,14 +1,13 @@ use crate::db::models::Periods; use chrono::{NaiveTime, Timelike}; -use diesel::deserialize::FromSql; -use diesel::serialize::{IsNull, Output, ToSql}; -use diesel::sql_types::Binary; -use diesel::sqlite::Sqlite; -use diesel::{deserialize, serialize}; use serde::{Deserialize, Serialize}; +use sqlx::{Decode, Encode, Sqlite, Type}; +use sqlx::database::HasArguments; +use sqlx::encode::IsNull; +use sqlx::error::BoxDynError; +use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef}; -#[derive(Debug, Serialize, Deserialize, AsExpression, FromSqlRow, PartialEq, Clone)] -#[diesel(sql_type = Binary)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct Period { #[serde(with = "period_format")] pub start: NaiveTime, @@ -52,13 +51,81 @@ impl Period { } } -impl ToSql<Binary, Sqlite> for Periods -where - Vec<u8>: ToSql<Binary, Sqlite>, -{ - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result { - let periods_u8: Vec<u8> = self - .0 +//impl ToSql<Binary, Sqlite> for Periods +//where +// Vec<u8>: ToSql<Binary, Sqlite>, +//{ +// fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, Sqlite>) -> serialize::Result { +// let periods_u8: Vec<u8> = self +// .0 +// .iter() +// .flat_map(|period| { +// let vec = vec![ +// period.start.hour() as u8, +// period.start.minute() as u8, +// period.end.hour() as u8, +// period.end.minute() as u8, +// ]; +// vec +// }) +// .collect(); +// +// out.set_value(periods_u8); +// +// Ok(IsNull::No) +// } +//} +// +//impl<DB> FromSql<Binary, DB> for Periods +//where +// DB: diesel::backend::Backend, +// Vec<u8>: FromSql<Binary, DB>, +//{ +// fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> { +// let blob: Vec<u8> = Vec::from_sql(bytes).unwrap(); +// +// let mut vec = Vec::new(); +// for i in (3..blob.len()).step_by(4) { +// let start_val_h: u32 = blob[i - 3] as u32; +// let start_val_m: u32 = blob[i - 2] as u32; +// let end_val_h: u32 = blob[i - 1] as u32; +// let end_val_m: u32 = blob[i] as u32; +// vec.push(Period { +// start: NaiveTime::from_hms_opt(start_val_h, start_val_m, 0).unwrap(), +// end: NaiveTime::from_hms_opt(end_val_h, end_val_m, 0).unwrap(), +// }); +// } +// Ok(Periods(vec)) +// } +//} + +impl Type<Sqlite> for Periods { + fn type_info() -> SqliteTypeInfo { + <&[u8] as Type<Sqlite>>::type_info() + } + + fn compatible(ty: &SqliteTypeInfo) -> bool { + <&[u8] as Type<Sqlite>>::compatible(ty) + } +} + +impl<'q> Encode<'q, Sqlite> for Periods { + //noinspection DuplicatedCode + fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull { + <&Vec<u8> as Encode<Sqlite>>::encode(&Vec::from(self), buf) + } +} + +impl<'r> Decode<'r, Sqlite> for Periods { + fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> { + let blob = <&[u8] as Decode<Sqlite>>::decode(value)?; + Ok(Periods::from(Vec::from(blob))) + } +} + +impl From<&Periods> for Vec<u8> { + fn from(periods: &Periods) -> Vec<u8> { + periods.0 .iter() .flat_map(|period| { let vec = vec![ @@ -69,33 +136,23 @@ where ]; vec }) - .collect(); - - out.set_value(periods_u8); - - Ok(IsNull::No) + .collect() } } -impl<DB> FromSql<Binary, DB> for Periods -where - DB: diesel::backend::Backend, - Vec<u8>: FromSql<Binary, DB>, -{ - fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> { - let blob: Vec<u8> = Vec::from_sql(bytes).unwrap(); - +impl From<Vec<u8>> for Periods { + fn from(value: Vec<u8>) -> Self { let mut vec = Vec::new(); - for i in (3..blob.len()).step_by(4) { - let start_val_h: u32 = blob[i - 3] as u32; - let start_val_m: u32 = blob[i - 2] as u32; - let end_val_h: u32 = blob[i - 1] as u32; - let end_val_m: u32 = blob[i] as u32; + for i in (3..value.len()).step_by(4) { + let start_val_h: u32 = value[i - 3] as u32; + let start_val_m: u32 = value[i - 2] as u32; + let end_val_h: u32 = value[i - 1] as u32; + let end_val_m: u32 = value[i] as u32; vec.push(Period { start: NaiveTime::from_hms_opt(start_val_h, start_val_m, 0).unwrap(), end: NaiveTime::from_hms_opt(end_val_h, end_val_m, 0).unwrap(), }); } - Ok(Periods(vec)) + Periods(vec) } } diff --git a/src/db/models.rs b/src/db/models.rs index 3c80774..4b1c99d 100644 --- a/src/db/models.rs +++ b/src/db/models.rs @@ -1,68 +1,37 @@ use crate::db::model_utils::Period; -use diesel::sql_types::Binary; use serde::{Deserialize, Serialize}; -use super::schema::*; use crate::types::EmgauwaUid; -#[derive(Debug, Serialize, Identifiable, Queryable)] +#[derive(Debug, Serialize)] pub struct Relay { #[serde(skip)] - pub id: i32, + pub id: i64, // TODO } -#[derive(Debug, Serialize, Identifiable, Queryable, Clone)] +#[derive(Debug, Serialize, Clone)] pub struct Schedule { #[serde(skip)] - pub id: i32, + pub id: i64, #[serde(rename(serialize = "id"))] pub uid: EmgauwaUid, pub name: String, pub periods: Periods, } -#[derive(Insertable)] -#[diesel(table_name = crate::db::schema::schedules)] -pub struct NewSchedule<'a> { - pub uid: &'a EmgauwaUid, - pub name: &'a str, - pub periods: &'a Periods, -} - -#[derive(Debug, Serialize, Deserialize, AsExpression, FromSqlRow, PartialEq, Clone)] -#[diesel(sql_type = Binary)] +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] pub struct Periods(pub Vec<Period>); -#[derive(Debug, Serialize, Identifiable, Queryable, Clone)] -#[diesel(table_name = crate::db::schema::tags)] +#[derive(Debug, Serialize, Clone)] pub struct Tag { - pub id: i32, + pub id: i64, pub tag: String, } -#[derive(Insertable)] -#[diesel(table_name = crate::db::schema::tags)] -pub struct NewTag<'a> { - pub tag: &'a str, -} - -#[derive(Queryable, Associations, Identifiable)] -#[diesel(belongs_to(Relay))] -#[diesel(belongs_to(Schedule))] -#[diesel(belongs_to(Tag))] -#[diesel(table_name = crate::db::schema::junction_tag)] pub struct JunctionTag { - pub id: i32, - pub tag_id: i32, - pub relay_id: Option<i32>, - pub schedule_id: Option<i32>, -} - -#[derive(Insertable)] -#[diesel(table_name = crate::db::schema::junction_tag)] -pub struct NewJunctionTag { - pub tag_id: i32, - pub relay_id: Option<i32>, - pub schedule_id: Option<i32>, + pub id: i64, + pub tag_id: i64, + pub relay_id: Option<i64>, + pub schedule_id: Option<i64>, } diff --git a/src/db/schedules.rs b/src/db/schedules.rs index 01f13f5..89431fe 100644 --- a/src/db/schedules.rs +++ b/src/db/schedules.rs @@ -1,141 +1,106 @@ -use diesel::dsl::sql; -use diesel::prelude::*; use std::borrow::Borrow; +use sqlx::{Pool, Sqlite}; use crate::types::EmgauwaUid; use crate::db::errors::DatabaseError; use crate::db::models::*; -use crate::db::schema::junction_tag::dsl::junction_tag; -use crate::db::schema::schedules::dsl::schedules; -use crate::db::schema::tags::dsl::tags; -use crate::db::tag::{create_junction_tag, create_tag}; -use crate::db::{get_connection, schema}; +use crate::db::tag::{create_junction_tag_schedule, create_tag}; -pub fn get_schedule_tags(schedule: &Schedule) -> Vec<String> { - let mut connection = get_connection(); - JunctionTag::belonging_to(schedule) - .inner_join(schema::tags::dsl::tags) - .select(schema::tags::tag) - .load::<String>(&mut connection) - .expect("Error loading tags") +pub async fn get_schedule_tags(pool: &Pool<Sqlite>, schedule: &Schedule) -> Result<Vec<String>, DatabaseError> { + Ok(sqlx::query_scalar!("SELECT tag FROM tags INNER JOIN junction_tag ON junction_tag.tag_id = tags.id WHERE junction_tag.schedule_id = ?", schedule.id) + .fetch_all(pool) + .await?) } -pub fn get_schedules() -> Vec<Schedule> { - let mut connection = get_connection(); - schedules - .load::<Schedule>(&mut connection) - .expect("Error loading schedules") +pub async fn get_schedules(pool: &Pool<Sqlite>) -> Result<Vec<Schedule>, DatabaseError> { + Ok(sqlx::query_as!(Schedule, "SELECT * FROM schedules") + .fetch_all(pool) + .await?) } -pub fn get_schedule_by_uid(filter_uid: EmgauwaUid) -> Result<Schedule, DatabaseError> { - let mut connection = get_connection(); - let result = schedules - .filter(schema::schedules::uid.eq(filter_uid)) - .first::<Schedule>(&mut connection) - .or(Err(DatabaseError::NotFound))?; - - Ok(result) +pub async fn get_schedule_by_uid(pool: &Pool<Sqlite>, filter_uid: &EmgauwaUid) -> Result<Schedule, DatabaseError> { + sqlx::query_as!(Schedule, "SELECT * FROM schedules WHERE uid = ?", filter_uid) + .fetch_optional(pool) + .await + .map(|s| s.ok_or(DatabaseError::NotFound))? } -pub fn get_schedules_by_tag(tag: &Tag) -> Vec<Schedule> { - let mut connection = get_connection(); - JunctionTag::belonging_to(tag) - .inner_join(schedules) - .select(schema::schedules::all_columns) - .load::<Schedule>(&mut connection) - .expect("Error loading tags") +pub async fn get_schedules_by_tag(pool: &Pool<Sqlite>, tag: &Tag) -> Result<Vec<Schedule>, DatabaseError> { + Ok(sqlx::query_as!(Schedule, "SELECT schedule.* FROM schedules AS schedule INNER JOIN junction_tag ON junction_tag.schedule_id = schedule.id WHERE junction_tag.tag_id = ?", tag.id) + .fetch_all(pool) + .await?) } -pub fn delete_schedule_by_uid(filter_uid: EmgauwaUid) -> Result<(), DatabaseError> { +pub async fn delete_schedule_by_uid(pool: &Pool<Sqlite>, filter_uid: EmgauwaUid) -> Result<(), DatabaseError> { let filter_uid = match filter_uid { EmgauwaUid::Off => Err(DatabaseError::Protected), EmgauwaUid::On => Err(DatabaseError::Protected), EmgauwaUid::Any(_) => Ok(filter_uid), }?; - let mut connection = get_connection(); - match diesel::delete(schedules.filter(schema::schedules::uid.eq(filter_uid))) - .execute(&mut connection) - { - Ok(rows) => { - if rows != 0 { - Ok(()) - } else { - Err(DatabaseError::DeleteError) - } - } - Err(_) => Err(DatabaseError::DeleteError), - } + sqlx::query!("DELETE FROM schedules WHERE uid = ?", filter_uid) + .execute(pool) + .await + .map(|res| match res.rows_affected() { + 0 => Err(DatabaseError::DeleteError), + _ => Ok(()), + })? } -pub fn create_schedule(new_name: &str, new_periods: &Periods) -> Result<Schedule, DatabaseError> { - let mut connection = get_connection(); - - let new_schedule = NewSchedule { - uid: &EmgauwaUid::default(), - name: new_name, - periods: new_periods, - }; - - diesel::insert_into(schedules) - .values(&new_schedule) - .execute(&mut connection) - .map_err(DatabaseError::InsertError)?; - - let result = schedules - .find(sql("last_insert_rowid()")) - .get_result::<Schedule>(&mut connection) - .or(Err(DatabaseError::InsertGetError))?; - - Ok(result) +pub async fn create_schedule(pool: &Pool<Sqlite>, new_name: &str, new_periods: &Periods) -> Result<Schedule, DatabaseError> { + let uid = EmgauwaUid::default(); + sqlx::query_as!(Schedule, "INSERT INTO schedules (uid, name, periods) VALUES (?, ?, ?) RETURNING *", + uid, + new_name, + new_periods, + ) + .fetch_optional(pool) + .await? + .ok_or(DatabaseError::InsertGetError) } -pub fn update_schedule( +pub async fn update_schedule( + pool: &Pool<Sqlite>, schedule: &Schedule, new_name: &str, new_periods: &Periods, ) -> Result<Schedule, DatabaseError> { - let mut connection = get_connection(); - + // overwrite periods on protected schedules let new_periods = match schedule.uid { EmgauwaUid::Off | EmgauwaUid::On => schedule.periods.borrow(), EmgauwaUid::Any(_) => new_periods, }; - diesel::update(schedule) - .set(( - schema::schedules::name.eq(new_name), - schema::schedules::periods.eq(new_periods), - )) - .execute(&mut connection) - .map_err(DatabaseError::UpdateError)?; + sqlx::query!("UPDATE schedules SET name = ?, periods = ? WHERE id = ?", + new_name, + new_periods, + schedule.id, + ) + .execute(pool) + .await?; - get_schedule_by_uid(schedule.uid.clone()) + get_schedule_by_uid(pool, &schedule.uid).await } -pub fn set_schedule_tags(schedule: &Schedule, new_tags: &[String]) -> Result<(), DatabaseError> { - let mut connection = get_connection(); - diesel::delete(junction_tag.filter(schema::junction_tag::schedule_id.eq(schedule.id))) - .execute(&mut connection) - .or(Err(DatabaseError::DeleteError))?; +pub async fn set_schedule_tags(pool: &Pool<Sqlite>, schedule: &Schedule, new_tags: &[String]) -> Result<(), DatabaseError> { + sqlx::query!("DELETE FROM junction_tag WHERE schedule_id = ?", schedule.id) + .execute(pool) + .await?; - let mut database_tags: Vec<Tag> = tags - .filter(schema::tags::tag.eq_any(new_tags)) - .load::<Tag>(&mut connection) - .expect("Error loading tags"); - - // create missing tags for new_tag in new_tags { - if !database_tags.iter().any(|tab_db| tab_db.tag.eq(new_tag)) { - database_tags.push(create_tag(new_tag).expect("Error inserting tag")); - } - } + let tag: Option<Tag> = sqlx::query_as!(Tag, "SELECT * FROM tags WHERE tag = ?", new_tag) + .fetch_optional(pool) + .await?; - for database_tag in database_tags { - create_junction_tag(database_tag, None, Some(schedule)) - .expect("Error saving junction between tag and schedule"); - } + let tag = match tag { + Some(id) => id, + None => { + create_tag(pool, new_tag).await? + } + }; + create_junction_tag_schedule(pool, tag, schedule).await?; + } Ok(()) } diff --git a/src/db/schema.rs b/src/db/schema.rs deleted file mode 100644 index 565cbee..0000000 --- a/src/db/schema.rs +++ /dev/null @@ -1,93 +0,0 @@ -table! { - controllers (id) { - id -> Integer, - uid -> Text, - name -> Text, - ip -> Nullable<Text>, - port -> Nullable<Integer>, - relay_count -> Nullable<Integer>, - active -> Bool, - } -} - -table! { - junction_relay_schedule (id) { - id -> Integer, - weekday -> SmallInt, - relay_id -> Nullable<Integer>, - schedule_id -> Nullable<Integer>, - } -} - -table! { - junction_tag (id) { - id -> Integer, - tag_id -> Integer, - relay_id -> Nullable<Integer>, - schedule_id -> Nullable<Integer>, - } -} - -table! { - macro_actions (id) { - id -> Integer, - macro_id -> Integer, - relay_id -> Integer, - schedule_id -> Integer, - weekday -> SmallInt, - } -} - -table! { - macros (id) { - id -> Integer, - uid -> Text, - name -> Text, - } -} - -table! { - relays (id) { - id -> Integer, - name -> Text, - number -> Integer, - controller_id -> Integer, - } -} - -table! { - schedules (id) { - id -> Integer, - uid -> Binary, - name -> Text, - periods -> Binary, - } -} - -table! { - tags (id) { - id -> Integer, - tag -> Text, - } -} - -joinable!(junction_relay_schedule -> relays (relay_id)); -joinable!(junction_relay_schedule -> schedules (schedule_id)); -joinable!(junction_tag -> relays (relay_id)); -joinable!(junction_tag -> schedules (schedule_id)); -joinable!(junction_tag -> tags (tag_id)); -joinable!(macro_actions -> macros (macro_id)); -joinable!(macro_actions -> relays (relay_id)); -joinable!(macro_actions -> schedules (schedule_id)); -joinable!(relays -> controllers (controller_id)); - -allow_tables_to_appear_in_same_query!( - controllers, - junction_relay_schedule, - junction_tag, - macro_actions, - macros, - relays, - schedules, - tags, -); diff --git a/src/db/tag.rs b/src/db/tag.rs index c31df9a..881b2c0 100644 --- a/src/db/tag.rs +++ b/src/db/tag.rs @@ -1,63 +1,41 @@ -use diesel::dsl::sql; -use diesel::prelude::*; - +use sqlx::{Pool, Sqlite}; use crate::db::errors::DatabaseError; use crate::db::models::*; -use crate::db::schema::junction_tag::dsl::junction_tag; -use crate::db::schema::tags::dsl::tags; -use crate::db::{get_connection, schema}; -pub fn create_tag(new_tag: &str) -> Result<Tag, DatabaseError> { - let mut connection = get_connection(); - - let new_tag = NewTag { tag: new_tag }; - - diesel::insert_into(tags) - .values(&new_tag) - .execute(&mut connection) - .map_err(DatabaseError::InsertError)?; - - let result = tags - .find(sql("last_insert_rowid()")) - .get_result::<Tag>(&mut connection) - .or(Err(DatabaseError::InsertGetError))?; - - Ok(result) +pub async fn create_tag(pool: &Pool<Sqlite>, new_tag: &str) -> Result<Tag, DatabaseError> { + sqlx::query_as!(Tag, "INSERT INTO tags (tag) VALUES (?) RETURNING *", new_tag) + .fetch_optional(pool) + .await? + .ok_or(DatabaseError::InsertGetError) } -pub fn get_tag(target_tag: &str) -> Result<Tag, DatabaseError> { - let mut connection = get_connection(); - - let result = tags - .filter(schema::tags::tag.eq(target_tag)) - .first::<Tag>(&mut connection) - .or(Err(DatabaseError::NotFound))?; - - Ok(result) +pub async fn get_tag(pool: &Pool<Sqlite>, target_tag: &str) -> Result<Tag, DatabaseError> { + sqlx::query_as!(Tag, "SELECT * FROM tags WHERE tag = ?", target_tag) + .fetch_optional(pool) + .await + .map(|t| t.ok_or(DatabaseError::NotFound))? } -pub fn create_junction_tag( +#[allow(dead_code)] +pub async fn create_junction_tag_relay( + pool: &Pool<Sqlite>, target_tag: Tag, - target_relay: Option<&Relay>, - target_schedule: Option<&Schedule>, + target_relay: &Relay, ) -> Result<JunctionTag, DatabaseError> { - let mut connection = get_connection(); - let new_junction_tag = NewJunctionTag { - relay_id: target_relay.map(|r| r.id), - schedule_id: target_schedule.map(|s| s.id), - tag_id: target_tag.id, - }; - - diesel::insert_into(junction_tag) - .values(&new_junction_tag) - .execute(&mut connection) - .map_err(DatabaseError::InsertError)?; - - let result = junction_tag - .find(sql("last_insert_rowid()")) - .get_result::<JunctionTag>(&mut connection) - .or(Err(DatabaseError::InsertGetError))?; - - Ok(result) + sqlx::query_as!(JunctionTag, "INSERT INTO junction_tag (tag_id, relay_id) VALUES (?, ?) RETURNING *", target_tag.id, target_relay.id) + .fetch_optional(pool) + .await? + .ok_or(DatabaseError::InsertGetError) +} + +pub async fn create_junction_tag_schedule( + pool: &Pool<Sqlite>, + target_tag: Tag, + target_schedule: &Schedule, +) -> Result<JunctionTag, DatabaseError> { + sqlx::query_as!(JunctionTag, "INSERT INTO junction_tag (tag_id, schedule_id) VALUES (?, ?) RETURNING *", target_tag.id, target_schedule.id) + .fetch_optional(pool) + .await? + .ok_or(DatabaseError::InsertGetError) } diff --git a/src/handlers/v1/schedules.rs b/src/handlers/v1/schedules.rs index c6ee513..21ce7cc 100644 --- a/src/handlers/v1/schedules.rs +++ b/src/handlers/v1/schedules.rs @@ -3,6 +3,8 @@ use actix_web::{delete, get, post, put, web, HttpResponse, Responder}; use serde::{Deserialize, Serialize}; use std::borrow::Borrow; use std::convert::TryFrom; +use futures::future; +use sqlx::{Pool, Sqlite}; use crate::db::models::{Periods, Schedule}; use crate::db::schedules::*; @@ -20,38 +22,59 @@ pub struct RequestSchedule { } #[get("/api/v1/schedules")] -pub async fn index() -> impl Responder { - let schedules = get_schedules(); - let return_schedules: Vec<ReturnSchedule> = - schedules.iter().map(ReturnSchedule::from).collect(); +pub async fn index(pool: web::Data<Pool<Sqlite>>) -> impl Responder { + let schedules = get_schedules(&pool).await; + + if let Err(err) = schedules { + return HttpResponse::from(err); + } + let schedules = schedules.unwrap(); + + let mut return_schedules: Vec<ReturnSchedule> = schedules.iter().map(ReturnSchedule::from).collect(); + for schedule in return_schedules.iter_mut() { + schedule.load_tags(&pool); + } + HttpResponse::Ok().json(return_schedules) } #[get("/api/v1/schedules/tag/{tag}")] -pub async fn tagged(path: web::Path<(String,)>) -> impl Responder { +pub async fn tagged(pool: web::Data<Pool<Sqlite>>, path: web::Path<(String,)>) -> impl Responder { let (tag,) = path.into_inner(); - let tag_db = get_tag(&tag); - if tag_db.is_err() { - return HttpResponse::from(tag_db.unwrap_err()); + let tag_db = get_tag(&pool, &tag).await; + if let Err(err) = tag_db { + return HttpResponse::from(err); } let tag_db = tag_db.unwrap(); - let schedules = get_schedules_by_tag(&tag_db); - let return_schedules: Vec<ReturnSchedule> = + let schedules = get_schedules_by_tag(&pool, &tag_db).await; + if let Err(err) = schedules { + return HttpResponse::from(err); + } + let schedules = schedules.unwrap(); + + let mut return_schedules: Vec<ReturnSchedule> = schedules.iter().map(ReturnSchedule::from).collect(); + for schedule in return_schedules.iter_mut() { + schedule.load_tags(&pool); + } HttpResponse::Ok().json(return_schedules) } #[get("/api/v1/schedules/{schedule_id}")] -pub async fn show(path: web::Path<(String,)>) -> impl Responder { +pub async fn show(pool: web::Data<Pool<Sqlite>>, path: web::Path<(String,)>) -> impl Responder { let (schedule_uid,) = path.into_inner(); let emgauwa_uid = EmgauwaUid::try_from(schedule_uid.as_str()).or(Err(HandlerError::BadUid)); match emgauwa_uid { Ok(uid) => { - let schedule = get_schedule_by_uid(uid); + let schedule = get_schedule_by_uid(&pool, &uid).await; match schedule { - Ok(ok) => HttpResponse::Ok().json(ReturnSchedule::from(ok)), + Ok(ok) => { + let mut return_schedule = ReturnSchedule::from(ok); + return_schedule.load_tags(&pool); + HttpResponse::Ok().json(return_schedule) + }, Err(err) => HttpResponse::from(err), } } @@ -60,35 +83,40 @@ pub async fn show(path: web::Path<(String,)>) -> impl Responder { } #[post("/api/v1/schedules")] -pub async fn add(data: web::Json<RequestSchedule>) -> impl Responder { - let new_schedule = create_schedule(&data.name, &data.periods); +pub async fn add(pool: web::Data<Pool<Sqlite>>, data: web::Json<RequestSchedule>) -> impl Responder { + let new_schedule = create_schedule(&pool, &data.name, &data.periods).await; - if new_schedule.is_err() { - return HttpResponse::from(new_schedule.unwrap_err()); + if let Err(err) = new_schedule { + return HttpResponse::from(err); } let new_schedule = new_schedule.unwrap(); - let result = set_schedule_tags(&new_schedule, data.tags.as_slice()); - if result.is_err() { - return HttpResponse::from(result.unwrap_err()); + let result = set_schedule_tags(&pool, &new_schedule, data.tags.as_slice()).await; + if let Err(err) = result { + return HttpResponse::from(err); } - HttpResponse::Created().json(ReturnSchedule::from(new_schedule)) + let mut return_schedule = ReturnSchedule::from(new_schedule); + return_schedule.load_tags(&pool); + HttpResponse::Created().json(return_schedule) +} + +async fn add_list_single(pool: &Pool<Sqlite>, request_schedule: &RequestSchedule) -> Result<Schedule, DatabaseError> { + let new_schedule = create_schedule(pool, &request_schedule.name, &request_schedule.periods).await?; + + set_schedule_tags(pool, &new_schedule, request_schedule.tags.as_slice()).await?; + + Ok(new_schedule) } #[post("/api/v1/schedules/list")] -pub async fn add_list(data: web::Json<Vec<RequestSchedule>>) -> impl Responder { - let result: Vec<Result<Schedule, DatabaseError>> = data +pub async fn add_list(pool: web::Data<Pool<Sqlite>>, data: web::Json<Vec<RequestSchedule>>) -> impl Responder { + let result: Vec<Result<Schedule, DatabaseError>> = future::join_all( + data .as_slice() .iter() - .map(|request_schedule| { - let new_schedule = create_schedule(&request_schedule.name, &request_schedule.periods)?; - - set_schedule_tags(&new_schedule, request_schedule.tags.as_slice())?; - - Ok(new_schedule) - }) - .collect(); + .map(|request_schedule| add_list_single(&pool, request_schedule)) + ).await; match vec_has_error(&result) { true => HttpResponse::from( @@ -99,10 +127,14 @@ pub async fn add_list(data: web::Json<Vec<RequestSchedule>>) -> impl Responder { .unwrap_err(), ), false => { - let return_schedules: Vec<ReturnSchedule> = result + let mut return_schedules: Vec<ReturnSchedule> = result .iter() .map(|s| ReturnSchedule::from(s.as_ref().unwrap())) .collect(); + + for schedule in return_schedules.iter_mut() { + schedule.load_tags(&pool); + } HttpResponse::Created().json(return_schedules) } } @@ -110,38 +142,41 @@ pub async fn add_list(data: web::Json<Vec<RequestSchedule>>) -> impl Responder { #[put("/api/v1/schedules/{schedule_id}")] pub async fn update( + pool: web::Data<Pool<Sqlite>>, path: web::Path<(String,)>, data: web::Json<RequestSchedule>, ) -> impl Responder { let (schedule_uid,) = path.into_inner(); let emgauwa_uid = EmgauwaUid::try_from(schedule_uid.as_str()).or(Err(HandlerError::BadUid)); - if emgauwa_uid.is_err() { - return HttpResponse::from(emgauwa_uid.unwrap_err()); + if let Err(err) = emgauwa_uid { + return HttpResponse::from(err); } let emgauwa_uid = emgauwa_uid.unwrap(); - let schedule = get_schedule_by_uid(emgauwa_uid); - if schedule.is_err() { - return HttpResponse::from(schedule.unwrap_err()); + let schedule = get_schedule_by_uid(&pool, &emgauwa_uid, ).await; + if let Err(err) = schedule { + return HttpResponse::from(err); } let schedule = schedule.unwrap(); - let schedule = update_schedule(&schedule, data.name.as_str(), data.periods.borrow()); - if schedule.is_err() { - return HttpResponse::from(schedule.unwrap_err()); + let schedule = update_schedule(&pool, &schedule, data.name.as_str(), data.periods.borrow()).await; + if let Err(err) = schedule { + return HttpResponse::from(err); } let schedule = schedule.unwrap(); - let result = set_schedule_tags(&schedule, data.tags.as_slice()); - if result.is_err() { - return HttpResponse::from(result.unwrap_err()); + let result = set_schedule_tags(&pool, &schedule, data.tags.as_slice()).await; + if let Err(err) = result { + return HttpResponse::from(err); } - HttpResponse::Ok().json(ReturnSchedule::from(schedule)) + let mut return_schedule = ReturnSchedule::from(schedule); + return_schedule.load_tags(&pool); + HttpResponse::Ok().json(return_schedule) } #[delete("/api/v1/schedules/{schedule_id}")] -pub async fn delete(path: web::Path<(String,)>) -> impl Responder { +pub async fn delete(pool: web::Data<Pool<Sqlite>>, path: web::Path<(String,)>) -> impl Responder { let (schedule_uid,) = path.into_inner(); let emgauwa_uid = EmgauwaUid::try_from(schedule_uid.as_str()).or(Err(HandlerError::BadUid)); @@ -149,7 +184,7 @@ pub async fn delete(path: web::Path<(String,)>) -> impl Responder { Ok(uid) => match uid { EmgauwaUid::Off => HttpResponse::from(HandlerError::ProtectedSchedule), EmgauwaUid::On => HttpResponse::from(HandlerError::ProtectedSchedule), - EmgauwaUid::Any(_) => match delete_schedule_by_uid(uid) { + EmgauwaUid::Any(_) => match delete_schedule_by_uid(&pool, uid).await { Ok(_) => HttpResponse::Ok().json("schedule got deleted"), Err(err) => HttpResponse::from(err), }, diff --git a/src/main.rs b/src/main.rs index 0aa72eb..8d3f292 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,9 @@ -#[macro_use] -extern crate diesel; -extern crate diesel_migrations; extern crate dotenv; use actix_web::middleware::TrailingSlash; use actix_web::{middleware, web, App, HttpServer}; use log::{trace, LevelFilter}; use simple_logger::SimpleLogger; -use std::fmt::format; use std::str::FromStr; mod db; @@ -31,9 +27,9 @@ async fn main() -> std::io::Result<()> { .init() .unwrap_or_else(|_| panic!("Error initializing logger.")); - db::init(&settings.database); + let pool = db::init(&settings.database).await; - HttpServer::new(|| { + HttpServer::new(move || { App::new() .wrap( middleware::DefaultHeaders::new() @@ -44,6 +40,7 @@ async fn main() -> std::io::Result<()> { .wrap(middleware::Logger::default()) .wrap(middleware::NormalizePath::new(TrailingSlash::Trim)) .app_data(web::JsonConfig::default().error_handler(handlers::json_error_handler)) + .app_data(web::Data::new(pool.clone())) .service(handlers::v1::schedules::index) .service(handlers::v1::schedules::tagged) .service(handlers::v1::schedules::show) diff --git a/src/return_models.rs b/src/return_models.rs index c000435..49e7212 100644 --- a/src/return_models.rs +++ b/src/return_models.rs @@ -1,3 +1,4 @@ +use futures::executor; use serde::Serialize; use crate::db::models::Schedule; @@ -10,10 +11,15 @@ pub struct ReturnSchedule { pub tags: Vec<String>, } +impl ReturnSchedule { + pub fn load_tags(&mut self, pool: &sqlx::Pool<sqlx::Sqlite>) { + self.tags = executor::block_on(get_schedule_tags(pool, &self.schedule)).unwrap(); + } +} + impl From<Schedule> for ReturnSchedule { fn from(schedule: Schedule) -> Self { - let tags: Vec<String> = get_schedule_tags(&schedule); - ReturnSchedule { schedule, tags } + ReturnSchedule { schedule, tags: vec![]} } } diff --git a/src/types.rs b/src/types.rs index 9fb50b5..f75f885 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,10 +1,8 @@ -use diesel::sql_types::Binary; use uuid::Uuid; pub mod emgauwa_uid; -#[derive(AsExpression, FromSqlRow, PartialEq, Clone)] -#[diesel(sql_type = Binary)] +#[derive(PartialEq, Clone)] pub enum EmgauwaUid { Off, On, diff --git a/src/types/emgauwa_uid.rs b/src/types/emgauwa_uid.rs index 7183f0d..84f0503 100644 --- a/src/types/emgauwa_uid.rs +++ b/src/types/emgauwa_uid.rs @@ -3,12 +3,12 @@ use std::fmt::{Debug, Formatter}; use std::str::FromStr; use crate::types::EmgauwaUid; -use diesel::backend::Backend; -use diesel::deserialize::FromSql; -use diesel::serialize::{IsNull, Output, ToSql}; -use diesel::sql_types::Binary; -use diesel::{deserialize, serialize}; use serde::{Serialize, Serializer}; +use sqlx::{Decode, Encode, Sqlite, Type}; +use sqlx::database::HasArguments; +use sqlx::encode::IsNull; +use sqlx::error::BoxDynError; +use sqlx::sqlite::{SqliteTypeInfo, SqliteValueRef}; use uuid::Uuid; impl EmgauwaUid { @@ -36,34 +36,26 @@ impl Debug for EmgauwaUid { } } -impl<DB> ToSql<Binary, DB> for EmgauwaUid -where - DB: Backend, - [u8]: ToSql<Binary, DB>, -{ - fn to_sql<'b>(&'b self, out: &mut Output<'b, '_, DB>) -> serialize::Result { - match self { - EmgauwaUid::Off => [EmgauwaUid::OFF_U8].to_sql(out)?, - EmgauwaUid::On => [EmgauwaUid::ON_U8].to_sql(out)?, - EmgauwaUid::Any(value) => value.as_bytes().to_sql(out)?, - }; - Ok(IsNull::No) +impl Type<Sqlite> for EmgauwaUid { + fn type_info() -> SqliteTypeInfo { + <&[u8] as Type<Sqlite>>::type_info() + } + + fn compatible(ty: &SqliteTypeInfo) -> bool { + <&[u8] as Type<Sqlite>>::compatible(ty) } } -impl<DB> FromSql<Binary, DB> for EmgauwaUid -where - DB: Backend, - Vec<u8>: FromSql<Binary, DB>, -{ - fn from_sql(bytes: DB::RawValue<'_>) -> deserialize::Result<Self> { - let blob: Vec<u8> = FromSql::<Binary, DB>::from_sql(bytes)?; +impl<'q> Encode<'q, Sqlite> for EmgauwaUid { + //noinspection DuplicatedCode + fn encode_by_ref(&self, buf: &mut <Sqlite as HasArguments<'q>>::ArgumentBuffer) -> IsNull { + <&Vec<u8> as Encode<Sqlite>>::encode(&Vec::from(self), buf) + } +} - match blob.as_slice() { - [EmgauwaUid::OFF_U8] => Ok(EmgauwaUid::Off), - [EmgauwaUid::ON_U8] => Ok(EmgauwaUid::On), - value_bytes => Ok(EmgauwaUid::Any(Uuid::from_slice(value_bytes).unwrap())), - } +impl<'r> Decode<'r, Sqlite> for EmgauwaUid { + fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> { + Ok(EmgauwaUid::from(<&[u8] as Decode<Sqlite>>::decode(value)?)) } } @@ -104,8 +96,8 @@ impl TryFrom<&str> for EmgauwaUid { impl From<&EmgauwaUid> for Uuid { fn from(emgauwa_uid: &EmgauwaUid) -> Uuid { match emgauwa_uid { - EmgauwaUid::Off => uuid::Uuid::from_u128(EmgauwaUid::OFF_U128), - EmgauwaUid::On => uuid::Uuid::from_u128(EmgauwaUid::ON_U128), + EmgauwaUid::Off => Uuid::from_u128(EmgauwaUid::OFF_U128), + EmgauwaUid::On => Uuid::from_u128(EmgauwaUid::ON_U128), EmgauwaUid::Any(value) => *value, } } @@ -120,3 +112,33 @@ impl From<&EmgauwaUid> for String { } } } + +impl From<&EmgauwaUid> for Vec<u8> { + fn from(emgauwa_uid: &EmgauwaUid) -> Vec<u8> { + match emgauwa_uid { + EmgauwaUid::Off => vec![EmgauwaUid::OFF_U8], + EmgauwaUid::On => vec![EmgauwaUid::ON_U8], + EmgauwaUid::Any(value) => value.as_bytes().to_vec(), + } + } +} + +impl From<&[u8]> for EmgauwaUid { + fn from(value: &[u8]) -> Self { + match value { + [EmgauwaUid::OFF_U8] => EmgauwaUid::Off, + [EmgauwaUid::ON_U8] => EmgauwaUid::On, + value_bytes => EmgauwaUid::Any(Uuid::from_slice(value_bytes).unwrap()), + } + } +} + +impl From<Vec<u8>> for EmgauwaUid { + fn from(value: Vec<u8>) -> Self { + match value.as_slice() { + [EmgauwaUid::OFF_U8] => EmgauwaUid::Off, + [EmgauwaUid::ON_U8] => EmgauwaUid::On, + value_bytes => EmgauwaUid::Any(Uuid::from_slice(value_bytes).unwrap()), + } + } +}