mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
added modify createdAt/updatedAt support
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": "0.73.0",
|
||||
"utopia-php/database": "0.74.*",
|
||||
"utopia-php/detector": "0.1.*",
|
||||
"utopia-php/domains": "0.8.*",
|
||||
"utopia-php/dsn": "0.2.1",
|
||||
|
||||
Generated
+73
-49
@@ -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": "f4876940be4499bea26a77a036dece4f",
|
||||
"content-hash": "43a92af943693f80341a8582cf582986",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -2547,16 +2547,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
"version": "v7.3.1",
|
||||
"version": "v7.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client.git",
|
||||
"reference": "4403d87a2c16f33345dca93407a8714ee8c05a64"
|
||||
"reference": "1c064a0c67749923483216b081066642751cc2c7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/4403d87a2c16f33345dca93407a8714ee8c05a64",
|
||||
"reference": "4403d87a2c16f33345dca93407a8714ee8c05a64",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/1c064a0c67749923483216b081066642751cc2c7",
|
||||
"reference": "1c064a0c67749923483216b081066642751cc2c7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2622,7 +2622,7 @@
|
||||
"http"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.3.1"
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2633,12 +2633,16 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-06-28T07:58:39+00:00"
|
||||
"time": "2025-07-15T11:36:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client-contracts",
|
||||
@@ -3493,16 +3497,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.73.0",
|
||||
"version": "0.74.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "f9b6c587e54069dc64c2d29174ce8a42b7ba6491"
|
||||
"reference": "065b4812799d57fd2c596f88aadd51644247c7e3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/f9b6c587e54069dc64c2d29174ce8a42b7ba6491",
|
||||
"reference": "f9b6c587e54069dc64c2d29174ce8a42b7ba6491",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/065b4812799d57fd2c596f88aadd51644247c7e3",
|
||||
"reference": "065b4812799d57fd2c596f88aadd51644247c7e3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3543,9 +3547,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.73.0"
|
||||
"source": "https://github.com/utopia-php/database/tree/0.74.3"
|
||||
},
|
||||
"time": "2025-07-27T04:10:06+00:00"
|
||||
"time": "2025-07-31T15:00:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/detector",
|
||||
@@ -4810,16 +4814,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "0.41.24",
|
||||
"version": "0.41.26",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "c9ebf8daa25332ca701515d42e8d0c4a7be6a489"
|
||||
"reference": "5a13191a5a4bdec8fe1b1180ff67f75c4ff6ac0b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/c9ebf8daa25332ca701515d42e8d0c4a7be6a489",
|
||||
"reference": "c9ebf8daa25332ca701515d42e8d0c4a7be6a489",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/5a13191a5a4bdec8fe1b1180ff67f75c4ff6ac0b",
|
||||
"reference": "5a13191a5a4bdec8fe1b1180ff67f75c4ff6ac0b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4855,9 +4859,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.24"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/0.41.26"
|
||||
},
|
||||
"time": "2025-07-28T06:27:00+00:00"
|
||||
"time": "2025-07-30T06:53:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/annotations",
|
||||
@@ -7258,16 +7262,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v7.3.1",
|
||||
"version": "v7.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "9e27aecde8f506ba0fd1d9989620c04a87697101"
|
||||
"reference": "5f360ebc65c55265a74d23d7fe27f957870158a1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/9e27aecde8f506ba0fd1d9989620c04a87697101",
|
||||
"reference": "9e27aecde8f506ba0fd1d9989620c04a87697101",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/5f360ebc65c55265a74d23d7fe27f957870158a1",
|
||||
"reference": "5f360ebc65c55265a74d23d7fe27f957870158a1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7332,7 +7336,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v7.3.1"
|
||||
"source": "https://github.com/symfony/console/tree/v7.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7343,25 +7347,29 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-06-27T19:55:54+00:00"
|
||||
"time": "2025-07-30T17:13:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v7.3.0",
|
||||
"version": "v7.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb"
|
||||
"reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
|
||||
"reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd",
|
||||
"reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7398,7 +7406,7 @@
|
||||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v7.3.0"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v7.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7409,25 +7417,29 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-25T15:15:23+00:00"
|
||||
"time": "2025-07-07T08:17:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v7.3.0",
|
||||
"version": "v7.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d"
|
||||
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/ec2344cf77a48253bbca6939aa3d2477773ea63d",
|
||||
"reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe",
|
||||
"reference": "2a6614966ba1074fa93dae0bc804227422df4dfe",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7462,7 +7474,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v7.3.0"
|
||||
"source": "https://github.com/symfony/finder/tree/v7.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7473,25 +7485,29 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-30T19:00:26+00:00"
|
||||
"time": "2025-07-15T13:41:35+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
"version": "v7.3.0",
|
||||
"version": "v7.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/options-resolver.git",
|
||||
"reference": "afb9a8038025e5dbc657378bfab9198d75f10fca"
|
||||
"reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/afb9a8038025e5dbc657378bfab9198d75f10fca",
|
||||
"reference": "afb9a8038025e5dbc657378bfab9198d75f10fca",
|
||||
"url": "https://api.github.com/repos/symfony/options-resolver/zipball/119bcf13e67dbd188e5dbc74228b1686f66acd37",
|
||||
"reference": "119bcf13e67dbd188e5dbc74228b1686f66acd37",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7529,7 +7545,7 @@
|
||||
"options"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/options-resolver/tree/v7.3.0"
|
||||
"source": "https://github.com/symfony/options-resolver/tree/v7.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7540,12 +7556,16 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-04-04T13:12:05+00:00"
|
||||
"time": "2025-07-15T11:36:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
@@ -7924,16 +7944,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v7.3.0",
|
||||
"version": "v7.3.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125"
|
||||
"reference": "42f505aff654e62ac7ac2ce21033818297ca89ca"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125",
|
||||
"reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/42f505aff654e62ac7ac2ce21033818297ca89ca",
|
||||
"reference": "42f505aff654e62ac7ac2ce21033818297ca89ca",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7991,7 +8011,7 @@
|
||||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v7.3.0"
|
||||
"source": "https://github.com/symfony/string/tree/v7.3.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8002,12 +8022,16 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-04-20T20:19:01+00:00"
|
||||
"time": "2025-07-10T08:47:49+00:00"
|
||||
},
|
||||
{
|
||||
"name": "textalk/websocket",
|
||||
|
||||
+12
-10
@@ -125,16 +125,18 @@ class Update extends Action
|
||||
$documents = [];
|
||||
|
||||
try {
|
||||
$modified = $dbForProject->updateDocuments(
|
||||
'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
new Document($data),
|
||||
$queries,
|
||||
onNext: function (Document $document) use ($plan, &$documents) {
|
||||
if (\count($documents) < ($plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH)) {
|
||||
$documents[] = $document;
|
||||
}
|
||||
},
|
||||
);
|
||||
$modified = $dbForProject->withPreserveDates(function () use ($plan, &$documents, $dbForProject, $database, $collection, $data, $queries) {
|
||||
return $dbForProject->updateDocuments(
|
||||
'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
new Document($data),
|
||||
$queries,
|
||||
onNext: function (Document $document) use ($plan, &$documents) {
|
||||
if (\count($documents) < ($plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH)) {
|
||||
$documents[] = $document;
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
} catch (ConflictException) {
|
||||
throw new Exception($this->getConflictException());
|
||||
} catch (RelationshipException $e) {
|
||||
|
||||
+11
-9
@@ -106,15 +106,17 @@ class Upsert extends Action
|
||||
$upserted = [];
|
||||
|
||||
try {
|
||||
$modified = $dbForProject->createOrUpdateDocuments(
|
||||
'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
$documents,
|
||||
onNext: function (Document $document) use ($plan, &$upserted) {
|
||||
if (\count($upserted) < ($plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH)) {
|
||||
$upserted[] = $document;
|
||||
}
|
||||
},
|
||||
);
|
||||
$modified = $dbForProject->withPreserveDates(function () use ($dbForProject, $database, $collection, $documents, $plan, &$upserted) {
|
||||
return $dbForProject->createOrUpdateDocuments(
|
||||
'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
$documents,
|
||||
onNext: function (Document $document) use ($plan, &$upserted) {
|
||||
if (\count($upserted) < ($plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH)) {
|
||||
$upserted[] = $document;
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
} catch (ConflictException) {
|
||||
throw new Exception($this->getConflictException());
|
||||
} catch (DuplicateException) {
|
||||
|
||||
+20
-4
@@ -332,7 +332,7 @@ class Create extends Action
|
||||
}
|
||||
};
|
||||
|
||||
$documents = \array_map(function ($document) use ($collection, $permissions, $checkPermissions, $isBulk, $documentId, $setPermissions) {
|
||||
$documents = \array_map(function ($document) use ($collection, $permissions, $checkPermissions, $isBulk, $documentId, $setPermissions, $isAPIKey) {
|
||||
$document['$collection'] = $collection->getId();
|
||||
|
||||
// Determine the source ID depending on whether it's a bulk operation.
|
||||
@@ -350,6 +350,20 @@ class Create extends Action
|
||||
|
||||
// Assign a unique ID if needed, otherwise use the provided ID.
|
||||
$document['$id'] = $sourceId === 'unique()' ? ID::unique() : $sourceId;
|
||||
|
||||
// Allowing to add createdAt and updatedAt timestamps if server side(api key)
|
||||
$createdAt = $document['$createdAt'] ?? null;
|
||||
$updatedAt = $document['$updatedAt'] ?? null;
|
||||
if (!$isAPIKey) {
|
||||
if ($createdAt !== null) {
|
||||
throw new Exception($this->getInvalidStructureException(), 'Attribute "$createdAt" is not allowed');
|
||||
}
|
||||
|
||||
if ($updatedAt !== null) {
|
||||
throw new Exception($this->getInvalidStructureException(), 'Attribute "$updatedAt" is not allowed');
|
||||
}
|
||||
}
|
||||
|
||||
$document = new Document($document);
|
||||
$setPermissions($document, $permissions);
|
||||
$checkPermissions($collection, $document, Database::PERMISSION_CREATE);
|
||||
@@ -358,9 +372,11 @@ class Create extends Action
|
||||
}, $documents);
|
||||
|
||||
try {
|
||||
$dbForProject->createDocuments(
|
||||
'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
$documents
|
||||
$dbForProject->withPreserveDates(
|
||||
fn () => $dbForProject->createDocuments(
|
||||
'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
$documents,
|
||||
)
|
||||
);
|
||||
} catch (DuplicateException) {
|
||||
throw new Exception($this->getDuplicateException());
|
||||
|
||||
+14
-2
@@ -109,6 +109,18 @@ class Update extends Action
|
||||
throw new Exception($this->getParentNotFoundException());
|
||||
}
|
||||
|
||||
// Allowing to add createdAt and updatedAt timestamps if server side(api key)
|
||||
$createdAt = $data['$createdAt'] ?? null;
|
||||
$updatedAt = $data['$updatedAt'] ?? null;
|
||||
if (!$isAPIKey) {
|
||||
if ($createdAt !== null) {
|
||||
throw new Exception($this->getInvalidStructureException(), 'Attribute "$createdAt" is not allowed');
|
||||
}
|
||||
|
||||
if ($updatedAt !== null) {
|
||||
throw new Exception($this->getInvalidStructureException(), 'Attribute "$updatedAt" is not allowed');
|
||||
}
|
||||
}
|
||||
// Read permission should not be required for update
|
||||
/** @var Document $document */
|
||||
$document = Authorization::skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence() . '_collection_' . $collection->getSequence(), $documentId));
|
||||
@@ -233,11 +245,11 @@ class Update extends Action
|
||||
try {
|
||||
$document = $dbForProject->withRequestTimestamp(
|
||||
$requestTimestamp,
|
||||
fn () => $dbForProject->updateDocument(
|
||||
fn () => $dbForProject->withPreserveDates(fn () => $dbForProject->updateDocument(
|
||||
'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
$document->getId(),
|
||||
$newDocument
|
||||
)
|
||||
))
|
||||
);
|
||||
} catch (ConflictException) {
|
||||
throw new Exception($this->getConflictException());
|
||||
|
||||
+21
-7
@@ -153,6 +153,18 @@ class Upsert extends Action
|
||||
}
|
||||
}
|
||||
}
|
||||
// Allowing to add createdAt and updatedAt timestamps if server side(api key)
|
||||
$createdAt = $data['$createdAt'] ?? null;
|
||||
$updatedAt = $data['$updatedAt'] ?? null;
|
||||
if (!$isAPIKey) {
|
||||
if ($createdAt !== null) {
|
||||
throw new Exception($this->getInvalidStructureException(), 'Attribute "$createdAt" is not allowed');
|
||||
}
|
||||
|
||||
if ($updatedAt !== null) {
|
||||
throw new Exception($this->getInvalidStructureException(), 'Attribute "$updatedAt" is not allowed');
|
||||
}
|
||||
}
|
||||
|
||||
$data['$id'] = $documentId;
|
||||
$data['$permissions'] = $permissions ?? [];
|
||||
@@ -236,13 +248,15 @@ class Upsert extends Action
|
||||
|
||||
$upserted = [];
|
||||
try {
|
||||
$dbForProject->createOrUpdateDocuments(
|
||||
'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
[$newDocument],
|
||||
onNext: function (Document $document) use (&$upserted) {
|
||||
$upserted[] = $document;
|
||||
},
|
||||
);
|
||||
$dbForProject->withPreserveDates(function () use (&$upserted, $dbForProject, $database, $collection, $newDocument) {
|
||||
return $dbForProject->createOrUpdateDocuments(
|
||||
'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
[$newDocument],
|
||||
onNext: function (Document $document) use (&$upserted) {
|
||||
$upserted[] = $document;
|
||||
},
|
||||
);
|
||||
});
|
||||
} catch (ConflictException) {
|
||||
throw new Exception($this->getConflictException());
|
||||
} catch (DuplicateException) {
|
||||
|
||||
@@ -2876,7 +2876,6 @@ trait DatabasesBase
|
||||
'releaseYear' => 2017,
|
||||
'birthDay' => '1976-06-12 14:12:55',
|
||||
'actors' => [],
|
||||
'$createdAt' => 5 // Should be ignored
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
@@ -4206,17 +4205,18 @@ trait DatabasesBase
|
||||
$document = $this->client->call(Client::METHOD_PATCH, '/databases/' . $data['databaseId'] . '/collections/' . $data['moviesId'] . '/documents/' . $documentId, $headers, [
|
||||
'data' => [
|
||||
'title' => 'Again Updated Date Test',
|
||||
'$createdAt' => '2022-08-01 13:09:23.040', // $createdAt is not updatable
|
||||
'$updatedAt' => '2022-08-01 13:09:23.050' // system will update it not api
|
||||
'$createdAt' => '2022-08-01 13:09:23.040',
|
||||
'$updatedAt' => '2022-08-01 13:09:23.050'
|
||||
]
|
||||
]);
|
||||
if ($this->getSide() === 'client') {
|
||||
$this->assertEquals($document['headers']['status-code'], 400);
|
||||
} else {
|
||||
$this->assertEquals($document['body']['title'], 'Again Updated Date Test');
|
||||
$this->assertEquals($document['body']['$createdAt'], DateTime::formatTz('2022-08-01 13:09:23.040'));
|
||||
$this->assertEquals($document['body']['$updatedAt'], DateTime::formatTz('2022-08-01 13:09:23.050'));
|
||||
|
||||
$this->assertEquals($document['body']['title'], 'Again Updated Date Test');
|
||||
$this->assertEquals($document['body']['$createdAt'], $createdAt);
|
||||
$this->assertNotEquals($document['body']['$createdAt'], '2022-08-01 13:09:23.040');
|
||||
$this->assertNotEquals($document['body']['$updatedAt'], $updatedAt);
|
||||
$this->assertNotEquals($document['body']['$updatedAt'], $updatedAtSecond);
|
||||
$this->assertNotEquals($document['body']['$updatedAt'], '2022-08-01 13:09:23.050');
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -889,4 +889,157 @@ class DatabasesCustomClientTest extends Scope
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
}
|
||||
public function testModifyCreatedAtUpdatedAtSingleDocument(): 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' => 'Test Database'
|
||||
]);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
$table = $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' => 'Test Table',
|
||||
'documentsecurity' => true,
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),
|
||||
],
|
||||
]);
|
||||
$collectionId = $table['body']['$id'];
|
||||
|
||||
// Create string column
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'title',
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
]);
|
||||
|
||||
sleep(1);
|
||||
|
||||
// Test 1: Try to create document with $createdAt - should return 400
|
||||
$response = $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' => [
|
||||
'title' => 'Test Movie',
|
||||
'$createdAt' => '2000-01-01T10:00:00.000+00:00'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 2: Try to create document with $updatedAt - should return 400
|
||||
$response = $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' => [
|
||||
'title' => 'Test Movie',
|
||||
'$updatedAt' => '2000-01-01T10:00:00.000+00:00'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 3: Try to create document with both $createdAt and $updatedAt - should return 400
|
||||
$response = $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' => [
|
||||
'title' => 'Test Movie',
|
||||
'$createdAt' => '2000-01-01T10:00:00.000+00:00',
|
||||
'$updatedAt' => '2000-01-01T10:00:00.000+00:00'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 4: Create a valid document first
|
||||
$validRow = $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' => [
|
||||
'title' => 'Valid Movie'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $validRow['headers']['status-code']);
|
||||
$documentId = $validRow['body']['$id'];
|
||||
|
||||
// Test 5: Try to update document with $createdAt - should return 400
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'title' => 'Updated Movie',
|
||||
'$createdAt' => '2000-01-01T10:00:00.000+00:00'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 6: Try to update document with $updatedAt - should return 400
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'title' => 'Updated Movie',
|
||||
'$updatedAt' => '2000-01-01T10:00:00.000+00:00'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Test 7: Try to update document with both $createdAt and $updatedAt - should return 400
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'title' => 'Updated Movie',
|
||||
'$createdAt' => '2000-01-01T10:00:00.000+00:00',
|
||||
'$updatedAt' => '2000-01-01T10:00:00.000+00:00'
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
|
||||
// Cleanup
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5243,4 +5243,936 @@ class DatabasesCustomServerTest extends Scope
|
||||
|
||||
$this->assertEquals(400, $response['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testDateTimeDocument(): void
|
||||
{
|
||||
$databaseId = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'DateTime Test Database',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $databaseId['headers']['status-code']);
|
||||
$databaseId = $databaseId['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' => 'create_modify_dates',
|
||||
'documentSecurity' => true,
|
||||
'permissions' => [],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
$collectionId = $collection['body']['$id'];
|
||||
|
||||
// Create string attribute
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'string',
|
||||
'size' => 128,
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
// Create datetime attribute
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/datetime', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'datetime',
|
||||
'required' => false,
|
||||
'format' => 'datetime',
|
||||
]);
|
||||
|
||||
sleep(1);
|
||||
|
||||
$date = '2000-01-01T10:00:00.000+00:00';
|
||||
|
||||
// Test - default behaviour of external datetime attribute not changed
|
||||
$doc = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documentId' => 'doc1',
|
||||
'data' => [
|
||||
'datetime' => ''
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::write(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $doc['headers']['status-code']);
|
||||
$this->assertNotEmpty($doc['body']['datetime']);
|
||||
$this->assertNotEmpty($doc['body']['$createdAt']);
|
||||
$this->assertNotEmpty($doc['body']['$updatedAt']);
|
||||
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/doc1', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertNotEmpty($doc['body']['datetime']);
|
||||
$this->assertNotEmpty($doc['body']['$createdAt']);
|
||||
$this->assertNotEmpty($doc['body']['$updatedAt']);
|
||||
|
||||
// Test - modifying $createdAt and $updatedAt
|
||||
$doc = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documentId' => 'doc2',
|
||||
'data' => [
|
||||
'$createdAt' => $date
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::write(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $doc['headers']['status-code']);
|
||||
$this->assertEquals($doc['body']['$createdAt'], $date);
|
||||
$this->assertNotEmpty($doc['body']['$updatedAt']);
|
||||
$this->assertNotEquals($doc['body']['$updatedAt'], $date);
|
||||
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/doc2', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertEquals($doc['body']['$createdAt'], $date);
|
||||
$this->assertNotEmpty($doc['body']['$updatedAt']);
|
||||
$this->assertNotEquals($doc['body']['$updatedAt'], $date);
|
||||
|
||||
// Cleanup
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
}
|
||||
|
||||
public function testSingleDocumentDateOperations(): void
|
||||
{
|
||||
$databaseId = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Single Date Operations Database',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $databaseId['headers']['status-code']);
|
||||
$databaseId = $databaseId['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' => 'normal_date_operations',
|
||||
'documentSecurity' => true,
|
||||
'permissions' => [],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
$collectionId = $collection['body']['$id'];
|
||||
|
||||
// Create string attribute
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'string',
|
||||
'size' => 128,
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
sleep(1);
|
||||
|
||||
$createDate = '2000-01-01T10:00:00.000+00:00';
|
||||
$updateDate = '2000-02-01T15:30:00.000+00:00';
|
||||
$date1 = '2000-01-01T10:00:00.000+00:00';
|
||||
$date2 = '2000-02-01T15:30:00.000+00:00';
|
||||
$date3 = '2000-03-01T20:45:00.000+00:00';
|
||||
|
||||
// Test 1: Create with custom createdAt, then update with custom updatedAt
|
||||
$doc = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documentId' => 'doc1',
|
||||
'data' => [
|
||||
'string' => 'initial',
|
||||
'$createdAt' => $createDate
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::write(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $doc['headers']['status-code']);
|
||||
$this->assertEquals($createDate, $doc['body']['$createdAt']);
|
||||
$this->assertNotEquals($createDate, $doc['body']['$updatedAt']);
|
||||
|
||||
// Update with custom updatedAt
|
||||
$updatedDoc = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/doc1', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'data' => [
|
||||
'string' => 'updated',
|
||||
'$updatedAt' => $updateDate
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $updatedDoc['headers']['status-code']);
|
||||
$this->assertEquals($createDate, $updatedDoc['body']['$createdAt']);
|
||||
$this->assertEquals($updateDate, $updatedDoc['body']['$updatedAt']);
|
||||
|
||||
// Test 2: Create with both custom dates
|
||||
$doc2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documentId' => 'doc2',
|
||||
'data' => [
|
||||
'string' => 'both_dates',
|
||||
'$createdAt' => $createDate,
|
||||
'$updatedAt' => $updateDate
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::write(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $doc2['headers']['status-code']);
|
||||
$this->assertEquals($createDate, $doc2['body']['$createdAt']);
|
||||
$this->assertEquals($updateDate, $doc2['body']['$updatedAt']);
|
||||
|
||||
// Test 3: Create without dates, then update with custom dates
|
||||
$doc3 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documentId' => 'doc3',
|
||||
'data' => [
|
||||
'string' => 'no_dates'
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::write(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $doc3['headers']['status-code']);
|
||||
|
||||
$updatedDoc3 = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/doc3', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'data' => [
|
||||
'string' => 'updated_no_dates',
|
||||
'$createdAt' => $createDate,
|
||||
'$updatedAt' => $updateDate
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $updatedDoc3['headers']['status-code']);
|
||||
$this->assertEquals($createDate, $updatedDoc3['body']['$createdAt']);
|
||||
$this->assertEquals($updateDate, $updatedDoc3['body']['$updatedAt']);
|
||||
|
||||
// Test 4: Update only createdAt
|
||||
$doc4 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documentId' => 'doc4',
|
||||
'data' => [
|
||||
'string' => 'initial'
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::write(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $doc4['headers']['status-code']);
|
||||
$originalCreatedAt4 = $doc4['body']['$createdAt'];
|
||||
$originalUpdatedAt4 = $doc4['body']['$updatedAt'];
|
||||
|
||||
$updatedDoc4 = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/doc4', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'data' => [
|
||||
'string' => 'updated',
|
||||
'$updatedAt' => null,
|
||||
'$createdAt' => null
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $updatedDoc4['headers']['status-code']);
|
||||
$this->assertEquals($originalCreatedAt4, $updatedDoc4['body']['$createdAt']);
|
||||
$this->assertNotEquals($originalUpdatedAt4, $updatedDoc4['body']['$updatedAt']);
|
||||
|
||||
// Test 5: Update only updatedAt
|
||||
$finalDoc4 = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/doc4', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'data' => [
|
||||
'string' => 'final',
|
||||
'$updatedAt' => $updateDate,
|
||||
'$createdAt' => $createDate
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $finalDoc4['headers']['status-code']);
|
||||
$this->assertEquals($createDate, $finalDoc4['body']['$createdAt']);
|
||||
$this->assertEquals($updateDate, $finalDoc4['body']['$updatedAt']);
|
||||
|
||||
// Test 6: Create with updatedAt, update with createdAt
|
||||
$doc5 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documentId' => 'doc5',
|
||||
'data' => [
|
||||
'string' => 'doc5',
|
||||
'$updatedAt' => $date2
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::write(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $doc5['headers']['status-code']);
|
||||
$this->assertNotEquals($date2, $doc5['body']['$createdAt']);
|
||||
$this->assertEquals($date2, $doc5['body']['$updatedAt']);
|
||||
|
||||
$updatedDoc5 = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/doc5', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'data' => [
|
||||
'string' => 'doc5_updated',
|
||||
'$createdAt' => $date1
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $updatedDoc5['headers']['status-code']);
|
||||
$this->assertEquals($date1, $updatedDoc5['body']['$createdAt']);
|
||||
$this->assertNotEquals($date2, $updatedDoc5['body']['$updatedAt']);
|
||||
|
||||
// Test 7: Create with both dates, update with different dates
|
||||
$doc6 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documentId' => 'doc6',
|
||||
'data' => [
|
||||
'string' => 'doc6',
|
||||
'$createdAt' => $date1,
|
||||
'$updatedAt' => $date2
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::write(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $doc6['headers']['status-code']);
|
||||
$this->assertEquals($date1, $doc6['body']['$createdAt']);
|
||||
$this->assertEquals($date2, $doc6['body']['$updatedAt']);
|
||||
|
||||
$updatedDoc6 = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/doc6', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'data' => [
|
||||
'string' => 'doc6_updated',
|
||||
'$createdAt' => $date3,
|
||||
'$updatedAt' => $date3
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $updatedDoc6['headers']['status-code']);
|
||||
$this->assertEquals($date3, $updatedDoc6['body']['$createdAt']);
|
||||
$this->assertEquals($date3, $updatedDoc6['body']['$updatedAt']);
|
||||
|
||||
// Cleanup
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
}
|
||||
|
||||
public function testBulkDocumentDateOperations(): void
|
||||
{
|
||||
$databaseId = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Bulk Date Operations Database',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $databaseId['headers']['status-code']);
|
||||
$databaseId = $databaseId['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_date_operations',
|
||||
'documentSecurity' => true,
|
||||
'permissions' => [],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
$collectionId = $collection['body']['$id'];
|
||||
|
||||
// Create string attribute
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'string',
|
||||
'size' => 128,
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
sleep(1);
|
||||
|
||||
$createDate = '2000-01-01T10:00:00.000+00:00';
|
||||
$updateDate = '2000-02-01T15:30:00.000+00:00';
|
||||
|
||||
// Test 1: Bulk create with different date configurations
|
||||
$documents = [
|
||||
[
|
||||
'$id' => 'doc1',
|
||||
'string' => 'doc1',
|
||||
'$createdAt' => $createDate,
|
||||
'$permissions' => [ Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),]
|
||||
],
|
||||
[
|
||||
'$id' => 'doc2',
|
||||
'string' => 'doc2',
|
||||
'$updatedAt' => $updateDate,
|
||||
'$permissions' => [ Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),]
|
||||
],
|
||||
[
|
||||
'$id' => 'doc3',
|
||||
'string' => 'doc3',
|
||||
'$createdAt' => $createDate,
|
||||
'$updatedAt' => $updateDate,
|
||||
'$permissions' => [ Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),]
|
||||
],
|
||||
[
|
||||
'$id' => 'doc4',
|
||||
'string' => 'doc4',
|
||||
'$permissions' => [ Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),]
|
||||
],
|
||||
[
|
||||
'$id' => 'doc5',
|
||||
'string' => 'doc5',
|
||||
'$createdAt' => null,
|
||||
'$permissions' => [ Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),]
|
||||
],
|
||||
[
|
||||
'$id' => 'doc6',
|
||||
'string' => 'doc6',
|
||||
'$updatedAt' => null,
|
||||
'$permissions' => [ Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),]
|
||||
]
|
||||
];
|
||||
|
||||
// Create all documents in one bulk operation
|
||||
$bulkCreateResponse = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documents' => $documents
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $bulkCreateResponse['headers']['status-code']);
|
||||
$this->assertCount(count($documents), $bulkCreateResponse['body']['documents']);
|
||||
|
||||
// Verify initial state
|
||||
foreach (['doc1', 'doc3'] as $id) {
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertEquals($createDate, $doc['body']['$createdAt'], "createdAt mismatch for $id");
|
||||
}
|
||||
|
||||
foreach (['doc2', 'doc3'] as $id) {
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertEquals($updateDate, $doc['body']['$updatedAt'], "updatedAt mismatch for $id");
|
||||
}
|
||||
|
||||
foreach (['doc4', 'doc5', 'doc6'] as $id) {
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertNotEmpty($doc['body']['$createdAt'], "createdAt missing for $id");
|
||||
$this->assertNotEmpty($doc['body']['$updatedAt'], "updatedAt missing for $id");
|
||||
}
|
||||
|
||||
// Test 2: Bulk update with custom dates
|
||||
$updateData = [
|
||||
'data' => [
|
||||
'string' => 'updated',
|
||||
'$createdAt' => $createDate,
|
||||
'$updatedAt' => $updateDate,
|
||||
'$permissions' => [ Permission::read(Role::user($this->getUser()['$id'])),
|
||||
Permission::update(Role::user($this->getUser()['$id'])),
|
||||
Permission::delete(Role::user($this->getUser()['$id'])),]
|
||||
],
|
||||
];
|
||||
|
||||
// Use bulk update instead of individual updates
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), $updateData);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertCount(6, $response['body']['documents']);
|
||||
|
||||
// Verify updated state
|
||||
foreach (['doc1', 'doc3'] as $id) {
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertEquals($createDate, $doc['body']['$createdAt'], "createdAt mismatch for $id");
|
||||
$this->assertEquals($updateDate, $doc['body']['$updatedAt'], "updatedAt mismatch for $id");
|
||||
$this->assertEquals('updated', $doc['body']['string'], "string mismatch for $id");
|
||||
}
|
||||
|
||||
foreach (['doc2', 'doc4', 'doc5', 'doc6'] as $id) {
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertEquals($updateDate, $doc['body']['$updatedAt'], "updatedAt mismatch for $id");
|
||||
$this->assertEquals('updated', $doc['body']['string'], "string mismatch for $id");
|
||||
}
|
||||
|
||||
$newDate = '2000-03-01T20:45:00.000+00:00';
|
||||
$updateDataEnabled = [
|
||||
'data' => [
|
||||
'string' => 'enabled_update',
|
||||
'$createdAt' => $newDate,
|
||||
'$updatedAt' => $newDate
|
||||
],
|
||||
];
|
||||
|
||||
// Use bulk update instead of individual updates
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), $updateDataEnabled);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertCount(6, $response['body']['documents']);
|
||||
|
||||
// Verify final state
|
||||
foreach (['doc1', 'doc2', 'doc3', 'doc4', 'doc5', 'doc6'] as $id) {
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertEquals($newDate, $doc['body']['$createdAt'], "createdAt mismatch for $id");
|
||||
$this->assertEquals($newDate, $doc['body']['$updatedAt'], "updatedAt mismatch for $id");
|
||||
$this->assertEquals('enabled_update', $doc['body']['string'], "string mismatch for $id");
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
}
|
||||
|
||||
public function testUpsertDateOperations(): void
|
||||
{
|
||||
$databaseId = $this->client->call(Client::METHOD_POST, '/databases', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Upsert Date Operations Database',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $databaseId['headers']['status-code']);
|
||||
$databaseId = $databaseId['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' => 'upsert_date_operations',
|
||||
'documentSecurity' => true,
|
||||
'permissions' => [],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $collection['headers']['status-code']);
|
||||
$collectionId = $collection['body']['$id'];
|
||||
|
||||
// Create string attribute
|
||||
$this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/attributes/string', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'key' => 'string',
|
||||
'size' => 128,
|
||||
'required' => false,
|
||||
]);
|
||||
|
||||
sleep(1);
|
||||
|
||||
$createDate = '2000-01-01T10:00:00.000+00:00';
|
||||
$updateDate = '2000-02-01T15:30:00.000+00:00';
|
||||
$date1 = '2000-01-01T10:00:00.000+00:00';
|
||||
$date2 = '2000-02-01T15:30:00.000+00:00';
|
||||
$date3 = '2000-03-01T20:45:00.000+00:00';
|
||||
|
||||
// Test 1: Upsert new document with custom createdAt
|
||||
$upsertDoc1 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documentId' => 'upsert1',
|
||||
'data' => [
|
||||
'string' => 'upsert1_initial',
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::write(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
],
|
||||
'$createdAt' => $createDate
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $upsertDoc1['headers']['status-code']);
|
||||
$this->assertEquals($createDate, $upsertDoc1['body']['$createdAt']);
|
||||
$this->assertNotEquals($createDate, $upsertDoc1['body']['$updatedAt']);
|
||||
|
||||
// Test 2: Upsert existing document with custom updatedAt
|
||||
$updatedUpsertDoc1 = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/upsert1', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'data' => [
|
||||
'string' => 'upsert1_updated',
|
||||
'$updatedAt' => $updateDate
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $updatedUpsertDoc1['headers']['status-code']);
|
||||
$this->assertEquals($createDate, $updatedUpsertDoc1['body']['$createdAt']);
|
||||
$this->assertEquals($updateDate, $updatedUpsertDoc1['body']['$updatedAt']);
|
||||
|
||||
// Test 3: Upsert new document with both custom dates
|
||||
$upsertDoc2 = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documentId' => 'upsert2',
|
||||
'data' => [
|
||||
'string' => 'upsert2_both_dates',
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::write(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
],
|
||||
'$createdAt' => $createDate,
|
||||
'$updatedAt' => $updateDate
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $upsertDoc2['headers']['status-code']);
|
||||
$this->assertEquals($createDate, $upsertDoc2['body']['$createdAt']);
|
||||
$this->assertEquals($updateDate, $upsertDoc2['body']['$updatedAt']);
|
||||
|
||||
// Test 4: Upsert existing document with different dates
|
||||
$updatedUpsertDoc2 = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/upsert2', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'data' => [
|
||||
'string' => 'upsert2_updated',
|
||||
'$createdAt' => $date3,
|
||||
'$updatedAt' => $date3,
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::write(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
],
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $updatedUpsertDoc2['headers']['status-code']);
|
||||
$this->assertEquals($date3, $updatedUpsertDoc2['body']['$createdAt']);
|
||||
$this->assertEquals($date3, $updatedUpsertDoc2['body']['$updatedAt']);
|
||||
|
||||
// Test 5: Bulk upsert operations with custom dates
|
||||
$upsertDocuments = [
|
||||
[
|
||||
'$id' => 'bulk_upsert1',
|
||||
'string' => 'bulk_upsert1_initial',
|
||||
'$createdAt' => $createDate
|
||||
],
|
||||
[
|
||||
'$id' => 'bulk_upsert2',
|
||||
'string' => 'bulk_upsert2_initial',
|
||||
'$updatedAt' => $updateDate
|
||||
],
|
||||
[
|
||||
'$id' => 'bulk_upsert3',
|
||||
'string' => 'bulk_upsert3_initial',
|
||||
'$createdAt' => $createDate,
|
||||
'$updatedAt' => $updateDate
|
||||
],
|
||||
[
|
||||
'$id' => 'bulk_upsert4',
|
||||
'string' => 'bulk_upsert4_initial'
|
||||
]
|
||||
];
|
||||
|
||||
// Create documents using bulk upsert
|
||||
$response = $this->client->call(Client::METHOD_PUT, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documents' => $upsertDocuments
|
||||
]);
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertCount(4, $response['body']['documents']);
|
||||
|
||||
// Test 7: Verify initial bulk upsert state
|
||||
foreach (['bulk_upsert1', 'bulk_upsert3'] as $id) {
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertEquals($createDate, $doc['body']['$createdAt'], "createdAt mismatch for $id");
|
||||
}
|
||||
|
||||
foreach (['bulk_upsert2', 'bulk_upsert3'] as $id) {
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertEquals($updateDate, $doc['body']['$updatedAt'], "updatedAt mismatch for $id");
|
||||
}
|
||||
|
||||
foreach (['bulk_upsert4'] as $id) {
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertNotEmpty($doc['body']['$createdAt'], "createdAt missing for $id");
|
||||
$this->assertNotEmpty($doc['body']['$updatedAt'], "updatedAt missing for $id");
|
||||
}
|
||||
|
||||
// Test 8: Bulk upsert update with custom dates
|
||||
$newDate = '2000-04-01T12:00:00.000+00:00';
|
||||
$updateUpsertData = [
|
||||
'data' => [
|
||||
'string' => 'bulk_upsert_updated',
|
||||
'$createdAt' => $newDate,
|
||||
'$updatedAt' => $newDate
|
||||
],
|
||||
'queries' => [Query::equal('$id', ['bulk_upsert1','bulk_upsert2','bulk_upsert3','bulk_upsert4'])->toString()]
|
||||
];
|
||||
|
||||
$upsertIds = ['bulk_upsert1', 'bulk_upsert2', 'bulk_upsert3', 'bulk_upsert4'];
|
||||
|
||||
// Use bulk update instead of individual updates
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), $updateUpsertData);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertCount(4, $response['body']['documents']);
|
||||
|
||||
// Verify updated state
|
||||
foreach ($upsertIds as $id) {
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertEquals($newDate, $doc['body']['$createdAt'], "createdAt mismatch for $id");
|
||||
$this->assertEquals($newDate, $doc['body']['$updatedAt'], "updatedAt mismatch for $id");
|
||||
$this->assertEquals('bulk_upsert_updated', $doc['body']['string'], "string mismatch for $id");
|
||||
}
|
||||
|
||||
// Test 9: checking by passing null to each
|
||||
$updateUpsertDataNull = [
|
||||
'data' => [
|
||||
'string' => 'bulk_upsert_null_test',
|
||||
'$createdAt' => null,
|
||||
'$updatedAt' => null
|
||||
],
|
||||
'queries' => [Query::equal('$id', ['bulk_upsert1','bulk_upsert2','bulk_upsert3','bulk_upsert4'])->toString()]
|
||||
];
|
||||
|
||||
// Use bulk update instead of individual updates
|
||||
$response = $this->client->call(Client::METHOD_PATCH, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), $updateUpsertDataNull);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertCount(4, $response['body']['documents']);
|
||||
|
||||
// Verify null handling
|
||||
foreach ($upsertIds as $id) {
|
||||
$doc = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId . '/documents/' . $id, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $doc['headers']['status-code']);
|
||||
$this->assertNotEmpty($doc['body']['$createdAt'], "createdAt missing for $id");
|
||||
$this->assertNotEmpty($doc['body']['$updatedAt'], "updatedAt missing for $id");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Cleanup
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
|
||||
$this->client->call(Client::METHOD_DELETE, '/databases/' . $databaseId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user