update: abstraction over attribute and column apis.

This commit is contained in:
Darshan 2025-05-08 10:40:35 +05:30
parent b55521e3de
commit fc456b4cca
26 changed files with 294 additions and 1583 deletions

View file

@ -30,7 +30,8 @@ class Create extends Action
{
$this->setResponseModel(UtopiaResponse::MODEL_ATTRIBUTE_BOOLEAN);
$this->setHttpMethod(self::HTTP_REQUEST_METHOD_POST)
$this
->setHttpMethod(self::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/databases/:databaseId/collections/:collectionId/attributes/boolean')
->desc('Create boolean attribute')
->groups(['api', 'database', 'schema'])

View file

@ -30,7 +30,8 @@ class Update extends Action
{
$this->setResponseModel(UtopiaResponse::MODEL_ATTRIBUTE_BOOLEAN);
$this->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH)
$this
->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/databases/:databaseId/collections/:collectionId/attributes/boolean/:key')
->desc('Update boolean attribute')
->groups(['api', 'database', 'schema'])

View file

@ -1,417 +0,0 @@
<?php
namespace Appwrite\Platform\Modules\Databases\Http\Columns;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Utopia\Response;
use Throwable;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Exception\Authorization as AuthorizationException;
use Utopia\Database\Exception\Conflict as ConflictException;
use Utopia\Database\Exception\Duplicate as DuplicateException;
use Utopia\Database\Exception\Index as IndexException;
use Utopia\Database\Exception\Limit as LimitException;
use Utopia\Database\Exception\NotFound as NotFoundException;
use Utopia\Database\Exception\Restricted as RestrictedException;
use Utopia\Database\Exception\Structure as StructureException;
use Utopia\Database\Exception\Truncate as TruncateException;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Structure;
use Utopia\Platform\Action as UtopiaAction;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Range;
class Action extends UtopiaAction
{
/**
* * Create column of varying type
*
* @param string $databaseId
* @param string $tableId
* @param Document $column
* @param Response $response
* @param Database $dbForProject
* @param EventDatabase $queueForDatabase
* @param Event $queueForEvents
*
* @return Document Newly created attribute document
*
* @throws AuthorizationException
* @throws Exception
* @throws LimitException
* @throws RestrictedException
* @throws StructureException
* @throws \Utopia\Database\Exception
* @throws ConflictException
*/
protected function createColumn(
string $databaseId,
string $tableId,
Document $column,
Response $response,
Database $dbForProject,
EventDatabase $queueForDatabase,
Event $queueForEvents
): Document {
$key = $column->getAttribute('key');
$type = $column->getAttribute('type', '');
$size = $column->getAttribute('size', 0);
$required = $column->getAttribute('required', true);
$signed = $column->getAttribute('signed', true); // integers are signed by default
$array = $column->getAttribute('array', false);
$format = $column->getAttribute('format', '');
$formatOptions = $column->getAttribute('formatOptions', []);
$filters = $column->getAttribute('filters', []); // filters are hidden from the endpoint
$default = $column->getAttribute('default');
$options = $column->getAttribute('options', []);
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
if ($db->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
$table = $dbForProject->getDocument('database_' . $db->getInternalId(), $tableId);
if ($table->isEmpty()) {
throw new Exception(Exception::TABLE_NOT_FOUND);
}
if (!empty($format)) {
if (!Structure::hasFormat($format, $type)) {
throw new Exception(Exception::COLUMN_FORMAT_UNSUPPORTED, "Format {$format} not available for {$type} columns.");
}
}
// Must throw here since dbForProject->createAttribute is performed by db worker
if ($required && isset($default)) {
throw new Exception(Exception::COLUMN_DEFAULT_UNSUPPORTED, 'Cannot set default value for required column');
}
if ($array && isset($default)) {
throw new Exception(Exception::COLUMN_DEFAULT_UNSUPPORTED, 'Cannot set default value for array columns');
}
if ($type === Database::VAR_RELATIONSHIP) {
$options['side'] = Database::RELATION_SIDE_PARENT;
$relatedTable = $dbForProject->getDocument('database_' . $db->getInternalId(), $options['relatedCollection'] ?? '');
if ($relatedTable->isEmpty()) {
throw new Exception(Exception::TABLE_NOT_FOUND, 'The related table was not found.');
}
}
try {
$column = new Document([
'$id' => ID::custom($db->getInternalId() . '_' . $table->getInternalId() . '_' . $key),
'key' => $key,
'databaseInternalId' => $db->getInternalId(),
'databaseId' => $db->getId(),
'collectionInternalId' => $table->getInternalId(),
'collectionId' => $tableId,
'type' => $type,
'status' => 'processing', // processing, available, failed, deleting, stuck
'size' => $size,
'required' => $required,
'signed' => $signed,
'default' => $default,
'array' => $array,
'format' => $format,
'formatOptions' => $formatOptions,
'filters' => $filters,
'options' => $options,
]);
$dbForProject->checkAttribute($table, $column);
$column = $dbForProject->createDocument('attributes', $column);
} catch (DuplicateException) {
throw new Exception(Exception::COLUMN_ALREADY_EXISTS);
} catch (LimitException) {
throw new Exception(Exception::COLUMN_LIMIT_EXCEEDED);
} catch (Throwable $e) {
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $tableId);
$dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $table->getInternalId());
throw $e;
}
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $tableId);
$dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $table->getInternalId());
if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) {
$twoWayKey = $options['twoWayKey'];
$options['relatedCollection'] = $table->getId();
$options['twoWayKey'] = $key;
$options['side'] = Database::RELATION_SIDE_CHILD;
try {
$twoWayAttribute = new Document([
'$id' => ID::custom($db->getInternalId() . '_' . $relatedTable->getInternalId() . '_' . $twoWayKey),
'key' => $twoWayKey,
'databaseInternalId' => $db->getInternalId(),
'databaseId' => $db->getId(),
'collectionInternalId' => $relatedTable->getInternalId(),
'collectionId' => $relatedTable->getId(),
'type' => $type,
'status' => 'processing', // processing, available, failed, deleting, stuck
'size' => $size,
'required' => $required,
'signed' => $signed,
'default' => $default,
'array' => $array,
'format' => $format,
'formatOptions' => $formatOptions,
'filters' => $filters,
'options' => $options,
]);
$dbForProject->checkAttribute($relatedTable, $twoWayAttribute);
$dbForProject->createDocument('attributes', $twoWayAttribute);
} catch (DuplicateException) {
$dbForProject->deleteDocument('attributes', $column->getId());
throw new Exception(Exception::COLUMN_ALREADY_EXISTS);
} catch (LimitException) {
$dbForProject->deleteDocument('attributes', $column->getId());
throw new Exception(Exception::COLUMN_LIMIT_EXCEEDED);
} catch (Throwable $e) {
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $relatedTable->getId());
$dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedTable->getInternalId());
throw $e;
}
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $relatedTable->getId());
$dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedTable->getInternalId());
}
$queueForDatabase
->setType(DATABASE_TYPE_CREATE_ATTRIBUTE)
->setDatabase($db)
->setTable($table)
->setRow($column);
$queueForEvents
->setContext('table', $table)
->setContext('database', $db)
->setParam('databaseId', $databaseId)
->setParam('tableId', $table->getId())
->setParam('columnId', $column->getId());
$response->setStatusCode(SwooleResponse::STATUS_CODE_CREATED);
return $column;
}
protected function updateColumn(
string $databaseId,
string $tableId,
string $key,
Database $dbForProject,
Event $queueForEvents,
string $type,
int $size = null,
string $filter = null,
string|bool|int|float $default = null,
bool $required = null,
int|float|null $min = null,
int|float|null $max = null,
array $elements = null,
array $options = [],
string $newKey = null,
): Document {
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
if ($db->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
$table = $dbForProject->getDocument('database_' . $db->getInternalId(), $tableId);
if ($table->isEmpty()) {
throw new Exception(Exception::TABLE_NOT_FOUND);
}
$column = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $table->getInternalId() . '_' . $key);
if ($column->isEmpty()) {
throw new Exception(Exception::COLUMN_NOT_FOUND);
}
if ($column->getAttribute('status') !== 'available') {
throw new Exception(Exception::COLUMN_NOT_AVAILABLE);
}
if ($column->getAttribute(('type') !== $type)) {
throw new Exception(Exception::COLUMN_TYPE_INVALID);
}
if ($column->getAttribute('type') === Database::VAR_STRING && $column->getAttribute(('filter') !== $filter)) {
throw new Exception(Exception::COLUMN_TYPE_INVALID);
}
if ($required && isset($default)) {
throw new Exception(Exception::COLUMN_DEFAULT_UNSUPPORTED, 'Cannot set default value for required column');
}
if ($column->getAttribute('array', false) && isset($default)) {
throw new Exception(Exception::COLUMN_DEFAULT_UNSUPPORTED, 'Cannot set default value for array columns');
}
$tableId = 'database_' . $db->getInternalId() . '_collection_' . $table->getInternalId();
$column
->setAttribute('default', $default)
->setAttribute('required', $required);
if (!empty($size)) {
$column->setAttribute('size', $size);
}
switch ($column->getAttribute('format')) {
case APP_DATABASE_ATTRIBUTE_INT_RANGE:
case APP_DATABASE_ATTRIBUTE_FLOAT_RANGE:
$min ??= $column->getAttribute('formatOptions')['min'];
$max ??= $column->getAttribute('formatOptions')['max'];
if ($min > $max) {
throw new Exception(Exception::COLUMN_VALUE_INVALID, 'Minimum value must be lesser than maximum value');
}
if ($column->getAttribute('format') === APP_DATABASE_ATTRIBUTE_INT_RANGE) {
$validator = new Range($min, $max, Database::VAR_INTEGER);
} else {
$validator = new Range($min, $max, Database::VAR_FLOAT);
if (!is_null($default)) {
$default = \floatval($default);
}
}
if (!is_null($default) && !$validator->isValid($default)) {
throw new Exception(Exception::COLUMN_VALUE_INVALID, $validator->getDescription());
}
$options = [
'min' => $min,
'max' => $max
];
$column->setAttribute('formatOptions', $options);
break;
case APP_DATABASE_ATTRIBUTE_ENUM:
if (empty($elements)) {
throw new Exception(Exception::COLUMN_VALUE_INVALID, 'Enum elements must not be empty');
}
foreach ($elements as $element) {
if (\strlen($element) === 0) {
throw new Exception(Exception::COLUMN_VALUE_INVALID, 'Each enum element must not be empty');
}
}
if (!is_null($default) && !in_array($default, $elements)) {
throw new Exception(Exception::COLUMN_VALUE_INVALID, 'Default value not found in elements');
}
$options = [
'elements' => $elements
];
$column->setAttribute('formatOptions', $options);
break;
}
if ($type === Database::VAR_RELATIONSHIP) {
$primaryRowOptions = \array_merge($column->getAttribute('options', []), $options);
$column->setAttribute('options', $primaryRowOptions);
try {
$dbForProject->updateRelationship(
collection: $tableId,
id: $key,
newKey: $newKey,
onDelete: $primaryRowOptions['onDelete'],
);
} catch (NotFoundException) {
throw new Exception(Exception::COLUMN_NOT_FOUND);
}
if ($primaryRowOptions['twoWay']) {
$relatedTable = $dbForProject->getDocument('database_' . $db->getInternalId(), $primaryRowOptions['relatedCollection']);
$relatedColumn = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $relatedTable->getInternalId() . '_' . $primaryRowOptions['twoWayKey']);
if (!empty($newKey) && $newKey !== $key) {
$options['twoWayKey'] = $newKey;
}
$relatedOptions = \array_merge($relatedColumn->getAttribute('options'), $options);
$relatedColumn->setAttribute('options', $relatedOptions);
$dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $relatedTable->getInternalId() . '_' . $primaryRowOptions['twoWayKey'], $relatedColumn);
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $relatedTable->getId());
}
} else {
try {
$dbForProject->updateAttribute(
collection: $tableId,
id: $key,
size: $size,
required: $required,
default: $default,
formatOptions: $options,
newKey: $newKey ?? null
);
} catch (TruncateException) {
throw new Exception(Exception::COLUMN_INVALID_RESIZE);
} catch (NotFoundException) {
throw new Exception(Exception::COLUMN_NOT_FOUND);
} catch (LimitException) {
throw new Exception(Exception::COLUMN_LIMIT_EXCEEDED);
} catch (IndexException $e) {
throw new Exception(Exception::INDEX_INVALID, $e->getMessage());
}
}
if (!empty($newKey) && $key !== $newKey) {
$originalUid = $column->getId();
$column
->setAttribute('$id', ID::custom($db->getInternalId() . '_' . $table->getInternalId() . '_' . $newKey))
->setAttribute('key', $newKey);
$dbForProject->updateDocument('attributes', $originalUid, $column);
/**
* @var Document $index
*/
foreach ($table->getAttribute('indexes') as $index) {
/**
* @var string[] $columns
*/
$columns = $index->getAttribute('attributes', []);
$found = \array_search($key, $columns);
if ($found !== false) {
$columns[$found] = $newKey;
$index->setAttribute('attributes', $columns);
$dbForProject->updateDocument('indexes', $index->getId(), $index);
}
}
} else {
$column = $dbForProject->updateDocument('attributes', $db->getInternalId() . '_' . $table->getInternalId() . '_' . $key, $column);
}
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $table->getId());
$queueForEvents
->setContext('table', $table)
->setContext('database', $db)
->setParam('databaseId', $databaseId)
->setParam('tableId', $table->getId())
->setParam('columnId', $column->getId());
return $column;
}
}

View file

@ -4,21 +4,19 @@ namespace Appwrite\Platform\Modules\Databases\Http\Columns\Boolean;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Boolean\Create as BooleanCreate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
class Create extends ColumnAction
class Create extends BooleanCreate
{
use HTTP;
@ -29,9 +27,12 @@ class Create extends ColumnAction
public function __construct()
{
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_BOOLEAN);
$this
->setHttpMethod(self::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/boolean')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/boolean')
->desc('Create boolean column')
->groups(['api', 'database', 'schema'])
->label('event', 'databases.[databaseId].tables.[tableId].columns.[columnId].create')
@ -41,14 +42,14 @@ class Create extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'createBooleanColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/create-boolean-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_ACCEPTED,
model: UtopiaResponse::MODEL_COLUMN_BOOLEAN,
model: $this->getResponseModel(),
)
]
))
@ -62,23 +63,8 @@ class Create extends ColumnAction
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(string $databaseId, string $tableId, string $key, ?bool $required, ?bool $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents): void
{
$column = $this->createColumn($databaseId, $tableId, new Document([
'key' => $key,
'type' => Database::VAR_BOOLEAN,
'size' => 0,
'required' => $required,
'default' => $default,
'array' => $array,
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_BOOLEAN);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?bool $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $default, $array, $response, $dbForProject, $queueForDatabase, $queueForEvents);
});
}
}

View file

@ -3,7 +3,7 @@
namespace Appwrite\Platform\Modules\Databases\Http\Columns\Boolean;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Boolean\Update as BooleanUpdate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@ -12,13 +12,12 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
use Utopia\Validator\Nullable;
class Update extends ColumnAction
class Update extends BooleanUpdate
{
use HTTP;
@ -29,9 +28,12 @@ class Update extends ColumnAction
public function __construct()
{
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_BOOLEAN);
$this
->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/boolean/:key')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/boolean/:key')
->desc('Update boolean column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -41,14 +43,14 @@ class Update extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'updateBooleanColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/update-boolean-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_OK,
model: UtopiaResponse::MODEL_COLUMN_BOOLEAN,
model: $this->getResponseModel(),
)
],
contentType: ContentType::JSON
@ -62,25 +64,8 @@ class Update extends ColumnAction
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(string $databaseId, string $tableId, string $key, ?bool $required, ?bool $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents): void
{
$column = $this->updateColumn(
databaseId: $databaseId,
tableId: $tableId,
key: $key,
dbForProject: $dbForProject,
queueForEvents: $queueForEvents,
type: Database::VAR_BOOLEAN,
default: $default,
required: $required,
newKey: $newKey
);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_OK)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_BOOLEAN);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?bool $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $default, $newKey, $response, $dbForProject, $queueForEvents);
});
}
}

View file

@ -4,22 +4,20 @@ namespace Appwrite\Platform\Modules\Databases\Http\Columns\Datetime;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Datetime\Create as DatetimeCreate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
class Create extends ColumnAction
class Create extends DatetimeCreate
{
use HTTP;
@ -30,10 +28,12 @@ class Create extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_DATETIME);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpMethod(self::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/datetime')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/datetime')
->desc('Create datetime column')
->groups(['api', 'database'])
->label('scope', 'collections.write')
@ -43,14 +43,14 @@ class Create extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'createDatetimeColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/create-datetime-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_ACCEPTED,
model: UtopiaResponse::MODEL_COLUMN_DATETIME,
model: $this->getResponseModel(),
)
]
))
@ -64,43 +64,8 @@ class Create extends ColumnAction
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?string $default,
bool $array,
UtopiaResponse $response,
Database $dbForProject,
EventDatabase $queueForDatabase,
Event $queueForEvents
): void {
$filters = ['datetime'];
$column = $this->createColumn(
$databaseId,
$tableId,
new Document([
'key' => $key,
'type' => Database::VAR_DATETIME,
'size' => 0,
'required' => $required,
'default' => $default,
'array' => $array,
'filters' => $filters,
]),
$response,
$dbForProject,
$queueForDatabase,
$queueForEvents
);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_DATETIME);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $default, $array, $response, $dbForProject, $queueForDatabase, $queueForEvents);
});
}
}

View file

@ -3,7 +3,7 @@
namespace Appwrite\Platform\Modules\Databases\Http\Columns\Datetime;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Datetime\Update as DatetimeUpdate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@ -13,13 +13,12 @@ use Utopia\Database\Database;
use Utopia\Database\Validator\Datetime as DatetimeValidator;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
use Utopia\Validator\Nullable;
class Update extends ColumnAction
class Update extends DatetimeUpdate
{
use HTTP;
@ -30,10 +29,12 @@ class Update extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_DATETIME);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/datetime/:key')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/datetime/:key')
->desc('Update dateTime column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -43,14 +44,14 @@ class Update extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'updateDatetimeColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/update-datetime-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_OK,
model: UtopiaResponse::MODEL_COLUMN_DATETIME,
model: $this->getResponseModel(),
)
],
contentType: ContentType::JSON
@ -64,34 +65,8 @@ class Update extends ColumnAction
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?string $default,
?string $newKey,
UtopiaResponse $response,
Database $dbForProject,
Event $queueForEvents
): void {
$column = $this->updateColumn(
databaseId: $databaseId,
tableId: $tableId,
key: $key,
dbForProject: $dbForProject,
queueForEvents: $queueForEvents,
type: Database::VAR_DATETIME,
default: $default,
required: $required,
newKey: $newKey
);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_OK)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_DATETIME);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?bool $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $default, $newKey, $response, $dbForProject, $queueForEvents);
});
}
}

View file

@ -4,22 +4,19 @@ namespace Appwrite\Platform\Modules\Databases\Http\Columns;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Delete as AttributesDelete;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\IndexDependency as IndexDependencyValidator;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
class Delete extends Action
class Delete extends AttributesDelete
{
use HTTP;
@ -30,10 +27,14 @@ class Delete extends Action
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
// parent action handles multiple model types internally
$this->setResponseModel(UtopiaResponse::MODEL_NONE);
$this
->setHttpMethod(self::HTTP_REQUEST_METHOD_DELETE)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/:key')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/:key')
->desc('Delete column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -43,14 +44,14 @@ class Delete extends Action
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'deleteColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/delete-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_NOCONTENT,
model: UtopiaResponse::MODEL_NONE,
model: $this->getResponseModel(),
)
],
contentType: ContentType::NONE
@ -62,103 +63,8 @@ class Delete extends Action
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
UtopiaResponse $response,
Database $dbForProject,
EventDatabase $queueForDatabase,
Event $queueForEvents,
): void {
$db = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
if ($db->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
$table = $dbForProject->getDocument('database_' . $db->getInternalId(), $tableId);
if ($table->isEmpty()) {
throw new Exception(Exception::TABLE_NOT_FOUND);
}
$column = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $table->getInternalId() . '_' . $key);
if ($column->isEmpty()) {
throw new Exception(Exception::COLUMN_NOT_FOUND);
}
$validator = new IndexDependencyValidator(
$table->getAttribute('indexes'),
$dbForProject->getAdapter()->getSupportForCastIndexArray(),
);
if (!$validator->isValid($column)) {
throw new Exception(Exception::INDEX_DEPENDENCY);
}
if ($column->getAttribute('status') === 'available') {
$column = $dbForProject->updateDocument('attributes', $column->getId(), $column->setAttribute('status', 'deleting'));
}
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $tableId);
$dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $table->getInternalId());
if ($column->getAttribute('type') === Database::VAR_RELATIONSHIP) {
$options = $column->getAttribute('options');
if ($options['twoWay']) {
$relatedTable = $dbForProject->getDocument('database_' . $db->getInternalId(), $options['relatedCollection']);
if ($relatedTable->isEmpty()) {
throw new Exception(Exception::TABLE_NOT_FOUND);
}
$relatedColumn = $dbForProject->getDocument('attributes', $db->getInternalId() . '_' . $relatedTable->getInternalId() . '_' . $options['twoWayKey']);
if ($relatedColumn->isEmpty()) {
throw new Exception(Exception::COLUMN_NOT_FOUND);
}
if ($relatedColumn->getAttribute('status') === 'available') {
$dbForProject->updateDocument('attributes', $relatedColumn->getId(), $relatedColumn->setAttribute('status', 'deleting'));
}
$dbForProject->purgeCachedDocument('database_' . $db->getInternalId(), $options['relatedCollection']);
$dbForProject->purgeCachedCollection('database_' . $db->getInternalId() . '_collection_' . $relatedTable->getInternalId());
}
}
$queueForDatabase
->setType(DATABASE_TYPE_DELETE_ATTRIBUTE)
->setTable($table)
->setDatabase($db)
->setRow($column);
$type = $column->getAttribute('type');
$format = $column->getAttribute('format');
$model = match ($type) {
Database::VAR_BOOLEAN => UtopiaResponse::MODEL_COLUMN_BOOLEAN,
Database::VAR_INTEGER => UtopiaResponse::MODEL_COLUMN_INTEGER,
Database::VAR_FLOAT => UtopiaResponse::MODEL_COLUMN_FLOAT,
Database::VAR_DATETIME => UtopiaResponse::MODEL_COLUMN_DATETIME,
Database::VAR_RELATIONSHIP => UtopiaResponse::MODEL_COLUMN_RELATIONSHIP,
Database::VAR_STRING => match ($format) {
APP_DATABASE_ATTRIBUTE_EMAIL => UtopiaResponse::MODEL_COLUMN_EMAIL,
APP_DATABASE_ATTRIBUTE_ENUM => UtopiaResponse::MODEL_COLUMN_ENUM,
APP_DATABASE_ATTRIBUTE_IP => UtopiaResponse::MODEL_COLUMN_IP,
APP_DATABASE_ATTRIBUTE_URL => UtopiaResponse::MODEL_COLUMN_URL,
default => UtopiaResponse::MODEL_COLUMN_STRING,
},
default => UtopiaResponse::MODEL_COLUMN,
};
$queueForEvents
->setParam('databaseId', $databaseId)
->setParam('tableId', $table->getId())
->setParam('columnId', $column->getId())
->setContext('table', $table)
->setContext('database', $db)
->setPayload($response->output($column, $model));
$response->noContent();
->callback(function (string $databaseId, string $tableId, string $key, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $response, $dbForProject, $queueForDatabase, $queueForEvents);
});
}
}

View file

@ -5,21 +5,19 @@ namespace Appwrite\Platform\Modules\Databases\Http\Columns\Email;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Network\Validator\Email;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Email\Create as EmailCreate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
class Create extends ColumnAction
class Create extends EmailCreate
{
use HTTP;
@ -30,10 +28,12 @@ class Create extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_EMAIL);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpMethod(self::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/email')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/email')
->desc('Create email column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -43,14 +43,14 @@ class Create extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'createEmailColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/create-email-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_ACCEPTED,
model: UtopiaResponse::MODEL_COLUMN_EMAIL,
model: $this->getResponseModel(),
)
]
))
@ -64,41 +64,8 @@ class Create extends ColumnAction
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?string $default,
bool $array,
\Appwrite\Utopia\Response $response,
Database $dbForProject,
EventDatabase $queueForDatabase,
Event $queueForEvents
): void {
$column = $this->createColumn(
$databaseId,
$tableId,
new Document([
'key' => $key,
'type' => Database::VAR_STRING,
'size' => 254,
'required' => $required,
'default' => $default,
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_EMAIL,
]),
$response,
$dbForProject,
$queueForDatabase,
$queueForEvents
);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_EMAIL);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $default, $array, $response, $dbForProject, $queueForDatabase, $queueForEvents);
});
}
}

View file

@ -4,7 +4,7 @@ namespace Appwrite\Platform\Modules\Databases\Http\Columns\Email;
use Appwrite\Event\Event;
use Appwrite\Network\Validator\Email;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Email\Update as EmailUpdate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@ -13,13 +13,12 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
use Utopia\Validator\Nullable;
class Update extends ColumnAction
class Update extends EmailUpdate
{
use HTTP;
@ -30,10 +29,12 @@ class Update extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_EMAIL);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/email/:key')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/email/:key')
->desc('Update email column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -43,14 +44,14 @@ class Update extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'updateEmailColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/update-email-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_OK,
model: UtopiaResponse::MODEL_COLUMN_EMAIL,
model: $this->getResponseModel(),
)
],
contentType: ContentType::JSON
@ -64,35 +65,8 @@ class Update extends ColumnAction
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?string $default,
?string $newKey,
UtopiaResponse $response,
Database $dbForProject,
Event $queueForEvents
): void {
$column = $this->updateColumn(
databaseId: $databaseId,
tableId: $tableId,
key: $key,
dbForProject: $dbForProject,
queueForEvents: $queueForEvents,
type: Database::VAR_STRING,
filter: APP_DATABASE_ATTRIBUTE_EMAIL,
default: $default,
required: $required,
newKey: $newKey
);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_OK)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_EMAIL);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?bool $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $default, $newKey, $response, $dbForProject, $queueForEvents);
});
}
}

View file

@ -4,24 +4,21 @@ namespace Appwrite\Platform\Modules\Databases\Http\Columns\Enum;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Enum\Create as EnumCreate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Boolean;
use Utopia\Validator\Text;
class Create extends ColumnAction
class Create extends EnumCreate
{
use HTTP;
@ -32,10 +29,12 @@ class Create extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_ENUM);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpMethod(self::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/enum')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/enum')
->desc('Create enum column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -45,14 +44,14 @@ class Create extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'createEnumColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/create-attribute-enum.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_ACCEPTED,
model: UtopiaResponse::MODEL_COLUMN_ENUM,
model: $this->getResponseModel(),
)
]
))
@ -67,47 +66,8 @@ class Create extends ColumnAction
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
array $elements,
?bool $required,
?string $default,
bool $array,
\Appwrite\Utopia\Response $response,
Database $dbForProject,
EventDatabase $queueForDatabase,
Event $queueForEvents
): void {
if (!is_null($default) && !in_array($default, $elements, true)) {
throw new Exception(Exception::COLUMN_VALUE_INVALID, 'Default value not found in elements');
}
$column = $this->createColumn(
$databaseId,
$tableId,
new Document([
'key' => $key,
'type' => Database::VAR_STRING,
'size' => Database::LENGTH_KEY,
'required' => $required,
'default' => $default,
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_ENUM,
'formatOptions' => ['elements' => $elements],
]),
$response,
$dbForProject,
$queueForDatabase,
$queueForEvents
);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_ENUM);
->callback(function (string $databaseId, string $tableId, string $key, array $elements, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $elements, $required, $default, $array, $response, $dbForProject, $queueForDatabase, $queueForEvents);
});
}
}

View file

@ -3,7 +3,7 @@
namespace Appwrite\Platform\Modules\Databases\Http\Columns\Enum;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Enum\Update as EnumUpdate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@ -12,7 +12,6 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\ArrayList;
@ -20,7 +19,7 @@ use Utopia\Validator\Boolean;
use Utopia\Validator\Nullable;
use Utopia\Validator\Text;
class Update extends ColumnAction
class Update extends EnumUpdate
{
use HTTP;
@ -31,10 +30,12 @@ class Update extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_ENUM);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/enum/:key')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/enum/:key')
->desc('Update enum column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -44,14 +45,14 @@ class Update extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'updateEnumColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/update-enum-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_OK,
model: UtopiaResponse::MODEL_COLUMN_ENUM,
model: $this->getResponseModel(),
)
],
contentType: ContentType::JSON
@ -66,37 +67,8 @@ class Update extends ColumnAction
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?array $elements,
?bool $required,
?string $default,
?string $newKey,
UtopiaResponse $response,
Database $dbForProject,
Event $queueForEvents
): void {
$column = $this->updateColumn(
databaseId: $databaseId,
tableId: $tableId,
key: $key,
dbForProject: $dbForProject,
queueForEvents: $queueForEvents,
type: Database::VAR_STRING,
filter: APP_DATABASE_ATTRIBUTE_ENUM,
default: $default,
required: $required,
elements: $elements,
newKey: $newKey
);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_OK)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_ENUM);
->callback(function (string $databaseId, string $tableId, string $key, array $elements, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $elements, $required, $default, $newKey, $response, $dbForProject, $queueForEvents);
});
}
}

View file

@ -4,24 +4,20 @@ namespace Appwrite\Platform\Modules\Databases\Http\Columns\Float;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Float\Create as FloatCreate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
use Utopia\Validator\FloatValidator;
use Utopia\Validator\Range;
class Create extends ColumnAction
class Create extends FloatCreate
{
use HTTP;
@ -32,10 +28,12 @@ class Create extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_FLOAT);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpMethod(self::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/float')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/float')
->desc('Create float column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -45,14 +43,14 @@ class Create extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'createFloatColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/create-float-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_ACCEPTED,
model: UtopiaResponse::MODEL_COLUMN_FLOAT,
model: $this->getResponseModel(),
)
]
))
@ -68,54 +66,8 @@ class Create extends ColumnAction
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?float $min,
?float $max,
?float $default,
bool $array,
UtopiaResponse $response,
Database $dbForProject,
EventDatabase $queueForDatabase,
Event $queueForEvents
): void {
$min ??= -PHP_FLOAT_MAX;
$max ??= PHP_FLOAT_MAX;
if ($min > $max) {
throw new Exception(Exception::COLUMN_VALUE_INVALID, 'Minimum value must be lesser than maximum value');
}
$validator = new Range($min, $max, Database::VAR_FLOAT);
if (!\is_null($default) && !$validator->isValid($default)) {
throw new Exception(Exception::COLUMN_VALUE_INVALID, $validator->getDescription());
}
$column = $this->createColumn($databaseId, $tableId, new Document([
'key' => $key,
'type' => Database::VAR_FLOAT,
'size' => 0,
'required' => $required,
'default' => $default,
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_FLOAT_RANGE,
'formatOptions' => ['min' => $min, 'max' => $max],
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$formatOptions = $column->getAttribute('formatOptions', []);
if (!empty($formatOptions)) {
$column->setAttribute('min', \floatval($formatOptions['min']));
$column->setAttribute('max', \floatval($formatOptions['max']));
}
$response
->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_FLOAT);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $min, $max, $default, $array, $response, $dbForProject, $queueForDatabase, $queueForEvents);
});
}
}

View file

@ -3,7 +3,7 @@
namespace Appwrite\Platform\Modules\Databases\Http\Columns\Float;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Float\Update as FloatUpdate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@ -12,14 +12,13 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
use Utopia\Validator\FloatValidator;
use Utopia\Validator\Nullable;
class Update extends ColumnAction
class Update extends FloatUpdate
{
use HTTP;
@ -30,10 +29,12 @@ class Update extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_FLOAT);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/float/:key')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/float/:key')
->desc('Update float column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -43,14 +44,14 @@ class Update extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'updateFloatColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/update-float-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_OK,
model: UtopiaResponse::MODEL_COLUMN_FLOAT,
model: $this->getResponseModel(),
)
],
contentType: ContentType::JSON
@ -66,44 +67,8 @@ class Update extends ColumnAction
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?float $min,
?float $max,
?float $default,
?string $newKey,
UtopiaResponse $response,
Database $dbForProject,
Event $queueForEvents
): void {
$column = $this->updateColumn(
databaseId: $databaseId,
tableId: $tableId,
key: $key,
dbForProject: $dbForProject,
queueForEvents: $queueForEvents,
type: Database::VAR_FLOAT,
default: $default,
required: $required,
min: $min,
max: $max,
newKey: $newKey
);
$formatOptions = $column->getAttribute('formatOptions', []);
if (!empty($formatOptions)) {
$column->setAttribute('min', \floatval($formatOptions['min']));
$column->setAttribute('max', \floatval($formatOptions['max']));
}
$response
->setStatusCode(SwooleResponse::STATUS_CODE_OK)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_FLOAT);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?float $min, ?float $max, ?float $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $min, $max, $default, $newKey, $response, $dbForProject, $queueForEvents);
});
}
}

View file

@ -2,20 +2,18 @@
namespace Appwrite\Platform\Modules\Databases\Http\Columns;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Get as AttributesGet;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
class Get extends Action
class Get extends AttributesGet
{
use HTTP;
@ -26,35 +24,38 @@ class Get extends Action
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel([
UtopiaResponse::MODEL_COLUMN_BOOLEAN,
UtopiaResponse::MODEL_COLUMN_INTEGER,
UtopiaResponse::MODEL_COLUMN_FLOAT,
UtopiaResponse::MODEL_COLUMN_EMAIL,
UtopiaResponse::MODEL_COLUMN_ENUM,
UtopiaResponse::MODEL_COLUMN_URL,
UtopiaResponse::MODEL_COLUMN_IP,
UtopiaResponse::MODEL_COLUMN_DATETIME,
UtopiaResponse::MODEL_COLUMN_RELATIONSHIP,
UtopiaResponse::MODEL_COLUMN_STRING,
]);
$this
->setHttpMethod(self::HTTP_REQUEST_METHOD_GET)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/:key')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/:key')
->desc('Get column')
->groups(['api', 'database'])
->label('scope', 'collections.read')
->label('resourceType', RESOURCE_TYPE_DATABASES)
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'getColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/get-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_OK,
model: [
UtopiaResponse::MODEL_COLUMN_BOOLEAN,
UtopiaResponse::MODEL_COLUMN_INTEGER,
UtopiaResponse::MODEL_COLUMN_FLOAT,
UtopiaResponse::MODEL_COLUMN_EMAIL,
UtopiaResponse::MODEL_COLUMN_ENUM,
UtopiaResponse::MODEL_COLUMN_URL,
UtopiaResponse::MODEL_COLUMN_IP,
UtopiaResponse::MODEL_COLUMN_DATETIME,
UtopiaResponse::MODEL_COLUMN_RELATIONSHIP,
UtopiaResponse::MODEL_COLUMN_STRING,
]
model: $this->getResponseModel()
)
]
))
@ -63,50 +64,8 @@ class Get extends Action
->param('key', '', new Key(), 'Column Key.')
->inject('response')
->inject('dbForProject')
->callback([$this, 'action']);
}
public function action(string $databaseId, string $tableId, string $key, UtopiaResponse $response, Database $dbForProject): void
{
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
$table = $dbForProject->getDocument('database_' . $database->getInternalId(), $tableId);
if ($table->isEmpty()) {
throw new Exception(Exception::TABLE_NOT_FOUND);
}
$column = $dbForProject->getDocument('attributes', $database->getInternalId() . '_' . $table->getInternalId() . '_' . $key);
if ($column->isEmpty()) {
throw new Exception(Exception::COLUMN_NOT_FOUND);
}
$type = $column->getAttribute('type');
$format = $column->getAttribute('format');
$options = $column->getAttribute('options', []);
foreach ($options as $optKey => $optValue) {
$column->setAttribute($optKey, $optValue);
}
$model = match ($type) {
Database::VAR_BOOLEAN => UtopiaResponse::MODEL_COLUMN_BOOLEAN,
Database::VAR_INTEGER => UtopiaResponse::MODEL_COLUMN_INTEGER,
Database::VAR_FLOAT => UtopiaResponse::MODEL_COLUMN_FLOAT,
Database::VAR_DATETIME => UtopiaResponse::MODEL_COLUMN_DATETIME,
Database::VAR_RELATIONSHIP => UtopiaResponse::MODEL_COLUMN_RELATIONSHIP,
Database::VAR_STRING => match ($format) {
APP_DATABASE_ATTRIBUTE_EMAIL => UtopiaResponse::MODEL_COLUMN_EMAIL,
APP_DATABASE_ATTRIBUTE_ENUM => UtopiaResponse::MODEL_COLUMN_ENUM,
APP_DATABASE_ATTRIBUTE_IP => UtopiaResponse::MODEL_COLUMN_IP,
APP_DATABASE_ATTRIBUTE_URL => UtopiaResponse::MODEL_COLUMN_URL,
default => UtopiaResponse::MODEL_COLUMN_STRING,
},
default => UtopiaResponse::MODEL_COLUMN,
};
$response->dynamic($column, $model);
->callback(function (string $databaseId, string $tableId, string $key, UtopiaResponse $response, Database $dbForProject) {
parent::action($databaseId, $tableId, $key, $response, $dbForProject);
});
}
}

View file

@ -4,22 +4,20 @@ namespace Appwrite\Platform\Modules\Databases\Http\Columns\IP;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\IP\Create as IPCreate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
use Utopia\Validator\IP;
class Create extends ColumnAction
class Create extends IPCreate
{
use HTTP;
@ -30,10 +28,12 @@ class Create extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_IP);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpMethod(self::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/ip')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/ip')
->desc('Create IP address column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -43,14 +43,14 @@ class Create extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'createIpColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/create-ip-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_ACCEPTED,
model: UtopiaResponse::MODEL_COLUMN_IP,
model: $this->getResponseModel(),
)
]
))
@ -64,33 +64,8 @@ class Create extends ColumnAction
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?string $default,
bool $array,
\Appwrite\Utopia\Response $response,
Database $dbForProject,
EventDatabase $queueForDatabase,
Event $queueForEvents
): void {
$column = $this->createColumn($databaseId, $tableId, new Document([
'key' => $key,
'type' => Database::VAR_STRING,
'size' => 39,
'required' => $required,
'default' => $default,
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_IP,
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_IP);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $default, $array, $response, $dbForProject, $queueForDatabase, $queueForEvents);
});
}
}

View file

@ -3,7 +3,7 @@
namespace Appwrite\Platform\Modules\Databases\Http\Columns\IP;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\IP\Update as IPUpdate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@ -12,14 +12,13 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
use Utopia\Validator\IP;
use Utopia\Validator\Nullable;
class Update extends ColumnAction
class Update extends IPUpdate
{
use HTTP;
@ -30,10 +29,12 @@ class Update extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_IP);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/ip/:key')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/ip/:key')
->desc('Update IP address column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -43,14 +44,14 @@ class Update extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'updateIpColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/update-ip-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_OK,
model: UtopiaResponse::MODEL_COLUMN_IP,
model: $this->getResponseModel(),
)
],
contentType: ContentType::JSON
@ -64,35 +65,8 @@ class Update extends ColumnAction
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?string $default,
?string $newKey,
UtopiaResponse $response,
Database $dbForProject,
Event $queueForEvents
): void {
$column = $this->updateColumn(
databaseId: $databaseId,
tableId: $tableId,
key: $key,
dbForProject: $dbForProject,
queueForEvents: $queueForEvents,
type: Database::VAR_STRING,
filter: APP_DATABASE_ATTRIBUTE_IP,
default: $default,
required: $required,
newKey: $newKey
);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_OK)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_IP);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $default, $newKey, $response, $dbForProject, $queueForEvents);
});
}
}

View file

@ -4,24 +4,20 @@ namespace Appwrite\Platform\Modules\Databases\Http\Columns\Integer;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Integer\Create as IntegerCreate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
use Utopia\Validator\Integer;
use Utopia\Validator\Range;
class Create extends ColumnAction
class Create extends IntegerCreate
{
use HTTP;
@ -32,10 +28,12 @@ class Create extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_INTEGER);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpMethod(self::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/integer')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/integer')
->desc('Create integer column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -45,14 +43,14 @@ class Create extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'createIntegerColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/create-integer-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_ACCEPTED,
model: UtopiaResponse::MODEL_COLUMN_INTEGER,
model: $this->getResponseModel(),
)
]
))
@ -68,56 +66,8 @@ class Create extends ColumnAction
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?int $min,
?int $max,
?int $default,
bool $array,
UtopiaResponse $response,
Database $dbForProject,
EventDatabase $queueForDatabase,
Event $queueForEvents
): void {
$min ??= \PHP_INT_MIN;
$max ??= \PHP_INT_MAX;
if ($min > $max) {
throw new Exception(Exception::COLUMN_VALUE_INVALID, 'Minimum value must be lesser than maximum value');
}
$validator = new Range($min, $max, Database::VAR_INTEGER);
if (!\is_null($default) && !$validator->isValid($default)) {
throw new Exception(Exception::COLUMN_VALUE_INVALID, $validator->getDescription());
}
$size = $max > 2147483647 ? 8 : 4;
$column = $this->createColumn($databaseId, $tableId, new Document([
'key' => $key,
'type' => Database::VAR_INTEGER,
'size' => $size,
'required' => $required,
'default' => $default,
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_INT_RANGE,
'formatOptions' => ['min' => $min, 'max' => $max],
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$formatOptions = $column->getAttribute('formatOptions', []);
if (!empty($formatOptions)) {
$column->setAttribute('min', \intval($formatOptions['min']));
$column->setAttribute('max', \intval($formatOptions['max']));
}
$response
->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_INTEGER);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $min, $max, $default, $array, $response, $dbForProject, $queueForDatabase, $queueForEvents);
});
}
}

View file

@ -3,7 +3,7 @@
namespace Appwrite\Platform\Modules\Databases\Http\Columns\Integer;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Integer\Update as IntegerUpdate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@ -12,14 +12,13 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
use Utopia\Validator\Integer;
use Utopia\Validator\Nullable;
class Update extends ColumnAction
class Update extends IntegerUpdate
{
use HTTP;
@ -30,10 +29,12 @@ class Update extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_INTEGER);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/integer/:key')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/integer/:key')
->desc('Update integer column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -43,14 +44,14 @@ class Update extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'updateIntegerColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/update-integer-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_OK,
model: UtopiaResponse::MODEL_COLUMN_INTEGER,
model: $this->getResponseModel(),
)
],
contentType: ContentType::JSON
@ -66,44 +67,8 @@ class Update extends ColumnAction
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?int $min,
?int $max,
?int $default,
?string $newKey,
UtopiaResponse $response,
Database $dbForProject,
Event $queueForEvents
): void {
$column = $this->updateColumn(
databaseId: $databaseId,
tableId: $tableId,
key: $key,
dbForProject: $dbForProject,
queueForEvents: $queueForEvents,
type: Database::VAR_INTEGER,
default: $default,
required: $required,
min: $min,
max: $max,
newKey: $newKey
);
$formatOptions = $column->getAttribute('formatOptions', []);
if (!empty($formatOptions)) {
$column->setAttribute('min', \intval($formatOptions['min']));
$column->setAttribute('max', \intval($formatOptions['max']));
}
$response
->setStatusCode(SwooleResponse::STATUS_CODE_OK)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_INTEGER);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?int $min, ?int $max, ?int $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $min, $max, $default, $newKey, $response, $dbForProject, $queueForEvents);
});
}
}

View file

@ -4,24 +4,20 @@ namespace Appwrite\Platform\Modules\Databases\Http\Columns\Relationship;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Relationship\Create as RelationshipCreate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
use Utopia\Validator\WhiteList;
class Create extends ColumnAction
class Create extends RelationshipCreate
{
use HTTP;
@ -32,10 +28,12 @@ class Create extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_RELATIONSHIP);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpMethod(self::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/relationship')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/relationship')
->desc('Create relationship column')
->groups(['api', 'database'])
->label('scope', 'collections.write')
@ -45,14 +43,14 @@ class Create extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'createRelationshipColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/create-relationship-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_ACCEPTED,
model: UtopiaResponse::MODEL_COLUMN_RELATIONSHIP
model: $this->getResponseModel()
)
]
))
@ -77,92 +75,8 @@ class Create extends ColumnAction
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $relatedTableId,
string $type,
bool $twoWay,
?string $key,
?string $twoWayKey,
string $onDelete,
UtopiaResponse $response,
Database $dbForProject,
EventDatabase $queueForDatabase,
Event $queueForEvents
): void {
$key ??= $relatedTableId;
$twoWayKey ??= $tableId;
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
$table = $dbForProject->getDocument('database_' . $database->getInternalId(), $tableId);
$table = $dbForProject->getCollection('database_' . $database->getInternalId() . '_collection_' . $table->getInternalId());
if ($table->isEmpty()) {
throw new Exception(Exception::TABLE_NOT_FOUND);
}
$relatedTableDocument = $dbForProject->getDocument('database_' . $database->getInternalId(), $relatedTableId);
$relatedTable = $dbForProject->getCollection('database_' . $database->getInternalId() . '_collection_' . $relatedTableDocument->getInternalId());
if ($relatedTable->isEmpty()) {
throw new Exception(Exception::TABLE_NOT_FOUND);
}
$columns = $table->getAttribute('attributes', []);
foreach ($columns as $column) {
if ($column->getAttribute('type') !== Database::VAR_RELATIONSHIP) {
continue;
}
if (\strtolower($column->getId()) === \strtolower($key)) {
throw new Exception(Exception::COLUMN_ALREADY_EXISTS);
}
if (
\strtolower($column->getAttribute('options')['twoWayKey']) === \strtolower($twoWayKey) &&
$column->getAttribute('options')['relatedCollection'] === $relatedTable->getId()
) {
throw new Exception(Exception::COLUMN_ALREADY_EXISTS, 'Attribute with the requested key already exists. Attribute keys must be unique, try again with a different key.');
}
if (
$type === Database::RELATION_MANY_TO_MANY &&
$column->getAttribute('options')['relationType'] === Database::RELATION_MANY_TO_MANY &&
$column->getAttribute('options')['relatedCollection'] === $relatedTable->getId()
) {
throw new Exception(Exception::COLUMN_ALREADY_EXISTS, 'Creating more than one "manyToMany" relationship on the same table is currently not permitted.');
}
}
$column = $this->createColumn($databaseId, $tableId, new Document([
'key' => $key,
'type' => Database::VAR_RELATIONSHIP,
'size' => 0,
'required' => false,
'default' => null,
'array' => false,
'filters' => [],
'options' => [
'relatedCollection' => $relatedTableId,
'relationType' => $type,
'twoWay' => $twoWay,
'twoWayKey' => $twoWayKey,
'onDelete' => $onDelete,
]
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
foreach ($column->getAttribute('options', []) as $k => $option) {
$column->setAttribute($k, $option);
}
$response
->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_RELATIONSHIP);
->callback(function (string $databaseId, string $tableId, string $relatedTableId, string $type, bool $twoWay, ?string $key, ?string $twoWayKey, string $onDelete, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
parent::action($databaseId, $tableId, $relatedTableId, $type, $twoWayKey, $key, $twoWayKey, $onDelete, $response, $dbForProject, $queueForDatabase, $queueForEvents);
});
}
}

View file

@ -3,7 +3,7 @@
namespace Appwrite\Platform\Modules\Databases\Http\Columns\Relationship;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\Relationship\Update as RelationshipUpdate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@ -12,12 +12,11 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\WhiteList;
class Update extends ColumnAction
class Update extends RelationshipUpdate
{
use HTTP;
@ -28,8 +27,11 @@ class Update extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_RELATIONSHIP);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/:key/relationship')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/:key/relationship')
->desc('Update relationship column')
@ -41,14 +43,14 @@ class Update extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'updateRelationshipColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/update-relationship-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_OK,
model: UtopiaResponse::MODEL_COLUMN_RELATIONSHIP
model: $this->getResponseModel()
)
],
contentType: ContentType::JSON
@ -65,39 +67,8 @@ class Update extends ColumnAction
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?string $onDelete,
?string $newKey,
UtopiaResponse $response,
Database $dbForProject,
Event $queueForEvents
): void {
$column = $this->updateColumn(
$databaseId,
$tableId,
$key,
$dbForProject,
$queueForEvents,
type: Database::VAR_RELATIONSHIP,
required: false,
options: [
'onDelete' => $onDelete
],
newKey: $newKey
);
foreach ($column->getAttribute('options', []) as $k => $option) {
$column->setAttribute($k, $option);
}
$response
->setStatusCode(SwooleResponse::STATUS_CODE_OK)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_RELATIONSHIP);
->callback(function (string $databaseId, string $tableId, string $key, ?string $onDelete, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $onDelete, $newKey, $response, $dbForProject, $queueForEvents);
});
}
}

View file

@ -4,17 +4,14 @@ namespace Appwrite\Platform\Modules\Databases\Http\Columns\String;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\String\Create as StringCreate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator;
@ -22,7 +19,7 @@ use Utopia\Validator\Boolean;
use Utopia\Validator\Range;
use Utopia\Validator\Text;
class Create extends ColumnAction
class Create extends StringCreate
{
use HTTP;
@ -33,10 +30,12 @@ class Create extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_STRING);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpMethod(self::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/string')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/string')
->desc('Create string column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -46,14 +45,14 @@ class Create extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'createStringColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/create-string-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_ACCEPTED,
model: UtopiaResponse::MODEL_COLUMN_STRING
model: $this->getResponseModel()
)
]
))
@ -69,54 +68,8 @@ class Create extends ColumnAction
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?int $size,
?bool $required,
?string $default,
bool $array,
bool $encrypt,
UtopiaResponse $response,
Database $dbForProject,
EventDatabase $queueForDatabase,
Event $queueForEvents
): void {
// Ensure default fits in the given size
$validator = new Text($size, 0);
if (!is_null($default) && !$validator->isValid($default)) {
throw new Exception(Exception::COLUMN_VALUE_INVALID, $validator->getDescription());
}
$filters = [];
if ($encrypt) {
$filters[] = 'encrypt';
}
$column = $this->createColumn(
$databaseId,
$tableId,
new Document([
'key' => $key,
'type' => Database::VAR_STRING,
'size' => $size,
'required' => $required,
'default' => $default,
'array' => $array,
'filters' => $filters,
]),
$response,
$dbForProject,
$queueForDatabase,
$queueForEvents
);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_STRING);
->callback(function (string $databaseId, string $tableId, string $key, ?int $size, ?bool $required, ?string $default, bool $array, bool $encrypt, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $size, $required, $default, $array, $encrypt, $response, $dbForProject, $queueForDatabase, $queueForEvents);
});
}
}

View file

@ -3,7 +3,7 @@
namespace Appwrite\Platform\Modules\Databases\Http\Columns\String;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\String\Update as StringUpdate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@ -12,7 +12,6 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator;
@ -21,7 +20,7 @@ use Utopia\Validator\Nullable;
use Utopia\Validator\Range;
use Utopia\Validator\Text;
class Update extends ColumnAction
class Update extends StringUpdate
{
use HTTP;
@ -32,9 +31,12 @@ class Update extends ColumnAction
public function __construct()
{
$this->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_STRING);
$this
->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/string/:key')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/string/:key')
->desc('Update string column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -44,14 +46,14 @@ class Update extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'updateStringColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/update-string-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_OK,
model: UtopiaResponse::MODEL_COLUMN_STRING,
model: $this->getResponseModel(),
)
],
contentType: ContentType::JSON
@ -66,36 +68,8 @@ class Update extends ColumnAction
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?string $default,
?int $size,
?string $newKey,
UtopiaResponse $response,
Database $dbForProject,
Event $queueForEvents
): void {
$column = $this->updateColumn(
databaseId: $databaseId,
tableId: $tableId,
key: $key,
dbForProject: $dbForProject,
queueForEvents: $queueForEvents,
type: Database::VAR_STRING,
size: $size,
default: $default,
required: $required,
newKey: $newKey
);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_OK)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_STRING);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?string $default, ?int $size, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $default, $size, $newKey, $response, $dbForProject, $queueForEvents);
});
}
}

View file

@ -4,22 +4,20 @@ namespace Appwrite\Platform\Modules\Databases\Http\Columns\URL;
use Appwrite\Event\Database as EventDatabase;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\URL\Create as URLCreate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
use Utopia\Validator\URL;
class Create extends ColumnAction
class Create extends URLCreate
{
use HTTP;
@ -30,10 +28,12 @@ class Create extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_URL);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
->setHttpMethod(self::HTTP_REQUEST_METHOD_POST)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/url')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/url')
->desc('Create URL column')
->groups(['api', 'database', 'schema'])
->label('scope', 'collections.write')
@ -43,14 +43,14 @@ class Create extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'createUrlColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/create-url-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_ACCEPTED,
model: UtopiaResponse::MODEL_COLUMN_URL,
model: $this->getResponseModel(),
)
]
))
@ -64,33 +64,8 @@ class Create extends ColumnAction
->inject('dbForProject')
->inject('queueForDatabase')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?string $default,
bool $array,
UtopiaResponse $response,
Database $dbForProject,
EventDatabase $queueForDatabase,
Event $queueForEvents
): void {
$column = $this->createColumn($databaseId, $tableId, new Document([
'key' => $key,
'type' => Database::VAR_STRING,
'size' => 2000,
'required' => $required,
'default' => $default,
'array' => $array,
'format' => APP_DATABASE_ATTRIBUTE_URL,
]), $response, $dbForProject, $queueForDatabase, $queueForEvents);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_ACCEPTED)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_URL);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?string $default, bool $array, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $default, $array, $response, $dbForProject, $queueForDatabase, $queueForEvents);
});
}
}

View file

@ -3,7 +3,7 @@
namespace Appwrite\Platform\Modules\Databases\Http\Columns\URL;
use Appwrite\Event\Event;
use Appwrite\Platform\Modules\Databases\Http\Columns\Action as ColumnAction;
use Appwrite\Platform\Modules\Databases\Http\Attributes\URL\Update as URLUpdate;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\ContentType;
use Appwrite\SDK\Method;
@ -12,14 +12,13 @@ use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Validator\Key;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
use Utopia\Validator\Boolean;
use Utopia\Validator\Nullable;
use Utopia\Validator\URL;
class Update extends ColumnAction
class Update extends URLUpdate
{
use HTTP;
@ -30,8 +29,11 @@ class Update extends ColumnAction
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_URL);
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpMethod(self::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns/url/:key')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes/url/:key')
->desc('Update URL column')
@ -43,14 +45,14 @@ class Update extends ColumnAction
->label('audits.resource', 'database/{request.databaseId}/table/{request.tableId}')
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'updateUrlColumn',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/update-url-attribute.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_OK,
model: UtopiaResponse::MODEL_COLUMN_URL,
model: $this->getResponseModel(),
)
],
contentType: ContentType::JSON
@ -64,35 +66,8 @@ class Update extends ColumnAction
->inject('response')
->inject('dbForProject')
->inject('queueForEvents')
->callback([$this, 'action']);
}
public function action(
string $databaseId,
string $tableId,
string $key,
?bool $required,
?string $default,
?string $newKey,
UtopiaResponse $response,
Database $dbForProject,
Event $queueForEvents
): void {
$column = $this->updateColumn(
$databaseId,
$tableId,
$key,
$dbForProject,
$queueForEvents,
type: Database::VAR_STRING,
filter: APP_DATABASE_ATTRIBUTE_URL,
default: $default,
required: $required,
newKey: $newKey
);
$response
->setStatusCode(SwooleResponse::STATUS_CODE_OK)
->dynamic($column, UtopiaResponse::MODEL_COLUMN_URL);
->callback(function (string $databaseId, string $tableId, string $key, ?bool $required, ?string $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents) {
parent::action($databaseId, $tableId, $key, $required, $default, $newKey, $response, $dbForProject, $queueForEvents);
});
}
}

View file

@ -2,24 +2,18 @@
namespace Appwrite\Platform\Modules\Databases\Http\Columns;
use Appwrite\Extend\Exception;
use Appwrite\Platform\Modules\Databases\Http\Attributes\XList as AttributesXList;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Database\Validator\Queries\Columns;
use Appwrite\Utopia\Response as UtopiaResponse;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Exception\Order as OrderException;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\Query\Cursor;
use Utopia\Database\Validator\UID;
use Utopia\Platform\Action;
use Utopia\Platform\Scope\HTTP;
use Utopia\Swoole\Response as SwooleResponse;
class XList extends Action
class XList extends AttributesXList
{
use HTTP;
@ -30,24 +24,26 @@ class XList extends Action
public function __construct()
{
$this->setContext(DATABASE_COLUMNS_CONTEXT);
$this->setResponseModel(UtopiaResponse::MODEL_COLUMN_LIST);
$this
->setHttpMethod(self::HTTP_REQUEST_METHOD_GET)
->setHttpPath('/v1/databases/:databaseId/tables/:tableId/columns')
->httpAlias('/v1/databases/:databaseId/collections/:tableId/attributes')
->desc('List columns')
->groups(['api', 'database'])
->label('scope', 'collections.read')
->label('resourceType', RESOURCE_TYPE_DATABASES)
->label('sdk', new Method(
namespace: 'databases',
group: 'columns',
name: 'listColumns',
group: $this->getSdkGroup(),
name: self::getName(),
description: '/docs/references/databases/list-attributes.md',
auth: [AuthType::KEY],
responses: [
new SDKResponse(
code: SwooleResponse::STATUS_CODE_OK,
model: UtopiaResponse::MODEL_COLUMN_LIST
model: $this->getResponseModel()
)
]
))
@ -56,70 +52,8 @@ class XList extends Action
->param('queries', [], new Columns(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' queries are allowed, each ' . APP_LIMIT_ARRAY_ELEMENT_SIZE . ' characters long. You may filter on the following attributes: ' . implode(', ', Columns::ALLOWED_ATTRIBUTES), true)
->inject('response')
->inject('dbForProject')
->callback([$this, 'action']);
}
public function action(string $databaseId, string $tableId, array $queries, UtopiaResponse $response, Database $dbForProject): void
{
$database = Authorization::skip(fn () => $dbForProject->getDocument('databases', $databaseId));
if ($database->isEmpty()) {
throw new Exception(Exception::DATABASE_NOT_FOUND);
}
$table = $dbForProject->getDocument('database_' . $database->getInternalId(), $tableId);
if ($table->isEmpty()) {
throw new Exception(Exception::TABLE_NOT_FOUND);
}
$queries = Query::parseQueries($queries);
\array_push(
$queries,
Query::equal('databaseInternalId', [$database->getInternalId()]),
Query::equal('collectionInternalId', [$table->getInternalId()])
);
$cursor = \array_filter(
$queries,
fn ($query) => \in_array($query->getMethod(), [Query::TYPE_CURSOR_AFTER, Query::TYPE_CURSOR_BEFORE])
);
$cursor = \reset($cursor);
if ($cursor) {
$validator = new Cursor();
if (!$validator->isValid($cursor)) {
throw new Exception(Exception::GENERAL_QUERY_INVALID, $validator->getDescription());
}
$columnId = $cursor->getValue();
$cursorDocument = Authorization::skip(
fn () => $dbForProject->find('attributes', [
Query::equal('databaseInternalId', [$database->getInternalId()]),
Query::equal('collectionInternalId', [$table->getInternalId()]),
Query::equal('key', [$columnId]),
Query::limit(1),
])
);
if (empty($cursorDocument) || $cursorDocument[0]->isEmpty()) {
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Column '{$columnId}' for the 'cursor' value not found.");
}
$cursor->setValue($cursorDocument[0]);
}
$filters = Query::groupByType($queries)['filters'];
try {
$columns = $dbForProject->find('attributes', $queries);
$total = $dbForProject->count('attributes', $filters, APP_LIMIT_COUNT);
} catch (OrderException $e) {
throw new Exception(Exception::DATABASE_QUERY_ORDER_NULL, "The order column '{$e->getAttribute()}' had a null value. Cursor pagination requires all rows order column values are non-null.");
}
$response->dynamic(new Document([
'columns' => $columns,
'total' => $total,
]), UtopiaResponse::MODEL_COLUMN_LIST);
->callback(function (string $databaseId, string $tableId, array $queries, UtopiaResponse $response, Database $dbForProject) {
parent::action($databaseId, $tableId, $queries, $response, $dbForProject);
});
}
}