From ac94f3adff35e7ba091066f3122915cfa4ca5ae8 Mon Sep 17 00:00:00 2001 From: Clark Alesna Date: Tue, 16 Apr 2024 08:38:49 +0800 Subject: [PATCH] feat(api): integrate graphql layer with backend db (#35) --- .gitignore | 8 +- Cargo.lock | 631 ++++++++++++++++++++++++++++++++++++++- backend/Cargo.toml | 4 +- backend/docs/example.sql | 21 ++ backend/docs/table.sql | 15 + backend/src/main.rs | 373 ++++++++++++++++++++++- 6 files changed, 1039 insertions(+), 13 deletions(-) create mode 100644 backend/docs/example.sql create mode 100644 backend/docs/table.sql diff --git a/.gitignore b/.gitignore index bdbe60a..397a47c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,10 @@ build/ src/docs/ # Cargo temp files -target \ No newline at end of file +target + +# .env files +**/.env + +# sqlx +**/.sqlx \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 626341c..d84b6c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -236,7 +236,9 @@ version = "0.1.0" dependencies = [ "async-graphql", "async-graphql-rocket", + "dotenv", "rocket", + "sqlx", ] [[package]] @@ -424,6 +426,15 @@ dependencies = [ "syn 2.0.58", ] +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + [[package]] name = "atomic" version = "0.5.3" @@ -472,6 +483,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bevy" version = "0.13.2" @@ -1593,6 +1610,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "const_panic" version = "0.2.8" @@ -1723,6 +1746,21 @@ dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "crc32fast" version = "1.4.0" @@ -1741,6 +1779,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.19" @@ -1821,6 +1868,17 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + [[package]] name = "deranged" version = "0.3.11" @@ -1881,7 +1939,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -1899,6 +1959,18 @@ dependencies = [ "libloading 0.8.3", ] +[[package]] +name = "dotenv" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + [[package]] name = "downcast-rs" version = "1.2.0" @@ -1910,6 +1982,9 @@ name = "either" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +dependencies = [ + "serde", +] [[package]] name = "encase" @@ -1977,6 +2052,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + [[package]] name = "euclid" version = "0.22.9" @@ -2072,6 +2158,12 @@ dependencies = [ "version_check", ] +[[package]] +name = "finl_unicode" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" + [[package]] name = "fixedbitset" version = "0.4.2" @@ -2088,6 +2180,17 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "futures-core", + "futures-sink", + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -2160,6 +2263,28 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + [[package]] name = "futures-io" version = "0.3.30" @@ -2513,6 +2638,15 @@ dependencies = [ "serde", ] +[[package]] +name = "hashlink" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" +dependencies = [ + "hashbrown", +] + [[package]] name = "hassle-rs" version = "0.11.0" @@ -2533,6 +2667,9 @@ name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +dependencies = [ + "unicode-segmentation", +] [[package]] name = "hermit-abi" @@ -2540,6 +2677,12 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hexasphere" version = "10.0.0" @@ -2556,6 +2699,33 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + [[package]] name = "http" version = "0.2.12" @@ -2642,6 +2812,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "image" version = "0.24.9" @@ -2805,6 +2985,9 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "lazycell" @@ -2849,6 +3032,12 @@ dependencies = [ "windows-targets 0.52.4", ] +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + [[package]] name = "libredox" version = "0.0.2" @@ -2860,6 +3049,17 @@ dependencies = [ "redox_syscall 0.4.1", ] +[[package]] +name = "libsqlite3-sys" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4e226dcd58b4be396f7bd3c20da8fdee2911400705297ba7d2d7cc2c30f716" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + [[package]] name = "libudev-sys" version = "0.1.4" @@ -2934,6 +3134,16 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + [[package]] name = "memchr" version = "2.7.2" @@ -3002,7 +3212,7 @@ dependencies = [ "log", "memchr", "mime", - "spin", + "spin 0.9.8", "tokio", "tokio-util", "version_check", @@ -3022,7 +3232,7 @@ dependencies = [ "log", "memchr", "mime", - "spin", + "spin 0.9.8", "version_check", ] @@ -3144,6 +3354,23 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.1.0" @@ -3161,6 +3388,26 @@ dependencies = [ "syn 2.0.58", ] +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.18" @@ -3168,6 +3415,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -3397,6 +3645,15 @@ dependencies = [ "syn 2.0.58", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -3481,6 +3738,27 @@ dependencies = [ "futures-io", ] +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.30" @@ -3865,6 +4143,26 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -3986,6 +4284,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.8" @@ -4021,6 +4330,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -4073,11 +4392,20 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spirv" @@ -4088,6 +4416,221 @@ dependencies = [ "bitflags 2.5.0", ] +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "sqlformat" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce81b7bd7c4493975347ef60d8c7e8b742d4694f4c49f93e0a12ea263938176c" +dependencies = [ + "itertools", + "nom", + "unicode_categories", +] + +[[package]] +name = "sqlx" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6" +dependencies = [ + "ahash", + "atoi", + "byteorder", + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener 2.5.3", + "futures-channel", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashlink", + "hex", + "indexmap", + "log", + "memchr", + "once_cell", + "paste", + "percent-encoding", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlformat", + "thiserror", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 1.0.109", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8" +dependencies = [ + "dotenvy", + "either", + "heck", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 1.0.109", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418" +dependencies = [ + "atoi", + "base64", + "bitflags 2.5.0", + "byteorder", + "bytes", + "crc", + "digest", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand", + "rsa", + "serde", + "sha1", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e" +dependencies = [ + "atoi", + "base64", + "bitflags 2.5.0", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "hex", + "hkdf", + "hmac", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand", + "serde", + "serde_json", + "sha2", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "sqlx-core", + "tracing", + "url", + "urlencoding", +] + [[package]] name = "stable-pattern" version = "0.1.0" @@ -4118,6 +4661,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7beae5182595e9a8b683fa98c4317f956c9a2dec3b9716990d20023cc60c766" +[[package]] +name = "stringprep" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6" +dependencies = [ + "finl_unicode", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "strsim" version = "0.10.0" @@ -4146,6 +4700,12 @@ dependencies = [ "syn 2.0.58", ] +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "svg_fmt" version = "0.4.2" @@ -4420,6 +4980,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -4550,12 +5111,27 @@ dependencies = [ "version_check", ] +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-segmentation" version = "1.11.0" @@ -4574,6 +5150,29 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "unicode_categories" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e" + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "uuid" version = "1.8.0" @@ -4590,6 +5189,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "vec_map" version = "0.8.2" @@ -4639,6 +5244,12 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + [[package]] name = "wasm-bindgen" version = "0.2.92" @@ -4832,6 +5443,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "whoami" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +dependencies = [ + "redox_syscall 0.4.1", + "wasite", +] + [[package]] name = "widestring" version = "1.0.2" @@ -5307,3 +5928,9 @@ dependencies = [ "quote", "syn 2.0.58", ] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/backend/Cargo.toml b/backend/Cargo.toml index 70a4351..673619c 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -8,4 +8,6 @@ edition = "2021" [dependencies] rocket = "0.5.0" async-graphql = "7.0.3" -async-graphql-rocket = "7.0.3" \ No newline at end of file +async-graphql-rocket = "7.0.3" +sqlx = { version = "0.7", features = [ "runtime-tokio", "postgres" ] } +dotenv = "0.15" \ No newline at end of file diff --git a/backend/docs/example.sql b/backend/docs/example.sql new file mode 100644 index 0000000..f1ca1f9 --- /dev/null +++ b/backend/docs/example.sql @@ -0,0 +1,21 @@ +-- Insert the central RewardPot +INSERT INTO MapObjects (id, type, positionX, positionY, totalRewards) +VALUES ('rewardpot01', 'RewardPot', 0, 0, 1000.0); + +-- Ships +INSERT INTO MapObjects (id, type, positionX, positionY, fuel, shipyardPolicy, shipTokenName, pilotTokenName) +VALUES ('ship01', 'Ship', 1, 0, 100, 'policy01', 'tokenName01', 'pilotName01'), + ('ship02', 'Ship', -1, 0, 120, 'policy02', 'tokenName02', 'pilotName02'), + ('ship03', 'Ship', 0, 1, 110, 'policy03', 'tokenName03', 'pilotName03'), + ('ship04', 'Ship', 0, -1, 130, 'policy04', 'tokenName04', 'pilotName04'), + ('ship05', 'Ship', 2, 1, 140, 'policy05', 'tokenName05', 'pilotName05'), + ('ship06', 'Ship', -2, -1, 150, 'policy06', 'tokenName06', 'pilotName06'); + +-- FuelPellets +INSERT INTO MapObjects (id, type, positionX, positionY, fuel) +VALUES ('fuel01', 'FuelPellet', 1, 1, 50), + ('fuel02', 'FuelPellet', 2, 0, 60), + ('fuel03', 'FuelPellet', -1, 2, 70), + ('fuel04', 'FuelPellet', -2, -2, 80), + ('fuel05', 'FuelPellet', 3, -1, 90), + ('fuel06', 'FuelPellet', -3, 1, 100); diff --git a/backend/docs/table.sql b/backend/docs/table.sql new file mode 100644 index 0000000..daf285c --- /dev/null +++ b/backend/docs/table.sql @@ -0,0 +1,15 @@ +CREATE TABLE MapObjects ( + id VARCHAR(255) PRIMARY KEY, -- Utxo (Hash#Index) as a unique identifier + class VARCHAR(50) NOT NULL, -- 'Ship', 'FuelPellet', 'RewardPot' + positionX INT NOT NULL, -- X coordinate + positionY INT NOT NULL, -- Y coordinate + fuel INT, -- Fuel amount, only relevant for ships and fuel pellets + shipyardPolicy VARCHAR(255), -- Policy ID relevant for all types + shipTokenName VARCHAR(255), -- Only relevant for ships + pilotTokenName VARCHAR(255), -- Only relevant for ships + totalRewards INT -- Only relevant for the reward pot +); + +-- Indexes for performance optimization +CREATE INDEX idx_mapobjects_type ON MapObjects(type); +CREATE INDEX idx_mapobjects_position ON MapObjects(positionX, positionY); \ No newline at end of file diff --git a/backend/src/main.rs b/backend/src/main.rs index a4be5b3..0e5dc6b 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -1,20 +1,358 @@ +use dotenv::dotenv; +use std::env; use std::ops::Deref; +use std::vec; -use async_graphql::{Context, EmptyMutation, EmptySubscription, Schema}; +use async_graphql::*; use async_graphql_rocket::GraphQLRequest as Request; use async_graphql_rocket::GraphQLResponse as Response; use rocket::State; struct QueryRoot; -#[async_graphql::Object] +#[derive(Clone, SimpleObject)] +pub struct Ship { + id: ID, + fuel: i32, + position: Position, + shipyard_policy: PolicyId, + ship_token_name: AssetName, + pilot_token_name: AssetName, + class: String, +} + +#[derive(Clone, SimpleObject)] +pub struct FuelPellet { + id: ID, + fuel: i32, + position: Position, + shipyard_policy: PolicyId, + class: String, +} + +#[derive(Clone, SimpleObject)] +pub struct RewardPot { + id: ID, + position: Position, + total_rewards: i32, + class: String, +} + +#[derive(Clone, SimpleObject)] +pub struct AsteriaState { + ship_counter: i32, + shipyard_policy: PolicyId, +} + +#[derive(Clone, SimpleObject)] +pub struct Position { + x: i32, + y: i32, +} + +#[derive(Clone, SimpleObject)] +pub struct PolicyId { + id: ID, +} + +#[derive(Clone, SimpleObject)] +pub struct AssetName { + name: String, +} + +#[derive(InputObject)] +pub struct AssetNameInput { + name: String, +} + +#[derive(InputObject, Clone, Copy)] +pub struct PositionInput { + x: i32, + y: i32, +} + +#[derive(SimpleObject, Clone)] +pub struct ShipAction { + action_id: ID, + ship_id: ID, + action_type: ShipActionType, + position: Position, + timestamp: String, +} + +#[derive(Enum, Copy, Clone, Eq, PartialEq)] +pub enum ShipActionType { + Move, + GatherFuel, +} + +#[derive(Union)] +pub enum MapObject { + Ship(Ship), + FuelPellet(FuelPellet), + RewardPot(RewardPot), +} + +#[derive(Interface)] +#[graphql( + field(name = "position", ty = "&Position"), + field(name = "class", ty = "String") +)] + +pub enum PositionalInterface { + Ship(Ship), + FuelPellet(FuelPellet), + RewardPot(RewardPot), +} + +struct MapObjectRecord { + id: String, + fuel: Option, + position_x: i32, + position_y: i32, + policy_id: Option, + token_name: Option, + pilot_name: Option, + class: Option, + total_rewards: Option, +} + +#[Object] impl QueryRoot { - async fn hello(&self, _ctx: &Context<'_>) -> String { - "GraphQL says hello!".to_string() + async fn ship(&self, _ctx: &Context<'_>, ship_token_name: AssetNameInput) -> Ship { + Ship { + id: ID::from("ship-1234"), + fuel: 100, + position: Position { x: 10, y: 20 }, + shipyard_policy: PolicyId { + id: ID::from("policy-5678"), + }, + ship_token_name: AssetName { + name: ship_token_name.name.clone(), + }, + pilot_token_name: AssetName { + name: "PilotOne".to_string(), + }, + class: "Ship".to_string(), + } + } + + async fn ships( + &self, + _ctx: &Context<'_>, + limit: Option, + offset: Option, + ) -> Vec { + let mut ships = Vec::new(); + let num_ships = limit.unwrap_or(10); + let start = offset.unwrap_or(0) as usize; + + // Generate fake data for ships + for i in start..(start + num_ships as usize) { + ships.push(Ship { + id: ID::from(format!("ship-{}", i)), + fuel: 100, + position: Position { + x: i as i32 * 10, + y: i as i32 * 20, + }, + shipyard_policy: PolicyId { + id: ID::from(format!("policy-{}", i)), + }, + ship_token_name: AssetName { + name: format!("Explorer-{}", i), + }, + pilot_token_name: AssetName { + name: format!("Pilot-{}", i), + }, + class: "Battleship".to_string(), + }); + } + + ships + } + + async fn fuel_pellets( + &self, + _ctx: &Context<'_>, + limit: Option, + offset: Option, + ) -> Vec { + let mut fuel_pellets = Vec::new(); + let num_pellets = limit.unwrap_or(10); + let start = offset.unwrap_or(0) as usize; + + // Generate fake data for fuel pellets + for i in start..(start + num_pellets as usize) { + fuel_pellets.push(FuelPellet { + id: ID::from(format!("pellet-{}", i)), + fuel: 100, + position: Position { + x: i as i32 * 5, + y: i as i32 * 10, + }, + shipyard_policy: PolicyId { + id: ID::from(format!("policy-{}", i)), + }, + class: "Standard".to_string(), + }); + } + + fuel_pellets + } + + async fn asteria_state(&self, _ctx: &Context<'_>) -> AsteriaState { + AsteriaState { + ship_counter: 123, + shipyard_policy: PolicyId { + id: ID::from("some-policy-id"), + }, + } + } + + async fn reward_pot(&self, _ctx: &Context<'_>) -> RewardPot { + RewardPot { + id: ID::from("reward-123"), + position: Position { x: 100, y: 200 }, + total_rewards: 5000, + class: "Standard".to_string(), + } + } + + async fn objects_in_radius( + &self, + ctx: &Context<'_>, + center: PositionInput, + radius: i32, + ) -> Result, Error> { + // Access the connection pool from the GraphQL context + let pool = ctx + .data::() + .map_err(|e| Error::new(e.message))?; + + // Query to select map objects within a radius using Manhattan distance + let fetched_objects = sqlx::query_as!(MapObjectRecord, + "SELECT id, fuel, positionX as position_x, positionY as position_y, shipyardPolicy as policy_id, shipTokenName as token_name, pilotTokenName as pilot_name, class, totalRewards as total_rewards + FROM MapObjects + WHERE positionX BETWEEN ($1::int - $3::int) AND ($1::int + $3::int) + AND positionY BETWEEN ($2::int - $3::int) AND ($2::int + $3::int) + AND ABS(positionX - $1::int) + ABS(positionY - $2::int) <= $3::int", + center.x, center.y, radius + ) + .fetch_all(pool) + .await + .map_err(|e| Error::new(e.to_string()))?; + + let map_objects: Vec = fetched_objects + .into_iter() + .map(|record| match record.class.as_deref() { + Some("Ship") => MapObject::Ship(Ship { + id: ID::from(record.id), + fuel: record.fuel.unwrap_or(0), + position: Position { + x: record.position_x, + y: record.position_y, + }, + shipyard_policy: PolicyId { + id: ID::from(record.policy_id.unwrap_or_default()), + }, + ship_token_name: AssetName { + name: record.token_name.unwrap_or_default(), + }, + pilot_token_name: AssetName { + name: record.pilot_name.unwrap_or_default(), + }, + class: record.class.unwrap_or_default(), + }), + Some("FuelPellet") => MapObject::FuelPellet(FuelPellet { + id: ID::from(record.id), + fuel: record.fuel.unwrap_or(0), + position: Position { + x: record.position_x, + y: record.position_y, + }, + shipyard_policy: PolicyId { + id: ID::from(record.policy_id.unwrap_or_default()), + }, + class: record.class.unwrap_or_default(), + }), + Some("RewardPot") => MapObject::RewardPot(RewardPot { + id: ID::from(record.id), + position: Position { + x: record.position_x, + y: record.position_y, + }, + total_rewards: record.total_rewards.unwrap_or(0), + class: record.class.unwrap_or_default(), + }), + _ => panic!("Unknown class type or class not provided"), + }) + .collect(); + + Ok(map_objects) + } + + async fn all_ship_actions( + &self, + _ctx: &Context<'_>, + limit: Option, + offset: Option, + ) -> Vec { + let mut actions = Vec::new(); + let num_actions = limit.unwrap_or(10) as usize; + let start = offset.unwrap_or(0) as usize; + + // Generate fake data for ship actions + for i in start..(start + num_actions) { + actions.push(ShipAction { + action_id: ID::from(format!("action-{}", i)), + ship_id: ID::from("ship-1"), + action_type: ShipActionType::Move, + position: Position { + x: i as i32 * 5, + y: i as i32 * 10, + }, + timestamp: "01/01/1971".to_string(), + }); + } + + actions + } + + async fn ship_actions( + &self, + _ctx: &Context<'_>, + ship_id: ID, + limit: Option, + offset: Option, + ) -> Vec { + let mut actions = Vec::new(); + let num_actions = limit.unwrap_or(5) as usize; + let start = offset.unwrap_or(0) as usize; + + // Generate fake data for specific ship actions + for i in start..(start + num_actions) { + actions.push(ShipAction { + action_id: ID::from(format!("action-{}-{}", *ship_id, i)), + ship_id: ship_id.clone(), + action_type: if i % 2 == 0 { + ShipActionType::Move + } else { + ShipActionType::GatherFuel + }, + position: Position { + x: 100 + i as i32, + y: 200 + i as i32, + }, + timestamp: "01/01/1971".to_string(), + }); + } + + actions } } -type MySchema = Schema; +type AsteriaSchema = Schema; #[macro_use] extern crate rocket; @@ -25,12 +363,29 @@ fn index() -> &'static str { } #[rocket::post("/graphql", data = "", format = "application/json")] -async fn graphql_request(schema: &State, request: Request) -> Response { +async fn graphql_request(schema: &State, request: Request) -> Response { request.execute(schema.deref()).await } #[launch] -fn rocket() -> _ { - let schema = Schema::new(QueryRoot, EmptyMutation, EmptySubscription); - rocket::build().manage(schema).mount("/", routes![index, graphql_request]) +async fn rocket() -> _ { + dotenv().ok(); + + let database_url = + env::var("DATABASE_URL").expect("DATABASE_URL must be set in the environment"); + + let pool = sqlx::postgres::PgPoolOptions::new() + .max_connections(5) + .connect(database_url.as_str()) + .await + .expect("Failed to create pool"); + + let schema = Schema::build(QueryRoot, EmptyMutation, EmptySubscription) + .register_output_type::() + .data(pool.clone()) + .finish(); + + rocket::build() + .manage(schema) + .mount("/", routes![index, graphql_request]) }