protected function setUp() { $this->syncError = new \Exception('sync'); $this->nonNullSyncError = new \Exception('nonNullSync'); $this->throwingData = ['sync' => function () { throw $this->syncError; }, 'nonNullSync' => function () { throw $this->nonNullSyncError; }, 'nest' => function () { return $this->throwingData; }, 'nonNullNest' => function () { return $this->throwingData; }]; $this->NULLingData = ['sync' => function () { return NULL; }, 'nonNullSync' => function () { return NULL; }, 'nest' => function () { return $this->NULLingData; }, 'nonNullNest' => function () { return $this->NULLingData; }]; $dataType = new ObjectType('DataType', ['sync' => ['type' => Type::stringType()], 'nonNullSync' => ['type' => new NonNullModifier(Type::stringType())], 'nest' => ['type' => function () use(&$dataType) { return $dataType; }], 'nonNullNest' => ['type' => function () use(&$dataType) { return new NonNullModifier($dataType); }]]); $this->schema = new Schema($dataType); }
protected function setUp() { $namedType = new InterfaceType('Named', ['name' => ['type' => Type::stringType()]]); $dogType = new ObjectType('Dog', ['name' => ['type' => Type::stringType()], 'barks' => ['type' => Type::booleanType()]], [$namedType], function ($value) { return $value instanceof Dog; }); $catType = new ObjectType('Cat', ['name' => ['type' => Type::stringType()], 'meows' => ['type' => Type::booleanType()]], [$namedType], function ($value) { return $value instanceof Cat; }); $petType = new UnionType('Pet', [$dogType, $catType], function ($value) use($dogType, $catType) { if ($value instanceof Dog) { return $dogType; } if ($value instanceof Cat) { return $catType; } return NULL; }); $personType = new ObjectType('Person', ['name' => ['type' => Type::stringType()], 'pets' => ['type' => new ListModifier($petType)], 'friends' => ['type' => new ListModifier($namedType)]], [$namedType], function ($value) { return $value instanceof Person; }); $this->schema = new Schema($personType); $this->garfield = new Cat('Garfield', FALSE); $this->odie = new Dog('Odie', TRUE); $this->liz = new Person('Liz'); $this->john = new Person('John', [$this->garfield, $this->odie], [$this->liz, $this->odie]); }
public function testDefinesAQueryOnlySchema() { $blogSchema = new Schema($this->blogQuery); $this->assertSame($this->blogQuery, $blogSchema->getQueryType()); /** @var \Fubhy\GraphQL\Type\Definition\FieldDefinition $articleField */ /** @var \Fubhy\GraphQL\Type\Definition\Types\ObjectType $articleFieldType */ $articleField = $this->blogQuery->getFields()['article']; $articleFieldType = $articleField->getType(); $this->assertEquals('article', $articleField->getName()); $this->assertSame($this->blogArticle, $articleFieldType); $this->assertEquals('Article', $articleFieldType->getName()); /** @var \Fubhy\GraphQL\Type\Definition\FieldDefinition $titleField */ /** @var \Fubhy\GraphQL\Type\Definition\Types\ObjectType $titleFieldType */ $titleField = $articleFieldType->getFields()['title']; $titleFieldType = $titleField->getType(); $this->assertEquals('title', $titleField->getName()); $this->assertEquals(Type::stringType(), $titleFieldType); $this->assertEquals('String', $titleFieldType->getName()); /** @var \Fubhy\GraphQL\Type\Definition\FieldDefinition $authorField */ /** @var \Fubhy\GraphQL\Type\Definition\Types\ObjectType $authorFieldType */ /** @var \Fubhy\GraphQL\Type\Definition\FieldDefinition $recentArticleField */ $authorField = $articleFieldType->getFields()['author']; $authorFieldType = $authorField->getType(); $recentArticleField = $authorFieldType->getFields()['recentArticle']; $this->assertSame($this->blogArticle, $recentArticleField->getType()); /** @var \Fubhy\GraphQL\Type\Definition\FieldDefinition $feedField */ /** @var \Fubhy\GraphQL\Type\Definition\Types\ListModifier $feedFieldType */ $feedField = $this->blogQuery->getFields()['feed']; $feedFieldType = $feedField->getType(); $this->assertEquals('feed', $feedField->getName()); $this->assertSame($this->blogArticle, $feedFieldType->getWrappedType()); }
public function testExecutesUsingASchema() { $blogArticle = NULL; $blogImage = new ObjectType('Image', ['url' => ['type' => Type::stringType()], 'width' => ['type' => Type::intType()], 'height' => ['type' => Type::intType()]]); $blogAuthor = new ObjectType('Author', ['id' => ['type' => Type::stringType()], 'name' => ['type' => Type::stringType()], 'pic' => ['args' => ['width' => ['type' => Type::intType()], 'height' => ['type' => Type::intType()]], 'type' => $blogImage, 'resolve' => function ($obj, $args) { return $obj['pic']($args['width'], $args['height']); }], 'recentArticle' => ['type' => function () use(&$blogArticle) { return $blogArticle; }]]); $blogArticle = new ObjectType('Article', ['id' => ['type' => new NonNullModifier(Type::stringType())], 'isPublished' => ['type' => Type::booleanType()], 'author' => ['type' => $blogAuthor], 'title' => ['type' => Type::stringType()], 'body' => ['type' => Type::stringType()], 'keywords' => ['type' => new ListModifier(Type::stringType())]]); $blogQuery = new ObjectType('Query', ['article' => ['type' => $blogArticle, 'args' => ['id' => ['type' => Type::idType()]], 'resolve' => function ($_, $args) { return $this->article($args['id']); }], 'feed' => ['type' => new ListModifier($blogArticle), 'resolve' => function () { return [$this->article(1), $this->article(2), $this->article(3), $this->article(4), $this->article(5), $this->article(6), $this->article(7), $this->article(8), $this->article(9), $this->article(10)]; }]]); $blogSchema = new Schema($blogQuery); $request = ' { feed { id, title }, article(id: "1") { ...articleFields, author { id, name, pic(width: 640, height: 480) { url, width, height }, recentArticle { ...articleFields, keywords } } } } fragment articleFields on Article { id, isPublished, title, body, hidden, notdefined } '; $expected = ['data' => ['feed' => [['id' => '1', 'title' => 'My Article 1'], ['id' => '2', 'title' => 'My Article 2'], ['id' => '3', 'title' => 'My Article 3'], ['id' => '4', 'title' => 'My Article 4'], ['id' => '5', 'title' => 'My Article 5'], ['id' => '6', 'title' => 'My Article 6'], ['id' => '7', 'title' => 'My Article 7'], ['id' => '8', 'title' => 'My Article 8'], ['id' => '9', 'title' => 'My Article 9'], ['id' => '10', 'title' => 'My Article 10']], 'article' => ['id' => '1', 'isPublished' => TRUE, 'title' => 'My Article 1', 'body' => 'This is a post', 'author' => ['id' => '123', 'name' => 'John Smith', 'pic' => ['url' => 'cdn://123', 'width' => 640, 'height' => 480], 'recentArticle' => ['id' => '1', 'isPublished' => TRUE, 'title' => 'My Article 1', 'body' => 'This is a post', 'keywords' => ['foo', 'bar', '1', 'true', NULL]]]]]]; $parser = new Parser(); $this->assertEquals($expected, Executor::execute($blogSchema, NULL, $parser->parse(new Source($request)), '', [])); }
/** * @dataProvider coercesOutputStringProvider * * @param mixed $input * @param float|null $expected */ public function testCoercesOutputString($input, $expected) { $this->assertSame($expected, Type::stringType()->coerce($input)); }
public function testRespectsTheIncludeDeprecatedParameterForFields() { $testType = new ObjectType('TestType', ['nonDeprecated' => ['type' => Type::stringType()], 'deprecated' => ['type' => Type::stringType(), 'deprecationReason' => 'Removed in 1.0']]); $schema = new Schema($testType); $request = ' { __type(name: "TestType") { name trueFields: fields(includeDeprecated: true) { name } falseFields: fields(includeDeprecated: false) { name } omittedFields: fields { name } } } '; $expected = ['data' => ['__type' => ['name' => 'TestType', 'trueFields' => [['name' => 'nonDeprecated'], ['name' => 'deprecated']], 'falseFields' => [['name' => 'nonDeprecated']], 'omittedFields' => [['name' => 'nonDeprecated']]]]]; $this->assertEquals($expected, GraphQL::execute($schema, $request)); }
protected function getSchema() { $testInputObject = new InputObjectType('TestInputObject', ['a' => ['type' => Type::stringType()], 'b' => ['type' => new ListModifier(Type::stringType())], 'c' => ['type' => new NonNullModifier(Type::stringType())]]); $testType = new ObjectType('TestType', ['fieldWithObjectInput' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => $testInputObject]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }], 'fieldWithNullableStringInput' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => Type::stringType()]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }], 'fieldWithNonNullableStringInput' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => new NonNullModifier(Type::stringType())]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }], 'list' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => new ListModifier(Type::stringType())]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }], 'nnList' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => new NonNullModifier(new ListModifier(Type::stringType()))]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }], 'listNN' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => new ListModifier(new NonNullModifier(Type::stringType()))]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }], 'nnListNN' => ['type' => Type::stringType(), 'args' => ['input' => ['type' => new NonNullModifier(new ListModifier(new NonNullModifier(Type::stringType())))]], 'resolve' => function ($_, $args) { return json_encode($args['input']); }]]); $schema = new Schema($testType); return $schema; }
/** * Re-populate static properties when de-serializing. */ public function __wakeup() { Type::intType(); Type::booleanType(); Type::floatType(); Type::idType(); Type::stringType(); }
/** * @return \Fubhy\GraphQL\Type\Definition\FieldDefinition */ public static function typeNameMetaFieldDefinition() { if (!isset(static::$typeNameMetaFieldDefinition)) { static::$typeNameMetaFieldDefinition = new FieldDefinition(['name' => '__typename', 'type' => new NonNullModifier(Type::stringType()), 'description' => 'The name of the current Object type at runtime.', 'args' => [], 'resolve' => [__CLASS__, 'resolveTypeNameMetaField']]); } return static::$typeNameMetaFieldDefinition; }
protected function getStarWarsSchema() { /** * The original trilogy consists of three movies. * * This implements the following type system shorthand: * enum Episode { NEWHOPE, EMPIRE, JEDI } */ $episodeEnum = new EnumType('Episode', ['NEWHOPE' => ['value' => 4, 'description' => 'Released in 1977.'], 'EMPIRE' => ['value' => 5, 'description' => 'Released in 1980.'], 'JEDI' => ['value' => 6, 'description' => 'Released in 1983.']], 'One of the films in the Star Wars Trilogy'); $humanType = NULL; $droidType = NULL; /** * Characters in the Star Wars trilogy are either humans or droids. * * This implements the following type system shorthand: * interface Character { * id: String! * name: String * friends: [Character] * appearsIn: [Episode] * } */ $characterInterface = new InterfaceType('Character', ['id' => ['type' => new NonNullModifier(Type::stringType()), 'description' => 'The id of the character.'], 'name' => ['type' => Type::stringType(), 'description' => 'The name of the character.'], 'friends' => ['type' => function () use(&$characterInterface) { return new ListModifier($characterInterface); }, 'description' => 'The friends of the character, or an empty list if they have none.'], 'appearsIn' => ['type' => new ListModifier($episodeEnum), 'description' => 'Which movies they appear in.']], function ($obj) use(&$humanType, &$droidType) { $humans = $this->getHumans(); if (isset($humans[$obj['id']])) { return $humanType; } $droids = $this->getDroids(); if (isset($droids[$obj['id']])) { return $droidType; } return NULL; }, 'A character in the Star Wars Trilogy'); /** * We define our human type, which implements the character interface. * * This implements the following type system shorthand: * type Human : Character { * id: String! * name: String * friends: [Character] * appearsIn: [Episode] * } */ $humanType = new ObjectType('Human', ['id' => ['type' => new NonNullModifier(Type::stringType()), 'description' => 'The id of the human.'], 'name' => ['type' => Type::stringType(), 'description' => 'The name of the human.'], 'friends' => ['type' => new ListModifier($characterInterface), 'description' => 'The friends of the human, or an empty list if they have none.', 'resolve' => function ($human) { return $this->getStarWarsFriends($human); }], 'appearsIn' => ['type' => new ListModifier($episodeEnum), 'description' => 'Which movies they appear in.'], 'homePlanet' => ['type' => Type::stringType(), 'description' => 'The home planet of the human, or null if unknown.']], [$characterInterface], NULL, 'A humanoid creature in the Star Wars universe.'); /** * The other type of character in Star Wars is a droid. * * This implements the following type system shorthand: * type Droid : Character { * id: String! * name: String * friends: [Character] * appearsIn: [Episode] * primaryFunction: String * } */ $droidType = new ObjectType('Droid', ['id' => ['type' => new NonNullModifier(Type::stringType()), 'description' => 'The id of the droid.'], 'name' => ['type' => Type::stringType(), 'description' => 'The name of the droid.'], 'friends' => ['type' => new ListModifier($characterInterface), 'description' => 'The friends of the droid, or an empty list if they have none.', 'resolve' => function ($droid) { return $this->getStarWarsFriends($droid); }], 'appearsIn' => ['type' => new ListModifier($episodeEnum), 'description' => 'Which movies they appear in.'], 'primaryFunction' => ['type' => Type::stringType(), 'description' => 'The primary function of the droid.']], [$characterInterface], NULL, 'A mechanical creature in the Star Wars universe.'); /** * This is the type that will be the root of our query, and the * entry point into our schema. It gives us the ability to fetch * objects by their IDs, as well as to fetch the undisputed hero * of the Star Wars trilogy, R2-D2, directly. * * This implements the following type system shorthand: * type Query { * hero: Character * human(id: String!): Human * droid(id: String!): Droid * } * */ $queryType = new ObjectType('Query', ['hero' => ['type' => $characterInterface, 'args' => ['episode' => ['description' => 'If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode.', 'type' => $episodeEnum]], 'resolve' => function () { return $this->getArtoo(); }], 'human' => ['type' => $humanType, 'args' => ['id' => ['name' => 'id', 'description' => 'The id of the human.', 'type' => new NonNullModifier(Type::stringType())]], 'resolve' => function ($root, array $args) { $humans = $this->getHumans(); return isset($humans[$args['id']]) ? $humans[$args['id']] : NULL; }], 'droid' => ['type' => $droidType, 'args' => ['id' => ['name' => 'id', 'description' => 'The id of the droid.', 'type' => new NonNullModifier(Type::stringType())]], 'resolve' => function ($root, array $args) { $droids = $this->getDroids(); return isset($droids[$args['id']]) ? $droids[$args['id']] : NULL; }]]); return new Schema($queryType); }
protected function executeTestQuery($document) { $data = ['a' => function () { return 'a'; }, 'b' => function () { return 'b'; }]; $schema = new Schema(new ObjectType('TestType', ['a' => ['type' => Type::stringType()], 'b' => ['type' => Type::stringType()]])); $parser = new Parser(); return Executor::execute($schema, $data, $parser->parse(new Source($document))); }
public function testDoesNotIncludeIllegalFieldsInOutput() { $document = ' mutation M { thisIsIllegalDontIncludeMe } '; $parser = new Parser(); $ast = $parser->parse(new Source($document)); $schema = new Schema(new ObjectType('Q', ['a' => ['type' => Type::stringType()]]), new ObjectType('M', ['c' => ['type' => Type::stringType()]])); $result = Executor::execute($schema, NULL, $ast); $this->assertEquals(['data' => []], $result); }