Бэкенд: по сути монго готово, пусть и белиберда

This commit is contained in:
Сергей Полевой 2023-05-19 12:49:22 +04:00
parent 6abd323314
commit 8184781b2d
12 changed files with 1491 additions and 25 deletions

587
backend/Cargo.lock generated
View File

@ -30,7 +30,7 @@ dependencies = [
"actix-service",
"actix-utils",
"ahash 0.8.3",
"base64",
"base64 0.21.0",
"bitflags",
"brotli",
"bytes",
@ -277,8 +277,10 @@ dependencies = [
"chrono",
"dotenv",
"dotenv_codegen",
"futures",
"mongodb",
"nanoid",
"pbkdf2",
"pbkdf2 0.12.1",
"rust_decimal",
"rust_decimal_macros",
"serde",
@ -288,6 +290,12 @@ dependencies = [
"tokio-postgres",
]
[[package]]
name = "base64"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.21.0"
@ -387,6 +395,28 @@ dependencies = [
"alloc-stdlib",
]
[[package]]
name = "bson"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aeb8bae494e49dbc330dd23cf78f6f7accee22f640ce3ab17841badaa4ce232"
dependencies = [
"ahash 0.7.6",
"base64 0.13.1",
"bitvec",
"chrono",
"hex",
"indexmap",
"js-sys",
"lazy_static",
"rand",
"serde",
"serde_bytes",
"serde_json",
"time 0.3.20",
"uuid",
]
[[package]]
name = "bumpalo"
version = "3.12.0"
@ -572,6 +602,58 @@ dependencies = [
"syn 2.0.12",
]
[[package]]
name = "darling"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 1.0.109",
]
[[package]]
name = "darling_macro"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [
"darling_core",
"quote",
"syn 1.0.109",
]
[[package]]
name = "data-encoding"
version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "derive_more"
version = "0.99.17"
@ -581,7 +663,7 @@ dependencies = [
"convert_case",
"proc-macro2",
"quote",
"rustc_version",
"rustc_version 0.4.0",
"syn 1.0.109",
]
@ -634,6 +716,18 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "enum-as-inner"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73"
dependencies = [
"heck",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "fallible-iterator"
version = "0.2.0"
@ -671,6 +765,21 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
[[package]]
name = "futures"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
dependencies = [
"futures-channel",
"futures-core",
"futures-executor",
"futures-io",
"futures-sink",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-channel"
version = "0.3.28"
@ -687,6 +796,23 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
[[package]]
name = "futures-executor"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
dependencies = [
"futures-core",
"futures-task",
"futures-util",
]
[[package]]
name = "futures-io"
version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
[[package]]
name = "futures-macro"
version = "0.3.28"
@ -716,10 +842,13 @@ version = "0.3.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
dependencies = [
"futures-channel",
"futures-core",
"futures-io",
"futures-macro",
"futures-sink",
"futures-task",
"memchr",
"pin-project-lite",
"pin-utils",
"slab",
@ -774,6 +903,12 @@ dependencies = [
"ahash 0.7.6",
]
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.2.6"
@ -783,6 +918,12 @@ dependencies = [
"libc",
]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hmac"
version = "0.12.1"
@ -792,6 +933,17 @@ dependencies = [
"digest",
]
[[package]]
name = "hostname"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
dependencies = [
"libc",
"match_cfg",
"winapi",
]
[[package]]
name = "http"
version = "0.2.9"
@ -839,6 +991,23 @@ dependencies = [
"cxx-build",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
dependencies = [
"matches",
"unicode-bidi",
"unicode-normalization",
]
[[package]]
name = "idna"
version = "0.3.0"
@ -859,6 +1028,24 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "ipconfig"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be"
dependencies = [
"socket2 0.4.9",
"widestring",
"winapi",
"winreg",
]
[[package]]
name = "ipnet"
version = "2.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
[[package]]
name = "itoa"
version = "1.0.6"
@ -889,6 +1076,12 @@ version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.140"
@ -904,6 +1097,12 @@ dependencies = [
"cc",
]
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "local-channel"
version = "0.1.3"
@ -941,6 +1140,27 @@ dependencies = [
"cfg-if",
]
[[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]]
name = "match_cfg"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
[[package]]
name = "matches"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
[[package]]
name = "md-5"
version = "0.10.5"
@ -983,6 +1203,53 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "mongodb"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebe15399de63ad4294c80069967736cbb87ebe467a8cd0629df9cab88a6fbde6"
dependencies = [
"async-trait",
"base64 0.13.1",
"bitflags",
"bson",
"chrono",
"derivative",
"derive_more",
"futures-core",
"futures-executor",
"futures-io",
"futures-util",
"hex",
"hmac",
"lazy_static",
"md-5",
"pbkdf2 0.11.0",
"percent-encoding",
"rand",
"rustc_version_runtime",
"rustls",
"rustls-pemfile",
"serde",
"serde_bytes",
"serde_with",
"sha-1",
"sha2",
"socket2 0.4.9",
"stringprep",
"strsim",
"take_mut",
"thiserror",
"tokio",
"tokio-rustls",
"tokio-util",
"trust-dns-proto",
"trust-dns-resolver",
"typed-builder",
"uuid",
"webpki-roots",
]
[[package]]
name = "nanoid"
version = "0.4.0"
@ -1056,6 +1323,15 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
[[package]]
name = "pbkdf2"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
dependencies = [
"digest",
]
[[package]]
name = "pbkdf2"
version = "0.12.1"
@ -1128,7 +1404,7 @@ version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78b7fa9f396f51dffd61546fd8573ee20592287996568e6175ceb0f8699ad75d"
dependencies = [
"base64",
"base64 0.21.0",
"byteorder",
"bytes",
"fallible-iterator",
@ -1202,6 +1478,12 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]]
name = "quote"
version = "1.0.26"
@ -1282,6 +1564,31 @@ dependencies = [
"bytecheck",
]
[[package]]
name = "resolv-conf"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00"
dependencies = [
"hostname",
"quick-error",
]
[[package]]
name = "ring"
version = "0.16.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
dependencies = [
"cc",
"libc",
"once_cell",
"spin",
"untrusted",
"web-sys",
"winapi",
]
[[package]]
name = "rkyv"
version = "0.7.42"
@ -1340,13 +1647,53 @@ dependencies = [
"rust_decimal",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver 0.9.0",
]
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver",
"semver 1.0.17",
]
[[package]]
name = "rustc_version_runtime"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d31b7153270ebf48bf91c65ae5b0c00e749c4cfad505f66530ac74950249582f"
dependencies = [
"rustc_version 0.2.3",
"semver 0.9.0",
]
[[package]]
name = "rustls"
version = "0.20.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
dependencies = [
"log",
"ring",
"sct",
"webpki",
]
[[package]]
name = "rustls-pemfile"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
dependencies = [
"base64 0.21.0",
]
[[package]]
@ -1367,18 +1714,43 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
[[package]]
name = "sct"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "seahash"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "serde"
version = "1.0.159"
@ -1388,6 +1760,15 @@ dependencies = [
"serde_derive",
]
[[package]]
name = "serde_bytes"
version = "0.11.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294"
dependencies = [
"serde",
]
[[package]]
name = "serde_derive"
version = "1.0.159"
@ -1405,6 +1786,7 @@ version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
@ -1422,6 +1804,39 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_with"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
dependencies = [
"serde",
"serde_with_macros",
]
[[package]]
name = "serde_with_macros"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "sha-1"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha1"
version = "0.10.5"
@ -1500,6 +1915,12 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "stringprep"
version = "0.1.2"
@ -1510,6 +1931,12 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "subtle"
version = "2.4.1"
@ -1538,6 +1965,12 @@ dependencies = [
"unicode-ident",
]
[[package]]
name = "take_mut"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
[[package]]
name = "tap"
version = "1.0.1"
@ -1553,6 +1986,26 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.12",
]
[[package]]
name = "time"
version = "0.1.45"
@ -1660,6 +2113,17 @@ dependencies = [
"tokio-util",
]
[[package]]
name = "tokio-rustls"
version = "0.23.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
dependencies = [
"rustls",
"tokio",
"webpki",
]
[[package]]
name = "tokio-util"
version = "0.7.7"
@ -1668,6 +2132,7 @@ checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2"
dependencies = [
"bytes",
"futures-core",
"futures-io",
"futures-sink",
"pin-project-lite",
"tokio",
@ -1704,6 +2169,62 @@ dependencies = [
"once_cell",
]
[[package]]
name = "trust-dns-proto"
version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d"
dependencies = [
"async-trait",
"cfg-if",
"data-encoding",
"enum-as-inner",
"futures-channel",
"futures-io",
"futures-util",
"idna 0.2.3",
"ipnet",
"lazy_static",
"log",
"rand",
"smallvec",
"thiserror",
"tinyvec",
"tokio",
"url",
]
[[package]]
name = "trust-dns-resolver"
version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558"
dependencies = [
"cfg-if",
"futures-util",
"ipconfig",
"lazy_static",
"log",
"lru-cache",
"parking_lot",
"resolv-conf",
"smallvec",
"thiserror",
"tokio",
"trust-dns-proto",
]
[[package]]
name = "typed-builder"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89851716b67b937e393b3daa8423e67ddfc4bbbf1654bcf05488e95e0828db0c"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "typenum"
version = "1.16.0"
@ -1737,6 +2258,12 @@ version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "untrusted"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "url"
version = "2.3.1"
@ -1744,7 +2271,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
dependencies = [
"form_urlencoded",
"idna",
"idna 0.3.0",
"percent-encoding",
]
@ -1753,6 +2280,10 @@ name = "uuid"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2"
dependencies = [
"getrandom",
"serde",
]
[[package]]
name = "version_check"
@ -1826,6 +2357,41 @@ version = "0.2.84"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
[[package]]
name = "web-sys"
version = "0.3.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webpki"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
"ring",
"untrusted",
]
[[package]]
name = "webpki-roots"
version = "0.22.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
dependencies = [
"webpki",
]
[[package]]
name = "widestring"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983"
[[package]]
name = "winapi"
version = "0.3.9"
@ -1932,6 +2498,15 @@ version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "winreg"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
[[package]]
name = "wyz"
version = "0.5.1"

View File

@ -19,4 +19,6 @@ pbkdf2 = "0.12.1"
nanoid = "0.4.0"
sha2 = "0.10.6"
rust_decimal = { version = "1.29", features = ["db-tokio-postgres"] }
rust_decimal_macros = "1.29"
rust_decimal_macros = "1.29"
mongodb = { version = "2.5.0", features = ["bson-chrono-0_4"] }
futures = "0.3"

View File

@ -6,6 +6,8 @@ use backend::endpoints::{auth::*};
use backend::storages::postgres::administrator::PostgresAdministratorRepository;
use dotenv_codegen::dotenv;
use backend::{State, services};
use mongodb::Client;
use mongodb::options::ClientOptions;
use tokio_postgres::NoTls;
use backend::storages::postgres::car::PostgresCarRepository;
use backend::storages::postgres::car_station::PostgresCarStationRepository;
@ -13,6 +15,14 @@ use backend::storages::postgres::client::PostgresClientRepository;
use backend::storages::postgres::rent::PostgresRentRepository;
use backend::storages::postgres::owner::PostgresOwnerRepository;
use backend::storages::postgres::benchmark::PostgresBenchmarkRepository;
use backend::storages::mongo::car::MongoCarRepository;
use backend::storages::mongo::car_station::MongoCarStationRepository;
use backend::storages::mongo::administrator::MongoAdministratorRepository;
use backend::storages::mongo::client::MongoClientRepository;
use backend::storages::mongo::rent::MongoRentRepository;
use backend::storages::mongo::owner::MongoOwnerRepository;
use backend::storages::mongo::benchmark::MongoBenchmarkRepository;
use backend::storages::*;
use backend::endpoints::car_station::*;
use backend::endpoints::car::*;
use backend::endpoints::client::*;
@ -21,32 +31,52 @@ use backend::endpoints::owner::*;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let (client, connection) = tokio_postgres::connect(
&format!("host={} user={} password={} dbname={}", dotenv!("HOST"), dotenv!("USERR"), dotenv!("PASSWORD"), dotenv!("DBNAMEE")),
NoTls
).await.unwrap();
// let (client, connection) = tokio_postgres::connect(
// &format!("host={} user={} password={} dbname={}", dotenv!("HOST"), dotenv!("USERR"), dotenv!("PASSWORD"), dotenv!("DBNAMEE")),
// NoTls
// ).await.unwrap();
tokio::spawn(async move {
if let Err(e) = connection.await {
eprintln!("connection error: {}", e);
}
});
// tokio::spawn(async move {
// if let Err(e) = connection.await {
// eprintln!("connection error: {}", e);
// }
// });
let client = Arc::new(client);
// let client = Arc::new(client);
let car_repository = PostgresCarRepository { connection: Arc::clone(&client) };
// let car_repository = PostgresCarRepository { connection: Arc::clone(&client) };
let car_station_repository = PostgresCarStationRepository { connection: Arc::clone(&client) };
// let car_station_repository = PostgresCarStationRepository { connection: Arc::clone(&client) };
let client_repository = PostgresClientRepository { connection: Arc::clone(&client) };
// let client_repository = PostgresClientRepository { connection: Arc::clone(&client) };
let owner_repository = PostgresOwnerRepository { connection: Arc::clone(&client) };
// let owner_repository = PostgresOwnerRepository { connection: Arc::clone(&client) };
let rent_repository = PostgresRentRepository { connection: Arc::clone(&client) };
// let rent_repository = PostgresRentRepository { connection: Arc::clone(&client) };
let administrator_repository = PostgresAdministratorRepository { connection: Arc::clone(&client) };
// let administrator_repository = PostgresAdministratorRepository { connection: Arc::clone(&client) };
let benchmark_repository = PostgresBenchmarkRepository { connection: Arc::clone(&client) };
// let benchmark_repository = PostgresBenchmarkRepository { connection: Arc::clone(&client) };
let client_options = ClientOptions::parse(dotenv!("MONGO")).await.unwrap();
let client = Client::with_options(client_options).unwrap();
let db = Arc::new(client.database("default_db"));
let car_repository = MongoCarRepository { database: Arc::clone(&db) };
let car_station_repository = MongoCarStationRepository { database: Arc::clone(&db) };
let client_repository = MongoClientRepository { database: Arc::clone(&db) };
let owner_repository = MongoOwnerRepository { database: Arc::clone(&db) };
let rent_repository = MongoRentRepository { database: Arc::clone(&db) };
let administrator_repository = MongoAdministratorRepository { database: Arc::clone(&db) };
let benchmark_repository = MongoBenchmarkRepository { database: Arc::clone(&db) };
let auth_service = services::auth::AuthService::new();

View File

@ -1,7 +1,7 @@
use rust_decimal::Decimal;
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct Car {
pub id: String,
pub brand: String,

View File

@ -0,0 +1,63 @@
use mongodb::Database;
use mongodb::bson::oid::ObjectId;
use mongodb::bson::{doc, Document, Bson};
use futures::stream::{TryStreamExt, StreamExt};
use mongodb::options::FindOptions;
use std::sync::Arc;
use crate::models::administrator::*;
use crate::storages::traits::AdministratorRepository;
use async_trait::async_trait;
pub struct MongoAdministratorRepository {
pub database: Arc<Database>
}
#[async_trait]
impl AdministratorRepository for MongoAdministratorRepository {
async fn read(&self, id: String) -> Result<Administrator, String> {
let collection = self.database.collection::<Document>("administrators");
let filter = doc! {
"_id": ObjectId::parse_str(&id).unwrap()
};
let result = collection.find_one(filter, None).await;
match result {
Ok(Some(document)) => {
let id = document.get_object_id("_id").unwrap().to_hex();
let username = document.get_str("username").unwrap().to_string();
let password = document.get_str("password").unwrap().to_string();
let name = document.get_str("name").unwrap().to_string();
let middlename = document.get_str("middlename").unwrap().to_string();
let surname = document.get_str("surname").unwrap().to_string();
let car_station_id = document.get_object_id("car_station_id").unwrap().to_hex();
let administrator = Administrator {id, username, password, name, surname, middlename, car_station_id};
Ok(administrator)
},
Ok(None) => Err("Administrator not found".to_string()),
Err(e) => Err(e.to_string())
}
}
async fn find_by_username(&self, username: &str) -> Result<Administrator, String> {
let collection = self.database.collection::<Document>("administrators");
let filter = doc! {
"username": username.to_string()
};
let result = collection.find_one(filter, None).await;
match result {
Ok(Some(document)) => {
let id = document.get_object_id("_id").unwrap().to_hex();
let username = document.get_str("username").unwrap().to_string();
let password = document.get_str("password").unwrap().to_string();
let name = document.get_str("name").unwrap().to_string();
let middlename = document.get_str("middlename").unwrap().to_string();
let surname = document.get_str("surname").unwrap().to_string();
let car_station_id = document.get_object_id("car_station_id").unwrap().to_hex();
let administrator = Administrator {id, username, password, name, surname, middlename, car_station_id};
Ok(administrator)
},
Ok(None) => Err("Administrator not found".to_string()),
Err(e) => Err(e.to_string())
}
}
}

View File

@ -0,0 +1,68 @@
use chrono::Utc;
use mongodb::Database;
use mongodb::bson::oid::ObjectId;
use mongodb::bson::{doc, Document, Bson};
use futures::stream::{TryStreamExt, StreamExt};
use mongodb::options::{FindOptions, AggregateOptions};
use rust_decimal::Decimal;
use rust_decimal::prelude::{ToPrimitive, FromPrimitive};
use std::default;
use std::sync::Arc;
use async_trait::async_trait;
use crate::storages::traits::BenchmarkRepository;
pub struct MongoBenchmarkRepository {
pub database: Arc<Database>
}
#[async_trait]
impl BenchmarkRepository for MongoBenchmarkRepository {
async fn benchmark(&self) -> Result<i64, String> {
let collection = self.database.collection::<Document>("clients");
collection.delete_many(doc! {}, None).await.unwrap();
let start_time = Utc::now().naive_local();
for i in 1..2001 {
let car_id = ObjectId::new();
let client_id = ObjectId::new();
let owner_id = ObjectId::new();
let rent_id = ObjectId::new();
collection.insert_one(doc! {
"_id": client_id,
"name": format!("Иван{}", i),
"surname": format!("Иванов{}", i),
"middlename": format!("Иванович{}", i),
"phone": i.to_string(),
"rents": [{
"_id": rent_id,
"start_time": chrono::Utc::now(),
"time_amount": i,
"car_id": car_id.clone()
}]
}, None).await.unwrap();
collection.insert_one(doc! {
"_id": owner_id,
"name": format!("Петр{}", i),
"surname": format!("Петров{}", i),
"middlename": format!("Петрович{}", i),
"phone": i.to_string(),
"rents": [],
"cars": [{
"_id": car_id,
"brand": format!("Лада{}", i),
"model": format!("Гранта{}", i),
"price": i as f64,
"car_station_id": ObjectId::parse_str("6466ca4c26b3b0b31d9a45bc").unwrap()
}]
}, None).await.unwrap();
}
return Ok((Utc::now().naive_local() - start_time).num_microseconds().unwrap())
}
}

View File

@ -0,0 +1,221 @@
use chrono::{Utc, Months};
use mongodb::Database;
use mongodb::bson::oid::ObjectId;
use mongodb::bson::{doc, Document, Bson};
use futures::stream::{TryStreamExt, StreamExt};
use mongodb::options::{FindOptions, AggregateOptions};
use rust_decimal::Decimal;
use rust_decimal::prelude::{ToPrimitive, FromPrimitive};
use std::default;
use std::sync::Arc;
use crate::models::car::*;
use crate::storages::traits::*;
use async_trait::async_trait;
use super::rent::MongoRentRepository;
pub struct MongoCarRepository {
pub database: Arc<Database>
}
#[async_trait]
impl CarRepository for MongoCarRepository {
async fn create(&self, car: BindingCar) -> Result<Car, String> {
let collection = self.database.collection::<Document>("clients");
let document = doc! {
"_id": ObjectId::parse_str(car.owner_id.clone()).unwrap()
};
let update = doc! {
"$push": {
"cars": doc! {
"_id": ObjectId::new(),
"brand": car.brand.clone(),
"model": car.model.clone(),
"price": car.price.to_f64().unwrap(),
"car_station_id": ObjectId::parse_str(car.car_station_id.to_string()).unwrap()
}
}
};
let result = collection.update_one(document, update, None).await;
match result {
Ok(result) => {
let brand = car.brand.clone();
let model = car.model.clone();
let price = car.price;
let car_station_id = car.car_station_id.clone();
let owner_id = car.owner_id.clone();
let car = Car { id: "".to_string(), brand, model, car_station_id, price, owner_id};
Ok(car)
},
Err(e) => Err(e.to_string())
}
}
async fn read(&self, id: String) -> Result<Car, String> {
match self.read_all().await.unwrap().into_iter().filter(|c| c.id.starts_with(&id)).next() {
Some(car) => Ok(car),
None => Err("Car not found".to_string())
}
}
async fn read_all(&self) -> Result<Vec<Car>, String> {
let collection = self.database.collection::<Document>("clients");
let mut cursor = collection.find(doc! {"cars": { "$exists": true }}, None).await.map_err(|e| e.to_string())?;
let mut cars = Vec::new();
while let Some(result) = cursor.next().await {
match result {
Ok(document) => {
for car_document in document.get_array("cars").unwrap() {
let car = car_document.as_document().unwrap();
let id = car.get("_id").unwrap().as_object_id().unwrap().to_hex();
let brand = car.get_str("brand").unwrap().to_string();
let model = car.get_str("model").unwrap().to_string();
let price = Decimal::from_f64(car.get_f64("price").unwrap()).unwrap();
let car_station_id = car.get_object_id("car_station_id").unwrap().to_hex();
let owner_id = document.get_object_id("_id").unwrap().to_hex();
let car = Car { id, brand, model, car_station_id, price, owner_id};
cars.push(car);
}
},
Err(e) => return Err(e.to_string())
}
}
Ok(cars)
}
async fn update(&self, id: String, car: BindingCar) -> Result<Car, String> {
let collection = self.database.collection::<Document>("clients");
let mut cursor = collection.find(None, None).await.map_err(|e| e.to_string())?;
while let Some(result) = cursor.next().await {
match result {
Ok(document) => {
for (i, car_document) in document.get_array("cars").unwrap().into_iter().enumerate() {
if car_document.as_document().unwrap().get_object_id("_id").unwrap().to_hex().starts_with(&id) {
collection.update_one(doc! {
"_id": ObjectId::parse_str(document.get_str("_id").unwrap()).unwrap()
}, doc! {
"$set": doc! {
format!("cars.${}.brand", i): car.brand.clone(),
format!("cars.${}.model", i): car.model.clone(),
format!("cars.${}.price", i): car.price.to_f64().unwrap(),
format!("cars.${}.car_station_id", i): ObjectId::parse_str(car.car_station_id.clone()).unwrap(),
}
}, None).await.unwrap();
return Ok(Car {..Default::default()})
}
}
},
Err(e) => return Err(e.to_string())
}
}
Err("Car not found".to_string())
}
async fn delete(&self, id: String) -> Result<(), String> {
let collection = self.database.collection::<Document>("clients");
let document = doc! {
"cars._id": ObjectId::parse_str(&id).unwrap()
};
let update = doc! {
"$pull": {
"cars": {
"_id": ObjectId::parse_str(&id).unwrap()
}
}
};
let result = collection.update_one(document, update, None).await;
match result {
Ok(result) => {
if result.modified_count == 0 {
Err("Car not found".to_string())
} else {
Ok(())
}
},
Err(e) => Err(e.to_string())
}
}
async fn get_report(&self) -> Result<Vec<Report>, String> {
let mut reports = Vec::new();
let rents = (MongoRentRepository {database: Arc::clone(&self.database)}).read_all().await.unwrap();
let cars = self.read_all().await.unwrap();
for car in cars {
let mut times = 0;
let mut sum = Decimal::from_f64(0.0).unwrap();
for rent in rents.iter() {
if rent.car_id.starts_with(&car.id) && rent.time_amount.is_some() {
times += 1;
sum += car.price * Decimal::from(rent.time_amount.unwrap());
}
}
reports.push(Report {car_id: car.id.clone(), brand: car.brand.clone(), model: car.model.clone(), times, income: sum})
}
// let pipeline = vec![
// doc! {
// "$match": {
// "rents.start_time": {
// "$gte": Utc::now().checked_sub_months(Months::new(1)).unwrap(),
// "$lt": Utc::now().checked_add_months(Months::new(1)).unwrap()
// }
// }
// },
// doc! {
// "$lookup": {
// "from": "cars",
// "localField": "rents.car_id",
// "foreignField": "_id",
// "as": "car"
// }
// },
// doc! {
// "$unwind": "$car"
// },
// doc! {
// "$group": {
// "_id": "$rents.car_id",
// "brand": { "$first": "$car.brand" },
// "model": { "$first": "$car.model" },
// "times": { "$sum": 1 },
// "income": { "$sum": { "$multiply": [ "$car.price", "$rents.time_amount" ] } }
// }
// },
// doc! {
// "$project": {
// "_id": 0,
// "car_id": { "$toString": "$_id" },
// "brand": 1,
// "model": 1,
// "times": 1,
// "income": { "$round": [ "$income", 2 ] }
// }
// }
// ];
// let collection = self.database.collection::<Document>("clients");
// let options = AggregateOptions::builder().build();
// let cursor = collection.aggregate(pipeline, options).await.unwrap();
// let reports = cursor
// .map(|doc| {
// let doc = doc.unwrap();
// let car_id = doc.get_str("car_id").unwrap().to_owned();
// let brand = doc.get_str("brand").unwrap().to_owned();
// let model = doc.get_str("model").unwrap().to_owned();
// let times = doc.get_i64("times").unwrap();
// let income = Decimal::from_f64(doc.get_f64("income").unwrap()).unwrap();
// Report { car_id, brand, model, times, income }
// })
// .collect::<Vec<_>>()
// .await;
Ok(reports)
}
}

View File

@ -0,0 +1,101 @@
use mongodb::Database;
use mongodb::bson::oid::ObjectId;
use mongodb::bson::{doc, Document, Bson};
use futures::stream::{TryStreamExt, StreamExt};
use mongodb::options::FindOptions;
use std::sync::Arc;
use crate::models::car_station::*;
use crate::storages::traits::CarStationRepository;
use async_trait::async_trait;
pub struct MongoCarStationRepository {
pub database: Arc<Database>
}
#[async_trait]
impl CarStationRepository for MongoCarStationRepository {
async fn create(&self, car_station: BindingCarStation) -> Result<CarStation, String> {
let collection = self.database.collection::<Document>("car_stations");
let document = doc! {
"address": car_station.address.clone()
};
let result = collection.insert_one(document, None).await;
match result {
Ok(result) => {
let id = result.inserted_id.as_object_id().unwrap().to_hex();
let car_station = CarStation { id, address: car_station.address };
Ok(car_station)
},
Err(e) => Err(e.to_string())
}
}
async fn read(&self, id: String) -> Result<CarStation, String> {
let collection = self.database.collection::<Document>("car_stations");
let filter = doc! {
"_id": ObjectId::parse_str(&id).unwrap()
};
let result = collection.find_one(filter, None).await;
match result {
Ok(Some(document)) => {
let id = document.get_object_id("_id").unwrap().to_hex();
let address = document.get_str("address").unwrap().to_string();
let car_station = CarStation { id, address };
Ok(car_station)
},
Ok(None) => Err("Car station not found".to_string()),
Err(e) => Err(e.to_string())
}
}
async fn read_all(&self) -> Result<Vec<CarStation>, String> {
let collection = self.database.collection::<Document>("car_stations");
let mut cursor = collection.find(None, None).await.map_err(|e| e.to_string())?;
let mut car_stations = Vec::new();
while let Some(result) = cursor.next().await {
match result {
Ok(document) => {
let id = document.get_object_id("_id").unwrap().to_hex();
let address = document.get_str("address").unwrap().to_string();
let car_station = CarStation { id, address };
car_stations.push(car_station);
},
Err(e) => return Err(e.to_string())
}
}
Ok(car_stations)
}
async fn update(&self, id: String, car_station: BindingCarStation) -> Result<CarStation, String> {
let collection = self.database.collection::<Document>("car_stations");
let filter = doc! {
"_id": ObjectId::parse_str(&id).unwrap()
};
let update = doc! {
"$set": {
"address": car_station.address.clone()
}
};
let result = collection.update_one(filter, update, None).await;
match result {
Ok(_) => {
let car_station = CarStation { id, address: car_station.address };
Ok(car_station)
},
Err(e) => Err(e.to_string())
}
}
async fn delete(&self, id: String) -> Result<(), String> {
let collection = self.database.collection::<Document>("car_stations");
let filter = doc! {
"_id": ObjectId::parse_str(&id).unwrap()
};
let result = collection.delete_one(filter, None).await;
match result {
Ok(_) => Ok(()),
Err(e) => Err(e.to_string())
}
}
}

View File

@ -0,0 +1,117 @@
use mongodb::Database;
use mongodb::bson::oid::ObjectId;
use mongodb::bson::{doc, Document, Bson};
use futures::stream::{TryStreamExt, StreamExt};
use mongodb::options::{FindOptions, AggregateOptions};
use rust_decimal::Decimal;
use rust_decimal::prelude::{ToPrimitive, FromPrimitive};
use std::default;
use std::sync::Arc;
use crate::models::client::*;
use crate::storages::traits::ClientRepository;
use async_trait::async_trait;
pub struct MongoClientRepository {
pub database: Arc<Database>
}
#[async_trait]
impl ClientRepository for MongoClientRepository {
async fn create(&self, client: BindingClient) -> Result<Client, String> {
let collection = self.database.collection::<Document>("clients");
let document = doc! {
"name": client.name.clone(),
"surname": client.surname.clone(),
"middlename": client.middlename.clone(),
"phone": client.phone.clone(),
"rents": Bson::Array(Vec::<Bson>::new())
};
let result = collection.insert_one(document, None).await;
match result {
Ok(result) => {
let id = result.inserted_id.as_object_id().unwrap().to_hex();
let client = Client { id, name: client.name, surname: client.surname, middlename: client.middlename, phone: client.phone };
Ok(client)
},
Err(e) => Err(e.to_string())
}
}
async fn read(&self, id: String) -> Result<Client, String> {
let collection = self.database.collection::<Document>("clients");
let filter = doc! {
"_id": ObjectId::parse_str(&id).unwrap()
};
let result = collection.find_one(filter, None).await;
match result {
Ok(Some(document)) => {
let id = document.get_object_id("_id").unwrap().to_hex();
let name = document.get_str("name").unwrap().to_string();
let surname = document.get_str("surname").unwrap().to_string();
let middlename = document.get_str("middlename").map(|s| s.to_string());
let phone = document.get_str("phone").unwrap().to_string();
let client = Client { id, name, surname, middlename: Some(middlename.unwrap()), phone };
Ok(client)
},
Ok(None) => Err("Client not found".to_string()),
Err(e) => Err(e.to_string())
}
}
async fn read_all(&self) -> Result<Vec<Client>, String> {
let collection = self.database.collection::<Document>("clients");
let mut cursor = collection.find(None, None).await.map_err(|e| e.to_string())?;
let mut clients = Vec::new();
while let Some(result) = cursor.next().await {
match result {
Ok(document) => {
let id = document.get_object_id("_id").unwrap().to_hex();
let name = document.get_str("name").unwrap().to_string();
let surname = document.get_str("surname").unwrap().to_string();
let middlename = document.get_str("middlename").map(|s| s.to_string());
let phone = document.get_str("phone").unwrap().to_string();
let client = Client { id, name, surname, middlename: Some(middlename.unwrap()), phone };
clients.push(client);
},
Err(e) => return Err(e.to_string())
}
}
Ok(clients)
}
async fn update(&self, id: String, client: BindingClient) -> Result<Client, String> {
let collection = self.database.collection::<Document>("clients");
let filter = doc! {
"_id": ObjectId::parse_str(&id).unwrap()
};
let update = doc! {
"$set": {
"name": client.name.clone(),
"surname": client.surname.clone(),
"middlename": client.middlename.clone(),
"phone": client.phone.clone()
}
};
let result = collection.update_one(filter, update, None).await;
match result {
Ok(_) => {
let client = Client { id, name: client.name, surname: client.surname, middlename: client.middlename, phone: client.phone };
Ok(client)
},
Err(e) => Err(e.to_string())
}
}
async fn delete(&self, id: String) -> Result<(), String> {
let collection = self.database.collection::<Document>("clients");
let filter = doc! {
"_id": ObjectId::parse_str(&id).unwrap()
};
let result = collection.delete_one(filter, None).await;
match result {
Ok(_) => Ok(()),
Err(e) => Err(e.to_string())
}
}
}

View File

@ -0,0 +1,7 @@
pub mod car_station;
pub mod administrator;
pub mod car;
pub mod client;
pub mod owner;
pub mod rent;
pub mod benchmark;

View File

@ -0,0 +1,129 @@
use mongodb::Database;
use mongodb::bson::oid::ObjectId;
use mongodb::bson::{doc, Document, Bson};
use futures::stream::{TryStreamExt, StreamExt};
use mongodb::options::{FindOptions, AggregateOptions};
use rust_decimal::Decimal;
use rust_decimal::prelude::{ToPrimitive, FromPrimitive};
use std::default;
use std::sync::Arc;
use crate::models::client::*;
use crate::storages::traits::OwnerRepository;
use async_trait::async_trait;
pub struct MongoOwnerRepository {
pub database: Arc<Database>
}
#[async_trait]
impl OwnerRepository for MongoOwnerRepository {
async fn create(&self, owner: BindingClient) -> Result<Client, String> {
let collection = self.database.collection::<Document>("clients");
let document = doc! {
"name": owner.name.clone(),
"surname": owner.surname.clone(),
"middlename": owner.middlename.clone(),
"phone": owner.phone.clone(),
"cars": Bson::Array(Vec::<Bson>::new()),
"rents": Bson::Array(Vec::<Bson>::new())
};
let result = collection.insert_one(document, None).await;
match result {
Ok(result) => {
let id = result.inserted_id.as_object_id().unwrap().to_hex();
let owner = Client { id, name: owner.name, surname: owner.surname, middlename: owner.middlename, phone: owner.phone };
Ok(owner)
},
Err(e) => Err(e.to_string())
}
}
async fn read(&self, id: String) -> Result<Client, String> {
let collection = self.database.collection::<Document>("clients");
let filter = doc! {
"_id": ObjectId::parse_str(&id).unwrap()
};
let result = collection.find_one(filter, None).await;
match result {
Ok(Some(document)) => {
let id = document.get_object_id("_id").unwrap().to_hex();
let name = document.get_str("name").unwrap().to_string();
let surname = document.get_str("surname").unwrap().to_string();
let middlename = document.get_str("middlename").map(|s| s.to_string());
let phone = document.get_str("phone").unwrap().to_string();
let owner = Client { id, name, surname, middlename: Some(middlename.unwrap()), phone };
Ok(owner)
},
Ok(None) => Err("Owner not found".to_string()),
Err(e) => Err(e.to_string())
}
}
async fn read_all(&self) -> Result<Vec<Client>, String> {
let collection = self.database.collection::<Document>("clients");
let mut cursor = collection.find(doc! {"cars": { "$exists": true }}, None).await.map_err(|e| e.to_string())?;
let mut owners = Vec::new();
while let Some(result) = cursor.next().await {
match result {
Ok(document) => {
let id = document.get_object_id("_id").unwrap().to_hex();
let name = document.get_str("name").unwrap().to_string();
let surname = document.get_str("surname").unwrap().to_string();
let middlename = document.get_str("middlename").map(|s| s.to_string());
let phone = document.get_str("phone").unwrap().to_string();
let owner = Client { id, name, surname, middlename: Some(middlename.unwrap()), phone };
owners.push(owner);
},
Err(e) => return Err(e.to_string())
}
}
Ok(owners)
}
async fn update(&self, id: String, owner: BindingClient) -> Result<Client, String> {
let collection = self.database.collection::<Document>("clients");
let filter = doc! {
"_id": ObjectId::parse_str(&id).unwrap()
};
let update = doc! {
"$set": {
"name": owner.name.clone(),
"surname": owner.surname.clone(),
"middlename": owner.middlename.clone(),
"phone": owner.phone.clone()
}
};
let result = collection.update_one(filter, update, None).await;
match result {
Ok(result) => {
if result.modified_count == 1 {
let owner = self.read(id).await?;
Ok(owner)
} else {
Err("Owner not found".to_string())
}
},
Err(e) => Err(e.to_string())
}
}
async fn delete(&self, id: String) -> Result<(), String> {
let collection = self.database.collection::<Document>("owners");
let filter = doc! {
"_id": ObjectId::parse_str(&id).unwrap()
};
let result = collection.delete_one(filter, None).await;
match result {
Ok(result) => {
if result.deleted_count == 1 {
Ok(())
} else {
Err("Owner not found".to_string())
}
},
Err(e) => Err(e.to_string())
}
}
}

View File

@ -0,0 +1,153 @@
use chrono::{NaiveDateTime, Utc};
use mongodb::Database;
use mongodb::bson::oid::ObjectId;
use mongodb::bson::{doc, Document, Bson};
use futures::stream::{TryStreamExt, StreamExt};
use mongodb::options::{FindOptions, AggregateOptions, FindOneOptions};
use rust_decimal::Decimal;
use rust_decimal::prelude::{ToPrimitive, FromPrimitive};
use std::default;
use std::sync::Arc;
use crate::models::rent::*;
use crate::storages::traits::RentRepository;
use async_trait::async_trait;
pub struct MongoRentRepository {
pub database: Arc<Database>
}
#[async_trait]
impl RentRepository for MongoRentRepository {
async fn create(&self, rent: BindingRent) -> Result<Rent, String> {
let collection = self.database.collection::<Document>("clients");
let start_time = chrono::Utc::now();
let filter = doc! {
"_id": ObjectId::parse_str(&rent.client_id).unwrap()
};
let update = doc! {
"$push": {
"rents": {
"_id": ObjectId::new(),
"start_time": start_time,
"time_amount": Bson::Null,
"car_id": ObjectId::parse_str(&rent.car_id).unwrap()
}
}
};
let result = collection.update_one(filter, update, None).await;
match result {
Ok(result) => {
if result.modified_count == 1 {
Ok(Rent {id: "".to_string(), start_time: Default::default(), time_amount: None, car_id: "".to_string(), client_id: "".to_string()})
} else {
Err("Rent not found".to_string())
}
},
Err(e) => Err(e.to_string())
}
}
async fn read(&self, id: String) -> Result<Rent, String> {
let collection = self.database.collection::<Document>("clients");
let filter = doc! {
"rents._id": ObjectId::parse_str(&id).unwrap()
};
let projection = doc! {
"rents.$": 1
};
let options = FindOneOptions::builder().projection(projection).build();
let result = collection.find_one(filter, options).await;
match result {
Ok(Some(document)) => {
let rent_document = document.get_array("rents").unwrap().get(0).unwrap().as_document().unwrap();
let client_id = document.get_object_id("_id").unwrap().to_hex();
let id = rent_document.get_object_id("_id").unwrap().to_hex();
let start_time = rent_document.get_datetime("start_time").unwrap();
let time_amount = rent_document.get_i32("time_amount").ok();
let car_id = rent_document.get_object_id("car_id").unwrap().to_hex();
let rent = Rent { id, start_time: NaiveDateTime::from_timestamp_millis(start_time.timestamp_millis()).unwrap(), time_amount, client_id, car_id };
Ok(rent)
},
Ok(None) => Err("Rent not found".to_string()),
Err(e) => Err(e.to_string())
}
}
async fn read_all(&self) -> Result<Vec<Rent>, String> {
let collection = self.database.collection::<Document>("clients");
let result = collection.find(None, None).await;
match result {
Ok(mut cursor) => {
let mut rents = Vec::new();
while let Some(document) = cursor.next().await {
let another = document.clone().unwrap();
let rents_array = another.get_array("rents").unwrap();
let client_id = document.unwrap().get_object_id("_id").unwrap().to_hex();
for rent_document in rents_array.iter().map(|x| x.as_document().unwrap()) {
let id = rent_document.get_object_id("_id").unwrap().to_hex();
let start_time = rent_document.get_datetime("start_time").unwrap();
let time_amount = rent_document.get_i32("time_amount").ok();
let car_id = rent_document.get_object_id("car_id").unwrap().to_hex();
let rent = Rent { id, start_time: NaiveDateTime::from_timestamp_millis(start_time.timestamp_millis()).unwrap(), time_amount, client_id: client_id.clone(), car_id };
rents.push(rent);
}
}
Ok(rents)
},
Err(e) => Err(e.to_string())
}
}
async fn update(&self, id: String, rent: BindingRent) -> Result<Rent, String> {
let collection = self.database.collection::<Document>("clients");
let filter = doc! {
"_id": ObjectId::parse_str(&rent.client_id).unwrap(),
"rents._id": ObjectId::parse_str(&id).unwrap()
};
let update = doc! {
"$set": {
"rents.$.time_amount": rent.time_amount
}
};
let result = collection.update_one(filter, update, None).await;
match result {
Ok(success) => self.read(success.upserted_id.unwrap().as_object_id().unwrap().to_hex()).await,
Err(e) => Err(e.to_string())
}
}
async fn delete(&self, id: String) -> Result<(), String> {
let collection = self.database.collection::<Document>("clients");
let rent = self.read(id.clone()).await.unwrap();
let filter = doc! {
"_id": ObjectId::parse_str(rent.client_id.clone()).unwrap(),
"rents._id": ObjectId::parse_str(id.clone()).unwrap()
};
let result = collection.update_one(filter, doc! {"$pull": {"rents": {"_id": ObjectId::parse_str(id.clone()).unwrap()}}}, None).await;
match result {
Ok(_) => Ok(()),
Err(e) => Err(e.to_string())
}
}
async fn end_rent(&self, id: String) -> Result<(), String> {
let rent = self.read(id.clone()).await?;
if rent.time_amount.is_some() {
return Err("Rent is already ended".to_owned());
}
let time_amount = (Utc::now().naive_local() - rent.start_time).num_minutes() as i32;
let collection = self.database.collection::<Document>("clients");
let filter = doc! {"_id": ObjectId::parse_str(&rent.client_id).unwrap(), "rents._id": ObjectId::parse_str(&rent.id).unwrap()};
let update = doc! {"$set": {"rents.$.time_amount": time_amount}};
let result = collection.update_one(filter, update, None).await;
match result {
Ok(_) => Ok(()),
Err(e) => Err(e.to_string())
}
}
}