diff --git a/composer.lock b/composer.lock index 5c53d4d7a4..8e57c70340 100644 --- a/composer.lock +++ b/composer.lock @@ -5349,16 +5349,16 @@ }, { "name": "twig/twig", - "version": "v3.4.2", + "version": "v3.4.3", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "e07cdd3d430cd7e453c31b36eb5ad6c0c5e43077" + "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/e07cdd3d430cd7e453c31b36eb5ad6c0c5e43077", - "reference": "e07cdd3d430cd7e453c31b36eb5ad6c0c5e43077", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/c38fd6b0b7f370c198db91ffd02e23b517426b58", + "reference": "c38fd6b0b7f370c198db91ffd02e23b517426b58", "shasum": "" }, "require": { @@ -5409,7 +5409,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.4.2" + "source": "https://github.com/twigphp/Twig/tree/v3.4.3" }, "funding": [ { @@ -5421,7 +5421,7 @@ "type": "tidelift" } ], - "time": "2022-08-12T06:47:24+00:00" + "time": "2022-09-28T08:42:51+00:00" } ], "aliases": [], diff --git a/docker-compose.yml b/docker-compose.yml index 25299833ea..943bdebc33 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -846,7 +846,7 @@ services: graphql-explorer: container_name: appwrite-graphql-explorer - image: appwrite/altair:0.1.0 + image: appwrite/altair:0.2.0 restart: unless-stopped networks: - appwrite diff --git a/src/Appwrite/GraphQL/TypeMapper.php b/src/Appwrite/GraphQL/TypeMapper.php index 14b8867313..33f4eb7591 100644 --- a/src/Appwrite/GraphQL/TypeMapper.php +++ b/src/Appwrite/GraphQL/TypeMapper.php @@ -209,7 +209,11 @@ class TypeMapper foreach ($model->getRules() as $key => $rule) { $escapedKey = str_replace('$', '_', $key); + if (\is_array($rule['type'])) { + $type = self::getUnionType($escapedKey, $rule); + } else { $type = self::getObjectType($rule); + } if ($rule['array']) { $type = Type::listOf($type); @@ -372,4 +376,27 @@ class TypeMapper return self::fromResponseModel(\ucfirst($complexModel->getType())); } + private static function getUnionType(string $name, array $rule): Type + { + $unionName = \ucfirst($name); + + if (TypeRegistry::has($unionName)) { + return TypeRegistry::get($unionName); + } + + $types = []; + foreach ($rule['type'] as $type) { + $types[] = self::fromResponseModel(\ucfirst($type)); + } + + $unionType = new UnionType([ + 'name' => $unionName, + 'types' => $types, + 'resolveType' => static fn($object) => $object['type'], + ]); + + TypeRegistry::set($unionName, $unionType); + + return $unionType; + } } diff --git a/src/Appwrite/GraphQL/TypeRegistry.php b/src/Appwrite/GraphQL/TypeRegistry.php index d2c8e16b59..2342acd267 100644 --- a/src/Appwrite/GraphQL/TypeRegistry.php +++ b/src/Appwrite/GraphQL/TypeRegistry.php @@ -8,54 +8,13 @@ use Appwrite\Utopia\Response; use Appwrite\Utopia\Response\Model; use GraphQL\Type\Definition\ObjectType; use GraphQL\Type\Definition\Type; +use GraphQL\Type\Definition\UnionType; use Utopia\CLI\Console; use Utopia\Database\Database; class TypeRegistry { - private static array $typeMapping = []; - private static array $defaultDocumentArgs = []; - private static array $models = []; - - /** - * Initialize the type registry for the given set of models. - * - * @param array $models - */ - public static function init(array $models): void - { - self::$typeMapping = [ - Model::TYPE_BOOLEAN => Type::boolean(), - Model::TYPE_STRING => Type::string(), - Model::TYPE_INTEGER => Type::int(), - Model::TYPE_FLOAT => Type::float(), - Model::TYPE_DATETIME => Type::string(), - Model::TYPE_JSON => static::json(), - Response::MODEL_NONE => static::json(), - Response::MODEL_ANY => static::json(), - ]; - self::$defaultDocumentArgs = [ - 'id' => [ - 'id' => [ - 'type' => Type::nonNull(Type::string()), - ], - ], - 'list' => [ - 'queries' => [ - 'type' => Type::listOf(Type::nonNull(Type::string())), - 'defaultValue' => [], - ], - ], - 'mutate' => [ - 'permissions' => [ - 'type' => Type::listOf(Type::nonNull(Type::string())), - 'defaultValue' => [], - ] - ], - ]; - - self::$models = $models; - } + private static array $register = []; /** * Check if a type exists in the registry. @@ -65,70 +24,18 @@ class TypeRegistry */ public static function has(string $type): bool { - return isset(self::$typeMapping[$type]); + return isset(self::$register[$type]); } /** - * Get a type from the registry, creating it if it does not already exist. + * Get a type from the registry. * - * @param string $name + * @param string $type * @return Type */ - public static function get(string $name): Type + public static function get(string $type): Type { - if (self::has($name)) { - return self::$typeMapping[$name]; - } - - $fields = []; - - $model = self::$models[\lcfirst($name)]; - - if ($model->isAny()) { - $fields['data'] = [ - 'type' => Type::string(), - 'description' => 'Additional data', - 'resolve' => static fn($object, $args, $context, $info) => \json_encode($object, JSON_FORCE_OBJECT), - ]; - } - - foreach ($model->getRules() as $key => $props) { - $escapedKey = str_replace('$', '_', $key); - - $types = \is_array($props['type']) - ? $props['type'] - : [$props['type']]; - - foreach ($types as $type) { - if (self::has($type)) { - $type = self::$typeMapping[$type]; - } else { - try { - $complexModel = self::$models[$type]; - $type = self::get($complexModel->getType()); - } catch (\Exception) { - Console::error('Could not find model for ' . $type); - } - } - - if ($props['array']) { - $type = Type::listOf($type); - } - - $fields[$escapedKey] = [ - 'type' => $type, - 'description' => $props['description'], - ]; - } - } - $objectType = [ - 'name' => $name, - 'fields' => $fields - ]; - - self::set($name, new ObjectType($objectType)); - - return self::$typeMapping[$name]; + return self::$register[$type]; } /** @@ -139,21 +46,6 @@ class TypeRegistry */ public static function set(string $type, Type $typeObject): void { - self::$typeMapping[$type] = $typeObject; - } - - /** - * Get the registered default arguments for a given key. - * - * @param string $key - * @return array - */ - public static function argumentsFor(string $key): array - { - if (isset(self::$defaultDocumentArgs[$key])) { - return self::$defaultDocumentArgs[$key]; - } - return []; - } + self::$register[$type] = $typeObject; } } diff --git a/tests/unit/GraphQL/BuilderTest.php b/tests/unit/GraphQL/BuilderTest.php index 46cc8d6b5c..6249ba911d 100644 --- a/tests/unit/GraphQL/BuilderTest.php +++ b/tests/unit/GraphQL/BuilderTest.php @@ -27,6 +27,6 @@ class BuilderTest extends TestCase public function testCreateTypeMapping() { $model = $this->response->getModel(Response::MODEL_COLLECTION); - $typeMapping = TypeRegistry::get($model->getType()); + $typeMapping = TypeRegistry::fromModel($model->getType()); } }