diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php index 5f8e548456..b819931f86 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Upsert.php @@ -82,7 +82,7 @@ class Upsert extends Action ->param('documentId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Document ID.', false, ['dbForProject']) ->param('data', [], new JSON(), 'Document data as JSON object. Include all required attributes of the document to be created or updated.', true, example: '{"username":"walter.obrien","email":"walter.obrien@example.com","fullName":"Walter O\'Brien","age":30,"isAdmin":false}') ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) - ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, fn (Database $dbForProject) => new Nullable(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'Transaction ID for staging the operation.', true, ['dbForProject']) ->inject('requestTimestamp') ->inject('response') ->inject('user') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php index 2a9b95fff5..7e073c95d4 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Indexes/Create.php @@ -213,7 +213,7 @@ class Create extends Action $dbForDatabases->getAdapter()->getSupportForUniqueIndex(), $dbForDatabases->getAdapter()->getSupportForFulltextIndex(), $dbForDatabases->getAdapter()->getSupportForTTLIndexes(), - $dbForDatabases->getAdapter()->getSupportForObject(), + $dbForDatabases->getAdapter()->getSupportForObject() ); if (!$validator->isValid($index)) { diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php index 050689fbe5..b38edf6218 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/XList.php @@ -58,9 +58,9 @@ class XList extends AttributesXList ->callback($this->action(...)); } - public function action(string $databaseId, string $collectionId, array $queries, bool $includeTotal, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void + public function action(string $databaseId, string $tableId, array $queries, bool $includeTotal, UtopiaResponse $response, Database $dbForProject, Authorization $authorization): void { // Call parent action with tableId as collectionId since they refer to the same resource - parent::action($databaseId, $collectionId, $queries, $includeTotal, $response, $dbForProject, $authorization); + parent::action($databaseId, $tableId, $queries, $includeTotal, $response, $dbForProject, $authorization); } } diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php index 9ff1a57e54..863eb7374a 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Update.php @@ -61,7 +61,7 @@ class Update extends DocumentUpdate ->param('rowId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Row ID.', false, ['dbForProject']) ->param('data', [], new JSON(), 'Row data as JSON object. Include only columns and value pairs to be updated.', true, example: '{"username":"walter.obrien","email":"walter.obrien@example.com","fullName":"Walter O\'Brien","age":33,"isAdmin":false}') ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) - ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, fn (Database $dbForProject) => new Nullable(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'Transaction ID for staging the operation.', true, ['dbForProject']) ->inject('requestTimestamp') ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php index f98ea693c2..81a3a788a2 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Rows/Upsert.php @@ -63,7 +63,7 @@ class Upsert extends DocumentUpsert ->param('rowId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Row ID.', false, ['dbForProject']) ->param('data', [], new JSON(), 'Row data as JSON object. Include all required columns of the row to be created or updated.', true, example: '{"username":"walter.obrien","email":"walter.obrien@example.com","fullName":"Walter O\'Brien","age":33,"isAdmin":false}') ->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true) - ->param('transactionId', null, new Nullable(new UID()), 'Transaction ID for staging the operation.', true) + ->param('transactionId', null, fn (Database $dbForProject) => new Nullable(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'Transaction ID for staging the operation.', true, ['dbForProject']) ->inject('requestTimestamp') ->inject('response') ->inject('user') diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Create.php index df1e4dffa1..ddb1f486d7 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Create.php @@ -75,7 +75,7 @@ class Create extends Action type: MethodType::UPLOAD, packaging: true, )) - ->param('functionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Function ID.', false, ['dbForProject']) + ->param('functionId', '', fn (Database $dbForProject) => new Nullable(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'Function ID.', false, ['dbForProject']) ->param('entrypoint', null, new Nullable(new Text(1028)), 'Entrypoint File.', true) ->param('commands', null, new Nullable(new Text(8192, 0)), 'Build Commands.', true) ->param('code', [], new File(), 'Gzip file with your code package. When used with the Appwrite CLI, pass the path to your code directory, and the CLI will automatically package your code. Use a path that is within the current directory.', skipValidation: true) diff --git a/src/Appwrite/Platform/Tasks/Install.php b/src/Appwrite/Platform/Tasks/Install.php index e5e6eb5ac1..2c0557f6c6 100644 --- a/src/Appwrite/Platform/Tasks/Install.php +++ b/src/Appwrite/Platform/Tasks/Install.php @@ -32,7 +32,7 @@ class Install extends Action ->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true) ->param('interactive', 'Y', new Text(1), 'Run an interactive session', true) ->param('no-start', false, new Boolean(true), 'Run an interactive session', true) - ->param('database', 'mariadb', new Text(0), 'Database to use (mariadb|postgresql)', true) + ->param('database', 'mongodb', new Text(0), 'Database to use (mongodb|mariadb|postgres)', true) ->callback($this->action(...)); } @@ -137,6 +137,14 @@ class Install extends Action } } } + + // Block database type changes on existing installations + $existingDatabase = $vars['_APP_DB_ADAPTER']['default'] ?? null; + if ($existingDatabase !== null && $existingDatabase !== $database) { + Console::error("Cannot change database type from '{$existingDatabase}' to '{$database}'."); + Console::error('Changing database types on an existing installation is not supported.'); + Console::exit(1); + } } @@ -178,6 +186,7 @@ class Install extends Action $input = []; $password = new Password(); + $password->setCharset('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'); $token = new Token(); foreach ($vars as $var) { if ($var['name'] === '_APP_ASSISTANT_OPENAI_API_KEY') { diff --git a/src/Appwrite/Platform/Tasks/Upgrade.php b/src/Appwrite/Platform/Tasks/Upgrade.php index df9257d329..2e77ddd885 100644 --- a/src/Appwrite/Platform/Tasks/Upgrade.php +++ b/src/Appwrite/Platform/Tasks/Upgrade.php @@ -2,6 +2,8 @@ namespace Appwrite\Platform\Tasks; +use Appwrite\Docker\Compose; +use Appwrite\Docker\Env; use Utopia\Console; use Utopia\System\System; use Utopia\Validator\Boolean; @@ -24,7 +26,7 @@ class Upgrade extends Install ->param('image', 'appwrite', new Text(0), 'Main appwrite docker image', true) ->param('interactive', 'Y', new Text(1), 'Run an interactive session', true) ->param('no-start', false, new Boolean(true), 'Run an interactive session', true) - ->param('database', 'mariadb', new Text(length: 0), 'Database to use (mariadb|postgresql)', true) + ->param('database', 'mongodb', new Text(length: 0), 'Database to use (mongodb|mariadb|postgresql)', true) ->callback($this->action(...)); } @@ -41,7 +43,33 @@ class Upgrade extends Install Console::log(' └── docker-compose.yml'); Console::exit(1); } - $database = System::getEnv('_APP_DB_ADAPTER', 'mariadb'); + + $database = null; + $compose = new Compose($data); + foreach ($compose->getServices() as $service) { + if (!$service) { + continue; + } + $env = $service->getEnvironment()->list(); + if (isset($env['_APP_DB_ADAPTER'])) { + $database = $env['_APP_DB_ADAPTER']; + break; + } + } + + if ($database === null) { + $envData = @file_get_contents($this->path . '/.env'); + if ($envData !== false) { + $envFile = new Env($envData); + $database = $envFile->list()['_APP_DB_ADAPTER'] ?? null; + } + } + + if ($database === null) { + // TODO: Change default to 'mongodb' after next release + $database = System::getEnv('_APP_DB_ADAPTER', 'mariadb'); + } + parent::action($httpPort, $httpsPort, $organization, $image, $interactive, $noStart, $database); } } diff --git a/src/Appwrite/Platform/Workers/StatsResources.php b/src/Appwrite/Platform/Workers/StatsResources.php index 6326a74036..8213032a5f 100644 --- a/src/Appwrite/Platform/Workers/StatsResources.php +++ b/src/Appwrite/Platform/Workers/StatsResources.php @@ -5,11 +5,11 @@ namespace Appwrite\Platform\Workers; use Appwrite\Platform\Action; use Exception; use Throwable; -use Utopia\Console; use Utopia\Database\Database; use Utopia\Database\Document; use Utopia\Database\Query; use Utopia\Queue\Message; +use Utopia\Span\Span; class StatsResources extends Action { @@ -79,29 +79,15 @@ class StatsResources extends Action // Reset documents for each job $this->documents = []; - $startTime = microtime(true); $this->countForProject($dbForPlatform, $getLogsDB, $getProjectDB, $getDatabasesDB, $project); - $endTime = microtime(true); - $executionTime = $endTime - $startTime; - Console::info('Project: ' . $project->getId() . '(' . $project->getSequence() . ') aggregated in ' . $executionTime .' seconds'); } protected function countForProject(Database $dbForPlatform, callable $getLogsDB, callable $getProjectDB, callable $getDatabasesDB, Document $project): void { - Console::info('Begining count for: ' . $project->getId()); - - $dbForLogs = null; - $dbForProject = null; - try { - /** @var \Utopia\Database\Database $dbForLogs */ - $dbForLogs = call_user_func($getLogsDB, $project); - /** @var \Utopia\Database\Database $dbForProject */ - $dbForProject = call_user_func($getProjectDB, $project); - } catch (Throwable $th) { - Console::error('Unable to get database'); - Console::error($th->getMessage()); - return; - } + /** @var \Utopia\Database\Database $dbForLogs */ + $dbForLogs = call_user_func($getLogsDB, $project); + /** @var \Utopia\Database\Database $dbForProject */ + $dbForProject = call_user_func($getProjectDB, $project); try { @@ -216,7 +202,6 @@ class StatsResources extends Action call_user_func_array($this->logError, [$th, "StatsResources", "count_for_project_{$project->getId()}"]); } - Console::info('End of count for: ' . $project->getId()); } protected function countForBuckets(Database $dbForProject, Database $dbForLogs, string $region) @@ -520,7 +505,7 @@ class StatsResources extends Action protected function writeDocuments(Database $dbForLogs, Document $project): void { - $message = 'Stats writeDocuments project: ' . $project->getId() . '(' . $project->getSequence() . ')'; + Span::add('documents.count', count($this->documents)); /** * sort by unique index key reduce locks/deadlocks @@ -549,16 +534,9 @@ class StatsResources extends Action return strcmp($a['time'], $b['time']); }); - try { - $dbForLogs->upsertDocuments( - 'stats', - $this->documents, - ); - - Console::success($message . ' | Documents: ' . count($this->documents)); - } catch (\Throwable $e) { - Console::error('Error: ' . $message . ' | Exception: ' . $e->getMessage()); - throw $e; - } + $dbForLogs->upsertDocuments( + 'stats', + $this->documents, + ); } } diff --git a/src/Appwrite/Utopia/Database/Validator/ProjectId.php b/src/Appwrite/Utopia/Database/Validator/ProjectId.php index 46b0cdf53e..dc05ff7c5a 100644 --- a/src/Appwrite/Utopia/Database/Validator/ProjectId.php +++ b/src/Appwrite/Utopia/Database/Validator/ProjectId.php @@ -2,10 +2,20 @@ namespace Appwrite\Utopia\Database\Validator; +use Utopia\Database\Database; use Utopia\Validator; class ProjectId extends Validator { + /** + * Constructor + * + * @param int $maxLength Maximum length for the project ID + */ + public function __construct(protected readonly int $maxLength = Database::MAX_UID_DEFAULT_LENGTH) + { + } + /** * Is valid. * @@ -17,7 +27,21 @@ class ProjectId extends Validator */ public function isValid($value): bool { - return $value == 'unique()' || preg_match('/^[a-z0-9][a-z0-9-]{1,35}$/', $value); + if ($value == 'unique()') { + return true; + } + + // Must start with a-z or 0-9, followed by a-z, 0-9, or hyphen + if (!\preg_match('/^[a-z0-9][a-z0-9-]*$/', $value)) { + return false; + } + + // Check length + if (\mb_strlen($value) > $this->maxLength) { + return false; + } + + return true; } /** @@ -27,7 +51,7 @@ class ProjectId extends Validator */ public function getDescription(): string { - return 'Project IDs must contain at most 36 chars. Valid chars are a-z, 0-9, and hyphen. Can\'t start with a special char.'; + return 'Project IDs must contain at most ' . $this->maxLength . ' chars. Valid chars are a-z, 0-9, and hyphen. Can\'t start with a special char.'; } /** diff --git a/src/Appwrite/Utopia/Response/Model.php b/src/Appwrite/Utopia/Response/Model.php index 687b8b3eba..b32894ab3c 100644 --- a/src/Appwrite/Utopia/Response/Model.php +++ b/src/Appwrite/Utopia/Response/Model.php @@ -17,6 +17,7 @@ abstract class Model public const TYPE_PAYLOAD = 'payload'; public const TYPE_ARRAY = 'array'; public const TYPE_ENUM = 'enum'; + public const TYPE_ID = 'id'; /** * @var bool diff --git a/src/Appwrite/Utopia/Response/Model/AttributeList.php b/src/Appwrite/Utopia/Response/Model/AttributeList.php index 0b17a655ab..50189a80c3 100644 --- a/src/Appwrite/Utopia/Response/Model/AttributeList.php +++ b/src/Appwrite/Utopia/Response/Model/AttributeList.php @@ -34,7 +34,7 @@ class AttributeList extends Model Response::MODEL_ATTRIBUTE_TEXT, Response::MODEL_ATTRIBUTE_MEDIUMTEXT, Response::MODEL_ATTRIBUTE_LONGTEXT, - Response::MODEL_ATTRIBUTE_STRING // needs to be last, since its condition would dominate any other string attribute + Response::MODEL_ATTRIBUTE_STRING, // needs to be last, since its condition would dominate any other string attribute ], 'description' => 'List of attributes.', 'default' => [], diff --git a/src/Appwrite/Utopia/Response/Model/ConsoleVariables.php b/src/Appwrite/Utopia/Response/Model/ConsoleVariables.php index cf8ae796e0..5ca01ca010 100644 --- a/src/Appwrite/Utopia/Response/Model/ConsoleVariables.php +++ b/src/Appwrite/Utopia/Response/Model/ConsoleVariables.php @@ -105,7 +105,107 @@ class ConsoleVariables extends Model 'default' => '', 'example' => 'ns1.example.com,ns2.example.com', ] - ); + ) + ->addRule( + '_APP_DB_ADAPTER', + [ + 'type' => self::TYPE_STRING, + 'description' => 'Database adapter in use.', + 'default' => 'mariadb', + 'example' => 'mysql', + ] + ) + ->addRule( + 'supportForRelationships', + [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Whether the database adapter supports relationships.', + 'default' => true, + 'example' => true, + ] + ) + ->addRule( + 'supportForOperators', + [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Whether the database adapter supports operators.', + 'default' => true, + 'example' => true, + ] + ) + ->addRule( + 'supportForSpatials', + [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Whether the database adapter supports spatial attributes.', + 'default' => true, + 'example' => true, + ] + ) + ->addRule( + 'supportForSpatialIndexNull', + [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Whether the database adapter supports spatial indexes on nullable columns.', + 'default' => false, + 'example' => false, + ] + ) + ->addRule( + 'supportForFulltextWildcard', + [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Whether the database adapter supports fulltext wildcard search.', + 'default' => true, + 'example' => true, + ] + ) + ->addRule( + 'supportForMultipleFulltextIndexes', + [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Whether the database adapter supports multiple fulltext indexes per collection.', + 'default' => true, + 'example' => true, + ] + ) + ->addRule( + 'supportForAttributeResizing', + [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Whether the database adapter supports resizing attributes.', + 'default' => true, + 'example' => true, + ] + ) + ->addRule( + 'supportForSchemas', + [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Whether the database adapter supports fixed schemas with row width limits.', + 'default' => true, + 'example' => true, + ] + ) + ->addRule( + 'maxIndexLength', + [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Maximum index length supported by the database adapter.', + 'default' => 768, + 'example' => 768, + ] + ) + ->addRule( + 'supportForIntegerIds', + [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Whether the database adapter uses integer sequence IDs.', + 'default' => true, + 'example' => true, + ] + ) + ; } /** diff --git a/src/Appwrite/Utopia/Response/Model/Document.php b/src/Appwrite/Utopia/Response/Model/Document.php index 31cc67f42f..e0aca32b3b 100644 --- a/src/Appwrite/Utopia/Response/Model/Document.php +++ b/src/Appwrite/Utopia/Response/Model/Document.php @@ -37,10 +37,10 @@ class Document extends Any 'example' => '5e5ea5c16897e', ]) ->addRule('$sequence', [ - 'type' => self::TYPE_INTEGER, - 'description' => 'Document automatically incrementing ID.', - 'default' => 0, - 'example' => 1, + 'type' => self::TYPE_ID, + 'description' => 'Document sequence ID.', + 'default' => '', + 'example' => '1', 'readOnly' => true, ]) ->addRule('$collectionId', [ @@ -83,12 +83,8 @@ class Document extends Any $document->removeAttribute('$collection'); $document->removeAttribute('$tenant'); - if (!$document->isEmpty()) { - $sequence = $document->getAttribute('$sequence', 0); - if (is_numeric($document->getAttribute('$sequence', 0))) { - $sequence = (int)$sequence; - } - $document->setAttribute('$sequence', $sequence); + if (!$document->isEmpty() && \is_numeric($document->getAttribute('$sequence', 0))) { + $document->setAttribute('$sequence', (int)$document->getAttribute('$sequence', 0)); } foreach ($document->getAttributes() as $attribute) { diff --git a/src/Appwrite/Utopia/Response/Model/Row.php b/src/Appwrite/Utopia/Response/Model/Row.php index 30f876d91c..a96df44bc3 100644 --- a/src/Appwrite/Utopia/Response/Model/Row.php +++ b/src/Appwrite/Utopia/Response/Model/Row.php @@ -37,10 +37,10 @@ class Row extends Any 'example' => '5e5ea5c16897e', ]) ->addRule('$sequence', [ - 'type' => self::TYPE_INTEGER, - 'description' => 'Row automatically incrementing ID.', - 'default' => 0, - 'example' => 1, + 'type' => self::TYPE_ID, + 'description' => 'Row sequence ID.', + 'default' => '', + 'example' => '1', 'readOnly' => true, ]) ->addRule('$tableId', [ @@ -82,9 +82,11 @@ class Row extends Any { $document->removeAttribute('$collection'); $document->removeAttribute('$tenant'); - if (!$document->isEmpty() && is_numeric($document->getAttribute('$sequence', 0))) { + + if (!$document->isEmpty() && \is_numeric($document->getAttribute('$sequence', 0))) { $document->setAttribute('$sequence', (int)$document->getAttribute('$sequence', 0)); } + foreach ($document->getAttributes() as $column) { if (\is_array($column)) { foreach ($column as $subAttribute) { diff --git a/src/Executor/Executor.php b/src/Executor/Executor.php index a8fab8fead..f899f06bad 100644 --- a/src/Executor/Executor.php +++ b/src/Executor/Executor.php @@ -149,14 +149,20 @@ class Executor 'x-opr-addressing-method' => 'broadcast' ], [], true, 30); + $status = $response['headers']['status-code']; + $message = \is_string($response['body']) ? $response['body'] : ($response['body']['message'] ?? ''); + + // Runtime already gone — nothing to do + if ($status === 404) { + return true; + } + // Temporary fix for race condition - if ($response['headers']['status-code'] === 500 && \str_contains($response['body']['message'], 'already in progress')) { + if ($status === 500 && \str_contains($message, 'already in progress')) { return true; // OK, removal already in progress } - $status = $response['headers']['status-code']; if ($status >= 400) { - $message = \is_string($response['body']) ? $response['body'] : $response['body']['message']; throw new \Exception($message, $status); } diff --git a/tests/e2e/General/UsageTest.php b/tests/e2e/General/UsageTest.php index 633b5a0e54..35afe23320 100644 --- a/tests/e2e/General/UsageTest.php +++ b/tests/e2e/General/UsageTest.php @@ -931,8 +931,7 @@ class UsageTest extends Scope return $data; } -<<<<<<< HEAD - /** @depends testDatabaseStatsTablesAPI */ + #[Depends('testDatabaseStatsTablesAPI')] public function testPrepareDocumentsDBStats(array $data): array { $documentsTotal = 0; @@ -1079,7 +1078,7 @@ class UsageTest extends Scope ]); } - /** @depends testPrepareDocumentsDBStats */ + #[Depends('testPrepareDocumentsDBStats')] #[Retry(count: 1)] public function testDocumentsDBStats(array $data): array { @@ -1150,7 +1149,7 @@ class UsageTest extends Scope return $data; } - /** @depends testDocumentsDBStats */ + #[Depends('testDocumentsDBStats')] public function testPrepareVectorDBStats(array $data): array { $documentsTotal = 0; @@ -1301,7 +1300,7 @@ class UsageTest extends Scope ]); } - /** @depends testPrepareVectorDBStats */ + #[Depends('testPrepareVectorDBStats')] #[Retry(count: 1)] public function testVectorDBStats(array $data): array { @@ -1372,10 +1371,7 @@ class UsageTest extends Scope return $data; } - /** @depends testVectorDBStats */ -======= - #[Depends('testDatabaseStatsTablesAPI')] ->>>>>>> origin/1.8.x + #[Depends('testVectorDBStats')] public function testPrepareFunctionsStats(array $data): array { $executionTime = 0; diff --git a/tests/e2e/Services/Databases/DatabasesBase.php b/tests/e2e/Services/Databases/DatabasesBase.php index c33834c4a3..23d9908029 100644 --- a/tests/e2e/Services/Databases/DatabasesBase.php +++ b/tests/e2e/Services/Databases/DatabasesBase.php @@ -1157,25 +1157,6 @@ trait DatabasesBase 'x-appwrite-key' => $this->getProject()['apiKey'] ])); -<<<<<<< HEAD:tests/e2e/Services/Databases/Legacy/DatabasesBase.php - $this->assertIsArray($movies['body']['attributes']); - $this->assertCount(10, $movies['body']['attributes']); - $this->assertArrayHasKey('bytesMax', $movies['body']); - $this->assertArrayHasKey('bytesUsed', $movies['body']); - $this->assertGreaterThanOrEqual(0, $movies['body']['bytesUsed']); - $this->assertEquals($movies['body']['attributes'][0]['key'], $title['body']['key']); - $this->assertEquals($movies['body']['attributes'][1]['key'], $description['body']['key']); - $this->assertEquals($movies['body']['attributes'][2]['key'], $tagline['body']['key']); - $this->assertEquals($movies['body']['attributes'][3]['key'], $releaseYear['body']['key']); - $this->assertEquals($movies['body']['attributes'][4]['key'], $duration['body']['key']); - $this->assertEquals($movies['body']['attributes'][5]['key'], $actors['body']['key']); - $this->assertEquals($movies['body']['attributes'][6]['key'], $datetime['body']['key']); - $this->assertEquals($movies['body']['attributes'][7]['key'], $relationship['body']['key']); - $this->assertEquals($movies['body']['attributes'][8]['key'], $integers['body']['key']); - $this->assertEquals($movies['body']['attributes'][9]['key'], $integers2['body']['key']); - - return $data; -======= $schemaResource = $this->getSchemaResource(); $this->assertIsArray($movies['body'][$schemaResource]); $this->assertCount($this->getSupportForRelationships() ? 10 : 9, $movies['body'][$schemaResource]); @@ -1197,7 +1178,6 @@ trait DatabasesBase $this->assertEquals($movies['body'][$schemaResource][8]['key'], $integers['body']['key']); $this->assertEquals($movies['body'][$schemaResource][9]['key'], $integers2['body']['key']); } ->>>>>>> origin/1.8.x:tests/e2e/Services/Databases/DatabasesBase.php } public function testListAttributes(): void @@ -1290,23 +1270,8 @@ trait DatabasesBase ]); $this->assertEquals(400, $attribute['headers']['status-code']); -<<<<<<< HEAD:tests/e2e/Services/Databases/Legacy/DatabasesBase.php - - $message = $attribute['body']['message']; - if ($this->isMongoDB()) { - $this->assertStringContainsString('Index length is longer than the maximum: 1024', $message); - } else { - // length depends on the shared table - $this->assertTrue( - str_contains($message, 'Index length is longer than the maximum: 767') || - str_contains($message, 'Index length is longer than the maximum: 768'), - "Message does not contain expected max length" - ); - } -======= $maxLength = $this->getMaxIndexLength(); $this->assertStringContainsString('Index length is longer than the maximum: '.$maxLength, $attribute['body']['message']); ->>>>>>> origin/1.8.x:tests/e2e/Services/Databases/DatabasesBase.php } public function testUpdateAttributeEnum(): void @@ -2218,17 +2183,7 @@ trait DatabasesBase $this->assertEquals(400, $fulltextReleaseYear['headers']['status-code']); -<<<<<<< HEAD:tests/e2e/Services/Databases/Legacy/DatabasesBase.php - // MongoDB only allows one fulltext index per collection, so it returns a different error - if ($this->isMongoDB()) { - $this->assertEquals('There is already a fulltext index in the collection', $fulltextReleaseYear['body']['message']); - } else { - $this->assertEquals('Attribute "releaseYear" cannot be part of a fulltext index, must be of type string', $fulltextReleaseYear['body']['message']); - } - $noAttributes = $this->client->call(Client::METHOD_POST, '/databases/' . $databaseId . '/collections/' . $data['moviesId'] . '/indexes', array_merge([ -======= $noAttributes = $this->client->call(Client::METHOD_POST, $this->getIndexUrl($databaseId, $collectionId), array_merge([ ->>>>>>> origin/1.8.x:tests/e2e/Services/Databases/DatabasesBase.php 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] @@ -2284,10 +2239,6 @@ trait DatabasesBase ]); $this->assertEquals(400, $fulltextArray['headers']['status-code']); -<<<<<<< HEAD:tests/e2e/Services/Databases/Legacy/DatabasesBase.php - -======= ->>>>>>> origin/1.8.x:tests/e2e/Services/Databases/DatabasesBase.php $this->assertEquals('Creating indexes on array attributes is not currently supported.', $fulltextArray['body']['message']); $actorsArray = $this->client->call(Client::METHOD_POST, $this->getIndexUrl($databaseId, $collectionId), array_merge([ @@ -2428,24 +2379,8 @@ trait DatabasesBase $this->assertEquals('lengthTestIndex', $index['body']['key']); $this->assertEquals([128, 200], $index['body']['lengths']); -<<<<<<< HEAD:tests/e2e/Services/Databases/Legacy/DatabasesBase.php - // Test case for lengths array overriding - // set a length for an array attribute, it should get overridden with Database::ARRAY_INDEX_LENGTH - if ($this->isMongoDB()) { - // MongoDB doesn't support identical indexes, so delete the existing one first - $this->client->call(Client::METHOD_DELETE, "/databases/{$databaseId}/collections/{$collectionId}/indexes/index-actors", [ - 'content-type' => 'application/json', - 'x-appwrite-project' => $this->getProject()['$id'], - 'x-appwrite-key' => $this->getProject()['apiKey'] - ]); - sleep(2); - } - - $create = $this->client->call(Client::METHOD_POST, "/databases/{$databaseId}/collections/{$collectionId}/indexes", [ -======= // Test case for array attribute index (should be blocked) $create = $this->client->call(Client::METHOD_POST, $this->getIndexUrl($databaseId, $collectionId), [ ->>>>>>> origin/1.8.x:tests/e2e/Services/Databases/DatabasesBase.php 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], 'x-appwrite-key' => $this->getProject()['apiKey'] @@ -2455,10 +2390,6 @@ trait DatabasesBase $this->getIndexAttributesParam() => ['actors'], 'lengths' => [120], ]); -<<<<<<< HEAD:tests/e2e/Services/Databases/Legacy/DatabasesBase.php - -======= ->>>>>>> origin/1.8.x:tests/e2e/Services/Databases/DatabasesBase.php $this->assertEquals(400, $create['headers']['status-code']); $this->assertEquals('Creating indexes on array attributes is not currently supported.', $create['body']['message']); @@ -2635,18 +2566,10 @@ trait DatabasesBase $this->assertEquals($document1['body']['actors'][1], 'Samuel Jackson'); $this->assertEquals($document1['body']['birthDay'], '1975-06-12T12:12:55.000+00:00'); $this->assertTrue(array_key_exists('$sequence', $document1['body'])); -<<<<<<< HEAD:tests/e2e/Services/Databases/Legacy/DatabasesBase.php - if ($this->isMongoDB()) { - $this->assertIsString($document1['body']['$sequence']); - } else { - $this->assertIsInt($document1['body']['$sequence']); - } -======= $this->getSupportForIntegerIds() ? $this->assertIsInt($document1['body']['$sequence']) : $this->assertIsString($document1['body']['$sequence']); ->>>>>>> origin/1.8.x:tests/e2e/Services/Databases/DatabasesBase.php $this->assertEquals(201, $document2['headers']['status-code']); $this->assertEquals($data['moviesId'], $document2['body'][$this->getContainerIdResponseKey()]); @@ -4070,17 +3993,11 @@ trait DatabasesBase public function testOperators(): void { -<<<<<<< HEAD:tests/e2e/Services/Databases/Legacy/DatabasesBase.php - if ($this->isMongoDB()) { - $this->markTestSkipped('MongoDB is not supported for this test'); - } -======= if (!$this->getSupportForOperators()) { $this->expectNotToPerformAssertions(); return; } ->>>>>>> origin/1.8.x:tests/e2e/Services/Databases/DatabasesBase.php // Create database $database = $this->client->call(Client::METHOD_POST, $this->getApiBasePath(), [ 'content-type' => 'application/json', @@ -4330,17 +4247,11 @@ trait DatabasesBase public function testBulkOperators(): void { -<<<<<<< HEAD:tests/e2e/Services/Databases/Legacy/DatabasesBase.php - if ($this->isMongoDB()) { - $this->markTestSkipped('MongoDB is not supported for this test'); - } -======= if (!$this->getSupportForOperators()) { $this->expectNotToPerformAssertions(); return; } ->>>>>>> origin/1.8.x:tests/e2e/Services/Databases/DatabasesBase.php // Create database $database = $this->client->call(Client::METHOD_POST, $this->getApiBasePath(), [ 'content-type' => 'application/json', diff --git a/tests/e2e/Services/Databases/Transactions/TransactionsBase.php b/tests/e2e/Services/Databases/Transactions/TransactionsBase.php index dae315dc39..479e4d5c68 100644 --- a/tests/e2e/Services/Databases/Transactions/TransactionsBase.php +++ b/tests/e2e/Services/Databases/Transactions/TransactionsBase.php @@ -5649,17 +5649,11 @@ trait TransactionsBase */ public function testArrayOperatorsWithUpdateRow(): void { -<<<<<<< HEAD:tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php - if ($this->isMongoDB()) { - $this->markTestSkipped('MongoDB is not supported for this test'); - } -======= if (!$this->getSupportForOperators()) { $this->expectNotToPerformAssertions(); return; } ->>>>>>> origin/1.8.x:tests/e2e/Services/Databases/Transactions/TransactionsBase.php // Create database $database = $this->client->call(Client::METHOD_POST, $this->getDatabaseUrl(), array_merge([ 'content-type' => 'application/json', @@ -5782,17 +5776,11 @@ trait TransactionsBase */ public function testArrayOperatorsWithCreateOperations(): void { -<<<<<<< HEAD:tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php - if ($this->isMongoDB()) { - $this->markTestSkipped('MongoDB is not supported for this test'); - } -======= if (!$this->getSupportForOperators()) { $this->expectNotToPerformAssertions(); return; } ->>>>>>> origin/1.8.x:tests/e2e/Services/Databases/Transactions/TransactionsBase.php // Create database $database = $this->client->call(Client::METHOD_POST, $this->getDatabaseUrl(), array_merge([ 'content-type' => 'application/json', @@ -5918,17 +5906,11 @@ trait TransactionsBase */ public function testMultipleArrayOperators(): void { -<<<<<<< HEAD:tests/e2e/Services/Databases/TablesDB/Transactions/TransactionsBase.php - if ($this->isMongoDB()) { - $this->markTestSkipped('MongoDB is not supported for this test'); - } -======= if (!$this->getSupportForOperators()) { $this->expectNotToPerformAssertions(); return; } ->>>>>>> origin/1.8.x:tests/e2e/Services/Databases/Transactions/TransactionsBase.php // Create database $database = $this->client->call(Client::METHOD_POST, $this->getDatabaseUrl(), array_merge([ 'content-type' => 'application/json', diff --git a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php index 3818818634..cbb84e2775 100644 --- a/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php +++ b/tests/e2e/Services/Projects/ProjectsConsoleClientTest.php @@ -819,12 +819,8 @@ class ProjectsConsoleClientTest extends Scope 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], ], $this->getHeaders())); -<<<<<<< HEAD - $this->assertContains($response['headers']['status-code'], [400, 404]); -======= $this->assertEquals(400, $response['headers']['status-code']); ->>>>>>> origin/1.8.x } public function testGetProjectUsage(): void