mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Compare commits
94
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1f9172739e | ||
|
|
efa30731e9 | ||
|
|
8032da148a | ||
|
|
1b77a78121 | ||
|
|
1b665fdb6f | ||
|
|
f66150aa8b | ||
|
|
48a01919bc | ||
|
|
4d85ab0dcd | ||
|
|
61a623fcc0 | ||
|
|
95552031ef | ||
|
|
5740cecbe5 | ||
|
|
080361338c | ||
|
|
3f7261167b | ||
|
|
5a0553a22f | ||
|
|
d7b61e6afc | ||
|
|
99394e6dfa | ||
|
|
dc77abf161 | ||
|
|
088f1c2953 | ||
|
|
2d093becc1 | ||
|
|
311ca9377b | ||
|
|
f69feec7ae | ||
|
|
09e8380328 | ||
|
|
1eb9c386f6 | ||
|
|
33b971a2c1 | ||
|
|
796179decd | ||
|
|
21e6715bd1 | ||
|
|
b3ed5032cf | ||
|
|
f4cb632dbc | ||
|
|
7dca267727 | ||
|
|
1c19cf5323 | ||
|
|
234fd8da2f | ||
|
|
124002f419 | ||
|
|
b05489bbc8 | ||
|
|
dca59528df | ||
|
|
f8b3e687a0 | ||
|
|
ca99508c55 | ||
|
|
cf71c104e8 | ||
|
|
a097f5a987 | ||
|
|
4cb70799ab | ||
|
|
e214a154b3 | ||
|
|
5f4b91c350 | ||
|
|
7520234e4a | ||
|
|
e8f4137249 | ||
|
|
1b1b1dfc2b | ||
|
|
7fc153d344 | ||
|
|
44d7591dd1 | ||
|
|
1f20a18587 | ||
|
|
2cf04e4b0f | ||
|
|
3a2e61224d | ||
|
|
348750b6d1 | ||
|
|
ead8e37699 | ||
|
|
a9fd6c6282 | ||
|
|
7de44f16b1 | ||
|
|
6c5f028d24 | ||
|
|
3ce82ab29f | ||
|
|
26f70357c8 | ||
|
|
0321ec5192 | ||
|
|
5156aae427 | ||
|
|
4b3de66e19 | ||
|
|
fd3df71660 | ||
|
|
1f5ac9e323 | ||
|
|
bc1c1718b8 | ||
|
|
79afbdddf7 | ||
|
|
29390a6b34 | ||
|
|
1e3b7c8d63 | ||
|
|
0755bf8e2c | ||
|
|
8280bdaf9e | ||
|
|
6ec07af3db | ||
|
|
8bab4b162f | ||
|
|
9d4475526a | ||
|
|
0ff9426d08 | ||
|
|
6869bef2ea | ||
|
|
1f4a66a5e9 | ||
|
|
6e797a60f5 | ||
|
|
135c337d08 | ||
|
|
dbe79bca27 | ||
|
|
8f4f739690 | ||
|
|
4a77a1ea57 | ||
|
|
a2a3e8fe27 | ||
|
|
84d16aaa73 | ||
|
|
efa7ccc8fc | ||
|
|
3e2504e75a | ||
|
|
91727a4d11 | ||
|
|
03e8e79424 | ||
|
|
9d199ec0e5 | ||
|
|
9cb517081a | ||
|
|
0aff210cab | ||
|
|
5101db4172 | ||
|
|
85467e3d7e | ||
|
|
a3b83a5d29 | ||
|
|
c791012bf7 | ||
|
|
1230f8201f | ||
|
|
82c9c5322e | ||
|
|
e4dc9bcd86 |
@@ -23,6 +23,7 @@ use Utopia\Console;
|
||||
use Utopia\Database\Adapter\Pool as DatabasePool;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Hook\Permissions;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\DI\Dependency;
|
||||
use Utopia\DSN\DSN;
|
||||
@@ -132,6 +133,8 @@ $setResource('dbForPlatform', function ($pools, $cache, $authorization) {
|
||||
throw new Exception('Console is not ready yet. Please try again later.');
|
||||
}
|
||||
|
||||
$dbForPlatform->addHook(new Permissions());
|
||||
|
||||
return $dbForPlatform;
|
||||
}, ['pools', 'cache', 'authorization']);
|
||||
|
||||
@@ -203,6 +206,8 @@ $setResource('getProjectDB', function (Group $pools, Database $dbForPlatform, $c
|
||||
->setMetadata('host', \gethostname())
|
||||
->setMetadata('project', $project->getId());
|
||||
|
||||
$database->addHook(new Permissions());
|
||||
|
||||
return $database;
|
||||
};
|
||||
}, ['pools', 'dbForPlatform', 'cache', 'authorization']);
|
||||
@@ -227,6 +232,8 @@ $setResource('getLogsDB', function (Group $pools, Cache $cache, Authorization $a
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_TASK)
|
||||
->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES);
|
||||
|
||||
$database->addHook(new Permissions());
|
||||
|
||||
// set tenant
|
||||
if ($project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
|
||||
$database->setTenant($project->getSequence());
|
||||
|
||||
+1536
-2627
File diff suppressed because it is too large
Load Diff
@@ -1,126 +1,88 @@
|
||||
<?php
|
||||
|
||||
use Utopia\Database\Attribute;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Index;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Query\Schema\IndexType;
|
||||
|
||||
return [
|
||||
'collections' => [
|
||||
'$collection' => ID::custom('databases'),
|
||||
'$id' => ID::custom('collections'),
|
||||
'$collection' => 'databases',
|
||||
'$id' => 'collections',
|
||||
'name' => 'Collections',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => ID::custom('databaseInternalId'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('databaseId'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'signed' => true,
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'format' => '',
|
||||
'filters' => [],
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('name'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
'signed' => true,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('enabled'),
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'signed' => true,
|
||||
'size' => 0,
|
||||
'format' => '',
|
||||
'filters' => [],
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('documentSecurity'),
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'signed' => true,
|
||||
'size' => 0,
|
||||
'format' => '',
|
||||
'filters' => [],
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('attributes'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 1000000,
|
||||
'required' => false,
|
||||
'signed' => true,
|
||||
'array' => false,
|
||||
'filters' => ['subQueryAttributes'],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('indexes'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 1000000,
|
||||
'required' => false,
|
||||
'signed' => true,
|
||||
'array' => false,
|
||||
'filters' => ['subQueryIndexes'],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('search'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
new Attribute(
|
||||
key: 'databaseInternalId',
|
||||
type: ColumnType::String,
|
||||
size: Database::LENGTH_KEY,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'databaseId',
|
||||
type: ColumnType::String,
|
||||
size: Database::LENGTH_KEY,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'name',
|
||||
type: ColumnType::String,
|
||||
size: 256,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'enabled',
|
||||
type: ColumnType::Boolean,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'documentSecurity',
|
||||
type: ColumnType::Boolean,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'attributes',
|
||||
type: ColumnType::String,
|
||||
size: 1000000,
|
||||
filters: ['subQueryAttributes'],
|
||||
),
|
||||
new Attribute(
|
||||
key: 'indexes',
|
||||
type: ColumnType::String,
|
||||
size: 1000000,
|
||||
filters: ['subQueryIndexes'],
|
||||
),
|
||||
new Attribute(
|
||||
key: 'search',
|
||||
type: ColumnType::String,
|
||||
size: 16384,
|
||||
),
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => ID::custom('_fulltext_search'),
|
||||
'type' => Database::INDEX_FULLTEXT,
|
||||
'attributes' => ['search'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_name'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['name'],
|
||||
'lengths' => [256],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_enabled'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['enabled'],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_documentSecurity'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['documentSecurity'],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
new Index(
|
||||
key: '_fulltext_search',
|
||||
type: IndexType::Fulltext,
|
||||
attributes: ['search'],
|
||||
),
|
||||
new Index(
|
||||
key: '_key_name',
|
||||
type: IndexType::Key,
|
||||
attributes: ['name'],
|
||||
lengths: [256],
|
||||
orders: ['ASC'],
|
||||
),
|
||||
new Index(
|
||||
key: '_key_enabled',
|
||||
type: IndexType::Key,
|
||||
attributes: ['enabled'],
|
||||
orders: ['ASC'],
|
||||
),
|
||||
new Index(
|
||||
key: '_key_documentSecurity',
|
||||
type: IndexType::Key,
|
||||
attributes: ['documentSecurity'],
|
||||
orders: ['ASC'],
|
||||
),
|
||||
],
|
||||
]
|
||||
],
|
||||
];
|
||||
|
||||
@@ -1,94 +1,67 @@
|
||||
<?php
|
||||
|
||||
use Utopia\Database\Attribute;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Index;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Query\Schema\IndexType;
|
||||
|
||||
$logsCollection = [];
|
||||
|
||||
$logsCollection['stats'] = [
|
||||
'$collection' => ID::custom(Database::METADATA),
|
||||
'$id' => ID::custom('stats'),
|
||||
'name' => 'stats',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => ID::custom('metric'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 255,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
return [
|
||||
'stats' => [
|
||||
'$collection' => '_metadata',
|
||||
'$id' => 'stats',
|
||||
'name' => 'stats',
|
||||
'attributes' => [
|
||||
new Attribute(
|
||||
key: 'metric',
|
||||
type: ColumnType::String,
|
||||
size: Database::LENGTH_KEY,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'region',
|
||||
type: ColumnType::String,
|
||||
size: Database::LENGTH_KEY,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'value',
|
||||
type: ColumnType::Integer,
|
||||
size: 8,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'time',
|
||||
type: ColumnType::Datetime,
|
||||
signed: false,
|
||||
filters: ['datetime'],
|
||||
),
|
||||
new Attribute(
|
||||
key: 'period',
|
||||
type: ColumnType::String,
|
||||
size: 4,
|
||||
required: true,
|
||||
),
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('region'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 255,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('value'),
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'format' => '',
|
||||
'size' => 8,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('time'),
|
||||
'type' => Database::VAR_DATETIME,
|
||||
'format' => '',
|
||||
'size' => 0,
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => ['datetime'],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('period'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 4,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => ID::custom('_key_time'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['time'],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_DESC],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_period_time'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['period', 'time'],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_metric_period_time'),
|
||||
'type' => Database::INDEX_UNIQUE,
|
||||
'attributes' => ['metric', 'period', 'time'],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_DESC],
|
||||
'indexes' => [
|
||||
new Index(
|
||||
key: '_key_time',
|
||||
type: IndexType::Key,
|
||||
attributes: ['time'],
|
||||
orders: ['DESC'],
|
||||
),
|
||||
new Index(
|
||||
key: '_key_period_time',
|
||||
type: IndexType::Key,
|
||||
attributes: ['period', 'time'],
|
||||
orders: ['ASC'],
|
||||
),
|
||||
new Index(
|
||||
key: '_key_metric_period_time',
|
||||
type: IndexType::Unique,
|
||||
attributes: ['metric', 'period', 'time'],
|
||||
orders: ['DESC'],
|
||||
),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return $logsCollection;
|
||||
|
||||
+1136
-1875
File diff suppressed because it is too large
Load Diff
+1537
-2666
File diff suppressed because it is too large
Load Diff
@@ -1,165 +1,115 @@
|
||||
<?php
|
||||
|
||||
use Utopia\Database\Attribute;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Index;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Query\Schema\IndexType;
|
||||
|
||||
return [
|
||||
'collections' => [
|
||||
'$collection' => ID::custom('databases'),
|
||||
'$id' => ID::custom('collections'),
|
||||
'$collection' => 'databases',
|
||||
'$id' => 'collections',
|
||||
'name' => 'Collections',
|
||||
'attributes' => [
|
||||
[
|
||||
'$id' => ID::custom('databaseInternalId'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'signed' => true,
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('databaseId'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'signed' => true,
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'format' => '',
|
||||
'filters' => [],
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('name'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 256,
|
||||
'required' => true,
|
||||
'signed' => true,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('dimension'),
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'size' => 0,
|
||||
'required' => true,
|
||||
'signed' => false,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('enabled'),
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'signed' => true,
|
||||
'size' => 0,
|
||||
'format' => '',
|
||||
'filters' => [],
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('documentSecurity'),
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'signed' => true,
|
||||
'size' => 0,
|
||||
'format' => '',
|
||||
'filters' => [],
|
||||
'required' => true,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('attributes'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 1000000,
|
||||
'required' => false,
|
||||
'signed' => true,
|
||||
'array' => false,
|
||||
'filters' => ['subQueryAttributes'],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('indexes'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'size' => 1000000,
|
||||
'required' => false,
|
||||
'signed' => true,
|
||||
'array' => false,
|
||||
'filters' => ['subQueryIndexes'],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('search'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 16384,
|
||||
'signed' => true,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
new Attribute(
|
||||
key: 'databaseInternalId',
|
||||
type: ColumnType::String,
|
||||
size: Database::LENGTH_KEY,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'databaseId',
|
||||
type: ColumnType::String,
|
||||
size: Database::LENGTH_KEY,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'name',
|
||||
type: ColumnType::String,
|
||||
size: 256,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'dimension',
|
||||
type: ColumnType::Integer,
|
||||
required: true,
|
||||
signed: false,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'enabled',
|
||||
type: ColumnType::Boolean,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'documentSecurity',
|
||||
type: ColumnType::Boolean,
|
||||
required: true,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'attributes',
|
||||
type: ColumnType::String,
|
||||
size: 1000000,
|
||||
filters: ['subQueryAttributes'],
|
||||
),
|
||||
new Attribute(
|
||||
key: 'indexes',
|
||||
type: ColumnType::String,
|
||||
size: 1000000,
|
||||
filters: ['subQueryIndexes'],
|
||||
),
|
||||
new Attribute(
|
||||
key: 'search',
|
||||
type: ColumnType::String,
|
||||
size: 16384,
|
||||
),
|
||||
],
|
||||
'defaultAttributes' => [
|
||||
[
|
||||
'$id' => ID::custom('embeddings'),
|
||||
'type' => Database::VAR_VECTOR,
|
||||
'required' => true,
|
||||
'signed' => false,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('metadata'),
|
||||
'type' => Database::VAR_OBJECT,
|
||||
'default' => [],
|
||||
'required' => false,
|
||||
'size' => 0,
|
||||
'signed' => false,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
],
|
||||
new Attribute(
|
||||
key: 'embeddings',
|
||||
type: ColumnType::Vector,
|
||||
required: true,
|
||||
signed: false,
|
||||
),
|
||||
new Attribute(
|
||||
key: 'metadata',
|
||||
type: ColumnType::Object,
|
||||
default: [],
|
||||
signed: false,
|
||||
),
|
||||
],
|
||||
'indexes' => [
|
||||
[
|
||||
'$id' => ID::custom('_fulltext_search'),
|
||||
'type' => Database::INDEX_FULLTEXT,
|
||||
'attributes' => ['search'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_name'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['name'],
|
||||
'lengths' => [256],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_enabled'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['enabled'],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
[
|
||||
'$id' => ID::custom('_key_documentSecurity'),
|
||||
'type' => Database::INDEX_KEY,
|
||||
'attributes' => ['documentSecurity'],
|
||||
'lengths' => [],
|
||||
'orders' => [Database::ORDER_ASC],
|
||||
],
|
||||
new Index(
|
||||
key: '_fulltext_search',
|
||||
type: IndexType::Fulltext,
|
||||
attributes: ['search'],
|
||||
),
|
||||
new Index(
|
||||
key: '_key_name',
|
||||
type: IndexType::Key,
|
||||
attributes: ['name'],
|
||||
lengths: [256],
|
||||
orders: ['ASC'],
|
||||
),
|
||||
new Index(
|
||||
key: '_key_enabled',
|
||||
type: IndexType::Key,
|
||||
attributes: ['enabled'],
|
||||
orders: ['ASC'],
|
||||
),
|
||||
new Index(
|
||||
key: '_key_documentSecurity',
|
||||
type: IndexType::Key,
|
||||
attributes: ['documentSecurity'],
|
||||
orders: ['ASC'],
|
||||
),
|
||||
],
|
||||
'defaultIndexes' => [
|
||||
// not creating default indexes on the embeddings as it depends on the type of query users using the most
|
||||
[
|
||||
'$id' => ID::custom('_key_metadata'),
|
||||
'type' => Database::INDEX_OBJECT,
|
||||
'attributes' => ['metadata'],
|
||||
'lengths' => [],
|
||||
'orders' => [],
|
||||
],
|
||||
]
|
||||
]
|
||||
new Index(
|
||||
key: '_key_metadata',
|
||||
type: IndexType::Object,
|
||||
attributes: ['metadata'],
|
||||
),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
@@ -52,6 +52,7 @@ use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\SetType;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
@@ -514,7 +515,7 @@ Http::post('/v1/account')
|
||||
Query::equal('identifier', [$email]),
|
||||
]);
|
||||
if (!$existingTarget->isEmpty()) {
|
||||
$user->setAttribute('targets', $existingTarget, Document::SET_TYPE_APPEND);
|
||||
$user->setAttribute('targets', $existingTarget, SetType::Append);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2520,7 +2521,7 @@ Http::post('/v1/account/tokens/email')
|
||||
Query::equal('identifier', [$email]),
|
||||
]);
|
||||
if (!$existingTarget->isEmpty()) {
|
||||
$user->setAttribute('targets', $existingTarget, Document::SET_TYPE_APPEND);
|
||||
$user->setAttribute('targets', $existingTarget, SetType::Append);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3116,8 +3117,8 @@ Http::get('/v1/account/logs')
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
$limit = $grouped->limit ?? 25;
|
||||
$offset = $grouped->offset ?? 0;
|
||||
$logs = $audit->getLogsByUser($user->getSequence(), offset: $offset, limit: $limit);
|
||||
|
||||
$output = [];
|
||||
@@ -4660,7 +4661,7 @@ Http::get('/v1/account/identities')
|
||||
$cursor->setValue($cursorDocument);
|
||||
}
|
||||
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
$filterQueries = Query::groupByType($queries)->filters;
|
||||
try {
|
||||
$results = $dbForProject->find('identities', $queries);
|
||||
} catch (OrderException $e) {
|
||||
|
||||
@@ -1157,8 +1157,8 @@ Http::get('/v1/messaging/providers/:providerId/logs')
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
$limit = $grouped->limit ?? 25;
|
||||
$offset = $grouped->offset ?? 0;
|
||||
|
||||
$resource = 'provider/' . $providerId;
|
||||
$logs = $audit->getLogsByResource($resource, offset: $offset, limit: $limit);
|
||||
@@ -2561,8 +2561,8 @@ Http::get('/v1/messaging/topics/:topicId/logs')
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
$limit = $grouped->limit ?? 25;
|
||||
$offset = $grouped->offset ?? 0;
|
||||
|
||||
$resource = 'topic/' . $topicId;
|
||||
$logs = $audit->getLogsByResource($resource, offset: $offset, limit: $limit);
|
||||
@@ -2976,8 +2976,8 @@ Http::get('/v1/messaging/subscribers/:subscriberId/logs')
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
$limit = $grouped->limit ?? 25;
|
||||
$offset = $grouped->offset ?? 0;
|
||||
|
||||
$resource = 'subscriber/' . $subscriberId;
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
@@ -3789,8 +3789,8 @@ Http::get('/v1/messaging/messages/:messageId/logs')
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
$limit = $grouped->limit ?? 25;
|
||||
$offset = $grouped->offset ?? 0;
|
||||
|
||||
$resource = 'message/' . $messageId;
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
|
||||
@@ -978,7 +978,7 @@ Http::get('/v1/migrations')
|
||||
$cursor->setValue($cursorDocument);
|
||||
}
|
||||
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
$filterQueries = Query::groupByType($queries)->filters;
|
||||
try {
|
||||
$migrations = $dbForProject->find('migrations', $queries);
|
||||
$total = $includeTotal ? $dbForProject->count('migrations', $filterQueries, APP_LIMIT_COUNT) : 0;
|
||||
|
||||
@@ -31,6 +31,7 @@ use Utopia\Database\Validator\UID;
|
||||
use Utopia\Emails\Validator\Email;
|
||||
use Utopia\Http\Http;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Query\Method as QueryMethod;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
@@ -872,7 +873,7 @@ Http::get('/v1/projects/:projectId/keys')
|
||||
}
|
||||
|
||||
// Backwards compatibility
|
||||
if (\count(Query::getByType($queries, [Query::TYPE_LIMIT])) === 0) {
|
||||
if (\count(Query::getByType($queries, [QueryMethod::Limit])) === 0) {
|
||||
$queries[] = Query::limit(5000);
|
||||
}
|
||||
|
||||
@@ -898,7 +899,7 @@ Http::get('/v1/projects/:projectId/keys')
|
||||
$cursor->setValue($cursorDocument);
|
||||
}
|
||||
|
||||
$filterQueries = Query::groupByType($queries)['filters'];
|
||||
$filterQueries = Query::groupByType($queries)->filters;
|
||||
|
||||
$keys = $dbForPlatform->find('keys', $queries);
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\SetType;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
@@ -191,7 +192,7 @@ function createUser(Hash $hash, string $userId, ?string $email, ?string $passwor
|
||||
Query::equal('identifier', [$email]),
|
||||
]);
|
||||
if (!$existingTarget->isEmpty()) {
|
||||
$user->setAttribute('targets', $existingTarget, Document::SET_TYPE_APPEND);
|
||||
$user->setAttribute('targets', $existingTarget, SetType::Append);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,7 +216,7 @@ function createUser(Hash $hash, string $userId, ?string $email, ?string $passwor
|
||||
Query::equal('identifier', [$phone]),
|
||||
]);
|
||||
if (!$existingTarget->isEmpty()) {
|
||||
$user->setAttribute('targets', $existingTarget, Document::SET_TYPE_APPEND);
|
||||
$user->setAttribute('targets', $existingTarget, SetType::Append);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -955,8 +956,8 @@ Http::get('/v1/users/:userId/logs')
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
$limit = $grouped->limit ?? 25;
|
||||
$offset = $grouped->offset ?? 0;
|
||||
|
||||
$logs = $audit->getLogsByUser($user->getSequence(), limit: $limit, offset: $offset);
|
||||
$output = [];
|
||||
|
||||
@@ -56,6 +56,7 @@ use Utopia\Logger\Log;
|
||||
use Utopia\Logger\Log\User;
|
||||
use Utopia\Logger\Logger;
|
||||
use Utopia\Platform\Service;
|
||||
use Utopia\Query\Method as QueryMethod;
|
||||
use Utopia\Span\Span;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator;
|
||||
@@ -1351,7 +1352,7 @@ Http::error()
|
||||
}
|
||||
|
||||
// logical queries - recursively format nested queries
|
||||
if (in_array($method, [Query::TYPE_AND, Query::TYPE_OR], true)) {
|
||||
if (in_array($method, [QueryMethod::And, QueryMethod::Or], true)) {
|
||||
$nested = [];
|
||||
foreach ($values as $nestedArray) {
|
||||
if (is_array($nestedArray)) {
|
||||
@@ -1365,26 +1366,26 @@ Http::error()
|
||||
}
|
||||
|
||||
// select - show selected attributes
|
||||
if ($method === Query::TYPE_SELECT) {
|
||||
if ($method === QueryMethod::Select) {
|
||||
$attributes = array_values(array_filter($values, 'is_string'));
|
||||
return [$method => $attributes];
|
||||
}
|
||||
|
||||
// pagination
|
||||
if (in_array($method, [
|
||||
Query::TYPE_LIMIT,
|
||||
Query::TYPE_OFFSET,
|
||||
Query::TYPE_CURSOR_AFTER,
|
||||
Query::TYPE_CURSOR_BEFORE
|
||||
QueryMethod::Limit,
|
||||
QueryMethod::Offset,
|
||||
QueryMethod::CursorAfter,
|
||||
QueryMethod::CursorBefore
|
||||
], true)) {
|
||||
return [$method => []];
|
||||
}
|
||||
|
||||
// orders
|
||||
if (in_array($method, [
|
||||
Query::TYPE_ORDER_DESC,
|
||||
Query::TYPE_ORDER_ASC,
|
||||
Query::TYPE_ORDER_RANDOM
|
||||
QueryMethod::OrderDesc,
|
||||
QueryMethod::OrderAsc,
|
||||
QueryMethod::OrderRandom
|
||||
], true)) {
|
||||
return [$method => !empty($attribute) ? [$attribute] : []];
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\PermissionType;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Authorization\Input;
|
||||
use Utopia\Database\Validator\Roles;
|
||||
@@ -362,7 +363,7 @@ Http::init()
|
||||
* whether the admin user has necessary permission on the project (sites, functions, etc. don't have permissions associated to them).
|
||||
*/
|
||||
if (empty($apiKey) && ! $user->isEmpty() && $project->getId() !== 'console' && $mode === APP_MODE_ADMIN) {
|
||||
$input = new Input(Database::PERMISSION_READ, $project->getPermissionsByType(Database::PERMISSION_READ));
|
||||
$input = new Input(PermissionType::Read, $project->getPermissionsByType(PermissionType::Read));
|
||||
$initialStatus = $authorization->getStatus();
|
||||
$authorization->enable();
|
||||
if (! $authorization->isValid($input)) {
|
||||
@@ -644,7 +645,7 @@ Http::init()
|
||||
}
|
||||
|
||||
$fileSecurity = $bucket->getAttribute('fileSecurity', false);
|
||||
$valid = $authorization->isValid(new Input(Database::PERMISSION_READ, $bucket->getRead()));
|
||||
$valid = $authorization->isValid(new Input(PermissionType::Read, $bucket->getRead()));
|
||||
if (! $fileSecurity && ! $valid && ! $isToken) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
|
||||
+8
-59
@@ -255,25 +255,8 @@ function createDatabase(Http $app, string $resourceKey, string $dbName, array $c
|
||||
continue;
|
||||
}
|
||||
|
||||
$attributes = array_map(fn ($attr) => new Document([
|
||||
'$id' => ID::custom($attr['$id']),
|
||||
'type' => $attr['type'],
|
||||
'size' => $attr['size'],
|
||||
'required' => $attr['required'],
|
||||
'signed' => $attr['signed'],
|
||||
'array' => $attr['array'],
|
||||
'filters' => $attr['filters'],
|
||||
'default' => $attr['default'] ?? null,
|
||||
'format' => $attr['format'] ?? ''
|
||||
]), $collection['attributes']);
|
||||
|
||||
$indexes = array_map(fn ($index) => new Document([
|
||||
'$id' => ID::custom($index['$id']),
|
||||
'type' => $index['type'],
|
||||
'attributes' => $index['attributes'],
|
||||
'lengths' => $index['lengths'],
|
||||
'orders' => $index['orders'],
|
||||
]), $collection['indexes']);
|
||||
$attributes = $collection['attributes'];
|
||||
$indexes = $collection['indexes'];
|
||||
|
||||
$database->createCollection($key, $attributes, $indexes);
|
||||
$collectionsCreated++;
|
||||
@@ -340,25 +323,8 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $tot
|
||||
throw new Exception('Files collection is not configured.');
|
||||
}
|
||||
|
||||
$attributes = array_map(fn ($attr) => new Document([
|
||||
'$id' => ID::custom($attr['$id']),
|
||||
'type' => $attr['type'],
|
||||
'size' => $attr['size'],
|
||||
'required' => $attr['required'],
|
||||
'signed' => $attr['signed'],
|
||||
'array' => $attr['array'],
|
||||
'filters' => $attr['filters'],
|
||||
'default' => $attr['default'] ?? null,
|
||||
'format' => $attr['format'] ?? ''
|
||||
]), $files['attributes']);
|
||||
|
||||
$indexes = array_map(fn ($index) => new Document([
|
||||
'$id' => ID::custom($index['$id']),
|
||||
'type' => $index['type'],
|
||||
'attributes' => $index['attributes'],
|
||||
'lengths' => $index['lengths'],
|
||||
'orders' => $index['orders'],
|
||||
]), $files['indexes']);
|
||||
$attributes = $files['attributes'];
|
||||
$indexes = $files['indexes'];
|
||||
|
||||
$dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes);
|
||||
}
|
||||
@@ -386,25 +352,8 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $tot
|
||||
throw new Exception('Files collection is not configured.');
|
||||
}
|
||||
|
||||
$attributes = array_map(fn ($attr) => new Document([
|
||||
'$id' => ID::custom($attr['$id']),
|
||||
'type' => $attr['type'],
|
||||
'size' => $attr['size'],
|
||||
'required' => $attr['required'],
|
||||
'signed' => $attr['signed'],
|
||||
'array' => $attr['array'],
|
||||
'filters' => $attr['filters'],
|
||||
'default' => $attr['default'] ?? null,
|
||||
'format' => $attr['format'] ?? ''
|
||||
]), $files['attributes']);
|
||||
|
||||
$indexes = array_map(fn ($index) => new Document([
|
||||
'$id' => ID::custom($index['$id']),
|
||||
'type' => $index['type'],
|
||||
'attributes' => $index['attributes'],
|
||||
'lengths' => $index['lengths'],
|
||||
'orders' => $index['orders'],
|
||||
]), $files['indexes']);
|
||||
$attributes = $files['attributes'];
|
||||
$indexes = $files['indexes'];
|
||||
|
||||
$authorization->skip(fn () => $dbForPlatform->createCollection('bucket_' . $bucket->getSequence(), $attributes, $indexes));
|
||||
}
|
||||
@@ -481,8 +430,8 @@ $http->on(Constant::EVENT_START, function (Server $http) use ($payloadSize, $tot
|
||||
continue;
|
||||
}
|
||||
|
||||
$attributes = \array_map(fn ($attribute) => new Document($attribute), $collection['attributes']);
|
||||
$indexes = \array_map(fn (array $index) => new Document($index), $collection['indexes']);
|
||||
$attributes = $collection['attributes'];
|
||||
$indexes = $collection['indexes'];
|
||||
|
||||
$dbForProject->createCollection($key, $attributes, $indexes);
|
||||
$collectionsCreated++;
|
||||
|
||||
@@ -4,6 +4,7 @@ use Appwrite\OpenSSL\OpenSSL;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\System\System;
|
||||
|
||||
Database::addFilter(
|
||||
@@ -79,7 +80,7 @@ Database::addFilter(
|
||||
$attributeType = $attribute->getAttribute('type');
|
||||
|
||||
switch ($attributeType) {
|
||||
case Database::VAR_RELATIONSHIP:
|
||||
case ColumnType::Relationship->value:
|
||||
$options = $attribute->getAttribute('options');
|
||||
foreach ($options as $key => $value) {
|
||||
$attribute->setAttribute($key, $value);
|
||||
@@ -87,11 +88,11 @@ Database::addFilter(
|
||||
$attribute->removeAttribute('options');
|
||||
break;
|
||||
|
||||
case Database::VAR_STRING:
|
||||
case Database::VAR_VARCHAR:
|
||||
case Database::VAR_TEXT:
|
||||
case Database::VAR_MEDIUMTEXT:
|
||||
case Database::VAR_LONGTEXT:
|
||||
case ColumnType::String->value:
|
||||
case ColumnType::Varchar->value:
|
||||
case ColumnType::Text->value:
|
||||
case ColumnType::MediumText->value:
|
||||
case ColumnType::LongText->value:
|
||||
$filters = $attribute->getAttribute('filters', []);
|
||||
$attribute->setAttribute('encrypt', in_array('encrypt', $filters));
|
||||
break;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
use Utopia\Database\Validator\Structure;
|
||||
use Utopia\Emails\Validator\Email;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\IP;
|
||||
use Utopia\Validator\Range;
|
||||
use Utopia\Validator\URL;
|
||||
@@ -11,33 +11,33 @@ use Utopia\Validator\WhiteList;
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_EMAIL, function () {
|
||||
return new Email();
|
||||
}, Database::VAR_STRING);
|
||||
}, ColumnType::String);
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_DATETIME, function () {
|
||||
return new DatetimeValidator();
|
||||
}, Database::VAR_DATETIME);
|
||||
}, ColumnType::Datetime);
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_ENUM, function ($attribute) {
|
||||
$elements = $attribute['formatOptions']['elements'] ?? [];
|
||||
return new WhiteList($elements, true);
|
||||
}, Database::VAR_STRING);
|
||||
}, ColumnType::String);
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_IP, function () {
|
||||
return new IP();
|
||||
}, Database::VAR_STRING);
|
||||
}, ColumnType::String);
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_URL, function () {
|
||||
return new URL();
|
||||
}, Database::VAR_STRING);
|
||||
}, ColumnType::String);
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_INT_RANGE, function ($attribute) {
|
||||
$min = $attribute['formatOptions']['min'] ?? -INF;
|
||||
$max = $attribute['formatOptions']['max'] ?? INF;
|
||||
return new Range($min, $max, Range::TYPE_INTEGER);
|
||||
}, Database::VAR_INTEGER);
|
||||
}, ColumnType::Integer);
|
||||
|
||||
Structure::addFormat(APP_DATABASE_ATTRIBUTE_FLOAT_RANGE, function ($attribute) {
|
||||
$min = $attribute['formatOptions']['min'] ?? -INF;
|
||||
$max = $attribute['formatOptions']['max'] ?? INF;
|
||||
$min = \floatval($attribute['formatOptions']['min'] ?? $attribute['min'] ?? -INF);
|
||||
$max = \floatval($attribute['formatOptions']['max'] ?? $attribute['max'] ?? INF);
|
||||
return new Range($min, $max, Range::TYPE_FLOAT);
|
||||
}, Database::VAR_FLOAT);
|
||||
}, ColumnType::Double);
|
||||
|
||||
+50
-273
@@ -28,6 +28,11 @@ use Appwrite\Network\Validator\Origin;
|
||||
use Appwrite\Network\Validator\Redirect;
|
||||
use Appwrite\Usage\Context as UsageContext;
|
||||
use Appwrite\Utopia\Database\Documents\User;
|
||||
use Appwrite\Utopia\Database\Hooks\DocumentUsage;
|
||||
use Appwrite\Utopia\Database\Hooks\FunctionCache;
|
||||
use Appwrite\Utopia\Database\Hooks\Metadata;
|
||||
use Appwrite\Utopia\Database\Hooks\Usage;
|
||||
use Appwrite\Utopia\Database\Hooks\UserEvents;
|
||||
use Appwrite\Utopia\Request;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Executor\Executor;
|
||||
@@ -51,6 +56,9 @@ use Utopia\Database\Adapter\Pool as DatabasePool;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime as DatabaseDateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Hook\Permissions;
|
||||
use Utopia\Database\Hook\Relationships;
|
||||
use Utopia\Database\Hook\Tenancy;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\DSN\DSN;
|
||||
@@ -58,6 +66,7 @@ use Utopia\Http\Http;
|
||||
use Utopia\Locale\Locale;
|
||||
use Utopia\Logger\Log;
|
||||
use Utopia\Pools\Group;
|
||||
use Utopia\Query\Method;
|
||||
use Utopia\Queue\Broker\Pool as BrokerPool;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\Queue\Queue;
|
||||
@@ -642,86 +651,7 @@ Http::setResource('dbForProject', function (Group $pools, Database $dbForPlatfor
|
||||
->setNamespace('_' . $project->getSequence());
|
||||
}
|
||||
|
||||
/**
|
||||
* This isolated event handling for `users.*.create` which is based on a `Database::EVENT_DOCUMENT_CREATE` listener may look odd, but it is **intentional**.
|
||||
*
|
||||
* Accounts can be created in many ways beyond `createAccount`
|
||||
* (anonymous, OAuth, phone, etc.), and those flows are probably not covered in event tests; so we handle this here.
|
||||
*/
|
||||
$eventDatabaseListener = function (Document $project, Document $document, Response $response, Event $queueForEvents, Func $queueForFunctions, Webhook $queueForWebhooks, Realtime $queueForRealtime) {
|
||||
// Only trigger events for user creation with the database listener.
|
||||
if ($document->getCollection() !== 'users') {
|
||||
return;
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
->setEvent('users.[userId].create')
|
||||
->setParam('userId', $document->getId())
|
||||
->setPayload($response->output($document, Response::MODEL_USER));
|
||||
|
||||
// Trigger functions, webhooks, and realtime events
|
||||
$queueForFunctions
|
||||
->from($queueForEvents)
|
||||
->trigger();
|
||||
|
||||
/** Trigger webhooks events only if a project has them enabled */
|
||||
if (! empty($project->getAttribute('webhooks'))) {
|
||||
$queueForWebhooks
|
||||
->from($queueForEvents)
|
||||
->trigger();
|
||||
}
|
||||
|
||||
/** Trigger realtime events only for non console events */
|
||||
if ($queueForEvents->getProject()->getId() !== 'console') {
|
||||
$queueForRealtime
|
||||
->from($queueForEvents)
|
||||
->trigger();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Purge function events cache when functions are created, updated or deleted.
|
||||
*/
|
||||
$functionsEventsCacheListener = function (string $event, Document $document, Document $project, Database $dbForProject) {
|
||||
|
||||
if ($document->getCollection() !== 'functions') {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($project->isEmpty() || $project->getId() === 'console') {
|
||||
return;
|
||||
}
|
||||
|
||||
$hostname = $dbForProject->getAdapter()->getHostname();
|
||||
$cacheKey = \sprintf(
|
||||
'%s-cache-%s:%s:%s:project:%s:functions:events',
|
||||
$dbForProject->getCacheName(),
|
||||
$hostname ?? '',
|
||||
$dbForProject->getNamespace(),
|
||||
$dbForProject->getTenant(),
|
||||
$project->getId()
|
||||
);
|
||||
|
||||
$dbForProject->getCache()->purge($cacheKey);
|
||||
};
|
||||
|
||||
/**
|
||||
* Prefix metrics with database type when applicable.
|
||||
* Avoids prefixing for legacy and tablesdb types to preserve historical metrics.
|
||||
*/
|
||||
$getDatabaseTypePrefixedMetric = function (string $databaseType, string $metric): string {
|
||||
if (
|
||||
$databaseType === '' ||
|
||||
$databaseType === DATABASE_TYPE_LEGACY ||
|
||||
$databaseType === DATABASE_TYPE_TABLESDB
|
||||
) {
|
||||
return $metric;
|
||||
}
|
||||
|
||||
return $databaseType . '.' . $metric;
|
||||
};
|
||||
|
||||
// Determine database type from request path, similar to api.php
|
||||
// Determine database type from request path
|
||||
$path = $request->getURI();
|
||||
$databaseType = match (true) {
|
||||
str_contains($path, '/documentsdb') => DATABASE_TYPE_DOCUMENTSDB,
|
||||
@@ -729,115 +659,6 @@ Http::setResource('dbForProject', function (Group $pools, Database $dbForPlatfor
|
||||
default => '',
|
||||
};
|
||||
|
||||
$usageDatabaseListener = function (string $event, Document $document, UsageContext $usage) use ($getDatabaseTypePrefixedMetric, $databaseType) {
|
||||
$value = 1;
|
||||
|
||||
switch ($event) {
|
||||
case Database::EVENT_DOCUMENT_DELETE:
|
||||
$value = -1;
|
||||
break;
|
||||
case Database::EVENT_DOCUMENTS_DELETE:
|
||||
$value = -1 * $document->getAttribute('modified', 0);
|
||||
break;
|
||||
case Database::EVENT_DOCUMENTS_CREATE:
|
||||
$value = $document->getAttribute('modified', 0);
|
||||
break;
|
||||
case Database::EVENT_DOCUMENTS_UPSERT:
|
||||
$value = $document->getAttribute('created', 0);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case $document->getCollection() === 'teams':
|
||||
$usage->addMetric(METRIC_TEAMS, $value); // per project
|
||||
break;
|
||||
case $document->getCollection() === 'users':
|
||||
$usage->addMetric(METRIC_USERS, $value); // per project
|
||||
if ($event === Database::EVENT_DOCUMENT_DELETE) {
|
||||
$usage->addReduce($document);
|
||||
}
|
||||
break;
|
||||
case $document->getCollection() === 'sessions': // sessions
|
||||
$usage->addMetric(METRIC_SESSIONS, $value); // per project
|
||||
break;
|
||||
case $document->getCollection() === 'databases': // databases
|
||||
$metric = $getDatabaseTypePrefixedMetric($databaseType, METRIC_DATABASES);
|
||||
$usage->addMetric($metric, $value); // per project
|
||||
|
||||
if ($event === Database::EVENT_DOCUMENT_DELETE) {
|
||||
$usage->addReduce($document);
|
||||
}
|
||||
break;
|
||||
case str_starts_with($document->getCollection(), 'database_') && ! str_contains($document->getCollection(), 'collection'): // collections
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionMetric = $getDatabaseTypePrefixedMetric($databaseType, METRIC_COLLECTIONS);
|
||||
$databaseIdCollectionMetric = $getDatabaseTypePrefixedMetric($databaseType, METRIC_DATABASE_ID_COLLECTIONS);
|
||||
$usage
|
||||
->addMetric($collectionMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdCollectionMetric), $value);
|
||||
|
||||
if ($event === Database::EVENT_DOCUMENT_DELETE) {
|
||||
$usage->addReduce($document);
|
||||
}
|
||||
break;
|
||||
case str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_'): // documents
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$documentsMetric = $getDatabaseTypePrefixedMetric($databaseType, METRIC_DOCUMENTS);
|
||||
$databaseIdDocumentsMetric = $getDatabaseTypePrefixedMetric($databaseType, METRIC_DATABASE_ID_DOCUMENTS);
|
||||
$databaseIdCollectionIdDocumentsMetric = $getDatabaseTypePrefixedMetric($databaseType, METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS);
|
||||
$usage
|
||||
->addMetric($documentsMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdDocumentsMetric), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], $databaseIdCollectionIdDocumentsMetric), $value); // per collection
|
||||
break;
|
||||
case $document->getCollection() === 'buckets': // buckets
|
||||
$usage->addMetric(METRIC_BUCKETS, $value); // per project
|
||||
if ($event === Database::EVENT_DOCUMENT_DELETE) {
|
||||
$usage
|
||||
->addReduce($document);
|
||||
}
|
||||
break;
|
||||
case str_starts_with($document->getCollection(), 'bucket_'): // files
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$bucketInternalId = $parts[1];
|
||||
$usage
|
||||
->addMetric(METRIC_FILES, $value) // per project
|
||||
->addMetric(METRIC_FILES_STORAGE, $document->getAttribute('sizeOriginal') * $value) // per project
|
||||
->addMetric(str_replace('{bucketInternalId}', $bucketInternalId, METRIC_BUCKET_ID_FILES), $value) // per bucket
|
||||
->addMetric(str_replace('{bucketInternalId}', $bucketInternalId, METRIC_BUCKET_ID_FILES_STORAGE), $document->getAttribute('sizeOriginal') * $value); // per bucket
|
||||
break;
|
||||
case $document->getCollection() === 'functions':
|
||||
$usage->addMetric(METRIC_FUNCTIONS, $value); // per project
|
||||
|
||||
if ($event === Database::EVENT_DOCUMENT_DELETE) {
|
||||
$usage
|
||||
->addReduce($document);
|
||||
}
|
||||
break;
|
||||
case $document->getCollection() === 'sites':
|
||||
$usage->addMetric(METRIC_SITES, $value); // per project
|
||||
|
||||
if ($event === Database::EVENT_DOCUMENT_DELETE) {
|
||||
$usage
|
||||
->addReduce($document);
|
||||
}
|
||||
break;
|
||||
case $document->getCollection() === 'deployments':
|
||||
$usage
|
||||
->addMetric(METRIC_DEPLOYMENTS, $value) // per project
|
||||
->addMetric(METRIC_DEPLOYMENTS_STORAGE, $document->getAttribute('size') * $value) // per project
|
||||
->addMetric(str_replace(['{resourceType}'], [$document->getAttribute('resourceType')], METRIC_RESOURCE_TYPE_DEPLOYMENTS), $value) // per function
|
||||
->addMetric(str_replace(['{resourceType}'], [$document->getAttribute('resourceType')], METRIC_RESOURCE_TYPE_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value)
|
||||
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS), $value) // per function
|
||||
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_RESOURCE_TYPE_ID_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
// Clone the queues, to prevent events triggered by the database listener
|
||||
// from overwriting the events that are supposed to be triggered in the shutdown hook.
|
||||
@@ -847,23 +668,22 @@ Http::setResource('dbForProject', function (Group $pools, Database $dbForPlatfor
|
||||
$queueForRealtime = new Realtime();
|
||||
|
||||
$database
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $usage))
|
||||
->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $usage))
|
||||
->on(Database::EVENT_DOCUMENTS_CREATE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $usage))
|
||||
->on(Database::EVENT_DOCUMENTS_DELETE, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $usage))
|
||||
->on(Database::EVENT_DOCUMENTS_UPSERT, 'calculate-usage', fn ($event, $document) => $usageDatabaseListener($event, $document, $usage))
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'create-trigger-events', fn ($event, $document) => $eventDatabaseListener(
|
||||
->addHook(new Usage($usage, $databaseType))
|
||||
->addHook(new UserEvents(
|
||||
$project,
|
||||
$document,
|
||||
$response,
|
||||
$queueForEventsClone->from($queueForEvents),
|
||||
$queueForFunctions->from($queueForEvents),
|
||||
$queueForWebhooks->from($queueForEvents),
|
||||
$queueForRealtime->from($queueForEvents)
|
||||
$queueForEvents,
|
||||
$queueForEventsClone,
|
||||
$queueForFunctions,
|
||||
$queueForWebhooks,
|
||||
$queueForRealtime,
|
||||
))
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'purge-function-events-cache', fn ($event, $document) => $functionsEventsCacheListener($event, $document, $project, $database))
|
||||
->on(Database::EVENT_DOCUMENT_UPDATE, 'purge-function-events-cache', fn ($event, $document) => $functionsEventsCacheListener($event, $document, $project, $database))
|
||||
->on(Database::EVENT_DOCUMENT_DELETE, 'purge-function-events-cache', fn ($event, $document) => $functionsEventsCacheListener($event, $document, $project, $database));
|
||||
->addHook(new FunctionCache($project, $database))
|
||||
->addHook(new Permissions());
|
||||
|
||||
if ($database->getSharedTables() && ($database->getTenant() !== null)) {
|
||||
$database->addHook(new Tenancy($database->getTenant()));
|
||||
}
|
||||
|
||||
return $database;
|
||||
}, ['pools', 'dbForPlatform', 'cache', 'project', 'response', 'publisher', 'publisherFunctions', 'publisherWebhooks', 'queueForEvents', 'queueForFunctions', 'queueForWebhooks', 'queueForRealtime', 'usage', 'authorization', 'request']);
|
||||
@@ -883,13 +703,16 @@ Http::setResource('dbForPlatform', function (Group $pools, Cache $cache, Authori
|
||||
->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES);
|
||||
|
||||
$database->setDocumentType('users', User::class);
|
||||
$database->addHook(new Permissions());
|
||||
|
||||
return $database;
|
||||
}, ['pools', 'cache', 'authorization']);
|
||||
|
||||
Http::setResource('getDatabasesDB', function (Group $pools, Cache $cache, Document $project, Request $request, UsageContext $usage, Authorization $authorization) {
|
||||
|
||||
return function (Document $database) use ($pools, $cache, $project, $request, $usage, $authorization): Database {
|
||||
return function (Document $database, ?Document $collection = null) use ($pools, $cache, $project, $request, $usage, $authorization): Database {
|
||||
$originalDatabase = $database;
|
||||
$context = str_contains($request->getURI(), '/tablesdb/') ? 'table' : 'collection';
|
||||
$databaseDSN = $database->getAttribute('database', $project->getAttribute('database', ''));
|
||||
$databaseType = $database->getAttribute('type', '');
|
||||
|
||||
@@ -938,81 +761,32 @@ Http::setResource('getDatabasesDB', function (Group $pools, Cache $cache, Docume
|
||||
$database->setTimeout($timeout);
|
||||
}
|
||||
|
||||
// Register database event listeners for usage stats collection
|
||||
$documentsMetric = METRIC_DOCUMENTS;
|
||||
$databaseIdDocumentsMetric = METRIC_DATABASE_ID_DOCUMENTS;
|
||||
$databaseIdCollectionIdDocumentsMetric = METRIC_DATABASE_ID_COLLECTION_ID_DOCUMENTS;
|
||||
if ($databaseType !== DATABASE_TYPE_LEGACY && $databaseType !== DATABASE_TYPE_TABLESDB) {
|
||||
$documentsMetric = $databaseType. '.' .$documentsMetric;
|
||||
$databaseIdDocumentsMetric = $databaseType. '.' .$databaseIdDocumentsMetric;
|
||||
$databaseIdCollectionIdDocumentsMetric = $databaseType . '.' .$databaseIdCollectionIdDocumentsMetric;
|
||||
$documentsMetric = $databaseType . '.' . $documentsMetric;
|
||||
$databaseIdDocumentsMetric = $databaseType . '.' . $databaseIdDocumentsMetric;
|
||||
$databaseIdCollectionIdDocumentsMetric = $databaseType . '.' . $databaseIdCollectionIdDocumentsMetric;
|
||||
}
|
||||
|
||||
$database
|
||||
->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', function ($event, $document) use ($usage, $documentsMetric, $databaseIdDocumentsMetric, $databaseIdCollectionIdDocumentsMetric) {
|
||||
$value = 1;
|
||||
->addHook(new DocumentUsage(
|
||||
$usage,
|
||||
$documentsMetric,
|
||||
$databaseIdDocumentsMetric,
|
||||
$databaseIdCollectionIdDocumentsMetric,
|
||||
))
|
||||
->addHook(new Permissions())
|
||||
->addHook(new Relationships($database))
|
||||
->addHook(new Metadata(
|
||||
database: $originalDatabase,
|
||||
context: $context,
|
||||
));
|
||||
|
||||
if (str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_')) {
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$usage
|
||||
->addMetric($documentsMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdDocumentsMetric), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], $databaseIdCollectionIdDocumentsMetric), $value); // per collection
|
||||
}
|
||||
})
|
||||
->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', function ($event, $document) use ($usage, $documentsMetric, $databaseIdDocumentsMetric, $databaseIdCollectionIdDocumentsMetric) {
|
||||
$value = -1;
|
||||
|
||||
if (str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_')) {
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$usage
|
||||
->addMetric($documentsMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdDocumentsMetric), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], $databaseIdCollectionIdDocumentsMetric), $value); // per collection
|
||||
}
|
||||
})
|
||||
->on(Database::EVENT_DOCUMENTS_CREATE, 'calculate-usage', function ($event, $document) use ($usage, $documentsMetric, $databaseIdDocumentsMetric, $databaseIdCollectionIdDocumentsMetric) {
|
||||
$value = $document->getAttribute('modified', 0);
|
||||
|
||||
if (str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_')) {
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$usage
|
||||
->addMetric($documentsMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdDocumentsMetric), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], $databaseIdCollectionIdDocumentsMetric), $value); // per collection
|
||||
}
|
||||
})
|
||||
->on(Database::EVENT_DOCUMENTS_DELETE, 'calculate-usage', function ($event, $document) use ($usage, $documentsMetric, $databaseIdDocumentsMetric, $databaseIdCollectionIdDocumentsMetric) {
|
||||
$value = -1 * $document->getAttribute('modified', 0);
|
||||
|
||||
if (str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_')) {
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$usage
|
||||
->addMetric($documentsMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdDocumentsMetric), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], $databaseIdCollectionIdDocumentsMetric), $value); // per collection
|
||||
}
|
||||
})
|
||||
->on(Database::EVENT_DOCUMENTS_UPSERT, 'calculate-usage', function ($event, $document) use ($usage, $documentsMetric, $databaseIdDocumentsMetric, $databaseIdCollectionIdDocumentsMetric) {
|
||||
$value = $document->getAttribute('created', 0);
|
||||
|
||||
if (str_starts_with($document->getCollection(), 'database_') && str_contains($document->getCollection(), '_collection_')) {
|
||||
$parts = explode('_', $document->getCollection());
|
||||
$databaseInternalId = $parts[1] ?? 0;
|
||||
$collectionInternalId = $parts[3] ?? 0;
|
||||
$usage
|
||||
->addMetric($documentsMetric, $value) // per project
|
||||
->addMetric(str_replace('{databaseInternalId}', $databaseInternalId, $databaseIdDocumentsMetric), $value) // per database
|
||||
->addMetric(str_replace(['{databaseInternalId}', '{collectionInternalId}'], [$databaseInternalId, $collectionInternalId], $databaseIdCollectionIdDocumentsMetric), $value); // per collection
|
||||
}
|
||||
});
|
||||
if ($database->getSharedTables() && ($database->getTenant() !== null)) {
|
||||
$database->addHook(new Tenancy($database->getTenant()));
|
||||
}
|
||||
|
||||
return $database;
|
||||
};
|
||||
@@ -1073,6 +847,7 @@ Http::setResource('getProjectDB', function (Group $pools, Database $dbForPlatfor
|
||||
|
||||
$adapter = new DatabasePool($pools->get($dsn->getHost()));
|
||||
$database = new Database($adapter, $cache);
|
||||
$database->addHook(new Permissions());
|
||||
$databases[$dsn->getHost()] = $database;
|
||||
$configure($database);
|
||||
|
||||
@@ -1100,6 +875,8 @@ Http::setResource('getLogsDB', function (Group $pools, Cache $cache, Authorizati
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_API)
|
||||
->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES);
|
||||
|
||||
$database->addHook(new Permissions());
|
||||
|
||||
// set tenant
|
||||
if ($project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
|
||||
$database->setTenant($project->getSequence());
|
||||
@@ -1323,7 +1100,7 @@ Http::setResource('schema', function ($utopia, $dbForProject, $authorization) {
|
||||
|
||||
$complexity = function (int $complexity, array $args) {
|
||||
$queries = Query::parseQueries($args['queries'] ?? []);
|
||||
$query = Query::getByType($queries, [Query::TYPE_LIMIT])[0] ?? null;
|
||||
$query = Query::getByType($queries, [Method::Limit])[0] ?? null;
|
||||
$limit = $query ? $query->getValue() : APP_LIMIT_LIST_DEFAULT;
|
||||
|
||||
return $complexity * $limit;
|
||||
|
||||
@@ -34,6 +34,7 @@ use Utopia\Database\Adapter\Pool as DatabasePool;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Hook\Permissions;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\DSN\DSN;
|
||||
use Utopia\Logger\Log;
|
||||
@@ -75,6 +76,7 @@ Server::setResource('dbForPlatform', function (Cache $cache, Registry $register,
|
||||
->setNamespace('_console')
|
||||
->setDocumentType('users', User::class);
|
||||
|
||||
$dbForPlatform->addHook(new Permissions());
|
||||
return $dbForPlatform;
|
||||
}, ['cache', 'register', 'authorization']);
|
||||
|
||||
@@ -126,6 +128,8 @@ Server::setResource('dbForProject', function (Cache $cache, Registry $register,
|
||||
->setAuthorization($authorization)
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER);
|
||||
|
||||
$database->addHook(new Permissions());
|
||||
|
||||
return $database;
|
||||
}, ['cache', 'register', 'message', 'project', 'dbForPlatform', 'authorization']);
|
||||
|
||||
@@ -188,6 +192,8 @@ Server::setResource('getProjectDB', function (Group $pools, Database $dbForPlatf
|
||||
->setAuthorization($authorization)
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER);
|
||||
|
||||
$database->addHook(new Permissions());
|
||||
|
||||
return $database;
|
||||
};
|
||||
}, ['pools', 'dbForPlatform', 'cache', 'authorization']);
|
||||
@@ -212,6 +218,8 @@ Server::setResource('getLogsDB', function (Group $pools, Cache $cache, Authoriza
|
||||
->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER)
|
||||
->setMaxQueryValues(APP_DATABASE_QUERY_MAX_VALUES_WORKER);
|
||||
|
||||
$database->addHook(new Permissions());
|
||||
|
||||
if ($project !== null && !$project->isEmpty() && $project->getId() !== 'console') {
|
||||
$database->setTenant($project->getSequence());
|
||||
}
|
||||
@@ -270,6 +278,7 @@ Server::setResource('getDatabasesDB', function (Cache $cache, Registry $register
|
||||
}
|
||||
|
||||
$database->setTimeout(APP_DATABASE_TIMEOUT_MILLISECONDS_WORKER);
|
||||
$database->addHook(new Permissions());
|
||||
return $database;
|
||||
};
|
||||
}, ['cache', 'register', 'project', 'authorization']);
|
||||
|
||||
+13
-3
@@ -53,14 +53,14 @@
|
||||
"appwrite/php-clamav": "2.0.*",
|
||||
"utopia-php/abuse": "1.2.*",
|
||||
"utopia-php/analytics": "0.15.*",
|
||||
"utopia-php/audit": "2.2.*",
|
||||
"utopia-php/audit": "dev-feat-query-lib as 2.2.0",
|
||||
"utopia-php/auth": "0.5.*",
|
||||
"utopia-php/cache": "1.0.*",
|
||||
"utopia-php/cli": "0.22.*",
|
||||
"utopia-php/compression": "0.1.*",
|
||||
"utopia-php/config": "1.*",
|
||||
"utopia-php/console": "0.1.*",
|
||||
"utopia-php/database": "5.*",
|
||||
"utopia-php/database": "dev-feat-query-lib as 5.3.17",
|
||||
"utopia-php/agents": "1.*",
|
||||
"utopia-php/detector": "0.2.*",
|
||||
"utopia-php/domains": "1.*",
|
||||
@@ -73,7 +73,7 @@
|
||||
"utopia-php/locale": "0.8.*",
|
||||
"utopia-php/logger": "0.6.*",
|
||||
"utopia-php/messaging": "0.20.*",
|
||||
"utopia-php/migration": "1.9.*",
|
||||
"utopia-php/migration": "dev-feat-query-lib as 1.8.0",
|
||||
"utopia-php/platform": "0.7.*",
|
||||
"utopia-php/pools": "1.*",
|
||||
"utopia-php/span": "1.1.*",
|
||||
@@ -111,6 +111,16 @@
|
||||
"provide": {
|
||||
"ext-phpiredis": "*"
|
||||
},
|
||||
"repositories": [
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/utopia-php/async.git"
|
||||
},
|
||||
{
|
||||
"type": "vcs",
|
||||
"url": "https://github.com/utopia-php/migration.git"
|
||||
}
|
||||
],
|
||||
"config": {
|
||||
"platform": {
|
||||
},
|
||||
|
||||
Generated
+354
-96
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "b5261855586680e467168f527e0634ae",
|
||||
"content-hash": "9d66f869fc3ff5abc5873a31e6976911",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -1634,6 +1634,71 @@
|
||||
},
|
||||
"time": "2026-01-21T04:14:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "opis/closure",
|
||||
"version": "4.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/opis/closure.git",
|
||||
"reference": "b97e42b95bb72d87507f5e2d137ceb239aea8d6b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/opis/closure/zipball/b97e42b95bb72d87507f5e2d137ceb239aea8d6b",
|
||||
"reference": "b97e42b95bb72d87507f5e2d137ceb239aea8d6b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Opis\\Closure\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Marius Sarca",
|
||||
"email": "marius.sarca@gmail.com"
|
||||
},
|
||||
{
|
||||
"name": "Sorin Sarca",
|
||||
"email": "sarca_sorin@hotmail.com"
|
||||
}
|
||||
],
|
||||
"description": "A library that can be used to serialize closures (anonymous functions) and arbitrary data.",
|
||||
"homepage": "https://opis.io/closure",
|
||||
"keywords": [
|
||||
"anonymous classes",
|
||||
"anonymous functions",
|
||||
"closure",
|
||||
"function",
|
||||
"serializable",
|
||||
"serialization",
|
||||
"serialize"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/opis/closure/issues",
|
||||
"source": "https://github.com/opis/closure/tree/4.5.0"
|
||||
},
|
||||
"time": "2026-03-05T13:32:42+00:00"
|
||||
},
|
||||
{
|
||||
"name": "paragonie/constant_time_encoding",
|
||||
"version": "v3.1.3",
|
||||
@@ -2708,16 +2773,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
"version": "v7.4.7",
|
||||
"version": "v7.4.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client.git",
|
||||
"reference": "1010624285470eb60e88ed10035102c75b4ea6af"
|
||||
"reference": "01933e626c3de76bea1e22641e205e78f6a34342"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/1010624285470eb60e88ed10035102c75b4ea6af",
|
||||
"reference": "1010624285470eb60e88ed10035102c75b4ea6af",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/01933e626c3de76bea1e22641e205e78f6a34342",
|
||||
"reference": "01933e626c3de76bea1e22641e205e78f6a34342",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2785,7 +2850,7 @@
|
||||
"http"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.4.7"
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.4.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2805,7 +2870,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-03-05T11:16:58+00:00"
|
||||
"time": "2026-03-30T12:55:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client-contracts",
|
||||
@@ -3501,24 +3566,143 @@
|
||||
"time": "2026-02-09T12:46:39+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "2.2.1",
|
||||
"name": "utopia-php/async",
|
||||
"version": "dev-main",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "e3e2d6ad5c7f6377d9237df296a12eb7943892fd"
|
||||
"url": "https://github.com/utopia-php/async.git",
|
||||
"reference": "7a0c6957b41731a5c999382ad26a0b2fdbd19812"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/e3e2d6ad5c7f6377d9237df296a12eb7943892fd",
|
||||
"reference": "e3e2d6ad5c7f6377d9237df296a12eb7943892fd",
|
||||
"url": "https://api.github.com/repos/utopia-php/async/zipball/7a0c6957b41731a5c999382ad26a0b2fdbd19812",
|
||||
"reference": "7a0c6957b41731a5c999382ad26a0b2fdbd19812",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"opis/closure": "4.*",
|
||||
"php": ">=8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"amphp/amp": "3.*",
|
||||
"amphp/parallel": "2.*",
|
||||
"amphp/process": "^2.0",
|
||||
"laravel/pint": "1.*",
|
||||
"phpstan/phpstan": "2.*",
|
||||
"phpunit/phpunit": "11.5.45",
|
||||
"react/child-process": "0.*",
|
||||
"react/event-loop": "1.*",
|
||||
"swoole/ide-helper": "*"
|
||||
},
|
||||
"suggest": {
|
||||
"amphp/amp": "Required for Amp promise adapter",
|
||||
"amphp/parallel": "Required for Amp parallel adapter",
|
||||
"ext-ev": "Required for ReactPHP event loop (recommended for best performance)",
|
||||
"ext-parallel": "Required for parallel adapter (requires PHP ZTS build)",
|
||||
"ext-sockets": "Required for Swoole Process adapter",
|
||||
"ext-swoole": "Required for Swoole Thread and Process adapters (recommended for best performance)",
|
||||
"react/child-process": "Required for ReactPHP parallel adapter",
|
||||
"react/event-loop": "Required for ReactPHP promise and parallel adapters"
|
||||
},
|
||||
"default-branch": true,
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Utopia\\Async\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Utopia\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test-unit": [
|
||||
"vendor/bin/phpunit tests/Unit --exclude-group no-swoole"
|
||||
],
|
||||
"test-promise-sync": [
|
||||
"vendor/bin/phpunit tests/E2e/Promise/SyncTest.php"
|
||||
],
|
||||
"test-promise-swoole": [
|
||||
"vendor/bin/phpunit tests/E2e/Promise/Swoole"
|
||||
],
|
||||
"test-promise-amp": [
|
||||
"vendor/bin/phpunit tests/E2e/Promise/Amp"
|
||||
],
|
||||
"test-promise-react": [
|
||||
"vendor/bin/phpunit tests/E2e/Promise/React"
|
||||
],
|
||||
"test-parallel-sync": [
|
||||
"vendor/bin/phpunit tests/E2e/Parallel/Sync"
|
||||
],
|
||||
"test-parallel-swoole-thread": [
|
||||
"vendor/bin/phpunit tests/E2e/Parallel/Swoole/ThreadTest.php"
|
||||
],
|
||||
"test-parallel-swoole-process": [
|
||||
"vendor/bin/phpunit tests/E2e/Parallel/Swoole/ProcessTest.php"
|
||||
],
|
||||
"test-parallel-amp": [
|
||||
"vendor/bin/phpunit tests/E2e/Parallel/Amp"
|
||||
],
|
||||
"test-parallel-react": [
|
||||
"vendor/bin/phpunit tests/E2e/Parallel/React"
|
||||
],
|
||||
"test-parallel-ext": [
|
||||
"php -n -d extension=parallel.so -d extension=sockets.so vendor/bin/phpunit tests/E2e/Parallel/Parallel"
|
||||
],
|
||||
"test-e2e": [
|
||||
"vendor/bin/phpunit tests/E2e --exclude-group ext-parallel"
|
||||
],
|
||||
"test": [
|
||||
"@test-unit",
|
||||
"@test-e2e",
|
||||
"@test-parallel-ext"
|
||||
],
|
||||
"lint": [
|
||||
"vendor/bin/pint"
|
||||
],
|
||||
"format": [
|
||||
"php -d memory_limit=4G vendor/bin/pint"
|
||||
],
|
||||
"check": [
|
||||
"vendor/bin/phpstan analyse src tests --level=max --memory-limit=4G"
|
||||
]
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Appwrite Team",
|
||||
"email": "team@appwrite.io"
|
||||
}
|
||||
],
|
||||
"description": "High-performance concurrent + parallel library with Promise and Parallel execution support for PHP.",
|
||||
"support": {
|
||||
"source": "https://github.com/utopia-php/async/tree/main",
|
||||
"issues": "https://github.com/utopia-php/async/issues"
|
||||
},
|
||||
"time": "2026-01-09T06:16:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "dev-feat-query-lib",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "ae866f6a6115bd9d6e6e7037978d5c5fb5b132d1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/ae866f6a6115bd9d6e6e7037978d5c5fb5b132d1",
|
||||
"reference": "ae866f6a6115bd9d6e6e7037978d5c5fb5b132d1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": "5.*",
|
||||
"utopia-php/fetch": "0.5.*",
|
||||
"utopia-php/validators": "0.2.*"
|
||||
"utopia-php/validators": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.*",
|
||||
@@ -3545,9 +3729,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/audit/issues",
|
||||
"source": "https://github.com/utopia-php/audit/tree/2.2.1"
|
||||
"source": "https://github.com/utopia-php/audit/tree/feat-query-lib"
|
||||
},
|
||||
"time": "2026-02-02T10:39:25+00:00"
|
||||
"time": "2026-03-26T15:29:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/auth",
|
||||
@@ -3850,16 +4034,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "5.3.17",
|
||||
"version": "dev-feat-query-lib",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "cff2b6ed63d3291b74110d086e16ff089fe05993"
|
||||
"reference": "2c49e169d47d00d03b485853e052ea83875da9de"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/cff2b6ed63d3291b74110d086e16ff089fe05993",
|
||||
"reference": "cff2b6ed63d3291b74110d086e16ff089fe05993",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/2c49e169d47d00d03b485853e052ea83875da9de",
|
||||
"reference": "2c49e169d47d00d03b485853e052ea83875da9de",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3867,18 +4051,20 @@
|
||||
"ext-mongodb": "*",
|
||||
"ext-pdo": "*",
|
||||
"php": ">=8.4",
|
||||
"utopia-php/async": "@dev",
|
||||
"utopia-php/cache": "1.*",
|
||||
"utopia-php/console": "0.1.*",
|
||||
"utopia-php/mongo": "1.*",
|
||||
"utopia-php/pools": "1.*",
|
||||
"utopia-php/query": "dev-feat-builder",
|
||||
"utopia-php/validators": "0.2.*"
|
||||
},
|
||||
"require-dev": {
|
||||
"brianium/paratest": "^7.7",
|
||||
"fakerphp/faker": "1.23.*",
|
||||
"laravel/pint": "*",
|
||||
"pcov/clobber": "2.*",
|
||||
"phpstan/phpstan": "1.*",
|
||||
"phpunit/phpunit": "9.*",
|
||||
"phpstan/phpstan": "^2.0",
|
||||
"phpunit/phpunit": "^12.0",
|
||||
"rregeer/phpunit-coverage-check": "0.3.*",
|
||||
"swoole/ide-helper": "5.1.3",
|
||||
"utopia-php/cli": "0.22.*"
|
||||
@@ -3903,9 +4089,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/5.3.17"
|
||||
"source": "https://github.com/utopia-php/database/tree/feat-query-lib"
|
||||
},
|
||||
"time": "2026-03-20T01:18:52+00:00"
|
||||
"time": "2026-04-02T11:40:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/detector",
|
||||
@@ -4518,16 +4704,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
"version": "1.9.1",
|
||||
"version": "dev-feat-query-lib",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/migration.git",
|
||||
"reference": "7a86aeadf182b63a9f4ceba7e137588b31c5d2e2"
|
||||
"reference": "1bc59979ee7a1af5f98333f277cad27785ef30c1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/7a86aeadf182b63a9f4ceba7e137588b31c5d2e2",
|
||||
"reference": "7a86aeadf182b63a9f4ceba7e137588b31c5d2e2",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/1bc59979ee7a1af5f98333f277cad27785ef30c1",
|
||||
"reference": "1bc59979ee7a1af5f98333f277cad27785ef30c1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4536,7 +4722,7 @@
|
||||
"ext-openssl": "*",
|
||||
"halaxa/json-machine": "^1.2",
|
||||
"php": ">=8.1",
|
||||
"utopia-php/database": "5.*",
|
||||
"utopia-php/database": "dev-feat-query-lib as 5.3.17",
|
||||
"utopia-php/dsn": "0.2.*",
|
||||
"utopia-php/storage": "1.0.*"
|
||||
},
|
||||
@@ -4553,7 +4739,25 @@
|
||||
"Utopia\\Migration\\": "src/Migration"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Utopia\\Tests\\": "tests/Migration"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": [
|
||||
"./vendor/bin/phpunit"
|
||||
],
|
||||
"lint": [
|
||||
"./vendor/bin/pint --test"
|
||||
],
|
||||
"format": [
|
||||
"./vendor/bin/pint"
|
||||
],
|
||||
"check": [
|
||||
"./vendor/bin/phpstan analyse --level 3 src tests --memory-limit 2G"
|
||||
]
|
||||
},
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
@@ -4566,10 +4770,10 @@
|
||||
"utopia"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/migration/issues",
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.9.1"
|
||||
"source": "https://github.com/utopia-php/migration/tree/feat-query-lib",
|
||||
"issues": "https://github.com/utopia-php/migration/issues"
|
||||
},
|
||||
"time": "2026-03-25T07:05:27+00:00"
|
||||
"time": "2026-04-01T14:01:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/mongo",
|
||||
@@ -4789,6 +4993,53 @@
|
||||
},
|
||||
"time": "2020-10-24T07:04:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/query",
|
||||
"version": "dev-feat-builder",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/query.git",
|
||||
"reference": "d40bf14fed0a5a92146d89cc6549518a2a559c8c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/query/zipball/d40bf14fed0a5a92146d89cc6549518a2a559c8c",
|
||||
"reference": "d40bf14fed0a5a92146d89cc6549518a2a559c8c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "*",
|
||||
"mongodb/mongodb": "^2.0",
|
||||
"phpstan/phpstan": "*",
|
||||
"phpunit/phpunit": "^12.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Utopia\\Query\\": "src/Query"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"description": "A simple library providing a query abstraction for filtering, ordering, and pagination",
|
||||
"keywords": [
|
||||
"framework",
|
||||
"php",
|
||||
"query",
|
||||
"upf",
|
||||
"utopia"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/query/issues",
|
||||
"source": "https://github.com/utopia-php/query/tree/feat-builder"
|
||||
},
|
||||
"time": "2026-03-31T02:21:12+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/queue",
|
||||
"version": "0.15.6",
|
||||
@@ -5439,16 +5690,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "1.14.0",
|
||||
"version": "1.16.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "7e7e257b10a8c1384a237e7d8d73452e2108901e"
|
||||
"reference": "d2a93863ec907cdcae283c3062d9a24192b909fc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/7e7e257b10a8c1384a237e7d8d73452e2108901e",
|
||||
"reference": "7e7e257b10a8c1384a237e7d8d73452e2108901e",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/d2a93863ec907cdcae283c3062d9a24192b909fc",
|
||||
"reference": "d2a93863ec907cdcae283c3062d9a24192b909fc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5484,22 +5735,22 @@
|
||||
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
||||
"support": {
|
||||
"issues": "https://github.com/appwrite/sdk-generator/issues",
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.14.0"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.16.5"
|
||||
},
|
||||
"time": "2026-03-26T12:50:11+00:00"
|
||||
"time": "2026-04-01T03:01:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brianium/paratest",
|
||||
"version": "v7.19.2",
|
||||
"version": "v7.20.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/paratestphp/paratest.git",
|
||||
"reference": "66e4f7910cecf67736bccf2b8bd53a2e3eb98bd9"
|
||||
"reference": "81c80677c9ec0ed4ef16b246167f11dec81a6e3d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/66e4f7910cecf67736bccf2b8bd53a2e3eb98bd9",
|
||||
"reference": "66e4f7910cecf67736bccf2b8bd53a2e3eb98bd9",
|
||||
"url": "https://api.github.com/repos/paratestphp/paratest/zipball/81c80677c9ec0ed4ef16b246167f11dec81a6e3d",
|
||||
"reference": "81c80677c9ec0ed4ef16b246167f11dec81a6e3d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5523,7 +5774,7 @@
|
||||
"ext-pcntl": "*",
|
||||
"ext-pcov": "*",
|
||||
"ext-posix": "*",
|
||||
"phpstan/phpstan": "^2.1.40",
|
||||
"phpstan/phpstan": "^2.1.44",
|
||||
"phpstan/phpstan-deprecation-rules": "^2.0.4",
|
||||
"phpstan/phpstan-phpunit": "^2.0.16",
|
||||
"phpstan/phpstan-strict-rules": "^2.0.10",
|
||||
@@ -5567,7 +5818,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/paratestphp/paratest/issues",
|
||||
"source": "https://github.com/paratestphp/paratest/tree/v7.19.2"
|
||||
"source": "https://github.com/paratestphp/paratest/tree/v7.20.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -5579,7 +5830,7 @@
|
||||
"type": "paypal"
|
||||
}
|
||||
],
|
||||
"time": "2026-03-09T14:33:17+00:00"
|
||||
"time": "2026-03-29T15:46:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "czproject/git-php",
|
||||
@@ -6195,11 +6446,11 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.1.44",
|
||||
"version": "2.1.46",
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/4a88c083c668b2c364a425c9b3171b2d9ea5d218",
|
||||
"reference": "4a88c083c668b2c364a425c9b3171b2d9ea5d218",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/a193923fc2d6325ef4e741cf3af8c3e8f54dbf25",
|
||||
"reference": "a193923fc2d6325ef4e741cf3af8c3e8f54dbf25",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6244,7 +6495,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-03-25T17:34:21+00:00"
|
||||
"time": "2026-04-01T09:25:14+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@@ -6594,16 +6845,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "12.5.14",
|
||||
"version": "12.5.15",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "47283cfd98d553edcb1353591f4e255dc1bb61f0"
|
||||
"reference": "aeb6899ffdbbf4b4ff5e6b6ebb77b35c51bb6d9a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/47283cfd98d553edcb1353591f4e255dc1bb61f0",
|
||||
"reference": "47283cfd98d553edcb1353591f4e255dc1bb61f0",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/aeb6899ffdbbf4b4ff5e6b6ebb77b35c51bb6d9a",
|
||||
"reference": "aeb6899ffdbbf4b4ff5e6b6ebb77b35c51bb6d9a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6625,7 +6876,7 @@
|
||||
"sebastian/cli-parser": "^4.2.0",
|
||||
"sebastian/comparator": "^7.1.4",
|
||||
"sebastian/diff": "^7.0.0",
|
||||
"sebastian/environment": "^8.0.3",
|
||||
"sebastian/environment": "^8.0.4",
|
||||
"sebastian/exporter": "^7.0.2",
|
||||
"sebastian/global-state": "^8.0.2",
|
||||
"sebastian/object-enumerator": "^7.0.0",
|
||||
@@ -6672,31 +6923,15 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.14"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/12.5.15"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://phpunit.de/sponsors.html",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/sebastianbergmann",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://liberapay.com/sebastianbergmann",
|
||||
"type": "liberapay"
|
||||
},
|
||||
{
|
||||
"url": "https://thanks.dev/u/gh/sebastianbergmann",
|
||||
"type": "thanks_dev"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
|
||||
"type": "tidelift"
|
||||
"url": "https://phpunit.de/sponsoring.html",
|
||||
"type": "other"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-18T12:38:40+00:00"
|
||||
"time": "2026-03-31T06:41:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
@@ -7681,16 +7916,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v8.0.7",
|
||||
"version": "v8.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a"
|
||||
"reference": "5b66d385dc58f69652e56f78a4184615e3f2b7f7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a",
|
||||
"reference": "15ed9008a4ebe2d6a78e4937f74e0c13ef2e618a",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/5b66d385dc58f69652e56f78a4184615e3f2b7f7",
|
||||
"reference": "5b66d385dc58f69652e56f78a4184615e3f2b7f7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -7747,7 +7982,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v8.0.7"
|
||||
"source": "https://github.com/symfony/console/tree/v8.0.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -7767,7 +8002,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-03-06T14:06:22+00:00"
|
||||
"time": "2026-03-30T15:14:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
@@ -8101,16 +8336,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "v8.0.5",
|
||||
"version": "v8.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/process.git",
|
||||
"reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674"
|
||||
"reference": "cb8939aff03470d1a9d1d1b66d08c6fa71b3bbdc"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674",
|
||||
"reference": "b5f3aa6762e33fd95efbaa2ec4f4bc9fdd16d674",
|
||||
"url": "https://api.github.com/repos/symfony/process/zipball/cb8939aff03470d1a9d1d1b66d08c6fa71b3bbdc",
|
||||
"reference": "cb8939aff03470d1a9d1d1b66d08c6fa71b3bbdc",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -8142,7 +8377,7 @@
|
||||
"description": "Executes commands in sub-processes",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/process/tree/v8.0.5"
|
||||
"source": "https://github.com/symfony/process/tree/v8.0.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8162,20 +8397,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-26T15:08:38+00:00"
|
||||
"time": "2026-03-30T15:14:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v8.0.6",
|
||||
"version": "v8.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4"
|
||||
"reference": "ae9488f874d7603f9d2dfbf120203882b645d963"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/6c9e1108041b5dce21a9a4984b531c4923aa9ec4",
|
||||
"reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/ae9488f874d7603f9d2dfbf120203882b645d963",
|
||||
"reference": "ae9488f874d7603f9d2dfbf120203882b645d963",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -8232,7 +8467,7 @@
|
||||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v8.0.6"
|
||||
"source": "https://github.com/symfony/string/tree/v8.0.8"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8252,7 +8487,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-09T10:14:57+00:00"
|
||||
"time": "2026-03-30T15:14:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "textalk/websocket",
|
||||
@@ -8433,9 +8668,32 @@
|
||||
"time": "2024-11-07T12:36:22+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
"aliases": [
|
||||
{
|
||||
"package": "utopia-php/audit",
|
||||
"version": "dev-feat-query-lib",
|
||||
"alias": "2.2.0",
|
||||
"alias_normalized": "2.2.0.0"
|
||||
},
|
||||
{
|
||||
"package": "utopia-php/database",
|
||||
"version": "dev-feat-query-lib",
|
||||
"alias": "5.3.17",
|
||||
"alias_normalized": "5.3.17.0"
|
||||
},
|
||||
{
|
||||
"package": "utopia-php/migration",
|
||||
"version": "dev-feat-query-lib",
|
||||
"alias": "1.8.0",
|
||||
"alias_normalized": "1.8.0.0"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {},
|
||||
"stability-flags": {
|
||||
"utopia-php/audit": 20,
|
||||
"utopia-php/database": 20,
|
||||
"utopia-php/migration": 20
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
|
||||
+1
-1
@@ -1362,7 +1362,7 @@ services:
|
||||
container_name: appwrite-redis
|
||||
command: >
|
||||
redis-server
|
||||
--maxmemory 512mb
|
||||
--maxmemory 2048mb
|
||||
--maxmemory-policy allkeys-lru
|
||||
--maxmemory-samples 5
|
||||
ports:
|
||||
|
||||
@@ -156,12 +156,6 @@ parameters:
|
||||
count: 1
|
||||
path: app/init/registers.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$hostname on left side of \?\? always exists and is not nullable\.$#'
|
||||
identifier: nullCoalesce.variable
|
||||
count: 1
|
||||
path: app/init/resources.php
|
||||
|
||||
-
|
||||
message: '#^Anonymous function has an unused use \$register\.$#'
|
||||
identifier: closure.unusedUse
|
||||
@@ -264,12 +258,6 @@ parameters:
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php
|
||||
|
||||
-
|
||||
message: '#^Variable \$relations in empty\(\) always exists and is not falsy\.$#'
|
||||
identifier: empty.variable
|
||||
count: 1
|
||||
path: src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Documents/Action.php
|
||||
|
||||
-
|
||||
message: '#^Anonymous function has an unused use \$dbForProject\.$#'
|
||||
identifier: closure.unusedUse
|
||||
|
||||
@@ -8,6 +8,7 @@ use Utopia\Database\Exception;
|
||||
use Utopia\Database\Exception\Timeout;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Query\Method;
|
||||
|
||||
/**
|
||||
* Service for managing transaction state and providing transaction-aware document operations
|
||||
@@ -578,7 +579,7 @@ class TransactionState
|
||||
|
||||
$selections = [];
|
||||
foreach ($queries as $query) {
|
||||
if ($query->getMethod() === Query::TYPE_SELECT) {
|
||||
if ($query->getMethod() === Method::Select) {
|
||||
$values = $query->getValues();
|
||||
foreach ($values as $value) {
|
||||
// Skip relationship selections (containing '.')
|
||||
@@ -627,13 +628,13 @@ class TransactionState
|
||||
foreach ($queries as $query) {
|
||||
$method = $query->getMethod();
|
||||
if (!\in_array($method, [
|
||||
Query::TYPE_LIMIT,
|
||||
Query::TYPE_OFFSET,
|
||||
Query::TYPE_CURSOR_AFTER,
|
||||
Query::TYPE_CURSOR_BEFORE,
|
||||
Query::TYPE_SELECT,
|
||||
Query::TYPE_ORDER_ASC,
|
||||
Query::TYPE_ORDER_DESC
|
||||
Method::Limit,
|
||||
Method::Offset,
|
||||
Method::CursorAfter,
|
||||
Method::CursorBefore,
|
||||
Method::Select,
|
||||
Method::OrderAsc,
|
||||
Method::OrderDesc
|
||||
])) {
|
||||
$filters[] = $query;
|
||||
}
|
||||
@@ -660,19 +661,19 @@ class TransactionState
|
||||
$docValue = $doc->getAttribute($attribute);
|
||||
|
||||
switch ($filter->getMethod()) {
|
||||
case Query::TYPE_EQUAL:
|
||||
case Method::Equal:
|
||||
if (!\in_array($docValue, $values)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Query::TYPE_NOT_EQUAL:
|
||||
case Method::NotEqual:
|
||||
if (\in_array($docValue, $values)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Query::TYPE_CONTAINS:
|
||||
case Method::Contains:
|
||||
$matches = false;
|
||||
foreach ($values as $value) {
|
||||
if (\is_array($docValue) && \in_array($value, $docValue)) {
|
||||
@@ -685,7 +686,7 @@ class TransactionState
|
||||
}
|
||||
break;
|
||||
|
||||
case Query::TYPE_STARTS_WITH:
|
||||
case Method::StartsWith:
|
||||
$matches = false;
|
||||
foreach ($values as $value) {
|
||||
if (\is_string($docValue) && \str_starts_with($docValue, $value)) {
|
||||
@@ -698,7 +699,7 @@ class TransactionState
|
||||
}
|
||||
break;
|
||||
|
||||
case Query::TYPE_ENDS_WITH:
|
||||
case Method::EndsWith:
|
||||
$matches = false;
|
||||
foreach ($values as $value) {
|
||||
if (\is_string($docValue) && \str_ends_with($docValue, $value)) {
|
||||
@@ -711,43 +712,43 @@ class TransactionState
|
||||
}
|
||||
break;
|
||||
|
||||
case Query::TYPE_GREATER:
|
||||
case Method::GreaterThan:
|
||||
if (!($docValue > $values[0])) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Query::TYPE_GREATER_EQUAL:
|
||||
case Method::GreaterThanEqual:
|
||||
if (!($docValue >= $values[0])) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Query::TYPE_LESSER:
|
||||
case Method::LessThan:
|
||||
if (!($docValue < $values[0])) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Query::TYPE_LESSER_EQUAL:
|
||||
case Method::LessThanEqual:
|
||||
if (!($docValue <= $values[0])) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Query::TYPE_IS_NULL:
|
||||
case Method::IsNull:
|
||||
if (!\is_null($docValue)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Query::TYPE_IS_NOT_NULL:
|
||||
case Method::IsNotNull:
|
||||
if (\is_null($docValue)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Query::TYPE_BETWEEN:
|
||||
case Method::Between:
|
||||
if (!($docValue >= $values[0] && $docValue <= $values[1])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Query\Method;
|
||||
|
||||
class Realtime extends MessagingAdapter
|
||||
{
|
||||
@@ -84,7 +85,7 @@ class Realtime extends MessagingAdapter
|
||||
|
||||
$data = [
|
||||
'strings' => $strings,
|
||||
'compiled' => RuntimeQuery::compile($queryGroup),
|
||||
'compiled' => RuntimeQuery::prepare($queryGroup),
|
||||
];
|
||||
|
||||
foreach ($roles as $role) {
|
||||
@@ -414,7 +415,7 @@ class Realtime extends MessagingAdapter
|
||||
{
|
||||
$queries = Query::parseQueries($queries);
|
||||
$stack = $queries;
|
||||
$allowed = implode(', ', RuntimeQuery::ALLOWED_QUERIES);
|
||||
$allowed = implode(', ', array_map(fn (Method $m) => $m->value, RuntimeQuery::ALLOWED_QUERIES));
|
||||
|
||||
while (!empty($stack)) {
|
||||
$query = array_pop($stack);
|
||||
@@ -422,15 +423,15 @@ class Realtime extends MessagingAdapter
|
||||
|
||||
if (!in_array($method, RuntimeQuery::ALLOWED_QUERIES, true)) {
|
||||
throw new QueryException(
|
||||
"Query method '{$method}' is not supported in Realtime queries. Allowed: {$allowed}"
|
||||
"Query method '{$method->value}' is not supported in Realtime queries. Allowed: {$allowed}"
|
||||
);
|
||||
}
|
||||
|
||||
if ($method === Query::TYPE_SELECT) {
|
||||
if ($method === Method::Select) {
|
||||
RuntimeQuery::validateSelectQuery($query);
|
||||
}
|
||||
|
||||
if (in_array($method, [Query::TYPE_AND, Query::TYPE_OR], true)) {
|
||||
if (in_array($method, [Method::And, Method::Or], true)) {
|
||||
\array_push($stack, ...$query->getValues());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace Appwrite\Migration;
|
||||
use Exception;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Console;
|
||||
use Utopia\Database\Attribute;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Conflict;
|
||||
@@ -252,15 +253,8 @@ abstract class Migration
|
||||
|
||||
$collection = $this->collections[$collectionType][$id];
|
||||
|
||||
$attributes = [];
|
||||
foreach ($collection['attributes'] as $attribute) {
|
||||
$attributes[] = new Document($attribute);
|
||||
}
|
||||
|
||||
$indexes = [];
|
||||
foreach ($collection['indexes'] as $index) {
|
||||
$indexes[] = new Document($index);
|
||||
}
|
||||
$attributes = $collection['attributes'];
|
||||
$indexes = $collection['indexes'];
|
||||
|
||||
try {
|
||||
$this->dbForProject->createCollection($name, $attributes, $indexes);
|
||||
@@ -309,7 +303,7 @@ abstract class Migration
|
||||
|
||||
$attributesToCreate = [];
|
||||
$attributes = $collection['attributes'];
|
||||
$attributeKeys = \array_column($collection['attributes'], '$id');
|
||||
$attributeKeys = \array_map(fn ($a) => $a->key, $collection['attributes']);
|
||||
|
||||
foreach ($attributeIds as $attributeId) {
|
||||
$attributeKey = \array_search($attributeId, $attributeKeys);
|
||||
@@ -318,12 +312,11 @@ abstract class Migration
|
||||
throw new Exception("Attribute {$attributeId} not found");
|
||||
}
|
||||
|
||||
$attribute = $attributes[$attributeKey];
|
||||
$attribute['filters'] ??= [];
|
||||
$attribute['default'] ??= null;
|
||||
$attribute['default'] = \in_array('json', $attribute['filters'])
|
||||
? \json_encode($attribute['default'])
|
||||
: $attribute['default'];
|
||||
$attribute = clone $attributes[$attributeKey];
|
||||
|
||||
if (\in_array('json', $attribute->filters) && $attribute->default !== null) {
|
||||
$attribute->default = \json_encode($attribute->default);
|
||||
}
|
||||
|
||||
$attributesToCreate[] = $attribute;
|
||||
}
|
||||
@@ -374,28 +367,21 @@ abstract class Migration
|
||||
|
||||
$attributes = $collection['attributes'];
|
||||
|
||||
$attributeKey = \array_search($attributeId, \array_column($attributes, '$id'));
|
||||
$attributeKey = \array_search($attributeId, \array_map(fn ($a) => $a->key, $attributes));
|
||||
|
||||
if ($attributeKey === false) {
|
||||
throw new Exception("Attribute {$attributeId} not found");
|
||||
}
|
||||
|
||||
$attribute = $attributes[$attributeKey];
|
||||
$filters = $attribute['filters'] ?? [];
|
||||
$default = $attribute['default'] ?? null;
|
||||
$attribute = clone $attributes[$attributeKey];
|
||||
|
||||
if (\in_array('json', $attribute->filters) && $attribute->default !== null) {
|
||||
$attribute->default = \json_encode($attribute->default);
|
||||
}
|
||||
|
||||
$database->createAttribute(
|
||||
collection: $collectionId,
|
||||
id: $attributeId,
|
||||
type: $attribute['type'],
|
||||
size: $attribute['size'],
|
||||
required: $attribute['required'],
|
||||
default: \in_array('json', $filters) ? \json_encode($default) : $default,
|
||||
signed: $attribute['signed'] ?? true,
|
||||
array: $attribute['array'] ?? false,
|
||||
format: $attribute['format'] ?? '',
|
||||
formatOptions: $attribute['formatOptions'] ?? [],
|
||||
filters: $filters,
|
||||
attribute: $attribute,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -432,21 +418,15 @@ abstract class Migration
|
||||
|
||||
$indexes = $collection['indexes'];
|
||||
|
||||
$indexKey = \array_search($indexId, \array_column($indexes, '$id'));
|
||||
$indexKey = \array_search($indexId, \array_map(fn ($i) => $i->key, $indexes));
|
||||
|
||||
if ($indexKey === false) {
|
||||
throw new Exception("Index {$indexId} not found");
|
||||
}
|
||||
|
||||
$index = $indexes[$indexKey];
|
||||
|
||||
$database->createIndex(
|
||||
collection: $collectionId,
|
||||
id: $indexId,
|
||||
type: $index['type'],
|
||||
attributes: $index['attributes'],
|
||||
lengths: $index['lengths'] ?? [],
|
||||
orders: $index['orders'] ?? []
|
||||
index: $indexes[$indexKey],
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\System\System;
|
||||
|
||||
class V15 extends Migration
|
||||
@@ -362,7 +363,7 @@ class V15 extends Migration
|
||||
$this->dbForProject->updateAttribute(
|
||||
collection: $table,
|
||||
id: $attribute,
|
||||
type: Database::VAR_DATETIME,
|
||||
type: ColumnType::Datetime->value,
|
||||
signed: false
|
||||
);
|
||||
} catch (\Throwable $th) {
|
||||
|
||||
@@ -7,6 +7,7 @@ use Utopia\Auth\Proofs\Password;
|
||||
use Utopia\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
|
||||
class V17 extends Migration
|
||||
{
|
||||
@@ -47,7 +48,7 @@ class V17 extends Migration
|
||||
$id = "bucket_{$bucket->getSequence()}";
|
||||
|
||||
try {
|
||||
$this->dbForProject->updateAttribute($id, 'mimeType', Database::VAR_STRING, 255, true, false);
|
||||
$this->dbForProject->updateAttribute($id, 'mimeType', ColumnType::String->value, 255, true, false);
|
||||
$this->dbForProject->purgeCachedCollection($id);
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning("'mimeType' from {$id}: {$th->getMessage()}");
|
||||
@@ -87,7 +88,7 @@ class V17 extends Migration
|
||||
/**
|
||||
* Update 'mimeType' attribute size (127->255)
|
||||
*/
|
||||
$this->dbForProject->updateAttribute($id, 'mimeType', Database::VAR_STRING, 255, true, false);
|
||||
$this->dbForProject->updateAttribute($id, 'mimeType', ColumnType::String->value, 255, true, false);
|
||||
$this->dbForProject->purgeCachedCollection($id);
|
||||
} catch (\Throwable $th) {
|
||||
Console::warning("'mimeType' from {$id}: {$th->getMessage()}");
|
||||
|
||||
@@ -8,6 +8,7 @@ use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
|
||||
class V18 extends Migration
|
||||
{
|
||||
@@ -56,7 +57,7 @@ class V18 extends Migration
|
||||
$collectionTable = "{$databaseTable}_collection_{$collection->getSequence()}";
|
||||
|
||||
foreach ($collection['attributes'] ?? [] as $attribute) {
|
||||
if ($attribute['type'] !== Database::VAR_FLOAT) {
|
||||
if ($attribute['type'] !== ColumnType::Float->value) {
|
||||
continue;
|
||||
}
|
||||
$this->changeAttributeInternalType($collectionTable, $attribute['key'], 'DOUBLE');
|
||||
@@ -87,7 +88,7 @@ class V18 extends Migration
|
||||
Console::log("Migrating Collection \"{$id}\"");
|
||||
|
||||
foreach ($collection['attributes'] ?? [] as $attribute) {
|
||||
if ($attribute['type'] !== Database::VAR_FLOAT) {
|
||||
if ($attribute['type'] !== ColumnType::Float->value) {
|
||||
continue;
|
||||
}
|
||||
$this->changeAttributeInternalType($id, $attribute['$id'], 'DOUBLE');
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Appwrite\Platform\Installer\Http\Installer;
|
||||
|
||||
use Appwrite\Platform\Installer\Runtime\State;
|
||||
use Appwrite\Platform\Installer\Server;
|
||||
use Swoole\Coroutine;
|
||||
use Utopia\Http\Adapter\Swoole\Request;
|
||||
use Utopia\Http\Adapter\Swoole\Response;
|
||||
use Utopia\Platform\Action;
|
||||
@@ -50,12 +51,17 @@ class Complete extends Action
|
||||
|
||||
$progressData = ($installId !== '') ? $state->readProgressFile($installId) : [];
|
||||
|
||||
if (!$sessionSecret) {
|
||||
$details = $progressData['details'][Server::STEP_ACCOUNT_SETUP] ?? [];
|
||||
if (!empty($details['sessionSecret'])) {
|
||||
$sessionSecret = $details['sessionSecret'];
|
||||
$sessionId = $sessionId ?: ($details['sessionId'] ?? '');
|
||||
$sessionExpire = $sessionExpire ?: ($details['sessionExpire'] ?? '');
|
||||
if (!$sessionSecret && $installId !== '') {
|
||||
for ($attempt = 0; $attempt < 10; $attempt++) {
|
||||
$progressData = $state->readProgressFile($installId);
|
||||
$details = $progressData['details'][Server::STEP_ACCOUNT_SETUP] ?? [];
|
||||
if (!empty($details['sessionSecret'])) {
|
||||
$sessionSecret = $details['sessionSecret'];
|
||||
$sessionId = $sessionId ?: ($details['sessionId'] ?? '');
|
||||
$sessionExpire = $sessionExpire ?: ($details['sessionExpire'] ?? '');
|
||||
break;
|
||||
}
|
||||
Coroutine::getCid() !== -1 ? Coroutine::sleep(0.5) : usleep(500_000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,9 @@ use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Adapter\Feature\Relationships as FeatureRelationships;
|
||||
use Utopia\Database\Adapter\Feature\Spatial;
|
||||
use Utopia\Database\Capability;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Domains\Domain;
|
||||
@@ -93,14 +96,14 @@ class Get extends Action
|
||||
'_APP_OPTIONS_FORCE_HTTPS' => System::getEnv('_APP_OPTIONS_FORCE_HTTPS'),
|
||||
'_APP_DOMAINS_NAMESERVERS' => System::getEnv('_APP_DOMAINS_NAMESERVERS'),
|
||||
'_APP_DB_ADAPTER' => System::getEnv('_APP_DB_ADAPTER', 'mariadb'),
|
||||
'supportForRelationships' => $adapter->getSupportForRelationships(),
|
||||
'supportForOperators' => $adapter->getSupportForOperators(),
|
||||
'supportForSpatials' => $adapter->getSupportForSpatialAttributes(),
|
||||
'supportForSpatialIndexNull' => $adapter->getSupportForSpatialIndexNull(),
|
||||
'supportForFulltextWildcard' => $adapter->getSupportForFulltextWildcardIndex(),
|
||||
'supportForMultipleFulltextIndexes' => $adapter->getSupportForMultipleFulltextIndexes(),
|
||||
'supportForAttributeResizing' => $adapter->getSupportForAttributeResizing(),
|
||||
'supportForSchemas' => $adapter->getSupportForSchemas(),
|
||||
'supportForRelationships' => $adapter instanceof FeatureRelationships,
|
||||
'supportForOperators' => $adapter->supports(Capability::Operators),
|
||||
'supportForSpatials' => $adapter instanceof Spatial,
|
||||
'supportForSpatialIndexNull' => $adapter->supports(Capability::SpatialIndexNull),
|
||||
'supportForFulltextWildcard' => $adapter->supports(Capability::FulltextWildcard),
|
||||
'supportForMultipleFulltextIndexes' => $adapter->supports(Capability::MultipleFulltextIndexes),
|
||||
'supportForAttributeResizing' => $adapter->supports(Capability::AttributeResizing),
|
||||
'supportForSchemas' => $adapter->supports(Capability::Schemas),
|
||||
'maxIndexLength' => $adapter->getMaxIndexLength(),
|
||||
'supportForIntegerIds' => $adapter->getIdAttributeType() === 'integer',
|
||||
]);
|
||||
|
||||
@@ -4,9 +4,9 @@ namespace Appwrite\Platform\Modules\Databases\Http\Databases;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Action as AppwriteAction;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Operator;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
|
||||
class Action extends AppwriteAction
|
||||
{
|
||||
@@ -43,7 +43,7 @@ class Action extends AppwriteAction
|
||||
{
|
||||
$relationshipKeys = [];
|
||||
foreach ($collection->getAttribute('attributes', []) as $attribute) {
|
||||
if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) {
|
||||
if ($attribute->getAttribute('type') === ColumnType::Relationship->value) {
|
||||
$relationshipKeys[$attribute->getAttribute('key')] = true;
|
||||
}
|
||||
}
|
||||
|
||||
+31
-26
@@ -8,6 +8,8 @@ use Appwrite\Extend\Exception;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Throwable;
|
||||
use Utopia\Database\Adapter\Feature\Spatial;
|
||||
use Utopia\Database\Capability;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
@@ -17,10 +19,13 @@ use Utopia\Database\Exception\Relationship as RelationshipException;
|
||||
use Utopia\Database\Exception\Structure as StructureException;
|
||||
use Utopia\Database\Exception\Truncate as TruncateException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\RelationSide;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Structure;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Platform\Action as UtopiaAction;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Query\Schema\ForeignKeyAction;
|
||||
use Utopia\Validator\Range;
|
||||
|
||||
abstract class Action extends UtopiaAction
|
||||
@@ -233,55 +238,55 @@ abstract class Action extends UtopiaAction
|
||||
$isCollections = $this->isCollectionsAPI();
|
||||
|
||||
return match ($type) {
|
||||
Database::VAR_BOOLEAN => $isCollections
|
||||
ColumnType::Boolean->value => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_BOOLEAN
|
||||
: UtopiaResponse::MODEL_COLUMN_BOOLEAN,
|
||||
|
||||
Database::VAR_INTEGER => $isCollections
|
||||
ColumnType::Integer->value => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_INTEGER
|
||||
: UtopiaResponse::MODEL_COLUMN_INTEGER,
|
||||
|
||||
Database::VAR_FLOAT => $isCollections
|
||||
ColumnType::Double->value => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_FLOAT
|
||||
: UtopiaResponse::MODEL_COLUMN_FLOAT,
|
||||
|
||||
Database::VAR_DATETIME => $isCollections
|
||||
ColumnType::Datetime->value => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_DATETIME
|
||||
: UtopiaResponse::MODEL_COLUMN_DATETIME,
|
||||
|
||||
Database::VAR_RELATIONSHIP => $isCollections
|
||||
ColumnType::Relationship->value => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_RELATIONSHIP
|
||||
: UtopiaResponse::MODEL_COLUMN_RELATIONSHIP,
|
||||
|
||||
Database::VAR_POINT => $isCollections
|
||||
ColumnType::Point->value => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_POINT
|
||||
: UtopiaResponse::MODEL_COLUMN_POINT,
|
||||
|
||||
Database::VAR_LINESTRING => $isCollections
|
||||
ColumnType::Linestring->value => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_LINE
|
||||
: UtopiaResponse::MODEL_COLUMN_LINE,
|
||||
|
||||
Database::VAR_POLYGON => $isCollections
|
||||
ColumnType::Polygon->value => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_POLYGON
|
||||
: UtopiaResponse::MODEL_COLUMN_POLYGON,
|
||||
|
||||
Database::VAR_VARCHAR => $isCollections
|
||||
ColumnType::Varchar->value => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_VARCHAR
|
||||
: UtopiaResponse::MODEL_COLUMN_VARCHAR,
|
||||
|
||||
Database::VAR_TEXT => $isCollections
|
||||
ColumnType::Text->value => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_TEXT
|
||||
: UtopiaResponse::MODEL_COLUMN_TEXT,
|
||||
|
||||
Database::VAR_MEDIUMTEXT => $isCollections
|
||||
ColumnType::MediumText->value => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_MEDIUMTEXT
|
||||
: UtopiaResponse::MODEL_COLUMN_MEDIUMTEXT,
|
||||
|
||||
Database::VAR_LONGTEXT => $isCollections
|
||||
ColumnType::LongText->value => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_LONGTEXT
|
||||
: UtopiaResponse::MODEL_COLUMN_LONGTEXT,
|
||||
|
||||
Database::VAR_STRING => match ($format) {
|
||||
ColumnType::String->value => match ($format) {
|
||||
APP_DATABASE_ATTRIBUTE_EMAIL => $isCollections
|
||||
? UtopiaResponse::MODEL_ATTRIBUTE_EMAIL
|
||||
: UtopiaResponse::MODEL_COLUMN_EMAIL,
|
||||
@@ -322,7 +327,7 @@ abstract class Action extends UtopiaAction
|
||||
$default = $attribute->getAttribute('default');
|
||||
$options = $attribute->getAttribute('options', []);
|
||||
|
||||
if (in_array($type, Database::SPATIAL_TYPES) && !$dbForProject->getAdapter()->getSupportForSpatialAttributes()) {
|
||||
if (in_array($type, [ColumnType::Point->value, ColumnType::Linestring->value, ColumnType::Polygon->value]) && !$dbForProject->getAdapter() instanceof Spatial) {
|
||||
throw new Exception($this->getSpatialTypeNotSupportedException(), params: [$type]);
|
||||
}
|
||||
|
||||
@@ -339,7 +344,7 @@ abstract class Action extends UtopiaAction
|
||||
}
|
||||
|
||||
if (!empty($format)) {
|
||||
if (!Structure::hasFormat($format, $type)) {
|
||||
if (!Structure::hasFormat($format, ColumnType::from($type))) {
|
||||
throw new Exception($this->getFormatUnsupportedException(), "Format $format not available for $type columns.");
|
||||
}
|
||||
}
|
||||
@@ -353,8 +358,8 @@ abstract class Action extends UtopiaAction
|
||||
throw new Exception($this->getDefaultUnsupportedException(), 'Cannot set default value for array ' . $this->getContext() . 's');
|
||||
}
|
||||
|
||||
if ($type === Database::VAR_RELATIONSHIP) {
|
||||
$options['side'] = Database::RELATION_SIDE_PARENT;
|
||||
if ($type === ColumnType::Relationship->value) {
|
||||
$options['side'] = RelationSide::Parent->value;
|
||||
$relatedCollection = $dbForProject->getDocument('database_' . $db->getSequence(), $options['relatedCollection'] ?? '');
|
||||
if ($relatedCollection->isEmpty()) {
|
||||
$parent = $this->isCollectionsAPI() ? 'collection' : 'table';
|
||||
@@ -384,8 +389,8 @@ abstract class Action extends UtopiaAction
|
||||
]);
|
||||
|
||||
if (
|
||||
!$dbForProject->getAdapter()->getSupportForSpatialIndexNull() &&
|
||||
\in_array($attribute->getAttribute('type'), Database::SPATIAL_TYPES) &&
|
||||
!$dbForProject->getAdapter()->supports(Capability::SpatialIndexNull) &&
|
||||
\in_array($attribute->getAttribute('type'), [ColumnType::Point->value, ColumnType::Linestring->value, ColumnType::Polygon->value]) &&
|
||||
$attribute->getAttribute('required')
|
||||
) {
|
||||
$hasData = $authorization->skip(fn () => $dbForProject
|
||||
@@ -412,11 +417,11 @@ abstract class Action extends UtopiaAction
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getSequence(), $collectionId);
|
||||
$dbForProject->purgeCachedCollection('database_' . $db->getSequence() . '_collection_' . $collection->getSequence());
|
||||
|
||||
if ($type === Database::VAR_RELATIONSHIP && $options['twoWay']) {
|
||||
if ($type === ColumnType::Relationship->value && $options['twoWay']) {
|
||||
$twoWayKey = $options['twoWayKey'];
|
||||
$options['relatedCollection'] = $collection->getId();
|
||||
$options['twoWayKey'] = $key;
|
||||
$options['side'] = Database::RELATION_SIDE_CHILD;
|
||||
$options['side'] = RelationSide::Child->value;
|
||||
|
||||
try {
|
||||
$twoWayAttribute = new Document([
|
||||
@@ -516,7 +521,7 @@ abstract class Action extends UtopiaAction
|
||||
throw new Exception($this->getTypeInvalidException());
|
||||
}
|
||||
|
||||
if ($attribute->getAttribute('type') === Database::VAR_STRING && $attribute->getAttribute(('filter') !== $filter)) {
|
||||
if ($attribute->getAttribute('type') === ColumnType::String->value && $attribute->getAttribute(('filter') !== $filter)) {
|
||||
throw new Exception($this->getTypeInvalidException());
|
||||
}
|
||||
|
||||
@@ -549,9 +554,9 @@ abstract class Action extends UtopiaAction
|
||||
}
|
||||
|
||||
if ($attribute->getAttribute('format') === APP_DATABASE_ATTRIBUTE_INT_RANGE) {
|
||||
$validator = new Range($min, $max, Database::VAR_INTEGER);
|
||||
$validator = new Range($min, $max, ColumnType::Integer->value);
|
||||
} else {
|
||||
$validator = new Range($min, $max, Database::VAR_FLOAT);
|
||||
$validator = new Range($min, $max, ColumnType::Double->value);
|
||||
|
||||
if (!is_null($default)) {
|
||||
$default = \floatval($default);
|
||||
@@ -593,7 +598,7 @@ abstract class Action extends UtopiaAction
|
||||
break;
|
||||
}
|
||||
|
||||
if ($type === Database::VAR_RELATIONSHIP) {
|
||||
if ($type === ColumnType::Relationship->value) {
|
||||
$primaryDocumentOptions = \array_merge($attribute->getAttribute('options', []), $options);
|
||||
$attribute->setAttribute('options', $primaryDocumentOptions);
|
||||
try {
|
||||
@@ -601,7 +606,7 @@ abstract class Action extends UtopiaAction
|
||||
collection: $collectionId,
|
||||
id: $key,
|
||||
newKey: $newKey,
|
||||
onDelete: $primaryDocumentOptions['onDelete'],
|
||||
onDelete: ForeignKeyAction::from($primaryDocumentOptions['onDelete']),
|
||||
);
|
||||
} catch (IndexException) {
|
||||
throw new Exception(Exception::INDEX_INVALID);
|
||||
|
||||
+2
-1
@@ -16,6 +16,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -78,7 +79,7 @@ class Create extends Action
|
||||
{
|
||||
$attribute = $this->createAttribute($databaseId, $collectionId, new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_BOOLEAN,
|
||||
'type' => ColumnType::Boolean->value,
|
||||
'size' => 0,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -82,7 +83,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_BOOLEAN,
|
||||
type: ColumnType::Boolean->value,
|
||||
default: $default,
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -82,7 +83,7 @@ class Create extends Action
|
||||
$collectionId,
|
||||
new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_DATETIME,
|
||||
'type' => ColumnType::Datetime->value,
|
||||
'size' => 0,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -16,6 +16,7 @@ use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -83,7 +84,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_DATETIME,
|
||||
type: ColumnType::Datetime->value,
|
||||
default: $default,
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
|
||||
+4
-2
@@ -11,6 +11,7 @@ use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Utopia\Database\Capability;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
@@ -18,6 +19,7 @@ use Utopia\Database\Validator\IndexDependency as IndexDependencyValidator;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
|
||||
class Delete extends Action
|
||||
{
|
||||
@@ -91,7 +93,7 @@ class Delete extends Action
|
||||
|
||||
$validator = new IndexDependencyValidator(
|
||||
$collection->getAttribute('indexes'),
|
||||
$dbForProject->getAdapter()->getSupportForCastIndexArray(),
|
||||
$dbForProject->getAdapter()->supports(Capability::CastIndexArray),
|
||||
);
|
||||
|
||||
if (!$validator->isValid($attribute)) {
|
||||
@@ -106,7 +108,7 @@ class Delete extends Action
|
||||
$dbForProject->purgeCachedDocument('database_' . $db->getSequence(), $collectionId);
|
||||
$dbForProject->purgeCachedCollection('database_' . $db->getSequence() . '_collection_' . $collection->getSequence());
|
||||
|
||||
if ($attribute->getAttribute('type') === Database::VAR_RELATIONSHIP) {
|
||||
if ($attribute->getAttribute('type') === ColumnType::Relationship->value) {
|
||||
$options = $attribute->getAttribute('options');
|
||||
if ($options['twoWay']) {
|
||||
$relatedCollection = $dbForProject->getDocument('database_' . $db->getSequence(), $options['relatedCollection']);
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Emails\Validator\Email;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -82,7 +83,7 @@ class Create extends Action
|
||||
$collectionId,
|
||||
new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_STRING,
|
||||
'type' => ColumnType::String->value,
|
||||
'size' => 254,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -16,6 +16,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Emails\Validator\Email;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -83,7 +84,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_STRING,
|
||||
type: ColumnType::String->value,
|
||||
filter: APP_DATABASE_ATTRIBUTE_EMAIL,
|
||||
default: $default,
|
||||
required: $required,
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -89,7 +90,7 @@ class Create extends Action
|
||||
$collectionId,
|
||||
new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_STRING,
|
||||
'type' => ColumnType::String->value,
|
||||
'size' => Database::LENGTH_KEY,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -85,7 +86,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_STRING,
|
||||
type: ColumnType::String->value,
|
||||
filter: APP_DATABASE_ATTRIBUTE_ENUM,
|
||||
default: $default,
|
||||
required: $required,
|
||||
|
||||
+3
-2
@@ -17,6 +17,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\FloatValidator;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -88,14 +89,14 @@ class Create extends Action
|
||||
throw new Exception($this->getInvalidValueException(), 'Minimum value must be lesser than maximum value');
|
||||
}
|
||||
|
||||
$validator = new Range($min, $max, Database::VAR_FLOAT);
|
||||
$validator = new Range($min, $max, ColumnType::Double->value);
|
||||
if (!\is_null($default) && !$validator->isValid($default)) {
|
||||
throw new Exception($this->getInvalidValueException(), $validator->getDescription());
|
||||
}
|
||||
|
||||
$attribute = $this->createAttribute($databaseId, $collectionId, new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_FLOAT,
|
||||
'type' => ColumnType::Double->value,
|
||||
'size' => 0,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\FloatValidator;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -85,7 +86,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_FLOAT,
|
||||
type: ColumnType::Double->value,
|
||||
default: $default,
|
||||
required: $required,
|
||||
min: $min,
|
||||
|
||||
+2
-1
@@ -16,6 +16,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\IP;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -82,7 +83,7 @@ class Create extends Action
|
||||
$collectionId,
|
||||
new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_STRING,
|
||||
'type' => ColumnType::String->value,
|
||||
'size' => 39,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\IP;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -83,7 +84,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_STRING,
|
||||
type: ColumnType::String->value,
|
||||
filter: APP_DATABASE_ATTRIBUTE_IP,
|
||||
default: $default,
|
||||
required: $required,
|
||||
|
||||
+3
-2
@@ -17,6 +17,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Integer;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -88,7 +89,7 @@ class Create extends Action
|
||||
throw new Exception($this->getInvalidValueException(), 'Minimum value must be lesser than maximum value');
|
||||
}
|
||||
|
||||
$validator = new Range($min, $max, Database::VAR_INTEGER);
|
||||
$validator = new Range($min, $max, ColumnType::Integer->value);
|
||||
if (!\is_null($default) && !$validator->isValid($default)) {
|
||||
throw new Exception($this->getInvalidValueException(), $validator->getDescription());
|
||||
}
|
||||
@@ -97,7 +98,7 @@ class Create extends Action
|
||||
|
||||
$attribute = $this->createAttribute($databaseId, $collectionId, new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_INTEGER,
|
||||
'type' => ColumnType::Integer->value,
|
||||
'size' => $size,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Integer;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -85,7 +86,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_INTEGER,
|
||||
type: ColumnType::Integer->value,
|
||||
default: $default,
|
||||
required: $required,
|
||||
min: $min,
|
||||
|
||||
+5
-3
@@ -11,6 +11,7 @@ use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Utopia\Database\Adapter\Feature\Spatial as SpatialFeature;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
@@ -18,6 +19,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Spatial;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -66,7 +68,7 @@ class Create extends Action
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_LINESTRING)), 'Default value for attribute when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when attribute is required.', true)
|
||||
->param('default', null, new Nullable(new Spatial(ColumnType::Linestring->value)), 'Default value for attribute when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when attribute is required.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForDatabase')
|
||||
@@ -77,13 +79,13 @@ class Create extends Action
|
||||
|
||||
public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void
|
||||
{
|
||||
if (!$dbForProject->getAdapter()->getSupportForSpatialAttributes()) {
|
||||
if (!$dbForProject->getAdapter() instanceof SpatialFeature) {
|
||||
throw new Exception(Exception::GENERAL_FEATURE_UNSUPPORTED, 'Spatial columns are not supported by this database.');
|
||||
}
|
||||
|
||||
$attribute = $this->createAttribute($databaseId, $collectionId, new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_LINESTRING,
|
||||
'type' => ColumnType::Linestring->value,
|
||||
'required' => $required,
|
||||
'default' => $default
|
||||
]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization);
|
||||
|
||||
+5
-3
@@ -11,12 +11,14 @@ use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Utopia\Database\Adapter\Feature\Spatial as SpatialFeature;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Spatial;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -66,7 +68,7 @@ class Update extends Action
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_LINESTRING)), 'Default value for attribute when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when attribute is required.', true)
|
||||
->param('default', null, new Nullable(new Spatial(ColumnType::Linestring->value)), 'Default value for attribute when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when attribute is required.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New attribute key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -77,7 +79,7 @@ class Update extends Action
|
||||
|
||||
public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void
|
||||
{
|
||||
if (!$dbForProject->getAdapter()->getSupportForSpatialAttributes()) {
|
||||
if (!$dbForProject->getAdapter() instanceof SpatialFeature) {
|
||||
throw new Exception(Exception::GENERAL_FEATURE_UNSUPPORTED, 'Spatial columns are not supported by this database.');
|
||||
}
|
||||
|
||||
@@ -88,7 +90,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_LINESTRING,
|
||||
type: ColumnType::Linestring->value,
|
||||
default: $default,
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Http\Http;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
@@ -103,7 +104,7 @@ class Create extends Action
|
||||
$collectionId,
|
||||
new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_LONGTEXT,
|
||||
'type' => ColumnType::LongText->value,
|
||||
'size' => 2147483647,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -14,6 +14,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
@@ -88,7 +89,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_LONGTEXT,
|
||||
type: ColumnType::LongText->value,
|
||||
default: $default,
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Http\Http;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
@@ -103,7 +104,7 @@ class Create extends Action
|
||||
$collectionId,
|
||||
new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_MEDIUMTEXT,
|
||||
'type' => ColumnType::MediumText->value,
|
||||
'size' => 16777215,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -14,6 +14,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
@@ -88,7 +89,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_MEDIUMTEXT,
|
||||
type: ColumnType::MediumText->value,
|
||||
default: $default,
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
|
||||
+5
-3
@@ -11,6 +11,7 @@ use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Utopia\Database\Adapter\Feature\Spatial as SpatialFeature;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
@@ -18,6 +19,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Spatial;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -66,7 +68,7 @@ class Create extends Action
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_POINT)), 'Default value for attribute when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when attribute is required.', true)
|
||||
->param('default', null, new Nullable(new Spatial(ColumnType::Point->value)), 'Default value for attribute when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when attribute is required.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForDatabase')
|
||||
@@ -77,13 +79,13 @@ class Create extends Action
|
||||
|
||||
public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void
|
||||
{
|
||||
if (!$dbForProject->getAdapter()->getSupportForSpatialAttributes()) {
|
||||
if (!$dbForProject->getAdapter() instanceof SpatialFeature) {
|
||||
throw new Exception(Exception::GENERAL_FEATURE_UNSUPPORTED, 'Spatial columns are not supported by this database.');
|
||||
}
|
||||
|
||||
$attribute = $this->createAttribute($databaseId, $collectionId, new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_POINT,
|
||||
'type' => ColumnType::Point->value,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization);
|
||||
|
||||
+5
-3
@@ -11,12 +11,14 @@ use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Utopia\Database\Adapter\Feature\Spatial as SpatialFeature;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Spatial;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -66,7 +68,7 @@ class Update extends Action
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_POINT)), 'Default value for attribute when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when attribute is required.', true)
|
||||
->param('default', null, new Nullable(new Spatial(ColumnType::Point->value)), 'Default value for attribute when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when attribute is required.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New attribute key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -77,7 +79,7 @@ class Update extends Action
|
||||
|
||||
public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void
|
||||
{
|
||||
if (!$dbForProject->getAdapter()->getSupportForSpatialAttributes()) {
|
||||
if (!$dbForProject->getAdapter() instanceof SpatialFeature) {
|
||||
throw new Exception(Exception::GENERAL_FEATURE_UNSUPPORTED, 'Spatial columns are not supported by this database.');
|
||||
}
|
||||
|
||||
@@ -88,7 +90,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_POINT,
|
||||
type: ColumnType::Point->value,
|
||||
default: $default,
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
|
||||
+5
-3
@@ -11,6 +11,7 @@ use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Utopia\Database\Adapter\Feature\Spatial as SpatialFeature;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
@@ -18,6 +19,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Spatial;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -66,7 +68,7 @@ class Create extends Action
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_POLYGON)), 'Default value for attribute when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when attribute is required.', true)
|
||||
->param('default', null, new Nullable(new Spatial(ColumnType::Polygon->value)), 'Default value for attribute when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when attribute is required.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForDatabase')
|
||||
@@ -77,13 +79,13 @@ class Create extends Action
|
||||
|
||||
public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void
|
||||
{
|
||||
if (!$dbForProject->getAdapter()->getSupportForSpatialAttributes()) {
|
||||
if (!$dbForProject->getAdapter() instanceof SpatialFeature) {
|
||||
throw new Exception(Exception::GENERAL_FEATURE_UNSUPPORTED, 'Spatial columns are not supported by this database.');
|
||||
}
|
||||
|
||||
$attribute = $this->createAttribute($databaseId, $collectionId, new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_POLYGON,
|
||||
'type' => ColumnType::Polygon->value,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
]), $response, $dbForProject, $queueForDatabase, $queueForEvents, $authorization);
|
||||
|
||||
+5
-3
@@ -11,12 +11,14 @@ use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Utopia\Database\Adapter\Feature\Spatial as SpatialFeature;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Spatial;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -66,7 +68,7 @@ class Update extends Action
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is attribute required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_POLYGON)), 'Default value for attribute when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when attribute is required.', true)
|
||||
->param('default', null, new Nullable(new Spatial(ColumnType::Polygon->value)), 'Default value for attribute when not provided, three-dimensional array where the outer array holds one or more linear rings, [[[longitude, latitude], …], …], the first ring is the exterior boundary, any additional rings are interior holes, and each ring must start and end with the same coordinate pair. Cannot be set when attribute is required.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New attribute key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -77,7 +79,7 @@ class Update extends Action
|
||||
|
||||
public function action(string $databaseId, string $collectionId, string $key, ?bool $required, ?array $default, ?string $newKey, UtopiaResponse $response, Database $dbForProject, Event $queueForEvents, Authorization $authorization): void
|
||||
{
|
||||
if (!$dbForProject->getAdapter()->getSupportForSpatialAttributes()) {
|
||||
if (!$dbForProject->getAdapter() instanceof SpatialFeature) {
|
||||
throw new Exception(Exception::GENERAL_FEATURE_UNSUPPORTED, 'Spatial columns are not supported by this database.');
|
||||
}
|
||||
|
||||
@@ -88,7 +90,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_POLYGON,
|
||||
type: ColumnType::Polygon->value,
|
||||
default: $default,
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
|
||||
+17
-13
@@ -11,12 +11,16 @@ use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Utopia\Database\Adapter\Feature\Relationships as FeatureRelationships;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\RelationType;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Query\Schema\ForeignKeyAction;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\WhiteList;
|
||||
@@ -66,18 +70,18 @@ class Create extends Action
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('relatedCollectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Related Collection ID.', false, ['dbForProject'])
|
||||
->param('type', '', new WhiteList([
|
||||
Database::RELATION_ONE_TO_ONE,
|
||||
Database::RELATION_MANY_TO_ONE,
|
||||
Database::RELATION_MANY_TO_MANY,
|
||||
Database::RELATION_ONE_TO_MANY
|
||||
RelationType::OneToOne->value,
|
||||
RelationType::ManyToOne->value,
|
||||
RelationType::ManyToMany->value,
|
||||
RelationType::OneToMany->value
|
||||
], true), 'Relation type')
|
||||
->param('twoWay', false, new Boolean(), 'Is Two Way?', true)
|
||||
->param('key', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'Attribute Key.', true, ['dbForProject'])
|
||||
->param('twoWayKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'Two Way Attribute Key.', true, ['dbForProject'])
|
||||
->param('onDelete', Database::RELATION_MUTATE_RESTRICT, new WhiteList([
|
||||
Database::RELATION_MUTATE_CASCADE,
|
||||
Database::RELATION_MUTATE_RESTRICT,
|
||||
Database::RELATION_MUTATE_SET_NULL
|
||||
->param('onDelete', ForeignKeyAction::Restrict->value, new WhiteList([
|
||||
ForeignKeyAction::Cascade->value,
|
||||
ForeignKeyAction::Restrict->value,
|
||||
ForeignKeyAction::SetNull->value
|
||||
], true), 'Constraints option', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -89,7 +93,7 @@ class Create extends Action
|
||||
|
||||
public function action(string $databaseId, string $collectionId, string $relatedCollectionId, string $type, bool $twoWay, ?string $key, ?string $twoWayKey, string $onDelete, UtopiaResponse $response, Database $dbForProject, EventDatabase $queueForDatabase, Event $queueForEvents, Authorization $authorization): void
|
||||
{
|
||||
if (!$dbForProject->getAdapter()->getSupportForRelationships()) {
|
||||
if (!$dbForProject->getAdapter() instanceof FeatureRelationships) {
|
||||
throw new Exception(Exception::GENERAL_FEATURE_UNSUPPORTED, 'Relationships are not supported by this database.');
|
||||
}
|
||||
|
||||
@@ -116,7 +120,7 @@ class Create extends Action
|
||||
|
||||
$attributes = $collection->getAttribute('attributes', []);
|
||||
foreach ($attributes as $attribute) {
|
||||
if ($attribute->getAttribute('type') !== Database::VAR_RELATIONSHIP) {
|
||||
if ($attribute->getAttribute('type') !== ColumnType::Relationship->value) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -135,8 +139,8 @@ class Create extends Action
|
||||
}
|
||||
|
||||
if (
|
||||
$type === Database::RELATION_MANY_TO_MANY &&
|
||||
$attribute->getAttribute('options')['relationType'] === Database::RELATION_MANY_TO_MANY &&
|
||||
$type === RelationType::ManyToMany->value &&
|
||||
$attribute->getAttribute('options')['relationType'] === RelationType::ManyToMany->value &&
|
||||
$attribute->getAttribute('options')['relatedCollection'] === $relatedCollection->getId()
|
||||
) {
|
||||
$parentType = $this->isCollectionsAPI() ? 'collection' : 'table';
|
||||
@@ -146,7 +150,7 @@ class Create extends Action
|
||||
|
||||
$attribute = $this->createAttribute($databaseId, $collectionId, new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_RELATIONSHIP,
|
||||
'type' => ColumnType::Relationship->value,
|
||||
'size' => 0,
|
||||
'required' => false,
|
||||
'default' => null,
|
||||
|
||||
+8
-5
@@ -11,11 +11,14 @@ use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Utopia\Database\Adapter\Feature\Relationships as FeatureRelationships;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Query\Schema\ForeignKeyAction;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
@@ -66,9 +69,9 @@ class Update extends Action
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Attribute Key.', false, ['dbForProject'])
|
||||
->param('onDelete', null, new WhiteList([
|
||||
Database::RELATION_MUTATE_CASCADE,
|
||||
Database::RELATION_MUTATE_RESTRICT,
|
||||
Database::RELATION_MUTATE_SET_NULL
|
||||
ForeignKeyAction::Cascade->value,
|
||||
ForeignKeyAction::Restrict->value,
|
||||
ForeignKeyAction::SetNull->value
|
||||
], true), 'Constraints option', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New Attribute Key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
@@ -89,7 +92,7 @@ class Update extends Action
|
||||
Event $queueForEvents,
|
||||
Authorization $authorization
|
||||
): void {
|
||||
if (!$dbForProject->getAdapter()->getSupportForRelationships()) {
|
||||
if (!$dbForProject->getAdapter() instanceof FeatureRelationships) {
|
||||
throw new Exception(Exception::GENERAL_FEATURE_UNSUPPORTED, 'Relationships are not supported by this database.');
|
||||
}
|
||||
|
||||
@@ -100,7 +103,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_RELATIONSHIP,
|
||||
type: ColumnType::Relationship->value,
|
||||
required: false,
|
||||
options: [
|
||||
'onDelete' => $onDelete
|
||||
|
||||
+2
-1
@@ -18,6 +18,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Http\Http;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -125,7 +126,7 @@ class Create extends Action
|
||||
$collectionId,
|
||||
new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_STRING,
|
||||
'type' => ColumnType::String->value,
|
||||
'size' => $size,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -97,7 +98,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_STRING,
|
||||
type: ColumnType::String->value,
|
||||
size: $size,
|
||||
default: $default,
|
||||
required: $required,
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Http\Http;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
@@ -103,7 +104,7 @@ class Create extends Action
|
||||
$collectionId,
|
||||
new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_TEXT,
|
||||
'type' => ColumnType::Text->value,
|
||||
'size' => 65535,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -14,6 +14,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
@@ -88,7 +89,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_TEXT,
|
||||
type: ColumnType::Text->value,
|
||||
default: $default,
|
||||
required: $required,
|
||||
newKey: $newKey
|
||||
|
||||
+2
-1
@@ -16,6 +16,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\URL;
|
||||
@@ -90,7 +91,7 @@ class Create extends Action
|
||||
): void {
|
||||
$attribute = $this->createAttribute($databaseId, $collectionId, new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_STRING,
|
||||
'type' => ColumnType::String->value,
|
||||
'size' => 2000,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -15,6 +15,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\URL;
|
||||
@@ -93,7 +94,7 @@ class Update extends Action
|
||||
$dbForProject,
|
||||
$queueForEvents,
|
||||
$authorization,
|
||||
type: Database::VAR_STRING,
|
||||
type: ColumnType::String->value,
|
||||
filter: APP_DATABASE_ATTRIBUTE_URL,
|
||||
default: $default,
|
||||
required: $required,
|
||||
|
||||
+2
-1
@@ -17,6 +17,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Http\Http;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -120,7 +121,7 @@ class Create extends Action
|
||||
$collectionId,
|
||||
new Document([
|
||||
'key' => $key,
|
||||
'type' => Database::VAR_VARCHAR,
|
||||
'type' => ColumnType::Varchar->value,
|
||||
'size' => $size,
|
||||
'required' => $required,
|
||||
'default' => $default,
|
||||
|
||||
+2
-1
@@ -14,6 +14,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -92,7 +93,7 @@ class Update extends Action
|
||||
dbForProject: $dbForProject,
|
||||
queueForEvents: $queueForEvents,
|
||||
authorization: $authorization,
|
||||
type: Database::VAR_VARCHAR,
|
||||
type: ColumnType::Varchar->value,
|
||||
size: $size,
|
||||
default: $default,
|
||||
required: $required,
|
||||
|
||||
+4
-2
@@ -18,6 +18,8 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Query\Cursor;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Method as QueryMethod;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
|
||||
class XList extends Action
|
||||
@@ -94,7 +96,7 @@ class XList extends Action
|
||||
|
||||
$cursor = \array_filter(
|
||||
$queries,
|
||||
fn ($query) => \in_array($query->getMethod(), [Query::TYPE_CURSOR_AFTER, Query::TYPE_CURSOR_BEFORE])
|
||||
fn ($query) => \in_array($query->getMethod(), [QueryMethod::CursorAfter, QueryMethod::CursorBefore])
|
||||
);
|
||||
$cursor = \reset($cursor);
|
||||
|
||||
@@ -136,7 +138,7 @@ class XList extends Action
|
||||
}
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
if ($attribute->getAttribute('type') === Database::VAR_STRING) {
|
||||
if ($attribute->getAttribute('type') === ColumnType::String->value) {
|
||||
$filters = $attribute->getAttribute('filters', []);
|
||||
$attribute->setAttribute('encrypt', in_array('encrypt', $filters));
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@ use Appwrite\Utopia\Database\Validator\Attributes as AttributesValidator;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Database\Validator\Indexes as IndexesValidator;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Utopia\Database\Adapter\Feature\SchemaAttributes;
|
||||
use Utopia\Database\Adapter\Feature\Spatial;
|
||||
use Utopia\Database\Capability;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
@@ -26,6 +29,7 @@ use Utopia\Database\Validator\Index as IndexValidator;
|
||||
use Utopia\Database\Validator\Permissions;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\JSON;
|
||||
@@ -125,15 +129,15 @@ class Create extends Action
|
||||
/**
|
||||
* @var Database $dbForDatabases
|
||||
*/
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
|
||||
$collectionKey = 'database_' . $database->getSequence() . '_collection_' . $collection->getSequence();
|
||||
$databaseKey = 'database_' . $database->getSequence();
|
||||
|
||||
$attributesValidator = new AttributesValidator(
|
||||
APP_LIMIT_ARRAY_PARAMS_SIZE,
|
||||
$dbForDatabases->getAdapter()->getSupportForSpatialAttributes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForAttributes()
|
||||
$dbForDatabases->getAdapter() instanceof Spatial,
|
||||
$dbForDatabases->getAdapter() instanceof SchemaAttributes
|
||||
);
|
||||
|
||||
if (!$attributesValidator->isValid($attributes)) {
|
||||
@@ -142,7 +146,7 @@ class Create extends Action
|
||||
}
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
if (($attribute['type'] ?? '') === Database::VAR_RELATIONSHIP) {
|
||||
if (($attribute['type'] ?? '') === ColumnType::Relationship->value) {
|
||||
$dbForProject->deleteDocument($databaseKey, $collection->getId());
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Relationship attributes cannot be created inline. Use the create relationship endpoint instead.');
|
||||
}
|
||||
@@ -187,21 +191,21 @@ class Create extends Action
|
||||
[],
|
||||
$dbForDatabases->getAdapter()->getMaxIndexLength(),
|
||||
$dbForDatabases->getAdapter()->getInternalIndexesKeys(),
|
||||
$dbForDatabases->getAdapter()->getSupportForIndexArray(),
|
||||
$dbForDatabases->getAdapter()->getSupportForSpatialIndexNull(),
|
||||
$dbForDatabases->getAdapter()->getSupportForSpatialIndexOrder(),
|
||||
$dbForDatabases->getAdapter()->getSupportForVectors(),
|
||||
$dbForDatabases->getAdapter()->getSupportForAttributes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForMultipleFulltextIndexes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForIdenticalIndexes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForObjectIndexes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForTrigramIndex(),
|
||||
$dbForDatabases->getAdapter()->getSupportForSpatialAttributes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForIndex(),
|
||||
$dbForDatabases->getAdapter()->getSupportForUniqueIndex(),
|
||||
$dbForDatabases->getAdapter()->getSupportForFulltextIndex(),
|
||||
$dbForDatabases->getAdapter()->getSupportForTTLIndexes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForObject(),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::IndexArray),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::SpatialIndexNull),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::SpatialIndexOrder),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::Vectors),
|
||||
$dbForDatabases->getAdapter() instanceof SchemaAttributes,
|
||||
$dbForDatabases->getAdapter()->supports(Capability::MultipleFulltextIndexes),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::IdenticalIndexes),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::ObjectIndexes),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::TrigramIndex),
|
||||
$dbForDatabases->getAdapter() instanceof Spatial,
|
||||
$dbForDatabases->getAdapter()->supports(Capability::Index),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::UniqueIndex),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::Fulltext),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::TTLIndexes),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::Objects),
|
||||
);
|
||||
|
||||
foreach ($collectionIndexes as $indexDoc) {
|
||||
@@ -217,7 +221,8 @@ class Create extends Action
|
||||
attributes: $collectionAttributes,
|
||||
indexes: $collectionIndexes,
|
||||
permissions: $permissions,
|
||||
documentSecurity: $documentSecurity
|
||||
documentSecurity: $documentSecurity,
|
||||
metadata: ['externalId' => $collectionId],
|
||||
);
|
||||
} catch (DuplicateException) {
|
||||
$dbForProject->deleteDocument($databaseKey, $collection->getId());
|
||||
@@ -275,7 +280,9 @@ class Create extends Action
|
||||
array $attribute,
|
||||
): array {
|
||||
$key = $attribute['key'];
|
||||
$type = $attribute['type'];
|
||||
$type = $attribute['type'] === ColumnType::Float->value
|
||||
? ColumnType::Double->value
|
||||
: $attribute['type'];
|
||||
$size = $attribute['size'] ?? 0;
|
||||
$required = $attribute['required'] ?? false;
|
||||
$signed = $attribute['signed'] ?? true;
|
||||
@@ -290,13 +297,13 @@ class Create extends Action
|
||||
}
|
||||
|
||||
if (isset($attribute['min']) || isset($attribute['max'])) {
|
||||
$format = $type === Database::VAR_INTEGER
|
||||
$format = $type === ColumnType::Integer->value
|
||||
? APP_DATABASE_ATTRIBUTE_INT_RANGE
|
||||
: APP_DATABASE_ATTRIBUTE_FLOAT_RANGE;
|
||||
|
||||
$formatOptions = [
|
||||
'min' => $attribute['min'] ?? ($type === Database::VAR_INTEGER ? \PHP_INT_MIN : -\PHP_FLOAT_MAX),
|
||||
'max' => $attribute['max'] ?? ($type === Database::VAR_INTEGER ? \PHP_INT_MAX : \PHP_FLOAT_MAX),
|
||||
'min' => $attribute['min'] ?? ($type === ColumnType::Integer->value ? \PHP_INT_MIN : -\PHP_FLOAT_MAX),
|
||||
'max' => $attribute['max'] ?? ($type === ColumnType::Integer->value ? \PHP_INT_MAX : \PHP_FLOAT_MAX),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -86,7 +86,7 @@ class Delete extends Action
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, "Failed to remove $type from DB");
|
||||
}
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
$dbForDatabases->purgeCachedCollection('database_' . $database->getSequence() . '_collection_' . $collection->getSequence());
|
||||
|
||||
$queueForDatabase
|
||||
|
||||
+1
-97
@@ -9,7 +9,6 @@ use Appwrite\Platform\Modules\Databases\Http\Databases\Action as DatabasesAction
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
|
||||
abstract class Action extends DatabasesAction
|
||||
{
|
||||
@@ -318,102 +317,6 @@ abstract class Action extends DatabasesAction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves relationships in a document and attaches metadata.
|
||||
*/
|
||||
protected function processDocument(
|
||||
/* database */
|
||||
Document $database,
|
||||
Document $collection,
|
||||
Document $document,
|
||||
Database $dbForProject,
|
||||
/* options */
|
||||
array &$collectionsCache,
|
||||
Authorization $authorization,
|
||||
?int &$operations = null,
|
||||
int $depth = 0,
|
||||
): bool {
|
||||
if ($operations !== null && $document->isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($operations !== null) {
|
||||
$operations++;
|
||||
}
|
||||
|
||||
$collectionId = $collection->getId();
|
||||
$document->removeAttribute('$collection');
|
||||
$document->setAttribute('$databaseId', $database->getId());
|
||||
$document->setAttribute('$' . $this->getCollectionsEventsContext() . 'Id', $collectionId);
|
||||
|
||||
// Stop processing relationships if max depth reached
|
||||
if ($depth >= Database::RELATION_MAX_DEPTH) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$relationships = $collectionsCache[$collectionId] ??= \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attr) => $attr->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
$key = $relationship->getAttribute('key');
|
||||
$related = $document->getAttribute($key);
|
||||
|
||||
if (empty($related)) {
|
||||
if (\in_array(\gettype($related), ['array', 'object']) && $operations !== null) {
|
||||
$operations++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$relations = \is_array($related) ? $related : [$related];
|
||||
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
|
||||
|
||||
if (!isset($collectionsCache[$relatedCollectionId])) {
|
||||
$relatedCollectionDoc = $authorization->skip(
|
||||
fn () => $dbForProject->getDocument(
|
||||
'database_' . $database->getSequence(),
|
||||
$relatedCollectionId
|
||||
)
|
||||
);
|
||||
|
||||
$collectionsCache[$relatedCollectionId] = \array_filter(
|
||||
$relatedCollectionDoc->getAttribute('attributes', []),
|
||||
fn ($attr) => $attr->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($relations as $relation) {
|
||||
if ($relation instanceof Document) {
|
||||
$relatedCollection = new Document([
|
||||
'$id' => $relatedCollectionId,
|
||||
'attributes' => $collectionsCache[$relatedCollectionId],
|
||||
]);
|
||||
|
||||
$this->processDocument(
|
||||
database: $database,
|
||||
collection: $relatedCollection,
|
||||
document: $relation,
|
||||
dbForProject: $dbForProject,
|
||||
collectionsCache: $collectionsCache,
|
||||
authorization: $authorization,
|
||||
operations: $operations,
|
||||
depth: $depth + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (\is_array($related)) {
|
||||
$document->setAttribute($relationship->getAttribute('key'), \array_values($relations));
|
||||
} elseif (empty($relations)) {
|
||||
$document->setAttribute($relationship->getAttribute('key'), null);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* For triggering different queues for each document for a bulk documents
|
||||
* @param string $event
|
||||
@@ -498,4 +401,5 @@ abstract class Action extends DatabasesAction
|
||||
$queueForFunctions->reset();
|
||||
$queueForWebhooks->reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-2
@@ -25,6 +25,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Numeric;
|
||||
|
||||
@@ -172,7 +173,7 @@ class Decrement extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
try {
|
||||
$document = $dbForDatabases->decreaseDocumentAttribute(
|
||||
collection: 'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
@@ -199,7 +200,7 @@ class Decrement extends Action
|
||||
fn ($document) => $document->getAttribute('key'),
|
||||
\array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn ($attribute) => $attribute->getAttribute('type') === ColumnType::Relationship->value
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
+3
-2
@@ -25,6 +25,7 @@ use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Numeric;
|
||||
|
||||
@@ -172,7 +173,7 @@ class Increment extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
try {
|
||||
$document = $dbForDatabases->increaseDocumentAttribute(
|
||||
collection: 'database_' . $database->getSequence() . '_collection_' . $collection->getSequence(),
|
||||
@@ -199,7 +200,7 @@ class Increment extends Action
|
||||
fn ($document) => $document->getAttribute('key'),
|
||||
\array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn ($attribute) => $attribute->getAttribute('type') === ColumnType::Relationship->value
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
+3
-2
@@ -22,6 +22,7 @@ use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Nullable;
|
||||
use Utopia\Validator\Text;
|
||||
@@ -101,7 +102,7 @@ class Delete extends Action
|
||||
|
||||
$hasRelationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn ($attribute) => $attribute->getAttribute('type') === ColumnType::Relationship->value
|
||||
);
|
||||
|
||||
if ($hasRelationships) {
|
||||
@@ -164,7 +165,7 @@ class Delete extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
$documents = [];
|
||||
|
||||
try {
|
||||
|
||||
+3
-2
@@ -24,6 +24,7 @@ use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Permissions;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\JSON;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -117,7 +118,7 @@ class Update extends Action
|
||||
|
||||
$hasRelationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn ($attribute) => $attribute->getAttribute('type') === ColumnType::Relationship->value
|
||||
);
|
||||
|
||||
if ($hasRelationships) {
|
||||
@@ -190,7 +191,7 @@ class Update extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
$documents = [];
|
||||
|
||||
try {
|
||||
|
||||
+3
-2
@@ -22,6 +22,7 @@ use Utopia\Database\Exception\Structure as StructureException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\JSON;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -103,7 +104,7 @@ class Upsert extends Action
|
||||
|
||||
$hasRelationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn ($attribute) => $attribute->getAttribute('type') === ColumnType::Relationship->value
|
||||
);
|
||||
|
||||
if ($hasRelationships) {
|
||||
@@ -166,7 +167,7 @@ class Upsert extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
$upserted = [];
|
||||
|
||||
try {
|
||||
|
||||
+15
-117
@@ -24,11 +24,12 @@ use Utopia\Database\Exception\Structure as StructureException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\PermissionType;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Authorization\Input;
|
||||
use Utopia\Database\Validator\Permissions;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\JSON;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -122,7 +123,7 @@ class Create extends Action
|
||||
->param('documentId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', true, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.', false, ['dbForProject'])
|
||||
->param('data', [], new JSON(), 'Document data as JSON object.', true, example: '{"username":"walter.obrien","email":"walter.obrien@example.com","fullName":"Walter O\'Brien","age":30,"isAdmin":false}')
|
||||
->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [PermissionType::Read, PermissionType::Update, PermissionType::Delete, PermissionType::Write])), 'An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->param('documents', [], fn (array $plan) => new ArrayList(new JSON(), $plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH), 'Array of documents data as JSON objects.', true, ['plan'])
|
||||
->param('transactionId', null, fn (Database $dbForProject) => new Nullable(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'Transaction ID for staging the operation.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
@@ -202,7 +203,7 @@ class Create extends Action
|
||||
|
||||
$hasRelationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn ($attribute) => $attribute->getAttribute('type') === ColumnType::Relationship->value
|
||||
);
|
||||
|
||||
if ($isBulk && $hasRelationships) {
|
||||
@@ -211,9 +212,9 @@ class Create extends Action
|
||||
|
||||
$setPermissions = function (Document $document, ?array $permissions) use ($user, $isAPIKey, $isPrivilegedUser, $isBulk, $dbForProject, $authorization) {
|
||||
$allowedPermissions = [
|
||||
Database::PERMISSION_READ,
|
||||
Database::PERMISSION_UPDATE,
|
||||
Database::PERMISSION_DELETE,
|
||||
PermissionType::Read,
|
||||
PermissionType::Update,
|
||||
PermissionType::Delete,
|
||||
];
|
||||
|
||||
// If bulk, we need to validate permissions explicitly per document
|
||||
@@ -234,17 +235,17 @@ class Create extends Action
|
||||
$permissions = [];
|
||||
if (!empty($user->getId()) && !$isPrivilegedUser) {
|
||||
foreach ($allowedPermissions as $permission) {
|
||||
$permissions[] = (new Permission($permission, 'user', $user->getId()))->toString();
|
||||
$permissions[] = (new Permission($permission->value, 'user', $user->getId()))->toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Users can only manage their own roles, API keys and Admin users can manage any
|
||||
if (!$isAPIKey && !$isPrivilegedUser) {
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ([PermissionType::Read, PermissionType::Create, PermissionType::Update, PermissionType::Delete] as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
if ($permission->getPermission() != $type) {
|
||||
if ($permission->getPermission() != $type->value) {
|
||||
continue;
|
||||
}
|
||||
$role = (new Role(
|
||||
@@ -262,98 +263,7 @@ class Create extends Action
|
||||
$document->setAttribute('$permissions', $permissions);
|
||||
};
|
||||
|
||||
$operations = 0;
|
||||
|
||||
$checkPermissions = function (Document $collection, Document $document, string $permission) use ($isAPIKey, $isPrivilegedUser, &$checkPermissions, $dbForProject, $database, &$operations, $authorization) {
|
||||
$operations++;
|
||||
|
||||
$documentSecurity = $collection->getAttribute('documentSecurity', false);
|
||||
|
||||
$validCollection = $authorization->isValid(
|
||||
new Input($permission, $collection->getPermissionsByType($permission))
|
||||
);
|
||||
if (($permission === Database::PERMISSION_UPDATE && !$documentSecurity) || !$validCollection) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription());
|
||||
}
|
||||
|
||||
if ($permission === Database::PERMISSION_UPDATE) {
|
||||
$validDocument = $authorization->isValid(
|
||||
new Input($permission, $document->getUpdate())
|
||||
);
|
||||
$valid = $validCollection || $validDocument;
|
||||
if ($documentSecurity && !$valid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED, $authorization->getDescription());
|
||||
}
|
||||
}
|
||||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
$related = $document->getAttribute($relationship->getAttribute('key'));
|
||||
|
||||
if (empty($related)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$isList = \is_array($related) && \array_values($related) === $related;
|
||||
|
||||
if ($isList) {
|
||||
$relations = $related;
|
||||
} else {
|
||||
$relations = [$related];
|
||||
}
|
||||
|
||||
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
|
||||
$relatedCollection = $authorization->skip(
|
||||
fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId)
|
||||
);
|
||||
|
||||
foreach ($relations as &$relation) {
|
||||
if (
|
||||
\is_array($relation)
|
||||
&& \array_values($relation) !== $relation
|
||||
&& !isset($relation['$id'])
|
||||
) {
|
||||
$relation['$id'] = ID::unique();
|
||||
$relation = new Document($relation);
|
||||
}
|
||||
|
||||
$this->validateRelationship($relation);
|
||||
|
||||
if ($relation instanceof Document) {
|
||||
$relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser);
|
||||
|
||||
$current = $authorization->skip(
|
||||
fn () => $dbForProject->getDocument('database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(), $relation->getId())
|
||||
);
|
||||
|
||||
if ($current->isEmpty()) {
|
||||
$type = Database::PERMISSION_CREATE;
|
||||
|
||||
if (isset($relation['$id']) && $relation['$id'] === 'unique()') {
|
||||
$relation['$id'] = ID::unique();
|
||||
}
|
||||
} else {
|
||||
$relation->setAttribute('$collection', $relatedCollection->getId());
|
||||
$type = Database::PERMISSION_UPDATE;
|
||||
}
|
||||
|
||||
$checkPermissions($relatedCollection, $relation, $type);
|
||||
}
|
||||
}
|
||||
|
||||
if ($isList) {
|
||||
$document->setAttribute($relationship->getAttribute('key'), \array_values($relations));
|
||||
} else {
|
||||
$document->setAttribute($relationship->getAttribute('key'), \reset($relations));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$documents = \array_map(function ($document) use ($collection, $permissions, $checkPermissions, $isBulk, $documentId, $setPermissions, $isAPIKey, $isPrivilegedUser) {
|
||||
$documents = \array_map(function ($document) use ($collection, $permissions, $isBulk, $documentId, $setPermissions, $isAPIKey, $isPrivilegedUser) {
|
||||
$document['$collection'] = $collection->getId();
|
||||
|
||||
// Determine the source ID depending on whether it's a bulk operation.
|
||||
@@ -374,7 +284,7 @@ class Create extends Action
|
||||
$document = $this->removeReadonlyAttributes($document, $isAPIKey || $isPrivilegedUser);
|
||||
$document = new Document($document);
|
||||
$setPermissions($document, $permissions);
|
||||
$checkPermissions($collection, $document, Database::PERMISSION_CREATE);
|
||||
|
||||
return $document;
|
||||
}, $documents);
|
||||
|
||||
@@ -448,7 +358,7 @@ class Create extends Action
|
||||
return;
|
||||
}
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
try {
|
||||
$created = [];
|
||||
$dbForDatabases->withPreserveDates(
|
||||
@@ -479,21 +389,9 @@ class Create extends Action
|
||||
->setParam('tableId', $collection->getId())
|
||||
->setContext($this->getCollectionsEventsContext(), $collection);
|
||||
|
||||
$collectionsCache = [];
|
||||
foreach ($created as $document) {
|
||||
$this->processDocument(
|
||||
database: $database,
|
||||
collection: $collection,
|
||||
document: $document,
|
||||
dbForProject: $dbForProject,
|
||||
collectionsCache: $collectionsCache,
|
||||
authorization: $authorization
|
||||
);
|
||||
}
|
||||
|
||||
$usage
|
||||
->addMetric($this->getDatabasesOperationWriteMetric(), \max(1, $operations))
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), $this->getDatabasesIdOperationWriteMetric()), \max(1, $operations)); // per collection
|
||||
->addMetric($this->getDatabasesOperationWriteMetric(), 1)
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), $this->getDatabasesIdOperationWriteMetric()), 1); // per collection
|
||||
|
||||
$response->setStatusCode(SwooleResponse::STATUS_CODE_CREATED);
|
||||
|
||||
|
||||
+3
-13
@@ -21,6 +21,7 @@ use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
class Delete extends Action
|
||||
@@ -120,7 +121,7 @@ class Delete extends Action
|
||||
throw new Exception($this->getParentNotFoundException(), params: [$collectionId]);
|
||||
}
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
// Read permission should not be required for delete
|
||||
$collectionTableId = 'database_' . $database->getSequence() . '_collection_' . $collection->getSequence();
|
||||
|
||||
@@ -204,17 +205,6 @@ class Delete extends Action
|
||||
throw new Exception($this->getRestrictedException());
|
||||
}
|
||||
|
||||
$collectionsCache = [];
|
||||
|
||||
$this->processDocument(
|
||||
database: $database,
|
||||
collection: $collection,
|
||||
document: $document,
|
||||
dbForProject: $dbForProject,
|
||||
collectionsCache: $collectionsCache,
|
||||
authorization: $authorization
|
||||
);
|
||||
|
||||
$usage
|
||||
->addMetric(METRIC_DATABASES_OPERATIONS_WRITES, 1)
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), METRIC_DATABASE_ID_OPERATIONS_WRITES), 1); // per collection
|
||||
@@ -225,7 +215,7 @@ class Delete extends Action
|
||||
fn ($document) => $document->getAttribute('key'),
|
||||
\array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn ($attribute) => $attribute->getAttribute('type') === ColumnType::Relationship->value
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
+4
-18
@@ -88,7 +88,7 @@ class Get extends Action
|
||||
|
||||
$collection = $authorization->skip(fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId));
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
if ($collection->isEmpty() || (!$collection->getAttribute('enabled', false) && !$isAPIKey && !$isPrivilegedUser)) {
|
||||
throw new Exception($this->getParentNotFoundException(), params: [$collectionId]);
|
||||
}
|
||||
@@ -100,7 +100,7 @@ class Get extends Action
|
||||
}
|
||||
|
||||
try {
|
||||
$selects = Query::groupByType($queries)['selections'] ?? [];
|
||||
$selects = Query::groupByType($queries)->selections ?? [];
|
||||
$collectionTableId = 'database_' . $database->getSequence() . '_collection_' . $collection->getSequence();
|
||||
$collectionTableId = 'database_' . $database->getSequence() . '_collection_' . $collection->getSequence();
|
||||
|
||||
@@ -122,23 +122,9 @@ class Get extends Action
|
||||
throw new Exception($this->getNotFoundException(), params: [$documentId]);
|
||||
}
|
||||
|
||||
$operations = 0;
|
||||
$collectionsCache = [];
|
||||
$this->processDocument(
|
||||
database: $database,
|
||||
collection: $collection,
|
||||
document: $document,
|
||||
dbForProject: $dbForProject,
|
||||
collectionsCache: $collectionsCache,
|
||||
authorization: $authorization,
|
||||
operations: $operations
|
||||
);
|
||||
|
||||
$usage
|
||||
->addMetric($this->getDatabasesOperationReadMetric(), max($operations, 1))
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), $this->getDatabasesIdOperationReadMetric()), $operations);
|
||||
|
||||
$response->addHeader('X-Debug-Operations', $operations);
|
||||
->addMetric($this->getDatabasesOperationReadMetric(), 1)
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), $this->getDatabasesIdOperationReadMetric()), 1);
|
||||
|
||||
$response->dynamic($document, $this->getResponseModel());
|
||||
}
|
||||
|
||||
+3
-3
@@ -90,7 +90,7 @@ class XList extends Action
|
||||
throw new Exception($this->getParentNotFoundException(), params: [$collectionId]);
|
||||
}
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
$document = $dbForDatabases->getDocument('database_' . $database->getSequence() . '_collection_' . $collection->getSequence(), $documentId);
|
||||
if ($document->isEmpty()) {
|
||||
throw new Exception($this->getNotFoundException(), params: [$documentId]);
|
||||
@@ -108,8 +108,8 @@ class XList extends Action
|
||||
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
$limit = $grouped->limit ?? 25;
|
||||
$offset = $grouped->offset ?? 0;
|
||||
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
|
||||
|
||||
+13
-97
@@ -22,10 +22,12 @@ use Utopia\Database\Exception\Structure as StructureException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\PermissionType;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Permissions;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\JSON;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -78,7 +80,7 @@ class Update extends Action
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('documentId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Document ID.', false, ['dbForProject'])
|
||||
->param('data', [], new JSON(), 'Document data as JSON object. Include only attribute and value pairs to be updated.', true, example: '{"username":"walter.obrien","email":"walter.obrien@example.com","fullName":"Walter O\'Brien","age":33,"isAdmin":false}')
|
||||
->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [PermissionType::Read, PermissionType::Update, PermissionType::Delete, PermissionType::Write])), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->param('transactionId', null, fn (Database $dbForProject) => new Nullable(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'Transaction ID for staging the operation.', true, ['dbForProject'])
|
||||
->inject('requestTimestamp')
|
||||
->inject('response')
|
||||
@@ -120,7 +122,7 @@ class Update extends Action
|
||||
$data = $this->parseOperators($data, $collection);
|
||||
}
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
// Read permission should not be required for update
|
||||
/** @var Document $document */
|
||||
$collectionTableId = 'database_' . $database->getSequence() . '_collection_' . $collection->getSequence();
|
||||
@@ -138,18 +140,18 @@ class Update extends Action
|
||||
|
||||
// Map aggregate permissions into the multiple permissions they represent.
|
||||
$permissions = Permission::aggregate($permissions, [
|
||||
Database::PERMISSION_READ,
|
||||
Database::PERMISSION_UPDATE,
|
||||
Database::PERMISSION_DELETE,
|
||||
PermissionType::Read,
|
||||
PermissionType::Update,
|
||||
PermissionType::Delete,
|
||||
]);
|
||||
|
||||
// Users can only manage their own roles, API keys and Admin users can manage any
|
||||
$roles = $authorization->getRoles();
|
||||
if (!$isAPIKey && !$isPrivilegedUser && !\is_null($permissions)) {
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ([PermissionType::Read, PermissionType::Create, PermissionType::Update, PermissionType::Delete] as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
if ($permission->getPermission() != $type) {
|
||||
if ($permission->getPermission() != $type->value) {
|
||||
continue;
|
||||
}
|
||||
$role = (new Role(
|
||||
@@ -173,86 +175,6 @@ class Update extends Action
|
||||
$data = $this->removeReadonlyAttributes($data, $isAPIKey || $isPrivilegedUser);
|
||||
$newDocument = new Document($data);
|
||||
|
||||
$operations = 0;
|
||||
|
||||
$setCollection = (function (Document $collection, Document $document) use ($isAPIKey, $isPrivilegedUser, &$setCollection, $dbForProject, $database, &$operations, $authorization) {
|
||||
$operations++;
|
||||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
$related = $document->getAttribute($relationship->getAttribute('key'));
|
||||
|
||||
if (empty($related)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$isList = \is_array($related) && \array_values($related) === $related;
|
||||
|
||||
if ($isList) {
|
||||
$relations = $related;
|
||||
} else {
|
||||
$relations = [$related];
|
||||
}
|
||||
|
||||
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
|
||||
$relatedCollection = $authorization->skip(
|
||||
fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId)
|
||||
);
|
||||
|
||||
foreach ($relations as &$relation) {
|
||||
// If the relation is an array it can be either update or create a child document.
|
||||
if (
|
||||
\is_array($relation)
|
||||
&& \array_values($relation) !== $relation
|
||||
&& !isset($relation['$id'])
|
||||
) {
|
||||
$relation['$id'] = ID::unique();
|
||||
$relation = new Document($relation);
|
||||
}
|
||||
|
||||
$this->validateRelationship($relation);
|
||||
|
||||
if ($relation instanceof Document) {
|
||||
$relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser);
|
||||
|
||||
$oldDocument = $authorization->skip(fn () => $dbForProject->getDocument(
|
||||
'database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(),
|
||||
$relation->getId()
|
||||
));
|
||||
|
||||
// Attribute $collection is required for Utopia.
|
||||
$relation->setAttribute(
|
||||
'$collection',
|
||||
'database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence()
|
||||
);
|
||||
|
||||
if ($oldDocument->isEmpty()) {
|
||||
if (isset($relation['$id']) && $relation['$id'] === 'unique()') {
|
||||
$relation['$id'] = ID::unique();
|
||||
}
|
||||
}
|
||||
$setCollection($relatedCollection, $relation);
|
||||
}
|
||||
}
|
||||
|
||||
if ($isList) {
|
||||
$document->setAttribute($relationship->getAttribute('key'), \array_values($relations));
|
||||
} else {
|
||||
$document->setAttribute($relationship->getAttribute('key'), \reset($relations));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$setCollection($collection, $newDocument);
|
||||
|
||||
$usage
|
||||
->addMetric($this->getDatabasesOperationWriteMetric(), max($operations, 1))
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), $this->getDatabasesIdOperationWriteMetric()), $operations);
|
||||
|
||||
// Handle transaction staging
|
||||
if ($transactionId !== null) {
|
||||
$transaction = ($isAPIKey || $isPrivilegedUser)
|
||||
@@ -340,15 +262,9 @@ class Update extends Action
|
||||
throw new Exception($this->getStructureException(), $e->getMessage());
|
||||
}
|
||||
|
||||
$collectionsCache = [];
|
||||
$this->processDocument(
|
||||
database: $database,
|
||||
collection: $collection,
|
||||
document: $document,
|
||||
dbForProject: $dbForProject,
|
||||
collectionsCache: $collectionsCache,
|
||||
authorization: $authorization,
|
||||
);
|
||||
$usage
|
||||
->addMetric($this->getDatabasesOperationWriteMetric(), 1)
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), $this->getDatabasesIdOperationWriteMetric()), 1);
|
||||
|
||||
$response->dynamic($document, $this->getResponseModel());
|
||||
|
||||
@@ -356,7 +272,7 @@ class Update extends Action
|
||||
fn ($document) => $document->getAttribute('key'),
|
||||
\array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn ($attribute) => $attribute->getAttribute('type') === ColumnType::Relationship->value
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
+14
-99
@@ -23,10 +23,12 @@ use Utopia\Database\Exception\Structure as StructureException;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\PermissionType;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Permissions;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\JSON;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -81,7 +83,7 @@ class Upsert extends Action
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID.', false, ['dbForProject'])
|
||||
->param('documentId', '', fn (Database $dbForProject) => new CustomId(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Document ID.', false, ['dbForProject'])
|
||||
->param('data', [], new JSON(), 'Document data as JSON object. Include all required attributes of the document to be created or updated.', true, example: '{"username":"walter.obrien","email":"walter.obrien@example.com","fullName":"Walter O\'Brien","age":30,"isAdmin":false}')
|
||||
->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE])), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->param('permissions', null, new Nullable(new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [PermissionType::Read, PermissionType::Update, PermissionType::Delete, PermissionType::Write])), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->param('transactionId', null, fn (Database $dbForProject) => new Nullable(new UID($dbForProject->getAdapter()->getMaxUIDLength())), 'Transaction ID for staging the operation.', true, ['dbForProject'])
|
||||
->inject('requestTimestamp')
|
||||
->inject('response')
|
||||
@@ -125,11 +127,11 @@ class Upsert extends Action
|
||||
$data = $this->parseOperators($data, $collection);
|
||||
}
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
$allowedPermissions = [
|
||||
Database::PERMISSION_READ,
|
||||
Database::PERMISSION_UPDATE,
|
||||
Database::PERMISSION_DELETE,
|
||||
PermissionType::Read,
|
||||
PermissionType::Update,
|
||||
PermissionType::Delete,
|
||||
];
|
||||
|
||||
$permissions = Permission::aggregate($permissions, $allowedPermissions);
|
||||
@@ -150,7 +152,7 @@ class Upsert extends Action
|
||||
if (!empty($user->getId())) {
|
||||
$defaultPermissions = [];
|
||||
foreach ($allowedPermissions as $permission) {
|
||||
$defaultPermissions[] = (new Permission($permission, 'user', $user->getId()))->toString();
|
||||
$defaultPermissions[] = (new Permission($permission->value, 'user', $user->getId()))->toString();
|
||||
}
|
||||
$permissions = $defaultPermissions;
|
||||
}
|
||||
@@ -162,10 +164,10 @@ class Upsert extends Action
|
||||
// Users can only manage their own roles, API keys and Admin users can manage any
|
||||
$roles = $authorization->getRoles();
|
||||
if (!$isAPIKey && !$isPrivilegedUser && !\is_null($permissions)) {
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ([PermissionType::Read, PermissionType::Create, PermissionType::Update, PermissionType::Delete] as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
if ($permission->getPermission() != $type) {
|
||||
if ($permission->getPermission() != $type->value) {
|
||||
continue;
|
||||
}
|
||||
$role = (new Role(
|
||||
@@ -184,85 +186,6 @@ class Upsert extends Action
|
||||
$data['$permissions'] = $permissions ?? [];
|
||||
$data = $this->removeReadonlyAttributes($data, $isAPIKey || $isPrivilegedUser);
|
||||
$newDocument = new Document($data);
|
||||
$operations = 0;
|
||||
|
||||
$setCollection = (function (Document $collection, Document $document) use ($isAPIKey, $isPrivilegedUser, &$setCollection, $dbForProject, $dbForDatabases, $database, &$operations, $authorization) {
|
||||
$operations++;
|
||||
|
||||
$relationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
);
|
||||
|
||||
foreach ($relationships as $relationship) {
|
||||
$related = $document->getAttribute($relationship->getAttribute('key'));
|
||||
|
||||
if (empty($related)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$isList = \is_array($related) && \array_values($related) === $related;
|
||||
|
||||
if ($isList) {
|
||||
$relations = $related;
|
||||
} else {
|
||||
$relations = [$related];
|
||||
}
|
||||
|
||||
$relatedCollectionId = $relationship->getAttribute('relatedCollection');
|
||||
$relatedCollection = $authorization->skip(
|
||||
fn () => $dbForProject->getDocument('database_' . $database->getSequence(), $relatedCollectionId)
|
||||
);
|
||||
|
||||
foreach ($relations as &$relation) {
|
||||
// If the relation is an array it can be either update or create a child document.
|
||||
if (
|
||||
\is_array($relation)
|
||||
&& \array_values($relation) !== $relation
|
||||
&& !isset($relation['$id'])
|
||||
) {
|
||||
$relation['$id'] = ID::unique();
|
||||
$relation = new Document($relation);
|
||||
}
|
||||
|
||||
$this->validateRelationship($relation);
|
||||
|
||||
if ($relation instanceof Document) {
|
||||
$relation = $this->removeReadonlyAttributes($relation, $isAPIKey || $isPrivilegedUser);
|
||||
|
||||
$oldDocument = $authorization->skip(fn () => $dbForDatabases->getDocument(
|
||||
'database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence(),
|
||||
$relation->getId()
|
||||
));
|
||||
|
||||
// Attribute $collection is required for Utopia.
|
||||
$relation->setAttribute(
|
||||
'$collection',
|
||||
'database_' . $database->getSequence() . '_collection_' . $relatedCollection->getSequence()
|
||||
);
|
||||
|
||||
if ($oldDocument->isEmpty()) {
|
||||
if (isset($relation['$id']) && $relation['$id'] === 'unique()') {
|
||||
$relation['$id'] = ID::unique();
|
||||
}
|
||||
}
|
||||
$setCollection($relatedCollection, $relation);
|
||||
}
|
||||
}
|
||||
|
||||
if ($isList) {
|
||||
$document->setAttribute($relationship->getAttribute('key'), \array_values($relations));
|
||||
} else {
|
||||
$document->setAttribute($relationship->getAttribute('key'), \reset($relations));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$setCollection($collection, $newDocument);
|
||||
|
||||
$usage
|
||||
->addMetric($this->getDatabasesOperationWriteMetric(), \max(1, $operations))
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), $this->getDatabasesIdOperationWriteMetric()), \max(1, $operations));
|
||||
|
||||
// Handle transaction staging
|
||||
if ($transactionId !== null) {
|
||||
@@ -350,11 +273,8 @@ class Upsert extends Action
|
||||
throw new Exception($this->getStructureException(), $e->getMessage());
|
||||
}
|
||||
|
||||
$collectionsCache = [];
|
||||
|
||||
if (empty($upserted[0])) {
|
||||
if ($transactionId !== null) {
|
||||
// For transactions, get the document with transaction changes applied
|
||||
$upserted[0] = $transactionState->getDocument($database, $collectionTableId, $documentId, $transactionId);
|
||||
} else {
|
||||
$upserted[0] = $dbForDatabases->getDocument($collectionTableId, $documentId);
|
||||
@@ -363,20 +283,15 @@ class Upsert extends Action
|
||||
|
||||
$document = $upserted[0];
|
||||
|
||||
$this->processDocument(
|
||||
database: $database,
|
||||
collection: $collection,
|
||||
document: $document,
|
||||
dbForProject: $dbForProject,
|
||||
collectionsCache: $collectionsCache,
|
||||
authorization: $authorization
|
||||
);
|
||||
$usage
|
||||
->addMetric($this->getDatabasesOperationWriteMetric(), 1)
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), $this->getDatabasesIdOperationWriteMetric()), 1);
|
||||
|
||||
$relationships = \array_map(
|
||||
fn ($document) => $document->getAttribute('key'),
|
||||
\array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn ($attribute) => $attribute->getAttribute('type') === ColumnType::Relationship->value
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
+3
-16
@@ -104,7 +104,7 @@ class XList extends Action
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
$cursor = Query::getCursorQueries($queries, false);
|
||||
$cursor = \reset($cursor);
|
||||
|
||||
@@ -127,7 +127,7 @@ class XList extends Action
|
||||
}
|
||||
|
||||
try {
|
||||
$selectQueries = Query::groupByType($queries)['selections'] ?? [];
|
||||
$selectQueries = Query::groupByType($queries)->selections ?? [];
|
||||
$collectionTableId = 'database_' . $database->getSequence() . '_collection_' . $collection->getSequence();
|
||||
// Use transaction-aware document retrieval if transactionId is provided
|
||||
if ($transactionId !== null) {
|
||||
@@ -218,20 +218,7 @@ class XList extends Action
|
||||
throw new Exception(Exception::DATABASE_TIMEOUT);
|
||||
}
|
||||
|
||||
$operations = 0;
|
||||
$collectionsCache = [];
|
||||
foreach ($documents as $document) {
|
||||
$this->processDocument(
|
||||
database: $database,
|
||||
collection: $collection,
|
||||
document: $document,
|
||||
dbForProject: $dbForProject,
|
||||
collectionsCache: $collectionsCache,
|
||||
authorization: $authorization,
|
||||
operations: $operations
|
||||
);
|
||||
}
|
||||
|
||||
$operations = \count($documents);
|
||||
$usage
|
||||
->addMetric($this->getDatabasesOperationReadMetric(), max($operations, 1))
|
||||
->addMetric(str_replace('{databaseInternalId}', $database->getSequence(), $this->getDatabasesIdOperationReadMetric()), $operations);
|
||||
|
||||
+28
-23
@@ -11,6 +11,9 @@ use Appwrite\SDK\Deprecated;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Utopia\Database\Adapter\Feature\SchemaAttributes;
|
||||
use Utopia\Database\Adapter\Feature\Spatial;
|
||||
use Utopia\Database\Capability;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Duplicate as DuplicateException;
|
||||
@@ -21,6 +24,8 @@ use Utopia\Database\Validator\Index as IndexValidator;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Query\Schema\IndexType;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Integer;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -71,9 +76,9 @@ class Create extends Action
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).', false, ['dbForProject'])
|
||||
->param('key', null, fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Index Key.', false, ['dbForProject'])
|
||||
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE, Database::INDEX_SPATIAL]), 'Index type.')
|
||||
->param('type', null, new WhiteList([IndexType::Key->value, IndexType::Fulltext->value, IndexType::Unique->value, IndexType::Spatial->value]), 'Index type.')
|
||||
->param('attributes', null, fn (Database $dbForProject) => new ArrayList(new Key(true, $dbForProject->getAdapter()->getMaxUIDLength()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.', false, ['dbForProject'])
|
||||
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true)
|
||||
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, ColumnType::String->value), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true)
|
||||
->param('lengths', [], new ArrayList(new Nullable(new Integer()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Length of index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE, optional: true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -104,7 +109,7 @@ class Create extends Action
|
||||
Query::equal('databaseInternalId', [$db->getSequence()])
|
||||
], 61);
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($db);
|
||||
$dbForDatabases = $getDatabasesDB($db, $collection);
|
||||
|
||||
$limit = $dbForDatabases->getLimitForIndexes();
|
||||
|
||||
@@ -119,7 +124,7 @@ class Create extends Action
|
||||
|
||||
$oldAttributes[] = [
|
||||
'key' => '$id',
|
||||
'type' => Database::VAR_STRING,
|
||||
'type' => ColumnType::String->value,
|
||||
'status' => 'available',
|
||||
'required' => true,
|
||||
'array' => false,
|
||||
@@ -128,7 +133,7 @@ class Create extends Action
|
||||
];
|
||||
$oldAttributes[] = [
|
||||
'key' => '$createdAt',
|
||||
'type' => Database::VAR_DATETIME,
|
||||
'type' => ColumnType::Datetime->value,
|
||||
'status' => 'available',
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
@@ -138,7 +143,7 @@ class Create extends Action
|
||||
];
|
||||
$oldAttributes[] = [
|
||||
'key' => '$updatedAt',
|
||||
'type' => Database::VAR_DATETIME,
|
||||
'type' => ColumnType::Datetime->value,
|
||||
'status' => 'available',
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
@@ -148,7 +153,7 @@ class Create extends Action
|
||||
];
|
||||
|
||||
$contextType = $this->getParentContext();
|
||||
if ($dbForDatabases->getAdapter()->getSupportForAttributes()) {
|
||||
if ($dbForDatabases->getAdapter() instanceof SchemaAttributes) {
|
||||
foreach ($attributes as $i => $attribute) {
|
||||
// find attribute metadata in collection document
|
||||
$attributeIndex = \array_search($attribute, array_column($oldAttributes, 'key'));
|
||||
@@ -161,7 +166,7 @@ class Create extends Action
|
||||
$attributeType = $oldAttributes[$attributeIndex]['type'];
|
||||
$attributeArray = $oldAttributes[$attributeIndex]['array'] ?? false;
|
||||
|
||||
if ($attributeType === Database::VAR_RELATIONSHIP) {
|
||||
if ($attributeType === ColumnType::Relationship->value) {
|
||||
throw new Exception($this->getParentInvalidTypeException(), "Cannot create an index for a relationship $contextType: " . $oldAttributes[$attributeIndex]['key']);
|
||||
}
|
||||
|
||||
@@ -199,21 +204,21 @@ class Create extends Action
|
||||
$collection->getAttribute('indexes'),
|
||||
$dbForDatabases->getAdapter()->getMaxIndexLength(),
|
||||
$dbForDatabases->getAdapter()->getInternalIndexesKeys(),
|
||||
$dbForDatabases->getAdapter()->getSupportForIndexArray(),
|
||||
$dbForDatabases->getAdapter()->getSupportForSpatialIndexNull(),
|
||||
$dbForDatabases->getAdapter()->getSupportForSpatialIndexOrder(),
|
||||
$dbForDatabases->getAdapter()->getSupportForVectors(),
|
||||
$dbForDatabases->getAdapter()->getSupportForAttributes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForMultipleFulltextIndexes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForIdenticalIndexes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForObjectIndexes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForTrigramIndex(),
|
||||
$dbForDatabases->getAdapter()->getSupportForSpatialAttributes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForIndex(),
|
||||
$dbForDatabases->getAdapter()->getSupportForUniqueIndex(),
|
||||
$dbForDatabases->getAdapter()->getSupportForFulltextIndex(),
|
||||
$dbForDatabases->getAdapter()->getSupportForTTLIndexes(),
|
||||
$dbForDatabases->getAdapter()->getSupportForObject()
|
||||
$dbForDatabases->getAdapter()->supports(Capability::IndexArray),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::SpatialIndexNull),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::SpatialIndexOrder),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::Vectors),
|
||||
$dbForDatabases->getAdapter() instanceof SchemaAttributes,
|
||||
$dbForDatabases->getAdapter()->supports(Capability::MultipleFulltextIndexes),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::IdenticalIndexes),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::ObjectIndexes),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::TrigramIndex),
|
||||
$dbForDatabases->getAdapter() instanceof Spatial,
|
||||
$dbForDatabases->getAdapter()->supports(Capability::Index),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::UniqueIndex),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::Fulltext),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::TTLIndexes),
|
||||
$dbForDatabases->getAdapter()->supports(Capability::Objects)
|
||||
);
|
||||
|
||||
if (!$validator->isValid($index)) {
|
||||
|
||||
@@ -98,8 +98,8 @@ class XList extends Action
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
$limit = $grouped->limit ?? 25;
|
||||
$offset = $grouped->offset ?? 0;
|
||||
|
||||
$context = $this->getContext();
|
||||
$resource = "database/$databaseId/$context/$collectionId";
|
||||
|
||||
@@ -111,7 +111,7 @@ class Update extends Action
|
||||
->setAttribute('search', \implode(' ', [$collectionId, $searchName]))
|
||||
);
|
||||
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collection);
|
||||
$dbForDatabases->updateCollection('database_' . $database->getSequence() . '_collection_' . $collection->getSequence(), $permissions, $documentSecurity);
|
||||
|
||||
$queueForEvents
|
||||
|
||||
@@ -77,7 +77,7 @@ class Get extends Action
|
||||
{
|
||||
$database = $dbForProject->getDocument('databases', $databaseId);
|
||||
$collectionDocument = $dbForProject->getDocument('database_' . $database->getSequence(), $collectionId);
|
||||
$dbForDatabases = $getDatabasesDB($database);
|
||||
$dbForDatabases = $getDatabasesDB($database, $collectionDocument);
|
||||
$collection = $dbForDatabases->getCollection('database_' . $database->getSequence() . '_collection_' . $collectionDocument->getSequence());
|
||||
|
||||
if ($collection->isEmpty()) {
|
||||
|
||||
@@ -216,15 +216,8 @@ class Create extends Action
|
||||
throw new Exception(Exception::GENERAL_SERVER_ERROR, 'The "collections" collection is not configured.');
|
||||
}
|
||||
|
||||
$attributes = [];
|
||||
foreach ($collections['attributes'] as $attribute) {
|
||||
$attributes[] = new Document($attribute);
|
||||
}
|
||||
|
||||
$indexes = [];
|
||||
foreach ($collections['indexes'] as $index) {
|
||||
$indexes[] = new Document($index);
|
||||
}
|
||||
$attributes = $collections['attributes'];
|
||||
$indexes = $collections['indexes'];
|
||||
|
||||
try {
|
||||
$dbForProject->createCollection('database_' . $database->getSequence(), $attributes, $indexes);
|
||||
|
||||
@@ -87,8 +87,8 @@ class XList extends Action
|
||||
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
$limit = $grouped->limit ?? 25;
|
||||
$offset = $grouped->offset ?? 0;
|
||||
|
||||
$resource = 'database/' . $databaseId;
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
|
||||
@@ -12,6 +12,7 @@ use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\PermissionType;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Validator\Range;
|
||||
@@ -64,13 +65,13 @@ class Create extends Action
|
||||
$permissions = [];
|
||||
if (!empty($user->getId())) {
|
||||
$allowedPermissions = [
|
||||
Database::PERMISSION_READ,
|
||||
Database::PERMISSION_UPDATE,
|
||||
Database::PERMISSION_DELETE,
|
||||
PermissionType::Read,
|
||||
PermissionType::Update,
|
||||
PermissionType::Delete,
|
||||
];
|
||||
|
||||
foreach ($allowedPermissions as $permission) {
|
||||
$permissions[] = (new Permission($permission, 'user', $user->getId()))->toString();
|
||||
$permissions[] = (new Permission($permission->value, 'user', $user->getId()))->toString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-12
@@ -17,10 +17,12 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\PermissionType;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\Authorization\Input;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\ArrayList;
|
||||
|
||||
class Create extends Action
|
||||
@@ -131,7 +133,7 @@ class Create extends Action
|
||||
if (\in_array($operation['action'], ['bulkCreate', 'bulkUpdate', 'bulkUpsert', 'bulkDelete'])) {
|
||||
$hasRelationships = \array_filter(
|
||||
$collection->getAttribute('attributes', []),
|
||||
fn ($attribute) => $attribute->getAttribute('type') === Database::VAR_RELATIONSHIP
|
||||
fn ($attribute) => $attribute->getAttribute('type') === ColumnType::Relationship->value
|
||||
);
|
||||
if ($hasRelationships) {
|
||||
throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Bulk operations are not supported for ' . $this->getGroupId() . ' with relationship attributes');
|
||||
@@ -158,10 +160,10 @@ class Create extends Action
|
||||
// Bulk operations skip permission validation entirely (API key/admin only, already checked above)
|
||||
if (!\in_array($operation['action'], ['bulkCreate', 'bulkUpdate', 'bulkUpsert', 'bulkDelete'])) {
|
||||
$permissionType = match ($operation['action']) {
|
||||
'create' => Database::PERMISSION_CREATE,
|
||||
'update', 'increment', 'decrement' => Database::PERMISSION_UPDATE,
|
||||
'delete' => Database::PERMISSION_DELETE,
|
||||
'upsert' => ($document && !$document->isEmpty()) ? Database::PERMISSION_UPDATE : Database::PERMISSION_CREATE,
|
||||
'create' => PermissionType::Create,
|
||||
'update', 'increment', 'decrement' => PermissionType::Update,
|
||||
'delete' => PermissionType::Delete,
|
||||
'upsert' => ($document && !$document->isEmpty()) ? PermissionType::Update : PermissionType::Create,
|
||||
default => throw new Exception(Exception::GENERAL_BAD_REQUEST, 'Invalid action: ' . $operation['action'])
|
||||
};
|
||||
|
||||
@@ -174,18 +176,18 @@ class Create extends Action
|
||||
);
|
||||
$documentValid = false;
|
||||
if ($document !== null && !$document->isEmpty() && $documentSecurity) {
|
||||
if ($permissionType === Database::PERMISSION_UPDATE) {
|
||||
if ($permissionType === PermissionType::Update) {
|
||||
$documentValid = $authorization->isValid(
|
||||
new Input(Database::PERMISSION_UPDATE, $document->getUpdate())
|
||||
new Input(PermissionType::Update, $document->getUpdate())
|
||||
);
|
||||
} elseif ($permissionType === Database::PERMISSION_DELETE) {
|
||||
} elseif ($permissionType === PermissionType::Delete) {
|
||||
$documentValid = $authorization->isValid(
|
||||
new Input(Database::PERMISSION_DELETE, $document->getDelete())
|
||||
new Input(PermissionType::Delete, $document->getDelete())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ($permissionType === Database::PERMISSION_CREATE || !$documentSecurity) {
|
||||
if ($permissionType === PermissionType::Create || !$documentSecurity) {
|
||||
if (!$collectionValid) {
|
||||
throw new Exception(Exception::USER_UNAUTHORIZED);
|
||||
}
|
||||
@@ -199,10 +201,10 @@ class Create extends Action
|
||||
if (isset($operation['data']['$permissions'])) {
|
||||
$permissions = $operation['data']['$permissions'];
|
||||
$roles = $authorization->getRoles();
|
||||
foreach (Database::PERMISSIONS as $type) {
|
||||
foreach ([PermissionType::Read, PermissionType::Create, PermissionType::Update, PermissionType::Delete] as $type) {
|
||||
foreach ($permissions as $permission) {
|
||||
$permission = Permission::parse($permission);
|
||||
if ($permission->getPermission() != $type) {
|
||||
if ($permission->getPermission() != $type->value) {
|
||||
continue;
|
||||
}
|
||||
$role = (new Role(
|
||||
|
||||
+2
-2
@@ -10,7 +10,7 @@ use Appwrite\SDK\Parameter;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Database\Validator\CustomId;
|
||||
use Appwrite\Utopia\Response as UtopiaResponse;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\PermissionType;
|
||||
use Utopia\Database\Validator\Permissions;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
@@ -96,7 +96,7 @@ class Create extends DocumentCreate
|
||||
->param('documentId', '', new CustomId(), 'Document ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can\'t start with a special char. Max length is 36 chars.', true)
|
||||
->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection). Make sure to define attributes before creating documents.')
|
||||
->param('data', [], new JSON(), 'Document data as JSON object.', true, example: '{"username":"walter.obrien","email":"walter.obrien@example.com","fullName":"Walter O\'Brien","age":30,"isAdmin":false}')
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [PermissionType::Read, PermissionType::Update, PermissionType::Delete, PermissionType::Write]), 'An array of permissions strings. By default, only the current user is granted all permissions. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->param('documents', [], fn (array $plan) => new ArrayList(new JSON(), $plan['databasesBatchSize'] ?? APP_LIMIT_DATABASE_BATCH), 'Array of documents data as JSON objects.', true, ['plan'])
|
||||
->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true)
|
||||
->inject('response')
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@ 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\PermissionType;
|
||||
use Utopia\Database\Validator\Permissions;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
@@ -59,7 +59,7 @@ class Update extends DocumentUpdate
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('documentId', '', new UID(), 'Document ID.')
|
||||
->param('data', [], new JSON(), 'Document data as JSON object. Include only fields and value pairs to be updated.', true)
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [PermissionType::Read, PermissionType::Update, PermissionType::Delete, PermissionType::Write]), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true)
|
||||
->inject('requestTimestamp')
|
||||
->inject('response')
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@ 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\PermissionType;
|
||||
use Utopia\Database\Validator\Permissions;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
@@ -61,7 +61,7 @@ class Upsert extends DocumentUpsert
|
||||
->param('collectionId', '', new UID(), 'Collection ID.')
|
||||
->param('documentId', '', new UID(), 'Document ID.')
|
||||
->param('data', [], new JSON(), 'Document data as JSON object. Include all required fields of the document to be created or updated.', true)
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [Database::PERMISSION_READ, Database::PERMISSION_UPDATE, Database::PERMISSION_DELETE, Database::PERMISSION_WRITE]), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->param('permissions', null, new Permissions(APP_LIMIT_ARRAY_PARAMS_SIZE, [PermissionType::Read, PermissionType::Update, PermissionType::Delete, PermissionType::Write]), 'An array of permissions strings. By default, the current permissions are inherited. [Learn more about permissions](https://appwrite.io/docs/permissions).', true)
|
||||
->param('transactionId', null, new UID(), 'Transaction ID for staging the operation.', true)
|
||||
->inject('requestTimestamp')
|
||||
->inject('response')
|
||||
|
||||
+4
-2
@@ -12,6 +12,8 @@ use Utopia\Database\Database;
|
||||
use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Query\Schema\IndexType;
|
||||
use Utopia\Validator\ArrayList;
|
||||
use Utopia\Validator\Integer;
|
||||
use Utopia\Validator\Nullable;
|
||||
@@ -58,9 +60,9 @@ class Create extends IndexCreate
|
||||
->param('databaseId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Database ID.', false, ['dbForProject'])
|
||||
->param('collectionId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).', false, ['dbForProject'])
|
||||
->param('key', null, fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Index Key.', false, ['dbForProject'])
|
||||
->param('type', null, new WhiteList([Database::INDEX_KEY, Database::INDEX_FULLTEXT, Database::INDEX_UNIQUE]), 'Index type.')
|
||||
->param('type', null, new WhiteList([IndexType::Key->value, IndexType::Fulltext->value, IndexType::Unique->value]), 'Index type.')
|
||||
->param('attributes', null, fn (Database $dbForProject) => new ArrayList(new Key(true, $dbForProject->getAdapter()->getMaxUIDLength()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of attributes to index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' attributes are allowed, each 32 characters long.', false, ['dbForProject'])
|
||||
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, Database::VAR_STRING), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true)
|
||||
->param('orders', [], new ArrayList(new WhiteList(['ASC', 'DESC'], false, ColumnType::String->value), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of index orders. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' orders are allowed.', true)
|
||||
->param('lengths', [], new ArrayList(new Nullable(new Integer()), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Length of index. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE, optional: true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
||||
@@ -81,8 +81,8 @@ class XList extends Action
|
||||
}
|
||||
|
||||
$grouped = Query::groupByType($queries);
|
||||
$limit = $grouped['limit'] ?? 25;
|
||||
$offset = $grouped['offset'] ?? 0;
|
||||
$limit = $grouped->limit ?? 25;
|
||||
$offset = $grouped->offset ?? 0;
|
||||
|
||||
$resource = 'database/' . $databaseId;
|
||||
$logs = $audit->getLogsByResource($resource, limit: $limit, offset: $offset);
|
||||
|
||||
+2
-1
@@ -12,6 +12,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Spatial;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -56,7 +57,7 @@ class Create extends LineCreate
|
||||
->param('tableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Column Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is column required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_LINESTRING)), 'Default value for column when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when column is required.', true)
|
||||
->param('default', null, new Nullable(new Spatial(ColumnType::Linestring->value)), 'Default value for column when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when column is required.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForDatabase')
|
||||
|
||||
+2
-1
@@ -13,6 +13,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Spatial;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -58,7 +59,7 @@ class Update extends LineUpdate
|
||||
->param('tableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Column Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is column required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_LINESTRING)), 'Default value for column when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when column is required.', true)
|
||||
->param('default', null, new Nullable(new Spatial(ColumnType::Linestring->value)), 'Default value for column when not provided, two-dimensional array of coordinate pairs, [[longitude, latitude], [longitude, latitude], …], listing the vertices of the line in order. Cannot be set when column is required.', true)
|
||||
->param('newKey', null, fn (Database $dbForProject) => new Nullable(new Key(false, $dbForProject->getAdapter()->getMaxUIDLength())), 'New Column Key.', true, ['dbForProject'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
|
||||
+2
-1
@@ -12,6 +12,7 @@ use Utopia\Database\Validator\Key;
|
||||
use Utopia\Database\Validator\Spatial;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Adapter\Swoole\Response as SwooleResponse;
|
||||
use Utopia\Query\Schema\ColumnType;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Nullable;
|
||||
|
||||
@@ -56,7 +57,7 @@ class Create extends PointCreate
|
||||
->param('tableId', '', fn (Database $dbForProject) => new UID($dbForProject->getAdapter()->getMaxUIDLength()), 'Table ID. You can create a new table using the TablesDB service [server integration](https://appwrite.io/docs/references/cloud/server-dart/tablesDB#createTable).', false, ['dbForProject'])
|
||||
->param('key', '', fn (Database $dbForProject) => new Key(false, $dbForProject->getAdapter()->getMaxUIDLength()), 'Column Key.', false, ['dbForProject'])
|
||||
->param('required', null, new Boolean(), 'Is column required?')
|
||||
->param('default', null, new Nullable(new Spatial(Database::VAR_POINT)), 'Default value for column when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when column is required.', true)
|
||||
->param('default', null, new Nullable(new Spatial(ColumnType::Point->value)), 'Default value for column when not provided, array of two numbers [longitude, latitude], representing a single coordinate. Cannot be set when column is required.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForDatabase')
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user