mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
updated endpoints
This commit is contained in:
+1
-1
@@ -52,7 +52,7 @@
|
||||
"utopia-php/cache": "0.13.*",
|
||||
"utopia-php/cli": "0.15.*",
|
||||
"utopia-php/config": "0.2.*",
|
||||
"utopia-php/database": "1.*",
|
||||
"utopia-php/database": "dev-dat-677 as 1.4.9",
|
||||
"utopia-php/detector": "0.1.*",
|
||||
"utopia-php/domains": "0.8.*",
|
||||
"utopia-php/dns": "0.3.*",
|
||||
|
||||
Generated
+30
-24
@@ -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": "7553e976312b0423cc31544abb91caec",
|
||||
"content-hash": "bf86eeb3175aac99688369676b4d3f84",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -756,24 +756,21 @@
|
||||
},
|
||||
{
|
||||
"name": "google/protobuf",
|
||||
"version": "v4.32.0",
|
||||
"version": "v4.32.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/protocolbuffers/protobuf-php.git",
|
||||
"reference": "9a9a92ecbe9c671dc1863f6d4a91ea3ea12c8646"
|
||||
"reference": "c4ed1c1f9bbc1e91766e2cd6c0af749324fe87cb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/9a9a92ecbe9c671dc1863f6d4a91ea3ea12c8646",
|
||||
"reference": "9a9a92ecbe9c671dc1863f6d4a91ea3ea12c8646",
|
||||
"url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/c4ed1c1f9bbc1e91766e2cd6c0af749324fe87cb",
|
||||
"reference": "c4ed1c1f9bbc1e91766e2cd6c0af749324fe87cb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.1.0"
|
||||
},
|
||||
"provide": {
|
||||
"ext-protobuf": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">=5.0.0 <8.5.27"
|
||||
},
|
||||
@@ -797,9 +794,9 @@
|
||||
"proto"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.32.0"
|
||||
"source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.32.1"
|
||||
},
|
||||
"time": "2025-08-14T20:00:33+00:00"
|
||||
"time": "2025-09-14T05:14:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/csv",
|
||||
@@ -3638,16 +3635,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "1.4.8",
|
||||
"version": "dev-dat-677",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "dbecdf89fde33a5f81ec19f4f97fe0c3715dc83a"
|
||||
"reference": "e95802fb07225a1616e5a242c379e8910e2f724a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/dbecdf89fde33a5f81ec19f4f97fe0c3715dc83a",
|
||||
"reference": "dbecdf89fde33a5f81ec19f4f97fe0c3715dc83a",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/e95802fb07225a1616e5a242c379e8910e2f724a",
|
||||
"reference": "e95802fb07225a1616e5a242c379e8910e2f724a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3688,9 +3685,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/1.4.8"
|
||||
"source": "https://github.com/utopia-php/database/tree/dat-677"
|
||||
},
|
||||
"time": "2025-09-12T03:35:59+00:00"
|
||||
"time": "2025-09-16T18:08:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/detector",
|
||||
@@ -6236,16 +6233,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.6.26",
|
||||
"version": "9.6.27",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "a0139ea157533454f611038326f3020b3051f129"
|
||||
"reference": "0a9aa4440b6a9528cf360071502628d717af3e0a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a0139ea157533454f611038326f3020b3051f129",
|
||||
"reference": "a0139ea157533454f611038326f3020b3051f129",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0a9aa4440b6a9528cf360071502628d717af3e0a",
|
||||
"reference": "0a9aa4440b6a9528cf360071502628d717af3e0a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6319,7 +6316,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.26"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.27"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -6343,7 +6340,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-09-11T06:17:45+00:00"
|
||||
"time": "2025-09-14T06:18:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/cache",
|
||||
@@ -8510,9 +8507,18 @@
|
||||
"time": "2024-03-07T20:33:40+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"aliases": [
|
||||
{
|
||||
"package": "utopia-php/database",
|
||||
"version": "dev-dat-677",
|
||||
"alias": "1.4.9",
|
||||
"alias_normalized": "1.4.9.0"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {},
|
||||
"stability-flags": {
|
||||
"utopia-php/database": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
||||
+2
@@ -37,6 +37,8 @@ abstract class Action extends AppwriteAction
|
||||
'privileged' => [
|
||||
'$createdAt',
|
||||
'$updatedAt',
|
||||
'$createdBy',
|
||||
'$updatedBy'
|
||||
],
|
||||
];
|
||||
|
||||
|
||||
+9
-1
@@ -23,6 +23,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Validator\Numeric;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Decrement extends Action
|
||||
{
|
||||
@@ -77,12 +78,13 @@ class Decrement extends Action
|
||||
->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('user')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForStatsUsage')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $min, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage): void
|
||||
public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $min, UtopiaResponse $response, Database $dbForProject, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage): void
|
||||
{
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
if ($database->isEmpty()) {
|
||||
@@ -114,6 +116,12 @@ class Decrement extends Action
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
// Set $updatedBy field to current user ID if available
|
||||
$userId = $user->getId();
|
||||
if (!empty($userId)) {
|
||||
$document->setAttribute('$updatedBy', $userId);
|
||||
}
|
||||
|
||||
$relationships = \array_map(
|
||||
fn ($document) => $document->getAttribute('key'),
|
||||
\array_filter(
|
||||
|
||||
+9
-1
@@ -23,6 +23,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Validator\Numeric;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class Increment extends Action
|
||||
{
|
||||
@@ -77,12 +78,13 @@ class Increment extends Action
|
||||
->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('user')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForStatsUsage')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $max, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, StatsUsage $queueForStatsUsage): void
|
||||
public function action(string $databaseId, string $collectionId, string $documentId, string $attribute, int|float $value, int|float|null $max, UtopiaResponse $response, Database $dbForProject, Document $user, Event $queueForEvents, StatsUsage $queueForStatsUsage): void
|
||||
{
|
||||
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
|
||||
if ($database->isEmpty()) {
|
||||
@@ -114,6 +116,12 @@ class Increment extends Action
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
// Set $updatedBy field to current user ID if available
|
||||
$userId = $user->getId();
|
||||
if (!empty($userId)) {
|
||||
$document->setAttribute('$updatedBy', $userId);
|
||||
}
|
||||
|
||||
$relationships = \array_map(
|
||||
fn ($document) => $document->getAttribute('key'),
|
||||
\array_filter(
|
||||
|
||||
+1
-1
@@ -113,7 +113,7 @@ class Upsert extends Action
|
||||
|
||||
try {
|
||||
$modified = $dbForProject->withPreserveDates(function () use ($dbForProject, $database, $collection, $documents, $plan, &$upserted) {
|
||||
return $dbForProject->createOrUpdateDocuments(
|
||||
return $dbForProject->upsertDocuments(
|
||||
'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
$documents,
|
||||
onNext: function (Document $document) use ($plan, &$upserted) {
|
||||
|
||||
+1
-1
@@ -243,7 +243,7 @@ class Upsert extends Action
|
||||
$upserted = [];
|
||||
try {
|
||||
$dbForProject->withPreserveDates(function () use (&$upserted, $dbForProject, $database, $collection, $newDocument) {
|
||||
return $dbForProject->createOrUpdateDocuments(
|
||||
return $dbForProject->upsertDocuments(
|
||||
'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
[$newDocument],
|
||||
onNext: function (Document $document) use (&$upserted) {
|
||||
|
||||
@@ -435,7 +435,7 @@ class StatsResources extends Action
|
||||
$message = 'Stats writeDocuments project: ' . $project->getId() . '(' . $project->getSequence() . ')';
|
||||
|
||||
try {
|
||||
$dbForLogs->createOrUpdateDocuments(
|
||||
$dbForLogs->upsertDocuments(
|
||||
'stats',
|
||||
$this->documents
|
||||
);
|
||||
|
||||
@@ -69,6 +69,18 @@ class Document extends Any
|
||||
'default' => '',
|
||||
'example' => self::TYPE_DATETIME_EXAMPLE,
|
||||
])
|
||||
->addRule('$createdBy', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'User ID of the user who created the document.',
|
||||
'default' => null,
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('$updatedBy', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'User ID of the user who updated the document.',
|
||||
'default' => null,
|
||||
'example' => '5e5ea5c16897e',
|
||||
])
|
||||
->addRule('$permissions', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Document permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).',
|
||||
|
||||
@@ -7,6 +7,8 @@ use Appwrite\Tests\Retryable;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Tests\E2E\Client;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\System\System;
|
||||
|
||||
abstract class Scope extends TestCase
|
||||
@@ -40,6 +42,10 @@ abstract class Scope extends TestCase
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$this->client = null;
|
||||
|
||||
// Clean up Authorization context to prevent state contamination between tests
|
||||
Authorization::cleanRoles();
|
||||
Authorization::setRole(Role::any()->toString());
|
||||
}
|
||||
|
||||
protected function getLastEmail(int $limit = 1): array
|
||||
|
||||
@@ -4354,6 +4354,189 @@ trait DatabasesBase
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testCreatedByUpdatedBy(): void
|
||||
{
|
||||
// Setup: Create database for createdBy/updatedBy tests
|
||||
$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' => 'Test Database'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
// Setup: Create collection for createdBy/updatedBy tests
|
||||
$collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'CreatedBy UpdatedBy Collection',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
$collectionId = $collection['body']['$id'];
|
||||
|
||||
// Setup: Add attributes
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'key' => 'title',
|
||||
'size' => 255,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'key' => 'releaseYear',
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'key' => 'count',
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
// Wait for attributes to be created
|
||||
sleep(2);
|
||||
|
||||
$headers = $this->getSide() === 'client' ? array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()): ['x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']];
|
||||
|
||||
// Test 1: Create document - verify $createdBy and $updatedBy behavior
|
||||
$document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', $headers, [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'CreatedBy UpdatedBy Test',
|
||||
'releaseYear' => 2024
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $document['headers']['status-code']);
|
||||
$this->assertEquals('CreatedBy UpdatedBy Test', $document['body']['title']);
|
||||
|
||||
$documentId = $document['body']['$id'];
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $document['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $document['body']['$updatedBy']);
|
||||
|
||||
\sleep(1);
|
||||
|
||||
// Test 2: Update document - verify $updatedBy behavior
|
||||
$updatedDocument = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, $headers, [
|
||||
'data' => [
|
||||
'title' => 'Updated CreatedBy UpdatedBy Test',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $updatedDocument['headers']['status-code']);
|
||||
$this->assertEquals('Updated CreatedBy UpdatedBy Test', $updatedDocument['body']['title']);
|
||||
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $updatedDocument['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $updatedDocument['body']['$updatedBy']);
|
||||
|
||||
// Test 4: Upsert operation
|
||||
$upsertDocument = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, $headers, [
|
||||
'data' => [
|
||||
'title' => 'Upserted Document',
|
||||
'releaseYear' => 2025
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $upsertDocument['headers']['status-code']);
|
||||
$this->assertEquals('Upserted Document', $upsertDocument['body']['title']);
|
||||
|
||||
// Client side: $createdBy should remain original user, $updatedBy should be current user
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $upsertDocument['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $upsertDocument['body']['$updatedBy']);
|
||||
|
||||
// Test 5: Create new document with upsert
|
||||
$newUpsertId = ID::unique();
|
||||
$newUpsertDocument = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $newUpsertId, $headers, [
|
||||
'data' => [
|
||||
'title' => 'New Upserted Document',
|
||||
'releaseYear' => 2026
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $newUpsertDocument['headers']['status-code']);
|
||||
$this->assertEquals('New Upserted Document', $newUpsertDocument['body']['title']);
|
||||
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $newUpsertDocument['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $newUpsertDocument['body']['$updatedBy']);
|
||||
|
||||
// Test 6: Increment/Decrement operations
|
||||
$countDocument = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', $headers, [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Count Test Document',
|
||||
'count' => 10
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $countDocument['headers']['status-code']);
|
||||
$countDocumentId = $countDocument['body']['$id'];
|
||||
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $countDocument['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $countDocument['body']['$updatedBy']);
|
||||
|
||||
// Test increment operation
|
||||
$incrementResponse = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $countDocumentId . '/count/increment', $headers, [
|
||||
'value' => 5
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $incrementResponse['headers']['status-code']);
|
||||
$this->assertEquals(15, $incrementResponse['body']['count']);
|
||||
|
||||
// Client side: $createdBy should remain unchanged, $updatedBy should be current user
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $incrementResponse['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $incrementResponse['body']['$updatedBy']);
|
||||
|
||||
// Test decrement operation
|
||||
$decrementResponse = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $countDocumentId . '/count/decrement', $headers, [
|
||||
'value' => 3
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $decrementResponse['headers']['status-code']);
|
||||
$this->assertEquals(12, $decrementResponse['body']['count']);
|
||||
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $decrementResponse['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $decrementResponse['body']['$updatedBy']);
|
||||
|
||||
// Cleanup
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, $headers);
|
||||
}
|
||||
|
||||
public function testUpdatePermissionsWithEmptyPayload(): array
|
||||
{
|
||||
// Create Database
|
||||
|
||||
@@ -6729,4 +6729,246 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
}
|
||||
|
||||
public function testCreatedByUpdatedByModify(): 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' => 'CreatedBy UpdatedBy Test DB'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
// Create collection
|
||||
$collection = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'CreatedBy UpdatedBy Collection',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
$collectionId = $collection['body']['$id'];
|
||||
|
||||
// Add attributes
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'key' => 'title',
|
||||
'size' => 255,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/integer', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'key' => 'count',
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
sleep(2);
|
||||
|
||||
// Test 1: Create document with manual $createdBy and $updatedBy
|
||||
$document = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Server Side Test',
|
||||
'count' => 10,
|
||||
'$createdBy' => 'user-123',
|
||||
'$updatedBy' => 'user-456'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $document['headers']['status-code']);
|
||||
$this->assertEquals('user-123', $document['body']['$createdBy']);
|
||||
$this->assertEquals('user-456', $document['body']['$updatedBy']);
|
||||
$documentId = $document['body']['$id'];
|
||||
|
||||
// Test 2: Update document with different $updatedBy
|
||||
$updatedDocument = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'data' => [
|
||||
'title' => 'Updated Server Side Test',
|
||||
'$updatedBy' => 'user-789'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $updatedDocument['headers']['status-code']);
|
||||
$this->assertEquals('user-123', $updatedDocument['body']['$createdBy']); // Should remain unchanged
|
||||
$this->assertEquals('user-789', $updatedDocument['body']['$updatedBy']); // Should be updated
|
||||
|
||||
// Test 3: Bulk create with mixed $createdBy and $updatedBy values
|
||||
// bulk1: both createdBy and updatedBy set
|
||||
// bulk2: only createdBy set, updatedBy should be null
|
||||
// bulk3: neither set, both should be null
|
||||
$bulkDocuments = [
|
||||
[
|
||||
'$id' => 'bulk1',
|
||||
'title' => 'Bulk Document 1',
|
||||
'count' => 1,
|
||||
'$createdBy' => 'bulk-user-1',
|
||||
'$updatedBy' => 'bulk-user-1'
|
||||
],
|
||||
[
|
||||
'$id' => 'bulk2',
|
||||
'title' => 'Bulk Document 2',
|
||||
'count' => 2,
|
||||
'$createdBy' => 'bulk-user-2'
|
||||
],
|
||||
[
|
||||
'$id' => 'bulk3',
|
||||
'title' => 'Bulk Document 3',
|
||||
'count' => 3
|
||||
]
|
||||
];
|
||||
|
||||
$bulkCreateResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'documents' => $bulkDocuments
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $bulkCreateResponse['headers']['status-code']);
|
||||
$this->assertCount(3, $bulkCreateResponse['body']['documents']);
|
||||
|
||||
// Verify bulk create results
|
||||
$this->assertEquals('bulk-user-1', $bulkCreateResponse['body']['documents'][0]['$createdBy']);
|
||||
$this->assertEquals('bulk-user-1', $bulkCreateResponse['body']['documents'][0]['$updatedBy']);
|
||||
$this->assertEquals('bulk-user-2', $bulkCreateResponse['body']['documents'][1]['$createdBy']);
|
||||
|
||||
// Test 4: Bulk update with $updatedBy
|
||||
$bulkUpdateResponse = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'data' => [
|
||||
'title' => 'Bulk Updated',
|
||||
'$updatedBy' => 'bulk-updater'
|
||||
],
|
||||
'queries' => [Query::startsWith('$id', 'bulk')->toString()]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $bulkUpdateResponse['headers']['status-code']);
|
||||
$this->assertCount(3, $bulkUpdateResponse['body']['documents']);
|
||||
|
||||
// Verify bulk update results - $createdBy should remain unchanged, $updatedBy should be updated
|
||||
foreach ($bulkUpdateResponse['body']['documents'] as $doc) {
|
||||
$this->assertEquals('bulk-updater', $doc['$updatedBy']);
|
||||
$this->assertEquals('Bulk Updated', $doc['title']);
|
||||
|
||||
// $createdBy should remain as originally set
|
||||
if ($doc['$id'] === 'bulk1') {
|
||||
$this->assertEquals('bulk-user-1', $doc['$createdBy']);
|
||||
} elseif ($doc['$id'] === 'bulk2') {
|
||||
$this->assertEquals('bulk-user-2', $doc['$createdBy']);
|
||||
}
|
||||
}
|
||||
|
||||
// Test 5: Bulk upsert with $createdBy and $updatedBy
|
||||
// bulk1: existing document - createdBy should be ignored, updatedBy should be updated
|
||||
// new-upsert: new document - both should be set as specified
|
||||
$upsertDocuments = [
|
||||
[
|
||||
'$id' => 'bulk1', // Existing document
|
||||
'title' => 'Upserted Document 1',
|
||||
'count' => 100,
|
||||
'$createdBy' => 'should-not-change',
|
||||
'$updatedBy' => 'upsert-updater-1'
|
||||
],
|
||||
[
|
||||
'$id' => 'new-upsert',
|
||||
'title' => 'New Upserted Document',
|
||||
'count' => 200,
|
||||
'$createdBy' => 'new-creator',
|
||||
'$updatedBy' => 'new-updater'
|
||||
]
|
||||
];
|
||||
|
||||
$bulkUpsertResponse = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'documents' => $upsertDocuments
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $bulkUpsertResponse['headers']['status-code']);
|
||||
$this->assertCount(2, $bulkUpsertResponse['body']['documents']);
|
||||
|
||||
// Verify upsert results
|
||||
foreach ($bulkUpsertResponse['body']['documents'] as $doc) {
|
||||
if ($doc['$id'] === 'bulk1') {
|
||||
$this->assertEquals('should-not-change', $doc['$createdBy']);
|
||||
$this->assertEquals('upsert-updater-1', $doc['$updatedBy']);
|
||||
} elseif ($doc['$id'] === 'new-upsert') {
|
||||
$this->assertEquals('new-creator', $doc['$createdBy']);
|
||||
$this->assertEquals('new-updater', $doc['$updatedBy']);
|
||||
}
|
||||
}
|
||||
|
||||
// Test 6: Increment operation
|
||||
// making requests via root
|
||||
$incrementResponse = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId . '/count/increment', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'value' => 5
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $incrementResponse['headers']['status-code']);
|
||||
$this->assertEquals(15, $incrementResponse['body']['count']);
|
||||
$this->assertEquals('user-123', $incrementResponse['body']['$createdBy']);
|
||||
$this->assertEquals($this->getRoot()['$id'], $incrementResponse['body']['$updatedBy']);
|
||||
|
||||
// Test 7: Decrement operation
|
||||
$decrementResponse = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId . '/count/decrement', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'value' => 3
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $decrementResponse['headers']['status-code']);
|
||||
$this->assertEquals(12, $decrementResponse['body']['count']);
|
||||
$this->assertEquals('user-123', $decrementResponse['body']['$createdBy']);
|
||||
$this->assertEquals($this->getRoot()['$id'], $decrementResponse['body']['$updatedBy']);
|
||||
|
||||
// Cleanup
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8828,4 +8828,186 @@ trait DatabasesBase
|
||||
$this->client->call(Client::METHOD_DELETE, "/tablesdb/{$databaseId}", $headers);
|
||||
}
|
||||
|
||||
public function testCreatedByUpdatedBy(): void
|
||||
{
|
||||
// Setup: Create database for createdBy/updatedBy tests
|
||||
$database = $this->client->call(Client::METHOD_POST, '/tablesdb', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Test Database'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
// Setup: Create table for createdBy/updatedBy tests
|
||||
$table = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'CreatedBy UpdatedBy Table',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $table['headers']['status-code']);
|
||||
$tableId = $table['body']['$id'];
|
||||
|
||||
// Setup: Add columns
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/string', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'key' => 'title',
|
||||
'size' => 255,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/integer', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'key' => 'releaseYear',
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/integer', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'key' => 'count',
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
// Wait for columns to be created
|
||||
sleep(2);
|
||||
|
||||
$headers = array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders());
|
||||
|
||||
// Test 1: Create row - verify $createdBy and $updatedBy behavior
|
||||
$row = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows', $headers, [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'CreatedBy UpdatedBy Test',
|
||||
'releaseYear' => 2024
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $row['headers']['status-code']);
|
||||
$this->assertEquals('CreatedBy UpdatedBy Test', $row['body']['title']);
|
||||
|
||||
$rowId = $row['body']['$id'];
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $row['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $row['body']['$updatedBy']);
|
||||
|
||||
\sleep(1);
|
||||
|
||||
// Test 2: Update row - verify $updatedBy behavior
|
||||
$updatedRow = $this->client->call(Client::METHOD_PATCH, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $rowId, $headers, [
|
||||
'data' => [
|
||||
'title' => 'Updated CreatedBy UpdatedBy Test',
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $updatedRow['headers']['status-code']);
|
||||
$this->assertEquals('Updated CreatedBy UpdatedBy Test', $updatedRow['body']['title']);
|
||||
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $updatedRow['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $updatedRow['body']['$updatedBy']);
|
||||
|
||||
// Test 4: Upsert operation
|
||||
$upsertRow = $this->client->call(Client::METHOD_PUT, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $rowId, $headers, [
|
||||
'data' => [
|
||||
'title' => 'Upserted Row',
|
||||
'releaseYear' => 2025
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $upsertRow['headers']['status-code']);
|
||||
$this->assertEquals('Upserted Row', $upsertRow['body']['title']);
|
||||
|
||||
// Client side: $createdBy should remain original user, $updatedBy should be current user
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $upsertRow['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $upsertRow['body']['$updatedBy']);
|
||||
|
||||
// Test 5: Create new row with upsert
|
||||
$newUpsertId = ID::unique();
|
||||
$newUpsertRow = $this->client->call(Client::METHOD_PUT, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $newUpsertId, $headers, [
|
||||
'data' => [
|
||||
'title' => 'New Upserted Row',
|
||||
'releaseYear' => 2026
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $newUpsertRow['headers']['status-code']);
|
||||
$this->assertEquals('New Upserted Row', $newUpsertRow['body']['title']);
|
||||
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $newUpsertRow['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $newUpsertRow['body']['$updatedBy']);
|
||||
|
||||
// Test 6: Increment/Decrement operations
|
||||
$countRow = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows', $headers, [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Count Test Row',
|
||||
'count' => 10
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $countRow['headers']['status-code']);
|
||||
$countRowId = $countRow['body']['$id'];
|
||||
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $countRow['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $countRow['body']['$updatedBy']);
|
||||
|
||||
// Test increment operation
|
||||
$incrementResponse = $this->client->call(Client::METHOD_PATCH, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $countRowId . '/count/increment', $headers, [
|
||||
'value' => 5
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $incrementResponse['headers']['status-code']);
|
||||
$this->assertEquals(15, $incrementResponse['body']['count']);
|
||||
|
||||
// Client side: $createdBy should remain unchanged, $updatedBy should be current user
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $incrementResponse['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $incrementResponse['body']['$updatedBy']);
|
||||
|
||||
// Test decrement operation
|
||||
$decrementResponse = $this->client->call(Client::METHOD_PATCH, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $countRowId . '/count/decrement', $headers, [
|
||||
'value' => 3
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $decrementResponse['headers']['status-code']);
|
||||
$this->assertEquals(12, $decrementResponse['body']['count']);
|
||||
|
||||
$user = $this->getSide() === 'client' ?$this->getUser() : $this->getRoot();
|
||||
$this->assertEquals($user['$id'], $decrementResponse['body']['$createdBy']);
|
||||
$this->assertEquals($user['$id'], $decrementResponse['body']['$updatedBy']);
|
||||
|
||||
// Cleanup
|
||||
$this->client->call(Client::METHOD_DELETE, '/tablesdb/' . $databaseId, $headers);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6697,4 +6697,246 @@ class DatabasesCustomServerTest extends Scope
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
}
|
||||
|
||||
public function testCreatedByUpdatedByModify(): void
|
||||
{
|
||||
// Create database
|
||||
$database = $this->client->call(Client::METHOD_POST, '/tablesdb', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'CreatedBy UpdatedBy Test DB'
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $database['headers']['status-code']);
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
// Create table
|
||||
$table = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'tableId' => ID::unique(),
|
||||
'name' => 'CreatedBy UpdatedBy Table',
|
||||
'documentSecurity' => false,
|
||||
'permissions' => [
|
||||
Permission::create(Role::any()),
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $table['headers']['status-code']);
|
||||
$tableId = $table['body']['$id'];
|
||||
|
||||
// Add columns
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/string', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'key' => 'title',
|
||||
'size' => 255,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
$this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/columns/integer', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'key' => 'count',
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
sleep(2);
|
||||
|
||||
// Test 1: Create row with manual $createdBy and $updatedBy
|
||||
$row = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'rowId' => ID::unique(),
|
||||
'data' => [
|
||||
'title' => 'Server Side Test',
|
||||
'count' => 10,
|
||||
'$createdBy' => 'user-123',
|
||||
'$updatedBy' => 'user-456'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $row['headers']['status-code']);
|
||||
$this->assertEquals('user-123', $row['body']['$createdBy']);
|
||||
$this->assertEquals('user-456', $row['body']['$updatedBy']);
|
||||
$rowId = $row['body']['$id'];
|
||||
|
||||
// Test 2: Update row with different $updatedBy
|
||||
$updatedRow = $this->client->call(Client::METHOD_PATCH, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $rowId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'data' => [
|
||||
'title' => 'Updated Server Side Test',
|
||||
'$updatedBy' => 'user-789'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $updatedRow['headers']['status-code']);
|
||||
$this->assertEquals('user-123', $updatedRow['body']['$createdBy']); // Should remain unchanged
|
||||
$this->assertEquals('user-789', $updatedRow['body']['$updatedBy']); // Should be updated
|
||||
|
||||
// Test 3: Bulk create with mixed $createdBy and $updatedBy values
|
||||
// bulk1: both createdBy and updatedBy set
|
||||
// bulk2: only createdBy set, updatedBy should be null
|
||||
// bulk3: neither set, both should be null
|
||||
$bulkRows = [
|
||||
[
|
||||
'$id' => 'bulk1',
|
||||
'title' => 'Bulk Row 1',
|
||||
'count' => 1,
|
||||
'$createdBy' => 'bulk-user-1',
|
||||
'$updatedBy' => 'bulk-user-1'
|
||||
],
|
||||
[
|
||||
'$id' => 'bulk2',
|
||||
'title' => 'Bulk Row 2',
|
||||
'count' => 2,
|
||||
'$createdBy' => 'bulk-user-2'
|
||||
],
|
||||
[
|
||||
'$id' => 'bulk3',
|
||||
'title' => 'Bulk Row 3',
|
||||
'count' => 3
|
||||
]
|
||||
];
|
||||
|
||||
$bulkCreateResponse = $this->client->call(Client::METHOD_POST, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'rows' => $bulkRows
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $bulkCreateResponse['headers']['status-code']);
|
||||
$this->assertCount(3, $bulkCreateResponse['body']['rows']);
|
||||
|
||||
// Verify bulk create results
|
||||
$this->assertEquals('bulk-user-1', $bulkCreateResponse['body']['rows'][0]['$createdBy']);
|
||||
$this->assertEquals('bulk-user-1', $bulkCreateResponse['body']['rows'][0]['$updatedBy']);
|
||||
$this->assertEquals('bulk-user-2', $bulkCreateResponse['body']['rows'][1]['$createdBy']);
|
||||
|
||||
// Test 4: Bulk update with $updatedBy
|
||||
$bulkUpdateResponse = $this->client->call(Client::METHOD_PATCH, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'data' => [
|
||||
'title' => 'Bulk Updated',
|
||||
'$updatedBy' => 'bulk-updater'
|
||||
],
|
||||
'queries' => [Query::startsWith('$id', 'bulk')->toString()]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $bulkUpdateResponse['headers']['status-code']);
|
||||
$this->assertCount(3, $bulkUpdateResponse['body']['rows']);
|
||||
|
||||
// Verify bulk update results - $createdBy should remain unchanged, $updatedBy should be updated
|
||||
foreach ($bulkUpdateResponse['body']['rows'] as $doc) {
|
||||
$this->assertEquals('bulk-updater', $doc['$updatedBy']);
|
||||
$this->assertEquals('Bulk Updated', $doc['title']);
|
||||
|
||||
// $createdBy should remain as originally set
|
||||
if ($doc['$id'] === 'bulk1') {
|
||||
$this->assertEquals('bulk-user-1', $doc['$createdBy']);
|
||||
} elseif ($doc['$id'] === 'bulk2') {
|
||||
$this->assertEquals('bulk-user-2', $doc['$createdBy']);
|
||||
}
|
||||
}
|
||||
|
||||
// Test 5: Bulk upsert with $createdBy and $updatedBy
|
||||
// bulk1: existing row - createdBy should be ignored, updatedBy should be updated
|
||||
// new-upsert: new row - both should be set as specified
|
||||
$upsertRows = [
|
||||
[
|
||||
'$id' => 'bulk1', // Existing row
|
||||
'title' => 'Upserted Row 1',
|
||||
'count' => 100,
|
||||
'$createdBy' => 'should-not-change',
|
||||
'$updatedBy' => 'upsert-updater-1'
|
||||
],
|
||||
[
|
||||
'$id' => 'new-upsert',
|
||||
'title' => 'New Upserted Row',
|
||||
'count' => 200,
|
||||
'$createdBy' => 'new-creator',
|
||||
'$updatedBy' => 'new-updater'
|
||||
]
|
||||
];
|
||||
|
||||
$bulkUpsertResponse = $this->client->call(Client::METHOD_PUT, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'rows' => $upsertRows
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $bulkUpsertResponse['headers']['status-code']);
|
||||
$this->assertCount(2, $bulkUpsertResponse['body']['rows']);
|
||||
|
||||
// Verify upsert results
|
||||
foreach ($bulkUpsertResponse['body']['rows'] as $doc) {
|
||||
if ($doc['$id'] === 'bulk1') {
|
||||
$this->assertEquals('should-not-change', $doc['$createdBy']);
|
||||
$this->assertEquals('upsert-updater-1', $doc['$updatedBy']);
|
||||
} elseif ($doc['$id'] === 'new-upsert') {
|
||||
$this->assertEquals('new-creator', $doc['$createdBy']);
|
||||
$this->assertEquals('new-updater', $doc['$updatedBy']);
|
||||
}
|
||||
}
|
||||
|
||||
// Test 6: Increment operation
|
||||
// making requests via root
|
||||
$incrementResponse = $this->client->call(Client::METHOD_PATCH, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $rowId . '/count/increment', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'value' => 5
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $incrementResponse['headers']['status-code']);
|
||||
$this->assertEquals(15, $incrementResponse['body']['count']);
|
||||
$this->assertEquals('user-123', $incrementResponse['body']['$createdBy']);
|
||||
$this->assertEquals($this->getRoot()['$id'], $incrementResponse['body']['$updatedBy']);
|
||||
|
||||
// Test 7: Decrement operation
|
||||
$decrementResponse = $this->client->call(Client::METHOD_PATCH, '/tablesdb/' . $databaseId . '/tables/' . $tableId . '/rows/' . $rowId . '/count/decrement', [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
], [
|
||||
'value' => 3
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $decrementResponse['headers']['status-code']);
|
||||
$this->assertEquals(12, $decrementResponse['body']['count']);
|
||||
$this->assertEquals('user-123', $decrementResponse['body']['$createdBy']);
|
||||
$this->assertEquals($this->getRoot()['$id'], $decrementResponse['body']['$updatedBy']);
|
||||
|
||||
// Cleanup
|
||||
$this->client->call(Client::METHOD_DELETE, '/tablesdb/' . $databaseId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user