Add resolvers for get, list, create, update, delete for user collections
This commit is contained in:
parent
69e7c2fed9
commit
48ba76f365
|
@ -1,6 +1,5 @@
|
|||
<?php
|
||||
|
||||
use Appwrite\GraphQL\GraphQLPromiseAdapter;
|
||||
use Appwrite\Utopia\Response;
|
||||
use GraphQL\Error\DebugFlag;
|
||||
use GraphQL\Executor\ExecutionResult;
|
||||
|
@ -29,9 +28,15 @@ App::post('/v1/graphql')
|
|||
|
||||
$query = $request->getPayload('query', '');
|
||||
$variables = $request->getPayload('variables');
|
||||
|
||||
$response->setContentType(Response::CONTENT_TYPE_NULL);
|
||||
|
||||
$register->set('__app', function () use ($utopia) {
|
||||
return $utopia;
|
||||
});
|
||||
$register->set('__response', function () use ($response) {
|
||||
return $response;
|
||||
});
|
||||
|
||||
$isDevelopment = App::isDevelopment();
|
||||
|
||||
$debugFlags = $isDevelopment
|
||||
|
|
14
app/init.php
14
app/init.php
|
@ -789,6 +789,8 @@ App::setResource('dbForProject', function($db, $cache, $project) {
|
|||
$database->setDefaultDatabase(App::getEnv('_APP_DB_SCHEMA', 'appwrite'));
|
||||
$database->setNamespace("_{$project->getId()}");
|
||||
|
||||
Console::info("Getting dbForProject with ID: {$project->getId()}");
|
||||
|
||||
return $database;
|
||||
}, ['db', 'cache', 'project']);
|
||||
|
||||
|
@ -858,16 +860,14 @@ App::setResource('geodb', function($register) {
|
|||
|
||||
App::setResource('schema', function($utopia, $response, $request, $register, $dbForProject) {
|
||||
try {
|
||||
// Try to get the schema from the register.
|
||||
// If there is no base schema catch the exception and generate it.
|
||||
// If the base schema exists, extend it with the current project schema.
|
||||
Console::log('Getting Schema from register...');
|
||||
Console::log('Getting GraphQL schema from register...');
|
||||
$schema = $register->get('_schema');
|
||||
$schema = Builder::appendSchema($schema, $dbForProject);
|
||||
} catch (Exception $e) {
|
||||
Console::error('Schema not present. Generating Schema...');
|
||||
} catch (\Exception $e) {
|
||||
Console::error('Base GraphQL schema not present. Generating...');
|
||||
$schema = Builder::buildSchema($utopia, $response, $register, $dbForProject);
|
||||
$register->set('_schema', function () use ($schema){
|
||||
Console::error('Built GraphQL schema: ' . \json_encode($schema));
|
||||
$register->set('_schema', function () use ($schema) {
|
||||
return $schema;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ use Utopia\WebSocket\Adapter;
|
|||
|
||||
require_once __DIR__ . '/init.php';
|
||||
|
||||
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
|
||||
Runtime::enableCoroutine(true,SWOOLE_HOOK_ALL);
|
||||
|
||||
$realtime = new Realtime();
|
||||
|
||||
|
|
24
composer.lock
generated
24
composer.lock
generated
|
@ -1583,16 +1583,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
"version": "v3.0.0",
|
||||
"version": "v3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||
"reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced"
|
||||
"reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/c726b64c1ccfe2896cb7df2e1331c357ad1c8ced",
|
||||
"reference": "c726b64c1ccfe2896cb7df2e1331c357ad1c8ced",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/26954b3d62a6c5fd0ea8a2a00c0353a14978d05c",
|
||||
"reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1630,7 +1630,7 @@
|
|||
"description": "A generic function and convention to trigger deprecation notices",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.0"
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1646,7 +1646,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-11-01T23:48:49+00:00"
|
||||
"time": "2022-01-02T09:55:41+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
|
@ -6127,16 +6127,16 @@
|
|||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
"version": "v3.0.0",
|
||||
"version": "v3.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/service-contracts.git",
|
||||
"reference": "36715ebf9fb9db73db0cb24263c79077c6fe8603"
|
||||
"reference": "e517458f278c2131ca9f262f8fbaf01410f2c65c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/36715ebf9fb9db73db0cb24263c79077c6fe8603",
|
||||
"reference": "36715ebf9fb9db73db0cb24263c79077c6fe8603",
|
||||
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/e517458f278c2131ca9f262f8fbaf01410f2c65c",
|
||||
"reference": "e517458f278c2131ca9f262f8fbaf01410f2c65c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -6189,7 +6189,7 @@
|
|||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/service-contracts/tree/v3.0.0"
|
||||
"source": "https://github.com/symfony/service-contracts/tree/v3.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -6205,7 +6205,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2021-11-04T17:53:12+00:00"
|
||||
"time": "2022-03-13T20:10:05+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
|
|
|
@ -727,13 +727,13 @@ services:
|
|||
# - '3001:80'
|
||||
|
||||
graphql-explorer:
|
||||
container_name: graphql-explorer
|
||||
container_name: appwrite-graphql-explorer
|
||||
image: appwrite/altair:0.1.0
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
ports:
|
||||
- 9509:3000
|
||||
- "9509:3000"
|
||||
environment:
|
||||
- SERVER_URL=http://localhost/v1/graphql
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@ use GraphQL\Type\Definition\ObjectType;
|
|||
use GraphQL\Type\Definition\Type;
|
||||
use GraphQL\Type\Schema;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Registry\Registry;
|
||||
|
||||
class Builder
|
||||
{
|
||||
|
@ -171,7 +175,7 @@ class Builder
|
|||
Console::log("[INFO] Appending GraphQL Database Schema...");
|
||||
$start = microtime(true);
|
||||
|
||||
$db = self::buildDatabaseSchema($dbForProject);
|
||||
$db = self::buildCollectionsSchema($dbForProject);
|
||||
|
||||
$queryFields = $schema->getQueryType()?->getFields() ?? [];
|
||||
$mutationFields = $schema->getMutationType()?->getFields() ?? [];
|
||||
|
@ -201,10 +205,13 @@ class Builder
|
|||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function buildSchema($utopia, $response, $register, $dbForProject): Schema
|
||||
{
|
||||
$db = self::buildDatabaseSchema($dbForProject);
|
||||
$api = self::buildAPISchema($utopia, $response, $register, $dbForProject);
|
||||
$db = self::buildCollectionsSchema($dbForProject, $register);
|
||||
$api = self::buildAPISchema($utopia, $response, $register);
|
||||
|
||||
$queryFields = \array_merge($api['query'], $db['query']);
|
||||
$mutationFields = \array_merge($api['mutation'], $db['mutation']);
|
||||
|
@ -215,12 +222,12 @@ class Builder
|
|||
return new Schema([
|
||||
'query' => new ObjectType([
|
||||
'name' => 'Query',
|
||||
'description' => 'The root of all your queries',
|
||||
'description' => 'The root of all queries',
|
||||
'fields' => $queryFields
|
||||
]),
|
||||
'mutation' => new ObjectType([
|
||||
'name' => 'Mutation',
|
||||
'description' => 'The root of all your mutations',
|
||||
'description' => 'The root of all mutations',
|
||||
'fields' => $mutationFields
|
||||
])
|
||||
]);
|
||||
|
@ -230,77 +237,120 @@ class Builder
|
|||
* This function goes through all the project attributes and builds a
|
||||
* GraphQL schema for all the collections they make up.
|
||||
*
|
||||
* @param $dbForProject
|
||||
* @param Database $dbForProject
|
||||
* @return array
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function buildDatabaseSchema($dbForProject): array
|
||||
public static function buildCollectionsSchema(Database $dbForProject, Registry &$register): array
|
||||
{
|
||||
Console::log("[INFO] Building GraphQL Database Schema...");
|
||||
$start = microtime(true);
|
||||
|
||||
$attrs = $dbForProject->getCollection('attributes');
|
||||
|
||||
$collections = [];
|
||||
$queryFields = [];
|
||||
$mutationFields = [];
|
||||
$collections = [];
|
||||
$offset = 0;
|
||||
|
||||
foreach ($attrs as $attr) {
|
||||
$collectionId = $attr->getAttribute('collectionId');
|
||||
Authorization::skip(function () use ($mutationFields, $queryFields, $collections, $register, $offset, $dbForProject) {
|
||||
while (!empty($attrs = $dbForProject->find(
|
||||
'attributes',
|
||||
limit: $dbForProject->getAttributeLimit(),
|
||||
offset: $offset
|
||||
))) {
|
||||
go(function ($attrs, $dbForProject, $register, $collections, $queryFields, $mutationFields) {
|
||||
foreach ($attrs as $attr) {
|
||||
go(function ($attr, &$collections) {
|
||||
/** @var Document $attr */
|
||||
|
||||
if (isset(self::$typeMapping[$collectionId])) {
|
||||
continue;
|
||||
}
|
||||
$collectionId = $attr->getAttribute('collectionId');
|
||||
|
||||
$key = $attr->getAttribute('key');
|
||||
$type = $attr->getAttribute('type');
|
||||
$keyWithoutSpecialChars = str_replace('$', '_', $key);
|
||||
if (isset(self::$typeMapping[$collectionId])) {
|
||||
return;
|
||||
}
|
||||
if ($attr->getAttribute('status') !== 'available') {
|
||||
return;
|
||||
}
|
||||
|
||||
$collections[$collectionId][$keyWithoutSpecialChars] = [
|
||||
'type' => $type,
|
||||
'resolve' => function ($object, $args, $context, $info) use ($key) {
|
||||
return $object->getAttribute($key);
|
||||
}
|
||||
];
|
||||
}
|
||||
$key = $attr->getAttribute('key');
|
||||
$type = $attr->getAttribute('type');
|
||||
|
||||
$args = [];
|
||||
$escapedKey = str_replace('$', '_', $key);
|
||||
|
||||
foreach ($collections as $id => $fields) {
|
||||
$objectType = new ObjectType([
|
||||
'name' => $id,
|
||||
'fields' => $fields
|
||||
]);
|
||||
$collections[$collectionId][$escapedKey] = [
|
||||
'type' => $type,
|
||||
'resolve' => function ($object, $args, $context, $info) use ($key) {
|
||||
return $object->getAttribute($key);
|
||||
}
|
||||
];
|
||||
|
||||
self::$typeMapping[$id] = $objectType;
|
||||
|
||||
foreach ($fields as $field => $fieldInfo) {
|
||||
$args[$field] = [
|
||||
'type' => $fieldInfo['type']
|
||||
];
|
||||
}
|
||||
|
||||
$resolve = function ($type, $args, $context, $info) use (&$register, $dbForProject) {
|
||||
return SwoolePromise::create(function (callable $resolve, callable $reject) use ($type, $args, $dbForProject) {
|
||||
try {
|
||||
$resolve($dbForProject->getCollection($type));
|
||||
} catch (\Throwable $e) {
|
||||
$reject($e);
|
||||
}, $attr, $collections);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$field = [
|
||||
'type' => $type,
|
||||
'args' => $args,
|
||||
'resolve' => $resolve
|
||||
];
|
||||
foreach ($collections as $collectionId => $attributes) {
|
||||
go(function ($collectionId, $attributes, $dbForProject, $register, &$queryFields, &$mutationFields) {
|
||||
if (isset(self::$typeMapping[$collectionId])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$queryFields[$id] = $field;
|
||||
$mutationFields[$id] = $field;
|
||||
}
|
||||
$objectType = new ObjectType([
|
||||
'name' => \ucfirst($collectionId),
|
||||
'fields' => $attributes
|
||||
]);
|
||||
|
||||
self::$typeMapping[$collectionId] = $objectType;
|
||||
|
||||
$mutateArgs = [];
|
||||
|
||||
foreach ($attributes as $name => $attribute) {
|
||||
$mutateArgs[$name] = [
|
||||
'type' => $attribute['type']
|
||||
];
|
||||
}
|
||||
|
||||
$idArgs = [
|
||||
'id' => [
|
||||
'type' => Type::string()
|
||||
]
|
||||
];
|
||||
|
||||
$listArgs = [
|
||||
'limit' => [
|
||||
'type' => Type::int()
|
||||
],
|
||||
'offset' => [
|
||||
'type' => Type::int()
|
||||
],
|
||||
'cursor' => [
|
||||
'type' => Type::string()
|
||||
],
|
||||
'orderAttributes' => [
|
||||
'type' => Type::listOf(Type::string())
|
||||
],
|
||||
'orderType' => [
|
||||
'types' => Type::listOf(Type::string())
|
||||
]
|
||||
];
|
||||
|
||||
self::createCollectionGetQuery($collectionId, $register, $dbForProject, $idArgs, $queryFields);
|
||||
self::createCollectionListQuery($collectionId, $register, $dbForProject, $listArgs, $queryFields);
|
||||
self::createCollectionCreateMutation($collectionId, $register, $dbForProject, $mutateArgs, $mutationFields);
|
||||
self::createCollectionUpdateMutation($collectionId, $register, $dbForProject, $mutateArgs, $mutationFields);
|
||||
self::createCollectionDeleteMutation($collectionId, $register, $dbForProject, $idArgs, $mutationFields);
|
||||
|
||||
}, $collectionId, $attributes, $dbForProject, $register, $queryFields, $mutationFields);
|
||||
}
|
||||
}, $attrs, $dbForProject, $register, $collections, $queryFields, $mutationFields);
|
||||
|
||||
$offset += $dbForProject->getAttributeLimit();
|
||||
}
|
||||
});
|
||||
|
||||
$time_elapsed_secs = microtime(true) - $start;
|
||||
Console::log("[INFO] Time Taken To Build Database Schema : ${time_elapsed_secs}s");
|
||||
Console::info('[INFO] Schema : ' . json_encode([
|
||||
'query' => $queryFields,
|
||||
'mutation' => $mutationFields
|
||||
]));
|
||||
|
||||
return [
|
||||
'query' => $queryFields,
|
||||
|
@ -308,6 +358,104 @@ class Builder
|
|||
];
|
||||
}
|
||||
|
||||
private static function createCollectionGetQuery($collectionId, $register, $dbForProject, $args, &$queryFields)
|
||||
{
|
||||
$resolve = function ($type, $args, $context, $info) use ($collectionId, &$register, $dbForProject) {
|
||||
return SwoolePromise::create(function (callable $resolve, callable $reject) use ($collectionId, $type, $args, $dbForProject) {
|
||||
try {
|
||||
$resolve($dbForProject->getDocument($collectionId, $args['id']));
|
||||
} catch (\Throwable $e) {
|
||||
$reject($e);
|
||||
}
|
||||
});
|
||||
};
|
||||
$get = [
|
||||
'type' => \ucfirst($collectionId),
|
||||
'args' => $args,
|
||||
'resolve' => $resolve
|
||||
];
|
||||
$queryFields['get' . \ucfirst($collectionId)] = $get;
|
||||
}
|
||||
|
||||
private static function createCollectionListQuery($collectionId, $register, $dbForProject, $args, &$queryFields)
|
||||
{
|
||||
$resolve = function ($type, $args, $context, $info) use ($collectionId, &$register, $dbForProject) {
|
||||
return SwoolePromise::create(function (callable $resolve, callable $reject) use ($collectionId, $type, $args, $dbForProject) {
|
||||
try {
|
||||
$resolve($dbForProject->getCollection($collectionId));
|
||||
} catch (\Throwable $e) {
|
||||
$reject($e);
|
||||
}
|
||||
});
|
||||
};
|
||||
$list = [
|
||||
'type' => \ucfirst($collectionId),
|
||||
'args' => $args,
|
||||
'resolve' => $resolve
|
||||
];
|
||||
$queryFields['list' . \ucfirst($collectionId)] = $list;
|
||||
}
|
||||
|
||||
private static function createCollectionCreateMutation($collectionId, $register, $dbForProject, $args, &$mutationFields)
|
||||
{
|
||||
$resolve = function ($type, $args, $context, $info) use ($collectionId, &$register, $dbForProject) {
|
||||
return SwoolePromise::create(function (callable $resolve, callable $reject) use ($collectionId, $type, $args, $dbForProject) {
|
||||
try {
|
||||
$resolve($dbForProject->createDocument($collectionId, new Document($args)));
|
||||
} catch (\Throwable $e) {
|
||||
$reject($e);
|
||||
}
|
||||
});
|
||||
};
|
||||
$create = [
|
||||
'type' => \ucfirst($collectionId),
|
||||
'args' => $args,
|
||||
'resolve' => $resolve
|
||||
];
|
||||
$mutationFields['create' . \ucfirst($collectionId)] = $create;
|
||||
}
|
||||
|
||||
private static function createCollectionUpdateMutation($collectionId, $register, $dbForProject, $args, &$mutationFields)
|
||||
{
|
||||
$resolve = function ($type, $args, $context, $info) use ($collectionId, &$register, $dbForProject) {
|
||||
return SwoolePromise::create(function (callable $resolve, callable $reject) use ($collectionId, $type, $args, $dbForProject) {
|
||||
try {
|
||||
$resolve($dbForProject->updateDocument($collectionId, $args['id'], new Document($args)));
|
||||
} catch (\Throwable $e) {
|
||||
$reject($e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$update = [
|
||||
'type' => \ucfirst($collectionId),
|
||||
'args' => $args,
|
||||
'resolve' => $resolve
|
||||
];
|
||||
|
||||
$mutationFields['update' . \ucfirst($collectionId)] = $update;
|
||||
}
|
||||
|
||||
|
||||
private static function createCollectionDeleteMutation($collectionId, $register, $dbForProject, $args, &$mutationFields)
|
||||
{
|
||||
$resolve = function ($type, $args, $context, $info) use ($collectionId, &$register, $dbForProject) {
|
||||
return SwoolePromise::create(function (callable $resolve, callable $reject) use ($collectionId, $type, $args, $dbForProject) {
|
||||
try {
|
||||
$resolve($dbForProject->deleteDocument($collectionId, $args['id']));
|
||||
} catch (\Throwable $e) {
|
||||
$reject($e);
|
||||
}
|
||||
});
|
||||
};
|
||||
$delete = [
|
||||
'type' => \ucfirst($collectionId),
|
||||
'args' => $args,
|
||||
'resolve' => $resolve
|
||||
];
|
||||
$mutationFields['delete' . \ucfirst($collectionId)] = $delete;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function goes through all the REST endpoints in the API and builds a
|
||||
* GraphQL schema for all those routes whose response model is neither empty nor NONE
|
||||
|
@ -315,10 +463,9 @@ class Builder
|
|||
* @param $utopia
|
||||
* @param $response
|
||||
* @param $register
|
||||
* @param $dbForProject
|
||||
* @return array
|
||||
*/
|
||||
public static function buildAPISchema($utopia, $response, $register, $dbForProject): array
|
||||
public static function buildAPISchema($utopia, $response, $register): array
|
||||
{
|
||||
Console::log("[INFO] Building GraphQL API Schema...");
|
||||
$start = microtime(true);
|
||||
|
@ -329,12 +476,17 @@ class Builder
|
|||
|
||||
foreach ($utopia->getRoutes() as $method => $routes) {
|
||||
foreach ($routes as $route) {
|
||||
|
||||
$namespace = $route->getLabel('sdk.namespace', '');
|
||||
$methodName = $namespace . '_' . $route->getLabel('sdk.method', '');
|
||||
$responseModelName = $route->getLabel('sdk.response.model', "");
|
||||
$methodName = $namespace . \ucfirst($route->getLabel('sdk.method', ''));
|
||||
$responseModelName = $route->getLabel('sdk.response.model', "none");
|
||||
|
||||
if ($responseModelName !== "") {
|
||||
Console::info("Namespace: $namespace");
|
||||
Console::info("Method: $methodName");
|
||||
Console::info("Response Model: $responseModelName");
|
||||
Console::info("Raw routes: " . \json_encode($routes));
|
||||
Console::info("Raw route: " . \json_encode($route));
|
||||
|
||||
if ($responseModelName !== "none") {
|
||||
$responseModel = $response->getModel($responseModelName);
|
||||
|
||||
/* Create a GraphQL type for the current response model */
|
||||
|
@ -351,8 +503,8 @@ class Builder
|
|||
];
|
||||
}
|
||||
/* Define a resolve function that defines how to fetch data for this type */
|
||||
$resolve = function ($type, $args, $context, $info) use (&$register, $route, $dbForProject) {
|
||||
return SwoolePromise::create(function (callable $resolve, callable $reject) use (&$register, $route, $dbForProject, $args) {
|
||||
$resolve = function ($type, $args, $context, $info) use (&$register, $route) {
|
||||
return SwoolePromise::create(function (callable $resolve, callable $reject) use (&$register, $route, $args) {
|
||||
$utopia = $register->get('__app');
|
||||
$utopia->setRoute($route)->execute($route, $args);
|
||||
|
||||
|
@ -403,12 +555,12 @@ class Builder
|
|||
* @param string $version
|
||||
* @return callable
|
||||
*/
|
||||
public
|
||||
static function getErrorFormatter(bool $isDevelopment, string $version): callable
|
||||
public static function getErrorFormatter(bool $isDevelopment, string $version): callable
|
||||
{
|
||||
$errorFormatter = function (Error $error) use ($isDevelopment, $version) {
|
||||
return function (Error $error) use ($isDevelopment, $version) {
|
||||
$formattedError = FormattedError::createFromException($error);
|
||||
/** Previous error represents the actual error thrown by Appwrite server */
|
||||
|
||||
// Previous error represents the actual error thrown by Appwrite server
|
||||
$previousError = $error->getPrevious() ?? $error;
|
||||
$formattedError['code'] = $previousError->getCode();
|
||||
$formattedError['version'] = $version;
|
||||
|
@ -418,7 +570,5 @@ class Builder
|
|||
}
|
||||
return $formattedError;
|
||||
};
|
||||
|
||||
return $errorFormatter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
namespace Appwrite\GraphQL;
|
||||
|
||||
use Swoole\Coroutine;
|
||||
use Swoole\Coroutine\Channel;
|
||||
use function Co\go;
|
||||
|
||||
/**
|
||||
* Class SwoolePromise
|
||||
|
@ -40,7 +40,8 @@ class SwoolePromise
|
|||
$this->setState(self::STATE_REJECTED);
|
||||
}
|
||||
};
|
||||
Coroutine::create(function (callable $executor, callable $resolve, callable $reject) {
|
||||
|
||||
go(function (callable $executor, callable $resolve, callable $reject) {
|
||||
try {
|
||||
$executor($resolve, $reject);
|
||||
} catch (\Throwable $exception) {
|
||||
|
|
|
@ -6,17 +6,19 @@ use GraphQL\Error\InvariantViolation;
|
|||
use GraphQL\Executor\Promise\Promise;
|
||||
use GraphQL\Executor\Promise\PromiseAdapter;
|
||||
use GraphQL\Utils\Utils;
|
||||
use function Co\go;
|
||||
use function Co\run;
|
||||
|
||||
class GraphQLPromiseAdapter implements PromiseAdapter
|
||||
class SwoolePromiseAdapter implements PromiseAdapter
|
||||
{
|
||||
public function isThenable($value): bool
|
||||
{
|
||||
return $value instanceof SwoolePromise;
|
||||
return $value instanceof Promise;
|
||||
}
|
||||
|
||||
public function convertThenable($thenable): Promise
|
||||
{
|
||||
if (!$thenable instanceof SwoolePromise) {
|
||||
if (!$thenable instanceof Promise) {
|
||||
throw new InvariantViolation('Expected instance of SwoolePromise, got ' . Utils::printSafe($thenable));
|
||||
}
|
||||
return new Promise($thenable, $this);
|
||||
|
@ -66,25 +68,30 @@ class GraphQLPromiseAdapter implements PromiseAdapter
|
|||
$count = 0;
|
||||
$result = [];
|
||||
|
||||
foreach ($promisesOrValues as $index => $promiseOrValue) {
|
||||
if ($promiseOrValue instanceof Promise) {
|
||||
$result[$index] = null;
|
||||
$promiseOrValue->then(
|
||||
static function ($value) use ($index, &$count, $total, &$result, $all): void {
|
||||
$result[$index] = $value;
|
||||
run(function ($promisesOrValues, $all, $total, &$count, $result) {
|
||||
foreach ($promisesOrValues as $index => $promiseOrValue) {
|
||||
go(function ($index, $promiseOrValue, $all, $total, &$count, $result) {
|
||||
if (!($promiseOrValue instanceof SwoolePromise)) {
|
||||
$result[$index] = $promiseOrValue;
|
||||
$count++;
|
||||
if ($count < $total) {
|
||||
return;
|
||||
}
|
||||
$all->resolve($result);
|
||||
},
|
||||
[$all, 'reject']
|
||||
);
|
||||
} else {
|
||||
$result[$index] = $promiseOrValue;
|
||||
$count++;
|
||||
return;
|
||||
}
|
||||
$result[$index] = null;
|
||||
$promiseOrValue->then(
|
||||
static function ($value) use ($index, &$count, $total, &$result, $all): void {
|
||||
$result[$index] = $value;
|
||||
$count++;
|
||||
if ($count < $total) {
|
||||
return;
|
||||
}
|
||||
$all->resolve($result);
|
||||
},
|
||||
[$all, 'reject']
|
||||
);
|
||||
}, $index, $promiseOrValue, $all, $total, $count, $result);
|
||||
}
|
||||
}
|
||||
}, $promisesOrValues, $all, $total, $count, $result);
|
||||
|
||||
if ($count === $total) {
|
||||
$all->resolve($result);
|
||||
}
|
|
@ -89,7 +89,7 @@ abstract class Migration
|
|||
*/
|
||||
public function forEachDocument(callable $callback): void
|
||||
{
|
||||
Runtime::enableCoroutine(SWOOLE_HOOK_ALL);
|
||||
Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);
|
||||
|
||||
foreach ($this->collections as $collection) {
|
||||
$sum = 0;
|
||||
|
|
Loading…
Reference in a new issue