Merge pull request #5271 from appwrite/feat-realtions-jake
Feat relations updates
This commit is contained in:
commit
f6aa4a4ab1
|
@ -302,7 +302,6 @@ function updateAttribute(
|
||||||
$dbForProject->updateRelationship(
|
$dbForProject->updateRelationship(
|
||||||
collection: $collectionId,
|
collection: $collectionId,
|
||||||
key: $key,
|
key: $key,
|
||||||
newTwoWayKey: $options['twoWayKey'],
|
|
||||||
twoWay: $options['twoWay'],
|
twoWay: $options['twoWay'],
|
||||||
onDelete: $options['onDelete'],
|
onDelete: $options['onDelete'],
|
||||||
);
|
);
|
||||||
|
@ -1529,11 +1528,11 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati
|
||||||
->label('sdk.response.model', Response::MODEL_ATTRIBUTE_RELATIONSHIP)
|
->label('sdk.response.model', Response::MODEL_ATTRIBUTE_RELATIONSHIP)
|
||||||
->param('databaseId', '', new UID(), 'Database ID.')
|
->param('databaseId', '', new UID(), 'Database ID.')
|
||||||
->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).')
|
->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).')
|
||||||
->param('key', '', new Key(), 'Attribute Key.')
|
|
||||||
->param('relatedCollectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
|
->param('relatedCollectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#databasesCreateCollection).')
|
||||||
->param('type', '', new WhiteList([Database::RELATION_ONE_TO_ONE, Database::RELATION_MANY_TO_ONE, Database::RELATION_MANY_TO_MANY, Database::RELATION_ONE_TO_MANY]), 'Relation type')
|
->param('type', '', new WhiteList([Database::RELATION_ONE_TO_ONE, Database::RELATION_MANY_TO_ONE, Database::RELATION_MANY_TO_MANY, Database::RELATION_ONE_TO_MANY]), 'Relation type')
|
||||||
->param('twoWay', false, new Boolean(), 'Is Two Way?', true)
|
->param('twoWay', false, new Boolean(), 'Is Two Way?', true)
|
||||||
->param('twoWayKey', null, new Key(), 'Two Way Key', true)
|
->param('key', null, new Key(), 'Attribute Key.', true)
|
||||||
|
->param('twoWayKey', null, new Key(), 'Two Way Attribute Key.', true)
|
||||||
->param('onDelete', Database::RELATION_MUTATE_RESTRICT, new WhiteList([Database::RELATION_MUTATE_CASCADE, Database::RELATION_MUTATE_RESTRICT, Database::RELATION_MUTATE_SET_NULL]), 'Constraints option', true)
|
->param('onDelete', Database::RELATION_MUTATE_RESTRICT, new WhiteList([Database::RELATION_MUTATE_CASCADE, Database::RELATION_MUTATE_RESTRICT, Database::RELATION_MUTATE_SET_NULL]), 'Constraints option', true)
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
|
@ -1542,10 +1541,10 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati
|
||||||
->action(function (
|
->action(function (
|
||||||
string $databaseId,
|
string $databaseId,
|
||||||
string $collectionId,
|
string $collectionId,
|
||||||
string $key,
|
|
||||||
string $relatedCollectionId,
|
string $relatedCollectionId,
|
||||||
string $type,
|
string $type,
|
||||||
bool $twoWay,
|
bool $twoWay,
|
||||||
|
?string $key,
|
||||||
?string $twoWayKey,
|
?string $twoWayKey,
|
||||||
string $onDelete,
|
string $onDelete,
|
||||||
Response $response,
|
Response $response,
|
||||||
|
@ -1553,6 +1552,7 @@ App::post('/v1/databases/:databaseId/collections/:collectionId/attributes/relati
|
||||||
EventDatabase $database,
|
EventDatabase $database,
|
||||||
Event $events
|
Event $events
|
||||||
) {
|
) {
|
||||||
|
$key ??= $relatedCollectionId;
|
||||||
$twoWayKey ??= $collectionId;
|
$twoWayKey ??= $collectionId;
|
||||||
|
|
||||||
$attribute = createAttribute(
|
$attribute = createAttribute(
|
||||||
|
@ -2750,12 +2750,7 @@ App::get('/v1/databases/:databaseId/collections/:collectionId/documents')
|
||||||
}
|
}
|
||||||
|
|
||||||
$filterQueries = Query::groupByType($queries)['filters'];
|
$filterQueries = Query::groupByType($queries)['filters'];
|
||||||
// todo: temporary fix until Utopia will be ready !!!!
|
|
||||||
foreach ($filterQueries as $key => $query) {
|
|
||||||
if (\str_contains($query->getAttribute(), '.')) {
|
|
||||||
unset($filterQueries[$key]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ($documentSecurity && !$valid) {
|
if ($documentSecurity && !$valid) {
|
||||||
$documents = $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries);
|
$documents = $dbForProject->find('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $queries);
|
||||||
$total = $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT);
|
$total = $dbForProject->count('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $filterQueries, APP_LIMIT_COUNT);
|
||||||
|
|
|
@ -95,26 +95,30 @@ class DatabaseV1 extends Worker
|
||||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($type === Database::VAR_RELATIONSHIP) {
|
switch ($type) {
|
||||||
$relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']);
|
case Database::VAR_RELATIONSHIP:
|
||||||
if ($relatedCollection->isEmpty()) {
|
$relatedCollection = $dbForProject->getDocument('database_' . $database->getInternalId(), $options['relatedCollection']);
|
||||||
throw new Exception('Missing collection');
|
if ($relatedCollection->isEmpty()) {
|
||||||
}
|
throw new Exception('Collection not found');
|
||||||
if (
|
}
|
||||||
!$dbForProject->createRelationship(
|
if (
|
||||||
collection: 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
|
!$dbForProject->createRelationship(
|
||||||
relatedCollection: 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(),
|
collection: 'database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(),
|
||||||
type: $options['relationType'],
|
relatedCollection: 'database_' . $database->getInternalId() . '_collection_' . $relatedCollection->getInternalId(),
|
||||||
twoWay: $options['twoWay'],
|
type: $options['relationType'],
|
||||||
id: $key,
|
twoWay: $options['twoWay'],
|
||||||
twoWayKey: $options['twoWayKey'],
|
id: $key,
|
||||||
onDelete: $options['onDelete'],
|
twoWayKey: $options['twoWayKey'],
|
||||||
)
|
onDelete: $options['onDelete'],
|
||||||
) {
|
)
|
||||||
throw new Exception('Failed to create Attribute');
|
) {
|
||||||
}
|
throw new Exception('Failed to create Attribute');
|
||||||
} elseif (!$dbForProject->createAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
|
}
|
||||||
throw new Exception('Failed to create Attribute');
|
break;
|
||||||
|
default:
|
||||||
|
if (!$dbForProject->createAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key, $type, $size, $required, $default, $signed, $array, $format, $formatOptions, $filters)) {
|
||||||
|
throw new Exception('Failed to create Attribute');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'available'));
|
$dbForProject->updateDocument('attributes', $attribute->getId(), $attribute->setAttribute('status', 'available'));
|
||||||
|
@ -151,6 +155,7 @@ class DatabaseV1 extends Worker
|
||||||
* @param Document $collection
|
* @param Document $collection
|
||||||
* @param Document $attribute
|
* @param Document $attribute
|
||||||
* @param string $projectId
|
* @param string $projectId
|
||||||
|
* @throws Throwable
|
||||||
*/
|
*/
|
||||||
protected function deleteAttribute(Document $database, Document $collection, Document $attribute, string $projectId): void
|
protected function deleteAttribute(Document $database, Document $collection, Document $attribute, string $projectId): void
|
||||||
{
|
{
|
||||||
|
@ -177,12 +182,16 @@ class DatabaseV1 extends Worker
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ($status !== 'failed') {
|
if ($status !== 'failed') {
|
||||||
if ($type === Database::VAR_RELATIONSHIP) {
|
switch ($type) {
|
||||||
if (!$dbForProject->deleteRelationship('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
|
case Database::VAR_RELATIONSHIP:
|
||||||
throw new Exception('Failed to delete Attribute');
|
if (!$dbForProject->deleteRelationship('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
|
||||||
}
|
throw new Exception('Failed to delete Attribute');
|
||||||
} elseif (!$dbForProject->deleteAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
|
}
|
||||||
throw new Exception('Failed to delete Attribute');
|
break;
|
||||||
|
default:
|
||||||
|
if (!$dbForProject->deleteAttribute('database_' . $database->getInternalId() . '_collection_' . $collection->getInternalId(), $key)) {
|
||||||
|
throw new Exception('Failed to delete Attribute');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$dbForProject->deleteDocument('attributes', $attribute->getId());
|
$dbForProject->deleteDocument('attributes', $attribute->getId());
|
||||||
|
|
|
@ -43,13 +43,13 @@
|
||||||
"ext-sockets": "*",
|
"ext-sockets": "*",
|
||||||
"appwrite/php-clamav": "1.1.*",
|
"appwrite/php-clamav": "1.1.*",
|
||||||
"appwrite/php-runtimes": "0.11.*",
|
"appwrite/php-runtimes": "0.11.*",
|
||||||
"utopia-php/abuse": "0.21.*",
|
"utopia-php/abuse": "0.22.*",
|
||||||
"utopia-php/analytics": "0.2.*",
|
"utopia-php/analytics": "0.2.*",
|
||||||
"utopia-php/audit": "0.23.*",
|
"utopia-php/audit": "0.24.*",
|
||||||
"utopia-php/cache": "0.8.*",
|
"utopia-php/cache": "0.8.*",
|
||||||
"utopia-php/cli": "0.13.*",
|
"utopia-php/cli": "0.13.*",
|
||||||
"utopia-php/config": "0.2.*",
|
"utopia-php/config": "0.2.*",
|
||||||
"utopia-php/database": "dev-feat-relationships as 0.33.0",
|
"utopia-php/database": "dev-feat-relationships as 0.34.0",
|
||||||
"utopia-php/preloader": "0.2.*",
|
"utopia-php/preloader": "0.2.*",
|
||||||
"utopia-php/domains": "1.1.*",
|
"utopia-php/domains": "1.1.*",
|
||||||
"utopia-php/framework": "0.28.*",
|
"utopia-php/framework": "0.28.*",
|
||||||
|
|
45
composer.lock
generated
45
composer.lock
generated
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "65ec111f49af9c148eb69dc16aec7a10",
|
"content-hash": "db3f68f41b0387401b964f65bad3053c",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "adhocore/jwt",
|
"name": "adhocore/jwt",
|
||||||
|
@ -1808,23 +1808,23 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "utopia-php/abuse",
|
"name": "utopia-php/abuse",
|
||||||
"version": "0.21.0",
|
"version": "0.22.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/utopia-php/abuse.git",
|
"url": "https://github.com/utopia-php/abuse.git",
|
||||||
"reference": "7483068b192b27d698da9534c80091f69666d5eb"
|
"reference": "9360a026d18809e35523b254ab57e51055008203"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/7483068b192b27d698da9534c80091f69666d5eb",
|
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/9360a026d18809e35523b254ab57e51055008203",
|
||||||
"reference": "7483068b192b27d698da9534c80091f69666d5eb",
|
"reference": "9360a026d18809e35523b254ab57e51055008203",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-curl": "*",
|
"ext-curl": "*",
|
||||||
"ext-pdo": "*",
|
"ext-pdo": "*",
|
||||||
"php": ">=8.0",
|
"php": ">=8.0",
|
||||||
"utopia-php/database": "0.33.*"
|
"utopia-php/database": "0.34.*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"laravel/pint": "1.2.*",
|
"laravel/pint": "1.2.*",
|
||||||
|
@ -1851,9 +1851,9 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/utopia-php/abuse/issues",
|
"issues": "https://github.com/utopia-php/abuse/issues",
|
||||||
"source": "https://github.com/utopia-php/abuse/tree/0.21.0"
|
"source": "https://github.com/utopia-php/abuse/tree/0.22.1"
|
||||||
},
|
},
|
||||||
"time": "2023-03-10T08:49:10+00:00"
|
"time": "2023-03-23T07:30:49+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "utopia-php/analytics",
|
"name": "utopia-php/analytics",
|
||||||
|
@ -1912,22 +1912,21 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "utopia-php/audit",
|
"name": "utopia-php/audit",
|
||||||
"version": "0.23.0",
|
"version": "0.24.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/utopia-php/audit.git",
|
"url": "https://github.com/utopia-php/audit.git",
|
||||||
"reference": "f16e893a22b93560d2af02afcb4761b3a940148a"
|
"reference": "237538b618506bbc0efc0e7884d49cdf52c20004"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/f16e893a22b93560d2af02afcb4761b3a940148a",
|
"url": "https://api.github.com/repos/utopia-php/audit/zipball/237538b618506bbc0efc0e7884d49cdf52c20004",
|
||||||
"reference": "f16e893a22b93560d2af02afcb4761b3a940148a",
|
"reference": "237538b618506bbc0efc0e7884d49cdf52c20004",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"ext-pdo": "*",
|
|
||||||
"php": ">=8.0",
|
"php": ">=8.0",
|
||||||
"utopia-php/database": "0.33.*"
|
"utopia-php/database": "0.34.*"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"laravel/pint": "1.2.*",
|
"laravel/pint": "1.2.*",
|
||||||
|
@ -1954,9 +1953,9 @@
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/utopia-php/audit/issues",
|
"issues": "https://github.com/utopia-php/audit/issues",
|
||||||
"source": "https://github.com/utopia-php/audit/tree/0.23.0"
|
"source": "https://github.com/utopia-php/audit/tree/0.24.1"
|
||||||
},
|
},
|
||||||
"time": "2023-03-10T08:51:26+00:00"
|
"time": "2023-03-23T07:29:11+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "utopia-php/cache",
|
"name": "utopia-php/cache",
|
||||||
|
@ -2117,12 +2116,12 @@
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/utopia-php/database.git",
|
"url": "https://github.com/utopia-php/database.git",
|
||||||
"reference": "3dac815092cf8dc8feff79b7db461c67518db875"
|
"reference": "c1df0b712746b1283737956a1b0b143dca8f8610"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/3dac815092cf8dc8feff79b7db461c67518db875",
|
"url": "https://api.github.com/repos/utopia-php/database/zipball/c1df0b712746b1283737956a1b0b143dca8f8610",
|
||||||
"reference": "3dac815092cf8dc8feff79b7db461c67518db875",
|
"reference": "c1df0b712746b1283737956a1b0b143dca8f8610",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -2167,7 +2166,7 @@
|
||||||
"issues": "https://github.com/utopia-php/database/issues",
|
"issues": "https://github.com/utopia-php/database/issues",
|
||||||
"source": "https://github.com/utopia-php/database/tree/feat-relationships"
|
"source": "https://github.com/utopia-php/database/tree/feat-relationships"
|
||||||
},
|
},
|
||||||
"time": "2023-03-22T11:41:15+00:00"
|
"time": "2023-03-23T10:52:28+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "utopia-php/domains",
|
"name": "utopia-php/domains",
|
||||||
|
@ -5662,8 +5661,8 @@
|
||||||
{
|
{
|
||||||
"package": "utopia-php/database",
|
"package": "utopia-php/database",
|
||||||
"version": "dev-feat-relationships",
|
"version": "dev-feat-relationships",
|
||||||
"alias": "0.33.0",
|
"alias": "0.34.0",
|
||||||
"alias_normalized": "0.33.0.0"
|
"alias_normalized": "0.34.0.0"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"minimum-stability": "stable",
|
"minimum-stability": "stable",
|
||||||
|
@ -5693,5 +5692,5 @@
|
||||||
"platform-overrides": {
|
"platform-overrides": {
|
||||||
"php": "8.0"
|
"php": "8.0"
|
||||||
},
|
},
|
||||||
"plugin-api-version": "2.2.0"
|
"plugin-api-version": "2.3.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,8 +83,6 @@ services:
|
||||||
- ./docs:/usr/src/code/docs
|
- ./docs:/usr/src/code/docs
|
||||||
- ./public:/usr/src/code/public
|
- ./public:/usr/src/code/public
|
||||||
- ./src:/usr/src/code/src
|
- ./src:/usr/src/code/src
|
||||||
- ./vendor/utopia-php/framework:/usr/src/code/vendor/utopia-php/framework
|
|
||||||
- ./vendor/utopia-php/database:/usr/src/code/vendor/utopia-php/database
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- mariadb
|
- mariadb
|
||||||
- redis
|
- redis
|
||||||
|
@ -345,8 +343,6 @@ services:
|
||||||
volumes:
|
volumes:
|
||||||
- ./app:/usr/src/code/app
|
- ./app:/usr/src/code/app
|
||||||
- ./src:/usr/src/code/src
|
- ./src:/usr/src/code/src
|
||||||
- ./vendor/utopia-php/database:/usr/src/code/vendor/utopia-php/database
|
|
||||||
- ./vendor/utopia-php/framework:/usr/src/code/vendor/utopia-php/framework
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
- mariadb
|
- mariadb
|
||||||
|
|
|
@ -62,12 +62,12 @@ class Base extends Queries
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$validators = [
|
$validators = [
|
||||||
new Select(),
|
|
||||||
new Limit(),
|
new Limit(),
|
||||||
new Offset(),
|
new Offset(),
|
||||||
new Cursor(),
|
new Cursor(),
|
||||||
new Filter($attributes),
|
new Filter($attributes),
|
||||||
new Order($attributes),
|
new Order($attributes),
|
||||||
|
new Select($attributes),
|
||||||
];
|
];
|
||||||
|
|
||||||
parent::__construct(...$validators);
|
parent::__construct(...$validators);
|
||||||
|
|
|
@ -61,7 +61,7 @@ class Filter extends Base
|
||||||
|
|
||||||
foreach ($values as $value) {
|
foreach ($values as $value) {
|
||||||
$condition = match ($attributeType) {
|
$condition = match ($attributeType) {
|
||||||
Database::VAR_RELATIONSHIP => true, // Todo: ?
|
Database::VAR_RELATIONSHIP => true,
|
||||||
Database::VAR_DATETIME => gettype($value) === Database::VAR_STRING,
|
Database::VAR_DATETIME => gettype($value) === Database::VAR_STRING,
|
||||||
default => gettype($value) === $attributeType
|
default => gettype($value) === $attributeType
|
||||||
};
|
};
|
||||||
|
@ -91,6 +91,7 @@ class Filter extends Base
|
||||||
// Validate method
|
// Validate method
|
||||||
$method = $query->getMethod();
|
$method = $query->getMethod();
|
||||||
$attribute = $query->getAttribute();
|
$attribute = $query->getAttribute();
|
||||||
|
|
||||||
switch ($method) {
|
switch ($method) {
|
||||||
case Query::TYPE_EQUAL:
|
case Query::TYPE_EQUAL:
|
||||||
case Query::TYPE_NOTEQUAL:
|
case Query::TYPE_NOTEQUAL:
|
||||||
|
|
|
@ -41,6 +41,8 @@ class Select extends Base
|
||||||
|
|
||||||
foreach ($query->getValues() as $attribute) {
|
foreach ($query->getValues() as $attribute) {
|
||||||
if (\str_contains($attribute, '.')) {
|
if (\str_contains($attribute, '.')) {
|
||||||
|
// For relationships, just validate the top level.
|
||||||
|
// Utopia will validate each nested level during the recursive calls.
|
||||||
$attribute = \explode('.', $attribute)[0];
|
$attribute = \explode('.', $attribute)[0];
|
||||||
}
|
}
|
||||||
if (!isset($this->schema[$attribute]) && $attribute !== '*') {
|
if (!isset($this->schema[$attribute]) && $attribute !== '*') {
|
||||||
|
|
|
@ -11,12 +11,6 @@ class AttributeRelationship extends Attribute
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
$this
|
$this
|
||||||
->addRule('default', [
|
|
||||||
'type' => self::TYPE_STRING,
|
|
||||||
'description' => 'Default value for attribute when not provided. Only null is optional',
|
|
||||||
'default' => null,
|
|
||||||
'example' => '',
|
|
||||||
])
|
|
||||||
->addRule('relatedCollection', [
|
->addRule('relatedCollection', [
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
'description' => 'The Id of the related collection',
|
'description' => 'The Id of the related collection',
|
||||||
|
@ -25,26 +19,26 @@ class AttributeRelationship extends Attribute
|
||||||
])
|
])
|
||||||
->addRule('relationType', [
|
->addRule('relationType', [
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
'description' => 'The type of the relationship ',
|
'description' => 'The type of the relationship',
|
||||||
'default' => null,
|
'default' => '',
|
||||||
'example' => 'oneToOne|oneToMany|manyToOne|manyToMany',
|
'example' => 'oneToOne|oneToMany|manyToOne|manyToMany',
|
||||||
])
|
])
|
||||||
->addRule('twoWay', [
|
->addRule('twoWay', [
|
||||||
'type' => self::TYPE_BOOLEAN,
|
'type' => self::TYPE_BOOLEAN,
|
||||||
'description' => 'Is the relationship two-way?',
|
'description' => 'Is the relationship two-way?',
|
||||||
'default' => null,
|
'default' => false,
|
||||||
'example' => 'relationship',
|
'example' => false,
|
||||||
])
|
])
|
||||||
->addRule('twoWayKey', [
|
->addRule('twoWayKey', [
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
'description' => 'The key of the two-way relationship',
|
'description' => 'The key of the two-way relationship',
|
||||||
'default' => null,
|
'default' => '',
|
||||||
'example' => 'string',
|
'example' => 'string',
|
||||||
])
|
])
|
||||||
->addRule('onDelete', [
|
->addRule('onDelete', [
|
||||||
'type' => self::TYPE_STRING,
|
'type' => self::TYPE_STRING,
|
||||||
'description' => 'Action to take on related documents when parent document is deleted',
|
'description' => 'Action to take on related documents when parent document is deleted',
|
||||||
'default' => null,
|
'default' => 'restrict',
|
||||||
'example' => 'restrict|cascade|setNull',
|
'example' => 'restrict|cascade|setNull',
|
||||||
])
|
])
|
||||||
;
|
;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1165,7 +1165,7 @@ class DatabasesCustomServerTest extends Scope
|
||||||
$this->assertEquals(202, $attribute['headers']['status-code']);
|
$this->assertEquals(202, $attribute['headers']['status-code']);
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep(20);
|
sleep(10);
|
||||||
|
|
||||||
$collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([
|
$collection = $this->client->call(Client::METHOD_GET, '/databases/' . $databaseId . '/collections/' . $collectionId, array_merge([
|
||||||
'content-type' => 'application/json',
|
'content-type' => 'application/json',
|
||||||
|
|
|
@ -26,6 +26,8 @@ trait Base
|
||||||
public static string $CREATE_IP_ATTRIBUTE = 'create_ip_attribute';
|
public static string $CREATE_IP_ATTRIBUTE = 'create_ip_attribute';
|
||||||
public static string $CREATE_ENUM_ATTRIBUTE = 'create_enum_attribute';
|
public static string $CREATE_ENUM_ATTRIBUTE = 'create_enum_attribute';
|
||||||
public static string $CREATE_DATETIME_ATTRIBUTE = 'create_datetime_attribute';
|
public static string $CREATE_DATETIME_ATTRIBUTE = 'create_datetime_attribute';
|
||||||
|
|
||||||
|
public static string $CREATE_RELATIONSHIP_ATTRIBUTE = 'create_relationship_attribute';
|
||||||
public static string $UPDATE_STRING_ATTRIBUTE = 'update_string_attribute';
|
public static string $UPDATE_STRING_ATTRIBUTE = 'update_string_attribute';
|
||||||
public static string $UPDATE_INTEGER_ATTRIBUTE = 'update_integer_attribute';
|
public static string $UPDATE_INTEGER_ATTRIBUTE = 'update_integer_attribute';
|
||||||
public static string $UPDATE_FLOAT_ATTRIBUTE = 'update_float_attribute';
|
public static string $UPDATE_FLOAT_ATTRIBUTE = 'update_float_attribute';
|
||||||
|
@ -35,6 +37,8 @@ trait Base
|
||||||
public static string $UPDATE_IP_ATTRIBUTE = 'update_ip_attribute';
|
public static string $UPDATE_IP_ATTRIBUTE = 'update_ip_attribute';
|
||||||
public static string $UPDATE_ENUM_ATTRIBUTE = 'update_enum_attribute';
|
public static string $UPDATE_ENUM_ATTRIBUTE = 'update_enum_attribute';
|
||||||
public static string $UPDATE_DATETIME_ATTRIBUTE = 'update_datetime_attribute';
|
public static string $UPDATE_DATETIME_ATTRIBUTE = 'update_datetime_attribute';
|
||||||
|
|
||||||
|
public static string $UPDATE_RELATIONSHIP_ATTRIBUTE = 'update_relationship_attribute';
|
||||||
public static string $GET_ATTRIBUTES = 'get_attributes';
|
public static string $GET_ATTRIBUTES = 'get_attributes';
|
||||||
public static string $GET_ATTRIBUTE = 'get_attribute';
|
public static string $GET_ATTRIBUTE = 'get_attribute';
|
||||||
public static string $DELETE_ATTRIBUTE = 'delete_attribute';
|
public static string $DELETE_ATTRIBUTE = 'delete_attribute';
|
||||||
|
@ -460,6 +464,17 @@ trait Base
|
||||||
array
|
array
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
|
case self::$CREATE_RELATIONSHIP_ATTRIBUTE:
|
||||||
|
return 'mutation createRelationshipAttribute($databaseId: String!, $collectionId: String!, $relatedCollectionId: String!, $type: String!, $twoWay: Boolean, $key: String, $twoWayKey: String, $onDelete: String){
|
||||||
|
databasesCreateRelationshipAttribute(databaseId: $databaseId, collectionId: $collectionId, relatedCollectionId: $relatedCollectionId, type: $type, twoWay: $twoWay, key: $key, twoWayKey: $twoWayKey, onDelete: $onDelete) {
|
||||||
|
relatedCollection
|
||||||
|
relationType
|
||||||
|
twoWay
|
||||||
|
key
|
||||||
|
twoWayKey
|
||||||
|
onDelete
|
||||||
|
}
|
||||||
|
}';
|
||||||
case self::$UPDATE_STRING_ATTRIBUTE:
|
case self::$UPDATE_STRING_ATTRIBUTE:
|
||||||
return 'mutation updateStringAttribute($databaseId: String!, $collectionId: String!, $key: String!, $required: Boolean!, $default: String){
|
return 'mutation updateStringAttribute($databaseId: String!, $collectionId: String!, $key: String!, $required: Boolean!, $default: String){
|
||||||
databasesUpdateStringAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, required: $required, default: $default) {
|
databasesUpdateStringAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, required: $required, default: $default) {
|
||||||
|
@ -528,6 +543,17 @@ trait Base
|
||||||
default
|
default
|
||||||
}
|
}
|
||||||
}';
|
}';
|
||||||
|
case self::$UPDATE_RELATIONSHIP_ATTRIBUTE:
|
||||||
|
return 'mutation updateRelationshipAttribute($databaseId: String!, $collectionId: String!, $key: String!, $twoWay: Boolean, $onDelete: String){
|
||||||
|
databasesUpdateRelationshipAttribute(databaseId: $databaseId, collectionId: $collectionId, key: $key, twoWay: $twoWay, onDelete: $onDelete) {
|
||||||
|
relatedCollection
|
||||||
|
relationType
|
||||||
|
twoWay
|
||||||
|
key
|
||||||
|
twoWayKey
|
||||||
|
onDelete
|
||||||
|
}
|
||||||
|
}';
|
||||||
case self::$CREATE_INDEX:
|
case self::$CREATE_INDEX:
|
||||||
return 'mutation createIndex($databaseId: String!, $collectionId: String!, $key: String!, $type: String!, $attributes: [String!]!, $orders: [String!]){
|
return 'mutation createIndex($databaseId: String!, $collectionId: String!, $key: String!, $type: String!, $attributes: [String!]!, $orders: [String!]){
|
||||||
databasesCreateIndex(databaseId: $databaseId, collectionId: $collectionId, key: $key, type: $type, attributes: $attributes, orders: $orders) {
|
databasesCreateIndex(databaseId: $databaseId, collectionId: $collectionId, key: $key, type: $type, attributes: $attributes, orders: $orders) {
|
||||||
|
|
|
@ -7,6 +7,7 @@ use Tests\E2E\Client;
|
||||||
use Tests\E2E\Scopes\ProjectCustom;
|
use Tests\E2E\Scopes\ProjectCustom;
|
||||||
use Tests\E2E\Scopes\Scope;
|
use Tests\E2E\Scopes\Scope;
|
||||||
use Tests\E2E\Scopes\SideServer;
|
use Tests\E2E\Scopes\SideServer;
|
||||||
|
use Utopia\Database\Database;
|
||||||
use Utopia\Database\Helpers\ID;
|
use Utopia\Database\Helpers\ID;
|
||||||
use Utopia\Database\Helpers\Permission;
|
use Utopia\Database\Helpers\Permission;
|
||||||
use Utopia\Database\Helpers\Role;
|
use Utopia\Database\Helpers\Role;
|
||||||
|
@ -75,9 +76,36 @@ class DatabaseServerTest extends Scope
|
||||||
$collection = $collection['body']['data']['databasesCreateCollection'];
|
$collection = $collection['body']['data']['databasesCreateCollection'];
|
||||||
$this->assertEquals('Actors', $collection['name']);
|
$this->assertEquals('Actors', $collection['name']);
|
||||||
|
|
||||||
|
$gqlPayload = [
|
||||||
|
'query' => $query,
|
||||||
|
'variables' => [
|
||||||
|
'databaseId' => $database['_id'],
|
||||||
|
'collectionId' => 'movies',
|
||||||
|
'name' => 'Movies',
|
||||||
|
'documentSecurity' => false,
|
||||||
|
'permissions' => [
|
||||||
|
Permission::read(Role::any()),
|
||||||
|
Permission::create(Role::users()),
|
||||||
|
Permission::update(Role::users()),
|
||||||
|
Permission::delete(Role::users()),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$collection2 = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $projectId,
|
||||||
|
], $this->getHeaders()), $gqlPayload);
|
||||||
|
|
||||||
|
$this->assertIsArray($collection2['body']['data']);
|
||||||
|
$this->assertArrayNotHasKey('errors', $collection2['body']);
|
||||||
|
$collection2 = $collection2['body']['data']['databasesCreateCollection'];
|
||||||
|
$this->assertEquals('Movies', $collection2['name']);
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'database' => $database,
|
'database' => $database,
|
||||||
'collection' => $collection,
|
'collection' => $collection,
|
||||||
|
'collection2' => $collection2,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,6 +598,69 @@ class DatabaseServerTest extends Scope
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testCreateCollection
|
||||||
|
*/
|
||||||
|
public function testCreateRelationshipAttribute(array $data): array
|
||||||
|
{
|
||||||
|
$projectId = $this->getProject()['$id'];
|
||||||
|
$query = $this->getQuery(self::$CREATE_RELATIONSHIP_ATTRIBUTE);
|
||||||
|
$gqlPayload = [
|
||||||
|
'query' => $query,
|
||||||
|
'variables' => [
|
||||||
|
'databaseId' => $data['database']['_id'],
|
||||||
|
'collectionId' => $data['collection2']['_id'], // Movies
|
||||||
|
'relatedCollectionId' => $data['collection']['_id'], // Actors
|
||||||
|
'type' => Database::RELATION_ONE_TO_MANY,
|
||||||
|
'twoWay' => true,
|
||||||
|
'key' => 'actors',
|
||||||
|
'twoWayKey' => 'movie'
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $projectId,
|
||||||
|
], $this->getHeaders()), $gqlPayload);
|
||||||
|
|
||||||
|
$this->assertArrayNotHasKey('errors', $attribute['body']);
|
||||||
|
$this->assertIsArray($attribute['body']['data']);
|
||||||
|
$this->assertIsArray($attribute['body']['data']['databasesCreateRelationshipAttribute']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testCreateRelationshipAttribute
|
||||||
|
*/
|
||||||
|
public function testUpdateRelationshipAttribute(array $data): array
|
||||||
|
{
|
||||||
|
sleep(3);
|
||||||
|
|
||||||
|
$projectId = $this->getProject()['$id'];
|
||||||
|
$query = $this->getQuery(self::$UPDATE_RELATIONSHIP_ATTRIBUTE);
|
||||||
|
$gqlPayload = [
|
||||||
|
'query' => $query,
|
||||||
|
'variables' => [
|
||||||
|
'databaseId' => $data['database']['_id'],
|
||||||
|
'collectionId' => $data['collection2']['_id'],
|
||||||
|
'key' => 'actors',
|
||||||
|
'twoWay' => false,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$attribute = $this->client->call(Client::METHOD_POST, '/graphql', array_merge([
|
||||||
|
'content-type' => 'application/json',
|
||||||
|
'x-appwrite-project' => $projectId,
|
||||||
|
], $this->getHeaders()), $gqlPayload);
|
||||||
|
|
||||||
|
$this->assertArrayNotHasKey('errors', $attribute['body']);
|
||||||
|
$this->assertIsArray($attribute['body']['data']);
|
||||||
|
$this->assertIsArray($attribute['body']['data']['databasesUpdateRelationshipAttribute']);
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @depends testCreateCollection
|
* @depends testCreateCollection
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
|
Loading…
Reference in a new issue