diff --git a/composer.lock b/composer.lock index 6e9475dc5c..e8cf08db6a 100644 --- a/composer.lock +++ b/composer.lock @@ -1179,16 +1179,16 @@ }, { "name": "open-telemetry/context", - "version": "1.2.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/opentelemetry-php/context.git", - "reference": "5f553042b951d3fedf47925852c380159dfca801" + "reference": "1eb2b837ee9362db064a6b65d5ecce15a9f9f020" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opentelemetry-php/context/zipball/5f553042b951d3fedf47925852c380159dfca801", - "reference": "5f553042b951d3fedf47925852c380159dfca801", + "url": "https://api.github.com/repos/opentelemetry-php/context/zipball/1eb2b837ee9362db064a6b65d5ecce15a9f9f020", + "reference": "1eb2b837ee9362db064a6b65d5ecce15a9f9f020", "shasum": "" }, "require": { @@ -1234,7 +1234,7 @@ "issues": "https://github.com/open-telemetry/opentelemetry-php/issues", "source": "https://github.com/open-telemetry/opentelemetry-php" }, - "time": "2025-05-02T01:57:57+00:00" + "time": "2025-05-07T23:36:50+00:00" }, { "name": "open-telemetry/exporter-otlp", diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index b5ddedbf90..1f19c514d1 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -4885,857 +4885,4 @@ trait DatabasesBase 'x-appwrite-key' => $this->getProject()['apiKey'] ])); } - - public function testBulkCreate(): void - { - // Create database - $database = $this->client->call(Client::METHOD_POST, '/databases', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'databaseId' => ID::unique(), - 'name' => 'Bulk Create Perms', - ]); - - $this->assertNotEmpty($database['body']['$id']); - - $databaseId = $database['body']['$id']; - - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'collectionId' => ID::unique(), - 'name' => 'Bulk Create Perms', - 'documentSecurity' => true, - 'permissions' => [ - Permission::create(Role::any()), - Permission::read(Role::any()), - Permission::delete(Role::any()), - Permission::update(Role::any()), - ], - ]); - - $this->assertEquals(201, $collection['headers']['status-code']); - - $data = [ - '$id' => $collection['body']['$id'], - 'databaseId' => $collection['body']['databaseId'] - ]; - - // Await attribute - $numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'key' => 'number', - 'required' => true, - ]); - - $this->assertEquals(202, $numberAttribute['headers']['status-code']); - - sleep(1); - - $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => [ - [ - '$id' => ID::unique(), - 'number' => 1, - ], - [ - '$id' => ID::unique(), - 'number' => 2, - ], - [ - '$id' => ID::unique(), - 'number' => 3, - ], - ], - ]); - - $this->assertEquals(201, $response['headers']['status-code']); - $this->assertCount(3, $response['body']['documents']); - - $response = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(1, $response['body']['documents'][0]['number']); - $this->assertEquals(2, $response['body']['documents'][1]['number']); - $this->assertEquals(3, $response['body']['documents'][2]['number']); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(3, $response['body']['documents']); - - // TEST FAIL - Can't use data and document together - $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'data' => [ - 'number' => 5 - ], - 'documents' => [ - [ - '$id' => ID::unique(), - 'number' => 1, - ] - ], - ]); - - $this->assertEquals(400, $response['headers']['status-code']); - - // TEST FAIL - Can't use $documentId and create bulk documents - $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documentId' => ID::unique(), - 'documents' => [ - [ - '$id' => ID::unique(), - 'number' => 1, - ] - ], - ]); - - $this->assertEquals(400, $response['headers']['status-code']); - - // TEST FAIL - Can't miss $id in bulk documents - $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => [ - [ - 'number' => 1, - ] - ], - ]); - - $this->assertEquals(400, $response['headers']['status-code']); - - // TEST FAIL - Can't miss number in bulk documents - $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => [ - [ - '$id' => ID::unique(), - 'number' => 1, - ], - [ - '$id' => ID::unique(), - ], - ], - ]); - - $this->assertEquals(400, $response['headers']['status-code']); - - // TEST FAIL - Can't push more than APP_LIMIT_DATABASE_BATCH documents - $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => array_fill(0, APP_LIMIT_DATABASE_BATCH + 1, [ - '$id' => ID::unique(), - 'number' => 1, - ]), - ]); - - $this->assertEquals(400, $response['headers']['status-code']); - } - - public function testBulkUpdates(): void - { - // Create database - $database = $this->client->call(Client::METHOD_POST, '/databases', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'databaseId' => ID::unique(), - 'name' => 'Bulk Updates' - ]); - - $this->assertNotEmpty($database['body']['$id']); - - $databaseId = $database['body']['$id']; - - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'collectionId' => ID::unique(), - 'name' => 'Bulk Updates', - 'documentSecurity' => true, - 'permissions' => [ - Permission::create(Role::any()), - Permission::read(Role::any()), - Permission::delete(Role::any()), - Permission::update(Role::any()), - ], - ]); - - $this->assertEquals(201, $collection['headers']['status-code']); - - $data = [ - '$id' => $collection['body']['$id'], - 'databaseId' => $collection['body']['databaseId'] - ]; - - // Await attribute - $numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'key' => 'number', - 'required' => true, - ]); - - $this->assertEquals(202, $numberAttribute['headers']['status-code']); - - // Wait for database worker to create attributes - sleep(2); - - // Create documents - $createBulkDocuments = function ($amount = 10) use ($data) { - $documents = []; - - for ($x = 1; $x <= $amount; $x++) { - $documents[] = [ - '$id' => ID::unique(), - 'number' => $x, - ]; - } - - $doc = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => $documents, - ]); - - $this->assertEquals(201, $doc['headers']['status-code']); - }; - - $createBulkDocuments(); - - // TEST: Update all documents - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'data' => [ - 'number' => 100, - '$permissions' => [ - Permission::read(Role::user($this->getUser()['$id'])), - Permission::update(Role::user($this->getUser()['$id'])), - Permission::delete(Role::user($this->getUser()['$id'])), - ] - ], - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(10, $response['body']['documents']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - Query::equal('number', [100])->toString(), - ]); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(10, $documents['body']['total']); - - $returnedDocuments = $response['body']['documents']; - $refetchedDocuments = $documents['body']['documents']; - - $this->assertEquals($returnedDocuments, $refetchedDocuments); - - foreach ($documents['body']['documents'] as $document) { - $this->assertEquals([ - Permission::read(Role::user($this->getUser()['$id'])), - Permission::update(Role::user($this->getUser()['$id'])), - Permission::delete(Role::user($this->getUser()['$id'])), - ], $document['$permissions']); - $this->assertEquals($collection['body']['$id'], $document['$collectionId']); - $this->assertEquals($data['databaseId'], $document['$databaseId']); - $this->assertEquals($document['number'], 100); - } - - // TEST: Check permissions persist - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'data' => [ - 'number' => 200 - ], - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(10, $response['body']['documents']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - Query::equal('number', [200])->toString(), - ]); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(10, $documents['body']['total']); - - foreach ($documents['body']['documents'] as $document) { - $this->assertEquals([ - Permission::read(Role::user($this->getUser()['$id'])), - Permission::update(Role::user($this->getUser()['$id'])), - Permission::delete(Role::user($this->getUser()['$id'])), - ], $document['$permissions']); - } - - // TEST: Update documents with limit - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'data' => [ - 'number' => 300 - ], - 'queries' => [ - Query::limit(5)->toString(), - ], - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(5, $response['body']['documents']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'queries' => [Query::equal('number', [200])->toString()] - ]); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(5, $documents['body']['total']); - - // TEST: Update documents with offset - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'data' => [ - 'number' => 300 - ], - 'queries' => [ - Query::offset(5)->toString(), - ], - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(5, $response['body']['documents']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'queries' => [Query::equal('number', [300])->toString()] - ]); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(10, $documents['body']['total']); - - // TEST: Update documents with equals filter - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'data' => [ - 'number' => 400 - ], - 'queries' => [ - Query::equal('number', [300])->toString(), - ], - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(10, $response['body']['documents']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'queries' => [Query::equal('number', [400])->toString()] - ]); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(10, $documents['body']['total']); - } - - public function testBulkUpserts(): void - { - // Create database - $database = $this->client->call(Client::METHOD_POST, '/databases', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'databaseId' => ID::unique(), - 'name' => 'Bulk Upserts' - ]); - - $this->assertNotEmpty($database['body']['$id']); - - $databaseId = $database['body']['$id']; - - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'collectionId' => ID::unique(), - 'name' => 'Bulk Upserts', - 'documentSecurity' => true, - 'permissions' => [ - Permission::create(Role::any()), - Permission::read(Role::any()), - Permission::delete(Role::any()), - Permission::update(Role::any()), - ], - ]); - - $this->assertEquals(201, $collection['headers']['status-code']); - - $data = [ - '$id' => $collection['body']['$id'], - 'databaseId' => $collection['body']['databaseId'] - ]; - - // Await attribute - $numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'key' => 'number', - 'required' => true, - ]); - - $this->assertEquals(202, $numberAttribute['headers']['status-code']); - - // Wait for database worker to create attributes - sleep(2); - - // Create documents - $createBulkDocuments = function ($amount = 10) use ($data) { - $documents = []; - - for ($x = 1; $x <= $amount; $x++) { - $documents[] = [ - '$id' => "$x", - 'number' => $x, - ]; - } - - $response = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => $documents, - ]); - - $this->assertEquals(201, $response['headers']['status-code']); - - return $documents; - }; - - $documents = $createBulkDocuments(); - - // Update a document - $documents[\array_key_last($documents)]['number'] = 1000; - - // Add a new document - $documents[] = ['number' => 11]; - - // TEST: Upsert all documents - $response = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => $documents, - ]); - - // Unchanged docs are skipped. 2 documents should be returned, 1 updated and 1 inserted. - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(2, $response['body']['documents']); - $this->assertEquals(1000, $response['body']['documents'][0]['number']); - $this->assertEquals(11, $response['body']['documents'][1]['number']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ])); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(11, $documents['body']['total']); - - foreach ($documents['body']['documents'] as $index => $document) { - $this->assertEquals($collection['body']['$id'], $document['$collectionId']); - $this->assertEquals($data['databaseId'], $document['$databaseId']); - switch ($index) { - case 9: - $this->assertEquals($document['number'], 1000); - break; - default: - $this->assertEquals($document['number'], $index + 1); - } - } - - // TEST: Upsert permissions: - $response = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => [ - [ - '$id' => '1', - 'number' => 1000, - ], - [ - '$id' => '10', - '$permissions' => [ - Permission::read(Role::user($this->getUser()['$id'])), - Permission::update(Role::user($this->getUser()['$id'])), - Permission::delete(Role::user($this->getUser()['$id'])), - ], - 'number' => 10, - ], - ], - ]); - - $this->assertEquals(1000, $response['body']['documents'][0]['number']); - $this->assertEquals([], $response['body']['documents'][0]['$permissions']); - $this->assertEquals([ - Permission::read(Role::user($this->getUser()['$id'])), - Permission::update(Role::user($this->getUser()['$id'])), - Permission::delete(Role::user($this->getUser()['$id'])), - ], $response['body']['documents'][1]['$permissions']); - } - - public function testBulkDeletes(): void - { - // Create database - $database = $this->client->call(Client::METHOD_POST, '/databases', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'databaseId' => ID::unique(), - 'name' => 'Bulk Deletes' - ]); - - $this->assertNotEmpty($database['body']['$id']); - - $databaseId = $database['body']['$id']; - - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'collectionId' => ID::unique(), - 'name' => 'Bulk Deletes', - 'documentSecurity' => false, - 'permissions' => [ - Permission::create(Role::any()), - Permission::read(Role::any()), - Permission::delete(Role::any()), - ], - ]); - - $this->assertEquals(201, $collection['headers']['status-code']); - - $data = [ - '$id' => $collection['body']['$id'], - 'databaseId' => $collection['body']['databaseId'] - ]; - - // Await attribute - $numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'key' => 'number', - 'required' => true, - ]); - - $this->assertEquals(202, $numberAttribute['headers']['status-code']); - - // wait for database worker to create attributes - sleep(2); - - // Create documents - $createBulkDocuments = function ($amount = 11) use ($data) { - $documents = []; - - for ($x = 0; $x < $amount; $x++) { - $documents[] = [ - '$id' => ID::unique(), - 'number' => $x, - ]; - } - - $doc = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => $documents, - ]); - - $this->assertEquals(201, $doc['headers']['status-code']); - }; - - $createBulkDocuments(); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(11, $documents['body']['total']); - - // TEST: Delete all documents - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(11, $response['body']['total']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(0, $documents['body']['total']); - - // TEST: Delete documents with query - $createBulkDocuments(); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(11, $documents['body']['total']); - - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'queries' => [ - Query::lessThan('number', 5)->toString(), - ], - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(5, $response['body']['total']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(6, $documents['body']['total']); - - foreach ($documents['body']['documents'] as $document) { - $this->assertGreaterThanOrEqual(5, $document['number']); - } - - // Cleanup - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(6, $response['body']['total']); - - // SUCCESS: Delete documents with query - $createBulkDocuments(); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(11, $documents['body']['total']); - - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'queries' => [ - Query::lessThan('number', 5)->toString(), - ], - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(5, $response['body']['total']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(6, $documents['body']['total']); - - // Cleanup - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(6, $response['body']['total']); - - // SUCCESS: Delete Documents with limit query - $createBulkDocuments(); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(11, $documents['body']['total']); - - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'queries' => [ - Query::limit(2)->toString(), - ], - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(2, $response['body']['total']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(9, $documents['body']['total']); - - // Cleanup - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(9, $response['body']['total']); - - // SUCCESS: Delete Documents with offset query - $createBulkDocuments(); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(11, $documents['body']['total']); - - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'queries' => [ - Query::offset(5)->toString(), - ], - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(6, $response['body']['total']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(5, $documents['body']['total']); - - $lastDoc = end($documents['body']['documents']); - - $this->assertNotEmpty($lastDoc); - $this->assertEquals(4, $lastDoc['number']); - - // Cleanup - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(5, $response['body']['total']); - - // SUCCESS: Delete 100 documents - $createBulkDocuments(100); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(100, $documents['body']['total']); - - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(100, $response['body']['total']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(0, $documents['body']['total']); - - // Delete Database - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'], array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - } } diff --git a/tests/e2e/Services/Databases/DatabasesCustomClientTest.php b/tests/e2e/Services/Databases/DatabasesCustomClientTest.php index 9f75e5f25c..d327b669da 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomClientTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomClientTest.php @@ -891,588 +891,4 @@ class DatabasesCustomClientTest extends Scope $this->assertEquals(200, $response['headers']['status-code']); } - - public function testBulkCreatePermissions(): void - { - // Create database - $database = $this->client->call(Client::METHOD_POST, '/databases', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'databaseId' => ID::unique(), - 'name' => 'Bulk Create' - ]); - - $this->assertNotEmpty($database['body']['$id']); - - $databaseId = $database['body']['$id']; - - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'collectionId' => ID::unique(), - 'name' => 'Bulk Create', - 'documentSecurity' => false, - 'permissions' => [ - Permission::read(Role::any()), - Permission::delete(Role::any()), - Permission::update(Role::any()), - ], - ]); - - $this->assertEquals(201, $collection['headers']['status-code']); - - - $data = [ - '$id' => $collection['body']['$id'], - 'databaseId' => $collection['body']['databaseId'] - ]; - - // Await attribute - $numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'key' => 'number', - 'required' => true, - ]); - - $this->assertEquals(202, $numberAttribute['headers']['status-code']); - - sleep(2); - - // TEST FAIL - Can't create document with missing collection level permissions - $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => [ - [ - '$id' => ID::unique(), - 'number' => 1, - ], - [ - '$id' => ID::unique(), - 'number' => 2, - ], - [ - '$id' => ID::unique(), - 'number' => 3, - ], - ], - ]); - - $this->assertEquals(401, $response['headers']['status-code']); - $this->assertEquals('The current user is not authorized to perform the requested action.', $response['body']['message']); - - // TEST FAIL - Can't create document with missing document level permissions - $collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'], array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'name' => 'Bulk Creates Perms', - 'documentSecurity' => true - ]); - - $this->assertEquals(200, $collection['headers']['status-code']); - - $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => [ - [ - '$id' => ID::unique(), - 'number' => 1, - ], - [ - '$id' => ID::unique(), - 'number' => 2, - ], - [ - '$id' => ID::unique(), - 'number' => 3, - ], - ], - ]); - - $this->assertEquals(401, $response['headers']['status-code']); - $this->assertEquals('The current user is not authorized to perform the requested action.', $response['body']['message']); - - // TEST FAIL - Can't create document with permissions that aren't our own. - $collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'], array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'name' => 'Bulk Creates Perms', - 'documentSecurity' => true, - 'permissions' => [ - Permission::create(Role::user($this->getUser()['$id'])), - Permission::read(Role::user($this->getUser()['$id'])), - Permission::update(Role::user($this->getUser()['$id'])), - Permission::delete(Role::user($this->getUser()['$id'])), - ] - ]); - - $this->assertEquals(200, $collection['headers']['status-code']); - - $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => [ - [ - '$id' => ID::unique(), - 'number' => 1, - '$permissions' => [ - Permission::create(Role::user('aaaaaa')), - Permission::read(Role::user('aaaaaa')), - Permission::update(Role::user('aaaaaa')), - Permission::delete(Role::user('aaaaaa')), - ] - ], - [ - '$id' => ID::unique(), - 'number' => 2, - '$permissions' => [ - Permission::create(Role::user('aaaaaa')), - Permission::read(Role::user('aaaaaa')), - Permission::update(Role::user('aaaaaa')), - Permission::delete(Role::user('aaaaaa')), - ] - ], - [ - '$id' => ID::unique(), - 'number' => 3, - '$permissions' => [ - Permission::create(Role::user('aaaaaa')), - Permission::read(Role::user('aaaaaa')), - Permission::update(Role::user('aaaaaa')), - Permission::delete(Role::user('aaaaaa')), - ] - ], - ], - ]); - - $this->assertEquals(401, $response['headers']['status-code']); - - // TEST SUCCESS - Can create document with our own permissions. - $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documents' => [ - [ - '$id' => ID::unique(), - 'number' => 1, - '$permissions' => [ - Permission::create(Role::user($this->getUser()['$id'])), - Permission::read(Role::user($this->getUser()['$id'])), - Permission::update(Role::user($this->getUser()['$id'])), - Permission::delete(Role::user($this->getUser()['$id'])), - ] - ], - [ - '$id' => ID::unique(), - 'number' => 2, - '$permissions' => [ - Permission::create(Role::user($this->getUser()['$id'])), - Permission::read(Role::user($this->getUser()['$id'])), - Permission::update(Role::user($this->getUser()['$id'])), - Permission::delete(Role::user($this->getUser()['$id'])), - ] - ], - [ - '$id' => ID::unique(), - 'number' => 3, - '$permissions' => [ - Permission::create(Role::user($this->getUser()['$id'])), - Permission::read(Role::user($this->getUser()['$id'])), - Permission::update(Role::user($this->getUser()['$id'])), - Permission::delete(Role::user($this->getUser()['$id'])), - ] - ], - ], - ]); - - $this->assertEquals(201, $response['headers']['status-code']); - $this->assertCount(3, $response['body']['documents']); - } - - // Bulk Updates - public function testBulkUpdatesPermissions(): void - { - // Create database - $database = $this->client->call(Client::METHOD_POST, '/databases', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'databaseId' => ID::unique(), - 'name' => 'Bulk Update Perms' - ]); - - $this->assertNotEmpty($database['body']['$id']); - - $databaseId = $database['body']['$id']; - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'collectionId' => ID::unique(), - 'name' => 'Bulk Updates Perms', - 'documentSecurity' => false, - 'permissions' => [ - Permission::create(Role::user($this->getUser()['$id'])) - ], - ]); - - $this->assertEquals(201, $collection['headers']['status-code']); - - $data = [ - '$id' => $collection['body']['$id'], - 'databaseId' => $collection['body']['databaseId'] - ]; - - // Await attribute - $numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'key' => 'number', - 'required' => true, - ]); - - $this->assertEquals(202, $numberAttribute['headers']['status-code']); - - sleep(2); - - // TEST: Update all documents with invalid collection level permissions - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'data' => [ - 'number' => 100 - ] - ]); - - $this->assertEquals(401, $response['headers']['status-code']); - - $collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'], array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'name' => 'Bulk Updates Perms', - 'documentSecurity' => true - ]); - - $this->assertEquals(200, $collection['headers']['status-code']); - - // TEST: Make sure we can update only documents we have permissions for - for ($i = 0; $i < 6; $i++) { - $doc = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documentId' => ID::unique(), - 'data' => [ - 'number' => $i, - ], - 'permissions' => [ - Permission::update(Role::user($this->getUser()['$id'])) - ] - ]); - - $this->assertEquals(201, $doc['headers']['status-code']); - } - - $doc = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'documentId' => ID::unique(), - 'data' => [ - 'number' => 6, - ], - 'permissions' => [ - Permission::update(Role::user('user2')), - Permission::read(Role::user($this->getUser()['$id'])), - ] - ]); - - $this->assertEquals(201, $doc['headers']['status-code']); - - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'data' => [ - 'number' => 100 - ] - ]); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertCount(6, $response['body']['documents']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] - ], $this->getHeaders()), [ - 'queries' => [Query::notEqual('number', 100)->toString()] - ]); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(1, $documents['body']['total']); - } - - public function testBulkUpdatesRelationship() - { - $database = $this->client->call(Client::METHOD_POST, '/databases', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'databaseId' => ID::unique(), - 'name' => 'Bulk Updates' - ]); - - $this->assertNotEmpty($database['body']['$id']); - - $databaseId = $database['body']['$id']; - - $collection1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'collectionId' => ID::unique(), - 'name' => 'Collection1', - 'documentSecurity' => false, - 'permissions' => [ - Permission::create(Role::any()), - Permission::read(Role::any()), - Permission::delete(Role::any()), - Permission::update(Role::any()), - ], - ]); - - $this->assertEquals(201, $collection1['headers']['status-code']); - - $collection2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'collectionId' => ID::unique(), - 'name' => 'Collection2', - 'documentSecurity' => false, - 'permissions' => [ - Permission::create(Role::any()), - Permission::read(Role::any()), - Permission::delete(Role::any()), - Permission::update(Role::any()), - ], - ]); - - $this->assertEquals(201, $collection2['headers']['status-code']); - - $collection1 = $collection1['body']['$id']; - $collection2 = $collection2['body']['$id']; - - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/attributes/relationship', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'relatedCollectionId' => $collection2, - 'type' => Database::RELATION_ONE_TO_MANY, - 'key' => 'collection2', - 'onDelete' => Database::RELATION_MUTATE_RESTRICT, - 'twoWay' => true, - 'twoWayKey' => 'collection1', - ]); - - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/attributes/string', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'key' => 'name', - 'size' => 256, - 'required' => true, - ]); - - $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection2 . '/attributes/string', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'key' => 'name', - 'size' => 256, - 'required' => true, - ]); - - sleep(3); - - $document1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collection1 . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] - ], $this->getHeaders()), [ - 'documentId' => ID::unique(), - 'data' => [ - 'name' => 'Document 1', - 'collection2' => [ - [ - 'name' => 'Document 2', - ], - ], - ], - ]); - - $this->assertEquals(201, $document1['headers']['status-code']); - $document1 = $document1['body']['$id']; - - $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collection1 . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'] - ], $this->getHeaders()), [ - 'data' => [ - 'name' => 'Document 1 Updated', - ] - ]); - - $this->assertEquals(400, $response['headers']['status-code']); - } - - public function testBulkDeletesPermissions(): void - { - // Create database - $database = $this->client->call(Client::METHOD_POST, '/databases', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'databaseId' => ID::unique(), - 'name' => 'Bulk Deletes Perms' - ]); - - $this->assertNotEmpty($database['body']['$id']); - - $databaseId = $database['body']['$id']; - - $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'collectionId' => ID::unique(), - 'name' => 'Bulk Deletes Perms', - 'documentSecurity' => false, - 'permissions' => [ - Permission::create(Role::user($this->getUser()['$id'])) - ], - ]); - - $this->assertEquals(201, $collection['headers']['status-code']); - - $data = [ - '$id' => $collection['body']['$id'], - 'databaseId' => $collection['body']['databaseId'] - ]; - - // Await attribute - $numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'key' => 'number', - 'required' => true, - ]); - - $this->assertEquals(202, $numberAttribute['headers']['status-code']); - - sleep(2); - - // TEST: Delete all documents with invalid collection level permissions - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(401, $response['headers']['status-code']); - - $collection = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'], array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]), [ - 'name' => 'Bulk Deletes Perms', - 'documentSecurity' => true - ]); - - $this->assertEquals(200, $collection['headers']['status-code']); - - // TEST: Make sure we can delete only documents we have permissions for - for ($i = 0; $i < 6; $i++) { - $doc = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders()), [ - 'documentId' => ID::unique(), - 'data' => [ - 'number' => $i, - ], - 'permissions' => [ - Permission::delete(Role::user($this->getUser()['$id'])) - ] - ]); - - $this->assertEquals(201, $doc['headers']['status-code']); - } - - $doc = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ], [ - 'documentId' => ID::unique(), - 'data' => [ - 'number' => 6, - ], - 'permissions' => [ - Permission::delete(Role::user('user2')) - ] - ]); - - $this->assertEquals(201, $doc['headers']['status-code']); - - $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - ], $this->getHeaders())); - - $this->assertEquals(200, $response['headers']['status-code']); - $this->assertEquals(6, $response['body']['total']); - - $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ])); - - $this->assertEquals(200, $documents['headers']['status-code']); - $this->assertEquals(1, $documents['body']['total']); - } } diff --git a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php index 57e0b93634..4cb0c84efd 100644 --- a/tests/e2e/Services/Databases/DatabasesCustomServerTest.php +++ b/tests/e2e/Services/Databases/DatabasesCustomServerTest.php @@ -4110,4 +4110,973 @@ class DatabasesCustomServerTest extends Scope $this->cleanupRelationshipCollection(); } + + public function testBulkCreate(): void + { + // Create database + $database = $this->client->call(Client::METHOD_POST, '/databases', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'databaseId' => ID::unique(), + 'name' => 'Bulk Create Perms', + ]); + + $this->assertNotEmpty($database['body']['$id']); + + $databaseId = $database['body']['$id']; + + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::unique(), + 'name' => 'Bulk Create Perms', + 'documentSecurity' => true, + 'permissions' => [ + Permission::create(Role::any()), + Permission::read(Role::any()), + Permission::delete(Role::any()), + Permission::update(Role::any()), + ], + ]); + + $this->assertEquals(201, $collection['headers']['status-code']); + + $data = [ + '$id' => $collection['body']['$id'], + 'databaseId' => $collection['body']['databaseId'] + ]; + + // Await attribute + $numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => 'number', + 'required' => true, + ]); + + $this->assertEquals(202, $numberAttribute['headers']['status-code']); + + sleep(1); + + $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documents' => [ + [ + '$id' => ID::unique(), + 'number' => 1, + ], + [ + '$id' => ID::unique(), + 'number' => 2, + ], + [ + '$id' => ID::unique(), + 'number' => 3, + ], + ], + ]); + + $this->assertEquals(201, $response['headers']['status-code']); + $this->assertCount(3, $response['body']['documents']); + + $response = $this->client->call(Client::METHOD_GET, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(1, $response['body']['documents'][0]['number']); + $this->assertEquals(2, $response['body']['documents'][1]['number']); + $this->assertEquals(3, $response['body']['documents'][2]['number']); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertCount(3, $response['body']['documents']); + + // TEST FAIL - Can't use data and document together + $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'number' => 5 + ], + 'documents' => [ + [ + '$id' => ID::unique(), + 'number' => 1, + ] + ], + ]); + + $this->assertEquals(400, $response['headers']['status-code']); + + // TEST FAIL - Can't use $documentId and create bulk documents + $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documentId' => ID::unique(), + 'documents' => [ + [ + '$id' => ID::unique(), + 'number' => 1, + ] + ], + ]); + + $this->assertEquals(400, $response['headers']['status-code']); + + // TEST FAIL - Can't miss $id in bulk documents + $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documents' => [ + [ + 'number' => 1, + ] + ], + ]); + + $this->assertEquals(400, $response['headers']['status-code']); + + // TEST FAIL - Can't miss number in bulk documents + $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documents' => [ + [ + '$id' => ID::unique(), + 'number' => 1, + ], + [ + '$id' => ID::unique(), + ], + ], + ]); + + $this->assertEquals(400, $response['headers']['status-code']); + + // TEST FAIL - Can't push more than APP_LIMIT_DATABASE_BATCH documents + $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documents' => array_fill(0, APP_LIMIT_DATABASE_BATCH + 1, [ + '$id' => ID::unique(), + 'number' => 1, + ]), + ]); + + $this->assertEquals(400, $response['headers']['status-code']); + + // TEST FAIL - Can't bulk create in a collection with relationships + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/relationship', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], $this->getHeaders()), [ + 'relatedCollectionId' => ID::unique(), + 'type' => 'manyToOne', + 'twoWay' => true, + 'onDelete' => 'cascade', + 'key' => 'level2', + 'twoWayKey' => 'level1' + ]); + + $this->assertEquals(202, $response['headers']['status-code']); + + sleep(1); + + $response = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$data['$id']}/documents", array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documents' => [ + ['$id' => ID::unique(), 'number' => 1,], + ['$id' => ID::unique(), 'number' => 2,], + ], + ]); + + $this->assertEquals(400, $response['headers']['status-code']); + } + + public function testBulkUpdates(): void + { + // Create database + $database = $this->client->call(Client::METHOD_POST, '/databases', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'databaseId' => ID::unique(), + 'name' => 'Bulk Updates' + ]); + + $this->assertNotEmpty($database['body']['$id']); + + $databaseId = $database['body']['$id']; + + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::unique(), + 'name' => 'Bulk Updates', + 'documentSecurity' => true, + 'permissions' => [ + Permission::create(Role::any()), + Permission::read(Role::any()), + Permission::delete(Role::any()), + Permission::update(Role::any()), + ], + ]); + + $this->assertEquals(201, $collection['headers']['status-code']); + + $data = [ + '$id' => $collection['body']['$id'], + 'databaseId' => $collection['body']['databaseId'] + ]; + + // Await attribute + $numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => 'number', + 'required' => true, + ]); + + $this->assertEquals(202, $numberAttribute['headers']['status-code']); + + // Wait for database worker to create attributes + sleep(2); + + // Create documents + $createBulkDocuments = function ($amount = 10) use ($data) { + $documents = []; + + for ($x = 1; $x <= $amount; $x++) { + $documents[] = [ + '$id' => ID::unique(), + 'number' => $x, + ]; + } + + $doc = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documents' => $documents, + ]); + + $this->assertEquals(201, $doc['headers']['status-code']); + }; + + $createBulkDocuments(); + + // TEST: Update all documents + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'number' => 100, + '$permissions' => [ + Permission::read(Role::user($this->getUser()['$id'])), + Permission::update(Role::user($this->getUser()['$id'])), + Permission::delete(Role::user($this->getUser()['$id'])), + ] + ], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertCount(10, $response['body']['documents']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + Query::equal('number', [100])->toString(), + ]); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(10, $documents['body']['total']); + + $returnedDocuments = $response['body']['documents']; + $refetchedDocuments = $documents['body']['documents']; + + $this->assertEquals($returnedDocuments, $refetchedDocuments); + + foreach ($documents['body']['documents'] as $document) { + $this->assertEquals([ + Permission::read(Role::user($this->getUser()['$id'])), + Permission::update(Role::user($this->getUser()['$id'])), + Permission::delete(Role::user($this->getUser()['$id'])), + ], $document['$permissions']); + $this->assertEquals($collection['body']['$id'], $document['$collectionId']); + $this->assertEquals($data['databaseId'], $document['$databaseId']); + $this->assertEquals($document['number'], 100); + } + + // TEST: Check permissions persist + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'number' => 200 + ], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertCount(10, $response['body']['documents']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + Query::equal('number', [200])->toString(), + ]); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(10, $documents['body']['total']); + + foreach ($documents['body']['documents'] as $document) { + $this->assertEquals([ + Permission::read(Role::user($this->getUser()['$id'])), + Permission::update(Role::user($this->getUser()['$id'])), + Permission::delete(Role::user($this->getUser()['$id'])), + ], $document['$permissions']); + } + + // TEST: Update documents with limit + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'number' => 300 + ], + 'queries' => [ + Query::limit(5)->toString(), + ], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertCount(5, $response['body']['documents']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [Query::equal('number', [200])->toString()] + ]); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(5, $documents['body']['total']); + + // TEST: Update documents with offset + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'number' => 300 + ], + 'queries' => [ + Query::offset(5)->toString(), + ], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertCount(5, $response['body']['documents']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [Query::equal('number', [300])->toString()] + ]); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(10, $documents['body']['total']); + + // TEST: Update documents with equals filter + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'number' => 400 + ], + 'queries' => [ + Query::equal('number', [300])->toString(), + ], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertCount(10, $response['body']['documents']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [Query::equal('number', [400])->toString()] + ]); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(10, $documents['body']['total']); + + // TEST: Fail - Can't bulk update in a collection with relationships + + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/relationship', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], $this->getHeaders()), [ + 'relatedCollectionId' => ID::unique(), + 'type' => 'manyToOne', + 'twoWay' => true, + 'onDelete' => 'cascade', + 'key' => 'level2', + 'twoWayKey' => 'level1' + ]); + + $this->assertEquals(202, $response['headers']['status-code']); + + sleep(1); + + $response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'data' => [ + 'number' => 500 + ], + 'queries' => [ + Query::equal('number', [300])->toString(), + ], + ]); + + $this->assertEquals(400, $response['headers']['status-code']); + } + + public function testBulkUpserts(): void + { + // Create database + $database = $this->client->call(Client::METHOD_POST, '/databases', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'databaseId' => ID::unique(), + 'name' => 'Bulk Upserts' + ]); + + $this->assertNotEmpty($database['body']['$id']); + + $databaseId = $database['body']['$id']; + + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::unique(), + 'name' => 'Bulk Upserts', + 'documentSecurity' => true, + 'permissions' => [ + Permission::create(Role::any()), + Permission::read(Role::any()), + Permission::delete(Role::any()), + Permission::update(Role::any()), + ], + ]); + + $this->assertEquals(201, $collection['headers']['status-code']); + + $data = [ + '$id' => $collection['body']['$id'], + 'databaseId' => $collection['body']['databaseId'] + ]; + + // Await attribute + $numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => 'number', + 'required' => true, + ]); + + $this->assertEquals(202, $numberAttribute['headers']['status-code']); + + // Wait for database worker to create attributes + sleep(2); + + // Create documents + $createBulkDocuments = function ($amount = 10) use ($data) { + $documents = []; + + for ($x = 1; $x <= $amount; $x++) { + $documents[] = [ + '$id' => "$x", + 'number' => $x, + ]; + } + + $response = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documents' => $documents, + ]); + + $this->assertEquals(201, $response['headers']['status-code']); + + return $documents; + }; + + $documents = $createBulkDocuments(); + + // Update 1 document + $documents[\array_key_last($documents)]['number'] = 1000; + + // Add 1 document + $documents[] = ['number' => 11]; + + // TEST: Upsert all documents + $response = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documents' => $documents, + ]); + + // Unchanged docs are skipped. 2 documents should be returned, 1 updated and 1 inserted. + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertCount(2, $response['body']['documents']); + $this->assertEquals(1000, $response['body']['documents'][0]['number']); + $this->assertEquals(11, $response['body']['documents'][1]['number']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ])); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(11, $documents['body']['total']); + + foreach ($documents['body']['documents'] as $index => $document) { + $this->assertEquals($collection['body']['$id'], $document['$collectionId']); + $this->assertEquals($data['databaseId'], $document['$databaseId']); + switch ($index) { + case 9: + $this->assertEquals(1000, $document['number']); + break; + default: + $this->assertEquals($index + 1, $document['number']); + } + } + + // TEST: Upsert permissions + $response = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documents' => [ + [ + '$id' => '1', + 'number' => 1000, + ], + [ + '$id' => '10', + '$permissions' => [ + Permission::read(Role::user($this->getUser()['$id'])), + Permission::update(Role::user($this->getUser()['$id'])), + Permission::delete(Role::user($this->getUser()['$id'])), + ], + 'number' => 10, + ], + ], + ]); + + $this->assertEquals(1000, $response['body']['documents'][0]['number']); + $this->assertEquals([], $response['body']['documents'][0]['$permissions']); + $this->assertEquals([ + Permission::read(Role::user($this->getUser()['$id'])), + Permission::update(Role::user($this->getUser()['$id'])), + Permission::delete(Role::user($this->getUser()['$id'])), + ], $response['body']['documents'][1]['$permissions']); + + // TEST: Fail - Can't bulk upsert in a collection with relationships + + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/relationship', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], $this->getHeaders()), [ + 'relatedCollectionId' => ID::unique(), + 'type' => 'manyToOne', + 'twoWay' => true, + 'onDelete' => 'cascade', + 'key' => 'level2', + 'twoWayKey' => 'level1' + ]); + + $this->assertEquals(202, $response['headers']['status-code']); + + sleep(1); + + $response = $this->client->call(Client::METHOD_PUT, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documents' => [ + [ + '$id' => '1', + 'number' => 1000, + ], + ], + ]); + + $this->assertEquals(400, $response['headers']['status-code']); + } + + public function testBulkDeletes(): void + { + // Create database + $database = $this->client->call(Client::METHOD_POST, '/databases', [ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], [ + 'databaseId' => ID::unique(), + 'name' => 'Bulk Deletes' + ]); + + $this->assertNotEmpty($database['body']['$id']); + + $databaseId = $database['body']['$id']; + + $collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'collectionId' => ID::unique(), + 'name' => 'Bulk Deletes', + 'documentSecurity' => false, + 'permissions' => [ + Permission::create(Role::any()), + Permission::read(Role::any()), + Permission::delete(Role::any()), + ], + ]); + + $this->assertEquals(201, $collection['headers']['status-code']); + + $data = [ + '$id' => $collection['body']['$id'], + 'databaseId' => $collection['body']['databaseId'] + ]; + + // Await attribute + $numberAttribute = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/integer', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ]), [ + 'key' => 'number', + 'required' => true, + ]); + + $this->assertEquals(202, $numberAttribute['headers']['status-code']); + + // wait for database worker to create attributes + sleep(2); + + // Create documents + $createBulkDocuments = function ($amount = 11) use ($data) { + $documents = []; + + for ($x = 0; $x < $amount; $x++) { + $documents[] = [ + '$id' => ID::unique(), + 'number' => $x, + ]; + } + + $doc = $this->client->call(Client::METHOD_POST, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'documents' => $documents, + ]); + + $this->assertEquals(201, $doc['headers']['status-code']); + }; + + $createBulkDocuments(); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(11, $documents['body']['total']); + + // TEST: Delete all documents + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(11, $response['body']['total']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(0, $documents['body']['total']); + + // TEST: Delete documents with query + $createBulkDocuments(); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(11, $documents['body']['total']); + + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + Query::lessThan('number', 5)->toString(), + ], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(5, $response['body']['total']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(6, $documents['body']['total']); + + foreach ($documents['body']['documents'] as $document) { + $this->assertGreaterThanOrEqual(5, $document['number']); + } + + // Cleanup + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(6, $response['body']['total']); + + // SUCCESS: Delete documents with query + $createBulkDocuments(); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(11, $documents['body']['total']); + + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + Query::lessThan('number', 5)->toString(), + ], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(5, $response['body']['total']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(6, $documents['body']['total']); + + // Cleanup + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(6, $response['body']['total']); + + // SUCCESS: Delete Documents with limit query + $createBulkDocuments(); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(11, $documents['body']['total']); + + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + Query::limit(2)->toString(), + ], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(2, $response['body']['total']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(9, $documents['body']['total']); + + // Cleanup + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(9, $response['body']['total']); + + // SUCCESS: Delete Documents with offset query + $createBulkDocuments(); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(11, $documents['body']['total']); + + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), [ + 'queries' => [ + Query::offset(5)->toString(), + ], + ]); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(6, $response['body']['total']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(5, $documents['body']['total']); + + $lastDoc = end($documents['body']['documents']); + + $this->assertNotEmpty($lastDoc); + $this->assertEquals(4, $lastDoc['number']); + + // Cleanup + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(5, $response['body']['total']); + + // SUCCESS: Delete 100 documents + $createBulkDocuments(100); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(100, $documents['body']['total']); + + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $response['headers']['status-code']); + $this->assertEquals(100, $response['body']['total']); + + $documents = $this->client->call(Client::METHOD_GET, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(200, $documents['headers']['status-code']); + $this->assertEquals(0, $documents['body']['total']); + + // TEST: Fail - Can't bulk delete in a collection with relationships + + $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['$id'] . '/attributes/relationship', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-appwrite-key' => $this->getProject()['apiKey'] + ], $this->getHeaders()), [ + 'relatedCollectionId' => ID::unique(), + 'type' => 'manyToOne', + 'twoWay' => true, + 'onDelete' => 'cascade', + 'key' => 'level2', + 'twoWayKey' => 'level1' + ]); + + $this->assertEquals(202, $response['headers']['status-code']); + + sleep(1); + + $response = $this->client->call(Client::METHOD_DELETE, '/databases/' . $data['databaseId'] . '/collections/' . $data['$id'] . '/documents', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders())); + + $this->assertEquals(400, $response['headers']['status-code']); + } }