Remove Appwrite URL dependency from resolvers
This commit is contained in:
parent
a1718e8a44
commit
d163217d1f
3 changed files with 108 additions and 70 deletions
49
app/init.php
49
app/init.php
|
@ -1059,6 +1059,49 @@ App::setResource('promiseAdapter', function ($register) {
|
||||||
return $register->get('promiseAdapter');
|
return $register->get('promiseAdapter');
|
||||||
}, ['register']);
|
}, ['register']);
|
||||||
|
|
||||||
App::setResource('schema', function ($utopia, $project, $dbForProject) {
|
App::setResource('schema', function ($utopia, $dbForProject) {
|
||||||
return Schema::build($utopia, $project->getId(), $dbForProject);
|
|
||||||
}, ['utopia', 'project', 'dbForProject']);
|
$complexity = function (int $complexity, array $args) {
|
||||||
|
$queries = Query::parseQueries($args['queries'] ?? []);
|
||||||
|
$query = Query::getByType($queries, Query::TYPE_LIMIT)[0] ?? null;
|
||||||
|
$limit = $query ? $query->getValue() : APP_LIMIT_LIST_DEFAULT;
|
||||||
|
|
||||||
|
return $complexity * $limit;
|
||||||
|
};
|
||||||
|
|
||||||
|
$attributes = function (int $limit, int $offset) use ($dbForProject) {
|
||||||
|
$attrs = Authorization::skip(fn() => $dbForProject->find('attributes', [
|
||||||
|
Query::limit($limit),
|
||||||
|
Query::offset($offset),
|
||||||
|
]));
|
||||||
|
|
||||||
|
return \array_map(function ($attr) {
|
||||||
|
return $attr->getArrayCopy();
|
||||||
|
}, $attrs);
|
||||||
|
};
|
||||||
|
|
||||||
|
$urls = [
|
||||||
|
'list' => function (string $collectionId, array $args) {
|
||||||
|
return "/v1/database/collections/{$collectionId}/documents";
|
||||||
|
},
|
||||||
|
'create' => function (string $collectionId, array $args) {
|
||||||
|
return "/v1/database/collections/{$collectionId}/documents";
|
||||||
|
},
|
||||||
|
'read' => function (string $collectionId, array $args) {
|
||||||
|
return "/v1/database/collections/{$collectionId}/documents/{$args['documentId']}";
|
||||||
|
},
|
||||||
|
'update' => function (string $collectionId, array $args) {
|
||||||
|
return "/v1/database/collections/{$collectionId}/documents/{$args['documentId']}";
|
||||||
|
},
|
||||||
|
'delete' => function (string $collectionId, array $args) {
|
||||||
|
return "/v1/database/collections/{$collectionId}/documents/{$args['documentId']}";
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return Schema::build(
|
||||||
|
$utopia,
|
||||||
|
$complexity,
|
||||||
|
$attributes,
|
||||||
|
$urls
|
||||||
|
);
|
||||||
|
}, ['utopia', 'dbForProject']);
|
||||||
|
|
|
@ -7,8 +7,6 @@ use Appwrite\Promises\Swoole;
|
||||||
use Appwrite\Utopia\Request;
|
use Appwrite\Utopia\Request;
|
||||||
use Appwrite\Utopia\Response;
|
use Appwrite\Utopia\Response;
|
||||||
use Utopia\App;
|
use Utopia\App;
|
||||||
use Utopia\Database\Database;
|
|
||||||
use Utopia\Database\ID;
|
|
||||||
use Utopia\Exception;
|
use Utopia\Exception;
|
||||||
use Utopia\Route;
|
use Utopia\Route;
|
||||||
|
|
||||||
|
@ -63,7 +61,6 @@ class Resolvers
|
||||||
* Create a resolver for a document in a specified database and collection with a specific method type.
|
* Create a resolver for a document in a specified database and collection with a specific method type.
|
||||||
*
|
*
|
||||||
* @param App $utopia
|
* @param App $utopia
|
||||||
* @param Database $dbForProject
|
|
||||||
* @param string $databaseId
|
* @param string $databaseId
|
||||||
* @param string $collectionId
|
* @param string $collectionId
|
||||||
* @param string $methodType
|
* @param string $methodType
|
||||||
|
@ -93,16 +90,17 @@ class Resolvers
|
||||||
public static function documentGet(
|
public static function documentGet(
|
||||||
App $utopia,
|
App $utopia,
|
||||||
string $databaseId,
|
string $databaseId,
|
||||||
string $collectionId
|
string $collectionId,
|
||||||
|
callable $url
|
||||||
): callable {
|
): callable {
|
||||||
return static fn($type, $args, $context, $info) => new Swoole(
|
return static fn($type, $args, $context, $info) => new Swoole(
|
||||||
function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $type, $args) {
|
function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) {
|
||||||
$utopia = $utopia->getResource('utopia:graphql', true);
|
$utopia = $utopia->getResource('utopia:graphql', true);
|
||||||
$request = $utopia->getResource('request', true);
|
$request = $utopia->getResource('request', true);
|
||||||
$response = $utopia->getResource('response', true);
|
$response = $utopia->getResource('response', true);
|
||||||
|
|
||||||
$request->setMethod('GET');
|
$request->setMethod('GET');
|
||||||
$request->setURI("/v1/database/collections/{$collectionId}/documents/{$args['documentId']}");
|
$request->setURI($url($collectionId, $args));
|
||||||
|
|
||||||
self::resolve($utopia, $request, $response, $resolve, $reject);
|
self::resolve($utopia, $request, $response, $resolve, $reject);
|
||||||
}
|
}
|
||||||
|
@ -121,15 +119,16 @@ class Resolvers
|
||||||
App $utopia,
|
App $utopia,
|
||||||
string $databaseId,
|
string $databaseId,
|
||||||
string $collectionId,
|
string $collectionId,
|
||||||
|
callable $url
|
||||||
): callable {
|
): callable {
|
||||||
return static fn($type, $args, $context, $info) => new Swoole(
|
return static fn($type, $args, $context, $info) => new Swoole(
|
||||||
function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $type, $args) {
|
function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) {
|
||||||
$utopia = $utopia->getResource('utopia:graphql', true);
|
$utopia = $utopia->getResource('utopia:graphql', true);
|
||||||
$request = $utopia->getResource('request', true);
|
$request = $utopia->getResource('request', true);
|
||||||
$response = $utopia->getResource('response', true);
|
$response = $utopia->getResource('response', true);
|
||||||
|
|
||||||
$request->setMethod('GET');
|
$request->setMethod('GET');
|
||||||
$request->setURI("/v1/database/collections/{$collectionId}/documents");
|
$request->setURI($url($collectionId, $args));
|
||||||
$request->setGet([
|
$request->setGet([
|
||||||
'queries' => $args['queries'],
|
'queries' => $args['queries'],
|
||||||
]);
|
]);
|
||||||
|
@ -155,21 +154,22 @@ class Resolvers
|
||||||
App $utopia,
|
App $utopia,
|
||||||
string $databaseId,
|
string $databaseId,
|
||||||
string $collectionId,
|
string $collectionId,
|
||||||
|
callable $url
|
||||||
): callable {
|
): callable {
|
||||||
return static fn($type, $args, $context, $info) => new Swoole(
|
return static fn($type, $args, $context, $info) => new Swoole(
|
||||||
function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $type, $args) {
|
function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) {
|
||||||
$utopia = $utopia->getResource('utopia:graphql', true);
|
$utopia = $utopia->getResource('utopia:graphql', true);
|
||||||
$request = $utopia->getResource('request', true);
|
$request = $utopia->getResource('request', true);
|
||||||
$response = $utopia->getResource('response', true);
|
$response = $utopia->getResource('response', true);
|
||||||
|
|
||||||
$id = $args['id'] ?? ID::unique();
|
$id = $args['id'] ?? 'unique()';
|
||||||
$permissions = $args['permissions'] ?? null;
|
$permissions = $args['permissions'] ?? null;
|
||||||
|
|
||||||
unset($args['id']);
|
unset($args['id']);
|
||||||
unset($args['permissions']);
|
unset($args['permissions']);
|
||||||
|
|
||||||
$request->setMethod('POST');
|
$request->setMethod('POST');
|
||||||
$request->setURI("/v1/databases/$databaseId/collections/$collectionId/documents");
|
$request->setURI($url($collectionId, $args));
|
||||||
|
|
||||||
// Order must be the same as the route params
|
// Order must be the same as the route params
|
||||||
$request->setPost([
|
$request->setPost([
|
||||||
|
@ -197,9 +197,10 @@ class Resolvers
|
||||||
App $utopia,
|
App $utopia,
|
||||||
string $databaseId,
|
string $databaseId,
|
||||||
string $collectionId,
|
string $collectionId,
|
||||||
|
callable $url
|
||||||
): callable {
|
): callable {
|
||||||
return static fn($type, $args, $context, $info) => new Swoole(
|
return static fn($type, $args, $context, $info) => new Swoole(
|
||||||
function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $type, $args) {
|
function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) {
|
||||||
$utopia = $utopia->getResource('utopia:graphql', true);
|
$utopia = $utopia->getResource('utopia:graphql', true);
|
||||||
$request = $utopia->getResource('request', true);
|
$request = $utopia->getResource('request', true);
|
||||||
$response = $utopia->getResource('response', true);
|
$response = $utopia->getResource('response', true);
|
||||||
|
@ -211,7 +212,7 @@ class Resolvers
|
||||||
unset($args['permissions']);
|
unset($args['permissions']);
|
||||||
|
|
||||||
$request->setMethod('PATCH');
|
$request->setMethod('PATCH');
|
||||||
$request->setURI("/v1/databases/$databaseId/collections/$collectionId/documents/$documentId");
|
$request->setURI($url($collectionId, $args));
|
||||||
|
|
||||||
// Order must be the same as the route params
|
// Order must be the same as the route params
|
||||||
$request->setPost([
|
$request->setPost([
|
||||||
|
@ -238,10 +239,11 @@ class Resolvers
|
||||||
public static function documentDelete(
|
public static function documentDelete(
|
||||||
App $utopia,
|
App $utopia,
|
||||||
string $databaseId,
|
string $databaseId,
|
||||||
string $collectionId
|
string $collectionId,
|
||||||
|
callable $url
|
||||||
): callable {
|
): callable {
|
||||||
return static fn($type, $args, $context, $info) => new Swoole(
|
return static fn($type, $args, $context, $info) => new Swoole(
|
||||||
function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $type, $args) {
|
function (callable $resolve, callable $reject) use ($utopia, $databaseId, $collectionId, $url, $type, $args) {
|
||||||
$utopia = $utopia->getResource('utopia:graphql', true);
|
$utopia = $utopia->getResource('utopia:graphql', true);
|
||||||
$request = $utopia->getResource('request', true);
|
$request = $utopia->getResource('request', true);
|
||||||
$response = $utopia->getResource('response', true);
|
$response = $utopia->getResource('response', true);
|
||||||
|
@ -249,7 +251,7 @@ class Resolvers
|
||||||
$documentId = $args['id'];
|
$documentId = $args['id'];
|
||||||
|
|
||||||
$request->setMethod('DELETE');
|
$request->setMethod('DELETE');
|
||||||
$request->setURI("/v1/databases/$databaseId/collections/$collectionId/documents/$documentId");
|
$request->setURI($url($collectionId, $args));
|
||||||
|
|
||||||
self::resolve($utopia, $request, $response, $resolve, $reject);
|
self::resolve($utopia, $request, $response, $resolve, $reject);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,14 +3,10 @@
|
||||||
namespace Appwrite\GraphQL;
|
namespace Appwrite\GraphQL;
|
||||||
|
|
||||||
use Appwrite\GraphQL\Types\Mapper;
|
use Appwrite\GraphQL\Types\Mapper;
|
||||||
use Appwrite\Utopia\Response;
|
|
||||||
use GraphQL\Type\Definition\ObjectType;
|
use GraphQL\Type\Definition\ObjectType;
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Type\Schema as GQLSchema;
|
use GraphQL\Type\Schema as GQLSchema;
|
||||||
use Utopia\App;
|
use Utopia\App;
|
||||||
use Utopia\Database\Database;
|
|
||||||
use Utopia\Database\Query;
|
|
||||||
use Utopia\Database\Validator\Authorization;
|
|
||||||
use Utopia\Route;
|
use Utopia\Route;
|
||||||
|
|
||||||
class Schema
|
class Schema
|
||||||
|
@ -23,8 +19,9 @@ class Schema
|
||||||
*/
|
*/
|
||||||
public static function build(
|
public static function build(
|
||||||
App $utopia,
|
App $utopia,
|
||||||
string $projectId,
|
callable $complexity,
|
||||||
Database $dbForProject
|
callable $attributes,
|
||||||
|
array $urls
|
||||||
): GQLSchema {
|
): GQLSchema {
|
||||||
App::setResource('utopia:graphql', static function () use ($utopia) {
|
App::setResource('utopia:graphql', static function () use ($utopia) {
|
||||||
return $utopia;
|
return $utopia;
|
||||||
|
@ -34,8 +31,16 @@ class Schema
|
||||||
return self::$schema;
|
return self::$schema;
|
||||||
}
|
}
|
||||||
|
|
||||||
$api = static::api($utopia);
|
$api = static::api(
|
||||||
//$collections = static::collections($utopia, $dbForProject);
|
$utopia,
|
||||||
|
$complexity
|
||||||
|
);
|
||||||
|
//$collections = static::collections(
|
||||||
|
// $utopia,
|
||||||
|
// $complexity,
|
||||||
|
// $attributes,
|
||||||
|
// $urls
|
||||||
|
//);
|
||||||
|
|
||||||
$queries = \array_merge_recursive(
|
$queries = \array_merge_recursive(
|
||||||
$api['query'],
|
$api['query'],
|
||||||
|
@ -69,7 +74,7 @@ class Schema
|
||||||
* @return array
|
* @return array
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected static function api(App $utopia): array
|
protected static function api(App $utopia, callable $complexity): array
|
||||||
{
|
{
|
||||||
Mapper::init($utopia
|
Mapper::init($utopia
|
||||||
->getResource('response')
|
->getResource('response')
|
||||||
|
@ -90,7 +95,7 @@ class Schema
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Mapper::route($utopia, $route) as $field) {
|
foreach (Mapper::route($utopia, $route, $complexity) as $field) {
|
||||||
switch ($route->getMethod()) {
|
switch ($route->getMethod()) {
|
||||||
case 'GET':
|
case 'GET':
|
||||||
$queries[$name] = $field;
|
$queries[$name] = $field;
|
||||||
|
@ -119,43 +124,37 @@ class Schema
|
||||||
* queries and mutations for the collections they make up.
|
* queries and mutations for the collections they make up.
|
||||||
*
|
*
|
||||||
* @param App $utopia
|
* @param App $utopia
|
||||||
* @param Database $dbForProject
|
* @param callable $getAttributes
|
||||||
* @return array
|
* @return array
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected static function collections(
|
protected static function collections(
|
||||||
App $utopia,
|
App $utopia,
|
||||||
Database $dbForProject
|
callable $complexity,
|
||||||
|
callable $attributes,
|
||||||
|
array $urls
|
||||||
): array {
|
): array {
|
||||||
$collections = [];
|
$collections = [];
|
||||||
$queryFields = [];
|
$queryFields = [];
|
||||||
$mutationFields = [];
|
$mutationFields = [];
|
||||||
$limit = 1000;
|
$limit = 1000;
|
||||||
$offset = 0;
|
$offset = 0;
|
||||||
$count = 0;
|
|
||||||
|
|
||||||
while (
|
|
||||||
!empty($attrs = Authorization::skip(fn() => $dbForProject->find('attributes', [
|
|
||||||
Query::limit($limit),
|
|
||||||
Query::offset($offset),
|
|
||||||
])))
|
|
||||||
) {
|
|
||||||
$count += count($attrs);
|
|
||||||
|
|
||||||
|
while (!empty($attrs = $attributes($limit, $offset))) {
|
||||||
foreach ($attrs as $attr) {
|
foreach ($attrs as $attr) {
|
||||||
if ($attr->getAttribute('status') !== 'available') {
|
if ($attr['status'] !== 'available') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$databaseId = $attr->getAttribute('databaseId');
|
$databaseId = $attr['databaseId'];
|
||||||
$collectionId = $attr->getAttribute('collectionId');
|
$collectionId = $attr['collectionId'];
|
||||||
$key = $attr->getAttribute('key');
|
$key = $attr['key'];
|
||||||
$type = $attr->getAttribute('type');
|
$type = $attr['type'];
|
||||||
$array = $attr->getAttribute('array');
|
$array = $attr['array'];
|
||||||
$required = $attr->getAttribute('required');
|
$required = $attr['required'];
|
||||||
$default = $attr->getAttribute('default');
|
$default = $attr['default'];
|
||||||
$escapedKey = str_replace('$', '_', $key);
|
$escapedKey = str_replace('$', '_', $key);
|
||||||
$collections[$collectionId][$escapedKey] = [
|
$collections[$collectionId][$escapedKey] = [
|
||||||
'type' => Mapper::fromCollectionAttribute(
|
'type' => Mapper::attribute(
|
||||||
$type,
|
$type,
|
||||||
$array,
|
$array,
|
||||||
$required
|
$required
|
||||||
|
@ -174,35 +173,29 @@ class Schema
|
||||||
]);
|
]);
|
||||||
$attributes = \array_merge(
|
$attributes = \array_merge(
|
||||||
$attributes,
|
$attributes,
|
||||||
Mapper::argumentsFor('mutate')
|
Mapper::args('mutate')
|
||||||
);
|
);
|
||||||
|
|
||||||
$queryFields[$collectionId . 'Get'] = [
|
$queryFields[$collectionId . 'Get'] = [
|
||||||
'type' => $objectType,
|
'type' => $objectType,
|
||||||
'args' => Mapper::argumentsFor('id'),
|
'args' => Mapper::args('id'),
|
||||||
'resolve' => Resolvers::documentGet(
|
'resolve' => Resolvers::documentGet(
|
||||||
$utopia,
|
$utopia,
|
||||||
$dbForProject,
|
|
||||||
$databaseId,
|
$databaseId,
|
||||||
$collectionId
|
$collectionId,
|
||||||
|
$urls['get'],
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
$queryFields[$collectionId . 'List'] = [
|
$queryFields[$collectionId . 'List'] = [
|
||||||
'type' => Type::listOf($objectType),
|
'type' => Type::listOf($objectType),
|
||||||
'args' => Mapper::argumentsFor('list'),
|
'args' => Mapper::args('list'),
|
||||||
'resolve' => Resolvers::documentList(
|
'resolve' => Resolvers::documentList(
|
||||||
$utopia,
|
$utopia,
|
||||||
$dbForProject,
|
|
||||||
$databaseId,
|
$databaseId,
|
||||||
$collectionId
|
$collectionId,
|
||||||
|
$urls['list'],
|
||||||
),
|
),
|
||||||
'complexity' => function (int $complexity, array $args) {
|
'complexity' => $complexity,
|
||||||
$queries = Query::parseQueries($args['queries'] ?? []);
|
|
||||||
$query = Query::getByType($queries, Query::TYPE_LIMIT)[0] ?? null;
|
|
||||||
$limit = $query ? $query->getValue() : APP_LIMIT_LIST_DEFAULT;
|
|
||||||
|
|
||||||
return $complexity * $limit;
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
$mutationFields[$collectionId . 'Create'] = [
|
$mutationFields[$collectionId . 'Create'] = [
|
||||||
|
@ -210,15 +203,15 @@ class Schema
|
||||||
'args' => $attributes,
|
'args' => $attributes,
|
||||||
'resolve' => Resolvers::documentCreate(
|
'resolve' => Resolvers::documentCreate(
|
||||||
$utopia,
|
$utopia,
|
||||||
$dbForProject,
|
|
||||||
$databaseId,
|
$databaseId,
|
||||||
$collectionId,
|
$collectionId,
|
||||||
|
$urls['create'],
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
$mutationFields[$collectionId . 'Update'] = [
|
$mutationFields[$collectionId . 'Update'] = [
|
||||||
'type' => $objectType,
|
'type' => $objectType,
|
||||||
'args' => \array_merge(
|
'args' => \array_merge(
|
||||||
Mapper::argumentsFor('id'),
|
Mapper::args('id'),
|
||||||
\array_map(
|
\array_map(
|
||||||
fn($attr) => $attr['type'] = Type::getNullableType($attr['type']),
|
fn($attr) => $attr['type'] = Type::getNullableType($attr['type']),
|
||||||
$attributes
|
$attributes
|
||||||
|
@ -226,19 +219,19 @@ class Schema
|
||||||
),
|
),
|
||||||
'resolve' => Resolvers::documentUpdate(
|
'resolve' => Resolvers::documentUpdate(
|
||||||
$utopia,
|
$utopia,
|
||||||
$dbForProject,
|
|
||||||
$databaseId,
|
$databaseId,
|
||||||
$collectionId,
|
$collectionId,
|
||||||
|
$urls['update'],
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
$mutationFields[$collectionId . 'Delete'] = [
|
$mutationFields[$collectionId . 'Delete'] = [
|
||||||
'type' => Mapper::fromResponseModel(Response::MODEL_NONE),
|
'type' => Mapper::model('none'),
|
||||||
'args' => Mapper::argumentsFor('id'),
|
'args' => Mapper::args('id'),
|
||||||
'resolve' => Resolvers::documentDelete(
|
'resolve' => Resolvers::documentDelete(
|
||||||
$utopia,
|
$utopia,
|
||||||
$dbForProject,
|
|
||||||
$databaseId,
|
$databaseId,
|
||||||
$collectionId
|
$collectionId,
|
||||||
|
$urls['delete'],
|
||||||
)
|
)
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue