diff --git a/src/Database/Database.php b/src/Database/Database.php index 1444286658..c891351f35 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -9863,6 +9863,12 @@ public function convertQuery(Document $collection, Query $query): Query $query->setOnArray($attribute->getAttribute('array', false)); $query->setAttributeType($attribute->getAttribute('type')); + // Permissions use scalar JSON storage metadata, but permission + // queries operate on the individual values in the stored array. + if ($query->getAttribute() === '$permissions') { + $query->setOnArray(true); + } + if ($attribute->getAttribute('type') == Database::VAR_DATETIME) { $values = $query->getValues(); foreach ($values as $valueIndex => $value) { diff --git a/src/Database/Validator/Queries/Documents.php b/src/Database/Validator/Queries/Documents.php index 4959a062cf..8581279b30 100644 --- a/src/Database/Validator/Queries/Documents.php +++ b/src/Database/Validator/Queries/Documents.php @@ -59,6 +59,12 @@ public function __construct( 'type' => Database::VAR_DATETIME, 'array' => false, ]); + $attributes[] = new Document([ + '$id' => '$permissions', + 'key' => '$permissions', + 'type' => Database::VAR_STRING, + 'array' => true, + ]); $validators = [ new Limit(), diff --git a/tests/e2e/Adapter/Scopes/PermissionTests.php b/tests/e2e/Adapter/Scopes/PermissionTests.php index 97e55633fc..0ecdf891e4 100644 --- a/tests/e2e/Adapter/Scopes/PermissionTests.php +++ b/tests/e2e/Adapter/Scopes/PermissionTests.php @@ -15,6 +15,56 @@ trait PermissionTests { + public function testQueryContainsOnPermissions(): void + { + /** @var Database $database */ + $database = $this->getDatabase(); + + $collection = __FUNCTION__; + $database->createCollection($collection); + + $readAny = Permission::read(Role::any()); + $updateAny = Permission::update(Role::any()); + $updateUser = Permission::update(Role::user('user1')); + $updateSimilarUser = Permission::update(Role::user('user10')); + + $database->createDocument($collection, new Document([ + '$id' => 'document1', + '$permissions' => [$readAny, $updateAny], + ])); + $database->createDocument($collection, new Document([ + '$id' => 'document2', + '$permissions' => [$readAny, $updateUser], + ])); + $database->createDocument($collection, new Document([ + '$id' => 'document3', + '$permissions' => [$readAny, $updateSimilarUser], + ])); + + $documents = $database->find($collection, [ + Query::contains('$permissions', [$updateAny]), + ]); + + $this->assertCount(1, $documents); + $this->assertSame('document1', $documents[0]->getId()); + + $documents = $database->find($collection, [ + Query::containsAny('$permissions', [$updateAny, $updateUser]), + ]); + + $this->assertCount(2, $documents); + + $documents = $database->find($collection, [ + Query::notContains('$permissions', [$updateUser]), + ]); + + $this->assertCount(2, $documents); + $this->assertSame(['document1', 'document3'], \array_map( + fn (Document $document) => $document->getId(), + $documents + )); + } + public function testUpdatingASharedDefinitionKeepsItsPermissionRowsTenantless(): void { /** @var Database $database */ diff --git a/tests/unit/Validator/DocumentsQueriesTest.php b/tests/unit/Validator/DocumentsQueriesTest.php index 6530ad2999..f18476142b 100644 --- a/tests/unit/Validator/DocumentsQueriesTest.php +++ b/tests/unit/Validator/DocumentsQueriesTest.php @@ -133,6 +133,8 @@ public function testValidQueries(): void Query::notEqual('id', '1000000'), Query::equal('description', ['Best movie ever']), Query::equal('description', ['']), + Query::contains('$permissions', ['read("any")']), + Query::notContains('$permissions', ['update("any")']), Query::equal('is_bool', [false]), Query::lessThanEqual('price', 6.50), Query::lessThan('price', 6.50), @@ -187,6 +189,9 @@ public function testInvalidQueries(): void $this->assertEquals(false, $validator->isValid($queries)); $this->assertEquals('Invalid query: Equal queries require at least one value.', $validator->getDescription()); + $queries = [Query::equal('$permissions', ['read("any")'])]; + $this->assertEquals(false, $validator->isValid($queries)); + $this->assertEquals('Invalid query: Cannot query equal on attribute "$permissions" because it is an array.', $validator->getDescription()); } }