diff --git a/Pipfile b/Pipfile index 42da6f72a..8e8c6db68 100644 --- a/Pipfile +++ b/Pipfile @@ -9,7 +9,7 @@ isort = "==5.13.2" pylint = "==3.1.0" coverage = "~=5.5" # api-server -api-server = {editable = true, path = "./packages/api-server"} +api-server = {editable = true, path = "./packages/api-server", extras = ["postgres"]} httpx = "~=0.26.0" datamodel-code-generator = "==0.25.4" requests = "~=2.25" diff --git a/Pipfile.lock b/Pipfile.lock index 7af923efb..0919317c5 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "b7b6e862e5191aca7cc5e8c8eb25fc8c0428ab21a7094307abda965ac78f4c83" + "sha256": "1d259c39e7e48f9f0f3f19ac86bfc9fe9a43386f43151cf22cb356afb7f40d0d" }, "pipfile-spec": 6, "requires": { @@ -35,31 +35,34 @@ }, "annotated-types": { "hashes": [ - "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43", - "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d" + "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", + "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89" ], "markers": "python_version >= '3.8'", - "version": "==0.6.0" + "version": "==0.7.0" }, "anyio": { "hashes": [ - "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8", - "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6" + "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94", + "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7" ], "markers": "python_version >= '3.8'", - "version": "==4.3.0" + "version": "==4.4.0" }, "api-server": { "editable": true, + "extras": [ + "postgres" + ], "path": "./packages/api-server" }, "argcomplete": { "hashes": [ - "sha256:bf7900329262e481be5a15f56f19736b376df6f82ed27576fa893652c5de6c23", - "sha256:c12355e0494c76a2a7b73e3a59b09024ca0ba1e279fb9ed6c1b82d5b74b6a70c" + "sha256:69a79e083a716173e5532e0fa3bef45f793f4e61096cf52b5a42c0211c8b8aa5", + "sha256:c2abcdfe1be8ace47ba777d4fce319eb13bf8ad9dace8d085dcad6eded88057f" ], "markers": "python_version >= '3.8'", - "version": "==3.2.3" + "version": "==3.4.0" }, "astroid": { "hashes": [ @@ -69,6 +72,61 @@ "markers": "python_full_version >= '3.8.0'", "version": "==3.1.0" }, + "async-timeout": { + "hashes": [ + "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", + "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028" + ], + "markers": "python_full_version < '3.12.0'", + "version": "==4.0.3" + }, + "asyncpg": { + "hashes": [ + "sha256:0009a300cae37b8c525e5b449233d59cd9868fd35431abc470a3e364d2b85cb9", + "sha256:000c996c53c04770798053e1730d34e30cb645ad95a63265aec82da9093d88e7", + "sha256:012d01df61e009015944ac7543d6ee30c2dc1eb2f6b10b62a3f598beb6531548", + "sha256:039a261af4f38f949095e1e780bae84a25ffe3e370175193174eb08d3cecab23", + "sha256:103aad2b92d1506700cbf51cd8bb5441e7e72e87a7b3a2ca4e32c840f051a6a3", + "sha256:1e186427c88225ef730555f5fdda6c1812daa884064bfe6bc462fd3a71c4b675", + "sha256:2245be8ec5047a605e0b454c894e54bf2ec787ac04b1cb7e0d3c67aa1e32f0fe", + "sha256:37a2ec1b9ff88d8773d3eb6d3784dc7e3fee7756a5317b67f923172a4748a175", + "sha256:48e7c58b516057126b363cec8ca02b804644fd012ef8e6c7e23386b7d5e6ce83", + "sha256:52e8f8f9ff6e21f9b39ca9f8e3e33a5fcdceaf5667a8c5c32bee158e313be385", + "sha256:5340dd515d7e52f4c11ada32171d87c05570479dc01dc66d03ee3e150fb695da", + "sha256:54858bc25b49d1114178d65a88e48ad50cb2b6f3e475caa0f0c092d5f527c106", + "sha256:5b52e46f165585fd6af4863f268566668407c76b2c72d366bb8b522fa66f1870", + "sha256:5bbb7f2cafd8d1fa3e65431833de2642f4b2124be61a449fa064e1a08d27e449", + "sha256:5cad1324dbb33f3ca0cd2074d5114354ed3be2b94d48ddfd88af75ebda7c43cc", + "sha256:6011b0dc29886ab424dc042bf9eeb507670a3b40aece3439944006aafe023178", + "sha256:642a36eb41b6313ffa328e8a5c5c2b5bea6ee138546c9c3cf1bffaad8ee36dd9", + "sha256:6feaf2d8f9138d190e5ec4390c1715c3e87b37715cd69b2c3dfca616134efd2b", + "sha256:72fd0ef9f00aeed37179c62282a3d14262dbbafb74ec0ba16e1b1864d8a12169", + "sha256:746e80d83ad5d5464cfbf94315eb6744222ab00aa4e522b704322fb182b83610", + "sha256:76c3ac6530904838a4b650b2880f8e7af938ee049e769ec2fba7cd66469d7772", + "sha256:797ab8123ebaed304a1fad4d7576d5376c3a006a4100380fb9d517f0b59c1ab2", + "sha256:8d36c7f14a22ec9e928f15f92a48207546ffe68bc412f3be718eedccdf10dc5c", + "sha256:97eb024685b1d7e72b1972863de527c11ff87960837919dac6e34754768098eb", + "sha256:a65c1dcd820d5aea7c7d82a3fdcb70e096f8f70d1a8bf93eb458e49bfad036ac", + "sha256:a921372bbd0aa3a5822dd0409da61b4cd50df89ae85150149f8c119f23e8c408", + "sha256:a9e6823a7012be8b68301342ba33b4740e5a166f6bbda0aee32bc01638491a22", + "sha256:b544ffc66b039d5ec5a7454667f855f7fec08e0dfaf5a5490dfafbb7abbd2cfb", + "sha256:bb1292d9fad43112a85e98ecdc2e051602bce97c199920586be83254d9dafc02", + "sha256:bde17a1861cf10d5afce80a36fca736a86769ab3579532c03e45f83ba8a09c59", + "sha256:cce08a178858b426ae1aa8409b5cc171def45d4293626e7aa6510696d46decd8", + "sha256:cfe73ffae35f518cfd6e4e5f5abb2618ceb5ef02a2365ce64f132601000587d3", + "sha256:d1c49e1f44fffafd9a55e1a9b101590859d881d639ea2922516f5d9c512d354e", + "sha256:d4900ee08e85af01adb207519bb4e14b1cae8fd21e0ccf80fac6aa60b6da37b4", + "sha256:d84156d5fb530b06c493f9e7635aa18f518fa1d1395ef240d211cb563c4e2364", + "sha256:dc600ee8ef3dd38b8d67421359779f8ccec30b463e7aec7ed481c8346decf99f", + "sha256:e0bfe9c4d3429706cf70d3249089de14d6a01192d617e9093a8e941fea8ee775", + "sha256:e17b52c6cf83e170d3d865571ba574577ab8e533e7361a2b8ce6157d02c665d3", + "sha256:f100d23f273555f4b19b74a96840aa27b85e99ba4b1f18d4ebff0734e78dc090", + "sha256:f9ea3f24eb4c49a615573724d88a48bd1b7821c890c2effe04f05382ed9e8810", + "sha256:ff8e8109cd6a46ff852a5e6bab8b0a047d7ea42fcb7ca5ae6eaae97d8eacf397" + ], + "markers": "python_full_version >= '3.8.0'", + "version": "==0.29.0" + }, "bidict": { "hashes": [ "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71", @@ -109,11 +167,11 @@ }, "certifi": { "hashes": [ - "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f", - "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1" + "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516", + "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56" ], "markers": "python_version >= '3.6'", - "version": "==2024.2.2" + "version": "==2024.6.2" }, "cffi": { "hashes": [ @@ -338,40 +396,40 @@ }, "cryptography": { "hashes": [ - "sha256:0270572b8bd2c833c3981724b8ee9747b3ec96f699a9665470018594301439ee", - "sha256:111a0d8553afcf8eb02a4fea6ca4f59d48ddb34497aa8706a6cf536f1a5ec576", - "sha256:16a48c23a62a2f4a285699dba2e4ff2d1cff3115b9df052cdd976a18856d8e3d", - "sha256:1b95b98b0d2af784078fa69f637135e3c317091b615cd0905f8b8a087e86fa30", - "sha256:1f71c10d1e88467126f0efd484bd44bca5e14c664ec2ede64c32f20875c0d413", - "sha256:2424ff4c4ac7f6b8177b53c17ed5d8fa74ae5955656867f5a8affaca36a27abb", - "sha256:2bce03af1ce5a5567ab89bd90d11e7bbdff56b8af3acbbec1faded8f44cb06da", - "sha256:329906dcc7b20ff3cad13c069a78124ed8247adcac44b10bea1130e36caae0b4", - "sha256:37dd623507659e08be98eec89323469e8c7b4c1407c85112634ae3dbdb926fdd", - "sha256:3eaafe47ec0d0ffcc9349e1708be2aaea4c6dd4978d76bf6eb0cb2c13636c6fc", - "sha256:5e6275c09d2badf57aea3afa80d975444f4be8d3bc58f7f80d2a484c6f9485c8", - "sha256:6fe07eec95dfd477eb9530aef5bead34fec819b3aaf6c5bd6d20565da607bfe1", - "sha256:7367d7b2eca6513681127ebad53b2582911d1736dc2ffc19f2c3ae49997496bc", - "sha256:7cde5f38e614f55e28d831754e8a3bacf9ace5d1566235e39d91b35502d6936e", - "sha256:9481ffe3cf013b71b2428b905c4f7a9a4f76ec03065b05ff499bb5682a8d9ad8", - "sha256:98d8dc6d012b82287f2c3d26ce1d2dd130ec200c8679b6213b3c73c08b2b7940", - "sha256:a011a644f6d7d03736214d38832e030d8268bcff4a41f728e6030325fea3e400", - "sha256:a2913c5375154b6ef2e91c10b5720ea6e21007412f6437504ffea2109b5a33d7", - "sha256:a30596bae9403a342c978fb47d9b0ee277699fa53bbafad14706af51fe543d16", - "sha256:b03c2ae5d2f0fc05f9a2c0c997e1bc18c8229f392234e8a0194f202169ccd278", - "sha256:b6cd2203306b63e41acdf39aa93b86fb566049aeb6dc489b70e34bcd07adca74", - "sha256:b7ffe927ee6531c78f81aa17e684e2ff617daeba7f189f911065b2ea2d526dec", - "sha256:b8cac287fafc4ad485b8a9b67d0ee80c66bf3574f655d3b97ef2e1082360faf1", - "sha256:ba334e6e4b1d92442b75ddacc615c5476d4ad55cc29b15d590cc6b86efa487e2", - "sha256:ba3e4a42397c25b7ff88cdec6e2a16c2be18720f317506ee25210f6d31925f9c", - "sha256:c41fb5e6a5fe9ebcd58ca3abfeb51dffb5d83d6775405305bfa8715b76521922", - "sha256:cd2030f6650c089aeb304cf093f3244d34745ce0cfcc39f20c6fbfe030102e2a", - "sha256:cd65d75953847815962c84a4654a84850b2bb4aed3f26fadcc1c13892e1e29f6", - "sha256:e4985a790f921508f36f81831817cbc03b102d643b5fcb81cd33df3fa291a1a1", - "sha256:e807b3188f9eb0eaa7bbb579b462c5ace579f1cedb28107ce8b48a9f7ad3679e", - "sha256:f12764b8fffc7a123f641d7d049d382b73f96a34117e0b637b80643169cec8ac", - "sha256:f8837fe1d6ac4a8052a9a8ddab256bc006242696f03368a4009be7ee3075cdb7" - ], - "version": "==42.0.5" + "sha256:013629ae70b40af70c9a7a5db40abe5d9054e6f4380e50ce769947b73bf3caad", + "sha256:2346b911eb349ab547076f47f2e035fc8ff2c02380a7cbbf8d87114fa0f1c583", + "sha256:2f66d9cd9147ee495a8374a45ca445819f8929a3efcd2e3df6428e46c3cbb10b", + "sha256:2f88d197e66c65be5e42cd72e5c18afbfae3f741742070e3019ac8f4ac57262c", + "sha256:31f721658a29331f895a5a54e7e82075554ccfb8b163a18719d342f5ffe5ecb1", + "sha256:343728aac38decfdeecf55ecab3264b015be68fc2816ca800db649607aeee648", + "sha256:5226d5d21ab681f432a9c1cf8b658c0cb02533eece706b155e5fbd8a0cdd3949", + "sha256:57080dee41209e556a9a4ce60d229244f7a66ef52750f813bfbe18959770cfba", + "sha256:5a94eccb2a81a309806027e1670a358b99b8fe8bfe9f8d329f27d72c094dde8c", + "sha256:6b7c4f03ce01afd3b76cf69a5455caa9cfa3de8c8f493e0d3ab7d20611c8dae9", + "sha256:7016f837e15b0a1c119d27ecd89b3515f01f90a8615ed5e9427e30d9cdbfed3d", + "sha256:81884c4d096c272f00aeb1f11cf62ccd39763581645b0812e99a91505fa48e0c", + "sha256:81d8a521705787afe7a18d5bfb47ea9d9cc068206270aad0b96a725022e18d2e", + "sha256:8d09d05439ce7baa8e9e95b07ec5b6c886f548deb7e0f69ef25f64b3bce842f2", + "sha256:961e61cefdcb06e0c6d7e3a1b22ebe8b996eb2bf50614e89384be54c48c6b63d", + "sha256:9c0c1716c8447ee7dbf08d6db2e5c41c688544c61074b54fc4564196f55c25a7", + "sha256:a0608251135d0e03111152e41f0cc2392d1e74e35703960d4190b2e0f4ca9c70", + "sha256:a0c5b2b0585b6af82d7e385f55a8bc568abff8923af147ee3c07bd8b42cda8b2", + "sha256:ad803773e9df0b92e0a817d22fd8a3675493f690b96130a5e24f1b8fabbea9c7", + "sha256:b297f90c5723d04bcc8265fc2a0f86d4ea2e0f7ab4b6994459548d3a6b992a14", + "sha256:ba4f0a211697362e89ad822e667d8d340b4d8d55fae72cdd619389fb5912eefe", + "sha256:c4783183f7cb757b73b2ae9aed6599b96338eb957233c58ca8f49a49cc32fd5e", + "sha256:c9bb2ae11bfbab395bdd072985abde58ea9860ed84e59dbc0463a5d0159f5b71", + "sha256:cafb92b2bc622cd1aa6a1dce4b93307792633f4c5fe1f46c6b97cf67073ec961", + "sha256:d45b940883a03e19e944456a558b67a41160e367a719833c53de6911cabba2b7", + "sha256:dc0fdf6787f37b1c6b08e6dfc892d9d068b5bdb671198c72072828b80bd5fe4c", + "sha256:dea567d1b0e8bc5764b9443858b673b734100c2871dc93163f58c46a97a83d28", + "sha256:dec9b018df185f08483f294cae6ccac29e7a6e0678996587363dc352dc65c842", + "sha256:e3ec3672626e1b9e55afd0df6d774ff0e953452886e06e0f1eb7eb0c832e8902", + "sha256:e599b53fd95357d92304510fb7bda8523ed1f79ca98dce2f43c115950aa78801", + "sha256:fa76fbb7596cc5839320000cdd5d0955313696d9511debab7ee7278fc8b5c84a", + "sha256:fff12c88a672ab9c9c1cf7b0c80e3ad9e2ebd9d828d955c126be4fd3e5578c9e" + ], + "version": "==42.0.8" }, "datamodel-code-generator": { "hashes": [ @@ -400,18 +458,18 @@ }, "email-validator": { "hashes": [ - "sha256:200a70680ba08904be6d1eef729205cc0d687634399a5924d842533efb824b84", - "sha256:97d882d174e2a65732fb43bfce81a3a834cbc1bde8bf419e30ef5ea976370a05" + "sha256:14c0f3d343c4beda37400421b39fa411bbe33a75df20825df73ad53e06a9f04c", + "sha256:d89f6324e13b1e39889eab7f9ca2f91dc9aebb6fa50a6d8bd4329ab50f251115" ], - "version": "==2.1.1" + "version": "==2.1.2" }, "exceptiongroup": { "hashes": [ - "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14", - "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68" + "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", + "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16" ], "markers": "python_version < '3.11'", - "version": "==1.2.0" + "version": "==1.2.1" }, "fastapi": { "hashes": [ @@ -423,9 +481,10 @@ }, "genson": { "hashes": [ - "sha256:8caf69aa10af7aee0e1a1351d1d06801f4696e005f06cedef438635384346a16" + "sha256:468feccd00274cc7e4c09e84b08704270ba8d95232aa280f65b986139cec67f7", + "sha256:e02db9ac2e3fd29e65b5286f7135762e2cd8a986537c075b06fc5f1517308e37" ], - "version": "==1.2.2" + "version": "==1.3.0" }, "h11": { "hashes": [ @@ -437,11 +496,11 @@ }, "httpcore": { "hashes": [ - "sha256:ac418c1db41bade2ad53ae2f3834a3a0f5ae76b56cf5aa497d2d033384fc7d73", - "sha256:cb2839ccfcba0d2d3c1131d3c3e26dfc327326fbe7a5dc0dbfe9f6c9151bb022" + "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61", + "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5" ], "markers": "python_version >= '3.8'", - "version": "==1.0.4" + "version": "==1.0.5" }, "httptools": { "hashes": [ @@ -495,11 +554,11 @@ }, "idna": { "hashes": [ - "sha256:9ecdbbd083b06798ae1e86adcbfe8ab1479cf864e4ee30fe4e46a003d12491ca", - "sha256:c05567e9c24a6b9faaa835c4821bad0590fbb9d5779e7caa6e1cc4978e7eb24f" + "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc", + "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0" ], "markers": "python_version >= '3.5'", - "version": "==3.6" + "version": "==3.7" }, "inflect": { "hashes": [ @@ -528,11 +587,11 @@ }, "jinja2": { "hashes": [ - "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa", - "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90" + "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", + "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d" ], "markers": "python_version >= '3.7'", - "version": "==3.1.3" + "version": "==3.1.4" }, "markupsafe": { "hashes": [ @@ -618,11 +677,11 @@ }, "packaging": { "hashes": [ - "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5", - "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9" + "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002", + "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124" ], - "markers": "python_version >= '3.7'", - "version": "==24.0" + "markers": "python_version >= '3.8'", + "version": "==24.1" }, "pathspec": { "hashes": [ @@ -634,18 +693,19 @@ }, "platformdirs": { "hashes": [ - "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068", - "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768" + "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee", + "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3" ], "markers": "python_version >= '3.8'", - "version": "==4.2.0" + "version": "==4.2.2" }, "pycparser": { "hashes": [ - "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9", - "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206" + "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", + "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc" ], - "version": "==2.21" + "markers": "python_version >= '3.8'", + "version": "==2.22" }, "pydantic": { "extras": [ @@ -780,19 +840,19 @@ }, "python-engineio": { "hashes": [ - "sha256:979859bff770725b75e60353d7ae53b397e8b517d05ba76733b404a3dcca3e4c", - "sha256:e87459c15638e567711fd156e6f9c4a402668871bed79523f0ecfec744729ec7" + "sha256:7631cf5563086076611e494c643b3fa93dd3a854634b5488be0bba0ef9b99709", + "sha256:f995e702b21f6b9ebde4e2000cd2ad0112ba0e5116ec8d22fe3515e76ba9dddd" ], "markers": "python_version >= '3.6'", - "version": "==4.9.0" + "version": "==4.9.1" }, "python-socketio": { "hashes": [ - "sha256:bbcbd758ed8c183775cb2853ba001361e2fa018babf5cbe11a5b77e91c2ec2a2", - "sha256:f1a0228b8b1fbdbd93fbbedd821ebce0ef54b2b5bf6e98fcf710deaa7c574259" + "sha256:194af8cdbb7b0768c2e807ba76c7abc288eb5bb85559b7cddee51a6bc7a65737", + "sha256:2a923a831ff70664b7c502df093c423eb6aa93c1ce68b8319e840227a26d8b69" ], "markers": "python_version >= '3.8'", - "version": "==5.11.1" + "version": "==5.11.3" }, "pytz": { "hashes": [ @@ -868,12 +928,12 @@ }, "requests": { "hashes": [ - "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f", - "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1" + "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", + "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6" ], "index": "pypi", - "markers": "python_version >= '3.7'", - "version": "==2.31.0" + "markers": "python_version >= '3.8'", + "version": "==2.32.3" }, "ros-translator": { "editable": true, @@ -881,11 +941,11 @@ }, "schedule": { "hashes": [ - "sha256:14cdeb083a596aa1de6dc77639a1b2ac8bf6eaafa82b1c9279d3612823063d01", - "sha256:843bc0538b99c93f02b8b50e3e39886c06f2d003b24f48e1aa4cadfa3f341279" + "sha256:15fe9c75fe5fd9b9627f3f19cc0ef1420508f9f9a46f45cd0769ef75ede5f0b7", + "sha256:5bef4a2a0183abf44046ae0d164cadcac21b1db011bdd8102e4a0c1e91e06a7d" ], "markers": "python_version >= '3.7'", - "version": "==1.2.1" + "version": "==1.2.2" }, "simple-websocket": { "hashes": [ @@ -924,51 +984,51 @@ "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f" ], - "markers": "python_version < '3.11'", + "markers": "python_full_version < '3.11.0a7'", "version": "==2.0.1" }, "tomlkit": { "hashes": [ - "sha256:5cd82d48a3dd89dee1f9d64420aa20ae65cfbd00668d6f094d7578a78efbb77b", - "sha256:7ca1cfc12232806517a8515047ba66a19369e71edf2439d0f5824f91032b6cc3" + "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f", + "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c" ], "markers": "python_version >= '3.7'", - "version": "==0.12.4" + "version": "==0.12.5" }, "tortoise-orm": { "hashes": [ - "sha256:1891ad935de689ddf002c5c65c864176d28659ab6069e45f0e2cde32359bb8d9", - "sha256:283af584d685dcc58d6cc1da35b9115bb1e41c89075eae2a19c493b39b9b41f7" + "sha256:bf88bc1ba7495a8827565c071efba0a89c4b5f83ff1c16be3c837a4e6b672c21", + "sha256:c896c90a90d1213b822ac0d607b61659ad5fcd5ff72698a8ba2d9efbad9932f3" ], "markers": "python_version >= '3.8' and python_version < '4.0'", - "version": "==0.20.0" + "version": "==0.20.1" }, "typing-extensions": { "hashes": [ - "sha256:69b1a937c3a517342112fb4c6df7e72fc39a38e7891a5730ed4985b5214b5475", - "sha256:b0abd7c89e8fb96f98db18d86106ff1d90ab692004eb746cf6eda2682f91b3cb" + "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", + "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8" ], "markers": "python_version < '3.11'", - "version": "==4.10.0" + "version": "==4.12.2" }, "urllib3": { "hashes": [ - "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d", - "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19" + "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472", + "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168" ], "markers": "python_version >= '3.8'", - "version": "==2.2.1" + "version": "==2.2.2" }, "uvicorn": { "extras": [ "standard" ], "hashes": [ - "sha256:6623abbbe6176204a4226e67607b4d52cc60ff62cda0ff177613645cefa2ece1", - "sha256:cab4473b5d1eaeb5a0f6375ac4bc85007ffc75c3cc1768816d9e5d589857b067" + "sha256:08103e79d546b6cf20f67c7e5e434d2cf500a6e29b28773e407250c54fc4fa3c", + "sha256:5162f6d652f545be91b1feeaee8180774af143965ca9dc8a47ff1dc6bafa4ad5" ], "markers": "python_version >= '3.8'", - "version": "==0.28.0" + "version": "==0.28.1" }, "uvloop": { "hashes": [ @@ -1008,83 +1068,83 @@ }, "watchfiles": { "hashes": [ - "sha256:02b73130687bc3f6bb79d8a170959042eb56eb3a42df3671c79b428cd73f17cc", - "sha256:02d91cbac553a3ad141db016e3350b03184deaafeba09b9d6439826ee594b365", - "sha256:06247538e8253975bdb328e7683f8515ff5ff041f43be6c40bff62d989b7d0b0", - "sha256:08dca260e85ffae975448e344834d765983237ad6dc308231aa16e7933db763e", - "sha256:0d9ac347653ebd95839a7c607608703b20bc07e577e870d824fa4801bc1cb124", - "sha256:0dd5fad9b9c0dd89904bbdea978ce89a2b692a7ee8a0ce19b940e538c88a809c", - "sha256:11cd0c3100e2233e9c53106265da31d574355c288e15259c0d40a4405cbae317", - "sha256:18722b50783b5e30a18a8a5db3006bab146d2b705c92eb9a94f78c72beb94094", - "sha256:18d5b4da8cf3e41895b34e8c37d13c9ed294954907929aacd95153508d5d89d7", - "sha256:1ad7247d79f9f55bb25ab1778fd47f32d70cf36053941f07de0b7c4e96b5d235", - "sha256:1b8d1eae0f65441963d805f766c7e9cd092f91e0c600c820c764a4ff71a0764c", - "sha256:1bd467213195e76f838caf2c28cd65e58302d0254e636e7c0fca81efa4a2e62c", - "sha256:1c9198c989f47898b2c22201756f73249de3748e0fc9de44adaf54a8b259cc0c", - "sha256:1fd9a5205139f3c6bb60d11f6072e0552f0a20b712c85f43d42342d162be1235", - "sha256:214cee7f9e09150d4fb42e24919a1e74d8c9b8a9306ed1474ecaddcd5479c293", - "sha256:27b4035013f1ea49c6c0b42d983133b136637a527e48c132d368eb19bf1ac6aa", - "sha256:3a23092a992e61c3a6a70f350a56db7197242f3490da9c87b500f389b2d01eef", - "sha256:3ad692bc7792be8c32918c699638b660c0de078a6cbe464c46e1340dadb94c19", - "sha256:3ccceb50c611c433145502735e0370877cced72a6c70fd2410238bcbc7fe51d8", - "sha256:3d0f32ebfaa9c6011f8454994f86108c2eb9c79b8b7de00b36d558cadcedaa3d", - "sha256:3f92944efc564867bbf841c823c8b71bb0be75e06b8ce45c084b46411475a915", - "sha256:40bca549fdc929b470dd1dbfcb47b3295cb46a6d2c90e50588b0a1b3bd98f429", - "sha256:43babacef21c519bc6631c5fce2a61eccdfc011b4bcb9047255e9620732c8097", - "sha256:4566006aa44cb0d21b8ab53baf4b9c667a0ed23efe4aaad8c227bfba0bf15cbe", - "sha256:49f56e6ecc2503e7dbe233fa328b2be1a7797d31548e7a193237dcdf1ad0eee0", - "sha256:4c48a10d17571d1275701e14a601e36959ffada3add8cdbc9e5061a6e3579a5d", - "sha256:4ea10a29aa5de67de02256a28d1bf53d21322295cb00bd2d57fcd19b850ebd99", - "sha256:511f0b034120cd1989932bf1e9081aa9fb00f1f949fbd2d9cab6264916ae89b1", - "sha256:51ddac60b96a42c15d24fbdc7a4bfcd02b5a29c047b7f8bf63d3f6f5a860949a", - "sha256:57d430f5fb63fea141ab71ca9c064e80de3a20b427ca2febcbfcef70ff0ce895", - "sha256:59137c0c6826bd56c710d1d2bda81553b5e6b7c84d5a676747d80caf0409ad94", - "sha256:5a03651352fc20975ee2a707cd2d74a386cd303cc688f407296064ad1e6d1562", - "sha256:5eb86c6acb498208e7663ca22dbe68ca2cf42ab5bf1c776670a50919a56e64ab", - "sha256:642d66b75eda909fd1112d35c53816d59789a4b38c141a96d62f50a3ef9b3360", - "sha256:6674b00b9756b0af620aa2a3346b01f8e2a3dc729d25617e1b89cf6af4a54eb1", - "sha256:668c265d90de8ae914f860d3eeb164534ba2e836811f91fecc7050416ee70aa7", - "sha256:66fac0c238ab9a2e72d026b5fb91cb902c146202bbd29a9a1a44e8db7b710b6f", - "sha256:6c107ea3cf2bd07199d66f156e3ea756d1b84dfd43b542b2d870b77868c98c03", - "sha256:6c889025f59884423428c261f212e04d438de865beda0b1e1babab85ef4c0f01", - "sha256:6cb8fdc044909e2078c248986f2fc76f911f72b51ea4a4fbbf472e01d14faa58", - "sha256:6e9be3ef84e2bb9710f3f777accce25556f4a71e15d2b73223788d528fcc2052", - "sha256:7f762a1a85a12cc3484f77eee7be87b10f8c50b0b787bb02f4e357403cad0c0e", - "sha256:83a696da8922314ff2aec02987eefb03784f473281d740bf9170181829133765", - "sha256:853853cbf7bf9408b404754b92512ebe3e3a83587503d766d23e6bf83d092ee6", - "sha256:8ad3fe0a3567c2f0f629d800409cd528cb6251da12e81a1f765e5c5345fd0137", - "sha256:8c6ed10c2497e5fedadf61e465b3ca12a19f96004c15dcffe4bd442ebadc2d85", - "sha256:8d5f400326840934e3507701f9f7269247f7c026d1b6cfd49477d2be0933cfca", - "sha256:927c589500f9f41e370b0125c12ac9e7d3a2fd166b89e9ee2828b3dda20bfe6f", - "sha256:9a0aa47f94ea9a0b39dd30850b0adf2e1cd32a8b4f9c7aa443d852aacf9ca214", - "sha256:9b37a7ba223b2f26122c148bb8d09a9ff312afca998c48c725ff5a0a632145f7", - "sha256:9c873345680c1b87f1e09e0eaf8cf6c891b9851d8b4d3645e7efe2ec20a20cc7", - "sha256:9d09869f2c5a6f2d9df50ce3064b3391d3ecb6dced708ad64467b9e4f2c9bef3", - "sha256:9d353c4cfda586db2a176ce42c88f2fc31ec25e50212650c89fdd0f560ee507b", - "sha256:a1e3014a625bcf107fbf38eece0e47fa0190e52e45dc6eee5a8265ddc6dc5ea7", - "sha256:a3b9bec9579a15fb3ca2d9878deae789df72f2b0fdaf90ad49ee389cad5edab6", - "sha256:ab03a90b305d2588e8352168e8c5a1520b721d2d367f31e9332c4235b30b8994", - "sha256:aff06b2cac3ef4616e26ba17a9c250c1fe9dd8a5d907d0193f84c499b1b6e6a9", - "sha256:b3cab0e06143768499384a8a5efb9c4dc53e19382952859e4802f294214f36ec", - "sha256:b4a21f71885aa2744719459951819e7bf5a906a6448a6b2bbce8e9cc9f2c8128", - "sha256:b6d45d9b699ecbac6c7bd8e0a2609767491540403610962968d258fd6405c17c", - "sha256:be6dd5d52b73018b21adc1c5d28ac0c68184a64769052dfeb0c5d9998e7f56a2", - "sha256:c550a56bf209a3d987d5a975cdf2063b3389a5d16caf29db4bdddeae49f22078", - "sha256:c76c635fabf542bb78524905718c39f736a98e5ab25b23ec6d4abede1a85a6a3", - "sha256:c81818595eff6e92535ff32825f31c116f867f64ff8cdf6562cd1d6b2e1e8f3e", - "sha256:cfb92d49dbb95ec7a07511bc9efb0faff8fe24ef3805662b8d6808ba8409a71a", - "sha256:d23bcd6c8eaa6324fe109d8cac01b41fe9a54b8c498af9ce464c1aeeb99903d6", - "sha256:d5b1dc0e708fad9f92c296ab2f948af403bf201db8fb2eb4c8179db143732e49", - "sha256:d78f30cbe8b2ce770160d3c08cff01b2ae9306fe66ce899b73f0409dc1846c1b", - "sha256:d8f57c4461cd24fda22493109c45b3980863c58a25b8bec885ca8bea6b8d4b28", - "sha256:d9792dff410f266051025ecfaa927078b94cc7478954b06796a9756ccc7e14a9", - "sha256:e7941bbcfdded9c26b0bf720cb7e6fd803d95a55d2c14b4bd1f6a2772230c586", - "sha256:ebe684d7d26239e23d102a2bad2a358dedf18e462e8808778703427d1f584400", - "sha256:ec8c8900dc5c83650a63dd48c4d1d245343f904c4b64b48798c67a3767d7e165", - "sha256:f564bf68404144ea6b87a78a3f910cc8de216c6b12a4cf0b27718bf4ec38d303", - "sha256:fd7ac678b92b29ba630d8c842d8ad6c555abda1b9ef044d6cc092dacbfc9719d" - ], - "version": "==0.21.0" + "sha256:00095dd368f73f8f1c3a7982a9801190cc88a2f3582dd395b289294f8975172b", + "sha256:00ad0bcd399503a84cc688590cdffbe7a991691314dde5b57b3ed50a41319a31", + "sha256:00f39592cdd124b4ec5ed0b1edfae091567c72c7da1487ae645426d1b0ffcad1", + "sha256:030bc4e68d14bcad2294ff68c1ed87215fbd9a10d9dea74e7cfe8a17869785ab", + "sha256:052d668a167e9fc345c24203b104c313c86654dd6c0feb4b8a6dfc2462239249", + "sha256:067dea90c43bf837d41e72e546196e674f68c23702d3ef80e4e816937b0a3ffd", + "sha256:0b04a2cbc30e110303baa6d3ddce8ca3664bc3403be0f0ad513d1843a41c97d1", + "sha256:0bc3b2f93a140df6806c8467c7f51ed5e55a931b031b5c2d7ff6132292e803d6", + "sha256:0c8e0aa0e8cc2a43561e0184c0513e291ca891db13a269d8d47cb9841ced7c71", + "sha256:103622865599f8082f03af4214eaff90e2426edff5e8522c8f9e93dc17caee13", + "sha256:1235c11510ea557fe21be5d0e354bae2c655a8ee6519c94617fe63e05bca4171", + "sha256:1cc0cba54f47c660d9fa3218158b8963c517ed23bd9f45fe463f08262a4adae1", + "sha256:1d9188979a58a096b6f8090e816ccc3f255f137a009dd4bbec628e27696d67c1", + "sha256:213792c2cd3150b903e6e7884d40660e0bcec4465e00563a5fc03f30ea9c166c", + "sha256:25c817ff2a86bc3de3ed2df1703e3d24ce03479b27bb4527c57e722f8554d971", + "sha256:2627a91e8110b8de2406d8b2474427c86f5a62bf7d9ab3654f541f319ef22bcb", + "sha256:280a4afbc607cdfc9571b9904b03a478fc9f08bbeec382d648181c695648202f", + "sha256:28324d6b28bcb8d7c1041648d7b63be07a16db5510bea923fc80b91a2a6cbed6", + "sha256:28585744c931576e535860eaf3f2c0ec7deb68e3b9c5a85ca566d69d36d8dd27", + "sha256:28f393c1194b6eaadcdd8f941307fc9bbd7eb567995232c830f6aef38e8a6e88", + "sha256:2abeb79209630da981f8ebca30a2c84b4c3516a214451bfc5f106723c5f45843", + "sha256:2bdadf6b90c099ca079d468f976fd50062905d61fae183f769637cb0f68ba59a", + "sha256:2f350cbaa4bb812314af5dab0eb8d538481e2e2279472890864547f3fe2281ed", + "sha256:3218a6f908f6a276941422b035b511b6d0d8328edd89a53ae8c65be139073f84", + "sha256:3973145235a38f73c61474d56ad6199124e7488822f3a4fc97c72009751ae3b0", + "sha256:3a0d883351a34c01bd53cfa75cd0292e3f7e268bacf2f9e33af4ecede7e21d1d", + "sha256:425440e55cd735386ec7925f64d5dde392e69979d4c8459f6bb4e920210407f2", + "sha256:4b9f2a128a32a2c273d63eb1fdbf49ad64852fc38d15b34eaa3f7ca2f0d2b797", + "sha256:4cc382083afba7918e32d5ef12321421ef43d685b9a67cc452a6e6e18920890e", + "sha256:52fc9b0dbf54d43301a19b236b4a4614e610605f95e8c3f0f65c3a456ffd7d35", + "sha256:55b7cc10261c2786c41d9207193a85c1db1b725cf87936df40972aab466179b6", + "sha256:581f0a051ba7bafd03e17127735d92f4d286af941dacf94bcf823b101366249e", + "sha256:5834e1f8b71476a26df97d121c0c0ed3549d869124ed2433e02491553cb468c2", + "sha256:5e45fb0d70dda1623a7045bd00c9e036e6f1f6a85e4ef2c8ae602b1dfadf7550", + "sha256:61af9efa0733dc4ca462347becb82e8ef4945aba5135b1638bfc20fad64d4f0e", + "sha256:68fe0c4d22332d7ce53ad094622b27e67440dacefbaedd29e0794d26e247280c", + "sha256:72a44e9481afc7a5ee3291b09c419abab93b7e9c306c9ef9108cb76728ca58d2", + "sha256:7a74436c415843af2a769b36bf043b6ccbc0f8d784814ba3d42fc961cdb0a9dc", + "sha256:8597b6f9dc410bdafc8bb362dac1cbc9b4684a8310e16b1ff5eee8725d13dcd6", + "sha256:8c39987a1397a877217be1ac0fb1d8b9f662c6077b90ff3de2c05f235e6a8f96", + "sha256:8c3e3675e6e39dc59b8fe5c914a19d30029e36e9f99468dddffd432d8a7b1c93", + "sha256:8dc1fc25a1dedf2dd952909c8e5cb210791e5f2d9bc5e0e8ebc28dd42fed7562", + "sha256:8fdebb655bb1ba0122402352b0a4254812717a017d2dc49372a1d47e24073795", + "sha256:9165bcab15f2b6d90eedc5c20a7f8a03156b3773e5fb06a790b54ccecdb73385", + "sha256:94ebe84a035993bb7668f58a0ebf998174fb723a39e4ef9fce95baabb42b787f", + "sha256:9624a68b96c878c10437199d9a8b7d7e542feddda8d5ecff58fdc8e67b460848", + "sha256:96eec15e5ea7c0b6eb5bfffe990fc7c6bd833acf7e26704eb18387fb2f5fd087", + "sha256:97b94e14b88409c58cdf4a8eaf0e67dfd3ece7e9ce7140ea6ff48b0407a593ec", + "sha256:988e981aaab4f3955209e7e28c7794acdb690be1efa7f16f8ea5aba7ffdadacb", + "sha256:a8a31bfd98f846c3c284ba694c6365620b637debdd36e46e1859c897123aa232", + "sha256:a927b3034d0672f62fb2ef7ea3c9fc76d063c4b15ea852d1db2dc75fe2c09696", + "sha256:ace7d060432acde5532e26863e897ee684780337afb775107c0a90ae8dbccfd2", + "sha256:aec83c3ba24c723eac14225194b862af176d52292d271c98820199110e31141e", + "sha256:b44b70850f0073b5fcc0b31ede8b4e736860d70e2dbf55701e05d3227a154a67", + "sha256:b610fb5e27825b570554d01cec427b6620ce9bd21ff8ab775fc3a32f28bba63e", + "sha256:b810a2c7878cbdecca12feae2c2ae8af59bea016a78bc353c184fa1e09f76b68", + "sha256:bbf8a20266136507abf88b0df2328e6a9a7c7309e8daff124dda3803306a9fdb", + "sha256:bd4c06100bce70a20c4b81e599e5886cf504c9532951df65ad1133e508bf20be", + "sha256:c2444dc7cb9d8cc5ab88ebe792a8d75709d96eeef47f4c8fccb6df7c7bc5be71", + "sha256:c49b76a78c156979759d759339fb62eb0549515acfe4fd18bb151cc07366629c", + "sha256:c4a65474fd2b4c63e2c18ac67a0c6c66b82f4e73e2e4d940f837ed3d2fd9d4da", + "sha256:c5af2347d17ab0bd59366db8752d9e037982e259cacb2ba06f2c41c08af02c39", + "sha256:c668228833c5619f6618699a2c12be057711b0ea6396aeaece4ded94184304ea", + "sha256:c7b978c384e29d6c7372209cbf421d82286a807bbcdeb315427687f8371c340a", + "sha256:d048ad5d25b363ba1d19f92dcf29023988524bee6f9d952130b316c5802069cb", + "sha256:d3e1f3cf81f1f823e7874ae563457828e940d75573c8fbf0ee66818c8b6a9099", + "sha256:d47e9ef1a94cc7a536039e46738e17cce058ac1593b2eccdede8bf72e45f372a", + "sha256:da1e0a8caebf17976e2ffd00fa15f258e14749db5e014660f53114b676e68538", + "sha256:dc1b9b56f051209be458b87edb6856a449ad3f803315d87b2da4c93b43a6fe72", + "sha256:dc2e8fe41f3cac0660197d95216c42910c2b7e9c70d48e6d84e22f577d106fc1", + "sha256:dc92d2d2706d2b862ce0568b24987eba51e17e14b79a1abcd2edc39e48e743c8", + "sha256:dd64f3a4db121bc161644c9e10a9acdb836853155a108c2446db2f5ae1778c3d", + "sha256:e0f0a874231e2839abbf473256efffe577d6ee2e3bfa5b540479e892e47c172d", + "sha256:f7e1f9c5d1160d03b93fc4b68a0aeb82fe25563e12fbcdc8507f8434ab6f823c", + "sha256:fe82d13461418ca5e5a808a9e40f79c1879351fcaeddbede094028e74d836e86" + ], + "version": "==0.22.0" }, "websocket-client": { "hashes": [ diff --git a/packages/api-server/README.md b/packages/api-server/README.md index 405ef6aa3..3c2548a6c 100644 --- a/packages/api-server/README.md +++ b/packages/api-server/README.md @@ -252,18 +252,24 @@ Restart the `api-server` and the changes to the databse should be reflected. ### Running unit tests ```bash -npm test +pnpm test +``` + +By default in-memory sqlite database is used for testing, to test on another database, set the `RMF_API_SERVER_TEST_DB_URL` environment variable. + +```bash +RMF_API_SERVER_TEST_DB_URL= pnpm test ``` ### Collecting code coverage ```bash -npm run test:cov +pnpm run test:cov ``` Generate coverage report ```bash -npm run test:report +pnpm run test:report ``` ## Live reload diff --git a/packages/api-server/api_server/dependencies.py b/packages/api-server/api_server/dependencies.py index e21cae0bc..4c429cd73 100644 --- a/packages/api-server/api_server/dependencies.py +++ b/packages/api-server/api_server/dependencies.py @@ -20,7 +20,11 @@ def pagination_query( ) -> Pagination: limit = limit or 100 offset = offset or 0 - return Pagination(limit=limit, offset=offset, order_by=order_by) + return Pagination( + limit=limit, + offset=offset, + order_by=order_by.split(",") if order_by else [], + ) # hacky way to get the sio user diff --git a/packages/api-server/api_server/models/pagination.py b/packages/api-server/api_server/models/pagination.py index b88a78b4c..9832a379d 100644 --- a/packages/api-server/api_server/models/pagination.py +++ b/packages/api-server/api_server/models/pagination.py @@ -1,9 +1,7 @@ -from typing import Optional - from pydantic import BaseModel class Pagination(BaseModel): limit: int offset: int - order_by: Optional[str] + order_by: list[str] diff --git a/packages/api-server/api_server/query.py b/packages/api-server/api_server/query.py index 4a6779ab4..c0ea9db33 100644 --- a/packages/api-server/api_server/query.py +++ b/packages/api-server/api_server/query.py @@ -1,5 +1,3 @@ -import tortoise.functions as tfuncs -from tortoise.expressions import Q from tortoise.queryset import MODEL, QuerySet from api_server.models.pagination import Pagination @@ -8,47 +6,10 @@ def add_pagination( query: QuerySet[MODEL], pagination: Pagination, - field_mappings: dict[str, str] | None = None, - group_by: str | None = None, ) -> QuerySet[MODEL]: - """ - Adds pagination and ordering to a query. If the order field starts with `label=`, it is - assumed to be a label and label sorting will used. In this case, the model must have - a reverse relation named "labels" and the `group_by` param is required. - - :param field_mapping: A dict mapping the order fields to the fields used to build the - query. e.g. a url of `?order_by=order_field` and a field mapping of `{"order_field": "db_field"}` - will order the query result according to `db_field`. - :param group_by: Required when sorting by labels, must be the foreign key column of the label table. - """ - field_mappings = field_mappings or {} - annotations = {} - query = query.limit(pagination.limit).offset(pagination.offset) - if pagination.order_by is not None: - order_fields = [] - order_values = pagination.order_by.split(",") - for v in order_values: - # perform the mapping after stripping the order prefix - order_prefix = "" - order_field = v - if v[0] in ["-", "+"]: - order_prefix = v[0] - order_field = v[1:] - order_field = field_mappings.get(order_field, order_field) - - # add annotations required for sorting by labels - if order_field.startswith("label="): - f = order_field[6:] - annotations[f"label_sort_{f}"] = tfuncs.Max( - "labels__label_value", - _filter=Q(labels__label_name=f), - ) - order_field = f"label_sort_{f}" - - order_fields.append(order_prefix + order_field) - - query = query.annotate(**annotations) - if group_by is not None: - query = query.group_by(group_by) - query = query.order_by(*order_fields) - return query + """Adds pagination and ordering to a query""" + return ( + query.limit(pagination.limit) + .offset(pagination.offset) + .order_by(*pagination.order_by) + ) diff --git a/packages/api-server/api_server/repositories/tasks.py b/packages/api-server/api_server/repositories/tasks.py index 9d52bb276..144bf5ec6 100644 --- a/packages/api-server/api_server/repositories/tasks.py +++ b/packages/api-server/api_server/repositories/tasks.py @@ -2,10 +2,11 @@ from datetime import datetime from typing import Dict, List, Optional, Sequence, Tuple +import tortoise.functions as tfuncs from fastapi import Depends, HTTPException from tortoise.exceptions import FieldError, IntegrityError +from tortoise.expressions import Expression, Q from tortoise.query_utils import Prefetch -from tortoise.queryset import QuerySet from tortoise.transactions import in_transaction from api_server.authenticator import user_dep @@ -18,6 +19,7 @@ TaskEventLog, TaskRequest, TaskState, + TaskStatus, User, ) from api_server.models import tortoise_models as ttm @@ -25,7 +27,6 @@ from api_server.models.rmf_api.task_state import Category, Id, Phase from api_server.models.tortoise_models import TaskRequest as DbTaskRequest from api_server.models.tortoise_models import TaskState as DbTaskState -from api_server.query import add_pagination from api_server.rmf_io import task_events @@ -96,11 +97,85 @@ async def save_task_state(self, task_state: TaskState) -> None: await self.save_task_labels(db_task_state, labels) async def query_task_states( - self, query: QuerySet[DbTaskState], pagination: Optional[Pagination] = None + self, + task_id: list[str] | None = None, + category: list[str] | None = None, + assigned_to: list[str] | None = None, + start_time_between: tuple[datetime, datetime] | None = None, + finish_time_between: tuple[datetime, datetime] | None = None, + status: list[str] | None = None, + label: Labels | None = None, + pagination: Optional[Pagination] = None, ) -> List[TaskState]: + filters = {} + if task_id is not None: + filters["id___in"] = task_id + if category is not None: + filters["category__in"] = category + if assigned_to is not None: + filters["assigned_to__in"] = assigned_to + if start_time_between is not None: + filters["unix_millis_start_time__gte"] = start_time_between[0] + filters["unix_millis_start_time__lte"] = start_time_between[1] + if finish_time_between is not None: + filters["unix_millis_finish_time__gte"] = finish_time_between[0] + filters["unix_millis_finish_time__lte"] = finish_time_between[1] + if status is not None: + valid_values = [member.value for member in TaskStatus] + filters["status__in"] = [] + for status_string in status: + if status_string not in valid_values: + continue + filters["status__in"].append(TaskStatus(status_string)) + query = DbTaskState.filter(**filters) + + need_group_by = False + label_filters = {} + if label is not None: + label_filters.update( + { + f"label_filter_{k}": tfuncs.Count( + "id_", + _filter=Q(labels__label_name=k, labels__label_value=v), + ) + for k, v in label.root.items() + } + ) + + if len(label_filters) > 0: + filter_gt = {f"{f}__gt": 0 for f in label_filters} + query = query.annotate(**label_filters).filter(**filter_gt) + need_group_by = True + + if pagination: + order_fields: list[str] = [] + annotations: dict[str, Expression] = {} + # add annotations required for sorting by labels + for f in pagination.order_by: + order_prefix = f[0] if f[0] == "-" else "" + order_field = f[1:] if order_prefix == "-" else f + if order_field.startswith("label="): + f = order_field[6:] + annotations[f"label_sort_{f}"] = tfuncs.Max( + "labels__label_value", + _filter=Q(labels__label_name=f), + ) + order_field = f"label_sort_{f}" + + order_fields.append(order_prefix + order_field) + + query = ( + query.annotate(**annotations) + .limit(pagination.limit) + .offset(pagination.offset) + .order_by(*order_fields) + ) + need_group_by = True + + if need_group_by: + query = query.group_by("id_", "labels__state_id") + try: - if pagination: - query = add_pagination(query, pagination, group_by="labels__state_id") # TODO: enforce with authz results = await query.values_list("data") return [TaskState(**r[0]) for r in results] diff --git a/packages/api-server/api_server/routes/tasks/scheduled_tasks.py b/packages/api-server/api_server/routes/tasks/scheduled_tasks.py index 40164d812..0b5b61a3f 100644 --- a/packages/api-server/api_server/routes/tasks/scheduled_tasks.py +++ b/packages/api-server/api_server/routes/tasks/scheduled_tasks.py @@ -134,7 +134,7 @@ async def get_scheduled_tasks( .offset(pagination.offset) ) if pagination.order_by: - q.order_by(*pagination.order_by.split(",")) + q.order_by(*pagination.order_by) results = await q await ttm.ScheduledTask.fetch_for_list(results) return [ScheduledTask.model_validate(x) for x in results] diff --git a/packages/api-server/api_server/routes/tasks/tasks.py b/packages/api-server/api_server/routes/tasks/tasks.py index 831b350d3..77059d8e3 100644 --- a/packages/api-server/api_server/routes/tasks/tasks.py +++ b/packages/api-server/api_server/routes/tasks/tasks.py @@ -1,10 +1,8 @@ from datetime import datetime from typing import List, Optional, Tuple, cast -import tortoise.functions as tfuncs from fastapi import Body, Depends, HTTPException, Path, Query from reactivex import operators as rxops -from tortoise.expressions import Q from api_server import models as mdl from api_server.dependencies import ( @@ -15,7 +13,6 @@ start_time_between_query, ) from api_server.fast_io import FastIORouter, SubscriptionRequest -from api_server.models.tortoise_models import TaskState as DbTaskState from api_server.repositories import TaskRepository, task_repo_dep from api_server.response import RawJSONResponse from api_server.rmf_io import task_events, tasks_service @@ -60,51 +57,16 @@ async def query_task_states( ), pagination: mdl.Pagination = Depends(pagination_query), ): - filters = {} - if task_id is not None: - filters["id___in"] = task_id.split(",") - if category is not None: - filters["category__in"] = category.split(",") - if assigned_to is not None: - filters["assigned_to__in"] = assigned_to.split(",") - if start_time_between is not None: - filters["unix_millis_start_time__gte"] = start_time_between[0] - filters["unix_millis_start_time__lte"] = start_time_between[1] - if finish_time_between is not None: - filters["unix_millis_finish_time__gte"] = finish_time_between[0] - filters["unix_millis_finish_time__lte"] = finish_time_between[1] - if status is not None: - valid_values = [member.value for member in mdl.TaskStatus] - filters["status__in"] = [] - for status_string in status.split(","): - if status_string not in valid_values: - continue - filters["status__in"].append(mdl.TaskStatus(status_string)) - query = DbTaskState.filter(**filters) - - label_filters = {} - if label is not None: - labels = mdl.Labels.from_strings(label.split(",")) - label_filters.update( - { - f"label_filter_{k}": tfuncs.Count( - "id_", _filter=Q(labels__label_name=k, labels__label_value=v) - ) - for k, v in labels.root.items() - } - ) - - if len(label_filters) > 0: - filter_gt = {f"{f}__gt": 0 for f in label_filters} - query = ( - query.annotate(**label_filters) - .group_by( - "labels__state_id" - ) # need to group by a related field to make tortoise-orm generate joins - .filter(**filter_gt) - ) - - return await task_repo.query_task_states(query, pagination) + return await task_repo.query_task_states( + task_id=task_id.split(",") if task_id else None, + category=category.split(",") if category else None, + assigned_to=assigned_to.split(",") if assigned_to else None, + start_time_between=start_time_between, + finish_time_between=finish_time_between, + status=status.split(",") if status else None, + label=mdl.Labels.from_strings(label.split(",")) if label else None, + pagination=pagination, + ) @router.get("/{task_id}/state", response_model=mdl.TaskState) diff --git a/packages/api-server/api_server/routes/tasks/test_tasks.py b/packages/api-server/api_server/routes/tasks/test_tasks.py index 6534ccc4f..9a12067a7 100644 --- a/packages/api-server/api_server/routes/tasks/test_tasks.py +++ b/packages/api-server/api_server/routes/tasks/test_tasks.py @@ -36,15 +36,12 @@ def setUpClass(cls): cls.task_logs = [make_task_log(task_id=f"test_{x}") for x in task_ids] cls.clsSetupErr: str | None = None - if cls.client.portal is None: - cls.clsSetupErr = "missing client portal, is the client context entered?" - return - + portal = cls.get_portal() repo = TaskRepository(cls.admin_user) for x in cls.task_states: - cls.client.portal.call(repo.save_task_state, x) + portal.call(repo.save_task_state, x) for x in cls.task_logs: - cls.client.portal.call(repo.save_task_log, x) + portal.call(repo.save_task_log, x) def setUp(self): super().setUp() diff --git a/packages/api-server/api_server/routes/test_building_map.py b/packages/api-server/api_server/routes/test_building_map.py index 44765b8b3..1aa1490e8 100644 --- a/packages/api-server/api_server/routes/test_building_map.py +++ b/packages/api-server/api_server/routes/test_building_map.py @@ -1,11 +1,11 @@ -from api_server.rmf_io import rmf_events from api_server.test import AppFixture, make_building_map, try_until class TestBuildingMapRoute(AppFixture): def test_get_building_map(self): building_map = make_building_map() - rmf_events.building_map.on_next(building_map) + portal = self.get_portal() + portal.call(building_map.save) resp = try_until( lambda: self.client.get("/building_map"), lambda x: x.status_code == 200 diff --git a/packages/api-server/api_server/routes/test_dispensers.py b/packages/api-server/api_server/routes/test_dispensers.py index 72b1ee91f..0e135b17b 100644 --- a/packages/api-server/api_server/routes/test_dispensers.py +++ b/packages/api-server/api_server/routes/test_dispensers.py @@ -1,4 +1,3 @@ -import asyncio from typing import List from uuid import uuid4 @@ -12,8 +11,9 @@ def setUpClass(cls): super().setUpClass() cls.dispenser_states = [make_dispenser_state(f"test_{uuid4()}")] + portal = cls.get_portal() for x in cls.dispenser_states: - asyncio.run(x.save()) + portal.call(x.save) def test_get_dispensers(self): resp = self.client.get("/dispensers") diff --git a/packages/api-server/api_server/routes/test_doors.py b/packages/api-server/api_server/routes/test_doors.py index 677f407ee..ec4a29f28 100644 --- a/packages/api-server/api_server/routes/test_doors.py +++ b/packages/api-server/api_server/routes/test_doors.py @@ -1,4 +1,3 @@ -import asyncio from uuid import uuid4 from rmf_door_msgs.msg import DoorMode as RmfDoorMode @@ -12,12 +11,13 @@ class TestDoorsRoute(AppFixture): def setUpClass(cls): super().setUpClass() cls.building_map = make_building_map() - asyncio.run(cls.building_map.save()) + portal = cls.get_portal() + portal.call(cls.building_map.save) cls.door_states = [make_door_state(f"test_{uuid4()}")] for x in cls.door_states: - asyncio.run(x.save()) + portal.call(x.save) def test_get_doors(self): resp = self.client.get("/doors") diff --git a/packages/api-server/api_server/routes/test_ingestors.py b/packages/api-server/api_server/routes/test_ingestors.py index 20916f697..810180508 100644 --- a/packages/api-server/api_server/routes/test_ingestors.py +++ b/packages/api-server/api_server/routes/test_ingestors.py @@ -1,4 +1,3 @@ -import asyncio from typing import List from uuid import uuid4 @@ -12,8 +11,9 @@ def setUpClass(cls): super().setUpClass() cls.ingestor_states = [make_ingestor_state(f"test_{uuid4()}")] + portal = cls.get_portal() for x in cls.ingestor_states: - asyncio.run(x.save()) + portal.call(x.save) def test_get_ingestors(self): resp = self.client.get("/ingestors") diff --git a/packages/api-server/api_server/routes/test_lifts.py b/packages/api-server/api_server/routes/test_lifts.py index 0c8f2c898..516f8533c 100644 --- a/packages/api-server/api_server/routes/test_lifts.py +++ b/packages/api-server/api_server/routes/test_lifts.py @@ -1,4 +1,3 @@ -import asyncio from uuid import uuid4 from rmf_lift_msgs.msg import LiftRequest as RmfLiftRequest @@ -12,11 +11,12 @@ class TestLiftsRoute(AppFixture): def setUpClass(cls): super().setUpClass() cls.building_map = make_building_map() - asyncio.run(cls.building_map.save()) + portal = cls.get_portal() + portal.call(cls.building_map.save) cls.lift_states = [make_lift_state(f"test_{uuid4()}")] for x in cls.lift_states: - asyncio.run(x.save()) + portal.call(x.save) def test_get_lifts(self): resp = self.client.get("/lifts") diff --git a/packages/api-server/api_server/test/__init__.py b/packages/api-server/api_server/test/__init__.py index f7725fb21..cfeecb29b 100644 --- a/packages/api-server/api_server/test/__init__.py +++ b/packages/api-server/api_server/test/__init__.py @@ -5,6 +5,5 @@ from .test_client import TestClient from .test_data import * from .test_fixtures import * -from .test_utils import * test_user = User(username="test_user", is_admin=True) diff --git a/packages/api-server/api_server/test/test_fixtures.py b/packages/api-server/api_server/test/test_fixtures.py index 29d599650..16e96caeb 100644 --- a/packages/api-server/api_server/test/test_fixtures.py +++ b/packages/api-server/api_server/test/test_fixtures.py @@ -11,8 +11,10 @@ from uuid import uuid4 import pydantic +from anyio.abc import BlockingPortal +from tortoise import Tortoise -from api_server.app import app +from api_server.app import app, app_config from api_server.models import User from api_server.routes.admin import PostUsers @@ -85,12 +87,32 @@ async def async_try_until( class AppFixture(unittest.TestCase): @classmethod def setUpClass(cls): + async def clean_db(): + # connect to the db to drop it + await Tortoise.init(db_url=app_config.db_url, modules={"models": []}) + await Tortoise._drop_databases() # pylint: disable=protected-access + # connect to it again to recreate it + await Tortoise.init( + db_url=app_config.db_url, modules={"models": []}, _create_db=True + ) + await Tortoise.close_connections() + + asyncio.run(clean_db()) + cls.admin_user = User(username="admin", is_admin=True) cls.client = TestClient() cls.client.headers["Content-Type"] = "application/json" cls.client.__enter__() cls.addClassCleanup(cls.client.__exit__) + @classmethod + def get_portal(cls) -> BlockingPortal: + if not cls.client.portal: + raise AssertionError( + "missing client portal, is the client context entered?" + ) + return cls.client.portal + @contextlib.contextmanager def subscribe_sio(self, room: str, *, user="admin"): """ diff --git a/packages/api-server/api_server/test/test_utils.py b/packages/api-server/api_server/test/test_utils.py deleted file mode 100644 index 71ae280f1..000000000 --- a/packages/api-server/api_server/test/test_utils.py +++ /dev/null @@ -1,12 +0,0 @@ -from typing import Optional, Sequence - -from tortoise import Tortoise - - -async def init_db(models: Optional[Sequence[str]] = None): - models = models or ["api_server.models.tortoise_models"] - await Tortoise.init( - db_url="sqlite://:memory:", - modules={"models": models}, - ) - await Tortoise.generate_schemas() diff --git a/packages/api-server/scripts/sqlite_test_config.py b/packages/api-server/scripts/sqlite_test_config.py deleted file mode 100644 index 70e85c659..000000000 --- a/packages/api-server/scripts/sqlite_test_config.py +++ /dev/null @@ -1,3 +0,0 @@ -from base_test_config import config - -config.update({"db_url": "sqlite://:memory:"}) diff --git a/packages/api-server/scripts/test.py b/packages/api-server/scripts/test.py index 8c60d946b..89df3df30 100644 --- a/packages/api-server/scripts/test.py +++ b/packages/api-server/scripts/test.py @@ -1,9 +1,7 @@ import os import sys -os.environ[ - "RMF_API_SERVER_CONFIG" -] = f"{os.path.dirname(__file__)}/sqlite_test_config.py" +os.environ["RMF_API_SERVER_CONFIG"] = f"{os.path.dirname(__file__)}/test_config.py" import unittest diff --git a/packages/api-server/scripts/base_test_config.py b/packages/api-server/scripts/test_config.py similarity index 65% rename from packages/api-server/scripts/base_test_config.py rename to packages/api-server/scripts/test_config.py index 35fce9a44..6afd866ae 100644 --- a/packages/api-server/scripts/base_test_config.py +++ b/packages/api-server/scripts/test_config.py @@ -4,7 +4,7 @@ here = os.path.dirname(__file__) -test_port = os.environ.get("RMF_SERVER_TEST_PORT", "8000") +test_port = os.environ.get("RMF_API_SERVER_TEST_PORT", "8000") config.update( { "host": "127.0.0.1", @@ -12,5 +12,6 @@ "log_level": "CRITICAL", "jwt_public_key": f"{here}/test.pub", "iss": "test", + "db_url": os.environ.get("RMF_API_SERVER_TEST_DB_URL", "sqlite://:memory:"), } )