mirror of
https://github.com/appwrite/appwrite
synced 2026-05-23 00:49:02 +00:00
Merge pull request #9986 from appwrite/feat-incr
Add increment + decrement routes
This commit is contained in:
commit
ff92b23d8e
6 changed files with 388 additions and 24 deletions
|
|
@ -38,6 +38,7 @@ use Utopia\Database\Exception\Relationship as RelationshipException;
|
|||
use Utopia\Database\Exception\Restricted as RestrictedException;
|
||||
use Utopia\Database\Exception\Structure as StructureException;
|
||||
use Utopia\Database\Exception\Truncate as TruncateException;
|
||||
use Utopia\Database\Exception\Type as TypeException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
|
@ -62,6 +63,7 @@ use Utopia\Validator\Integer;
|
|||
use Utopia\Validator\IP;
|
||||
use Utopia\Validator\JSON;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Numeric;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\Validator\URL;
|
||||
|
|
@ -4462,6 +4464,160 @@ App::put('/v1/databases/:databaseId/collections/:collectionId/documents/:documen
|
|||
$response->dynamic($document, Response::MODEL_DOCUMENT);
|
||||
});
|
||||
|
||||
App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:documentId/:attribute/increment')
|
||||
->desc('Increment document attribute')
|
||||
->groups(['api', 'database'])
|
||||
->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].increment')
|
||||
->label('scope', 'documents.write')
|
||||
->label('resourceType', RESOURCE_TYPE_DATABASES)
|
||||
->label('audits.event', 'documents.increment')
|
||||
->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 * 2)
|
||||
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
|
||||
->label('sdk', new Method(
|
||||
namespace: 'databases',
|
||||
group: 'documents',
|
||||
name: 'incrementDocumentAttribute',
|
||||
description: '/docs/references/databases/increment-document-attribute.md',
|
||||
auth: [AuthType::KEY, AuthType::SESSION, AuthType::JWT],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_DOCUMENT,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('documentId', '', new UID(), 'Document ID.')
|
||||
->param('attribute', '', new Key(), 'Attribute key.')
|
||||
->param('value', 1, new Numeric(), 'Value to increment the attribute by. The value must be a number.', true)
|
||||
->param('max', null, new Numeric(), 'Maximum value for the attribute. If the current value is greater than this value, an error will be thrown.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForStatsUsage')
|
||||
->action(function (string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $max, Response $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage) {
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
if ($database->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId));
|
||||
if ($collection->isEmpty()) {
|
||||
throw new Exception(Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$document = $dbForProject->increaseDocumentAttribute(
|
||||
collection: 'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
id: $documentId,
|
||||
attribute: $attribute,
|
||||
value: $value,
|
||||
max: $max
|
||||
);
|
||||
} catch (ConflictException) {
|
||||
throw new Exception(Exception::DOCUMENT_UPDATE_CONFLICT);
|
||||
} catch (NotFoundException) {
|
||||
throw new Exception(Exception::ATTRIBUTE_NOT_FOUND);
|
||||
} catch (LimitException) {
|
||||
throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, 'Attribute "' . $attribute . '" has reached the maximum value of ' . $max);
|
||||
} catch (TypeException) {
|
||||
throw new Exception(Exception::ATTRIBUTE_TYPE_INVALID, 'Attribute "' . $attribute . '" is not a number');
|
||||
}
|
||||
|
||||
$queueForStatsUsage
|
||||
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, 1)
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), METRIC_DATABASE_ID_OPERATIONS_WRITES), 1);
|
||||
|
||||
$queueForEvents
|
||||
->setParam('databaseId', $databaseId)
|
||||
->setParam('collectionId', $collectionId)
|
||||
->setContext('collection', $collection)
|
||||
->setContext('database', $database);
|
||||
|
||||
$response->dynamic($document, Response::MODEL_DOCUMENT);
|
||||
});
|
||||
|
||||
App::patch('/v1/databases/:databaseId/collections/:collectionId/documents/:documentId/:attribute/decrement')
|
||||
->desc('Decrement document attribute')
|
||||
->groups(['api', 'database'])
|
||||
->label('event', 'databases.[databaseId].collections.[collectionId].documents.[documentId].decrement')
|
||||
->label('scope', 'documents.write')
|
||||
->label('resourceType', RESOURCE_TYPE_DATABASES)
|
||||
->label('audits.event', 'documents.decrement')
|
||||
->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 * 2)
|
||||
->label('abuse-time', APP_LIMIT_WRITE_RATE_PERIOD_DEFAULT)
|
||||
->label('sdk', new Method(
|
||||
namespace: 'databases',
|
||||
group: 'documents',
|
||||
name: 'decrementDocumentAttribute',
|
||||
description: '/docs/references/databases/decrement-document-attribute.md',
|
||||
auth: [AuthType::KEY, AuthType::SESSION, AuthType::JWT],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_OK,
|
||||
model: Response::MODEL_DOCUMENT,
|
||||
)
|
||||
],
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('databaseId', '', new UID(), 'Database ID.')
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('documentId', '', new UID(), 'Document ID.')
|
||||
->param('attribute', '', new Key(), 'Attribute key.')
|
||||
->param('value', 1, new Numeric(), 'Value to decrement the attribute by. The value must be a number.', true)
|
||||
->param('min', null, new Numeric(), 'Minimum value for the attribute. If the current value is lesser than this value, an exception will be thrown.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForStatsUsage')
|
||||
->action(function (string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $min, Response $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage) {
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
if ($database->isEmpty()) {
|
||||
throw new Exception(Exception::DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$collection = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId));
|
||||
if ($collection->isEmpty()) {
|
||||
throw new Exception(Exception::COLLECTION_NOT_FOUND);
|
||||
}
|
||||
|
||||
try {
|
||||
$document = $dbForProject->decreaseDocumentAttribute(
|
||||
collection: 'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
id: $documentId,
|
||||
attribute: $attribute,
|
||||
value: $value,
|
||||
min: $min
|
||||
);
|
||||
} catch (ConflictException) {
|
||||
throw new Exception(Exception::DOCUMENT_UPDATE_CONFLICT);
|
||||
} catch (NotFoundException) {
|
||||
throw new Exception(Exception::ATTRIBUTE_NOT_FOUND);
|
||||
} catch (LimitException) {
|
||||
throw new Exception(Exception::ATTRIBUTE_LIMIT_EXCEEDED, 'Attribute "' . $attribute . '" has reached the minimum value of ' . $min);
|
||||
} catch (TypeException) {
|
||||
throw new Exception(Exception::ATTRIBUTE_TYPE_INVALID, 'Attribute "' . $attribute . '" is not a number');
|
||||
}
|
||||
|
||||
$queueForStatsUsage
|
||||
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, 1)
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), METRIC_DATABASE_ID_OPERATIONS_WRITES), 1);
|
||||
|
||||
$queueForEvents
|
||||
->setParam('databaseId', $databaseId)
|
||||
->setParam('collectionId', $collectionId)
|
||||
->setContext('collection', $collection)
|
||||
->setContext('database', $database);
|
||||
|
||||
$response->dynamic($document, Response::MODEL_DOCUMENT);
|
||||
});
|
||||
|
||||
App::patch('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||
->desc('Update documents')
|
||||
->groups(['api', 'database'])
|
||||
|
|
|
|||
36
composer.lock
generated
36
composer.lock
generated
|
|
@ -3490,16 +3490,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.71.1",
|
||||
"version": "0.71.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "7b2622d336c2fa4bd6627d5e175083bd4f3c7c0e"
|
||||
"reference": "308cbeb65780f954f9f3abfff2ef17c5941ae00e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/7b2622d336c2fa4bd6627d5e175083bd4f3c7c0e",
|
||||
"reference": "7b2622d336c2fa4bd6627d5e175083bd4f3c7c0e",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/308cbeb65780f954f9f3abfff2ef17c5941ae00e",
|
||||
"reference": "308cbeb65780f954f9f3abfff2ef17c5941ae00e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -3540,9 +3540,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.71.1"
|
||||
"source": "https://github.com/utopia-php/database/tree/0.71.4"
|
||||
},
|
||||
"time": "2025-06-09T18:14:46+00:00"
|
||||
"time": "2025-06-10T15:47:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/detector",
|
||||
|
|
@ -4584,16 +4584,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/vcs",
|
||||
"version": "0.10.4",
|
||||
"version": "0.10.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/vcs.git",
|
||||
"reference": "f635b368909eb3c3fe57344fe43525e74e8fdc03"
|
||||
"reference": "b358439dc387f6097019eb83ebb9fc258fe9da05"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/f635b368909eb3c3fe57344fe43525e74e8fdc03",
|
||||
"reference": "f635b368909eb3c3fe57344fe43525e74e8fdc03",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/b358439dc387f6097019eb83ebb9fc258fe9da05",
|
||||
"reference": "b358439dc387f6097019eb83ebb9fc258fe9da05",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -4627,9 +4627,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/vcs/issues",
|
||||
"source": "https://github.com/utopia-php/vcs/tree/0.10.4"
|
||||
"source": "https://github.com/utopia-php/vcs/tree/0.10.5"
|
||||
},
|
||||
"time": "2025-06-02T09:18:36+00:00"
|
||||
"time": "2025-06-10T15:01:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/websocket",
|
||||
|
|
@ -4807,16 +4807,16 @@
|
|||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "0.41.1",
|
||||
"version": "0.41.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "6d9318abf4542a757c87abf056557d6afa1dc06b"
|
||||
"reference": "07804269131f411576aac60c795a5ebc3afaa48a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/6d9318abf4542a757c87abf056557d6afa1dc06b",
|
||||
"reference": "6d9318abf4542a757c87abf056557d6afa1dc06b",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/07804269131f411576aac60c795a5ebc3afaa48a",
|
||||
"reference": "07804269131f411576aac60c795a5ebc3afaa48a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
|
@ -4852,9 +4852,9 @@
|
|||
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
||||
"support": {
|
||||
"issues": "https://github.com/appwrite/sdk-generator/issues",
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/0.41.1"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/0.41.4"
|
||||
},
|
||||
"time": "2025-06-01T04:20:04+00:00"
|
||||
"time": "2025-06-10T08:28:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
Decrement a specific attribute of a document by a given value.
|
||||
|
|
@ -0,0 +1 @@
|
|||
Increment a specific attribute of a document by a given value.
|
||||
|
|
@ -25,7 +25,7 @@ class Base extends Queries
|
|||
{
|
||||
$config = Config::getParam('collections', []);
|
||||
|
||||
$collections = array_merge(
|
||||
$collections = \array_merge(
|
||||
$config['projects'],
|
||||
$config['buckets'],
|
||||
$config['databases'],
|
||||
|
|
@ -34,7 +34,7 @@ class Base extends Queries
|
|||
);
|
||||
|
||||
$collection = $collections[$collection];
|
||||
// array for constant lookup time
|
||||
|
||||
$allowedAttributesLookup = [];
|
||||
foreach ($allowedAttributes as $attribute) {
|
||||
$allowedAttributesLookup[$attribute] = true;
|
||||
|
|
@ -70,10 +70,9 @@ class Base extends Queries
|
|||
'type' => Database::VAR_DATETIME,
|
||||
'array' => false,
|
||||
]);
|
||||
|
||||
$sequence = new Document([
|
||||
$attributes[] = new Document([
|
||||
'key' => '$sequence',
|
||||
'type' => Database::VAR_STRING,
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'array' => false,
|
||||
]);
|
||||
|
||||
|
|
@ -82,7 +81,7 @@ class Base extends Queries
|
|||
new Offset(),
|
||||
new Cursor(),
|
||||
new Filter($attributes, APP_DATABASE_QUERY_MAX_VALUES),
|
||||
new Order([...$attributes, $sequence]),
|
||||
new Order($attributes),
|
||||
];
|
||||
|
||||
parent::__construct($validators);
|
||||
|
|
|
|||
|
|
@ -5298,4 +5298,211 @@ trait DatabasesBase
|
|||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testIncrementAttribute(): void
|
||||
{
|
||||
$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' => 'CounterDatabase'
|
||||
]);
|
||||
$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' => 'CounterCollection',
|
||||
'documentSecurity' => true,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
],
|
||||
]);
|
||||
$collectionId = $collection['body']['$id'];
|
||||
|
||||
// Add integer attribute
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'count',
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
\sleep(2);
|
||||
|
||||
// Create document with initial count = 5
|
||||
$doc = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documentId' => 'counter1',
|
||||
'data' => [
|
||||
'count' => 5
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
],
|
||||
]);
|
||||
$this->assertEquals(201, $doc['headers']['status-code']);
|
||||
|
||||
// Increment by default 1
|
||||
$inc = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/counter1/count/increment', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]));
|
||||
$this->assertEquals(200, $inc['headers']['status-code']);
|
||||
$this->assertEquals(6, $inc['body']['count']);
|
||||
|
||||
// Verify count = 6
|
||||
$get = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/counter1', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
$this->assertEquals(6, $get['body']['count']);
|
||||
|
||||
// Increment by custom value 4
|
||||
$inc2 = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/counter1/count/increment', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'value' => 4
|
||||
]);
|
||||
$this->assertEquals(200, $inc2['headers']['status-code']);
|
||||
$this->assertEquals(10, $inc2['body']['count']);
|
||||
|
||||
$get2 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/counter1', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
$this->assertEquals(10, $get2['body']['count']);
|
||||
|
||||
// Test max limit exceeded
|
||||
$err = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/counter1/count/increment', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), ['max' => 8]);
|
||||
$this->assertEquals(400, $err['headers']['status-code']);
|
||||
|
||||
// Test attribute not found
|
||||
$notFound = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/counter1/unknown/increment', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]));
|
||||
$this->assertEquals(404, $notFound['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testDecrementAttribute(): void
|
||||
{
|
||||
$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' => 'CounterDatabase'
|
||||
]);
|
||||
|
||||
$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' => 'CounterCollection',
|
||||
'documentSecurity' => true,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
],
|
||||
]);
|
||||
|
||||
$collectionId = $collection['body']['$id'];
|
||||
|
||||
// Add integer attribute
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'count',
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
\sleep(2);
|
||||
|
||||
// Create document with initial count = 10
|
||||
$doc = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => ['count' => 10],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$documentId = $doc['body']['$id'];
|
||||
|
||||
// Decrement by default 1 (count = 10 -> 9)
|
||||
$dec = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId . '/count/decrement', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]));
|
||||
$this->assertEquals(200, $dec['headers']['status-code']);
|
||||
$this->assertEquals(9, $dec['body']['count']);
|
||||
|
||||
$get = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
$this->assertEquals(9, $get['body']['count']);
|
||||
|
||||
// Decrement by custom value 3 (count 9 -> 6)
|
||||
$dec2 = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId . '/count/decrement', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), [
|
||||
'value' => 3
|
||||
]);
|
||||
$this->assertEquals(200, $dec2['headers']['status-code']);
|
||||
$this->assertEquals(6, $dec2['body']['count']);
|
||||
|
||||
$get2 = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
$this->assertEquals(6, $get2['body']['count']);
|
||||
|
||||
// Test min limit exceeded
|
||||
$err = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId . '/count/decrement', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), ['min' => 7]);
|
||||
$this->assertEquals(400, $err['headers']['status-code']);
|
||||
|
||||
// Test type error on non-numeric attribut
|
||||
$typeErr = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId . '/count/decrement', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
]), ['value' => 'not-a-number']);
|
||||
$this->assertEquals(400, $typeErr['headers']['status-code']);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue