From ee117b816a7ecc4c2bbf4a2f7245825dc7907c7c Mon Sep 17 00:00:00 2001 From: Darshan Date: Wed, 7 May 2025 10:33:54 +0530 Subject: [PATCH 1/2] manage: events and channels. --- app/controllers/shared/api.php | 22 +++------------------ src/Appwrite/Event/Realtime.php | 6 ++++-- src/Appwrite/Messaging/Adapter/Realtime.php | 14 ++++++------- 3 files changed, 14 insertions(+), 28 deletions(-) diff --git a/app/controllers/shared/api.php b/app/controllers/shared/api.php index ba695acff4..8c15f27acc 100644 --- a/app/controllers/shared/api.php +++ b/app/controllers/shared/api.php @@ -483,26 +483,10 @@ App::init() /* * Background Jobs */ - $events = $route->getLabel('event', ''); $queueForEvents - ->setUser($user) - ->setEvent($events) - ->setProject($project); - - if (str_contains($events, '.tables.')) { - $requestFormat = $request->getHeader('x-appwrite-response-format', System::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', '')); - if ($requestFormat && version_compare($requestFormat, '1.7.0', '<')) { - $map = [ - 'rows' => 'documents', - 'tables' => 'collections', - 'columns' => 'attributes', - ]; - - $compatibleEvents = str_replace(array_keys($map), array_values($map), $events); - // override the events - $queueForEvents->setEvent($compatibleEvents); - } - } + ->setEvent($route->getLabel('event', '')) + ->setProject($project) + ->setUser($user); $queueForAudits ->setMode($mode) diff --git a/src/Appwrite/Event/Realtime.php b/src/Appwrite/Event/Realtime.php index e1ec891e67..67d51e5c52 100644 --- a/src/Appwrite/Event/Realtime.php +++ b/src/Appwrite/Event/Realtime.php @@ -76,16 +76,18 @@ class Realtime extends Event $payload = new Document($this->getPayload()); $db = $this->getContext('database'); - $table = $this->getContext('table'); $bucket = $this->getContext('bucket'); + // can be Tables API or Collections API, generated channels include both! + $tableOrCollection = $this->getContext('table') ?? $this->getContext('collection'); + $target = RealtimeAdapter::fromPayload( // Pass first, most verbose event pattern event: $allEvents[0], payload: $payload, project: $this->getProject(), database: $db, - table: $table, + table: $tableOrCollection, bucket: $bucket, ); diff --git a/src/Appwrite/Messaging/Adapter/Realtime.php b/src/Appwrite/Messaging/Adapter/Realtime.php index b775078c61..5cb908464f 100644 --- a/src/Appwrite/Messaging/Adapter/Realtime.php +++ b/src/Appwrite/Messaging/Adapter/Realtime.php @@ -303,23 +303,23 @@ class Realtime extends Adapter $channels[] = 'projects.' . $project->getId(); $projectId = 'console'; $roles = [Role::team($project->getAttribute('teamId'))->toString()]; - } elseif (($parts[4] ?? '') === 'rows') { + } elseif (($parts[4] ?? '') === 'rows' || ($parts[4] ?? '') === 'documents') { if ($database->isEmpty()) { - throw new \Exception('Database needs to be passed to Realtime for Row events in the Database.'); + throw new \Exception('Database needs to be passed to Realtime for Document/Row events in the Database.'); } if ($table->isEmpty()) { - throw new \Exception('Table needs to be passed to Realtime for Row events in the Database.'); + throw new \Exception('Collection or the Table needs to be passed to Realtime for Document/Row events in the Database.'); } - // 1.7.x + // 1.7.x - Tables API $channels[] = 'rows'; $channels[] = 'databases.' . $database->getId() . '.tables.' . $payload->getAttribute('$tableId') . '.rows'; $channels[] = 'databases.' . $database->getId() . '.tables.' . $payload->getAttribute('$tableId') . '.rows.' . $payload->getId(); - // 1.6.x + // 1.6.x - Collections API $channels[] = 'documents'; - $channels[] = 'databases.' . $database->getId() . '.collections.' . $payload->getAttribute('$tableId') . '.documents'; - $channels[] = 'databases.' . $database->getId() . '.collections.' . $payload->getAttribute('$tableId') . '.documents.' . $payload->getId(); + $channels[] = 'databases.' . $database->getId() . '.collections.' . $payload->getAttribute('$collectionId') . '.documents'; + $channels[] = 'databases.' . $database->getId() . '.collections.' . $payload->getAttribute('$collectionId') . '.documents.' . $payload->getId(); $roles = $table->getAttribute('documentSecurity', false) ? \array_merge($table->getRead(), $payload->getRead()) From 46ccf6f5370dd7c7a871fed143a257e2736c84d1 Mon Sep 17 00:00:00 2001 From: Darshan Date: Wed, 7 May 2025 11:13:15 +0530 Subject: [PATCH 2/2] update: re-add legacy models; remove: filters. --- app/config/events.php | 50 ++++++++ app/controllers/api/project.php | 2 +- app/init/resources.php | 9 +- src/Appwrite/GraphQL/Types/Mapper.php | 43 ++++--- .../Specification/Format/OpenAPI3.php | 2 + .../Database/Validator/Queries/Attributes.php | 25 ++++ .../Validator/Queries/Collections.php | 21 ++++ src/Appwrite/Utopia/Request/Filters/V19.php | 35 ++---- src/Appwrite/Utopia/Response.php | 53 +++++++++ src/Appwrite/Utopia/Response/Filters/V19.php | 77 +------------ .../Utopia/Response/Model/Attribute.php | 85 ++++++++++++++ .../Response/Model/AttributeBoolean.php | 59 ++++++++++ .../Response/Model/AttributeDatetime.php | 67 +++++++++++ .../Utopia/Response/Model/AttributeEmail.php | 66 +++++++++++ .../Utopia/Response/Model/AttributeEnum.php | 73 ++++++++++++ .../Utopia/Response/Model/AttributeFloat.php | 73 ++++++++++++ .../Utopia/Response/Model/AttributeIP.php | 66 +++++++++++ .../Response/Model/AttributeInteger.php | 72 ++++++++++++ .../Utopia/Response/Model/AttributeList.php | 58 ++++++++++ .../Response/Model/AttributeRelationship.php | 96 +++++++++++++++ .../Utopia/Response/Model/AttributeString.php | 53 +++++++++ .../Utopia/Response/Model/AttributeURL.php | 66 +++++++++++ .../Utopia/Response/Model/BaseList.php | 8 +- .../Utopia/Response/Model/Collection.php | 109 ++++++++++++++++++ .../Utopia/Response/Model/Document.php | 92 +++++++++++++++ .../Utopia/Response/Model/UsageCollection.php | 54 +++++++++ 26 files changed, 1283 insertions(+), 131 deletions(-) create mode 100644 src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php create mode 100644 src/Appwrite/Utopia/Database/Validator/Queries/Collections.php create mode 100644 src/Appwrite/Utopia/Response/Model/Attribute.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeBoolean.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeDatetime.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeEmail.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeEnum.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeFloat.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeIP.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeInteger.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeList.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeRelationship.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeString.php create mode 100644 src/Appwrite/Utopia/Response/Model/AttributeURL.php create mode 100644 src/Appwrite/Utopia/Response/Model/Collection.php create mode 100644 src/Appwrite/Utopia/Response/Model/Document.php create mode 100644 src/Appwrite/Utopia/Response/Model/UsageCollection.php diff --git a/app/config/events.php b/app/config/events.php index 4523b56206..182aa91363 100644 --- a/app/config/events.php +++ b/app/config/events.php @@ -145,6 +145,56 @@ return [ '$description' => 'This event triggers when a table is updated.', ] ], + 'collections' => [ + '$model' => Response::MODEL_COLLECTION, + '$resource' => true, + '$description' => 'This event triggers on any collection event.', + 'documents' => [ + '$model' => Response::MODEL_DOCUMENT, + '$resource' => true, + '$description' => 'This event triggers on any document event.', + 'create' => [ + '$description' => 'This event triggers when a document is created.', + ], + 'delete' => [ + '$description' => 'This event triggers when a document is deleted.' + ], + 'update' => [ + '$description' => 'This event triggers when a document is updated.' + ], + ], + 'indexes' => [ + '$model' => Response::MODEL_INDEX, + '$resource' => true, + '$description' => 'This event triggers on any indexes event.', + 'create' => [ + '$description' => 'This event triggers when an index is created.', + ], + 'delete' => [ + '$description' => 'This event triggers when an index is deleted.' + ] + ], + 'attributes' => [ + '$model' => Response::MODEL_ATTRIBUTE, + '$resource' => true, + '$description' => 'This event triggers on any attributes event.', + 'create' => [ + '$description' => 'This event triggers when an attribute is created.', + ], + 'delete' => [ + '$description' => 'This event triggers when an attribute is deleted.' + ] + ], + 'create' => [ + '$description' => 'This event triggers when a collection is created.' + ], + 'delete' => [ + '$description' => 'This event triggers when a collection is deleted.', + ], + 'update' => [ + '$description' => 'This event triggers when a collection is updated.', + ] + ], 'create' => [ '$description' => 'This event triggers when a database is created.' ], diff --git a/app/controllers/api/project.php b/app/controllers/api/project.php index 97475c743a..047179b888 100644 --- a/app/controllers/api/project.php +++ b/app/controllers/api/project.php @@ -353,7 +353,7 @@ App::get('/v1/project/usage') 'executionsTotal' => $total[METRIC_EXECUTIONS], 'executionsMbSecondsTotal' => $total[METRIC_EXECUTIONS_MB_SECONDS], 'buildsMbSecondsTotal' => $total[METRIC_BUILDS_MB_SECONDS], - 'rowsTotal' => $total[METRIC_DOCUMENTS], + 'documentsTotal' => $total[METRIC_DOCUMENTS], 'databasesTotal' => $total[METRIC_DATABASES], 'databasesStorageTotal' => $total[METRIC_DATABASES_STORAGE], 'usersTotal' => $total[METRIC_USERS], diff --git a/app/init/resources.php b/app/init/resources.php index 7657b9ea69..5ac26281a2 100644 --- a/app/init/resources.php +++ b/app/init/resources.php @@ -707,6 +707,7 @@ App::setResource('schema', function ($utopia, $dbForProject) { }, ]; + // NOTE: `params` and `urls` are not used internally in the `Schema::build` function below! $params = [ 'list' => function (string $databaseId, string $collectionId, array $args) { return [ 'queries' => $args['queries']]; @@ -721,8 +722,8 @@ App::setResource('schema', function ($utopia, $dbForProject) { // Order must be the same as the route params return [ 'databaseId' => $databaseId, - 'rowId' => $id, - 'tableId' => $collectionId, + 'documentId' => $id, + 'collectionId' => $collectionId, 'data' => $args, 'permissions' => $permissions, ]; @@ -737,8 +738,8 @@ App::setResource('schema', function ($utopia, $dbForProject) { // Order must be the same as the route params return [ 'databaseId' => $databaseId, - 'tableId' => $collectionId, - 'rowId' => $documentId, + 'collectionId' => $collectionId, + 'documentId' => $documentId, 'data' => $args, 'permissions' => $permissions, ]; diff --git a/src/Appwrite/GraphQL/Types/Mapper.php b/src/Appwrite/GraphQL/Types/Mapper.php index 45aa9e0085..a56b7f2f8a 100644 --- a/src/Appwrite/GraphQL/Types/Mapper.php +++ b/src/Appwrite/GraphQL/Types/Mapper.php @@ -285,7 +285,9 @@ class Mapper case 'Appwrite\Utopia\Database\Validator\Queries\Base': case 'Appwrite\Utopia\Database\Validator\Queries\Buckets': case 'Appwrite\Utopia\Database\Validator\Queries\Tables': + case 'Appwrite\Utopia\Database\Validator\Queries\Collections': case 'Appwrite\Utopia\Database\Validator\Queries\Columns': + case 'Appwrite\Utopia\Database\Validator\Queries\Attributes': case 'Appwrite\Utopia\Database\Validator\Queries\Indexes': case 'Appwrite\Utopia\Database\Validator\Queries\Databases': case 'Appwrite\Utopia\Database\Validator\Queries\Deployments': @@ -418,8 +420,10 @@ class Mapper // TODO: Find a better way to do this switch ($name) { - case 'Columns': + case 'Attributes': return static::getColumnImplementation($object); + case 'Columns': + return static::getColumnImplementation($object, true); case 'HashOptions': return static::getHashOptionsImplementation($object); } @@ -427,29 +431,24 @@ class Mapper throw new Exception('Unknown union type: ' . $name); } - private static function getColumnImplementation(array $object): Type + private static function getColumnImplementation(array $object, bool $isColumns = false): Type { - switch ($object['type']) { - case 'string': - return match ($object['format'] ?? '') { - 'email' => static::model('ColumnEmail'), - 'url' => static::model('ColumnUrl'), - 'ip' => static::model('ColumnIp'), - default => static::model('ColumnString'), - }; - case 'integer': - return static::model('ColumnInteger'); - case 'double': - return static::model('ColumnFloat'); - case 'boolean': - return static::model('ColumnBoolean'); - case 'datetime': - return static::model('ColumnDatetime'); - case 'relationship': - return static::model('ColumnRelationship'); - } + $prefix = $isColumns ? 'Column' : 'Attribute'; - throw new Exception('Unknown column implementation'); + return match ($object['type']) { + 'string' => match ($object['format'] ?? '') { + 'email' => static::model("{$prefix}Email"), + 'url' => static::model("{$prefix}Url"), + 'ip' => static::model("{$prefix}Ip"), + default => static::model("{$prefix}String"), + }, + 'integer' => static::model("{$prefix}Integer"), + 'double' => static::model("{$prefix}Float"), + 'boolean' => static::model("{$prefix}Boolean"), + 'datetime' => static::model("{$prefix}Datetime"), + 'relationship' => static::model("{$prefix}Relationship"), + default => throw new Exception('Unknown ' . strtolower($prefix) . ' implementation'), + }; } private static function getHashOptionsImplementation(array $object): Type diff --git a/src/Appwrite/Specification/Format/OpenAPI3.php b/src/Appwrite/Specification/Format/OpenAPI3.php index 088a20ff98..9c906d3ebc 100644 --- a/src/Appwrite/Specification/Format/OpenAPI3.php +++ b/src/Appwrite/Specification/Format/OpenAPI3.php @@ -408,8 +408,10 @@ class OpenAPI3 extends Format ]; break; case 'Appwrite\Utopia\Database\Validator\Queries\Columns': + case 'Appwrite\Utopia\Database\Validator\Queries\Attributes': case 'Appwrite\Utopia\Database\Validator\Queries\Buckets': case 'Appwrite\Utopia\Database\Validator\Queries\Tables': + case 'Appwrite\Utopia\Database\Validator\Queries\Collections': case 'Appwrite\Utopia\Database\Validator\Queries\Databases': case 'Appwrite\Utopia\Database\Validator\Queries\Deployments': case 'Appwrite\Utopia\Database\Validator\Queries\Executions': diff --git a/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php b/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php new file mode 100644 index 0000000000..4a35c82b73 --- /dev/null +++ b/src/Appwrite/Utopia/Database/Validator/Queries/Attributes.php @@ -0,0 +1,25 @@ + 'rowId', - 'attributes' => 'columns', - 'collectionId' => 'tableId', - 'attributeId' => 'columnId', - '$collectionId' => '$tableId', - 'relatedCollection' => 'relatedTable', - 'relatedCollectionId' => 'relatedTableId', - ]; - // Convert 1.6 params to 1.7 public function parse(array $content, string $model): array { - $content = $this->overrideDatabaseParams($content, $model); - - return $content; - } - - protected function overrideDatabaseParams(array $content, string $model): array - { - if (!str_starts_with($model, 'databases.')) { - return $content; - } - - $intersect = array_intersect_key(self::PARAMS_MAP, $content); - - foreach ($intersect as $oldKey => $newKey) { - $content[$newKey] = $content[$oldKey]; - unset($content[$oldKey]); + /* + Uncomment with first request filter; current is just a copy of V18 + switch ($model) { + case 'functions.create': + $content['something'] = $content['somethingElse'] ?? ""; + unset($content['something']); + break; } + */ return $content; } diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index 62822e9956..c72a01c79a 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -15,10 +15,23 @@ use Appwrite\Utopia\Response\Model\AlgoScrypt; use Appwrite\Utopia\Response\Model\AlgoScryptModified; use Appwrite\Utopia\Response\Model\AlgoSha; use Appwrite\Utopia\Response\Model\Any; +use Appwrite\Utopia\Response\Model\Attribute; +use Appwrite\Utopia\Response\Model\AttributeBoolean; +use Appwrite\Utopia\Response\Model\AttributeDatetime; +use Appwrite\Utopia\Response\Model\AttributeEmail; +use Appwrite\Utopia\Response\Model\AttributeEnum; +use Appwrite\Utopia\Response\Model\AttributeFloat; +use Appwrite\Utopia\Response\Model\AttributeInteger; +use Appwrite\Utopia\Response\Model\AttributeIP; +use Appwrite\Utopia\Response\Model\AttributeList; +use Appwrite\Utopia\Response\Model\AttributeRelationship; +use Appwrite\Utopia\Response\Model\AttributeString; +use Appwrite\Utopia\Response\Model\AttributeURL; use Appwrite\Utopia\Response\Model\AuthProvider; use Appwrite\Utopia\Response\Model\BaseList; use Appwrite\Utopia\Response\Model\Branch; use Appwrite\Utopia\Response\Model\Bucket; +use Appwrite\Utopia\Response\Model\Collection; use Appwrite\Utopia\Response\Model\Column; use Appwrite\Utopia\Response\Model\ColumnBoolean; use Appwrite\Utopia\Response\Model\ColumnDatetime; @@ -40,6 +53,7 @@ use Appwrite\Utopia\Response\Model\Deployment; use Appwrite\Utopia\Response\Model\DetectionFramework; use Appwrite\Utopia\Response\Model\DetectionRuntime; use Appwrite\Utopia\Response\Model\DevKey; +use Appwrite\Utopia\Response\Model\Document as ModelDocument; use Appwrite\Utopia\Response\Model\Error; use Appwrite\Utopia\Response\Model\ErrorDev; use Appwrite\Utopia\Response\Model\Execution; @@ -106,6 +120,7 @@ use Appwrite\Utopia\Response\Model\TemplateVariable; use Appwrite\Utopia\Response\Model\Token; use Appwrite\Utopia\Response\Model\Topic; use Appwrite\Utopia\Response\Model\UsageBuckets; +use Appwrite\Utopia\Response\Model\UsageCollection; use Appwrite\Utopia\Response\Model\UsageDatabase; use Appwrite\Utopia\Response\Model\UsageDatabases; use Appwrite\Utopia\Response\Model\UsageFunction; @@ -148,6 +163,7 @@ class Response extends SwooleResponse public const MODEL_USAGE_DATABASES = 'usageDatabases'; public const MODEL_USAGE_DATABASE = 'usageDatabase'; public const MODEL_USAGE_TABLE = 'usageTable'; + public const MODEL_USAGE_COLLECTION = 'usageCollection'; public const MODEL_USAGE_USERS = 'usageUsers'; public const MODEL_USAGE_BUCKETS = 'usageBuckets'; public const MODEL_USAGE_STORAGE = 'usageStorage'; @@ -160,14 +176,32 @@ class Response extends SwooleResponse // Database public const MODEL_DATABASE = 'database'; public const MODEL_DATABASE_LIST = 'databaseList'; + public const MODEL_COLLECTION = 'collection'; + public const MODEL_COLLECTION_LIST = 'collectionList'; public const MODEL_TABLE = 'table'; public const MODEL_TABLE_LIST = 'tableList'; public const MODEL_INDEX = 'index'; public const MODEL_INDEX_LIST = 'indexList'; + public const MODEL_DOCUMENT = 'document'; + public const MODEL_DOCUMENT_LIST = 'documentList'; public const MODEL_ROW = 'row'; public const MODEL_ROW_LIST = 'rowList'; // Database Attributes + public const MODEL_ATTRIBUTE = 'attribute'; + public const MODEL_ATTRIBUTE_LIST = 'attributeList'; + public const MODEL_ATTRIBUTE_STRING = 'attributeString'; + public const MODEL_ATTRIBUTE_INTEGER = 'attributeInteger'; + public const MODEL_ATTRIBUTE_FLOAT = 'attributeFloat'; + public const MODEL_ATTRIBUTE_BOOLEAN = 'attributeBoolean'; + public const MODEL_ATTRIBUTE_EMAIL = 'attributeEmail'; + public const MODEL_ATTRIBUTE_ENUM = 'attributeEnum'; + public const MODEL_ATTRIBUTE_IP = 'attributeIp'; + public const MODEL_ATTRIBUTE_URL = 'attributeUrl'; + public const MODEL_ATTRIBUTE_DATETIME = 'attributeDatetime'; + public const MODEL_ATTRIBUTE_RELATIONSHIP = 'attributeRelationship'; + + // Database Columns public const MODEL_COLUMN = 'column'; public const MODEL_COLUMN_LIST = 'columnList'; public const MODEL_COLUMN_STRING = 'columnString'; @@ -377,7 +411,9 @@ class Response extends SwooleResponse ->setModel(new ErrorDev()) // Lists ->setModel(new BaseList('Rows List', self::MODEL_ROW_LIST, 'rows', self::MODEL_ROW)) + ->setModel(new BaseList('Documents List', self::MODEL_DOCUMENT_LIST, 'documents', self::MODEL_DOCUMENT)) ->setModel(new BaseList('Tables List', self::MODEL_TABLE_LIST, 'tables', self::MODEL_TABLE)) + ->setModel(new BaseList('Collections List', self::MODEL_COLLECTION_LIST, 'collections', self::MODEL_COLLECTION)) ->setModel(new BaseList('Databases List', self::MODEL_DATABASE_LIST, 'databases', self::MODEL_DATABASE)) ->setModel(new BaseList('Indexes List', self::MODEL_INDEX_LIST, 'indexes', self::MODEL_INDEX)) ->setModel(new BaseList('Users List', self::MODEL_USER_LIST, 'users', self::MODEL_USER)) @@ -428,6 +464,21 @@ class Response extends SwooleResponse ->setModel(new BaseList('VCS Content List', self::MODEL_VCS_CONTENT_LIST, 'contents', self::MODEL_VCS_CONTENT)) // Entities ->setModel(new Database()) + // Collection API Models + ->setModel(new Collection()) + ->setModel(new Attribute()) + ->setModel(new AttributeList()) + ->setModel(new AttributeString()) + ->setModel(new AttributeInteger()) + ->setModel(new AttributeFloat()) + ->setModel(new AttributeBoolean()) + ->setModel(new AttributeEmail()) + ->setModel(new AttributeEnum()) + ->setModel(new AttributeIP()) + ->setModel(new AttributeURL()) + ->setModel(new AttributeDatetime()) + ->setModel(new AttributeRelationship()) + // Table API Models ->setModel(new Table()) ->setModel(new Column()) ->setModel(new ColumnList()) @@ -443,6 +494,7 @@ class Response extends SwooleResponse ->setModel(new ColumnRelationship()) ->setModel(new Index()) ->setModel(new Row()) + ->setModel(new ModelDocument()) ->setModel(new Log()) ->setModel(new User()) ->setModel(new AlgoMd5()) @@ -509,6 +561,7 @@ class Response extends SwooleResponse ->setModel(new UsageDatabases()) ->setModel(new UsageDatabase()) ->setModel(new UsageTable()) + ->setModel(new UsageCollection()) ->setModel(new UsageUsers()) ->setModel(new UsageStorage()) ->setModel(new UsageBuckets()) diff --git a/src/Appwrite/Utopia/Response/Filters/V19.php b/src/Appwrite/Utopia/Response/Filters/V19.php index 24cb07889f..4505b2c8f2 100644 --- a/src/Appwrite/Utopia/Response/Filters/V19.php +++ b/src/Appwrite/Utopia/Response/Filters/V19.php @@ -7,44 +7,18 @@ use Appwrite\Utopia\Response\Filter; class V19 extends Filter { - private const DATABASE_MAPPINGS = [ - 'table' => 'collection', - 'tables' => 'collections', - '$tableId' => '$collectionId', - 'tablesTotal' => 'collectionsTotal', - 'relatedTable' => 'relatedCollection', - 'relatedTableId' => 'relatedCollectionId', - - 'column' => 'attribute', - 'columns' => 'attributes', - 'columnsTotal' => 'attributesTotal', - - 'row' => 'document', - 'rows' => 'documents', - 'rowsTotal' => 'documentsTotal' - ]; - // Convert 1.7 Data format to 1.6 format public function parse(array $content, string $model): array { $parsedResponse = $content; - return match ($model) { - Response::MODEL_ROW, - Response::MODEL_TABLE, - Response::MODEL_COLUMN, - Response::MODEL_ROW_LIST, - Response::MODEL_TABLE_LIST, - Response::MODEL_COLUMN_LIST, - Response::MODEL_USAGE_TABLE, - Response::MODEL_USAGE_DATABASE, - Response::MODEL_USAGE_DATABASES, - Response::MODEL_COLUMN_RELATIONSHIP => $this->handleDBTerminology($model, $content), - + $parsedResponse = match($model) { Response::MODEL_FUNCTION => $this->parseFunction($content), Response::MODEL_FUNCTION_LIST => $this->handleList($content, 'functions', fn ($item) => $this->parseFunction($item)), default => $parsedResponse, }; + + return $parsedResponse; } protected function parseFunction(array $content): array @@ -53,49 +27,4 @@ class V19 extends Filter unset($content['deploymentId']); return $content; } - - protected function handleDBTerminology(string $model, array $content): array - { - $isListModel = match ($model) { - Response::MODEL_ROW_LIST, - Response::MODEL_TABLE_LIST, - Response::MODEL_COLUMN_LIST => true, - - default => false - }; - - if ($isListModel) { - foreach (self::DATABASE_MAPPINGS as $oldKey => $newKey) { - if (isset($content[$oldKey])) { - $content[$newKey] = array_map(fn ($item) => $this->remapKeys($item), $content[$oldKey]); - unset($content[$oldKey]); - } - } - } else { - $content = $this->remapKeysRecursive($content); - } - - return $content; - } - - private function remapKeys(array $data): array - { - foreach (self::DATABASE_MAPPINGS as $old => $new) { - if (isset($data[$old])) { - $data[$new] = $data[$old]; - unset($data[$old]); - } - } - return $data; - } - - private function remapKeysRecursive(array $data): array - { - $result = []; - foreach ($data as $key => $value) { - $newKey = self::DATABASE_MAPPINGS[$key] ?? $key; - $result[$newKey] = \is_array($value) ? $this->remapKeysRecursive($value) : $value; - } - return $result; - } } diff --git a/src/Appwrite/Utopia/Response/Model/Attribute.php b/src/Appwrite/Utopia/Response/Model/Attribute.php new file mode 100644 index 0000000000..8c43f8d21c --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Attribute.php @@ -0,0 +1,85 @@ +addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'fullName', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('status', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute status. Possible values: `available`, `processing`, `deleting`, `stuck`, or `failed`', + 'default' => '', + 'example' => 'available', + ]) + ->addRule('error', [ + 'type' => self::TYPE_STRING, + 'description' => 'Error message. Displays error generated on failure of creating or deleting an attribute.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('required', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute required?', + 'default' => false, + 'example' => true, + ]) + ->addRule('array', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is attribute an array?', + 'default' => false, + 'required' => false, + 'example' => false, + ]) + ->addRule('$createdAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Attribute creation date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Attribute update date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]); + } + + public array $conditions = []; + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Attribute'; + } + + /** + * Get Collection + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php new file mode 100644 index 0000000000..05846817ca --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeBoolean.php @@ -0,0 +1,59 @@ +addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'isEnabled', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'boolean', + ]) + ->addRule('default', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'required' => false, + 'example' => false + ]) + ; + } + + public array $conditions = [ + 'type' => self::TYPE_BOOLEAN + ]; + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'AttributeBoolean'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE_BOOLEAN; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php b/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php new file mode 100644 index 0000000000..4651aebd06 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeDatetime.php @@ -0,0 +1,67 @@ +addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'birthDay', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => self::TYPE_DATETIME, + ]) + ->addRule('format', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'ISO 8601 format.', + 'default' => APP_DATABASE_ATTRIBUTE_DATETIME, + 'example' => APP_DATABASE_ATTRIBUTE_DATETIME, + 'array' => false, + ]) + ->addRule('default', [ + 'type' => self::TYPE_STRING, + 'description' => 'Default value for attribute when not provided. Only null is optional', + 'default' => null, + 'example' => self::TYPE_DATETIME_EXAMPLE, + 'array' => false, + 'required' => false, + ]) + ; + } + + public array $conditions = [ + 'type' => self::TYPE_DATETIME + ]; + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'AttributeDatetime'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE_DATETIME; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEmail.php b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php new file mode 100644 index 0000000000..078087dd4b --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeEmail.php @@ -0,0 +1,66 @@ +addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'userEmail', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('format', [ + 'type' => self::TYPE_STRING, + 'description' => 'String format.', + 'default' => APP_DATABASE_ATTRIBUTE_EMAIL, + 'example' => APP_DATABASE_ATTRIBUTE_EMAIL, + ]) + ->addRule('default', [ + 'type' => self::TYPE_STRING, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'required' => false, + 'example' => 'default@example.com', + ]) + ; + } + + public array $conditions = [ + 'type' => self::TYPE_STRING, + 'format' => \APP_DATABASE_ATTRIBUTE_EMAIL + ]; + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'AttributeEmail'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE_EMAIL; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/AttributeEnum.php b/src/Appwrite/Utopia/Response/Model/AttributeEnum.php new file mode 100644 index 0000000000..992b62ee3a --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeEnum.php @@ -0,0 +1,73 @@ +addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'status', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('elements', [ + 'type' => self::TYPE_STRING, + 'description' => 'Array of elements in enumerated type.', + 'default' => null, + 'example' => 'element', + 'array' => true, + ]) + ->addRule('format', [ + 'type' => self::TYPE_STRING, + 'description' => 'String format.', + 'default' => APP_DATABASE_ATTRIBUTE_ENUM, + 'example' => APP_DATABASE_ATTRIBUTE_ENUM, + ]) + ->addRule('default', [ + 'type' => self::TYPE_STRING, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'required' => false, + 'example' => 'element', + ]) + ; + } + + public array $conditions = [ + 'type' => self::TYPE_STRING, + 'format' => \APP_DATABASE_ATTRIBUTE_ENUM + ]; + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'AttributeEnum'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE_ENUM; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/AttributeFloat.php b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php new file mode 100644 index 0000000000..266b89c330 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeFloat.php @@ -0,0 +1,73 @@ +addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'percentageCompleted', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'double', + ]) + ->addRule('min', [ + 'type' => self::TYPE_FLOAT, + 'description' => 'Minimum value to enforce for new documents.', + 'default' => null, + 'required' => false, + 'example' => 1.5, + ]) + ->addRule('max', [ + 'type' => self::TYPE_FLOAT, + 'description' => 'Maximum value to enforce for new documents.', + 'default' => null, + 'required' => false, + 'example' => 10.5, + ]) + ->addRule('default', [ + 'type' => self::TYPE_FLOAT, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'required' => false, + 'example' => 2.5, + ]) + ; + } + + public array $conditions = [ + 'type' => self::TYPE_FLOAT, + ]; + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'AttributeFloat'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE_FLOAT; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/AttributeIP.php b/src/Appwrite/Utopia/Response/Model/AttributeIP.php new file mode 100644 index 0000000000..cfa309317a --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeIP.php @@ -0,0 +1,66 @@ +addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'ipAddress', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('format', [ + 'type' => self::TYPE_STRING, + 'description' => 'String format.', + 'default' => APP_DATABASE_ATTRIBUTE_IP, + 'example' => APP_DATABASE_ATTRIBUTE_IP, + ]) + ->addRule('default', [ + 'type' => self::TYPE_STRING, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'required' => false, + 'example' => '192.0.2.0', + ]) + ; + } + + public array $conditions = [ + 'type' => self::TYPE_STRING, + 'format' => \APP_DATABASE_ATTRIBUTE_IP + ]; + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'AttributeIP'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE_IP; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/AttributeInteger.php b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php new file mode 100644 index 0000000000..fddfe57445 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeInteger.php @@ -0,0 +1,72 @@ +addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'count', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'integer', + ]) + ->addRule('min', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Minimum value to enforce for new documents.', + 'default' => null, + 'required' => false, + 'example' => 1, + ]) + ->addRule('max', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Maximum value to enforce for new documents.', + 'default' => null, + 'required' => false, + 'example' => 10, + ]) + ->addRule('default', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'required' => false, + 'example' => 10, + ]) + ; + } + + public array $conditions = [ + 'type' => self::TYPE_INTEGER, + ]; + + /** + * Get Name * + * @return string + */ + public function getName(): string + { + return 'AttributeInteger'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE_INTEGER; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/AttributeList.php b/src/Appwrite/Utopia/Response/Model/AttributeList.php new file mode 100644 index 0000000000..8b04475a14 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeList.php @@ -0,0 +1,58 @@ +addRule('total', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Total number of attributes in the given collection.', + 'default' => 0, + 'example' => 5, + ]) + ->addRule('attributes', [ + 'type' => [ + Response::MODEL_ATTRIBUTE_BOOLEAN, + Response::MODEL_ATTRIBUTE_INTEGER, + Response::MODEL_ATTRIBUTE_FLOAT, + Response::MODEL_ATTRIBUTE_EMAIL, + Response::MODEL_ATTRIBUTE_ENUM, + Response::MODEL_ATTRIBUTE_URL, + Response::MODEL_ATTRIBUTE_IP, + Response::MODEL_ATTRIBUTE_DATETIME, + Response::MODEL_ATTRIBUTE_RELATIONSHIP, + Response::MODEL_ATTRIBUTE_STRING // needs to be last, since its condition would dominate any other string attribute + ], + 'description' => 'List of attributes.', + 'default' => [], + 'array' => true + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Attributes List'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE_LIST; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php b/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php new file mode 100644 index 0000000000..d88fbd1530 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeRelationship.php @@ -0,0 +1,96 @@ +addRule('relatedCollection', [ + 'type' => self::TYPE_STRING, + 'description' => 'The ID of the related collection.', + 'default' => null, + 'example' => 'collection', + ]) + ->addRule('relationType', [ + 'type' => self::TYPE_STRING, + 'description' => 'The type of the relationship.', + 'default' => '', + 'example' => 'oneToOne|oneToMany|manyToOne|manyToMany', + ]) + ->addRule('twoWay', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Is the relationship two-way?', + 'default' => false, + 'example' => false, + ]) + ->addRule('twoWayKey', [ + 'type' => self::TYPE_STRING, + 'description' => 'The key of the two-way relationship.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('onDelete', [ + 'type' => self::TYPE_STRING, + 'description' => 'How deleting the parent document will propagate to child documents.', + 'default' => 'restrict', + 'example' => 'restrict|cascade|setNull', + ]) + ->addRule('side', [ + 'type' => self::TYPE_STRING, + 'description' => 'Whether this is the parent or child side of the relationship', + 'default' => '', + 'example' => 'parent|child', + ]) + ; + } + + public array $conditions = [ + 'type' => self::TYPE_RELATIONSHIP, + ]; + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'AttributeRelationship'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE_RELATIONSHIP; + } + + /** + * Process Document before returning it to the client + * + * @return Document + */ + public function filter(Document $document): Document + { + $options = $document->getAttribute('options'); + if (!\is_null($options)) { + $document->setAttribute('relatedCollection', $options['relatedCollection']); + $document->setAttribute('relationType', $options['relationType']); + $document->setAttribute('twoWay', $options['twoWay']); + $document->setAttribute('twoWayKey', $options['twoWayKey']); + $document->setAttribute('side', $options['side']); + $document->setAttribute('onDelete', $options['onDelete']); + } + return $document; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/AttributeString.php b/src/Appwrite/Utopia/Response/Model/AttributeString.php new file mode 100644 index 0000000000..12bb42009d --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeString.php @@ -0,0 +1,53 @@ +addRule('size', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Attribute size.', + 'default' => 0, + 'example' => 128, + ]) + ->addRule('default', [ + 'type' => self::TYPE_STRING, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'required' => false, + 'example' => 'default', + ]) + ; + } + + public array $conditions = [ + 'type' => self::TYPE_STRING, + ]; + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'AttributeString'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE_STRING; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/AttributeURL.php b/src/Appwrite/Utopia/Response/Model/AttributeURL.php new file mode 100644 index 0000000000..633d5b49d7 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/AttributeURL.php @@ -0,0 +1,66 @@ +addRule('key', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute Key.', + 'default' => '', + 'example' => 'githubUrl', + ]) + ->addRule('type', [ + 'type' => self::TYPE_STRING, + 'description' => 'Attribute type.', + 'default' => '', + 'example' => 'string', + ]) + ->addRule('format', [ + 'type' => self::TYPE_STRING, + 'description' => 'String format.', + 'default' => APP_DATABASE_ATTRIBUTE_URL, + 'example' => APP_DATABASE_ATTRIBUTE_URL, + ]) + ->addRule('default', [ + 'type' => self::TYPE_STRING, + 'description' => 'Default value for attribute when not provided. Cannot be set when attribute is required.', + 'default' => null, + 'required' => false, + 'example' => 'http://example.com', + ]) + ; + } + + public array $conditions = [ + 'type' => self::TYPE_STRING, + 'format' => \APP_DATABASE_ATTRIBUTE_URL + ]; + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'AttributeURL'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_ATTRIBUTE_URL; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/BaseList.php b/src/Appwrite/Utopia/Response/Model/BaseList.php index 1fa3197ba7..dea5d476f2 100644 --- a/src/Appwrite/Utopia/Response/Model/BaseList.php +++ b/src/Appwrite/Utopia/Response/Model/BaseList.php @@ -32,9 +32,11 @@ class BaseList extends Model if ($paging) { $namesWithCap = [ - 'rows', 'tables', 'users', 'files', 'buckets', 'functions', - 'deployments', 'executions', 'projects', 'webhooks', 'keys', - 'platforms', 'rules', 'memberships', 'teams' + 'rows', 'tables', // new api + 'documents', 'collections', // legacy api + 'users', 'files', 'buckets', 'functions', + 'deployments', 'executions', 'projects', + 'webhooks', 'keys', 'platforms', 'rules', 'memberships', 'teams' ]; if (\in_array($name, $namesWithCap)) { diff --git a/src/Appwrite/Utopia/Response/Model/Collection.php b/src/Appwrite/Utopia/Response/Model/Collection.php new file mode 100644 index 0000000000..2c2bf0cca8 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Collection.php @@ -0,0 +1,109 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Collection ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('$createdAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Collection creation date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Collection update date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$permissions', [ + 'type' => self::TYPE_STRING, + 'description' => 'Collection permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', + 'default' => '', + 'example' => ['read("any")'], + 'array' => true + ]) + ->addRule('databaseId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Database ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'Collection name.', + 'default' => '', + 'example' => 'My Collection', + ]) + ->addRule('enabled', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Collection enabled. Can be \'enabled\' or \'disabled\'. When disabled, the collection is inaccessible to users, but remains accessible to Server SDKs using API keys.', + 'default' => true, + 'example' => false, + ]) + ->addRule('documentSecurity', [ + 'type' => self::TYPE_BOOLEAN, + 'description' => 'Whether document-level permissions are enabled. [Learn more about permissions](https://appwrite.io/docs/permissions).', + 'default' => '', + 'example' => true, + ]) + ->addRule('attributes', [ + 'type' => [ + Response::MODEL_ATTRIBUTE_BOOLEAN, + Response::MODEL_ATTRIBUTE_INTEGER, + Response::MODEL_ATTRIBUTE_FLOAT, + Response::MODEL_ATTRIBUTE_EMAIL, + Response::MODEL_ATTRIBUTE_ENUM, + Response::MODEL_ATTRIBUTE_URL, + Response::MODEL_ATTRIBUTE_IP, + Response::MODEL_ATTRIBUTE_DATETIME, + Response::MODEL_ATTRIBUTE_RELATIONSHIP, + Response::MODEL_ATTRIBUTE_STRING, // needs to be last, since its condition would dominate any other string attribute + ], + 'description' => 'Collection attributes.', + 'default' => [], + 'example' => new \stdClass(), + 'array' => true, + ]) + ->addRule('indexes', [ + 'type' => Response::MODEL_INDEX, + 'description' => 'Collection indexes.', + 'default' => [], + 'example' => new \stdClass(), + 'array' => true + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'Collection'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_COLLECTION; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/Document.php b/src/Appwrite/Utopia/Response/Model/Document.php new file mode 100644 index 0000000000..41a10cee89 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Document.php @@ -0,0 +1,92 @@ +addRule('$id', [ + 'type' => self::TYPE_STRING, + 'description' => 'Document ID.', + 'default' => '', + 'example' => '5e5ea5c16897e', + ]) + ->addRule('$collectionId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Collection ID.', + 'default' => '', + 'example' => '5e5ea5c15117e', + ]) + ->addRule('$databaseId', [ + 'type' => self::TYPE_STRING, + 'description' => 'Database ID.', + 'default' => '', + 'example' => '5e5ea5c15117e', + ]) + ->addRule('$createdAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Document creation date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$updatedAt', [ + 'type' => self::TYPE_DATETIME, + 'description' => 'Document update date in ISO 8601 format.', + 'default' => '', + 'example' => self::TYPE_DATETIME_EXAMPLE, + ]) + ->addRule('$permissions', [ + 'type' => self::TYPE_STRING, + 'description' => 'Document permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', + 'default' => '', + 'example' => ['read("any")'], + 'array' => true, + ]); + } + + public function filter(DatabaseDocument $document): DatabaseDocument + { + $document->removeAttribute('$internalId'); + $document->removeAttribute('$collection'); + $document->removeAttribute('$tenant'); + + foreach ($document->getAttributes() as $attribute) { + if (\is_array($attribute)) { + foreach ($attribute as $subAttribute) { + if ($subAttribute instanceof DatabaseDocument) { + $this->filter($subAttribute); + } + } + } elseif ($attribute instanceof DatabaseDocument) { + $this->filter($attribute); + } + } + + return $document; + } +} diff --git a/src/Appwrite/Utopia/Response/Model/UsageCollection.php b/src/Appwrite/Utopia/Response/Model/UsageCollection.php new file mode 100644 index 0000000000..b2336d65ba --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/UsageCollection.php @@ -0,0 +1,54 @@ +addRule('range', [ + 'type' => self::TYPE_STRING, + 'description' => 'Time range of the usage stats.', + 'default' => '', + 'example' => '30d', + ]) + ->addRule('documentsTotal', [ + 'type' => self::TYPE_INTEGER, + 'description' => 'Total aggregated number of of documents.', + 'default' => 0, + 'example' => 0, + ]) + ->addRule('documents', [ + 'type' => Response::MODEL_METRIC, + 'description' => 'Aggregated number of documents per period.', + 'default' => [], + 'example' => [], + 'array' => true + ]) + ; + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'UsageCollection'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_USAGE_COLLECTION; + } +}