From 238ff6fcd4a195aae989acbd7e0c84f86a406422 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 2 Nov 2021 19:43:10 -0400 Subject: [PATCH 1/5] Enable strict query checking if queries are provided --- app/controllers/api/database.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/database.php b/app/controllers/api/database.php index 5b228d6004..29ac582d5e 100644 --- a/app/controllers/api/database.php +++ b/app/controllers/api/database.php @@ -1654,11 +1654,11 @@ App::get('/v1/database/collections/:collectionId/documents') return Query::parse($query); }, $queries); - // TODO@kodumbeats use strict query validation - $validator = new QueriesValidator(new QueryValidator($collection->getAttribute('attributes', [])), $collection->getAttribute('indexes', []), false); - - if (!$validator->isValid($queries)) { - throw new Exception($validator->getDescription(), 400); + if (!empty($queries)) { + $validator = new QueriesValidator(new QueryValidator($collection->getAttribute('attributes', [])), $collection->getAttribute('indexes', []), true); + if (!$validator->isValid($queries)) { + throw new Exception($validator->getDescription(), 400); + } } $cursorDocument = null; From 58e6b3a6d62ea5d8e52e1a6382216e0243ad6d4d Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 2 Nov 2021 19:45:04 -0400 Subject: [PATCH 2/5] Reorder so that expected value is first in assertions --- tests/e2e/Services/Database/DatabaseBase.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index 3f11154c49..1f0ad36603 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -595,11 +595,11 @@ trait DatabaseBase 'attributes' => ['title'], ]); - $this->assertEquals($titleIndex['headers']['status-code'], 201); - $this->assertEquals($titleIndex['body']['key'], 'titleIndex'); - $this->assertEquals($titleIndex['body']['type'], 'fulltext'); + $this->assertEquals(201, $titleIndex['headers']['status-code']); + $this->assertEquals('titleIndex', $titleIndex['body']['key']); + $this->assertEquals('fulltext', $titleIndex['body']['type']); $this->assertCount(1, $titleIndex['body']['attributes']); - $this->assertEquals($titleIndex['body']['attributes'][0], 'title'); + $this->assertEquals('title', $titleIndex['body']['attributes'][0]); // wait for database worker to create index sleep(2); @@ -612,7 +612,8 @@ trait DatabaseBase $this->assertIsArray($movies['body']['indexes']); $this->assertCount(1, $movies['body']['indexes']); - $this->assertEquals($movies['body']['indexes'][0]['key'], $titleIndex['body']['key']); + $this->assertEquals($titleIndex['body']['key'], $movies['body']['indexes'][0]['key']); + $this->assertEquals('available', $movies['body']['indexes'][0]['status']); return $data; } From af52dbd07484858c5709b6a3bfcbb729e8f1c9d7 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Tue, 2 Nov 2021 19:45:23 -0400 Subject: [PATCH 3/5] Test patch to query validator constructor --- composer.json | 2 +- composer.lock | 78 ++++++++++++++++++++++++++++----------------------- 2 files changed, 44 insertions(+), 36 deletions(-) diff --git a/composer.json b/composer.json index 8b0d69f1fe..d2a9c9d1d3 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.10.*", + "utopia-php/database": "dev-fix-query-validator-constructor as 0.10.9", "utopia-php/locale": "0.4.*", "utopia-php/orchestration": "0.2.*", "utopia-php/registry": "0.5.*", diff --git a/composer.lock b/composer.lock index 9ad7258756..82e05789c6 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": "fa378feaffc446f557a140035a1c77b6", + "content-hash": "55ff735e10c409ad5bc05c8793839f06", "packages": [ { "name": "adhocore/jwt", @@ -2138,16 +2138,16 @@ }, { "name": "utopia-php/database", - "version": "0.10.0", + "version": "dev-fix-query-validator-constructor", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "b7c60b0ec769a9050dd2b939b78ff1f5d4fa27e8" + "reference": "a475b232578389f5c74714bec77c880254802b1c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/b7c60b0ec769a9050dd2b939b78ff1f5d4fa27e8", - "reference": "b7c60b0ec769a9050dd2b939b78ff1f5d4fa27e8", + "url": "https://api.github.com/repos/utopia-php/database/zipball/a475b232578389f5c74714bec77c880254802b1c", + "reference": "a475b232578389f5c74714bec77c880254802b1c", "shasum": "" }, "require": { @@ -2195,9 +2195,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/0.10.0" + "source": "https://github.com/utopia-php/database/tree/fix-query-validator-constructor" }, - "time": "2021-10-04T17:23:25+00:00" + "time": "2021-11-02T22:56:56+00:00" }, { "name": "utopia-php/domains", @@ -2304,20 +2304,19 @@ }, { "name": "utopia-php/image", - "version": "0.5.2", + "version": "0.5.3", "source": { "type": "git", "url": "https://github.com/utopia-php/image.git", - "reference": "049446fea7cb53db8a431455ec382e30e6d1482a" + "reference": "4a8429b62dcf56562b038d6712375f75166f0c02" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/image/zipball/049446fea7cb53db8a431455ec382e30e6d1482a", - "reference": "049446fea7cb53db8a431455ec382e30e6d1482a", + "url": "https://api.github.com/repos/utopia-php/image/zipball/4a8429b62dcf56562b038d6712375f75166f0c02", + "reference": "4a8429b62dcf56562b038d6712375f75166f0c02", "shasum": "" }, "require": { - "chillerlan/php-qrcode": "4.3.1", "ext-imagick": "*", "php": ">=7.4" }, @@ -2351,9 +2350,9 @@ ], "support": { "issues": "https://github.com/utopia-php/image/issues", - "source": "https://github.com/utopia-php/image/tree/0.5.2" + "source": "https://github.com/utopia-php/image/tree/0.5.3" }, - "time": "2021-10-18T06:41:05+00:00" + "time": "2021-11-02T05:47:16+00:00" }, { "name": "utopia-php/locale", @@ -4103,23 +4102,23 @@ }, { "name": "phpunit/php-code-coverage", - "version": "9.2.7", + "version": "9.2.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218" + "reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/d4c798ed8d51506800b441f7a13ecb0f76f12218", - "reference": "d4c798ed8d51506800b441f7a13ecb0f76f12218", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/cf04e88a2e3c56fc1a65488afd493325b4c1bc3e", + "reference": "cf04e88a2e3c56fc1a65488afd493325b4c1bc3e", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.12.0", + "nikic/php-parser": "^4.13.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -4168,7 +4167,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.7" + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.8" }, "funding": [ { @@ -4176,7 +4175,7 @@ "type": "github" } ], - "time": "2021-09-17T05:39:03+00:00" + "time": "2021-10-30T08:01:38+00:00" }, { "name": "phpunit/php-file-iterator", @@ -5588,16 +5587,16 @@ }, { "name": "symfony/console", - "version": "v5.3.7", + "version": "v5.3.10", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a" + "reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/8b1008344647462ae6ec57559da166c2bfa5e16a", - "reference": "8b1008344647462ae6ec57559da166c2bfa5e16a", + "url": "https://api.github.com/repos/symfony/console/zipball/d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3", + "reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3", "shasum": "" }, "require": { @@ -5667,7 +5666,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.3.7" + "source": "https://github.com/symfony/console/tree/v5.3.10" }, "funding": [ { @@ -5683,7 +5682,7 @@ "type": "tidelift" } ], - "time": "2021-08-25T20:02:16+00:00" + "time": "2021-10-26T09:30:15+00:00" }, { "name": "symfony/polyfill-intl-grapheme", @@ -6090,16 +6089,16 @@ }, { "name": "symfony/string", - "version": "v5.3.7", + "version": "v5.3.10", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5" + "reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/8d224396e28d30f81969f083a58763b8b9ceb0a5", - "reference": "8d224396e28d30f81969f083a58763b8b9ceb0a5", + "url": "https://api.github.com/repos/symfony/string/zipball/d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c", + "reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c", "shasum": "" }, "require": { @@ -6153,7 +6152,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.3.7" + "source": "https://github.com/symfony/string/tree/v5.3.10" }, "funding": [ { @@ -6169,7 +6168,7 @@ "type": "tidelift" } ], - "time": "2021-08-26T08:00:08+00:00" + "time": "2021-10-27T18:21:46+00:00" }, { "name": "textalk/websocket", @@ -6505,9 +6504,18 @@ "time": "2015-12-17T08:42:14+00:00" } ], - "aliases": [], + "aliases": [ + { + "package": "utopia-php/database", + "version": "dev-fix-query-validator-constructor", + "alias": "0.10.9", + "alias_normalized": "0.10.9.0" + } + ], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "utopia-php/database": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { From d6b794d3056d00a0f25b2554e10d0816d6551705 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Wed, 3 Nov 2021 11:02:41 -0400 Subject: [PATCH 4/5] Add query e2e tests to check for strict matching --- tests/e2e/Services/Database/DatabaseBase.php | 156 ++++++++++--------- 1 file changed, 80 insertions(+), 76 deletions(-) diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index 1f0ad36603..00723040e0 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -601,6 +601,22 @@ trait DatabaseBase $this->assertCount(1, $titleIndex['body']['attributes']); $this->assertEquals('title', $titleIndex['body']['attributes'][0]); + $releaseYearIndex = $this->client->call(Client::METHOD_POST, '/database/collections/' . $data['moviesId'] . '/indexes', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'indexId' => 'releaseYear', + 'type' => 'key', + 'attributes' => ['releaseYear'], + ]); + + $this->assertEquals(201, $releaseYearIndex['headers']['status-code']); + $this->assertEquals('releaseYear', $releaseYearIndex['body']['key']); + $this->assertEquals('key', $releaseYearIndex['body']['type']); + $this->assertCount(1, $releaseYearIndex['body']['attributes']); + $this->assertEquals('releaseYear', $releaseYearIndex['body']['attributes'][0]); + // wait for database worker to create index sleep(2); @@ -611,9 +627,11 @@ trait DatabaseBase ]), []); $this->assertIsArray($movies['body']['indexes']); - $this->assertCount(1, $movies['body']['indexes']); + $this->assertCount(2, $movies['body']['indexes']); $this->assertEquals($titleIndex['body']['key'], $movies['body']['indexes'][0]['key']); + $this->assertEquals($releaseYearIndex['body']['key'], $movies['body']['indexes'][1]['key']); $this->assertEquals('available', $movies['body']['indexes'][0]['status']); + $this->assertEquals('available', $movies['body']['indexes'][1]['status']); return $data; } @@ -1025,93 +1043,79 @@ trait DatabaseBase /** * @depends testCreateDocument */ - // public function testDocumentsListSuccessSearch(array $data):array - // { - // $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()), [ - // 'queries' => ['title.search("Captain America")'], - // ]); + public function testDocumentsListQueries(array $data):array + { + $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()), [ + 'queries' => ['title.search("Captain America")'], + ]); - // var_dump($documents); + var_dump($documents); - // $this->assertEquals($documents['headers']['status-code'], 200); - // $this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']); - // $this->assertCount(1, $documents['body']['documents']); + $this->assertEquals($documents['headers']['status-code'], 200); + $this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']); + $this->assertCount(1, $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()), [ - // 'queries' => ['title.search("Homecoming")'], - // ]); + $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()), [ + 'queries' => ['title.search("Homecoming")'], + ]); - // $this->assertEquals($documents['headers']['status-code'], 200); - // $this->assertEquals(2017, $documents['body']['documents'][0]['releaseYear']); - // $this->assertCount(1, $documents['body']['documents']); + $this->assertEquals($documents['headers']['status-code'], 200); + $this->assertEquals(2017, $documents['body']['documents'][0]['releaseYear']); + $this->assertCount(1, $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()), [ - // 'queries' => ['title.search("spider")'], - // ]); + $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()), [ + 'queries' => ['title.search("spider")'], + ]); - // $this->assertEquals($documents['headers']['status-code'], 200); - // $this->assertEquals(2019, $documents['body']['documents'][0]['releaseYear']); - // $this->assertEquals(2017, $documents['body']['documents'][1]['releaseYear']); - // $this->assertCount(2, $documents['body']['documents']); + $this->assertEquals($documents['headers']['status-code'], 200); + $this->assertEquals(2019, $documents['body']['documents'][0]['releaseYear']); + $this->assertEquals(2017, $documents['body']['documents'][1]['releaseYear']); + $this->assertCount(2, $documents['body']['documents']); - // return []; - // } - // TODO@kodumbeats test for empty searches and misformatted queries + $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()), [ + 'queries' => ['releaseYear.equal(1944)'], + ]); - /** - * @depends testCreateDocument - */ - // public function testListDocumentsFilters(array $data):array - // { - // $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()), [ - // 'filters' => [ - // 'actors.firstName=Tom' - // ], - // ]); + $this->assertCount(1, $documents['body']['documents']); + $this->assertEquals('Captain America', $documents['body']['documents'][0]['title']); - // $this->assertCount(2, $documents['body']['documents']); - // $this->assertEquals('Spider-Man: Far From Home', $documents['body']['documents'][0]['name']); - // $this->assertEquals('Spider-Man: Homecoming', $documents['body']['documents'][1]['name']); + $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()), [ + 'queries' => ['releaseYear.notEqual(1944)'], + ]); - // $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()), [ - // 'filters' => [ - // 'releaseYear=1944' - // ], - // ]); + $this->assertCount(2, $documents['body']['documents']); + $this->assertEquals('Spider-Man: Far From Home', $documents['body']['documents'][0]['title']); + $this->assertEquals('Spider-Man: Homecoming', $documents['body']['documents'][1]['title']); - // $this->assertCount(1, $documents['body']['documents']); - // $this->assertEquals('Captain America', $documents['body']['documents'][0]['name']); + /** + * Test for Failure + */ + $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()), [ + 'queries' => ['actors.equal("Tom Holland")'], + ]); + $this->assertEquals(400, $documents['headers']['status-code']); + $this->assertEquals('Index not found: actors', $documents['body']['message']); - // $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()), [ - // 'filters' => [ - // 'releaseYear!=1944' - // ], - // ]); - - // $this->assertCount(2, $documents['body']['documents']); - // $this->assertEquals('Spider-Man: Far From Home', $documents['body']['documents'][0]['name']); - // $this->assertEquals('Spider-Man: Homecoming', $documents['body']['documents'][1]['name']); - - // return []; - // } + return []; + } /** * @depends testCreateDocument From dc7bb3eefc7e007ebd3fbae7f0c9616a58e0c1a7 Mon Sep 17 00:00:00 2001 From: kodumbeats Date: Thu, 11 Nov 2021 20:17:03 -0500 Subject: [PATCH 5/5] Remove testing code --- tests/e2e/Services/Database/DatabaseBase.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/e2e/Services/Database/DatabaseBase.php b/tests/e2e/Services/Database/DatabaseBase.php index 00723040e0..77c8528cfe 100644 --- a/tests/e2e/Services/Database/DatabaseBase.php +++ b/tests/e2e/Services/Database/DatabaseBase.php @@ -1052,8 +1052,6 @@ trait DatabaseBase 'queries' => ['title.search("Captain America")'], ]); - var_dump($documents); - $this->assertEquals($documents['headers']['status-code'], 200); $this->assertEquals(1944, $documents['body']['documents'][0]['releaseYear']); $this->assertCount(1, $documents['body']['documents']);