Compare commits
10 commits
37cca40192
...
58150002e6
Author | SHA1 | Date | |
---|---|---|---|
58150002e6 | |||
b0bae64efc | |||
949340a7f2 | |||
f24e3f1e3c | |||
1e9efe4c12 | |||
d830e677ba | |||
9784c3cac6 | |||
9b56a434e7 | |||
05e09295a5 | |||
228f113dbf |
12 changed files with 657 additions and 218 deletions
187
Cargo.lock
generated
187
Cargo.lock
generated
|
@ -4,18 +4,18 @@ version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
version = "0.22.0"
|
version = "0.24.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
|
checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gimli",
|
"gimli",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler"
|
name = "adler2"
|
||||||
version = "1.0.2"
|
version = "2.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ahash"
|
name = "ahash"
|
||||||
|
@ -56,13 +56,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.81"
|
version = "0.1.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107"
|
checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.77",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -73,17 +73,17 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "backtrace"
|
name = "backtrace"
|
||||||
version = "0.3.73"
|
version = "0.3.74"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a"
|
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"addr2line",
|
"addr2line",
|
||||||
"cc",
|
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"miniz_oxide",
|
"miniz_oxide",
|
||||||
"object",
|
"object",
|
||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -159,10 +159,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "byteorder"
|
||||||
version = "1.6.1"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952"
|
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytes"
|
||||||
|
version = "1.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "case"
|
name = "case"
|
||||||
|
@ -172,9 +178,12 @@ checksum = "fd6c0e7b807d60291f42f33f58480c0bfafe28ed08286446f45e463728cf9c1c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.1.6"
|
version = "1.1.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f"
|
checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476"
|
||||||
|
dependencies = [
|
||||||
|
"shlex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
|
@ -204,15 +213,15 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.12"
|
version = "0.2.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
|
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
@ -297,8 +306,8 @@ dependencies = [
|
||||||
"convert_case",
|
"convert_case",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustc_version 0.4.0",
|
"rustc_version 0.4.1",
|
||||||
"syn 2.0.72",
|
"syn 2.0.77",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -407,7 +416,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.77",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -463,9 +472,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.29.0"
|
version = "0.31.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
|
@ -563,9 +572,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.2.6"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
|
@ -585,9 +594,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.9.0"
|
version = "2.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
|
checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
|
@ -597,9 +606,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.69"
|
version = "0.3.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
|
checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
@ -612,9 +621,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.155"
|
version = "0.2.158"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linked-hash-map"
|
name = "linked-hash-map"
|
||||||
|
@ -677,18 +686,18 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.7.4"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08"
|
checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler",
|
"adler2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "1.0.1"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4"
|
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -698,7 +707,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mongod"
|
name = "mongod"
|
||||||
version = "0.2.0"
|
version = "0.2.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"futures",
|
"futures",
|
||||||
|
@ -785,9 +794,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.36.2"
|
version = "0.36.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e"
|
checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
@ -856,9 +865,12 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.17"
|
version = "0.2.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
|
@ -877,9 +889,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.36"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
@ -931,9 +943,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.10.5"
|
version = "1.10.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
|
checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -1000,9 +1012,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc_version"
|
name = "rustc_version"
|
||||||
version = "0.4.0"
|
version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
|
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"semver 1.0.23",
|
"semver 1.0.23",
|
||||||
]
|
]
|
||||||
|
@ -1093,9 +1105,9 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.204"
|
version = "1.0.210"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12"
|
checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
@ -1111,23 +1123,24 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.204"
|
version = "1.0.210"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222"
|
checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.77",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.120"
|
version = "1.0.128"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
|
checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"itoa",
|
"itoa",
|
||||||
|
"memchr",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
@ -1176,6 +1189,12 @@ dependencies = [
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "shlex"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.2"
|
version = "1.4.2"
|
||||||
|
@ -1262,9 +1281,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.72"
|
version = "2.0.77"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af"
|
checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1300,7 +1319,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.77",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1351,9 +1370,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.39.1"
|
version = "1.40.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d040ac2b29ab03b09d4129c2f5bbd012a3ac2f79d38ff506a4bf8dd34b0eac8a"
|
checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
@ -1374,7 +1393,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.77",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1389,9 +1408,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.11"
|
version = "0.7.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1"
|
checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
|
@ -1471,9 +1490,9 @@ checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.12"
|
version = "1.0.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-normalization"
|
name = "unicode-normalization"
|
||||||
|
@ -1486,9 +1505,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-properties"
|
name = "unicode-properties"
|
||||||
version = "0.1.1"
|
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 = "e4259d9d4425d9f0661581b804cb85fe66a4c631cadd8f490d1c13a35d5d9291"
|
checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
|
@ -1519,9 +1538,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasi"
|
name = "wasi"
|
||||||
|
@ -1531,34 +1550,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.92"
|
version = "0.2.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
|
checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
"wasm-bindgen-macro",
|
"wasm-bindgen-macro",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.92"
|
version = "0.2.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
|
checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.77",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.92"
|
version = "0.2.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
|
checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
|
@ -1566,22 +1586,22 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.92"
|
version = "0.2.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.77",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.92"
|
version = "0.2.93"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
|
checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webpki-roots"
|
name = "webpki-roots"
|
||||||
|
@ -1790,6 +1810,7 @@ version = "0.7.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1801,5 +1822,5 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.72",
|
"syn 2.0.77",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "mongod"
|
name = "mongod"
|
||||||
version = "0.2.0"
|
version = "0.2.2"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
35
README.md
35
README.md
|
@ -11,9 +11,9 @@ You can derive the `Model` and `Referencable` traits for your struct. This will
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use mongod::Validate;
|
use mongod::Validate;
|
||||||
use mongod::Reference;
|
use mongod::Reference;
|
||||||
use mongod::derive::{Module, Referencable};
|
use mongod::derive::{Model, Referencable};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, Module, Referencable)]
|
#[derive(Debug, Clone, Serialize, Deserialize, Model, Referencable)]
|
||||||
struct MyStruct {
|
struct MyStruct {
|
||||||
_id: String,
|
_id: String,
|
||||||
name: String,
|
name: String,
|
||||||
|
@ -105,3 +105,34 @@ let ms = MyStruct::get_partial("someid", &serde_json::json!({"other": 1})).await
|
||||||
let myref = ms.other.unwrap(); // will be there
|
let myref = ms.other.unwrap(); // will be there
|
||||||
let name = ms.name.unwrap() // will panic!
|
let name = ms.name.unwrap() // will panic!
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Updating values
|
||||||
|
You can either update the values by passing a JSON object overwriting the current values or update the values using a builder pattern.
|
||||||
|
|
||||||
|
```rust
|
||||||
|
[...]
|
||||||
|
struct MyStruct {
|
||||||
|
_id: String,
|
||||||
|
name: String,
|
||||||
|
age: u32,
|
||||||
|
other: Option<Reference>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut a = MyStruct::get("someid").await.unwrap();
|
||||||
|
|
||||||
|
// JSON
|
||||||
|
a.update(serde_json::json!({"name": "bye"})).await.unwrap();
|
||||||
|
|
||||||
|
// Builder
|
||||||
|
let mut changes = a.change();
|
||||||
|
|
||||||
|
// Set fields
|
||||||
|
changes = changes.name("bye");
|
||||||
|
|
||||||
|
// There are type specific functions
|
||||||
|
// Increment age by 1
|
||||||
|
changes = changes.age_increment(1);
|
||||||
|
|
||||||
|
// Finalize
|
||||||
|
let changed_model: MyStruct = changes.update().await.unwrap();
|
||||||
|
```
|
||||||
|
|
213
mongod_derive/src/change_fields.rs
Normal file
213
mongod_derive/src/change_fields.rs
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
use quote::quote;
|
||||||
|
use syn::Field;
|
||||||
|
|
||||||
|
use crate::{extract_inner_type, is_one_of_type, is_type};
|
||||||
|
|
||||||
|
/// Generate the ChangeBuilder field fns
|
||||||
|
pub fn builder_change_fields(field: &Field) -> proc_macro2::TokenStream {
|
||||||
|
let field_name = &field.ident.as_ref().unwrap();
|
||||||
|
let field_type = &field.ty;
|
||||||
|
let field_name_str = field_name.to_string();
|
||||||
|
|
||||||
|
// Never update _id
|
||||||
|
if field_name_str == "_id" {
|
||||||
|
return quote! {};
|
||||||
|
}
|
||||||
|
|
||||||
|
let number_types = [
|
||||||
|
"u8", "u16", "u32", "u64", "u128", "usize", "i8", "i16", "i32", "i64", "i128", "isize",
|
||||||
|
"f16", "f32", "f64", "f128",
|
||||||
|
];
|
||||||
|
|
||||||
|
// Number type fn
|
||||||
|
if is_one_of_type(field_type, &number_types) {
|
||||||
|
let documentation = format!("Set the value of `{field_name}`");
|
||||||
|
let inc_fn_name = syn::Ident::new(&format!("{}_increment", field_name), field_name.span());
|
||||||
|
let doc_inc = format!("Increment value of `{field_name}` by `value`. Consecutive calls to this function will not add up, they overwrite the increment.");
|
||||||
|
|
||||||
|
let mul_fn_name = syn::Ident::new(&format!("{}_multiply", field_name), field_name.span());
|
||||||
|
let doc_mul = format!("Multiply value of `{field_name}` by `value`. Consecutive calls to this function will not add up, they overwrite the multiply.");
|
||||||
|
|
||||||
|
return quote! {
|
||||||
|
#[doc = #documentation]
|
||||||
|
pub fn #field_name(mut self, value: #field_type)-> Self {
|
||||||
|
self.model.#field_name = value.into();
|
||||||
|
|
||||||
|
self.changeset.entry("$set".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert(
|
||||||
|
#field_name_str.to_string(),
|
||||||
|
mongod::mongodb::bson::to_bson(&self.model.#field_name).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc = #doc_inc]
|
||||||
|
pub fn #inc_fn_name(mut self, value: #field_type) -> Self {
|
||||||
|
self.model.#field_name += value;
|
||||||
|
|
||||||
|
self.changeset.entry("$inc".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap()
|
||||||
|
.insert(
|
||||||
|
#field_name_str.to_string(),
|
||||||
|
mongod::mongodb::bson::to_bson(&value).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc = #doc_mul]
|
||||||
|
pub fn #mul_fn_name(mut self, value: #field_type) -> Self {
|
||||||
|
self.model.#field_name *= value;
|
||||||
|
|
||||||
|
self.changeset.entry("$mul".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap()
|
||||||
|
.insert(
|
||||||
|
#field_name_str.to_string(),
|
||||||
|
mongod::mongodb::bson::to_bson(&value).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_type(field_type, "Vec") {
|
||||||
|
let inner_field_type = extract_inner_type(field_type, "Vec").unwrap();
|
||||||
|
|
||||||
|
let push_fn_name = syn::Ident::new(&format!("{}_push", field_name), field_name.span());
|
||||||
|
|
||||||
|
let documentation = format!("Add a value to the Vec `{field_name}`");
|
||||||
|
let documentation2 = format!("Set the value of `{field_name}`");
|
||||||
|
|
||||||
|
return quote! {
|
||||||
|
#[doc = #documentation]
|
||||||
|
pub fn #push_fn_name<T>(mut self, value: T) -> Self where T: Into<#inner_field_type> + serde::Serialize {
|
||||||
|
let mut push = self.changeset.entry("$push".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap();
|
||||||
|
|
||||||
|
if push.contains_key(#field_name_str) {
|
||||||
|
let current = push.get_mut(#field_name_str.to_string()).unwrap();
|
||||||
|
|
||||||
|
if current.as_document().map(|x| !x.contains_key("$each")).unwrap_or(true) {
|
||||||
|
let each = mongod::mongodb::bson::doc! {
|
||||||
|
"$each": [current, mongod::mongodb::bson::to_bson(&value).unwrap()]
|
||||||
|
};
|
||||||
|
|
||||||
|
push.insert(#field_name_str.to_string(), each);
|
||||||
|
} else {
|
||||||
|
current.as_document_mut().unwrap().get_mut("$each").unwrap().as_array_mut().unwrap().push(mongod::mongodb::bson::to_bson(&value).unwrap());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
push.insert(#field_name_str.to_string(), mongod::mongodb::bson::to_bson(&value).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.model.#field_name.push(value.into());
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc = #documentation2]
|
||||||
|
pub fn #field_name<T>(mut self, value: T)-> Self where T: Into<#field_type> + serde::Serialize {
|
||||||
|
self.model.#field_name = value.into();
|
||||||
|
|
||||||
|
self.changeset.entry("$set".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert(
|
||||||
|
#field_name_str.to_string(),
|
||||||
|
mongod::mongodb::bson::to_bson(&self.model.#field_name).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_type(field_type, "Historic") {
|
||||||
|
let inner_field_type = extract_inner_type(field_type, "Historic").unwrap();
|
||||||
|
|
||||||
|
let documentation = format!(
|
||||||
|
"Update the value of `{field_name}`. This change will be recorded by the `Historic`"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Code for Historic<T>
|
||||||
|
return quote! {
|
||||||
|
#[doc = #documentation]
|
||||||
|
pub fn #field_name<T>(mut self, value: T) -> Self where T: Into<#inner_field_type> + serde::Serialize {
|
||||||
|
self.model.#field_name.update(value.into());
|
||||||
|
|
||||||
|
self.changeset.entry("$set".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert(
|
||||||
|
#field_name_str.to_string(),
|
||||||
|
mongod::mongodb::bson::to_bson(&self.model.#field_name).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_type(field_type, "Option") {
|
||||||
|
let inner_field_type = extract_inner_type(field_type, "Option").unwrap();
|
||||||
|
|
||||||
|
if is_type(inner_field_type, "Historic") {
|
||||||
|
let inner_field_type = extract_inner_type(inner_field_type, "Historic").unwrap();
|
||||||
|
|
||||||
|
let documentation = format!("Update the value of `{field_name}`. This change will be recorded by the `Historic`. If `{field_name}` is `None` a new `Historic` will be initialized.");
|
||||||
|
|
||||||
|
// Code for Option<Historic<T>>
|
||||||
|
return quote! {
|
||||||
|
#[doc = #documentation]
|
||||||
|
pub fn #field_name<T>(mut self, value: T) -> Self where T: Into<#inner_field_type> + serde::Serialize {
|
||||||
|
if let Some(mut opt) = self.model.#field_name.as_mut() {
|
||||||
|
opt.update(value.into());
|
||||||
|
} else {
|
||||||
|
self.model.#field_name = Some(mongod::Historic::new(value.into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.changeset.entry("$set".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert(
|
||||||
|
#field_name_str.to_string(),
|
||||||
|
mongod::mongodb::bson::to_bson(&self.model.#field_name).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let documentation = format!("Set the value of `{field_name}`. If `Some(_)` it will be updated or removed if it is `None`");
|
||||||
|
|
||||||
|
return quote! {
|
||||||
|
#[doc = #documentation]
|
||||||
|
pub fn #field_name(mut self, value: Option<#inner_field_type>) -> Self {
|
||||||
|
let is_some = value.is_some();
|
||||||
|
|
||||||
|
self.model.#field_name = value.into();
|
||||||
|
|
||||||
|
if is_some {
|
||||||
|
self.changeset.entry("$set".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert(
|
||||||
|
#field_name_str.to_string(),
|
||||||
|
mongod::mongodb::bson::to_bson(&self.model.#field_name).unwrap(),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
self.changeset.entry("$unset".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert(
|
||||||
|
#field_name_str.to_string(),
|
||||||
|
mongod::mongodb::bson::to_bson("").unwrap(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
let documentation = format!("Set the value of `{field_name}`");
|
||||||
|
// Code for T
|
||||||
|
quote! {
|
||||||
|
#[doc = #documentation]
|
||||||
|
pub fn #field_name<T>(mut self, value: T)-> Self where T: Into<#field_type> + serde::Serialize {
|
||||||
|
self.model.#field_name = value.into();
|
||||||
|
|
||||||
|
self.changeset.entry("$set".to_string()).or_insert(mongod::mongodb::bson::doc! {}.into()).as_document_mut().unwrap().insert(
|
||||||
|
#field_name_str.to_string(),
|
||||||
|
mongod::mongodb::bson::to_bson(&self.model.#field_name).unwrap(),
|
||||||
|
);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,40 +3,18 @@ use case::CaseExt;
|
||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{parse_macro_input, Data, DeriveInput, Fields, Type, TypePath};
|
use syn::{parse_macro_input, Data, DeriveInput, Fields};
|
||||||
|
|
||||||
/// Get inner type. Example: Returns `T` for `Option<T>`.
|
mod types;
|
||||||
fn extract_inner_type<'a>(ty: &'a Type, parent: &'a str) -> Option<&'a Type> {
|
use types::*;
|
||||||
if let Type::Path(type_path) = ty {
|
mod partial_fields;
|
||||||
if type_path.path.segments.len() == 1 {
|
use partial_fields::partial_code_field;
|
||||||
let segment = &type_path.path.segments[0];
|
mod update_fields;
|
||||||
if segment.ident == parent {
|
use update_fields::update_code_field;
|
||||||
if let syn::PathArguments::AngleBracketed(ref args) = segment.arguments {
|
mod change_fields;
|
||||||
if args.args.len() == 1 {
|
use change_fields::builder_change_fields;
|
||||||
if let syn::GenericArgument::Type(ref inner_type) = args.args[0] {
|
|
||||||
return Some(inner_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn type_path(ty: &syn::Type) -> TypePath {
|
|
||||||
if let syn::Type::Path(type_path) = ty {
|
|
||||||
return type_path.clone();
|
|
||||||
}
|
|
||||||
unreachable!();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_type(ty: &syn::Type, t: &str) -> bool {
|
|
||||||
let type_path = type_path(ty);
|
|
||||||
let id = type_path.path.segments.first().unwrap().ident.to_string();
|
|
||||||
id == t
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// #[derive(Model)]
|
||||||
#[proc_macro_derive(Model)]
|
#[proc_macro_derive(Model)]
|
||||||
pub fn model_derive(input: TokenStream) -> TokenStream {
|
pub fn model_derive(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
|
@ -44,84 +22,37 @@ pub fn model_derive(input: TokenStream) -> TokenStream {
|
||||||
let name = input.ident;
|
let name = input.ident;
|
||||||
let name_str = name.to_string().to_snake();
|
let name_str = name.to_string().to_snake();
|
||||||
let partial_name = syn::Ident::new(&format!("Partial{}", name), name.span());
|
let partial_name = syn::Ident::new(&format!("Partial{}", name), name.span());
|
||||||
|
let changebuilder_name = syn::Ident::new(&format!("Change{}", name), name.span());
|
||||||
|
|
||||||
|
let update_doc = "Commit the builder changes to DB";
|
||||||
|
|
||||||
// Generate code for each field
|
// Generate code for each field
|
||||||
let field_code = if let Data::Struct(data_struct) = input.data {
|
let field_code = if let Data::Struct(data_struct) = input.data {
|
||||||
match data_struct.fields {
|
match data_struct.fields {
|
||||||
Fields::Named(fields_named) => {
|
Fields::Named(fields_named) => {
|
||||||
let field_process_code: Vec<_> = fields_named.named.iter().map(|field| {
|
// Update code
|
||||||
let field_name = &field.ident.as_ref().unwrap();
|
let field_process_code: Vec<_> =
|
||||||
let field_type = &field.ty;
|
fields_named.named.iter().map(update_code_field).collect();
|
||||||
let field_name_str = field_name.to_string();
|
|
||||||
|
|
||||||
if field_name_str == "_id" {
|
// Partial struct fields
|
||||||
return quote! {};
|
let partial_struct: Vec<_> =
|
||||||
}
|
fields_named.named.iter().map(partial_code_field).collect();
|
||||||
|
|
||||||
if is_type(field_type, "Historic") {
|
// Builder functions
|
||||||
let inner_field_type = extract_inner_type(field_type, "Historic").unwrap();
|
let builder_change_fields: Vec<_> = fields_named
|
||||||
if is_type(inner_field_type, "Vec") {
|
|
||||||
return quote! {
|
|
||||||
mongod::update_historic_vec!(self, obj, #field_name_str, #field_name, update);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return quote! {
|
|
||||||
mongod::update_historic_str!(self, obj, #field_name_str, #field_name, update);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_type(field_type, "Option") {
|
|
||||||
let inner_field_type = extract_inner_type(field_type, "Option").unwrap();
|
|
||||||
|
|
||||||
if is_type(inner_field_type, "Historic") {
|
|
||||||
let sub_inner_field_type = extract_inner_type(inner_field_type, "Historic").unwrap();
|
|
||||||
if is_type(sub_inner_field_type, "Reference") {
|
|
||||||
return quote! {
|
|
||||||
mongod::update_historic_ref_option!(self, obj, #field_name_str, #field_name, update);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return quote! {
|
|
||||||
mongod::update_value_option!(self, obj, #field_name_str, #field_name, update, #inner_field_type);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
mongod::update_value!(self, obj, #field_name_str, #field_name, update, #field_type);
|
|
||||||
}
|
|
||||||
}).collect();
|
|
||||||
|
|
||||||
let partial_struct: Vec<_> = fields_named
|
|
||||||
.named
|
.named
|
||||||
.iter()
|
.iter()
|
||||||
.map(|field| {
|
.map(builder_change_fields)
|
||||||
let field_name = &field.ident.as_ref().unwrap();
|
|
||||||
let field_type = &field.ty;
|
|
||||||
let field_name_str = field_name.to_string();
|
|
||||||
|
|
||||||
if field_name_str == "_id" {
|
|
||||||
return quote! {
|
|
||||||
pub _id: String,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_type(field_type, "Option") {
|
|
||||||
return quote! {
|
|
||||||
pub #field_name: #field_type,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
pub #field_name: Option<#field_type>,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl mongod::model::Model for #name {
|
impl mongod::model::Model for #name {
|
||||||
type Partial = #partial_name;
|
type Partial = #partial_name;
|
||||||
|
type ChangeBuilder = #changebuilder_name;
|
||||||
|
|
||||||
|
fn change_builder(self) -> Self::ChangeBuilder {
|
||||||
|
#changebuilder_name::new(self)
|
||||||
|
}
|
||||||
|
|
||||||
async fn update_values(
|
async fn update_values(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -137,6 +68,47 @@ pub fn model_derive(input: TokenStream) -> TokenStream {
|
||||||
#( #partial_struct )*
|
#( #partial_struct )*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct #changebuilder_name {
|
||||||
|
model: #name,
|
||||||
|
changeset: mongod::mongodb::bson::Document
|
||||||
|
}
|
||||||
|
|
||||||
|
impl #changebuilder_name {
|
||||||
|
pub fn new(model: #name) -> Self {
|
||||||
|
Self {
|
||||||
|
model,
|
||||||
|
changeset: mongod::mongodb::bson::doc! {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc = #update_doc]
|
||||||
|
pub async fn update(self) -> Result<#name, mongod::model::UpdateError> {
|
||||||
|
let db = mongod::get_mongo!();
|
||||||
|
let collection = mongod::col!(db, <#name as mongod::Referencable>::collection_name());
|
||||||
|
|
||||||
|
if let Err(msg) = mongod::Validate::validate(&self.model).await {
|
||||||
|
return Err(mongod::model::UpdateError::Validation(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
let changeset = self.changeset;
|
||||||
|
|
||||||
|
collection
|
||||||
|
.update_one(
|
||||||
|
mongod::id_of!(mongod::Referencable::id(&self.model)),
|
||||||
|
changeset,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.map_err(mongod::model::UpdateError::Database)?;
|
||||||
|
|
||||||
|
Ok(self.model)
|
||||||
|
}
|
||||||
|
|
||||||
|
#( #builder_change_fields )*
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
impl mongod::model::reference::Referencable for #partial_name {
|
impl mongod::model::reference::Referencable for #partial_name {
|
||||||
fn collection_name() -> &'static str {
|
fn collection_name() -> &'static str {
|
||||||
#name_str
|
#name_str
|
||||||
|
@ -157,6 +129,7 @@ pub fn model_derive(input: TokenStream) -> TokenStream {
|
||||||
TokenStream::from(field_code)
|
TokenStream::from(field_code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// #[derive(Referencable)]
|
||||||
#[proc_macro_derive(Referencable)]
|
#[proc_macro_derive(Referencable)]
|
||||||
pub fn referencable_derive(input: TokenStream) -> TokenStream {
|
pub fn referencable_derive(input: TokenStream) -> TokenStream {
|
||||||
let input = parse_macro_input!(input as DeriveInput);
|
let input = parse_macro_input!(input as DeriveInput);
|
||||||
|
|
30
mongod_derive/src/partial_fields.rs
Normal file
30
mongod_derive/src/partial_fields.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
use quote::quote;
|
||||||
|
use syn::Field;
|
||||||
|
|
||||||
|
use crate::is_type;
|
||||||
|
|
||||||
|
/// Generate struct fields for Partial Model
|
||||||
|
pub fn partial_code_field(field: &Field) -> proc_macro2::TokenStream {
|
||||||
|
let field_name = &field.ident.as_ref().unwrap();
|
||||||
|
let field_type = &field.ty;
|
||||||
|
let field_name_str = field_name.to_string();
|
||||||
|
|
||||||
|
// Keep _id
|
||||||
|
if field_name_str == "_id" {
|
||||||
|
return quote! {
|
||||||
|
pub _id: String,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leave Option<T> alone
|
||||||
|
if is_type(field_type, "Option") {
|
||||||
|
return quote! {
|
||||||
|
pub #field_name: #field_type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Turn every field into Option<T>
|
||||||
|
quote! {
|
||||||
|
pub #field_name: Option<#field_type>,
|
||||||
|
}
|
||||||
|
}
|
42
mongod_derive/src/types.rs
Normal file
42
mongod_derive/src/types.rs
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
use syn::{Type, TypePath};
|
||||||
|
|
||||||
|
/// Get inner type. Example: Returns `T` for `Option<T>`.
|
||||||
|
pub fn extract_inner_type<'a>(ty: &'a Type, parent: &'a str) -> Option<&'a Type> {
|
||||||
|
if let Type::Path(type_path) = ty {
|
||||||
|
if type_path.path.segments.len() == 1 {
|
||||||
|
let segment = &type_path.path.segments[0];
|
||||||
|
if segment.ident == parent {
|
||||||
|
if let syn::PathArguments::AngleBracketed(ref args) = segment.arguments {
|
||||||
|
if args.args.len() == 1 {
|
||||||
|
if let syn::GenericArgument::Type(ref inner_type) = args.args[0] {
|
||||||
|
return Some(inner_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_path(ty: &syn::Type) -> TypePath {
|
||||||
|
if let syn::Type::Path(type_path) = ty {
|
||||||
|
return type_path.clone();
|
||||||
|
}
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_one_of_type(ty: &syn::Type, t: &[&str]) -> bool {
|
||||||
|
for typ in t {
|
||||||
|
if is_type(ty, typ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_type(ty: &syn::Type, t: &str) -> bool {
|
||||||
|
let type_path = type_path(ty);
|
||||||
|
let id = type_path.path.segments.first().unwrap().ident.to_string();
|
||||||
|
id == t
|
||||||
|
}
|
55
mongod_derive/src/update_fields.rs
Normal file
55
mongod_derive/src/update_fields.rs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
use quote::quote;
|
||||||
|
use syn::Field;
|
||||||
|
|
||||||
|
use crate::{extract_inner_type, is_type};
|
||||||
|
|
||||||
|
/// Generate code for the update fn of models
|
||||||
|
pub fn update_code_field(field: &Field) -> proc_macro2::TokenStream {
|
||||||
|
let field_name = &field.ident.as_ref().unwrap();
|
||||||
|
let field_type = &field.ty;
|
||||||
|
let field_name_str = field_name.to_string();
|
||||||
|
|
||||||
|
// Never update _id
|
||||||
|
if field_name_str == "_id" {
|
||||||
|
return quote! {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_type(field_type, "Historic") {
|
||||||
|
let inner_field_type = extract_inner_type(field_type, "Historic").unwrap();
|
||||||
|
if is_type(inner_field_type, "Vec") {
|
||||||
|
// Custom code Historic<Vec<T>>
|
||||||
|
return quote! {
|
||||||
|
mongod::update_historic_vec!(self, obj, #field_name_str, #field_name, update);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code for Historic<T>
|
||||||
|
return quote! {
|
||||||
|
mongod::update_historic_str!(self, obj, #field_name_str, #field_name, update);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if is_type(field_type, "Option") {
|
||||||
|
let inner_field_type = extract_inner_type(field_type, "Option").unwrap();
|
||||||
|
|
||||||
|
if is_type(inner_field_type, "Historic") {
|
||||||
|
let sub_inner_field_type = extract_inner_type(inner_field_type, "Historic").unwrap();
|
||||||
|
if is_type(sub_inner_field_type, "Reference") {
|
||||||
|
// Code for Option<Historic<Reference>>
|
||||||
|
return quote! {
|
||||||
|
mongod::update_historic_ref_option!(self, obj, #field_name_str, #field_name, update);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code for Option<T>
|
||||||
|
return quote! {
|
||||||
|
mongod::update_value_option!(self, obj, #field_name_str, #field_name, update, #inner_field_type);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code for T
|
||||||
|
quote! {
|
||||||
|
mongod::update_value!(self, obj, #field_name_str, #field_name, update, #field_type);
|
||||||
|
}
|
||||||
|
}
|
21
src/lib.rs
21
src/lib.rs
|
@ -3,8 +3,10 @@ pub use model::historic::Historic;
|
||||||
pub use model::reference::*;
|
pub use model::reference::*;
|
||||||
pub use model::valid::Validate;
|
pub use model::valid::Validate;
|
||||||
pub use model::Model;
|
pub use model::Model;
|
||||||
|
pub use model::Sort;
|
||||||
pub use mongod_derive as derive;
|
pub use mongod_derive as derive;
|
||||||
pub use mongodb;
|
pub use mongodb;
|
||||||
|
|
||||||
#[cfg(feature = "cache")]
|
#[cfg(feature = "cache")]
|
||||||
pub mod cache;
|
pub mod cache;
|
||||||
#[cfg(feature = "cache")]
|
#[cfg(feature = "cache")]
|
||||||
|
@ -55,7 +57,7 @@ macro_rules! get_mongo {
|
||||||
if let Some(client) = $crate::MONGO_CLIENT.get() {
|
if let Some(client) = $crate::MONGO_CLIENT.get() {
|
||||||
client
|
client
|
||||||
} else {
|
} else {
|
||||||
let client = mongodb::Client::with_uri_str(&std::env::var("DB_URI").unwrap())
|
let client = $crate::mongodb::Client::with_uri_str(&std::env::var("DB_URI").unwrap())
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
$crate::MONGO_CLIENT.set(client).unwrap();
|
$crate::MONGO_CLIENT.set(client).unwrap();
|
||||||
|
@ -95,3 +97,20 @@ macro_rules! id_of {
|
||||||
$crate::mongodb::bson::doc! { "_id": $id}
|
$crate::mongodb::bson::doc! { "_id": $id}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A trait to generate a Model API representation in JSON format.
|
||||||
|
pub trait ToAPI: Sized {
|
||||||
|
/// Generate public API JSON
|
||||||
|
fn api(&self) -> impl std::future::Future<Output = serde_json::Value>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Converts a slice of items implementing the `ToAPI` trait into a `Vec` of JSON values.
|
||||||
|
pub async fn vec_to_api(items: &[impl ToAPI]) -> Vec<serde_json::Value> {
|
||||||
|
let mut ret = Vec::with_capacity(items.len());
|
||||||
|
|
||||||
|
for e in items {
|
||||||
|
ret.push(e.api().await);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::{collections::HashMap, ops::Deref};
|
||||||
|
|
||||||
/// A struct to keep track of historical changes to a value.
|
/// A struct to keep track of historical changes to a value.
|
||||||
/// This struct represents a value that has a current state and a history of previous states.
|
/// This struct represents a value that has a current state and a history of previous states.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct Historic<T> {
|
pub struct Historic<T> {
|
||||||
/// The current value
|
/// The current value
|
||||||
pub current: T,
|
pub current: T,
|
||||||
|
@ -24,6 +24,13 @@ impl<T: Clone> Historic<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T: Default + Clone> Historic<T> {
|
||||||
|
/// Create a new tracked value initialized with Default
|
||||||
|
pub fn new_default() -> Historic<T> {
|
||||||
|
Self::new(T::default())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: Clone> Historic<T> {
|
impl<T: Clone> Historic<T> {
|
||||||
/// Update the value. The change will be recorded.
|
/// Update the value. The change will be recorded.
|
||||||
/// Will record a change even if the value is the same as the current one.
|
/// Will record a change even if the value is the same as the current one.
|
||||||
|
|
|
@ -8,15 +8,16 @@ use serde::de::DeserializeOwned;
|
||||||
use serde_json::{Map, Value};
|
use serde_json::{Map, Value};
|
||||||
use valid::Validate;
|
use valid::Validate;
|
||||||
|
|
||||||
use crate::{cache_read, cache_write, col, collect_results, get_mongo, id_of};
|
#[cfg(feature = "cache")]
|
||||||
|
use crate::{cache_read, cache_write};
|
||||||
|
|
||||||
|
use crate::{col, collect_results, get_mongo, id_of};
|
||||||
|
|
||||||
pub mod historic;
|
pub mod historic;
|
||||||
pub mod reference;
|
pub mod reference;
|
||||||
pub mod update;
|
pub mod update;
|
||||||
pub mod valid;
|
pub mod valid;
|
||||||
|
|
||||||
// todo : use mongodb projection to only get fields you actually use, maybe PartialModel shadow struct?
|
|
||||||
|
|
||||||
/// Error type when updating a model
|
/// Error type when updating a model
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum UpdateError {
|
pub enum UpdateError {
|
||||||
|
@ -32,6 +33,7 @@ pub trait Model:
|
||||||
Sized + Referencable + Validate + serde::Serialize + for<'a> serde::Deserialize<'a>
|
Sized + Referencable + Validate + serde::Serialize + for<'a> serde::Deserialize<'a>
|
||||||
{
|
{
|
||||||
type Partial: DeserializeOwned;
|
type Partial: DeserializeOwned;
|
||||||
|
type ChangeBuilder;
|
||||||
|
|
||||||
/// Insert the `Model` into the database
|
/// Insert the `Model` into the database
|
||||||
fn insert(
|
fn insert(
|
||||||
|
@ -215,7 +217,7 @@ pub trait Model:
|
||||||
/// Get all `Model`s from the database
|
/// Get all `Model`s from the database
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn find_all() -> impl std::future::Future<Output = Option<Vec<Self>>> {
|
fn find_all() -> impl std::future::Future<Output = Option<Vec<Self>>> {
|
||||||
Self::find(doc! {}, None)
|
Self::find(doc! {}, None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all `Model`s partial from the database
|
/// Get all `Model`s partial from the database
|
||||||
|
@ -223,7 +225,7 @@ pub trait Model:
|
||||||
fn find_all_partial(
|
fn find_all_partial(
|
||||||
part: serde_json::Value,
|
part: serde_json::Value,
|
||||||
) -> impl std::future::Future<Output = Option<Vec<Self::Partial>>> {
|
) -> impl std::future::Future<Output = Option<Vec<Self::Partial>>> {
|
||||||
Self::find_partial(doc! {}, part, None)
|
Self::find_partial(doc! {}, part, None, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get multiple `Model`s by using a filter from the database. Pass a `limit` parameter to limit the amount of `Model`s returned.
|
/// Get multiple `Model`s by using a filter from the database. Pass a `limit` parameter to limit the amount of `Model`s returned.
|
||||||
|
@ -231,17 +233,15 @@ pub trait Model:
|
||||||
fn find(
|
fn find(
|
||||||
filter: mongodb::bson::Document,
|
filter: mongodb::bson::Document,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
|
sort: Option<mongodb::bson::Document>,
|
||||||
) -> impl std::future::Future<Output = Option<Vec<Self>>> {
|
) -> impl std::future::Future<Output = Option<Vec<Self>>> {
|
||||||
async move {
|
async move {
|
||||||
let db = get_mongo!();
|
let db = get_mongo!();
|
||||||
let collection = col!(db, Self::collection_name());
|
let collection = col!(db, Self::collection_name());
|
||||||
let mut results = collection
|
|
||||||
.find(
|
let options = FindOptions::builder().limit(limit).sort(sort).build();
|
||||||
filter,
|
|
||||||
limit.map(|x| FindOptions::builder().limit(x).build()),
|
let mut results = collection.find(filter, options).await.ok()?;
|
||||||
)
|
|
||||||
.await
|
|
||||||
.ok()?;
|
|
||||||
let docs = collect_results!(results);
|
let docs = collect_results!(results);
|
||||||
docs.into_iter()
|
docs.into_iter()
|
||||||
.map(|x| mongodb::bson::from_document(x).unwrap())
|
.map(|x| mongodb::bson::from_document(x).unwrap())
|
||||||
|
@ -249,12 +249,28 @@ pub trait Model:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get unique values of a Models field
|
||||||
|
fn unique<T: DeserializeOwned>(
|
||||||
|
filter: mongodb::bson::Document,
|
||||||
|
field: &str,
|
||||||
|
) -> impl std::future::Future<Output = Vec<T>> {
|
||||||
|
async move {
|
||||||
|
let db = get_mongo!();
|
||||||
|
let collection = col!(db, Self::collection_name());
|
||||||
|
let res = collection.distinct(field, filter, None).await.unwrap();
|
||||||
|
res.into_iter()
|
||||||
|
.filter_map(|x| mongodb::bson::from_bson(x).ok())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Get multiple partial `Model`s by using a filter from the database. Pass a `limit` parameter to limit the amount of `Model`s returned.
|
/// Get multiple partial `Model`s by using a filter from the database. Pass a `limit` parameter to limit the amount of `Model`s returned.
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn find_partial(
|
fn find_partial(
|
||||||
filter: mongodb::bson::Document,
|
filter: mongodb::bson::Document,
|
||||||
mut part: serde_json::Value,
|
mut part: serde_json::Value,
|
||||||
limit: Option<i64>,
|
limit: Option<i64>,
|
||||||
|
sort: Option<mongodb::bson::Document>,
|
||||||
) -> impl std::future::Future<Output = Option<Vec<Self::Partial>>> {
|
) -> impl std::future::Future<Output = Option<Vec<Self::Partial>>> {
|
||||||
async move {
|
async move {
|
||||||
let db = get_mongo!();
|
let db = get_mongo!();
|
||||||
|
@ -262,18 +278,13 @@ pub trait Model:
|
||||||
|
|
||||||
part.as_object_mut()?.insert("_id".into(), 1.into());
|
part.as_object_mut()?.insert("_id".into(), 1.into());
|
||||||
|
|
||||||
let mut results = collection
|
let options = FindOptions::builder()
|
||||||
.find(
|
|
||||||
filter,
|
|
||||||
Some(
|
|
||||||
FindOptions::builder()
|
|
||||||
.projection(Some(mongodb::bson::to_document(&part).unwrap()))
|
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
.build(),
|
.sort(sort)
|
||||||
),
|
.projection(Some(mongodb::bson::to_document(&part).unwrap()))
|
||||||
)
|
.build();
|
||||||
.await
|
|
||||||
.ok()?;
|
let mut results = collection.find(filter, Some(options)).await.ok()?;
|
||||||
let docs = collect_results!(results);
|
let docs = collect_results!(results);
|
||||||
docs.into_iter()
|
docs.into_iter()
|
||||||
.map(|x| mongodb::bson::from_document(x).unwrap())
|
.map(|x| mongodb::bson::from_document(x).unwrap())
|
||||||
|
@ -281,6 +292,18 @@ pub trait Model:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn change_builder(self) -> Self::ChangeBuilder;
|
||||||
|
|
||||||
|
/// Update values of `Model` using a builder pattern
|
||||||
|
fn change(self) -> Self::ChangeBuilder {
|
||||||
|
#[cfg(feature = "cache")]
|
||||||
|
{
|
||||||
|
cache_write!().invalidate(Self::collection_name(), self.id());
|
||||||
|
}
|
||||||
|
|
||||||
|
self.change_builder()
|
||||||
|
}
|
||||||
|
|
||||||
/// Update values of `Model` into database
|
/// Update values of `Model` into database
|
||||||
fn update(
|
fn update(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -333,3 +356,28 @@ pub trait Model:
|
||||||
update: &mut mongodb::bson::Document,
|
update: &mut mongodb::bson::Document,
|
||||||
) -> impl std::future::Future<Output = ()> + Send;
|
) -> impl std::future::Future<Output = ()> + Send;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sorting Order
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```ignore
|
||||||
|
/// let m = MyModel::find(doc! {}, None, Some(doc! {
|
||||||
|
/// "sort_key": Sort::Ascending
|
||||||
|
/// })).await.unwrap();
|
||||||
|
/// ```
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Sort {
|
||||||
|
/// Sort in ascending order
|
||||||
|
Ascending,
|
||||||
|
/// Sort in descending order
|
||||||
|
Descending,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<mongodb::bson::Bson> for Sort {
|
||||||
|
fn into(self) -> mongodb::bson::Bson {
|
||||||
|
match self {
|
||||||
|
Sort::Ascending => mongodb::bson::bson!(1),
|
||||||
|
Sort::Descending => mongodb::bson::bson!(-1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,9 +10,14 @@ use super::{valid::Validate, Model};
|
||||||
pub struct Reference(String);
|
pub struct Reference(String);
|
||||||
|
|
||||||
impl Reference {
|
impl Reference {
|
||||||
/// Create a new reference from String
|
/// Create a new reference from String without checks
|
||||||
pub async fn new_raw(reference: &str) -> Option<Self> {
|
pub fn new_raw(reference: &str) -> Self {
|
||||||
let r = Self(reference.to_string());
|
Self(reference.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new reference
|
||||||
|
pub async fn new(model: &str, id: &str) -> Option<Self> {
|
||||||
|
let r = Self(format!("{model}::{id}"));
|
||||||
if r.validate().await.is_ok() {
|
if r.validate().await.is_ok() {
|
||||||
Some(r)
|
Some(r)
|
||||||
} else {
|
} else {
|
||||||
|
@ -20,11 +25,6 @@ impl Reference {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new reference
|
|
||||||
pub async fn new(model: &str, id: &str) -> Option<Self> {
|
|
||||||
Self::new_raw(&format!("{model}::{id}")).await
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get just the ID of the referenced `Model`
|
/// Get just the ID of the referenced `Model`
|
||||||
pub fn id(&self) -> &str {
|
pub fn id(&self) -> &str {
|
||||||
self.0.split_once("::").unwrap().1
|
self.0.split_once("::").unwrap().1
|
||||||
|
@ -130,11 +130,11 @@ macro_rules! reference_of {
|
||||||
($model:ident, $id:ident) => {{
|
($model:ident, $id:ident) => {{
|
||||||
$model::get_partial($id, serde_json::json!({}))
|
$model::get_partial($id, serde_json::json!({}))
|
||||||
.await
|
.await
|
||||||
.map(|x| x.reference())
|
.map(|x| mongod::Referencable::reference(&x))
|
||||||
}};
|
}};
|
||||||
($model:ident, $id:literal) => {{
|
($model:ident, $id:literal) => {{
|
||||||
$model::get_partial($id, serde_json::json!({}))
|
$model::get_partial($id, serde_json::json!({}))
|
||||||
.await
|
.await
|
||||||
.map(|x| x.reference())
|
.map(|x| mongod::Referencable::reference(&x))
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue