Upgrade to sqlx 0.4 beta master branch
This required a ton of changes including updating error handling and separating out the models into intermediate representations so that fields that are marked non-null in the database are not `Option` in the final model. The update allows using `query_as!` in `interior_ref_list` and `merchandise_list` and model functions to specify a generic `Executor` param that can take either a db pool connection, transaction, or plain db connection. This should allow me to impl my old `Model` trait again. Also compile times are magically 20x faster?!?
This commit is contained in:
parent
1a1806ffc3
commit
780f0be433
351
Cargo.lock
generated
351
Cargo.lock
generated
@ -15,6 +15,16 @@ dependencies = [
|
|||||||
"const-random",
|
"const-random",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ahash"
|
||||||
|
version = "0.5.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4eb6ec8807cd25b59e6b8100815afc73f54e294f1a425a2e555971969889a8f8"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.2.0",
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.13"
|
version = "0.7.13"
|
||||||
@ -68,39 +78,6 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-native-tls"
|
|
||||||
version = "0.3.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9e9e7a929bd34c68a82d58a4de7f86fffdaf97fb2af850162a7bb19dd7269b33"
|
|
||||||
dependencies = [
|
|
||||||
"native-tls",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
"url",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-stream"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "22068c0c19514942eefcfd4daf8976ef1aad84e61539f95cd200c35202f80af5"
|
|
||||||
dependencies = [
|
|
||||||
"async-stream-impl",
|
|
||||||
"futures-core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "async-stream-impl"
|
|
||||||
version = "0.2.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "25f9db3b38af870bf7e5cc649167533b493928e50744e2c30ae350230b414670"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.36"
|
version = "0.1.36"
|
||||||
@ -112,6 +89,15 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atoi"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c897df197d57c25b37df9d8fa2f93ddbfeee9ebd2264350ac79c8ec4b795885"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "0.1.7"
|
version = "0.1.7"
|
||||||
@ -130,6 +116,12 @@ version = "0.12.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bazaar_realm_api"
|
name = "bazaar_realm_api"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -268,6 +260,12 @@ version = "0.1.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.13"
|
version = "0.4.13"
|
||||||
@ -289,6 +287,15 @@ dependencies = [
|
|||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cloudabi"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4344512281c643ae7638bbabc3af17a11307803ec8f0fcad9fae512a8bf36467"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "const-random"
|
name = "const-random"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
@ -305,7 +312,7 @@ version = "0.1.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a"
|
checksum = "25e4c606eb459dd29f7c57b2e0879f2b6f14ee130918c2b78ccb58a9624e6c7a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.1.14",
|
||||||
"proc-macro-hack",
|
"proc-macro-hack",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -337,7 +344,17 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crossbeam-channel"
|
||||||
|
version = "0.4.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
"maybe-uninit",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -346,7 +363,7 @@ version = "0.2.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
|
checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"maybe-uninit",
|
"maybe-uninit",
|
||||||
]
|
]
|
||||||
@ -358,17 +375,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg 1.0.0",
|
"autocfg 1.0.0",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-mac"
|
name = "crypto-mac"
|
||||||
version = "0.7.0"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5"
|
checksum = "58bcd97a54c7ca5ce2f6eb16f6bede5b0ab5f0055fedc17d2f0b4466e21671ca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array 0.12.3",
|
"generic-array 0.14.3",
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -402,6 +419,12 @@ version = "0.4.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
|
checksum = "134951f4028bdadb9b84baf4232681efbf277da25144b9b0ad65df75946c422b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "either"
|
||||||
|
version = "1.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fake-simd"
|
name = "fake-simd"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@ -414,7 +437,7 @@ version = "1.0.16"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e"
|
checksum = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"libc",
|
"libc",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
@ -511,6 +534,18 @@ version = "0.3.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789"
|
checksum = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-macro"
|
||||||
|
version = "0.3.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e36fccf3fc58563b4a14d265027c627c3b665d7fed489427e88e7cc929559efe"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-hack",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-sink"
|
name = "futures-sink"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
@ -535,11 +570,14 @@ dependencies = [
|
|||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
|
"futures-macro",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-task",
|
"futures-task",
|
||||||
"memchr",
|
"memchr",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"pin-utils",
|
"pin-utils",
|
||||||
|
"proc-macro-hack",
|
||||||
|
"proc-macro-nested",
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -568,7 +606,18 @@ version = "0.1.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
|
"libc",
|
||||||
|
"wasi",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
]
|
]
|
||||||
@ -598,7 +647,7 @@ version = "0.6.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead"
|
checksum = "8e6073d0ca812575946eb5f35ff68dbe519907b25c42530389ff946dc84c6ead"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash 0.2.18",
|
||||||
"autocfg 0.1.7",
|
"autocfg 0.1.7",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -617,7 +666,7 @@ version = "0.3.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed18eb2459bf1a09ad2d6b1547840c3e5e62882fa09b9a6a20b1de8e3228848f"
|
checksum = "ed18eb2459bf1a09ad2d6b1547840c3e5e62882fa09b9a6a20b1de8e3228848f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64 0.12.3",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bytes",
|
"bytes",
|
||||||
"headers-core",
|
"headers-core",
|
||||||
@ -662,12 +711,12 @@ checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hmac"
|
name = "hmac"
|
||||||
version = "0.7.1"
|
version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5dcb5e64cda4c23119ab41ba960d1e170a774c8e4b9d9e6a9bc18aabf5e59695"
|
checksum = "deae6d9dbb35ec2c502d62b8f7b1c000a0822c3b0794ba36b3149c0a1c840dff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crypto-mac",
|
"crypto-mac",
|
||||||
"digest 0.8.1",
|
"digest 0.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -763,6 +812,15 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb1fc4429a33e1f80d41dc9fea4d108a88bec1de8053878898ae448a0b52f613"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "iovec"
|
name = "iovec"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
@ -774,9 +832,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnetwork"
|
name = "ipnetwork"
|
||||||
version = "0.16.0"
|
version = "0.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8eca9f51da27bc908ef3dd85c21e1bbba794edaf94d7841e37356275b82d31e"
|
checksum = "02c3eaab3ac0ede60ffa41add21970a7df7d91772c03383aac6c2c3d53cc716b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@ -809,6 +867,12 @@ version = "0.2.74"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10"
|
checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked-hash-map"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "listenfd"
|
name = "listenfd"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@ -820,13 +884,22 @@ dependencies = [
|
|||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28247cc5a5be2f05fbcd76dd0cf2c7d3b5400cb978a28042abcd4fa0b3f8261c"
|
||||||
|
dependencies = [
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.4.11"
|
version = "0.4.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -838,6 +911,15 @@ dependencies = [
|
|||||||
"hashbrown 0.6.3",
|
"hashbrown 0.6.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lru-cache"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
|
||||||
|
dependencies = [
|
||||||
|
"linked-hash-map",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "maplit"
|
name = "maplit"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@ -867,13 +949,13 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "md-5"
|
name = "md-5"
|
||||||
version = "0.8.0"
|
version = "0.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8"
|
checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer 0.7.3",
|
"block-buffer 0.9.0",
|
||||||
"digest 0.8.1",
|
"digest 0.9.0",
|
||||||
"opaque-debug 0.2.3",
|
"opaque-debug 0.3.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -913,7 +995,7 @@ version = "0.6.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
|
checksum = "fce347092656428bc8eaf6201042cb551b8d67855af7374542a92a0fbfcac430"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"fuchsia-zircon",
|
"fuchsia-zircon",
|
||||||
"fuchsia-zircon-sys",
|
"fuchsia-zircon-sys",
|
||||||
"iovec",
|
"iovec",
|
||||||
@ -991,7 +1073,7 @@ version = "0.2.34"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
|
checksum = "2ba7c918ac76704fb42afcbbb43891e72731f3dcca3bef2a19786297baf14af7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"libc",
|
"libc",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
]
|
]
|
||||||
@ -1050,7 +1132,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4"
|
checksum = "8d575eff3665419f9b83678ff2815858ad9d11567e082f5ac1814baba4e2bcb4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"foreign-types",
|
"foreign-types",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
@ -1076,6 +1158,32 @@ dependencies = [
|
|||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4893845fa2ca272e647da5d0e46660a314ead9c2fdd9a883aabc32e481a8733"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
"lock_api",
|
||||||
|
"parking_lot_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking_lot_core"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c361aa727dd08437f2f1447be8b59a33b0edd15e0fcee698f935613d9efbca9b"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.10",
|
||||||
|
"cloudabi 0.1.0",
|
||||||
|
"instant",
|
||||||
|
"libc",
|
||||||
|
"redox_syscall",
|
||||||
|
"smallvec",
|
||||||
|
"winapi 0.3.9",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.1.0"
|
version = "2.1.0"
|
||||||
@ -1132,6 +1240,12 @@ version = "0.5.18"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598"
|
checksum = "99c605b9a0adc77b7211c6b1f722dcb613d68d66859a44f3d485a6da332b0598"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-nested"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.19"
|
version = "1.0.19"
|
||||||
@ -1181,7 +1295,7 @@ version = "0.7.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.1.14",
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha 0.2.2",
|
"rand_chacha 0.2.2",
|
||||||
"rand_core 0.5.1",
|
"rand_core 0.5.1",
|
||||||
@ -1229,7 +1343,7 @@ version = "0.5.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.1.14",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1276,7 +1390,7 @@ version = "0.1.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
|
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cloudabi",
|
"cloudabi 0.0.3",
|
||||||
"fuchsia-cprng",
|
"fuchsia-cprng",
|
||||||
"libc",
|
"libc",
|
||||||
"rand_core 0.4.2",
|
"rand_core 0.4.2",
|
||||||
@ -1383,6 +1497,12 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
|
checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "seahash"
|
name = "seahash"
|
||||||
version = "4.0.1"
|
version = "4.0.1"
|
||||||
@ -1438,6 +1558,7 @@ version = "1.0.57"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
|
checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
@ -1474,7 +1595,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "170a36ea86c864a3f16dd2687712dd6646f7019f301e57537c7f4dc9f5916770"
|
checksum = "170a36ea86c864a3f16dd2687712dd6646f7019f301e57537c7f4dc9f5916770"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer 0.9.0",
|
"block-buffer 0.9.0",
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"cpuid-bool",
|
"cpuid-bool",
|
||||||
"digest 0.9.0",
|
"digest 0.9.0",
|
||||||
"opaque-debug 0.3.0",
|
"opaque-debug 0.3.0",
|
||||||
@ -1482,14 +1603,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.8.2"
|
version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69"
|
checksum = "6e7aab86fe2149bad8c507606bdb3f4ef5e7b2380eb92350f56122cca72a42a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"block-buffer 0.7.3",
|
"block-buffer 0.9.0",
|
||||||
"digest 0.8.1",
|
"cfg-if 1.0.0",
|
||||||
"fake-simd",
|
"cpuid-bool",
|
||||||
"opaque-debug 0.2.3",
|
"digest 0.9.0",
|
||||||
|
"opaque-debug 0.3.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1519,7 +1641,7 @@ version = "0.3.12"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918"
|
checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
@ -1538,9 +1660,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx"
|
name = "sqlx"
|
||||||
version = "0.3.5"
|
version = "0.4.0-beta.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/launchbadge/sqlx?branch=master#12b4250454b13fa2699dee9a4c761154ae60ddb6"
|
||||||
checksum = "8974cacd80085fbe49e778708d660dec6fb351604dc34c3905b26efb2803b038"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
"sqlx-macros",
|
"sqlx-macros",
|
||||||
@ -1548,64 +1669,94 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-core"
|
name = "sqlx-core"
|
||||||
version = "0.3.5"
|
version = "0.4.0-beta.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/launchbadge/sqlx?branch=master#12b4250454b13fa2699dee9a4c761154ae60ddb6"
|
||||||
checksum = "88ac5a436f941c42eac509471a730df5c3c58e1450e68cd39afedbd948206273"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-native-tls",
|
"ahash 0.5.8",
|
||||||
"async-stream",
|
"atoi",
|
||||||
"base64",
|
"base64 0.13.0",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
"crossbeam-channel",
|
||||||
"crossbeam-queue",
|
"crossbeam-queue",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
|
"either",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hex",
|
"hex",
|
||||||
"hmac",
|
"hmac",
|
||||||
"ipnetwork",
|
"ipnetwork",
|
||||||
|
"itoa",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
"lru-cache",
|
||||||
"md-5",
|
"md-5",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
"once_cell",
|
||||||
|
"parking_lot",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha-1 0.8.2",
|
"sha-1 0.9.1",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
"smallvec",
|
||||||
"sqlformat",
|
"sqlformat",
|
||||||
"tokio",
|
"sqlx-rt",
|
||||||
|
"stringprep",
|
||||||
|
"thiserror",
|
||||||
"url",
|
"url",
|
||||||
"uuid 0.8.1",
|
"uuid 0.8.1",
|
||||||
|
"whoami",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sqlx-macros"
|
name = "sqlx-macros"
|
||||||
version = "0.3.5"
|
version = "0.4.0-beta.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/launchbadge/sqlx?branch=master#12b4250454b13fa2699dee9a4c761154ae60ddb6"
|
||||||
checksum = "de2ae78b783af5922d811b14665a5a3755e531c3087bb805cf24cf71f15e6780"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dotenv",
|
"dotenv",
|
||||||
|
"either",
|
||||||
"futures",
|
"futures",
|
||||||
"heck",
|
"heck",
|
||||||
"lazy_static",
|
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sqlx-core",
|
"sqlx-core",
|
||||||
|
"sqlx-rt",
|
||||||
"syn",
|
"syn",
|
||||||
"tokio",
|
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "subtle"
|
name = "sqlx-rt"
|
||||||
version = "1.0.0"
|
version = "0.1.1"
|
||||||
|
source = "git+https://github.com/launchbadge/sqlx?branch=master#12b4250454b13fa2699dee9a4c761154ae60ddb6"
|
||||||
|
dependencies = [
|
||||||
|
"native-tls",
|
||||||
|
"once_cell",
|
||||||
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "stringprep"
|
||||||
|
version = "0.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee"
|
checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-bidi",
|
||||||
|
"unicode-normalization",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
@ -1624,7 +1775,7 @@ version = "3.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"libc",
|
"libc",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
@ -1709,6 +1860,16 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-native-tls"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd608593a919a8e05a7d1fc6df885e40f6a88d3a70a3a7eff23ff27964eda069"
|
||||||
|
dependencies = [
|
||||||
|
"native-tls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-tungstenite"
|
name = "tokio-tungstenite"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
@ -1748,7 +1909,7 @@ version = "0.1.18"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0aae59226cf195d8e74d4b34beae1859257efb4e5fed3f147d2dc2c7d372178"
|
checksum = "f0aae59226cf195d8e74d4b34beae1859257efb4e5fed3f147d2dc2c7d372178"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
"log",
|
"log",
|
||||||
"tracing-attributes",
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
@ -1837,7 +1998,7 @@ version = "0.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0308d80d86700c5878b9ef6321f020f29b1bb9d5ff3cab25e75e23f3a492a23"
|
checksum = "f0308d80d86700c5878b9ef6321f020f29b1bb9d5ff3cab25e75e23f3a492a23"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64 0.12.3",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes",
|
"bytes",
|
||||||
"http",
|
"http",
|
||||||
@ -1933,7 +2094,7 @@ version = "0.6.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363"
|
checksum = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if 0.1.10",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2003,6 +2164,12 @@ version = "0.9.0+wasi-snapshot-preview1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "whoami"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7884773ab69074615cb8f8425d0e53f11710786158704fca70f53e71b0e05504"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi"
|
name = "winapi"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
|
@ -18,12 +18,12 @@ listenfd = "0.3"
|
|||||||
mime = "0.3"
|
mime = "0.3"
|
||||||
openssl-probe = "0.1"
|
openssl-probe = "0.1"
|
||||||
tokio = { version = "0.2", features = ["macros", "rt-threaded", "sync"] }
|
tokio = { version = "0.2", features = ["macros", "rt-threaded", "sync"] }
|
||||||
sqlx = { version = "0.3", default-features = false, features = [ "runtime-tokio", "macros", "postgres", "chrono", "uuid", "ipnetwork", "json" ] }
|
sqlx = { git = "https://github.com/launchbadge/sqlx", branch = "master", default-features = false, features = [ "runtime-tokio", "macros", "postgres", "chrono", "uuid", "ipnetwork", "json" ] }
|
||||||
warp = { version = "0.2", features = ["compression"] }
|
warp = { version = "0.2", features = ["compression"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
uuid = { version = "0.8", features = ["serde", "v4"] }
|
uuid = { version = "0.8", features = ["serde", "v4"] }
|
||||||
ipnetwork = "0.16"
|
ipnetwork = "0.17"
|
||||||
url = "2.1"
|
url = "2.1"
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
seahash = "4.0"
|
seahash = "4.0"
|
||||||
|
@ -6,7 +6,7 @@ use warp::reply::{with_header, with_status};
|
|||||||
use warp::{Rejection, Reply};
|
use warp::{Rejection, Reply};
|
||||||
|
|
||||||
use crate::caches::CACHES;
|
use crate::caches::CACHES;
|
||||||
use crate::models::{InteriorRefList, ListParams};
|
use crate::models::{InteriorRefList, ListParams, PostedInteriorRefList, UnsavedInteriorRefList};
|
||||||
use crate::problem::reject_anyhow;
|
use crate::problem::reject_anyhow;
|
||||||
use crate::Environment;
|
use crate::Environment;
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ pub async fn list(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create(
|
pub async fn create(
|
||||||
interior_ref_list: InteriorRefList,
|
interior_ref_list: PostedInteriorRefList,
|
||||||
api_key: Option<Uuid>,
|
api_key: Option<Uuid>,
|
||||||
content_type: Option<Mime>,
|
content_type: Option<Mime>,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
@ -119,12 +119,12 @@ pub async fn create(
|
|||||||
_ => ContentType::Json,
|
_ => ContentType::Json,
|
||||||
};
|
};
|
||||||
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
||||||
let ref_list_with_owner_id = InteriorRefList {
|
let unsaved_interior_ref_list = UnsavedInteriorRefList {
|
||||||
owner_id: Some(owner_id),
|
owner_id,
|
||||||
..interior_ref_list
|
shop_id: interior_ref_list.shop_id,
|
||||||
|
ref_list: interior_ref_list.ref_list,
|
||||||
};
|
};
|
||||||
let saved_interior_ref_list = ref_list_with_owner_id
|
let saved_interior_ref_list = InteriorRefList::create(unsaved_interior_ref_list, &env.db)
|
||||||
.create(&env.db)
|
|
||||||
.await
|
.await
|
||||||
.map_err(reject_anyhow)?;
|
.map_err(reject_anyhow)?;
|
||||||
let url = saved_interior_ref_list
|
let url = saved_interior_ref_list
|
||||||
@ -159,7 +159,7 @@ pub async fn create(
|
|||||||
|
|
||||||
pub async fn update(
|
pub async fn update(
|
||||||
id: i32,
|
id: i32,
|
||||||
interior_ref_list: InteriorRefList,
|
interior_ref_list: PostedInteriorRefList,
|
||||||
api_key: Option<Uuid>,
|
api_key: Option<Uuid>,
|
||||||
content_type: Option<Mime>,
|
content_type: Option<Mime>,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
@ -171,22 +171,10 @@ pub async fn update(
|
|||||||
_ => ContentType::Json,
|
_ => ContentType::Json,
|
||||||
};
|
};
|
||||||
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
||||||
let interior_ref_list_with_id_and_owner_id = if interior_ref_list.owner_id.is_some() {
|
let updated_interior_ref_list =
|
||||||
InteriorRefList {
|
InteriorRefList::update(interior_ref_list, &env.db, owner_id, id)
|
||||||
id: Some(id),
|
.await
|
||||||
..interior_ref_list
|
.map_err(reject_anyhow)?;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
InteriorRefList {
|
|
||||||
id: Some(id),
|
|
||||||
owner_id: Some(owner_id),
|
|
||||||
..interior_ref_list
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let updated_interior_ref_list = interior_ref_list_with_id_and_owner_id
|
|
||||||
.update(&env.db, owner_id, id)
|
|
||||||
.await
|
|
||||||
.map_err(reject_anyhow)?;
|
|
||||||
let url = updated_interior_ref_list
|
let url = updated_interior_ref_list
|
||||||
.url(&env.api_url)
|
.url(&env.api_url)
|
||||||
.map_err(reject_anyhow)?;
|
.map_err(reject_anyhow)?;
|
||||||
@ -221,7 +209,7 @@ pub async fn update(
|
|||||||
|
|
||||||
pub async fn update_by_shop_id(
|
pub async fn update_by_shop_id(
|
||||||
shop_id: i32,
|
shop_id: i32,
|
||||||
interior_ref_list: InteriorRefList,
|
interior_ref_list: PostedInteriorRefList,
|
||||||
api_key: Option<Uuid>,
|
api_key: Option<Uuid>,
|
||||||
content_type: Option<Mime>,
|
content_type: Option<Mime>,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
@ -233,14 +221,10 @@ pub async fn update_by_shop_id(
|
|||||||
_ => ContentType::Json,
|
_ => ContentType::Json,
|
||||||
};
|
};
|
||||||
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
||||||
let interior_ref_list_with_owner_id = InteriorRefList {
|
let updated_interior_ref_list =
|
||||||
owner_id: Some(owner_id),
|
InteriorRefList::update_by_shop_id(interior_ref_list, &env.db, owner_id, shop_id)
|
||||||
..interior_ref_list
|
.await
|
||||||
};
|
.map_err(reject_anyhow)?;
|
||||||
let updated_interior_ref_list = interior_ref_list_with_owner_id
|
|
||||||
.update_by_shop_id(&env.db, owner_id, shop_id)
|
|
||||||
.await
|
|
||||||
.map_err(reject_anyhow)?;
|
|
||||||
let url = updated_interior_ref_list
|
let url = updated_interior_ref_list
|
||||||
.url(&env.api_url)
|
.url(&env.api_url)
|
||||||
.map_err(reject_anyhow)?;
|
.map_err(reject_anyhow)?;
|
||||||
@ -257,11 +241,14 @@ pub async fn update_by_shop_id(
|
|||||||
let reply = with_header(reply, "Location", url.as_str());
|
let reply = with_header(reply, "Location", url.as_str());
|
||||||
let reply = with_status(reply, StatusCode::CREATED);
|
let reply = with_status(reply, StatusCode::CREATED);
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let id = updated_interior_ref_list
|
CACHES
|
||||||
.id
|
.interior_ref_list
|
||||||
.expect("saved interior_ref_list has no id");
|
.delete_response(updated_interior_ref_list.id)
|
||||||
CACHES.interior_ref_list.delete_response(id).await;
|
.await;
|
||||||
CACHES.interior_ref_list_bin.delete_response(id).await;
|
CACHES
|
||||||
|
.interior_ref_list_bin
|
||||||
|
.delete_response(updated_interior_ref_list.id)
|
||||||
|
.await;
|
||||||
CACHES
|
CACHES
|
||||||
.interior_ref_list_by_shop_id
|
.interior_ref_list_by_shop_id
|
||||||
.delete_response(updated_interior_ref_list.shop_id)
|
.delete_response(updated_interior_ref_list.shop_id)
|
||||||
|
@ -6,7 +6,7 @@ use warp::reply::{with_header, with_status};
|
|||||||
use warp::{Rejection, Reply};
|
use warp::{Rejection, Reply};
|
||||||
|
|
||||||
use crate::caches::CACHES;
|
use crate::caches::CACHES;
|
||||||
use crate::models::{ListParams, MerchandiseList};
|
use crate::models::{ListParams, MerchandiseList, PostedMerchandiseList, UnsavedMerchandiseList};
|
||||||
use crate::problem::reject_anyhow;
|
use crate::problem::reject_anyhow;
|
||||||
use crate::Environment;
|
use crate::Environment;
|
||||||
|
|
||||||
@ -105,7 +105,7 @@ pub async fn list(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create(
|
pub async fn create(
|
||||||
merchandise_list: MerchandiseList,
|
merchandise_list: PostedMerchandiseList,
|
||||||
api_key: Option<Uuid>,
|
api_key: Option<Uuid>,
|
||||||
content_type: Option<Mime>,
|
content_type: Option<Mime>,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
@ -117,12 +117,12 @@ pub async fn create(
|
|||||||
_ => ContentType::Json,
|
_ => ContentType::Json,
|
||||||
};
|
};
|
||||||
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
||||||
let ref_list_with_owner_id = MerchandiseList {
|
let unsaved_merchandise_list = UnsavedMerchandiseList {
|
||||||
owner_id: Some(owner_id),
|
owner_id,
|
||||||
..merchandise_list
|
shop_id: merchandise_list.shop_id,
|
||||||
|
form_list: merchandise_list.form_list,
|
||||||
};
|
};
|
||||||
let saved_merchandise_list = ref_list_with_owner_id
|
let saved_merchandise_list = MerchandiseList::create(unsaved_merchandise_list, &env.db)
|
||||||
.create(&env.db)
|
|
||||||
.await
|
.await
|
||||||
.map_err(reject_anyhow)?;
|
.map_err(reject_anyhow)?;
|
||||||
let url = saved_merchandise_list
|
let url = saved_merchandise_list
|
||||||
@ -156,7 +156,7 @@ pub async fn create(
|
|||||||
|
|
||||||
pub async fn update(
|
pub async fn update(
|
||||||
id: i32,
|
id: i32,
|
||||||
merchandise_list: MerchandiseList,
|
merchandise_list: PostedMerchandiseList,
|
||||||
api_key: Option<Uuid>,
|
api_key: Option<Uuid>,
|
||||||
content_type: Option<Mime>,
|
content_type: Option<Mime>,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
@ -168,20 +168,7 @@ pub async fn update(
|
|||||||
_ => ContentType::Json,
|
_ => ContentType::Json,
|
||||||
};
|
};
|
||||||
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
||||||
let merchandise_list_with_id_and_owner_id = if merchandise_list.owner_id.is_some() {
|
let updated_merchandise_list = MerchandiseList::update(merchandise_list, &env.db, owner_id, id)
|
||||||
MerchandiseList {
|
|
||||||
id: Some(id),
|
|
||||||
..merchandise_list
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
MerchandiseList {
|
|
||||||
id: Some(id),
|
|
||||||
owner_id: Some(owner_id),
|
|
||||||
..merchandise_list
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let updated_merchandise_list = merchandise_list_with_id_and_owner_id
|
|
||||||
.update(&env.db, owner_id, id)
|
|
||||||
.await
|
.await
|
||||||
.map_err(reject_anyhow)?;
|
.map_err(reject_anyhow)?;
|
||||||
let url = updated_merchandise_list
|
let url = updated_merchandise_list
|
||||||
@ -218,7 +205,7 @@ pub async fn update(
|
|||||||
|
|
||||||
pub async fn update_by_shop_id(
|
pub async fn update_by_shop_id(
|
||||||
shop_id: i32,
|
shop_id: i32,
|
||||||
merchandise_list: MerchandiseList,
|
merchandise_list: PostedMerchandiseList,
|
||||||
api_key: Option<Uuid>,
|
api_key: Option<Uuid>,
|
||||||
content_type: Option<Mime>,
|
content_type: Option<Mime>,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
@ -230,14 +217,10 @@ pub async fn update_by_shop_id(
|
|||||||
_ => ContentType::Json,
|
_ => ContentType::Json,
|
||||||
};
|
};
|
||||||
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
||||||
let merchandise_list_with_owner_id = MerchandiseList {
|
let updated_merchandise_list =
|
||||||
owner_id: Some(owner_id),
|
MerchandiseList::update_by_shop_id(merchandise_list, &env.db, owner_id, shop_id)
|
||||||
..merchandise_list
|
.await
|
||||||
};
|
.map_err(reject_anyhow)?;
|
||||||
let updated_merchandise_list = merchandise_list_with_owner_id
|
|
||||||
.update_by_shop_id(&env.db, owner_id, shop_id)
|
|
||||||
.await
|
|
||||||
.map_err(reject_anyhow)?;
|
|
||||||
let url = updated_merchandise_list
|
let url = updated_merchandise_list
|
||||||
.url(&env.api_url)
|
.url(&env.api_url)
|
||||||
.map_err(reject_anyhow)?;
|
.map_err(reject_anyhow)?;
|
||||||
@ -254,11 +237,14 @@ pub async fn update_by_shop_id(
|
|||||||
let reply = with_header(reply, "Location", url.as_str());
|
let reply = with_header(reply, "Location", url.as_str());
|
||||||
let reply = with_status(reply, StatusCode::CREATED);
|
let reply = with_status(reply, StatusCode::CREATED);
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let id = updated_merchandise_list
|
CACHES
|
||||||
.id
|
.merchandise_list
|
||||||
.expect("saved merchandise_list has no id");
|
.delete_response(updated_merchandise_list.id)
|
||||||
CACHES.merchandise_list.delete_response(id).await;
|
.await;
|
||||||
CACHES.merchandise_list_bin.delete_response(id).await;
|
CACHES
|
||||||
|
.merchandise_list_bin
|
||||||
|
.delete_response(updated_merchandise_list.id)
|
||||||
|
.await;
|
||||||
CACHES
|
CACHES
|
||||||
.merchandise_list_by_shop_id
|
.merchandise_list_by_shop_id
|
||||||
.delete_response(updated_merchandise_list.shop_id)
|
.delete_response(updated_merchandise_list.shop_id)
|
||||||
|
@ -8,7 +8,7 @@ use warp::reply::{with_header, with_status};
|
|||||||
use warp::{Rejection, Reply};
|
use warp::{Rejection, Reply};
|
||||||
|
|
||||||
use crate::caches::CACHES;
|
use crate::caches::CACHES;
|
||||||
use crate::models::{ListParams, Owner};
|
use crate::models::{ListParams, Owner, PostedOwner, UnsavedOwner};
|
||||||
use crate::problem::{reject_anyhow, unauthorized_no_api_key};
|
use crate::problem::{reject_anyhow, unauthorized_no_api_key};
|
||||||
use crate::Environment;
|
use crate::Environment;
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ pub async fn list(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create(
|
pub async fn create(
|
||||||
owner: Owner,
|
owner: PostedOwner,
|
||||||
remote_addr: Option<SocketAddr>,
|
remote_addr: Option<SocketAddr>,
|
||||||
api_key: Option<Uuid>,
|
api_key: Option<Uuid>,
|
||||||
real_ip: Option<IpNetwork>,
|
real_ip: Option<IpNetwork>,
|
||||||
@ -79,20 +79,16 @@ pub async fn create(
|
|||||||
}
|
}
|
||||||
_ => ContentType::Json,
|
_ => ContentType::Json,
|
||||||
};
|
};
|
||||||
let owner_with_ip_and_key = match remote_addr {
|
let unsaved_owner = UnsavedOwner {
|
||||||
Some(addr) => Owner {
|
api_key,
|
||||||
api_key: Some(api_key),
|
ip_address: match remote_addr {
|
||||||
ip_address: Some(IpNetwork::from(addr.ip())),
|
Some(addr) => Some(IpNetwork::from(addr.ip())),
|
||||||
..owner
|
None => real_ip,
|
||||||
},
|
|
||||||
None => Owner {
|
|
||||||
api_key: Some(api_key),
|
|
||||||
ip_address: real_ip,
|
|
||||||
..owner
|
|
||||||
},
|
},
|
||||||
|
name: owner.name,
|
||||||
|
mod_version: owner.mod_version,
|
||||||
};
|
};
|
||||||
let saved_owner = owner_with_ip_and_key
|
let saved_owner = Owner::create(unsaved_owner, &env.db)
|
||||||
.create(&env.db)
|
|
||||||
.await
|
.await
|
||||||
.map_err(reject_anyhow)?;
|
.map_err(reject_anyhow)?;
|
||||||
let url = saved_owner.url(&env.api_url).map_err(reject_anyhow)?;
|
let url = saved_owner.url(&env.api_url).map_err(reject_anyhow)?;
|
||||||
@ -118,7 +114,7 @@ pub async fn create(
|
|||||||
|
|
||||||
pub async fn update(
|
pub async fn update(
|
||||||
id: i32,
|
id: i32,
|
||||||
owner: Owner,
|
owner: PostedOwner,
|
||||||
api_key: Option<Uuid>,
|
api_key: Option<Uuid>,
|
||||||
content_type: Option<Mime>,
|
content_type: Option<Mime>,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
@ -130,12 +126,7 @@ pub async fn update(
|
|||||||
_ => ContentType::Json,
|
_ => ContentType::Json,
|
||||||
};
|
};
|
||||||
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
||||||
let owner_with_id = Owner {
|
let updated_owner = Owner::update(owner, &env.db, owner_id, id)
|
||||||
id: Some(id),
|
|
||||||
..owner
|
|
||||||
};
|
|
||||||
let updated_owner = owner_with_id
|
|
||||||
.update(&env.db, owner_id, id)
|
|
||||||
.await
|
.await
|
||||||
.map_err(reject_anyhow)?;
|
.map_err(reject_anyhow)?;
|
||||||
let url = updated_owner.url(&env.api_url).map_err(reject_anyhow)?;
|
let url = updated_owner.url(&env.api_url).map_err(reject_anyhow)?;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use anyhow::Result;
|
use anyhow::{anyhow, Result};
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
use mime::Mime;
|
use mime::Mime;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -6,7 +6,10 @@ use warp::reply::{with_header, with_status};
|
|||||||
use warp::{Rejection, Reply};
|
use warp::{Rejection, Reply};
|
||||||
|
|
||||||
use crate::caches::CACHES;
|
use crate::caches::CACHES;
|
||||||
use crate::models::{InteriorRefList, ListParams, MerchandiseList, Shop};
|
use crate::models::{
|
||||||
|
InteriorRefList, ListParams, MerchandiseList, PostedShop, Shop, UnsavedInteriorRefList,
|
||||||
|
UnsavedMerchandiseList, UnsavedShop,
|
||||||
|
};
|
||||||
use crate::problem::reject_anyhow;
|
use crate::problem::reject_anyhow;
|
||||||
use crate::Environment;
|
use crate::Environment;
|
||||||
|
|
||||||
@ -63,7 +66,7 @@ pub async fn list(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create(
|
pub async fn create(
|
||||||
shop: Shop,
|
shop: PostedShop,
|
||||||
api_key: Option<Uuid>,
|
api_key: Option<Uuid>,
|
||||||
content_type: Option<Mime>,
|
content_type: Option<Mime>,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
@ -75,43 +78,40 @@ pub async fn create(
|
|||||||
_ => ContentType::Json,
|
_ => ContentType::Json,
|
||||||
};
|
};
|
||||||
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
||||||
let shop_with_owner_id = Shop {
|
let unsaved_shop = UnsavedShop {
|
||||||
owner_id: Some(owner_id),
|
name: shop.name,
|
||||||
..shop
|
description: shop.description,
|
||||||
|
owner_id,
|
||||||
};
|
};
|
||||||
let saved_shop = shop_with_owner_id
|
let mut tx = env
|
||||||
.create(&env.db)
|
.db
|
||||||
|
.begin()
|
||||||
|
.await
|
||||||
|
.map_err(|error| reject_anyhow(anyhow!(error)))?;
|
||||||
|
let saved_shop = Shop::create(unsaved_shop, &mut tx)
|
||||||
.await
|
.await
|
||||||
.map_err(reject_anyhow)?;
|
.map_err(reject_anyhow)?;
|
||||||
|
|
||||||
// also save empty interior_ref_list and merchandise_list rows
|
// also save empty interior_ref_list and merchandise_list rows
|
||||||
// TODO: do this in a transaction with shop.create
|
let interior_ref_list = UnsavedInteriorRefList {
|
||||||
if let Some(shop_id) = saved_shop.id {
|
shop_id: saved_shop.id,
|
||||||
let interior_ref_list = InteriorRefList {
|
owner_id,
|
||||||
id: None,
|
ref_list: sqlx::types::Json::default(),
|
||||||
shop_id,
|
};
|
||||||
owner_id: Some(owner_id),
|
InteriorRefList::create(interior_ref_list, &mut tx)
|
||||||
ref_list: sqlx::types::Json::default(),
|
.await
|
||||||
created_at: None,
|
.map_err(reject_anyhow)?;
|
||||||
updated_at: None,
|
let merchandise_list = UnsavedMerchandiseList {
|
||||||
};
|
shop_id: saved_shop.id,
|
||||||
interior_ref_list
|
owner_id,
|
||||||
.create(&env.db)
|
form_list: sqlx::types::Json::default(),
|
||||||
.await
|
};
|
||||||
.map_err(reject_anyhow)?;
|
MerchandiseList::create(merchandise_list, &mut tx)
|
||||||
let merchandise_list = MerchandiseList {
|
.await
|
||||||
id: None,
|
.map_err(reject_anyhow)?;
|
||||||
shop_id,
|
tx.commit()
|
||||||
owner_id: Some(owner_id),
|
.await
|
||||||
form_list: sqlx::types::Json::default(),
|
.map_err(|error| reject_anyhow(anyhow!(error)))?;
|
||||||
created_at: None,
|
|
||||||
updated_at: None,
|
|
||||||
};
|
|
||||||
merchandise_list
|
|
||||||
.create(&env.db)
|
|
||||||
.await
|
|
||||||
.map_err(reject_anyhow)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let url = saved_shop.url(&env.api_url).map_err(reject_anyhow)?;
|
let url = saved_shop.url(&env.api_url).map_err(reject_anyhow)?;
|
||||||
let reply: Box<dyn Reply> = match content_type {
|
let reply: Box<dyn Reply> = match content_type {
|
||||||
@ -133,7 +133,7 @@ pub async fn create(
|
|||||||
|
|
||||||
pub async fn update(
|
pub async fn update(
|
||||||
id: i32,
|
id: i32,
|
||||||
shop: Shop,
|
shop: PostedShop,
|
||||||
api_key: Option<Uuid>,
|
api_key: Option<Uuid>,
|
||||||
content_type: Option<Mime>,
|
content_type: Option<Mime>,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
@ -145,21 +145,15 @@ pub async fn update(
|
|||||||
_ => ContentType::Json,
|
_ => ContentType::Json,
|
||||||
};
|
};
|
||||||
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
||||||
let shop_with_id_and_owner_id = if shop.owner_id.is_some() {
|
let posted_shop = PostedShop {
|
||||||
// allows an owner to transfer ownership of shop to another owner
|
owner_id: match shop.owner_id {
|
||||||
Shop {
|
// allows an owner to transfer ownership of shop to another owner
|
||||||
id: Some(id),
|
Some(posted_owner_id) => Some(posted_owner_id),
|
||||||
..shop
|
None => Some(owner_id),
|
||||||
}
|
},
|
||||||
} else {
|
..shop
|
||||||
Shop {
|
|
||||||
id: Some(id),
|
|
||||||
owner_id: Some(owner_id),
|
|
||||||
..shop
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let updated_shop = shop_with_id_and_owner_id
|
let updated_shop = Shop::update(posted_shop, &env.db, owner_id, id)
|
||||||
.update(&env.db, owner_id, id)
|
|
||||||
.await
|
.await
|
||||||
.map_err(reject_anyhow)?;
|
.map_err(reject_anyhow)?;
|
||||||
let url = updated_shop.url(&env.api_url).map_err(reject_anyhow)?;
|
let url = updated_shop.url(&env.api_url).map_err(reject_anyhow)?;
|
||||||
|
@ -6,7 +6,9 @@ use warp::reply::{with_header, with_status};
|
|||||||
use warp::{Rejection, Reply};
|
use warp::{Rejection, Reply};
|
||||||
|
|
||||||
use crate::caches::CACHES;
|
use crate::caches::CACHES;
|
||||||
use crate::models::{ListParams, MerchandiseList, Transaction};
|
use crate::models::{
|
||||||
|
ListParams, MerchandiseList, PostedTransaction, Transaction, UnsavedTransaction,
|
||||||
|
};
|
||||||
use crate::problem::reject_anyhow;
|
use crate::problem::reject_anyhow;
|
||||||
use crate::Environment;
|
use crate::Environment;
|
||||||
|
|
||||||
@ -99,7 +101,7 @@ pub async fn list_by_shop_id(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create(
|
pub async fn create(
|
||||||
transaction: Transaction,
|
transaction: PostedTransaction,
|
||||||
api_key: Option<Uuid>,
|
api_key: Option<Uuid>,
|
||||||
content_type: Option<Mime>,
|
content_type: Option<Mime>,
|
||||||
env: Environment,
|
env: Environment,
|
||||||
@ -111,17 +113,25 @@ pub async fn create(
|
|||||||
_ => ContentType::Json,
|
_ => ContentType::Json,
|
||||||
};
|
};
|
||||||
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
let owner_id = authenticate(&env, api_key).await.map_err(reject_anyhow)?;
|
||||||
let transaction_with_owner_id = Transaction {
|
let unsaved_transaction = UnsavedTransaction {
|
||||||
owner_id: Some(owner_id),
|
shop_id: transaction.shop_id,
|
||||||
..transaction
|
owner_id,
|
||||||
|
mod_name: transaction.mod_name,
|
||||||
|
local_form_id: transaction.local_form_id,
|
||||||
|
name: transaction.name,
|
||||||
|
form_type: transaction.form_type,
|
||||||
|
is_food: transaction.is_food,
|
||||||
|
price: transaction.price,
|
||||||
|
is_sell: transaction.is_sell,
|
||||||
|
quantity: transaction.quantity,
|
||||||
|
amount: transaction.amount,
|
||||||
};
|
};
|
||||||
let mut tx = env
|
let mut tx = env
|
||||||
.db
|
.db
|
||||||
.begin()
|
.begin()
|
||||||
.await
|
.await
|
||||||
.map_err(|error| reject_anyhow(anyhow!(error)))?;
|
.map_err(|error| reject_anyhow(anyhow!(error)))?;
|
||||||
let saved_transaction = transaction_with_owner_id
|
let saved_transaction = Transaction::create(unsaved_transaction, &mut tx)
|
||||||
.create(&mut tx)
|
|
||||||
.await
|
.await
|
||||||
.map_err(reject_anyhow)?;
|
.map_err(reject_anyhow)?;
|
||||||
let quantity_delta = match transaction.is_sell {
|
let quantity_delta = match transaction.is_sell {
|
||||||
@ -157,11 +167,14 @@ pub async fn create(
|
|||||||
let reply = with_status(reply, StatusCode::CREATED);
|
let reply = with_status(reply, StatusCode::CREATED);
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
// TODO: will this make these caches effectively useless?
|
// TODO: will this make these caches effectively useless?
|
||||||
let merch_id = updated_merchandise_list
|
CACHES
|
||||||
.id
|
.merchandise_list
|
||||||
.expect("saved merchandise_list has no id");
|
.delete_response(updated_merchandise_list.id)
|
||||||
CACHES.merchandise_list.delete_response(merch_id).await;
|
.await;
|
||||||
CACHES.merchandise_list_bin.delete_response(merch_id).await;
|
CACHES
|
||||||
|
.merchandise_list_bin
|
||||||
|
.delete_response(updated_merchandise_list.id)
|
||||||
|
.await;
|
||||||
CACHES
|
CACHES
|
||||||
.merchandise_list_by_shop_id
|
.merchandise_list_by_shop_id
|
||||||
.delete_response(updated_merchandise_list.shop_id)
|
.delete_response(updated_merchandise_list.shop_id)
|
||||||
|
38
src/main.rs
38
src/main.rs
@ -7,7 +7,8 @@ use http::StatusCode;
|
|||||||
use hyper::server::Server;
|
use hyper::server::Server;
|
||||||
use listenfd::ListenFd;
|
use listenfd::ListenFd;
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
use sqlx::postgres::PgPool;
|
use sqlx::postgres::PgPoolOptions;
|
||||||
|
use sqlx::{Pool, Postgres};
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use std::env;
|
use std::env;
|
||||||
use tracing_subscriber::fmt::format::FmtSpan;
|
use tracing_subscriber::fmt::format::FmtSpan;
|
||||||
@ -21,20 +22,23 @@ mod macros;
|
|||||||
mod models;
|
mod models;
|
||||||
mod problem;
|
mod problem;
|
||||||
|
|
||||||
use models::{InteriorRefList, ListParams, MerchandiseList, Owner, Shop, Transaction};
|
use models::{
|
||||||
|
ListParams, PostedInteriorRefList, PostedMerchandiseList, PostedOwner, PostedShop,
|
||||||
|
PostedTransaction,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Environment {
|
pub struct Environment {
|
||||||
pub db: PgPool,
|
pub db: Pool<Postgres>,
|
||||||
pub api_url: Url,
|
pub api_url: Url,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Environment {
|
impl Environment {
|
||||||
async fn new(api_url: Url) -> Result<Environment> {
|
async fn new(api_url: Url) -> Result<Environment> {
|
||||||
Ok(Environment {
|
Ok(Environment {
|
||||||
db: PgPool::builder()
|
db: PgPoolOptions::new()
|
||||||
.max_size(5)
|
.max_connections(5)
|
||||||
.build(&env::var("DATABASE_URL")?)
|
.connect(&env::var("DATABASE_URL")?)
|
||||||
.await?,
|
.await?,
|
||||||
api_url,
|
api_url,
|
||||||
})
|
})
|
||||||
@ -90,7 +94,7 @@ async fn main() -> Result<()> {
|
|||||||
let create_owner_handler = warp::path("owners").and(
|
let create_owner_handler = warp::path("owners").and(
|
||||||
warp::path::end()
|
warp::path::end()
|
||||||
.and(warp::post())
|
.and(warp::post())
|
||||||
.and(json_body::<Owner>())
|
.and(json_body::<PostedOwner>())
|
||||||
.and(warp::addr::remote())
|
.and(warp::addr::remote())
|
||||||
.and(warp::header::optional("api-key"))
|
.and(warp::header::optional("api-key"))
|
||||||
.and(warp::header::optional("x-real-ip"))
|
.and(warp::header::optional("x-real-ip"))
|
||||||
@ -110,7 +114,7 @@ async fn main() -> Result<()> {
|
|||||||
warp::path::param()
|
warp::path::param()
|
||||||
.and(warp::path::end())
|
.and(warp::path::end())
|
||||||
.and(warp::patch())
|
.and(warp::patch())
|
||||||
.and(json_body::<Owner>())
|
.and(json_body::<PostedOwner>())
|
||||||
.and(warp::header::optional("api-key"))
|
.and(warp::header::optional("api-key"))
|
||||||
.and(warp::header::optional("content-type"))
|
.and(warp::header::optional("content-type"))
|
||||||
.and(with_env(env.clone()))
|
.and(with_env(env.clone()))
|
||||||
@ -137,7 +141,7 @@ async fn main() -> Result<()> {
|
|||||||
let create_shop_handler = warp::path("shops").and(
|
let create_shop_handler = warp::path("shops").and(
|
||||||
warp::path::end()
|
warp::path::end()
|
||||||
.and(warp::post())
|
.and(warp::post())
|
||||||
.and(json_body::<Shop>())
|
.and(json_body::<PostedShop>())
|
||||||
.and(warp::header::optional("api-key"))
|
.and(warp::header::optional("api-key"))
|
||||||
.and(warp::header::optional("content-type"))
|
.and(warp::header::optional("content-type"))
|
||||||
.and(with_env(env.clone()))
|
.and(with_env(env.clone()))
|
||||||
@ -155,7 +159,7 @@ async fn main() -> Result<()> {
|
|||||||
warp::path::param()
|
warp::path::param()
|
||||||
.and(warp::path::end())
|
.and(warp::path::end())
|
||||||
.and(warp::patch())
|
.and(warp::patch())
|
||||||
.and(json_body::<Shop>())
|
.and(json_body::<PostedShop>())
|
||||||
.and(warp::header::optional("api-key"))
|
.and(warp::header::optional("api-key"))
|
||||||
.and(warp::header::optional("content-type"))
|
.and(warp::header::optional("content-type"))
|
||||||
.and(with_env(env.clone()))
|
.and(with_env(env.clone()))
|
||||||
@ -182,7 +186,7 @@ async fn main() -> Result<()> {
|
|||||||
let create_interior_ref_list_handler = warp::path("interior_ref_lists").and(
|
let create_interior_ref_list_handler = warp::path("interior_ref_lists").and(
|
||||||
warp::path::end()
|
warp::path::end()
|
||||||
.and(warp::post())
|
.and(warp::post())
|
||||||
.and(json_body::<InteriorRefList>())
|
.and(json_body::<PostedInteriorRefList>())
|
||||||
.and(warp::header::optional("api-key"))
|
.and(warp::header::optional("api-key"))
|
||||||
.and(warp::header::optional("content-type"))
|
.and(warp::header::optional("content-type"))
|
||||||
.and(with_env(env.clone()))
|
.and(with_env(env.clone()))
|
||||||
@ -200,7 +204,7 @@ async fn main() -> Result<()> {
|
|||||||
warp::path::param()
|
warp::path::param()
|
||||||
.and(warp::path::end())
|
.and(warp::path::end())
|
||||||
.and(warp::patch())
|
.and(warp::patch())
|
||||||
.and(json_body::<InteriorRefList>())
|
.and(json_body::<PostedInteriorRefList>())
|
||||||
.and(warp::header::optional("api-key"))
|
.and(warp::header::optional("api-key"))
|
||||||
.and(warp::header::optional("content-type"))
|
.and(warp::header::optional("content-type"))
|
||||||
.and(with_env(env.clone()))
|
.and(with_env(env.clone()))
|
||||||
@ -211,7 +215,7 @@ async fn main() -> Result<()> {
|
|||||||
.and(warp::path("interior_ref_list"))
|
.and(warp::path("interior_ref_list"))
|
||||||
.and(warp::path::end())
|
.and(warp::path::end())
|
||||||
.and(warp::patch())
|
.and(warp::patch())
|
||||||
.and(json_body::<InteriorRefList>())
|
.and(json_body::<PostedInteriorRefList>())
|
||||||
.and(warp::header::optional("api-key"))
|
.and(warp::header::optional("api-key"))
|
||||||
.and(warp::header::optional("content-type"))
|
.and(warp::header::optional("content-type"))
|
||||||
.and(with_env(env.clone()))
|
.and(with_env(env.clone()))
|
||||||
@ -248,7 +252,7 @@ async fn main() -> Result<()> {
|
|||||||
let create_merchandise_list_handler = warp::path("merchandise_lists").and(
|
let create_merchandise_list_handler = warp::path("merchandise_lists").and(
|
||||||
warp::path::end()
|
warp::path::end()
|
||||||
.and(warp::post())
|
.and(warp::post())
|
||||||
.and(json_body::<MerchandiseList>())
|
.and(json_body::<PostedMerchandiseList>())
|
||||||
.and(warp::header::optional("api-key"))
|
.and(warp::header::optional("api-key"))
|
||||||
.and(warp::header::optional("content-type"))
|
.and(warp::header::optional("content-type"))
|
||||||
.and(with_env(env.clone()))
|
.and(with_env(env.clone()))
|
||||||
@ -266,7 +270,7 @@ async fn main() -> Result<()> {
|
|||||||
warp::path::param()
|
warp::path::param()
|
||||||
.and(warp::path::end())
|
.and(warp::path::end())
|
||||||
.and(warp::patch())
|
.and(warp::patch())
|
||||||
.and(json_body::<MerchandiseList>())
|
.and(json_body::<PostedMerchandiseList>())
|
||||||
.and(warp::header::optional("api-key"))
|
.and(warp::header::optional("api-key"))
|
||||||
.and(warp::header::optional("content-type"))
|
.and(warp::header::optional("content-type"))
|
||||||
.and(with_env(env.clone()))
|
.and(with_env(env.clone()))
|
||||||
@ -277,7 +281,7 @@ async fn main() -> Result<()> {
|
|||||||
.and(warp::path("merchandise_list"))
|
.and(warp::path("merchandise_list"))
|
||||||
.and(warp::path::end())
|
.and(warp::path::end())
|
||||||
.and(warp::patch())
|
.and(warp::patch())
|
||||||
.and(json_body::<MerchandiseList>())
|
.and(json_body::<PostedMerchandiseList>())
|
||||||
.and(warp::header::optional("api-key"))
|
.and(warp::header::optional("api-key"))
|
||||||
.and(warp::header::optional("content-type"))
|
.and(warp::header::optional("content-type"))
|
||||||
.and(with_env(env.clone()))
|
.and(with_env(env.clone()))
|
||||||
@ -314,7 +318,7 @@ async fn main() -> Result<()> {
|
|||||||
let create_transaction_handler = warp::path("transactions").and(
|
let create_transaction_handler = warp::path("transactions").and(
|
||||||
warp::path::end()
|
warp::path::end()
|
||||||
.and(warp::post())
|
.and(warp::post())
|
||||||
.and(json_body::<Transaction>())
|
.and(json_body::<PostedTransaction>())
|
||||||
.and(warp::header::optional("api-key"))
|
.and(warp::header::optional("api-key"))
|
||||||
.and(warp::header::optional("content-type"))
|
.and(warp::header::optional("content-type"))
|
||||||
.and(with_env(env.clone()))
|
.and(with_env(env.clone()))
|
||||||
|
@ -1,19 +1,14 @@
|
|||||||
use anyhow::{anyhow, Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::types::Json;
|
use sqlx::types::Json;
|
||||||
use sqlx::PgPool;
|
use sqlx::{Done, Executor, Postgres};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use super::ListParams;
|
use super::ListParams;
|
||||||
use crate::problem::forbidden_permission;
|
use crate::problem::forbidden_permission;
|
||||||
|
|
||||||
// sqlx queries for this model need to be `query_as_unchecked!` because `query_as!` does not
|
|
||||||
// support user-defined types (`ref_list` Json field).
|
|
||||||
// See for more info: https://github.com/thallada/rust_sqlx_bug/blob/master/src/main.rs
|
|
||||||
// This may be fixed in sqlx 0.4.
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct InteriorRef {
|
pub struct InteriorRef {
|
||||||
pub base_mod_name: String,
|
pub base_mod_name: String,
|
||||||
@ -31,12 +26,26 @@ pub struct InteriorRef {
|
|||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct InteriorRefList {
|
pub struct InteriorRefList {
|
||||||
pub id: Option<i32>,
|
pub id: i32,
|
||||||
|
pub shop_id: i32,
|
||||||
|
pub owner_id: i32,
|
||||||
|
pub ref_list: serde_json::Value,
|
||||||
|
pub created_at: NaiveDateTime,
|
||||||
|
pub updated_at: NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct UnsavedInteriorRefList {
|
||||||
|
pub shop_id: i32,
|
||||||
|
pub owner_id: i32,
|
||||||
|
pub ref_list: Json<Vec<InteriorRef>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct PostedInteriorRefList {
|
||||||
pub shop_id: i32,
|
pub shop_id: i32,
|
||||||
pub owner_id: Option<i32>,
|
pub owner_id: Option<i32>,
|
||||||
pub ref_list: Json<Vec<InteriorRef>>,
|
pub ref_list: Json<Vec<InteriorRef>>,
|
||||||
pub created_at: Option<NaiveDateTime>,
|
|
||||||
pub updated_at: Option<NaiveDateTime>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InteriorRefList {
|
impl InteriorRefList {
|
||||||
@ -44,52 +53,48 @@ impl InteriorRefList {
|
|||||||
"interior_ref_list"
|
"interior_ref_list"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pk(&self) -> Option<i32> {
|
pub fn pk(&self) -> i32 {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn url(&self, api_url: &Url) -> Result<Url> {
|
pub fn url(&self, api_url: &Url) -> Result<Url> {
|
||||||
if let Some(pk) = self.pk() {
|
Ok(api_url.join(&format!("{}s/{}", Self::resource_name(), self.pk()))?)
|
||||||
Ok(api_url.join(&format!("{}s/{}", Self::resource_name(), pk))?)
|
|
||||||
} else {
|
|
||||||
Err(anyhow!(
|
|
||||||
"Cannot get URL for {} with no primary key",
|
|
||||||
Self::resource_name()
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this model will probably never need to be accessed through it's ID, should these methods be removed/unimplemented?
|
// TODO: this model will probably never need to be accessed through it's ID, should these methods be removed/unimplemented?
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn get(db: &PgPool, id: i32) -> Result<Self> {
|
pub async fn get(db: impl Executor<'_, Database = Postgres>, id: i32) -> Result<Self> {
|
||||||
sqlx::query_as_unchecked!(Self, "SELECT * FROM interior_ref_lists WHERE id = $1", id)
|
sqlx::query_as!(Self, "SELECT * FROM interior_ref_lists WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await
|
.await
|
||||||
.map_err(Error::new)
|
.map_err(Error::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, db))]
|
#[instrument(level = "debug", skip(interior_ref_list, db))]
|
||||||
pub async fn create(self, db: &PgPool) -> Result<Self> {
|
pub async fn create(
|
||||||
// TODO:
|
interior_ref_list: UnsavedInteriorRefList,
|
||||||
// * Decide if I'll need to make the same changes to merchandise and transactions
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
// - answer depends on how many rows of each I expect to insert in one go
|
) -> Result<Self> {
|
||||||
// * should probably omit ref_list from response
|
Ok(sqlx::query_as!(
|
||||||
Ok(sqlx::query_as_unchecked!(
|
|
||||||
Self,
|
Self,
|
||||||
"INSERT INTO interior_ref_lists
|
"INSERT INTO interior_ref_lists
|
||||||
(shop_id, owner_id, ref_list, created_at, updated_at)
|
(shop_id, owner_id, ref_list, created_at, updated_at)
|
||||||
VALUES ($1, $2, $3, now(), now())
|
VALUES ($1, $2, $3, now(), now())
|
||||||
RETURNING *",
|
RETURNING *",
|
||||||
self.shop_id,
|
interior_ref_list.shop_id,
|
||||||
self.owner_id,
|
interior_ref_list.owner_id,
|
||||||
self.ref_list,
|
serde_json::json!(interior_ref_list.ref_list),
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn delete(db: &PgPool, owner_id: i32, id: i32) -> Result<u64> {
|
pub async fn delete(
|
||||||
|
db: impl Executor<'_, Database = Postgres> + Copy,
|
||||||
|
owner_id: i32,
|
||||||
|
id: i32,
|
||||||
|
) -> Result<u64> {
|
||||||
let interior_ref_list =
|
let interior_ref_list =
|
||||||
sqlx::query!("SELECT owner_id FROM interior_ref_lists WHERE id = $1", id)
|
sqlx::query!("SELECT owner_id FROM interior_ref_lists WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
@ -98,7 +103,8 @@ impl InteriorRefList {
|
|||||||
return Ok(
|
return Ok(
|
||||||
sqlx::query!("DELETE FROM interior_ref_lists WHERE id = $1", id)
|
sqlx::query!("DELETE FROM interior_ref_lists WHERE id = $1", id)
|
||||||
.execute(db)
|
.execute(db)
|
||||||
.await?,
|
.await?
|
||||||
|
.rows_affected(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Err(forbidden_permission());
|
return Err(forbidden_permission());
|
||||||
@ -106,9 +112,12 @@ impl InteriorRefList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn list(db: &PgPool, list_params: &ListParams) -> Result<Vec<Self>> {
|
pub async fn list(
|
||||||
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
|
list_params: &ListParams,
|
||||||
|
) -> Result<Vec<Self>> {
|
||||||
let result = if let Some(order_by) = list_params.get_order_by() {
|
let result = if let Some(order_by) = list_params.get_order_by() {
|
||||||
sqlx::query_as_unchecked!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"SELECT * FROM interior_ref_lists
|
"SELECT * FROM interior_ref_lists
|
||||||
ORDER BY $1
|
ORDER BY $1
|
||||||
@ -121,7 +130,7 @@ impl InteriorRefList {
|
|||||||
.fetch_all(db)
|
.fetch_all(db)
|
||||||
.await?
|
.await?
|
||||||
} else {
|
} else {
|
||||||
sqlx::query_as_unchecked!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"SELECT * FROM interior_ref_lists
|
"SELECT * FROM interior_ref_lists
|
||||||
LIMIT $1
|
LIMIT $1
|
||||||
@ -135,14 +144,19 @@ impl InteriorRefList {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, db))]
|
#[instrument(level = "debug", skip(interior_ref_list, db))]
|
||||||
pub async fn update(self, db: &PgPool, owner_id: i32, id: i32) -> Result<Self> {
|
pub async fn update(
|
||||||
let interior_ref_list =
|
interior_ref_list: PostedInteriorRefList,
|
||||||
|
db: impl Executor<'_, Database = Postgres> + Copy,
|
||||||
|
owner_id: i32,
|
||||||
|
id: i32,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let existing_interior_ref_list =
|
||||||
sqlx::query!("SELECT owner_id FROM interior_ref_lists WHERE id = $1", id)
|
sqlx::query!("SELECT owner_id FROM interior_ref_lists WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?;
|
.await?;
|
||||||
if interior_ref_list.owner_id == owner_id {
|
if existing_interior_ref_list.owner_id == owner_id {
|
||||||
Ok(sqlx::query_as_unchecked!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"UPDATE interior_ref_lists SET
|
"UPDATE interior_ref_lists SET
|
||||||
ref_list = $2,
|
ref_list = $2,
|
||||||
@ -150,7 +164,7 @@ impl InteriorRefList {
|
|||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING *",
|
RETURNING *",
|
||||||
id,
|
id,
|
||||||
self.ref_list,
|
serde_json::json!(interior_ref_list.ref_list),
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?)
|
.await?)
|
||||||
@ -160,8 +174,11 @@ impl InteriorRefList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn get_by_shop_id(db: &PgPool, shop_id: i32) -> Result<Self> {
|
pub async fn get_by_shop_id(
|
||||||
sqlx::query_as_unchecked!(
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
|
shop_id: i32,
|
||||||
|
) -> Result<Self> {
|
||||||
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"SELECT * FROM interior_ref_lists
|
"SELECT * FROM interior_ref_lists
|
||||||
WHERE shop_id = $1",
|
WHERE shop_id = $1",
|
||||||
@ -172,16 +189,21 @@ impl InteriorRefList {
|
|||||||
.map_err(Error::new)
|
.map_err(Error::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, db))]
|
#[instrument(level = "debug", skip(interior_ref_list, db))]
|
||||||
pub async fn update_by_shop_id(self, db: &PgPool, owner_id: i32, shop_id: i32) -> Result<Self> {
|
pub async fn update_by_shop_id(
|
||||||
let interior_ref_list = sqlx::query!(
|
interior_ref_list: PostedInteriorRefList,
|
||||||
|
db: impl Executor<'_, Database = Postgres> + Copy,
|
||||||
|
owner_id: i32,
|
||||||
|
shop_id: i32,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let existing_interior_ref_list = sqlx::query!(
|
||||||
"SELECT owner_id FROM interior_ref_lists WHERE shop_id = $1",
|
"SELECT owner_id FROM interior_ref_lists WHERE shop_id = $1",
|
||||||
shop_id
|
shop_id
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?;
|
.await?;
|
||||||
if interior_ref_list.owner_id == owner_id {
|
if existing_interior_ref_list.owner_id == owner_id {
|
||||||
Ok(sqlx::query_as_unchecked!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"UPDATE interior_ref_lists SET
|
"UPDATE interior_ref_lists SET
|
||||||
ref_list = $2,
|
ref_list = $2,
|
||||||
@ -189,7 +211,7 @@ impl InteriorRefList {
|
|||||||
WHERE shop_id = $1
|
WHERE shop_id = $1
|
||||||
RETURNING *",
|
RETURNING *",
|
||||||
shop_id,
|
shop_id,
|
||||||
self.ref_list,
|
serde_json::json!(interior_ref_list.ref_list),
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?)
|
.await?)
|
||||||
|
@ -4,20 +4,14 @@ use http::StatusCode;
|
|||||||
use http_api_problem::HttpApiProblem;
|
use http_api_problem::HttpApiProblem;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use sqlx::pool::PoolConnection;
|
|
||||||
use sqlx::types::Json;
|
use sqlx::types::Json;
|
||||||
use sqlx::{PgConnection, PgPool, Transaction};
|
use sqlx::{Done, Executor, Postgres};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use super::ListParams;
|
use super::ListParams;
|
||||||
use crate::problem::forbidden_permission;
|
use crate::problem::forbidden_permission;
|
||||||
|
|
||||||
// sqlx queries for this model need to be `query_as_unchecked!` because `query_as!` does not
|
|
||||||
// support user-defined types (`form_list` Json field).
|
|
||||||
// See for more info: https://github.com/thallada/rust_sqlx_bug/blob/master/src/main.rs
|
|
||||||
// This may be fixed in sqlx 0.4.
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Merchandise {
|
pub struct Merchandise {
|
||||||
pub mod_name: String,
|
pub mod_name: String,
|
||||||
@ -31,12 +25,26 @@ pub struct Merchandise {
|
|||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct MerchandiseList {
|
pub struct MerchandiseList {
|
||||||
pub id: Option<i32>,
|
pub id: i32,
|
||||||
|
pub shop_id: i32,
|
||||||
|
pub owner_id: i32,
|
||||||
|
pub form_list: serde_json::Value,
|
||||||
|
pub created_at: NaiveDateTime,
|
||||||
|
pub updated_at: NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct UnsavedMerchandiseList {
|
||||||
|
pub shop_id: i32,
|
||||||
|
pub owner_id: i32,
|
||||||
|
pub form_list: Json<Vec<Merchandise>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct PostedMerchandiseList {
|
||||||
pub shop_id: i32,
|
pub shop_id: i32,
|
||||||
pub owner_id: Option<i32>,
|
pub owner_id: Option<i32>,
|
||||||
pub form_list: Json<Vec<Merchandise>>,
|
pub form_list: Json<Vec<Merchandise>>,
|
||||||
pub created_at: Option<NaiveDateTime>,
|
|
||||||
pub updated_at: Option<NaiveDateTime>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MerchandiseList {
|
impl MerchandiseList {
|
||||||
@ -44,48 +52,48 @@ impl MerchandiseList {
|
|||||||
"merchandise_list"
|
"merchandise_list"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pk(&self) -> Option<i32> {
|
pub fn pk(&self) -> i32 {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn url(&self, api_url: &Url) -> Result<Url> {
|
pub fn url(&self, api_url: &Url) -> Result<Url> {
|
||||||
if let Some(pk) = self.pk() {
|
Ok(api_url.join(&format!("{}s/{}", Self::resource_name(), self.pk()))?)
|
||||||
Ok(api_url.join(&format!("{}s/{}", Self::resource_name(), pk))?)
|
|
||||||
} else {
|
|
||||||
Err(anyhow!(
|
|
||||||
"Cannot get URL for {} with no primary key",
|
|
||||||
Self::resource_name()
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: this model will probably never need to be accessed through it's ID, should these methods be removed/unimplemented?
|
// TODO: this model will probably never need to be accessed through it's ID, should these methods be removed/unimplemented?
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn get(db: &PgPool, id: i32) -> Result<Self> {
|
pub async fn get(db: impl Executor<'_, Database = Postgres>, id: i32) -> Result<Self> {
|
||||||
sqlx::query_as_unchecked!(Self, "SELECT * FROM merchandise_lists WHERE id = $1", id)
|
sqlx::query_as!(Self, "SELECT * FROM merchandise_lists WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await
|
.await
|
||||||
.map_err(Error::new)
|
.map_err(Error::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, db))]
|
#[instrument(level = "debug", skip(merchandise_list, db))]
|
||||||
pub async fn create(self, db: &PgPool) -> Result<Self> {
|
pub async fn create(
|
||||||
Ok(sqlx::query_as_unchecked!(
|
merchandise_list: UnsavedMerchandiseList,
|
||||||
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
|
) -> Result<Self> {
|
||||||
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"INSERT INTO merchandise_lists
|
"INSERT INTO merchandise_lists
|
||||||
(shop_id, owner_id, form_list, created_at, updated_at)
|
(shop_id, owner_id, form_list, created_at, updated_at)
|
||||||
VALUES ($1, $2, $3, now(), now())
|
VALUES ($1, $2, $3, now(), now())
|
||||||
RETURNING *",
|
RETURNING *",
|
||||||
self.shop_id,
|
merchandise_list.shop_id,
|
||||||
self.owner_id,
|
merchandise_list.owner_id,
|
||||||
self.form_list,
|
serde_json::json!(merchandise_list.form_list),
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn delete(db: &PgPool, owner_id: i32, id: i32) -> Result<u64> {
|
pub async fn delete(
|
||||||
|
db: impl Executor<'_, Database = Postgres> + Copy,
|
||||||
|
owner_id: i32,
|
||||||
|
id: i32,
|
||||||
|
) -> Result<u64> {
|
||||||
let merchandise_list =
|
let merchandise_list =
|
||||||
sqlx::query!("SELECT owner_id FROM merchandise_lists WHERE id = $1", id)
|
sqlx::query!("SELECT owner_id FROM merchandise_lists WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
@ -94,7 +102,8 @@ impl MerchandiseList {
|
|||||||
return Ok(
|
return Ok(
|
||||||
sqlx::query!("DELETE FROM merchandise_lists WHERE id = $1", id)
|
sqlx::query!("DELETE FROM merchandise_lists WHERE id = $1", id)
|
||||||
.execute(db)
|
.execute(db)
|
||||||
.await?,
|
.await?
|
||||||
|
.rows_affected(),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Err(forbidden_permission());
|
return Err(forbidden_permission());
|
||||||
@ -102,9 +111,12 @@ impl MerchandiseList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn list(db: &PgPool, list_params: &ListParams) -> Result<Vec<Self>> {
|
pub async fn list(
|
||||||
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
|
list_params: &ListParams,
|
||||||
|
) -> Result<Vec<Self>> {
|
||||||
let result = if let Some(order_by) = list_params.get_order_by() {
|
let result = if let Some(order_by) = list_params.get_order_by() {
|
||||||
sqlx::query_as_unchecked!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"SELECT * FROM merchandise_lists
|
"SELECT * FROM merchandise_lists
|
||||||
ORDER BY $1
|
ORDER BY $1
|
||||||
@ -117,7 +129,7 @@ impl MerchandiseList {
|
|||||||
.fetch_all(db)
|
.fetch_all(db)
|
||||||
.await?
|
.await?
|
||||||
} else {
|
} else {
|
||||||
sqlx::query_as_unchecked!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"SELECT * FROM merchandise_lists
|
"SELECT * FROM merchandise_lists
|
||||||
LIMIT $1
|
LIMIT $1
|
||||||
@ -131,14 +143,19 @@ impl MerchandiseList {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, db))]
|
#[instrument(level = "debug", skip(merchandise_list, db))]
|
||||||
pub async fn update(self, db: &PgPool, owner_id: i32, id: i32) -> Result<Self> {
|
pub async fn update(
|
||||||
let merchandise_list =
|
merchandise_list: PostedMerchandiseList,
|
||||||
|
db: impl Executor<'_, Database = Postgres> + Copy,
|
||||||
|
owner_id: i32,
|
||||||
|
id: i32,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let existing_merchandise_list =
|
||||||
sqlx::query!("SELECT owner_id FROM merchandise_lists WHERE id = $1", id)
|
sqlx::query!("SELECT owner_id FROM merchandise_lists WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?;
|
.await?;
|
||||||
if merchandise_list.owner_id == owner_id {
|
if existing_merchandise_list.owner_id == owner_id {
|
||||||
Ok(sqlx::query_as_unchecked!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"UPDATE merchandise_lists SET
|
"UPDATE merchandise_lists SET
|
||||||
form_list = $2,
|
form_list = $2,
|
||||||
@ -146,7 +163,7 @@ impl MerchandiseList {
|
|||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING *",
|
RETURNING *",
|
||||||
id,
|
id,
|
||||||
self.form_list,
|
serde_json::json!(merchandise_list.form_list),
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?)
|
.await?)
|
||||||
@ -156,8 +173,11 @@ impl MerchandiseList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn get_by_shop_id(db: &PgPool, shop_id: i32) -> Result<Self> {
|
pub async fn get_by_shop_id(
|
||||||
sqlx::query_as_unchecked!(
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
|
shop_id: i32,
|
||||||
|
) -> Result<Self> {
|
||||||
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"SELECT * FROM merchandise_lists
|
"SELECT * FROM merchandise_lists
|
||||||
WHERE shop_id = $1",
|
WHERE shop_id = $1",
|
||||||
@ -168,16 +188,21 @@ impl MerchandiseList {
|
|||||||
.map_err(Error::new)
|
.map_err(Error::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, db))]
|
#[instrument(level = "debug", skip(merchandise_list, db))]
|
||||||
pub async fn update_by_shop_id(self, db: &PgPool, owner_id: i32, shop_id: i32) -> Result<Self> {
|
pub async fn update_by_shop_id(
|
||||||
let merchandise_list = sqlx::query!(
|
merchandise_list: PostedMerchandiseList,
|
||||||
|
db: impl Executor<'_, Database = Postgres> + Copy,
|
||||||
|
owner_id: i32,
|
||||||
|
shop_id: i32,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let existing_merchandise_list = sqlx::query!(
|
||||||
"SELECT owner_id FROM merchandise_lists WHERE shop_id = $1",
|
"SELECT owner_id FROM merchandise_lists WHERE shop_id = $1",
|
||||||
shop_id
|
shop_id
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?;
|
.await?;
|
||||||
if merchandise_list.owner_id == owner_id {
|
if existing_merchandise_list.owner_id == owner_id {
|
||||||
Ok(sqlx::query_as_unchecked!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"UPDATE merchandise_lists SET
|
"UPDATE merchandise_lists SET
|
||||||
form_list = $2,
|
form_list = $2,
|
||||||
@ -185,7 +210,7 @@ impl MerchandiseList {
|
|||||||
WHERE shop_id = $1
|
WHERE shop_id = $1
|
||||||
RETURNING *",
|
RETURNING *",
|
||||||
shop_id,
|
shop_id,
|
||||||
self.form_list,
|
serde_json::json!(merchandise_list.form_list),
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?)
|
.await?)
|
||||||
@ -196,7 +221,7 @@ impl MerchandiseList {
|
|||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn update_merchandise_quantity(
|
pub async fn update_merchandise_quantity(
|
||||||
db: &mut Transaction<PoolConnection<PgConnection>>,
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
shop_id: i32,
|
shop_id: i32,
|
||||||
mod_name: &str,
|
mod_name: &str,
|
||||||
local_form_id: i32,
|
local_form_id: i32,
|
||||||
@ -215,7 +240,7 @@ impl MerchandiseList {
|
|||||||
"is_food": is_food,
|
"is_food": is_food,
|
||||||
"price": price,
|
"price": price,
|
||||||
}]);
|
}]);
|
||||||
Ok(sqlx::query_as_unchecked!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"UPDATE
|
"UPDATE
|
||||||
merchandise_lists
|
merchandise_lists
|
||||||
@ -255,7 +280,7 @@ impl MerchandiseList {
|
|||||||
RETURNING merchandise_lists.*",
|
RETURNING merchandise_lists.*",
|
||||||
shop_id,
|
shop_id,
|
||||||
mod_name,
|
mod_name,
|
||||||
local_form_id,
|
&local_form_id.to_string(),
|
||||||
quantity_delta,
|
quantity_delta,
|
||||||
add_item,
|
add_item,
|
||||||
)
|
)
|
||||||
@ -263,10 +288,10 @@ impl MerchandiseList {
|
|||||||
.await
|
.await
|
||||||
.map_err(|error| {
|
.map_err(|error| {
|
||||||
let anyhow_error = anyhow!(error);
|
let anyhow_error = anyhow!(error);
|
||||||
if let Some(sqlx::error::Error::Database(db_error)) =
|
if let Some(db_error) =
|
||||||
anyhow_error.downcast_ref::<sqlx::error::Error>()
|
anyhow_error.downcast_ref::<sqlx::postgres::PgDatabaseError>()
|
||||||
{
|
{
|
||||||
if db_error.code() == Some("23502") && db_error.column_name() == Some("form_list") {
|
if db_error.code() == "23502" && db_error.column() == Some("form_list") {
|
||||||
return anyhow!(HttpApiProblem::with_title_and_type_from_status(
|
return anyhow!(HttpApiProblem::with_title_and_type_from_status(
|
||||||
StatusCode::NOT_FOUND
|
StatusCode::NOT_FOUND
|
||||||
)
|
)
|
||||||
|
@ -9,12 +9,12 @@ pub mod owner;
|
|||||||
pub mod shop;
|
pub mod shop;
|
||||||
pub mod transaction;
|
pub mod transaction;
|
||||||
|
|
||||||
pub use interior_ref_list::InteriorRefList;
|
pub use interior_ref_list::{InteriorRefList, PostedInteriorRefList, UnsavedInteriorRefList};
|
||||||
pub use merchandise_list::MerchandiseList;
|
pub use merchandise_list::{MerchandiseList, PostedMerchandiseList, UnsavedMerchandiseList};
|
||||||
pub use model::{Model, UpdateableModel};
|
pub use model::{Model, UpdateableModel};
|
||||||
pub use owner::Owner;
|
pub use owner::{Owner, PostedOwner, UnsavedOwner};
|
||||||
pub use shop::Shop;
|
pub use shop::{PostedShop, Shop, UnsavedShop};
|
||||||
pub use transaction::Transaction;
|
pub use transaction::{PostedTransaction, Transaction, UnsavedTransaction};
|
||||||
|
|
||||||
#[derive(Debug, Eq, PartialEq, Hash, Clone, Deserialize)]
|
#[derive(Debug, Eq, PartialEq, Hash, Clone, Deserialize)]
|
||||||
pub enum Order {
|
pub enum Order {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use anyhow::{anyhow, Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use ipnetwork::IpNetwork;
|
use ipnetwork::IpNetwork;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::PgPool;
|
use sqlx::{Done, Executor, Postgres};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
@ -12,15 +12,31 @@ use crate::problem::forbidden_permission;
|
|||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Owner {
|
pub struct Owner {
|
||||||
pub id: Option<i32>,
|
pub id: i32,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
pub api_key: Option<Uuid>,
|
pub api_key: Uuid,
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip_serializing)]
|
||||||
pub ip_address: Option<IpNetwork>,
|
pub ip_address: Option<IpNetwork>,
|
||||||
pub mod_version: i32,
|
pub mod_version: i32,
|
||||||
pub created_at: Option<NaiveDateTime>,
|
pub created_at: NaiveDateTime,
|
||||||
pub updated_at: Option<NaiveDateTime>,
|
pub updated_at: NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct UnsavedOwner {
|
||||||
|
pub name: String,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub api_key: Uuid,
|
||||||
|
#[serde(skip_serializing)]
|
||||||
|
pub ip_address: Option<IpNetwork>,
|
||||||
|
pub mod_version: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct PostedOwner {
|
||||||
|
pub name: String,
|
||||||
|
pub mod_version: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Owner {
|
impl Owner {
|
||||||
@ -28,62 +44,66 @@ impl Owner {
|
|||||||
"owner"
|
"owner"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pk(&self) -> Option<i32> {
|
pub fn pk(&self) -> i32 {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn url(&self, api_url: &Url) -> Result<Url> {
|
pub fn url(&self, api_url: &Url) -> Result<Url> {
|
||||||
if let Some(pk) = self.pk() {
|
Ok(api_url.join(&format!("{}s/{}", Self::resource_name(), self.pk()))?)
|
||||||
Ok(api_url.join(&format!("{}s/{}", Self::resource_name(), pk))?)
|
|
||||||
} else {
|
|
||||||
Err(anyhow!(
|
|
||||||
"Cannot get URL for {} with no primary key",
|
|
||||||
Self::resource_name()
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn get(db: &PgPool, id: i32) -> Result<Self> {
|
pub async fn get(db: impl Executor<'_, Database = Postgres>, id: i32) -> Result<Self> {
|
||||||
sqlx::query_as!(Self, "SELECT * FROM owners WHERE id = $1", id)
|
sqlx::query_as!(Self, "SELECT * FROM owners WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await
|
.await
|
||||||
.map_err(Error::new)
|
.map_err(Error::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, db))]
|
#[instrument(level = "debug", skip(owner, db))]
|
||||||
pub async fn create(self, db: &PgPool) -> Result<Self> {
|
pub async fn create(
|
||||||
|
owner: UnsavedOwner,
|
||||||
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
|
) -> Result<Self> {
|
||||||
Ok(sqlx::query_as!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"INSERT INTO owners
|
"INSERT INTO owners
|
||||||
(name, api_key, ip_address, mod_version, created_at, updated_at)
|
(name, api_key, ip_address, mod_version, created_at, updated_at)
|
||||||
VALUES ($1, $2, $3, $4, now(), now())
|
VALUES ($1, $2, $3, $4, now(), now())
|
||||||
RETURNING *",
|
RETURNING *",
|
||||||
self.name,
|
owner.name,
|
||||||
self.api_key,
|
owner.api_key,
|
||||||
self.ip_address,
|
owner.ip_address,
|
||||||
self.mod_version,
|
owner.mod_version,
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn delete(db: &PgPool, owner_id: i32, id: i32) -> Result<u64> {
|
pub async fn delete(
|
||||||
|
db: impl Executor<'_, Database = Postgres> + Copy,
|
||||||
|
owner_id: i32,
|
||||||
|
id: i32,
|
||||||
|
) -> Result<u64> {
|
||||||
let owner = sqlx::query!("SELECT id FROM owners WHERE id = $1", id)
|
let owner = sqlx::query!("SELECT id FROM owners WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?;
|
.await?;
|
||||||
if owner.id == owner_id {
|
if owner.id == owner_id {
|
||||||
Ok(sqlx::query!("DELETE FROM owners WHERE id = $1", id)
|
Ok(sqlx::query!("DELETE FROM owners WHERE id = $1", id)
|
||||||
.execute(db)
|
.execute(db)
|
||||||
.await?)
|
.await?
|
||||||
|
.rows_affected())
|
||||||
} else {
|
} else {
|
||||||
return Err(forbidden_permission());
|
return Err(forbidden_permission());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn list(db: &PgPool, list_params: &ListParams) -> Result<Vec<Self>> {
|
pub async fn list(
|
||||||
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
|
list_params: &ListParams,
|
||||||
|
) -> Result<Vec<Self>> {
|
||||||
let result = if let Some(order_by) = list_params.get_order_by() {
|
let result = if let Some(order_by) = list_params.get_order_by() {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
@ -112,12 +132,17 @@ impl Owner {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, db))]
|
#[instrument(level = "debug", skip(owner, db))]
|
||||||
pub async fn update(self, db: &PgPool, owner_id: i32, id: i32) -> Result<Self> {
|
pub async fn update(
|
||||||
let owner = sqlx::query!("SELECT id FROM owners WHERE id = $1", id)
|
owner: PostedOwner,
|
||||||
|
db: impl Executor<'_, Database = Postgres> + Copy,
|
||||||
|
owner_id: i32,
|
||||||
|
id: i32,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let existing_owner = sqlx::query!("SELECT id FROM owners WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?;
|
.await?;
|
||||||
if owner.id == owner_id {
|
if existing_owner.id == owner_id {
|
||||||
Ok(sqlx::query_as!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"UPDATE owners SET
|
"UPDATE owners SET
|
||||||
@ -127,8 +152,8 @@ impl Owner {
|
|||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING *",
|
RETURNING *",
|
||||||
id,
|
id,
|
||||||
self.name,
|
owner.name,
|
||||||
self.mod_version,
|
owner.mod_version,
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?)
|
.await?)
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use anyhow::{anyhow, Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::PgPool;
|
use sqlx::{Done, Executor, Postgres};
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@ -10,17 +10,26 @@ use crate::problem::forbidden_permission;
|
|||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Shop {
|
pub struct Shop {
|
||||||
pub id: Option<i32>,
|
pub id: i32,
|
||||||
|
pub name: String,
|
||||||
|
pub owner_id: i32,
|
||||||
|
pub description: Option<String>,
|
||||||
|
pub created_at: NaiveDateTime,
|
||||||
|
pub updated_at: NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct UnsavedShop {
|
||||||
|
pub name: String,
|
||||||
|
pub owner_id: i32,
|
||||||
|
pub description: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct PostedShop {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub owner_id: Option<i32>,
|
pub owner_id: Option<i32>,
|
||||||
pub description: String,
|
pub description: Option<String>,
|
||||||
// removing these until I figure out the plan for buying and selling
|
|
||||||
// pub is_not_sell_buy: bool,
|
|
||||||
// pub sell_buy_list_id: i32,
|
|
||||||
// pub vendor_id: i32,
|
|
||||||
// pub vendor_gold: i32,
|
|
||||||
pub created_at: Option<NaiveDateTime>,
|
|
||||||
pub updated_at: Option<NaiveDateTime>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shop {
|
impl Shop {
|
||||||
@ -28,61 +37,65 @@ impl Shop {
|
|||||||
"shop"
|
"shop"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pk(&self) -> Option<i32> {
|
pub fn pk(&self) -> i32 {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn url(&self, api_url: &Url) -> Result<Url> {
|
pub fn url(&self, api_url: &Url) -> Result<Url> {
|
||||||
if let Some(pk) = self.pk() {
|
Ok(api_url.join(&format!("{}s/{}", Self::resource_name(), self.pk()))?)
|
||||||
Ok(api_url.join(&format!("{}s/{}", Self::resource_name(), pk))?)
|
|
||||||
} else {
|
|
||||||
Err(anyhow!(
|
|
||||||
"Cannot get URL for {} with no primary key",
|
|
||||||
Self::resource_name()
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn get(db: &PgPool, id: i32) -> Result<Self> {
|
pub async fn get(db: impl Executor<'_, Database = Postgres>, id: i32) -> Result<Self> {
|
||||||
sqlx::query_as!(Self, "SELECT * FROM shops WHERE id = $1", id)
|
sqlx::query_as!(Self, "SELECT * FROM shops WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await
|
.await
|
||||||
.map_err(Error::new)
|
.map_err(Error::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, db))]
|
#[instrument(level = "debug", skip(shop, db))]
|
||||||
pub async fn create(self, db: &PgPool) -> Result<Self> {
|
pub async fn create(
|
||||||
|
shop: UnsavedShop,
|
||||||
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
|
) -> Result<Self> {
|
||||||
Ok(sqlx::query_as!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"INSERT INTO shops
|
"INSERT INTO shops
|
||||||
(name, owner_id, description, created_at, updated_at)
|
(name, owner_id, description, created_at, updated_at)
|
||||||
VALUES ($1, $2, $3, now(), now())
|
VALUES ($1, $2, $3, now(), now())
|
||||||
RETURNING *",
|
RETURNING *",
|
||||||
self.name,
|
shop.name,
|
||||||
self.owner_id,
|
shop.owner_id,
|
||||||
self.description,
|
shop.description,
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn delete(db: &PgPool, owner_id: i32, id: i32) -> Result<u64> {
|
pub async fn delete(
|
||||||
|
db: impl Executor<'_, Database = Postgres> + Copy,
|
||||||
|
owner_id: i32,
|
||||||
|
id: i32,
|
||||||
|
) -> Result<u64> {
|
||||||
let shop = sqlx::query!("SELECT owner_id FROM shops WHERE id = $1", id)
|
let shop = sqlx::query!("SELECT owner_id FROM shops WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?;
|
.await?;
|
||||||
if shop.owner_id == owner_id {
|
if shop.owner_id == owner_id {
|
||||||
return Ok(sqlx::query!("DELETE FROM shops WHERE shops.id = $1", id)
|
return Ok(sqlx::query!("DELETE FROM shops WHERE shops.id = $1", id)
|
||||||
.execute(db)
|
.execute(db)
|
||||||
.await?);
|
.await?
|
||||||
|
.rows_affected());
|
||||||
} else {
|
} else {
|
||||||
return Err(forbidden_permission());
|
return Err(forbidden_permission());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn list(db: &PgPool, list_params: &ListParams) -> Result<Vec<Self>> {
|
pub async fn list(
|
||||||
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
|
list_params: &ListParams,
|
||||||
|
) -> Result<Vec<Self>> {
|
||||||
let result = if let Some(order_by) = list_params.get_order_by() {
|
let result = if let Some(order_by) = list_params.get_order_by() {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
@ -111,12 +124,17 @@ impl Shop {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(self, db))]
|
#[instrument(level = "debug", skip(shop, db))]
|
||||||
pub async fn update(self, db: &PgPool, owner_id: i32, id: i32) -> Result<Self> {
|
pub async fn update(
|
||||||
let shop = sqlx::query!("SELECT owner_id FROM shops WHERE id = $1", id)
|
shop: PostedShop,
|
||||||
|
db: impl Executor<'_, Database = Postgres> + Copy,
|
||||||
|
owner_id: i32,
|
||||||
|
id: i32,
|
||||||
|
) -> Result<Self> {
|
||||||
|
let existing_shop = sqlx::query!("SELECT owner_id FROM shops WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?;
|
.await?;
|
||||||
if shop.owner_id == owner_id {
|
if existing_shop.owner_id == owner_id {
|
||||||
Ok(sqlx::query_as!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
"UPDATE shops SET
|
"UPDATE shops SET
|
||||||
@ -127,9 +145,9 @@ impl Shop {
|
|||||||
WHERE id = $1
|
WHERE id = $1
|
||||||
RETURNING *",
|
RETURNING *",
|
||||||
id,
|
id,
|
||||||
self.name,
|
shop.name,
|
||||||
self.owner_id,
|
shop.owner_id,
|
||||||
self.description,
|
shop.description,
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?)
|
.await?)
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
use anyhow::{anyhow, Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use sqlx::pool::PoolConnection;
|
use sqlx::{Done, Executor, Postgres};
|
||||||
use sqlx::{PgConnection, PgPool};
|
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@ -11,7 +10,39 @@ use crate::problem::forbidden_permission;
|
|||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Transaction {
|
pub struct Transaction {
|
||||||
pub id: Option<i32>,
|
pub id: i32,
|
||||||
|
pub shop_id: i32,
|
||||||
|
pub owner_id: i32,
|
||||||
|
pub mod_name: String,
|
||||||
|
pub local_form_id: i32,
|
||||||
|
pub name: String,
|
||||||
|
pub form_type: i32,
|
||||||
|
pub is_food: bool,
|
||||||
|
pub price: i32,
|
||||||
|
pub is_sell: bool,
|
||||||
|
pub quantity: i32,
|
||||||
|
pub amount: i32,
|
||||||
|
pub created_at: NaiveDateTime,
|
||||||
|
pub updated_at: NaiveDateTime,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct UnsavedTransaction {
|
||||||
|
pub shop_id: i32,
|
||||||
|
pub owner_id: i32,
|
||||||
|
pub mod_name: String,
|
||||||
|
pub local_form_id: i32,
|
||||||
|
pub name: String,
|
||||||
|
pub form_type: i32,
|
||||||
|
pub is_food: bool,
|
||||||
|
pub price: i32,
|
||||||
|
pub is_sell: bool,
|
||||||
|
pub quantity: i32,
|
||||||
|
pub amount: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct PostedTransaction {
|
||||||
pub shop_id: i32,
|
pub shop_id: i32,
|
||||||
pub owner_id: Option<i32>,
|
pub owner_id: Option<i32>,
|
||||||
pub mod_name: String,
|
pub mod_name: String,
|
||||||
@ -23,8 +54,6 @@ pub struct Transaction {
|
|||||||
pub is_sell: bool,
|
pub is_sell: bool,
|
||||||
pub quantity: i32,
|
pub quantity: i32,
|
||||||
pub amount: i32,
|
pub amount: i32,
|
||||||
pub created_at: Option<NaiveDateTime>,
|
|
||||||
pub updated_at: Option<NaiveDateTime>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Transaction {
|
impl Transaction {
|
||||||
@ -32,23 +61,16 @@ impl Transaction {
|
|||||||
"transaction"
|
"transaction"
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pk(&self) -> Option<i32> {
|
pub fn pk(&self) -> i32 {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn url(&self, api_url: &Url) -> Result<Url> {
|
pub fn url(&self, api_url: &Url) -> Result<Url> {
|
||||||
if let Some(pk) = self.pk() {
|
Ok(api_url.join(&format!("{}s/{}", Self::resource_name(), self.pk()))?)
|
||||||
Ok(api_url.join(&format!("{}s/{}", Self::resource_name(), pk))?)
|
|
||||||
} else {
|
|
||||||
Err(anyhow!(
|
|
||||||
"Cannot get URL for {} with no primary key",
|
|
||||||
Self::resource_name()
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn get(db: &PgPool, id: i32) -> Result<Self> {
|
pub async fn get(db: impl Executor<'_, Database = Postgres>, id: i32) -> Result<Self> {
|
||||||
sqlx::query_as!(Self, "SELECT * FROM transactions WHERE id = $1", id)
|
sqlx::query_as!(Self, "SELECT * FROM transactions WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await
|
.await
|
||||||
@ -57,8 +79,8 @@ impl Transaction {
|
|||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn create(
|
pub async fn create(
|
||||||
self,
|
transaction: UnsavedTransaction,
|
||||||
db: &mut sqlx::Transaction<PoolConnection<PgConnection>>,
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
Ok(sqlx::query_as!(
|
Ok(sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
@ -67,38 +89,46 @@ impl Transaction {
|
|||||||
is_sell, quantity, amount, created_at, updated_at)
|
is_sell, quantity, amount, created_at, updated_at)
|
||||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, now(), now())
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, now(), now())
|
||||||
RETURNING *",
|
RETURNING *",
|
||||||
self.shop_id,
|
transaction.shop_id,
|
||||||
self.owner_id,
|
transaction.owner_id,
|
||||||
self.mod_name,
|
transaction.mod_name,
|
||||||
self.local_form_id,
|
transaction.local_form_id,
|
||||||
self.name,
|
transaction.name,
|
||||||
self.form_type,
|
transaction.form_type,
|
||||||
self.is_food,
|
transaction.is_food,
|
||||||
self.price,
|
transaction.price,
|
||||||
self.is_sell,
|
transaction.is_sell,
|
||||||
self.quantity,
|
transaction.quantity,
|
||||||
self.amount,
|
transaction.amount,
|
||||||
)
|
)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn delete(db: &PgPool, owner_id: i32, id: i32) -> Result<u64> {
|
pub async fn delete(
|
||||||
|
db: impl Executor<'_, Database = Postgres> + Copy,
|
||||||
|
owner_id: i32,
|
||||||
|
id: i32,
|
||||||
|
) -> Result<u64> {
|
||||||
let transaction = sqlx::query!("SELECT owner_id FROM transactions WHERE id = $1", id)
|
let transaction = sqlx::query!("SELECT owner_id FROM transactions WHERE id = $1", id)
|
||||||
.fetch_one(db)
|
.fetch_one(db)
|
||||||
.await?;
|
.await?;
|
||||||
if transaction.owner_id == owner_id {
|
if transaction.owner_id == owner_id {
|
||||||
return Ok(sqlx::query!("DELETE FROM transactions WHERE id = $1", id)
|
return Ok(sqlx::query!("DELETE FROM transactions WHERE id = $1", id)
|
||||||
.execute(db)
|
.execute(db)
|
||||||
.await?);
|
.await?
|
||||||
|
.rows_affected());
|
||||||
} else {
|
} else {
|
||||||
return Err(forbidden_permission());
|
return Err(forbidden_permission());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn list(db: &PgPool, list_params: &ListParams) -> Result<Vec<Self>> {
|
pub async fn list(
|
||||||
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
|
list_params: &ListParams,
|
||||||
|
) -> Result<Vec<Self>> {
|
||||||
let result = if let Some(order_by) = list_params.get_order_by() {
|
let result = if let Some(order_by) = list_params.get_order_by() {
|
||||||
sqlx::query_as!(
|
sqlx::query_as!(
|
||||||
Self,
|
Self,
|
||||||
@ -129,7 +159,7 @@ impl Transaction {
|
|||||||
|
|
||||||
#[instrument(level = "debug", skip(db))]
|
#[instrument(level = "debug", skip(db))]
|
||||||
pub async fn list_by_shop_id(
|
pub async fn list_by_shop_id(
|
||||||
db: &PgPool,
|
db: impl Executor<'_, Database = Postgres>,
|
||||||
shop_id: i32,
|
shop_id: i32,
|
||||||
list_params: &ListParams,
|
list_params: &ListParams,
|
||||||
) -> Result<Vec<Self>> {
|
) -> Result<Vec<Self>> {
|
||||||
|
@ -36,56 +36,44 @@ pub fn from_anyhow(error: anyhow::Error) -> HttpApiProblem {
|
|||||||
sqlx::error::Error::RowNotFound => {
|
sqlx::error::Error::RowNotFound => {
|
||||||
return HttpApiProblem::with_title_and_type_from_status(StatusCode::NOT_FOUND)
|
return HttpApiProblem::with_title_and_type_from_status(StatusCode::NOT_FOUND)
|
||||||
}
|
}
|
||||||
sqlx::error::Error::Database(db_error) => {
|
|
||||||
error!(
|
|
||||||
"Database error: {}. {}",
|
|
||||||
db_error.message(),
|
|
||||||
db_error.details().unwrap_or("")
|
|
||||||
);
|
|
||||||
dbg!(&db_error);
|
|
||||||
if let Some(code) = db_error.code() {
|
|
||||||
dbg!(&code);
|
|
||||||
if let Some(constraint) = db_error.constraint_name() {
|
|
||||||
dbg!(&constraint);
|
|
||||||
if code == "23503" && constraint == "shops_owner_id_fkey" {
|
|
||||||
// foreign_key_violation
|
|
||||||
return HttpApiProblem::with_title_and_type_from_status(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
)
|
|
||||||
.set_detail("Owner does not exist");
|
|
||||||
} else if code == "23505" && constraint == "owners_api_key_key" {
|
|
||||||
// unique_violation
|
|
||||||
return HttpApiProblem::with_title_and_type_from_status(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
)
|
|
||||||
.set_detail("Owner with Api-Key already exists");
|
|
||||||
} else if code == "23505" && constraint == "owners_unique_name_and_api_key"
|
|
||||||
{
|
|
||||||
// unique_violation
|
|
||||||
return HttpApiProblem::with_title_and_type_from_status(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
)
|
|
||||||
.set_detail("Duplicate owner with same name and Api-Key exists");
|
|
||||||
} else if code == "23505" && constraint == "shops_unique_name_and_owner_id"
|
|
||||||
{
|
|
||||||
// unique_violation
|
|
||||||
return HttpApiProblem::with_title_and_type_from_status(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
)
|
|
||||||
.set_detail("Owner already has a shop with that name");
|
|
||||||
} else if code == "23514" && constraint == "merchandise_quantity_gt_zero" {
|
|
||||||
return HttpApiProblem::with_title_and_type_from_status(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
)
|
|
||||||
.set_detail("Quantity of merchandise must be greater than zero");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(pg_error) = error.downcast_ref::<sqlx::postgres::PgDatabaseError>() {
|
||||||
|
error!(
|
||||||
|
"Database error: {}. {}",
|
||||||
|
pg_error.message(),
|
||||||
|
pg_error.detail().unwrap_or("")
|
||||||
|
);
|
||||||
|
dbg!(&pg_error);
|
||||||
|
let code = pg_error.code();
|
||||||
|
dbg!(&code);
|
||||||
|
if let Some(constraint) = pg_error.constraint() {
|
||||||
|
dbg!(&constraint);
|
||||||
|
if code == "23503" && constraint == "shops_owner_id_fkey" {
|
||||||
|
// foreign_key_violation
|
||||||
|
return HttpApiProblem::with_title_and_type_from_status(StatusCode::BAD_REQUEST)
|
||||||
|
.set_detail("Owner does not exist");
|
||||||
|
} else if code == "23505" && constraint == "owners_api_key_key" {
|
||||||
|
// unique_violation
|
||||||
|
return HttpApiProblem::with_title_and_type_from_status(StatusCode::BAD_REQUEST)
|
||||||
|
.set_detail("Owner with Api-Key already exists");
|
||||||
|
} else if code == "23505" && constraint == "owners_unique_name_and_api_key" {
|
||||||
|
// unique_violation
|
||||||
|
return HttpApiProblem::with_title_and_type_from_status(StatusCode::BAD_REQUEST)
|
||||||
|
.set_detail("Duplicate owner with same name and Api-Key exists");
|
||||||
|
} else if code == "23505" && constraint == "shops_unique_name_and_owner_id" {
|
||||||
|
// unique_violation
|
||||||
|
return HttpApiProblem::with_title_and_type_from_status(StatusCode::BAD_REQUEST)
|
||||||
|
.set_detail("Owner already has a shop with that name");
|
||||||
|
} else if code == "23514" && constraint == "merchandise_quantity_gt_zero" {
|
||||||
|
return HttpApiProblem::with_title_and_type_from_status(StatusCode::BAD_REQUEST)
|
||||||
|
.set_detail("Quantity of merchandise must be greater than zero");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
error!("Recovering unhandled error: {:?}", error);
|
error!("Recovering unhandled error: {:?}", error);
|
||||||
// TODO: this leaks internal info, should not stringify error
|
// TODO: this leaks internal info, should not stringify error
|
||||||
HttpApiProblem::new(format!("Internal Server Error: {:?}", error))
|
HttpApiProblem::new(format!("Internal Server Error: {:?}", error))
|
||||||
|
Loading…
Reference in New Issue
Block a user