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()),
+		}
+	}
+}