From 01d0ce698825c16a233a1c3944763a0de650973d Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Thu, 5 Aug 2021 21:01:00 +0200 Subject: [PATCH 01/21] feat(database): after pagination --- app/controllers/api/database.php | 14 ++- composer.json | 2 +- composer.lock | 30 +++-- tests/e2e/Services/Database/DatabaseBase.php | 109 +++++++++++++++++++ tests/e2e/Services/Storage/StorageBase.php | 4 +- 5 files changed, 143 insertions(+), 16 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 649c346452..00d86b7007 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -1056,12 +1056,12 @@ App::get('/v1/database/collections/:collectionId/documents') ->param('queries', [], new ArrayList(new Text(128)), 'Array of query strings.', true) ->param('limit', 25, new Range(0, 100), 'Maximum number of documents to return in response. Use this value to manage pagination. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 900000000), 'Offset value. The default value is 0. Use this param to manage pagination.', true) - // TODO@kodumbeats 'after' param for pagination ->param('orderAttributes', [], new ArrayList(new Text(128)), 'Array of attributes used to sort results.', true) ->param('orderTypes', [], new ArrayList(new WhiteList(['DESC', 'ASC'], true)), 'Array of order directions for sorting attribtues. Possible values are DESC for descending order, or ASC for ascending order.', true) + ->param('orderAfter', '', new UID(), 'ID of the document used to return documents listed after. Should be used for efficient pagination working with many documents.', true) ->inject('response') ->inject('dbForExternal') - ->action(function ($collectionId, $queries, $limit, $offset, $orderAttributes, $orderTypes, $response, $dbForExternal) { + ->action(function ($collectionId, $queries, $limit, $offset, $orderAttributes, $orderTypes, $orderAfter, $response, $dbForExternal) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForExternal */ @@ -1087,7 +1087,15 @@ App::get('/v1/database/collections/:collectionId/documents') throw new Exception($validator->getDescription(), 400); } - $documents = $dbForExternal->find($collectionId, $queries, $limit, $offset, $orderAttributes, $orderTypes); + if (!empty($orderAfter)) { + $orderAfterDocument = $dbForExternal->getDocument($collectionId, $orderAfter); + + if ($orderAfterDocument->isEmpty()) { + throw new Exception('Document for orderAfter not found', 400); + } + } + + $documents = $dbForExternal->find($collectionId, $queries, $limit, $offset, $orderAttributes, $orderTypes, $orderAfterDocument ?? null); $response->dynamic(new Document([ 'sum' => \count($documents), diff --git a/composer.json b/composer.json index f595bfd1a8..47cfe2d005 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "utopia-php/cache": "0.4.*", "utopia-php/cli": "0.11.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.6.*", + "utopia-php/database": "dev-main as 0.6.0", "utopia-php/locale": "0.3.*", "utopia-php/registry": "0.5.*", "utopia-php/preloader": "0.2.*", diff --git a/composer.lock b/composer.lock index b43adc9166..a1bd64bb84 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f9727be2725e573a92b2d1aeeb77b421", + "content-hash": "1669de851a29702eba426a09a6871921", "packages": [ { "name": "adhocore/jwt", @@ -1984,16 +1984,16 @@ }, { "name": "utopia-php/database", - "version": "0.6.0", + "version": "dev-main", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "561adc215fce3bd3b8c3ebb971ca354fb1526f26" + "reference": "c48b60884f63a547520ecef35714827af1870bc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/561adc215fce3bd3b8c3ebb971ca354fb1526f26", - "reference": "561adc215fce3bd3b8c3ebb971ca354fb1526f26", + "url": "https://api.github.com/repos/utopia-php/database/zipball/c48b60884f63a547520ecef35714827af1870bc4", + "reference": "c48b60884f63a547520ecef35714827af1870bc4", "shasum": "" }, "require": { @@ -2011,6 +2011,7 @@ "utopia-php/cli": "^0.11.0", "vimeo/psalm": "4.0.1" }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -2041,9 +2042,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.6.0" + "source": "https://github.com/utopia-php/database/tree/main" }, - "time": "2021-08-03T15:13:48+00:00" + "time": "2021-08-04T16:53:44+00:00" }, { "name": "utopia-php/domains", @@ -6254,9 +6255,18 @@ "time": "2015-12-17T08:42:14+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/database", + "version": "dev-main", + "alias": "0.6.0", + "alias_normalized": "0.6.0.0" + } + ], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "utopia-php/database": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -6278,5 +6288,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.0.0" } diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index 755321ed73..cae46e3ffe 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -289,6 +289,115 @@ trait DatabaseBase return []; } + /** + * @depends testCreateDocument + */ + public function testListDocumentsAfterPagination(array $data):array + { + /** + * Test after without order. + */ + $base = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals('Captain America', $base['body']['documents'][0]['title']); + $this->assertEquals('Spider-Man: Far From Home', $base['body']['documents'][1]['title']); + $this->assertEquals('Spider-Man: Homecoming', $base['body']['documents'][2]['title']); + $this->assertCount(3, $base['body']['documents']); + + $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'orderAfter' => $base['body']['documents'][0]['$id'] + ]); + + $this->assertEquals($base['body']['documents'][1]['$id'], $documents['body']['documents'][0]['$id']); + $this->assertEquals($base['body']['documents'][2]['$id'], $documents['body']['documents'][1]['$id']); + $this->assertCount(2, $documents['body']['documents']); + + $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'orderAfter' => $base['body']['documents'][2]['$id'] + ]); + + $this->assertEmpty($documents['body']['documents']); + + /** + * Test with ASC order and after. + */ + $base = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'orderAttributes' => ['releaseYear'], + 'orderTypes' => ['ASC'], + ]); + + $this->assertEquals(1944, $base['body']['documents'][0]['releaseYear']); + $this->assertEquals(2017, $base['body']['documents'][1]['releaseYear']); + $this->assertEquals(2019, $base['body']['documents'][2]['releaseYear']); + $this->assertCount(3, $base['body']['documents']); + + $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'orderAttributes' => ['releaseYear'], + 'orderTypes' => ['ASC'], + 'orderAfter' => $base['body']['documents'][1]['$id'] + ]); + + $this->assertEquals($base['body']['documents'][2]['$id'], $documents['body']['documents'][0]['$id']); + $this->assertCount(1, $documents['body']['documents']); + + /** + * Test with DESC order and after. + */ + $base = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'orderAttributes' => ['releaseYear'], + 'orderTypes' => ['DESC'], + ]); + + $this->assertEquals(1944, $base['body']['documents'][2]['releaseYear']); + $this->assertEquals(2017, $base['body']['documents'][1]['releaseYear']); + $this->assertEquals(2019, $base['body']['documents'][0]['releaseYear']); + $this->assertCount(3, $base['body']['documents']); + + $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'orderAttributes' => ['releaseYear'], + 'orderTypes' => ['DESC'], + 'orderAfter' => $base['body']['documents'][1]['$id'] + ]); + + $this->assertEquals($base['body']['documents'][2]['$id'], $documents['body']['documents'][0]['$id']); + $this->assertCount(1, $documents['body']['documents']); + + /** + * Test after with unknown document. + */ + $documents = $this->client->call(Client::METHOD_GET, '/database/collections/' . $data['moviesId'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'orderAfter' => 'unknown' + ]); + + $this->assertEquals($documents['headers']['status-code'], 400); + + return []; + } + /** * @depends testCreateDocument */ diff --git a/tests/e2e/Services/Storage/StorageBase.php b/tests/e2e/Services/Storage/StorageBase.php index 508866b6a1..6a614c02eb 100644 --- a/tests/e2e/Services/Storage/StorageBase.php +++ b/tests/e2e/Services/Storage/StorageBase.php @@ -34,7 +34,7 @@ trait StorageBase */ return ['fileId' => $file['body']['$id']]; } - + /** * @depends testCreateFile */ @@ -169,7 +169,7 @@ trait StorageBase /** * Test for FAILURE */ - + return $data; } From fb1546cfccce3df14849338774e8e09b1ba86a89 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 6 Aug 2021 12:34:42 +0200 Subject: [PATCH 02/21] rename orderAfter to after --- app/controllers/api/database.php | 12 ++++++------ composer.lock | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 00d86b7007..283bb77e4d 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -1056,12 +1056,12 @@ App::get('/v1/database/collections/:collectionId/documents') ->param('queries', [], new ArrayList(new Text(128)), 'Array of query strings.', true) ->param('limit', 25, new Range(0, 100), 'Maximum number of documents to return in response. Use this value to manage pagination. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 900000000), 'Offset value. The default value is 0. Use this param to manage pagination.', true) + ->param('after', '', new UID(), 'ID of the document used to return documents listed after. Should be used for efficient pagination working with many documents.', true) ->param('orderAttributes', [], new ArrayList(new Text(128)), 'Array of attributes used to sort results.', true) ->param('orderTypes', [], new ArrayList(new WhiteList(['DESC', 'ASC'], true)), 'Array of order directions for sorting attribtues. Possible values are DESC for descending order, or ASC for ascending order.', true) - ->param('orderAfter', '', new UID(), 'ID of the document used to return documents listed after. Should be used for efficient pagination working with many documents.', true) ->inject('response') ->inject('dbForExternal') - ->action(function ($collectionId, $queries, $limit, $offset, $orderAttributes, $orderTypes, $orderAfter, $response, $dbForExternal) { + ->action(function ($collectionId, $queries, $limit, $offset, $after, $orderAttributes, $orderTypes, $response, $dbForExternal) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForExternal */ @@ -1087,15 +1087,15 @@ App::get('/v1/database/collections/:collectionId/documents') throw new Exception($validator->getDescription(), 400); } - if (!empty($orderAfter)) { - $orderAfterDocument = $dbForExternal->getDocument($collectionId, $orderAfter); + if (!empty($after)) { + $afterDocument = $dbForExternal->getDocument($collectionId, $after); - if ($orderAfterDocument->isEmpty()) { + if ($afterDocument->isEmpty()) { throw new Exception('Document for orderAfter not found', 400); } } - $documents = $dbForExternal->find($collectionId, $queries, $limit, $offset, $orderAttributes, $orderTypes, $orderAfterDocument ?? null); + $documents = $dbForExternal->find($collectionId, $queries, $limit, $offset, $orderAttributes, $orderTypes, $afterDocument ?? null); $response->dynamic(new Document([ 'sum' => \count($documents), diff --git a/composer.lock b/composer.lock index d670606358..a56ff12590 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c2bda60e7b774a0c813f52033a268c6c", + "content-hash": "7233a857d191a94d96aa5d0fa59d7bce", "packages": [ { "name": "adhocore/jwt", @@ -1988,12 +1988,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "c48b60884f63a547520ecef35714827af1870bc4" + "reference": "59d9d34164b6fb896bc43085a9a82a292b43473a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/c48b60884f63a547520ecef35714827af1870bc4", - "reference": "c48b60884f63a547520ecef35714827af1870bc4", + "url": "https://api.github.com/repos/utopia-php/database/zipball/59d9d34164b6fb896bc43085a9a82a292b43473a", + "reference": "59d9d34164b6fb896bc43085a9a82a292b43473a", "shasum": "" }, "require": { @@ -2042,9 +2042,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/main" + "source": "https://github.com/utopia-php/database/tree/0.6.1" }, - "time": "2021-08-04T16:53:44+00:00" + "time": "2021-08-05T17:19:16+00:00" }, { "name": "utopia-php/domains", From 99442bdfc399903866358518323c046f8c0fbf42 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 6 Aug 2021 12:36:32 +0200 Subject: [PATCH 03/21] revert utopia-php/database from dev to tag --- composer.json | 2 +- composer.lock | 18 ++++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/composer.json b/composer.json index 20f9624768..b3593e34d9 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "utopia-php/cache": "0.4.*", "utopia-php/cli": "0.11.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-main as 0.6.0", + "utopia-php/database": "0.6.*", "utopia-php/locale": "0.4.*", "utopia-php/registry": "0.5.*", "utopia-php/preloader": "0.2.*", diff --git a/composer.lock b/composer.lock index a56ff12590..9a8a5a4f19 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7233a857d191a94d96aa5d0fa59d7bce", + "content-hash": "c2bda60e7b774a0c813f52033a268c6c", "packages": [ { "name": "adhocore/jwt", @@ -1984,7 +1984,7 @@ }, { "name": "utopia-php/database", - "version": "dev-main", + "version": "0.6.1", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", @@ -2011,7 +2011,6 @@ "utopia-php/cli": "^0.11.0", "vimeo/psalm": "4.0.1" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -6255,18 +6254,9 @@ "time": "2015-12-17T08:42:14+00:00" } ], - "aliases": [ - { - "package": "utopia-php/database", - "version": "dev-main", - "alias": "0.6.0", - "alias_normalized": "0.6.0.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/database": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { From dac093c645647d03ce0d7a18d31602644b0ac972 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 6 Aug 2021 14:35:57 +0200 Subject: [PATCH 04/21] feat(database): add after pagination --- app/controllers/api/database.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 283bb77e4d..ff1edd8a33 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -180,17 +180,26 @@ App::get('/v1/database/collections') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 40000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('after', '', new UID(), 'ID of the collection used to return collection listed after. Should be used for efficient pagination working with many collections.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForExternal') - ->action(function ($search, $limit, $offset, $orderType, $response, $dbForExternal) { + ->action(function ($search, $limit, $offset, $after, $orderType, $response, $dbForExternal) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForExternal */ $queries = ($search) ? [new Query('name', Query::TYPE_SEARCH, [$search])] : []; + if (!empty($after)) { + $afterCollection = $dbForExternal->getDocument('collections', $after); + + if ($afterCollection->isEmpty()) { + throw new Exception('Collection for after not found', 400); + } + } + $response->dynamic(new Document([ - 'collections' => $dbForExternal->find(Database::COLLECTIONS, $queries, $limit, $offset, ['_id'], [$orderType]), + 'collections' => $dbForExternal->find(Database::COLLECTIONS, $queries, $limit, $offset, [], [$orderType], $afterCollection ?? null), 'sum' => $dbForExternal->count(Database::COLLECTIONS, $queries, APP_LIMIT_COUNT), ]), Response::MODEL_COLLECTION_LIST); }); From a49b12c542679556000637cea3a49b354f7096dd Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 6 Aug 2021 14:36:05 +0200 Subject: [PATCH 05/21] feat(functions): add after pagination --- app/controllers/api/functions.php | 45 ++++++++++++++++++++++++------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 8d2f28a87a..4adfd81fee 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -85,17 +85,26 @@ App::get('/v1/functions') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('after', '', new UID(), 'ID of the function used to return functions listed after. Should be used for efficient pagination working with many functions.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForInternal') - ->action(function ($search, $limit, $offset, $orderType, $response, $dbForInternal) { + ->action(function ($search, $limit, $offset, $after, $orderType, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForInternal */ $queries = ($search) ? [new Query('name', Query::TYPE_SEARCH, [$search])] : []; + if (!empty($after)) { + $afterFunction = $dbForInternal->getDocument('functions', $after); + + if ($afterFunction->isEmpty()) { + throw new Exception('Function for after not found', 400); + } + } + $response->dynamic(new Document([ - 'functions' => $dbForInternal->find('functions', $queries, $limit, $offset, ['_id'], [$orderType]), + 'functions' => $dbForInternal->find('functions', $queries, $limit, $offset, [], [$orderType], $afterFunction ?? null), 'sum' => $dbForInternal->count('functions', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_FUNCTION_LIST); }); @@ -502,10 +511,11 @@ App::get('/v1/functions/:functionId/tags') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('after', '', new UID(), 'ID of the tag used to return tags listed after. Should be used for efficient pagination working with many tags.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForInternal') - ->action(function ($functionId, $search, $limit, $offset, $orderType, $response, $dbForInternal) { + ->action(function ($functionId, $search, $limit, $offset, $after, $orderType, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForInternal */ @@ -516,8 +526,16 @@ App::get('/v1/functions/:functionId/tags') } $queries[] = new Query('functionId', Query::TYPE_EQUAL, [$function->getId()]); - - $results = $dbForInternal->find('tags', $queries, $limit, $offset, ['_id'], [$orderType]); + + if (!empty($after)) { + $afterTag = $dbForInternal->getDocument('tags', $after); + + if ($afterTag->isEmpty()) { + throw new Exception('Tag for after not found', 400); + } + } + + $results = $dbForInternal->find('tags', $queries, $limit, $offset, [], [$orderType], $afterTag ?? null); $sum = $dbForInternal->count('tags', $queries, APP_LIMIT_COUNT); $response->dynamic(new Document([ @@ -743,12 +761,13 @@ App::get('/v1/functions/:functionId/executions') ->param('functionId', '', new UID(), 'Function unique ID.') ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('after', '', new UID(), 'ID of the execution used to return executions listed after. Should be used for efficient pagination working with many executions.', true) ->inject('response') ->inject('dbForInternal') - ->action(function ($functionId, $limit, $offset, $response, $dbForInternal) { + ->action(function ($functionId, $limit, $offset, $after, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForInternal */ - + Authorization::disable(); $function = $dbForInternal->getDocument('functions', $functionId); Authorization::reset(); @@ -757,10 +776,18 @@ App::get('/v1/functions/:functionId/executions') throw new Exception('Function not found', 404); } + if (!empty($after)) { + $afterExecution = $dbForInternal->getDocument('executions', $after); + + if ($afterExecution->isEmpty()) { + throw new Exception('Execution for after not found', 400); + } + } + $results = $dbForInternal->find('executions', [ new Query('functionId', Query::TYPE_EQUAL, [$function->getId()]), - ], $limit, $offset, ['_id'], [Database::ORDER_DESC]); - + ], $limit, $offset, [], [Database::ORDER_DESC], $afterExecution ?? null); + $sum = $dbForInternal->count('executions', [ new Query('functionId', Query::TYPE_EQUAL, [$function->getId()]), ], APP_LIMIT_COUNT); From ca9dafddae229532d2a6d9e4aa26273e5db81ad8 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 6 Aug 2021 14:36:17 +0200 Subject: [PATCH 06/21] feat(projects): add after pagination --- app/controllers/api/projects.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 44fa614adb..030ec3a76e 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -166,16 +166,25 @@ App::get('/v1/projects') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('after', '', new UID(), 'ID of the project used to return projects listed after. Should be used for efficient pagination working with many projects.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForConsole') - ->action(function ($search, $limit, $offset, $orderType, $response, $dbForConsole) { + ->action(function ($search, $limit, $offset, $after, $orderType, $response, $dbForConsole) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForConsole */ $queries = ($search) ? [new Query('name', Query::TYPE_SEARCH, [$search])] : []; - $results = $dbForConsole->find('projects', $queries, $limit, $offset, ['_id'], [$orderType]); + if (!empty($after)) { + $afterProject = $dbForConsole->getDocument('projects', $after); + + if ($afterProject->isEmpty()) { + throw new Exception('Project for after not found', 400); + } + } + + $results = $dbForConsole->find('projects', $queries, $limit, $offset, [], [$orderType], $afterProject ?? null); $sum = $dbForConsole->count('projects', $queries, APP_LIMIT_COUNT); $response->dynamic(new Document([ From 8e6c415d01f88474cd1244db721c5b40ee8aa42d Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 6 Aug 2021 14:36:27 +0200 Subject: [PATCH 07/21] feat(storage): add after pagination --- app/controllers/api/storage.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 552b0a9df1..cf7ec10fbd 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -168,17 +168,26 @@ App::get('/v1/storage/files') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('after', '', new UID(), 'ID of the file used to return files listed after. Should be used for efficient pagination working with many files.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForInternal') - ->action(function ($search, $limit, $offset, $orderType, $response, $dbForInternal) { + ->action(function ($search, $limit, $offset, $after, $orderType, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForInternal */ $queries = ($search) ? [new Query('name', Query::TYPE_SEARCH, $search)] : []; + if (!empty($after)) { + $afterFile = $dbForInternal->getDocument('files', $after); + + if ($afterFile->isEmpty()) { + throw new Exception('File for after not found', 400); + } + } + $response->dynamic(new Document([ - 'files' => $dbForInternal->find('files', $queries, $limit, $offset, ['_id'], [$orderType]), + 'files' => $dbForInternal->find('files', $queries, $limit, $offset, [], [$orderType], $afterFile ?? null), 'sum' => $dbForInternal->count('files', $queries, APP_LIMIT_COUNT), ]), Response::MODEL_FILE_LIST); }); From 79971330f2b739a338b2815f517509e54fa87ae1 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 6 Aug 2021 14:36:35 +0200 Subject: [PATCH 08/21] feat(teams): add after pagination --- app/controllers/api/teams.php | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index b9015267a7..ee08f8cae1 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -97,16 +97,25 @@ App::get('/v1/teams') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('after', '', new UID(), 'ID of the team used to return teams listed after. Should be used for efficient pagination working with many teams.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForInternal') - ->action(function ($search, $limit, $offset, $orderType, $response, $dbForInternal) { + ->action(function ($search, $limit, $offset, $after, $orderType, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForInternal */ $queries = ($search) ? [new Query('name', Query::TYPE_SEARCH, [$search])] : []; - $results = $dbForInternal->find('teams', $queries, $limit, $offset, ['_id'], [$orderType]); + if (!empty($after)) { + $afterTeam = $dbForInternal->getDocument('teams', $after); + + if ($afterTeam->isEmpty()) { + throw new Exception('Team for after not found', 400); + } + } + + $results = $dbForInternal->find('teams', $queries, $limit, $offset, [], [$orderType], $afterTeam ?? null); $sum = $dbForInternal->count('teams', $queries, APP_LIMIT_COUNT); $response->dynamic(new Document([ @@ -413,10 +422,11 @@ App::get('/v1/teams/:teamId/memberships') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('after', '', new UID(), 'ID of the file used to return files listed after. Should be used for efficient pagination working with many files.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForInternal') - ->action(function ($teamId, $search, $limit, $offset, $orderType, $response, $dbForInternal) { + ->action(function ($teamId, $search, $limit, $offset, $after, $orderType, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForInternal */ @@ -426,7 +436,15 @@ App::get('/v1/teams/:teamId/memberships') throw new Exception('Team not found', 404); } - $memberships = $dbForInternal->find('memberships', [new Query('teamId', Query::TYPE_EQUAL, [$teamId])], $limit, $offset, ['_id'], [$orderType]); + if (!empty($after)) { + $afterMembership = $dbForInternal->getDocument('memberships', $after); + + if ($afterMembership->isEmpty()) { + throw new Exception('Membership for after not found', 400); + } + } + + $memberships = $dbForInternal->find('memberships', [new Query('teamId', Query::TYPE_EQUAL, [$teamId])], $limit, $offset, [], [$orderType], $afterMembership ?? null); $sum = $dbForInternal->count('memberships', [new Query('teamId', Query::TYPE_EQUAL, [$teamId])], APP_LIMIT_COUNT); $users = []; From af570076122eba98863d1a40814620a2bffd100e Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 6 Aug 2021 14:36:48 +0200 Subject: [PATCH 09/21] feat(users): add after pagination --- app/controllers/api/users.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index 8c30b8b1c4..bff1373f3e 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -81,14 +81,23 @@ App::get('/v1/users') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) + ->param('after', '', new UID(), 'ID of the user used to return users listed after. Should be used for efficient pagination working with many users.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForInternal') - ->action(function ($search, $limit, $offset, $orderType, $response, $dbForInternal) { + ->action(function ($search, $limit, $offset, $after, $orderType, $response, $dbForInternal) { /** @var Appwrite\Utopia\Response $response */ /** @var Utopia\Database\Database $dbForInternal */ - $results = $dbForInternal->find('users', [], $limit, $offset, ['_id'], [$orderType]); + if (!empty($after)) { + $afterUser = $dbForInternal->getDocument('users', $after); + + if ($afterUser->isEmpty()) { + throw new Exception('User for after not found', 400); + } + } + + $results = $dbForInternal->find('users', [], $limit, $offset, [], [$orderType], $afterUser ?? null); $sum = $dbForInternal->count('users', [], APP_LIMIT_COUNT); $response->dynamic(new Document([ From 2a540ff7999dde8c70a0473a48175d30e2d7f6d0 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 9 Aug 2021 14:33:16 +0200 Subject: [PATCH 10/21] tests(functions): after paginatio tests --- composer.json | 2 +- composer.lock | 29 ++++++---- .../Functions/FunctionsCustomClientTest.php | 57 +++++++++++++++---- .../Functions/FunctionsCustomServerTest.php | 47 +++++++++++++-- 4 files changed, 106 insertions(+), 29 deletions(-) diff --git a/composer.json b/composer.json index b3593e34d9..3bb8025eec 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "utopia-php/cache": "0.4.*", "utopia-php/cli": "0.11.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "0.6.*", + "utopia-php/database": "dev-fix-after-pagination-with-order as 0.6.1", "utopia-php/locale": "0.4.*", "utopia-php/registry": "0.5.*", "utopia-php/preloader": "0.2.*", diff --git a/composer.lock b/composer.lock index c528f39540..141427bebe 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c2bda60e7b774a0c813f52033a268c6c", + "content-hash": "e79cbd92bfd81499b5111bf3329e2318", "packages": [ { "name": "adhocore/jwt", @@ -1984,16 +1984,16 @@ }, { "name": "utopia-php/database", - "version": "0.6.1", + "version": "dev-fix-after-pagination-with-order", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "59d9d34164b6fb896bc43085a9a82a292b43473a" + "reference": "2179adfdeb385864cebc86e2b063929dcfbf77e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/59d9d34164b6fb896bc43085a9a82a292b43473a", - "reference": "59d9d34164b6fb896bc43085a9a82a292b43473a", + "url": "https://api.github.com/repos/utopia-php/database/zipball/2179adfdeb385864cebc86e2b063929dcfbf77e6", + "reference": "2179adfdeb385864cebc86e2b063929dcfbf77e6", "shasum": "" }, "require": { @@ -2041,9 +2041,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.6.1" + "source": "https://github.com/utopia-php/database/tree/fix-after-pagination-with-order" }, - "time": "2021-08-05T17:19:16+00:00" + "time": "2021-08-09T12:01:35+00:00" }, { "name": "utopia-php/domains", @@ -6254,9 +6254,18 @@ "time": "2015-12-17T08:42:14+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/database", + "version": "dev-fix-after-pagination-with-order", + "alias": "0.6.1", + "alias_normalized": "0.6.1.0" + } + ], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "utopia-php/database": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -6278,5 +6287,5 @@ "platform-overrides": { "php": "8.0" }, - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.0.0" } diff --git a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php index 1ebc654892..86f6fde482 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomClientTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomClientTest.php @@ -112,7 +112,7 @@ class FunctionsCustomClientTest extends Scope ]); $this->assertEquals(201, $execution['headers']['status-code']); - + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$function['body']['$id'].'/executions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -121,7 +121,7 @@ class FunctionsCustomClientTest extends Scope ]); $this->assertEquals(401, $execution['headers']['status-code']); - + return []; } @@ -187,7 +187,7 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals(201, $execution['headers']['status-code']); $executionId = $execution['body']['$id'] ?? ''; - + sleep(10); $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions/'.$executionId, [ @@ -212,19 +212,52 @@ class FunctionsCustomClientTest extends Scope $this->assertEquals($this->getUser()['$id'], $output['APPWRITE_FUNCTION_USER_ID']); $this->assertNotEmpty($output['APPWRITE_FUNCTION_JWT']); - $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ + return [ + 'functionId' => $functionId + ]; + } + + /** + * @depends testCreateCustomExecution + */ + public function testListExecutions(array $data) + { + $functionId = $data['functionId']; + $projectId = $this->getProject()['$id']; + $apikey = $this->getProject()['apiKey']; + + $execution = $this->client->call(Client::METHOD_POST, '/functions/'.$functionId.'/executions', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + ], $this->getHeaders()), [ + 'data' => 'foobar', + ]); + + $this->assertEquals(201, $execution['headers']['status-code']); + + sleep(10); + + $base = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ 'content-type' => 'application/json', 'x-appwrite-project' => $projectId, 'x-appwrite-key' => $apikey, ]); - $this->assertEquals(200, $executions['headers']['status-code']); - $this->assertCount(1, $executions['body']['executions']); - $this->assertEquals('completed', $executions['body']['executions'][0]['status']); - $this->assertStringContainsString('foobar', $executions['body']['executions'][0]['stdout']); - $this->assertStringContainsString($this->getUser()['$id'], $executions['body']['executions'][0]['stdout']); - - return []; - } + $this->assertEquals(200, $base['headers']['status-code']); + $this->assertCount(2, $base['body']['executions']); + $this->assertEquals('completed', $base['body']['executions'][0]['status']); + $this->assertEquals('completed', $base['body']['executions'][1]['status']); + $executions = $this->client->call(Client::METHOD_GET, '/functions/'.$functionId.'/executions', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $projectId, + 'x-appwrite-key' => $apikey, + ], [ + 'after' => $base['body']['executions'][0]['$id'] + ]); + + $this->assertCount(1, $executions['body']['executions']); + $this->assertEquals($base['body']['executions'][1]['$id'], $executions['body']['executions'][0]['$id']); + + } } diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index b78f9d42ff..cb820b45c3 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -77,16 +77,51 @@ class FunctionsCustomServerTest extends Scope /** * Test for SUCCESS */ - $function = $this->client->call(Client::METHOD_GET, '/functions', array_merge([ + + $response = $this->client->call(Client::METHOD_POST, '/functions', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'functionId' => 'unique()', + 'name' => 'Test 2', + 'runtime' => 'php-8.0', + 'vars' => [ + 'funcKey1' => 'funcValue1', + 'funcKey2' => 'funcValue2', + 'funcKey3' => 'funcValue3', + ], + 'events' => [ + 'account.create', + 'account.delete', + ], + 'schedule' => '0 0 1 1 *', + 'timeout' => 10, + ]); + $this->assertNotEmpty($response['body']['$id']); + + $functions = $this->client->call(Client::METHOD_GET, '/functions', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); - $this->assertEquals($function['headers']['status-code'], 200); - $this->assertEquals($function['body']['sum'], 1); - $this->assertIsArray($function['body']['functions']); - $this->assertCount(1, $function['body']['functions']); - $this->assertEquals($function['body']['functions'][0]['name'], 'Test'); + $this->assertEquals($functions['headers']['status-code'], 200); + $this->assertEquals($functions['body']['sum'], 2); + $this->assertIsArray($functions['body']['functions']); + $this->assertCount(2, $functions['body']['functions']); + $this->assertEquals($functions['body']['functions'][0]['name'], 'Test'); + $this->assertEquals($functions['body']['functions'][1]['name'], 'Test 2'); + + $response = $this->client->call(Client::METHOD_GET, '/functions', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'after' => $functions['body']['functions'][0]['$id'] + ]); + + $this->assertEquals($response['headers']['status-code'], 200); + $this->assertCount(1, $response['body']['functions']); + $this->assertEquals($response['body']['functions'][0]['name'], 'Test 2'); + return $data; } From d85997e33ec2efd3c77b504a7a5f5019a84618c8 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 9 Aug 2021 14:47:16 +0200 Subject: [PATCH 11/21] tests(projects): after pagination tests --- .../Projects/ProjectsConsoleClientTest.php | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index fd5b708797..4d83efb416 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -63,7 +63,7 @@ class ProjectsConsoleClientTest extends Scope ]); $this->assertEquals(400, $response['headers']['status-code']); - + $response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -97,6 +97,60 @@ class ProjectsConsoleClientTest extends Scope $this->assertEquals($id, $response['body']['projects'][0]['$id']); $this->assertEquals('Project Test', $response['body']['projects'][0]['name']); + /** + * Test after pagination + */ + $team = $this->client->call(Client::METHOD_POST, '/teams', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'teamId' => 'unique()', + 'name' => 'Project Test 2', + ]); + + $this->assertEquals(201, $team['headers']['status-code']); + $this->assertEquals('Project Test 2', $team['body']['name']); + $this->assertNotEmpty($team['body']['$id']); + + $response = $this->client->call(Client::METHOD_POST, '/projects', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'projectId' => 'unique()', + 'name' => 'Project Test 2', + 'teamId' => $team['body']['$id'], + ]); + + $this->assertEquals(201, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']['$id']); + $this->assertEquals('Project Test 2', $response['body']['name']); + $this->assertEquals($team['body']['$id'], $response['body']['teamId']); + $this->assertArrayHasKey('platforms', $response['body']); + $this->assertArrayHasKey('webhooks', $response['body']); + $this->assertArrayHasKey('keys', $response['body']); + + $response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']); + $this->assertCount(2, $response['body']['projects']); + $this->assertEquals('Project Test', $response['body']['projects'][0]['name']); + $this->assertEquals('Project Test 2', $response['body']['projects'][1]['name']); + + $response = $this->client->call(Client::METHOD_GET, '/projects', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()),[ + 'after' => $response['body']['projects'][0]['$id'] + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertNotEmpty($response['body']); + $this->assertCount(1, $response['body']['projects']); + $this->assertEquals('Project Test 2', $response['body']['projects'][0]['name']); /** * Test for FAILURE */ From 0b3bf500748b61a4125963da3ffe01e8f0f465ba Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 9 Aug 2021 14:55:30 +0200 Subject: [PATCH 12/21] tests(users): after pagination tests --- tests/e2e/Services/Users/UsersBase.php | 36 ++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/e2e/Services/Users/UsersBase.php b/tests/e2e/Services/Users/UsersBase.php index e5907105e2..b35f355c90 100644 --- a/tests/e2e/Services/Users/UsersBase.php +++ b/tests/e2e/Services/Users/UsersBase.php @@ -50,6 +50,42 @@ trait UsersBase return ['userId' => $user['body']['$id']]; } + /** + * @depends testCreateUser + */ + public function testListUsers(array $data): void + { + /** + * Test for SUCCESS + */ + $response = $this->client->call(Client::METHOD_GET, '/users', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals($response['headers']['status-code'], 200); + $this->assertNotEmpty($response['body']); + $this->assertNotEmpty($response['body']['users']); + $this->assertCount(2, $response['body']['users']); + + $this->assertEquals($response['body']['users'][0]['$id'], $data['userId']); + $this->assertEquals($response['body']['users'][1]['$id'], 'user1'); + + $response = $this->client->call(Client::METHOD_GET, '/users', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'after' => $response['body']['users'][0]['$id'] + ]); + + $this->assertEquals($response['headers']['status-code'], 200); + $this->assertNotEmpty($response['body']); + $this->assertNotEmpty($response['body']['users']); + $this->assertCount(1, $response['body']['users']); + + $this->assertEquals($response['body']['users'][0]['$id'], 'user1'); + } + /** * @depends testCreateUser */ From 69e5194dd6f139a7d15ff5cfbb5c9579759326cf Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 9 Aug 2021 15:04:14 +0200 Subject: [PATCH 13/21] tests(teams): after pagination tests --- tests/e2e/Services/Teams/TeamsBase.php | 32 ++++++++++++++++++-- tests/e2e/Services/Teams/TeamsBaseClient.php | 29 ++++++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/tests/e2e/Services/Teams/TeamsBase.php b/tests/e2e/Services/Teams/TeamsBase.php index 3e4a4971fa..6c1ebbe36a 100644 --- a/tests/e2e/Services/Teams/TeamsBase.php +++ b/tests/e2e/Services/Teams/TeamsBase.php @@ -133,7 +133,7 @@ trait TeamsBase $this->assertGreaterThan(0, $response['body']['sum']); $this->assertIsInt($response['body']['sum']); $this->assertCount(2, $response['body']['teams']); - + $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -145,7 +145,7 @@ trait TeamsBase $this->assertGreaterThan(0, $response['body']['sum']); $this->assertIsInt($response['body']['sum']); $this->assertGreaterThan(2, $response['body']['teams']); - + $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -158,7 +158,7 @@ trait TeamsBase $this->assertIsInt($response['body']['sum']); $this->assertCount(1, $response['body']['teams']); $this->assertEquals('Manchester United', $response['body']['teams'][0]['name']); - + $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], @@ -172,6 +172,32 @@ trait TeamsBase $this->assertCount(1, $response['body']['teams']); $this->assertEquals('Manchester United', $response['body']['teams'][0]['name']); + $teams = $this->client->call(Client::METHOD_GET, '/teams', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'limit' => 2, + ]); + + $this->assertEquals(200, $teams['headers']['status-code']); + $this->assertGreaterThan(0, $teams['body']['sum']); + $this->assertIsInt($teams['body']['sum']); + $this->assertCount(2, $teams['body']['teams']); + + $response = $this->client->call(Client::METHOD_GET, '/teams', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'limit' => 1, + 'after' => $teams['body']['teams'][0]['$id'] + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertGreaterThan(0, $response['body']['sum']); + $this->assertIsInt($response['body']['sum']); + $this->assertCount(1, $response['body']['teams']); + $this->assertEquals($teams['body']['teams'][1]['$id'], $response['body']['teams'][0]['$id']); + /** * Test for FAILURE */ diff --git a/tests/e2e/Services/Teams/TeamsBaseClient.php b/tests/e2e/Services/Teams/TeamsBaseClient.php index ad57737297..90964c4f6e 100644 --- a/tests/e2e/Services/Teams/TeamsBaseClient.php +++ b/tests/e2e/Services/Teams/TeamsBaseClient.php @@ -138,6 +138,35 @@ trait TeamsBaseClient ]; } + /** + * @depends testCreateTeamMembership + */ + public function testListTeamMemberships($data): void + { + $memberships = $this->client->call(Client::METHOD_GET, '/teams/'.$data['teamUid'].'/memberships', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $memberships['headers']['status-code']); + $this->assertIsInt($memberships['body']['sum']); + $this->assertNotEmpty($memberships['body']['memberships']); + $this->assertCount(2, $memberships['body']['memberships']); + + $response = $this->client->call(Client::METHOD_GET, '/teams/'.$data['teamUid'].'/memberships', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'after' => $memberships['body']['memberships'][0]['$id'] + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertIsInt($response['body']['sum']); + $this->assertNotEmpty($response['body']['memberships']); + $this->assertCount(1, $response['body']['memberships']); + $this->assertEquals($memberships['body']['memberships'][1]['$id'], $response['body']['memberships'][0]['$id']); + } + /** * @depends testCreateTeamMembership */ From ae28fcf4f97932d4fc94e816a6e1099bb6ec63ab Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 9 Aug 2021 15:08:44 +0200 Subject: [PATCH 14/21] tests(storage): after pagination tests --- tests/e2e/Services/Storage/StorageBase.php | 36 ++++++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/tests/e2e/Services/Storage/StorageBase.php b/tests/e2e/Services/Storage/StorageBase.php index 329047b8a3..57a5ee6972 100644 --- a/tests/e2e/Services/Storage/StorageBase.php +++ b/tests/e2e/Services/Storage/StorageBase.php @@ -158,14 +158,44 @@ trait StorageBase /** * Test for SUCCESS */ + $file = $this->client->call(Client::METHOD_POST, '/storage/files', array_merge([ + 'content-type' => 'multipart/form-data', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'fileId' => 'unique()', + 'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'), + 'read' => ['role:all'], + 'write' => ['role:all'], + ]); + + $this->assertEquals($file['headers']['status-code'], 201); + $this->assertNotEmpty($file['body']['$id']); + $this->assertIsInt($file['body']['dateCreated']); + $this->assertEquals('logo.png', $file['body']['name']); + $this->assertEquals('image/png', $file['body']['mimeType']); + $this->assertEquals(47218, $file['body']['sizeOriginal']); + $files = $this->client->call(Client::METHOD_GET, '/storage/files', array_merge([ 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); + ], $this->getHeaders()), [ + 'limit' => 2 + ]); $this->assertEquals(200, $files['headers']['status-code']); - $this->assertGreaterThan(0, $files['body']['sum']); - $this->assertGreaterThan(0, count($files['body']['files'])); + $this->assertCount(2, $files['body']['files']); + + $response = $this->client->call(Client::METHOD_GET, '/storage/files', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'limit' => 1, + 'after' => $files['body']['files'][0]['$id'] + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals($files['body']['files'][1]['$id'], $response['body']['files'][0]['$id']); + $this->assertCount(1, $response['body']['files']); /** * Test for FAILURE From 40ecd0688aae3f79b22e9ae7c96b53a48a960286 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 9 Aug 2021 15:12:09 +0200 Subject: [PATCH 15/21] chore(composer): update --- composer.json | 2 +- composer.lock | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 3bb8025eec..4a5685b4c9 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "utopia-php/cache": "0.4.*", "utopia-php/cli": "0.11.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-fix-after-pagination-with-order as 0.6.1", + "utopia-php/database": "dev-main as 0.6.1", "utopia-php/locale": "0.4.*", "utopia-php/registry": "0.5.*", "utopia-php/preloader": "0.2.*", diff --git a/composer.lock b/composer.lock index 141427bebe..35275b9603 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e79cbd92bfd81499b5111bf3329e2318", + "content-hash": "6b3c314f3faa9c3aff868eaf7f6f3cbb", "packages": [ { "name": "adhocore/jwt", @@ -1984,16 +1984,16 @@ }, { "name": "utopia-php/database", - "version": "dev-fix-after-pagination-with-order", + "version": "dev-main", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "2179adfdeb385864cebc86e2b063929dcfbf77e6" + "reference": "272bb30d641792fb82f68adcd002be3bd34c5461" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/2179adfdeb385864cebc86e2b063929dcfbf77e6", - "reference": "2179adfdeb385864cebc86e2b063929dcfbf77e6", + "url": "https://api.github.com/repos/utopia-php/database/zipball/272bb30d641792fb82f68adcd002be3bd34c5461", + "reference": "272bb30d641792fb82f68adcd002be3bd34c5461", "shasum": "" }, "require": { @@ -2011,6 +2011,7 @@ "utopia-php/cli": "^0.11.0", "vimeo/psalm": "4.0.1" }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -2041,9 +2042,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/fix-after-pagination-with-order" + "source": "https://github.com/utopia-php/database/tree/main" }, - "time": "2021-08-09T12:01:35+00:00" + "time": "2021-08-09T13:01:43+00:00" }, { "name": "utopia-php/domains", @@ -6257,7 +6258,7 @@ "aliases": [ { "package": "utopia-php/database", - "version": "dev-fix-after-pagination-with-order", + "version": "dev-main", "alias": "0.6.1", "alias_normalized": "0.6.1.0" } From f7be5cd7b1a5b30111590cfde532766ccbe3cea7 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 9 Aug 2021 16:54:10 +0200 Subject: [PATCH 16/21] tests(database): after pagination tests --- tests/e2e/Services/Database/DatabaseBase.php | 10 +-- .../Database/DatabaseCustomServerTest.php | 80 +++++++++++++++++++ 2 files changed, 85 insertions(+), 5 deletions(-) diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index aa246706f1..6ea9a885e0 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -316,7 +316,7 @@ trait DatabaseBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'orderAfter' => $base['body']['documents'][0]['$id'] + 'after' => $base['body']['documents'][0]['$id'] ]); $this->assertEquals($base['body']['documents'][1]['$id'], $documents['body']['documents'][0]['$id']); @@ -327,7 +327,7 @@ trait DatabaseBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'orderAfter' => $base['body']['documents'][2]['$id'] + 'after' => $base['body']['documents'][2]['$id'] ]); $this->assertEmpty($documents['body']['documents']); @@ -354,7 +354,7 @@ trait DatabaseBase ], $this->getHeaders()), [ 'orderAttributes' => ['releaseYear'], 'orderTypes' => ['ASC'], - 'orderAfter' => $base['body']['documents'][1]['$id'] + 'after' => $base['body']['documents'][1]['$id'] ]); $this->assertEquals($base['body']['documents'][2]['$id'], $documents['body']['documents'][0]['$id']); @@ -382,7 +382,7 @@ trait DatabaseBase ], $this->getHeaders()), [ 'orderAttributes' => ['releaseYear'], 'orderTypes' => ['DESC'], - 'orderAfter' => $base['body']['documents'][1]['$id'] + 'after' => $base['body']['documents'][1]['$id'] ]); $this->assertEquals($base['body']['documents'][2]['$id'], $documents['body']['documents'][0]['$id']); @@ -395,7 +395,7 @@ trait DatabaseBase 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders()), [ - 'orderAfter' => 'unknown' + 'after' => 'unknown' ]); $this->assertEquals($documents['headers']['status-code'], 400); diff --git a/tests/e2e/Services/Database/DatabaseCustomServerTest.php b/tests/e2e/Services/Database/DatabaseCustomServerTest.php index dea3b588c7..68cc4ee44e 100644 --- a/tests/e2e/Services/Database/DatabaseCustomServerTest.php +++ b/tests/e2e/Services/Database/DatabaseCustomServerTest.php @@ -13,6 +13,86 @@ class DatabaseCustomServerTest extends Scope use ProjectCustom; use SideServer; + public function testListCollections() + { + /** + * Test for SUCCESS + */ + $test1 = $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'name' => 'Test 1', + 'collectionId' => 'first', + 'read' => ['role:all'], + 'write' => ['role:all'], + ]); + + $test2 = $this->client->call(Client::METHOD_POST, '/database/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'name' => 'Test 2', + 'collectionId' => 'second', + 'read' => ['role:all'], + 'write' => ['role:all'], + ]); + + $collections = $this->client->call(Client::METHOD_GET, '/database/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(2, $collections['body']['sum']); + $this->assertEquals($test1['body']['$id'], $collections['body']['collections'][0]['$id']); + $this->assertEquals($test2['body']['$id'], $collections['body']['collections'][1]['$id']); + + /** + * Test for Order + */ + $base = array_reverse($collections['body']['collections']); + $collections = $this->client->call(Client::METHOD_GET, '/database/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'orderType' => 'DESC' + ]); + + $this->assertEquals(2, $collections['body']['sum']); + $this->assertEquals($base[0]['$id'], $collections['body']['collections'][0]['$id']); + $this->assertEquals($base[1]['$id'], $collections['body']['collections'][1]['$id']); + + /** + * Test for After + */ + $base = $this->client->call(Client::METHOD_GET, '/database/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $collections = $this->client->call(Client::METHOD_GET, '/database/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'after' => $base['body']['collections'][0]['$id'] + ]); + + $this->assertCount(1, $collections['body']['collections']); + $this->assertEquals($base['body']['collections'][1]['$id'], $collections['body']['collections'][0]['$id']); + + $collections = $this->client->call(Client::METHOD_GET, '/database/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'after' => $base['body']['collections'][1]['$id'] + ]); + + $this->assertCount(0, $collections['body']['collections']); + $this->assertEmpty($collections['body']['collections']); + } + public function testDeleteCollection() { /** From 26c27ff876196e9398d33c5fa5fc437cecc7dfce Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 9 Aug 2021 16:54:27 +0200 Subject: [PATCH 17/21] add temporary dependency from branch --- composer.json | 2 +- composer.lock | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index 4a5685b4c9..567f4a4fbd 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "utopia-php/cache": "0.4.*", "utopia-php/cli": "0.11.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-main as 0.6.1", + "utopia-php/database": "dev-fix-update-document-cache as 0.6.1", "utopia-php/locale": "0.4.*", "utopia-php/registry": "0.5.*", "utopia-php/preloader": "0.2.*", diff --git a/composer.lock b/composer.lock index 35275b9603..4c8eab6db0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6b3c314f3faa9c3aff868eaf7f6f3cbb", + "content-hash": "e2cbe858dd5e1a6575d4631e2886e1e3", "packages": [ { "name": "adhocore/jwt", @@ -1984,16 +1984,16 @@ }, { "name": "utopia-php/database", - "version": "dev-main", + "version": "dev-fix-update-document-cache", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "272bb30d641792fb82f68adcd002be3bd34c5461" + "reference": "13cafc216c53e22cedadc42aa9e4c9297f07c4de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/272bb30d641792fb82f68adcd002be3bd34c5461", - "reference": "272bb30d641792fb82f68adcd002be3bd34c5461", + "url": "https://api.github.com/repos/utopia-php/database/zipball/13cafc216c53e22cedadc42aa9e4c9297f07c4de", + "reference": "13cafc216c53e22cedadc42aa9e4c9297f07c4de", "shasum": "" }, "require": { @@ -2011,7 +2011,6 @@ "utopia-php/cli": "^0.11.0", "vimeo/psalm": "4.0.1" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -2042,9 +2041,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/main" + "source": "https://github.com/utopia-php/database/tree/fix-update-document-cache" }, - "time": "2021-08-09T13:01:43+00:00" + "time": "2021-08-09T14:46:11+00:00" }, { "name": "utopia-php/domains", @@ -6258,7 +6257,7 @@ "aliases": [ { "package": "utopia-php/database", - "version": "dev-main", + "version": "dev-fix-update-document-cache", "alias": "0.6.1", "alias_normalized": "0.6.1.0" } From a2372d2bad9bcae96743d93c0216ab41ffa402a5 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Mon, 9 Aug 2021 17:56:58 +0200 Subject: [PATCH 18/21] chore(composer): update --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index 4c8eab6db0..1cb2819aae 100644 --- a/composer.lock +++ b/composer.lock @@ -1988,12 +1988,12 @@ "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "13cafc216c53e22cedadc42aa9e4c9297f07c4de" + "reference": "3672e3f5d70457ba4c46980b765c772bdf898e04" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/13cafc216c53e22cedadc42aa9e4c9297f07c4de", - "reference": "13cafc216c53e22cedadc42aa9e4c9297f07c4de", + "url": "https://api.github.com/repos/utopia-php/database/zipball/3672e3f5d70457ba4c46980b765c772bdf898e04", + "reference": "3672e3f5d70457ba4c46980b765c772bdf898e04", "shasum": "" }, "require": { @@ -2043,7 +2043,7 @@ "issues": "https://github.com/utopia-php/database/issues", "source": "https://github.com/utopia-php/database/tree/fix-update-document-cache" }, - "time": "2021-08-09T14:46:11+00:00" + "time": "2021-08-09T15:56:38+00:00" }, { "name": "utopia-php/domains", From 7aa712ed7cb4c1c1d791b9c2b7a3fd5502913dd2 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Tue, 10 Aug 2021 10:42:45 +0200 Subject: [PATCH 19/21] chore(composer): update --- composer.json | 2 +- composer.lock | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/composer.json b/composer.json index 567f4a4fbd..4a5685b4c9 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "utopia-php/cache": "0.4.*", "utopia-php/cli": "0.11.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-fix-update-document-cache as 0.6.1", + "utopia-php/database": "dev-main as 0.6.1", "utopia-php/locale": "0.4.*", "utopia-php/registry": "0.5.*", "utopia-php/preloader": "0.2.*", diff --git a/composer.lock b/composer.lock index 1cb2819aae..844a746398 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e2cbe858dd5e1a6575d4631e2886e1e3", + "content-hash": "6b3c314f3faa9c3aff868eaf7f6f3cbb", "packages": [ { "name": "adhocore/jwt", @@ -1984,16 +1984,16 @@ }, { "name": "utopia-php/database", - "version": "dev-fix-update-document-cache", + "version": "dev-main", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "3672e3f5d70457ba4c46980b765c772bdf898e04" + "reference": "bd765cd67e042defb8d0a15ef9a400784d6beb24" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/3672e3f5d70457ba4c46980b765c772bdf898e04", - "reference": "3672e3f5d70457ba4c46980b765c772bdf898e04", + "url": "https://api.github.com/repos/utopia-php/database/zipball/bd765cd67e042defb8d0a15ef9a400784d6beb24", + "reference": "bd765cd67e042defb8d0a15ef9a400784d6beb24", "shasum": "" }, "require": { @@ -2011,6 +2011,7 @@ "utopia-php/cli": "^0.11.0", "vimeo/psalm": "4.0.1" }, + "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -2041,9 +2042,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/fix-update-document-cache" + "source": "https://github.com/utopia-php/database/tree/main" }, - "time": "2021-08-09T15:56:38+00:00" + "time": "2021-08-10T06:09:02+00:00" }, { "name": "utopia-php/domains", @@ -6257,7 +6258,7 @@ "aliases": [ { "package": "utopia-php/database", - "version": "dev-fix-update-document-cache", + "version": "dev-main", "alias": "0.6.1", "alias_normalized": "0.6.1.0" } From 1061dc63661d682bb071df0b79981cbf8288ad4f Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Wed, 11 Aug 2021 15:30:25 +0200 Subject: [PATCH 20/21] fix(after-pagination): updated descriptions --- app/controllers/api/database.php | 8 ++++---- app/controllers/api/functions.php | 12 ++++++------ app/controllers/api/projects.php | 4 ++-- app/controllers/api/storage.php | 4 ++-- app/controllers/api/teams.php | 8 ++++---- app/controllers/api/users.php | 2 +- 6 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index d48a94468b..f89f87d908 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -182,7 +182,7 @@ App::get('/v1/database/collections') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 40000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('after', '', new UID(), 'ID of the collection used to return collection listed after. Should be used for efficient pagination working with many collections.', true) + ->param('after', '', new UID(), 'ID of the collection used as the starting point for the query, excluding the collection itself. Should be used for efficient pagination when working with large sets of data.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForExternal') @@ -196,7 +196,7 @@ App::get('/v1/database/collections') $afterCollection = $dbForExternal->getDocument('collections', $after); if ($afterCollection->isEmpty()) { - throw new Exception('Collection for after not found', 400); + throw new Exception("Collection '{$after}' for the 'after' value not found.", 400); } } @@ -1068,7 +1068,7 @@ App::get('/v1/database/collections/:collectionId/documents') ->param('queries', [], new ArrayList(new Text(128)), 'Array of query strings.', true) ->param('limit', 25, new Range(0, 100), 'Maximum number of documents to return in response. Use this value to manage pagination. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 900000000), 'Offset value. The default value is 0. Use this param to manage pagination.', true) - ->param('after', '', new UID(), 'ID of the document used to return documents listed after. Should be used for efficient pagination working with many documents.', true) + ->param('after', '', new UID(), 'ID of the document used as the starting point for the query, excluding the document itself. Should be used for efficient pagination when working with large sets of data.', true) ->param('orderAttributes', [], new ArrayList(new Text(128)), 'Array of attributes used to sort results.', true) ->param('orderTypes', [], new ArrayList(new WhiteList(['DESC', 'ASC'], true)), 'Array of order directions for sorting attribtues. Possible values are DESC for descending order, or ASC for ascending order.', true) ->inject('response') @@ -1103,7 +1103,7 @@ App::get('/v1/database/collections/:collectionId/documents') $afterDocument = $dbForExternal->getDocument($collectionId, $after); if ($afterDocument->isEmpty()) { - throw new Exception('Document for orderAfter not found', 400); + throw new Exception("Document '{$after}' for the 'after' value not found.", 400); } } diff --git a/app/controllers/api/functions.php b/app/controllers/api/functions.php index 6fc426534e..1441707559 100644 --- a/app/controllers/api/functions.php +++ b/app/controllers/api/functions.php @@ -88,7 +88,7 @@ App::get('/v1/functions') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('after', '', new UID(), 'ID of the function used to return functions listed after. Should be used for efficient pagination working with many functions.', true) + ->param('after', '', new UID(), 'ID of the function used as the starting point for the query, excluding the function itself. Should be used for efficient pagination when working with large sets of data.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForInternal') @@ -102,7 +102,7 @@ App::get('/v1/functions') $afterFunction = $dbForInternal->getDocument('functions', $after); if ($afterFunction->isEmpty()) { - throw new Exception('Function for after not found', 400); + throw new Exception("Function '{$after}' for the 'after' value not found.", 400); } } @@ -515,7 +515,7 @@ App::get('/v1/functions/:functionId/tags') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('after', '', new UID(), 'ID of the tag used to return tags listed after. Should be used for efficient pagination working with many tags.', true) + ->param('after', '', new UID(), 'ID of the tag used as the starting point for the query, excluding the tag itself. Should be used for efficient pagination when working with large sets of data.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForInternal') @@ -535,7 +535,7 @@ App::get('/v1/functions/:functionId/tags') $afterTag = $dbForInternal->getDocument('tags', $after); if ($afterTag->isEmpty()) { - throw new Exception('Tag for after not found', 400); + throw new Exception("Tag '{$after}' for the 'after' value not found.", 400); } } @@ -766,7 +766,7 @@ App::get('/v1/functions/:functionId/executions') ->param('functionId', '', new UID(), 'Function unique ID.') ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('after', '', new UID(), 'ID of the execution used to return executions listed after. Should be used for efficient pagination working with many executions.', true) + ->param('after', '', new UID(), 'ID of the execution used as the starting point for the query, excluding the execution itself. Should be used for efficient pagination when working with large sets of data.', true) ->inject('response') ->inject('dbForInternal') ->action(function ($functionId, $limit, $offset, $after, $response, $dbForInternal) { @@ -785,7 +785,7 @@ App::get('/v1/functions/:functionId/executions') $afterExecution = $dbForInternal->getDocument('executions', $after); if ($afterExecution->isEmpty()) { - throw new Exception('Execution for after not found', 400); + throw new Exception("Execution '{$after}' for the 'after' value not found.", 400); } } diff --git a/app/controllers/api/projects.php b/app/controllers/api/projects.php index 7ac9557016..e34c948837 100644 --- a/app/controllers/api/projects.php +++ b/app/controllers/api/projects.php @@ -164,7 +164,7 @@ App::get('/v1/projects') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('after', '', new UID(), 'ID of the project used to return projects listed after. Should be used for efficient pagination working with many projects.', true) + ->param('after', '', new UID(), 'ID of the project used as the starting point for the query, excluding the project itself. Should be used for efficient pagination when working with large sets of data.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForConsole') @@ -178,7 +178,7 @@ App::get('/v1/projects') $afterProject = $dbForConsole->getDocument('projects', $after); if ($afterProject->isEmpty()) { - throw new Exception('Project for after not found', 400); + throw new Exception("Project '{$after}' for the 'after' value not found.", 400); } } diff --git a/app/controllers/api/storage.php b/app/controllers/api/storage.php index 37df8f6f2d..5a5c43de58 100644 --- a/app/controllers/api/storage.php +++ b/app/controllers/api/storage.php @@ -171,7 +171,7 @@ App::get('/v1/storage/files') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('after', '', new UID(), 'ID of the file used to return files listed after. Should be used for efficient pagination working with many files.', true) + ->param('after', '', new UID(), 'ID of the file used as the starting point for the query, excluding the file itself. Should be used for efficient pagination when working with large sets of data.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForInternal') @@ -185,7 +185,7 @@ App::get('/v1/storage/files') $afterFile = $dbForInternal->getDocument('files', $after); if ($afterFile->isEmpty()) { - throw new Exception('File for after not found', 400); + throw new Exception("File '{$after}' for the 'after' value not found.", 400); } } diff --git a/app/controllers/api/teams.php b/app/controllers/api/teams.php index cce2e835ea..569940c42e 100644 --- a/app/controllers/api/teams.php +++ b/app/controllers/api/teams.php @@ -99,7 +99,7 @@ App::get('/v1/teams') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('after', '', new UID(), 'ID of the team used to return teams listed after. Should be used for efficient pagination working with many teams.', true) + ->param('after', '', new UID(), 'ID of the team used as the starting point for the query, excluding the team itself. Should be used for efficient pagination when working with large sets of data.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForInternal') @@ -113,7 +113,7 @@ App::get('/v1/teams') $afterTeam = $dbForInternal->getDocument('teams', $after); if ($afterTeam->isEmpty()) { - throw new Exception('Team for after not found', 400); + throw new Exception("Team '{$after}' for the 'after' value not found.", 400); } } @@ -424,7 +424,7 @@ App::get('/v1/teams/:teamId/memberships') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('after', '', new UID(), 'ID of the file used to return files listed after. Should be used for efficient pagination working with many files.', true) + ->param('after', '', new UID(), 'ID of the membership used as the starting point for the query, excluding the membership itself. Should be used for efficient pagination when working with large sets of data.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForInternal') @@ -442,7 +442,7 @@ App::get('/v1/teams/:teamId/memberships') $afterMembership = $dbForInternal->getDocument('memberships', $after); if ($afterMembership->isEmpty()) { - throw new Exception('Membership for after not found', 400); + throw new Exception("Membership '{$after}' for the 'after' value not found.", 400); } } diff --git a/app/controllers/api/users.php b/app/controllers/api/users.php index a51dbf668d..11beca048b 100644 --- a/app/controllers/api/users.php +++ b/app/controllers/api/users.php @@ -83,7 +83,7 @@ App::get('/v1/users') ->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true) ->param('limit', 25, new Range(0, 100), 'Results limit value. By default will return maximum 25 results. Maximum of 100 results allowed per request.', true) ->param('offset', 0, new Range(0, 2000), 'Results offset. The default value is 0. Use this param to manage pagination.', true) - ->param('after', '', new UID(), 'ID of the user used to return users listed after. Should be used for efficient pagination working with many users.', true) + ->param('after', '', new UID(), 'ID of the user used as the starting point for the query, excluding the user itself. Should be used for efficient pagination when working with large sets of data.', true) ->param('orderType', 'ASC', new WhiteList(['ASC', 'DESC'], true), 'Order result by ASC or DESC order.', true) ->inject('response') ->inject('dbForInternal') From ba5eb5208441f565fb535f131e54c90963d7ffd1 Mon Sep 17 00:00:00 2001 From: Torsten Dittmann Date: Fri, 13 Aug 2021 10:08:10 +0200 Subject: [PATCH 21/21] chore(composer): update utopia audit and abuse --- composer.json | 2 +- composer.lock | 56 +++++++++++++++++++++------------------------------ 2 files changed, 24 insertions(+), 34 deletions(-) diff --git a/composer.json b/composer.json index 4a5685b4c9..ba45139b98 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "utopia-php/cache": "0.4.*", "utopia-php/cli": "0.11.*", "utopia-php/config": "0.2.*", - "utopia-php/database": "dev-main as 0.6.1", + "utopia-php/database": "0.7.*", "utopia-php/locale": "0.4.*", "utopia-php/registry": "0.5.*", "utopia-php/preloader": "0.2.*", diff --git a/composer.lock b/composer.lock index 844a746398..db07f5df2b 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6b3c314f3faa9c3aff868eaf7f6f3cbb", + "content-hash": "7de5dc8a9fe3cbc14696c685d1cdddee", "packages": [ { "name": "adhocore/jwt", @@ -1666,22 +1666,22 @@ }, { "name": "utopia-php/abuse", - "version": "0.6.1", + "version": "0.6.2", "source": { "type": "git", "url": "https://github.com/utopia-php/abuse.git", - "reference": "c9078aa3a87750d66060f0ed7642e03e5815da17" + "reference": "4cd9c16610f7398d2e1737663ef682fa721ae736" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/abuse/zipball/c9078aa3a87750d66060f0ed7642e03e5815da17", - "reference": "c9078aa3a87750d66060f0ed7642e03e5815da17", + "url": "https://api.github.com/repos/utopia-php/abuse/zipball/4cd9c16610f7398d2e1737663ef682fa721ae736", + "reference": "4cd9c16610f7398d2e1737663ef682fa721ae736", "shasum": "" }, "require": { "ext-pdo": "*", "php": ">=7.4", - "utopia-php/database": "0.6.*" + "utopia-php/database": "0.7.*" }, "require-dev": { "phpunit/phpunit": "^9.4", @@ -1713,9 +1713,9 @@ ], "support": { "issues": "https://github.com/utopia-php/abuse/issues", - "source": "https://github.com/utopia-php/abuse/tree/0.6.1" + "source": "https://github.com/utopia-php/abuse/tree/0.6.2" }, - "time": "2021-08-03T19:31:07+00:00" + "time": "2021-08-13T07:52:34+00:00" }, { "name": "utopia-php/analytics", @@ -1774,22 +1774,22 @@ }, { "name": "utopia-php/audit", - "version": "0.6.1", + "version": "0.6.2", "source": { "type": "git", "url": "https://github.com/utopia-php/audit.git", - "reference": "971dcd5c88309656df31ac20f326d3ac8b555594" + "reference": "2ec39a53eb98a5f9d230550ad56c7c04de5d77df" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/audit/zipball/971dcd5c88309656df31ac20f326d3ac8b555594", - "reference": "971dcd5c88309656df31ac20f326d3ac8b555594", + "url": "https://api.github.com/repos/utopia-php/audit/zipball/2ec39a53eb98a5f9d230550ad56c7c04de5d77df", + "reference": "2ec39a53eb98a5f9d230550ad56c7c04de5d77df", "shasum": "" }, "require": { "ext-pdo": "*", "php": ">=7.4", - "utopia-php/database": "0.6.*" + "utopia-php/database": "0.7.*" }, "require-dev": { "phpunit/phpunit": "^9.3", @@ -1821,9 +1821,9 @@ ], "support": { "issues": "https://github.com/utopia-php/audit/issues", - "source": "https://github.com/utopia-php/audit/tree/0.6.1" + "source": "https://github.com/utopia-php/audit/tree/0.6.2" }, - "time": "2021-08-03T19:29:34+00:00" + "time": "2021-08-13T08:05:20+00:00" }, { "name": "utopia-php/cache", @@ -1984,16 +1984,16 @@ }, { "name": "utopia-php/database", - "version": "dev-main", + "version": "0.7.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "bd765cd67e042defb8d0a15ef9a400784d6beb24" + "reference": "46c4a99347397e362a9429826e1888b0aefb2056" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/bd765cd67e042defb8d0a15ef9a400784d6beb24", - "reference": "bd765cd67e042defb8d0a15ef9a400784d6beb24", + "url": "https://api.github.com/repos/utopia-php/database/zipball/46c4a99347397e362a9429826e1888b0aefb2056", + "reference": "46c4a99347397e362a9429826e1888b0aefb2056", "shasum": "" }, "require": { @@ -2011,7 +2011,6 @@ "utopia-php/cli": "^0.11.0", "vimeo/psalm": "4.0.1" }, - "default-branch": true, "type": "library", "autoload": { "psr-4": { @@ -2042,9 +2041,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/main" + "source": "https://github.com/utopia-php/database/tree/0.7.0" }, - "time": "2021-08-10T06:09:02+00:00" + "time": "2021-08-10T19:09:58+00:00" }, { "name": "utopia-php/domains", @@ -6255,18 +6254,9 @@ "time": "2015-12-17T08:42:14+00:00" } ], - "aliases": [ - { - "package": "utopia-php/database", - "version": "dev-main", - "alias": "0.6.1", - "alias_normalized": "0.6.1.0" - } - ], + "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/database": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": {