Implement Bulk Deletes API

This commit is contained in:
Bradley Schofield
2024-11-07 12:30:17 +09:00
parent 5d4ae8075a
commit 86053e9028
6 changed files with 476 additions and 63 deletions
+69
View File
@@ -3809,6 +3809,75 @@ App::delete('/v1/databases/:databaseId/collections/:collectionId/documents/:docu
$response->noContent();
});
App::delete('/v1/databases/:databaseId/collections/:collectionId/documents')
->alias('/v1/database/collections/:collectionId/documents', ['databaseId' => 'default'])
->desc('Delete documents')
->groups(['api', 'database'])
->label('scope', 'documents.write')
->label('resourceType', RESOURCE_TYPE_DATABASES)
->label('event', 'databases.[databaseId].collections.[collectionId].documents.delete')
->label('audits.event', 'documents.delete')
->label('audits.resource', 'database/{request.databaseId}/collection/{request.collectionId}')
->label('abuse-key', 'ip:{ip},method:{method},url:{url},userId:{userId}')
->label('abuse-limit', APP_LIMIT_WRITE_RATE_DEFAULT)
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
->label('sdk.auth', [APP_AUTH_TYPE_SESSION, APP_AUTH_TYPE_KEY, APP_AUTH_TYPE_JWT])
->label('sdk.namespace', 'databases')
->label('sdk.method', 'deleteDocuments')
->label('sdk.description', '/docs/references/databases/delete-documents.md')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.model', Response::MODEL_NONE)
->label('sdk.offline.model', '/databases/{databaseId}/collections/{collectionId}/documents')
->label('sdk.offline.key', '{documentId}')
->param('databaseId', '', new UID(), 'Database ID.')
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
->param('queries', [], new ArrayList(new Text(APP_LIMIT_ARRAY_ELEMENT_SIZE), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long.', true)
->inject('requestTimestamp')
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->inject('queueForUsage')
->inject('mode')
->action(function (string $databaseId, string $collectionId, array $queries, ?\DateTime $requestTimestamp, Response $response, Database $dbForProject, Event $queueForEvents, Usage $queueForUsage, string $mode) {
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
$isAPIKey = Auth::isAppUser(Authorization::getRoles());
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::getRoles());
if ($database->isEmpty() || (!$database->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
$collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getInternalId(), $collectionId));
if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
throw new Exception(Exception::COLLECTION_NOT_FOUND);
}
try {
$queries = Query::parseQueries($queries);
} catch (QueryException $e) {
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
}
var_dump($queries);
try {
$modified = $dbForProject->withRequestTimestamp($requestTimestamp, function () use ($dbForProject, $database, $collection, $queries) {
return $dbForProject->deleteDocuments(
'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
$queries
);
});
} catch (NotFoundException $e) {
throw new Exception(Exception::COLLECTION_NOT_FOUND);
}
return $response->dynamic(new Document([
'modified' => $modified,
]), Response::MODEL_BULK_OPERATION);
});
App::get('/v1/databases/usage')
->desc('Get databases usage stats')
->groups(['api', 'database', 'usage'])
+2 -2
View File
@@ -48,10 +48,10 @@
"utopia-php/abuse": "0.43.0",
"utopia-php/analytics": "0.10.*",
"utopia-php/audit": "0.43.0",
"utopia-php/cache": "0.10.*",
"utopia-php/cache": "0.11.*",
"utopia-php/cli": "0.15.*",
"utopia-php/config": "0.2.*",
"utopia-php/database": "0.53.12",
"utopia-php/database": "0.53.17",
"utopia-php/domains": "0.5.*",
"utopia-php/dsn": "0.2.1",
"utopia-php/framework": "0.33.*",
Generated
+61 -61
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "102bab0efa76adc92312b9c5a7f488e3",
"content-hash": "971e88c7387ffd92d755772e0f4e7805",
"packages": [
{
"name": "adhocore/jwt",
@@ -1574,16 +1574,16 @@
},
{
"name": "utopia-php/cache",
"version": "0.10.2",
"version": "0.11.0",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/cache.git",
"reference": "b22c6eb6d308de246b023efd0fc9758aee8b8247"
"reference": "8ebcab5aac7606331cef69b0081f6c9eff2e58bc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/cache/zipball/b22c6eb6d308de246b023efd0fc9758aee8b8247",
"reference": "b22c6eb6d308de246b023efd0fc9758aee8b8247",
"url": "https://api.github.com/repos/utopia-php/cache/zipball/8ebcab5aac7606331cef69b0081f6c9eff2e58bc",
"reference": "8ebcab5aac7606331cef69b0081f6c9eff2e58bc",
"shasum": ""
},
"require": {
@@ -1594,7 +1594,7 @@
},
"require-dev": {
"laravel/pint": "1.2.*",
"phpstan/phpstan": "1.9.x-dev",
"phpstan/phpstan": "^1.12",
"phpunit/phpunit": "^9.3",
"vimeo/psalm": "4.13.1"
},
@@ -1618,9 +1618,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/cache/issues",
"source": "https://github.com/utopia-php/cache/tree/0.10.2"
"source": "https://github.com/utopia-php/cache/tree/0.11.0"
},
"time": "2024-06-25T20:36:35+00:00"
"time": "2024-11-05T16:53:58+00:00"
},
{
"name": "utopia-php/cli",
@@ -1724,23 +1724,23 @@
},
{
"name": "utopia-php/database",
"version": "0.53.12",
"version": "0.53.17",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/database.git",
"reference": "4068d0c5c503ec4562f8c0aa9cfd095889418b83"
"reference": "07e3e5a1f5dbf9b351aab138085bde06611b305a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/database/zipball/4068d0c5c503ec4562f8c0aa9cfd095889418b83",
"reference": "4068d0c5c503ec4562f8c0aa9cfd095889418b83",
"url": "https://api.github.com/repos/utopia-php/database/zipball/07e3e5a1f5dbf9b351aab138085bde06611b305a",
"reference": "07e3e5a1f5dbf9b351aab138085bde06611b305a",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"ext-pdo": "*",
"php": ">=8.3",
"utopia-php/cache": "0.10.*",
"utopia-php/cache": "0.11.*",
"utopia-php/framework": "0.33.*",
"utopia-php/mongo": "0.3.*"
},
@@ -1774,9 +1774,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/database/issues",
"source": "https://github.com/utopia-php/database/tree/0.53.12"
"source": "https://github.com/utopia-php/database/tree/0.53.17"
},
"time": "2024-11-04T07:51:44+00:00"
"time": "2024-11-06T09:20:59+00:00"
},
{
"name": "utopia-php/domains",
@@ -2495,16 +2495,16 @@
},
{
"name": "utopia-php/queue",
"version": "0.7.0",
"version": "0.7.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/queue.git",
"reference": "917565256eb94bcab7246f7a746b1a486813761b"
"reference": "94c240d9f6383829807ce7b2d737f04b159fd3e8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/queue/zipball/917565256eb94bcab7246f7a746b1a486813761b",
"reference": "917565256eb94bcab7246f7a746b1a486813761b",
"url": "https://api.github.com/repos/utopia-php/queue/zipball/94c240d9f6383829807ce7b2d737f04b159fd3e8",
"reference": "94c240d9f6383829807ce7b2d737f04b159fd3e8",
"shasum": ""
},
"require": {
@@ -2550,9 +2550,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/queue/issues",
"source": "https://github.com/utopia-php/queue/tree/0.7.0"
"source": "https://github.com/utopia-php/queue/tree/0.7.1"
},
"time": "2024-01-17T19:00:43+00:00"
"time": "2024-11-05T17:00:38+00:00"
},
{
"name": "utopia-php/registry",
@@ -2608,16 +2608,16 @@
},
{
"name": "utopia-php/storage",
"version": "0.18.5",
"version": "0.18.6",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/storage.git",
"reference": "7d355c5e3ccc8ecebc0266f8ddd30088a43be919"
"reference": "893ccf06e183f8ece2aed8dbf14d64d6ba036071"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/storage/zipball/7d355c5e3ccc8ecebc0266f8ddd30088a43be919",
"reference": "7d355c5e3ccc8ecebc0266f8ddd30088a43be919",
"url": "https://api.github.com/repos/utopia-php/storage/zipball/893ccf06e183f8ece2aed8dbf14d64d6ba036071",
"reference": "893ccf06e183f8ece2aed8dbf14d64d6ba036071",
"shasum": ""
},
"require": {
@@ -2657,9 +2657,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/storage/issues",
"source": "https://github.com/utopia-php/storage/tree/0.18.5"
"source": "https://github.com/utopia-php/storage/tree/0.18.6"
},
"time": "2024-09-04T08:57:27+00:00"
"time": "2024-11-06T09:58:50+00:00"
},
{
"name": "utopia-php/swoole",
@@ -2770,22 +2770,22 @@
},
{
"name": "utopia-php/vcs",
"version": "0.8.2",
"version": "0.8.3",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/vcs.git",
"reference": "eb9b7eade1a46a4f660e0d5a6304f7fa26ec9d18"
"reference": "a032ed0611a8f4467aeaa9484f73223074457337"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/eb9b7eade1a46a4f660e0d5a6304f7fa26ec9d18",
"reference": "eb9b7eade1a46a4f660e0d5a6304f7fa26ec9d18",
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/a032ed0611a8f4467aeaa9484f73223074457337",
"reference": "a032ed0611a8f4467aeaa9484f73223074457337",
"shasum": ""
},
"require": {
"adhocore/jwt": "^1.1",
"php": ">=8.0",
"utopia-php/cache": "^0.10.0",
"utopia-php/cache": "^0.11.0",
"utopia-php/framework": "0.*.*"
},
"require-dev": {
@@ -2813,9 +2813,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/vcs/issues",
"source": "https://github.com/utopia-php/vcs/tree/0.8.2"
"source": "https://github.com/utopia-php/vcs/tree/0.8.3"
},
"time": "2024-08-13T14:36:30+00:00"
"time": "2024-11-05T17:10:09+00:00"
},
{
"name": "utopia-php/websocket",
@@ -4004,16 +4004,16 @@
},
{
"name": "phpdocumentor/reflection-docblock",
"version": "5.4.1",
"version": "5.5.1",
"source": {
"type": "git",
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
"reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c"
"reference": "0c70d2c566e899666f367ab7b80986beb3581e6f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c",
"reference": "9d07b3f7fdcf5efec5d1609cba3c19c5ea2bdc9c",
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/0c70d2c566e899666f367ab7b80986beb3581e6f",
"reference": "0c70d2c566e899666f367ab7b80986beb3581e6f",
"shasum": ""
},
"require": {
@@ -4026,13 +4026,13 @@
"webmozart/assert": "^1.9.1"
},
"require-dev": {
"mockery/mockery": "~1.3.5",
"mockery/mockery": "~1.3.5 || ~1.6.0",
"phpstan/extension-installer": "^1.1",
"phpstan/phpstan": "^1.8",
"phpstan/phpstan-mockery": "^1.1",
"phpstan/phpstan-webmozart-assert": "^1.2",
"phpunit/phpunit": "^9.5",
"vimeo/psalm": "^5.13"
"psalm/phar": "^5.26"
},
"type": "library",
"extra": {
@@ -4062,9 +4062,9 @@
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.4.1"
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.5.1"
},
"time": "2024-05-21T05:55:05+00:00"
"time": "2024-11-06T11:58:54+00:00"
},
{
"name": "phpdocumentor/type-resolver",
@@ -5875,16 +5875,16 @@
},
{
"name": "symfony/console",
"version": "v7.1.6",
"version": "v7.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "bb5192af6edc797cbab5c8e8ecfea2fe5f421e57"
"reference": "3284aafcac338b6e86fd955ee4d794cbe434151a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/bb5192af6edc797cbab5c8e8ecfea2fe5f421e57",
"reference": "bb5192af6edc797cbab5c8e8ecfea2fe5f421e57",
"url": "https://api.github.com/repos/symfony/console/zipball/3284aafcac338b6e86fd955ee4d794cbe434151a",
"reference": "3284aafcac338b6e86fd955ee4d794cbe434151a",
"shasum": ""
},
"require": {
@@ -5948,7 +5948,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v7.1.6"
"source": "https://github.com/symfony/console/tree/v7.1.7"
},
"funding": [
{
@@ -5964,7 +5964,7 @@
"type": "tidelift"
}
],
"time": "2024-10-09T08:46:59+00:00"
"time": "2024-11-05T15:34:55+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -6546,16 +6546,16 @@
},
{
"name": "symfony/process",
"version": "v7.1.6",
"version": "v7.1.7",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "6aaa189ddb4ff6b5de8fa3210f2fb42c87b4d12e"
"reference": "9b8a40b7289767aa7117e957573c2a535efe6585"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/6aaa189ddb4ff6b5de8fa3210f2fb42c87b4d12e",
"reference": "6aaa189ddb4ff6b5de8fa3210f2fb42c87b4d12e",
"url": "https://api.github.com/repos/symfony/process/zipball/9b8a40b7289767aa7117e957573c2a535efe6585",
"reference": "9b8a40b7289767aa7117e957573c2a535efe6585",
"shasum": ""
},
"require": {
@@ -6587,7 +6587,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v7.1.6"
"source": "https://github.com/symfony/process/tree/v7.1.7"
},
"funding": [
{
@@ -6603,7 +6603,7 @@
"type": "tidelift"
}
],
"time": "2024-09-25T14:20:29+00:00"
"time": "2024-11-06T09:25:12+00:00"
},
{
"name": "symfony/service-contracts",
@@ -6876,16 +6876,16 @@
},
{
"name": "twig/twig",
"version": "v3.14.0",
"version": "v3.14.1",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72"
"reference": "f405356d20fb43603bcadc8b09bfb676cb04a379"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/126b2c97818dbff0cdf3fbfc881aedb3d40aae72",
"reference": "126b2c97818dbff0cdf3fbfc881aedb3d40aae72",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/f405356d20fb43603bcadc8b09bfb676cb04a379",
"reference": "f405356d20fb43603bcadc8b09bfb676cb04a379",
"shasum": ""
},
"require": {
@@ -6939,7 +6939,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.14.0"
"source": "https://github.com/twigphp/Twig/tree/v3.14.1"
},
"funding": [
{
@@ -6951,7 +6951,7 @@
"type": "tidelift"
}
],
"time": "2024-09-09T17:55:12+00:00"
"time": "2024-11-06T18:17:38+00:00"
},
{
"name": "webmozart/glob",
@@ -7005,7 +7005,7 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
+3
View File
@@ -31,6 +31,7 @@ use Appwrite\Utopia\Response\Model\BaseList;
use Appwrite\Utopia\Response\Model\Branch;
use Appwrite\Utopia\Response\Model\Bucket;
use Appwrite\Utopia\Response\Model\Build;
use Appwrite\Utopia\Response\Model\BulkOperation;
use Appwrite\Utopia\Response\Model\Collection;
use Appwrite\Utopia\Response\Model\ConsoleVariables;
use Appwrite\Utopia\Response\Model\Continent;
@@ -151,6 +152,7 @@ class Response extends SwooleResponse
public const MODEL_INDEX_LIST = 'indexList';
public const MODEL_DOCUMENT = 'document';
public const MODEL_DOCUMENT_LIST = 'documentList';
public const MODEL_BULK_OPERATION = 'bulkOperation';
// Database Attributes
public const MODEL_ATTRIBUTE = 'attribute';
@@ -482,6 +484,7 @@ class Response extends SwooleResponse
->setModel(new Migration())
->setModel(new MigrationReport())
->setModel(new MigrationFirebaseProject())
->setModel(new BulkOperation())
// Tests (keep last)
->setModel(new Mock());
@@ -0,0 +1,41 @@
<?php
namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Model;
class BulkOperation extends Model
{
public function __construct()
{
$this
->addRule('modified', [
'type' => self::TYPE_INTEGER,
'description' => 'Total number of documents affected by the operation.',
'default' => 0,
'example' => 64,
]);
}
/**
* Get Name
*
* @return string
*/
public function getName(): string
{
return 'BulkOperation';
}
/**
* Get Type
*
* @return string
*/
public function getType(): string
{
return Response::MODEL_BULK_OPERATION;
}
}
@@ -4799,4 +4799,304 @@ trait DatabasesBase
$this->assertEquals(408, $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 = 10) use ($data) {
for ($x = 0; $x <= $amount; $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()), [
'documentId' => ID::unique(),
'data' => [
'number' => $x,
],
]);
$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']['modified']);
$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']['modified']);
$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']['modified']);
// 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']['modified']);
$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']['modified']);
// 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']['modified']);
$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']['modified']);
// 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']['modified']);
$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']['modified']);
// SUCCESS: Delete over 1k documents
$createBulkDocuments(1000);
$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(1000, $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(1000, $response['body']['modified']);
$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()));
}
}