QueryPlan can now be used on interfaces not only objects.

It's often the case to use interfaces in queries:

interface Pet { name: String! }

Query {
 pets: [Pet]
}
This commit is contained in:
Aurélien David 2019-06-12 11:59:42 +02:00
parent 6f6a39468c
commit e87460880c
No known key found for this signature in database
GPG Key ID: 2BC66BC4369752CB
2 changed files with 116 additions and 1 deletions

View File

@ -140,9 +140,11 @@ class QueryPlan
/** /**
* @return mixed[] * @return mixed[]
* *
* $parentType InterfaceType|ObjectType.
*
* @throws Error * @throws Error
*/ */
private function analyzeSelectionSet(SelectionSetNode $selectionSet, ObjectType $parentType) : array private function analyzeSelectionSet(SelectionSetNode $selectionSet, Type $parentType) : array
{ {
$fields = []; $fields = [];
foreach ($selectionSet->selections as $selectionNode) { foreach ($selectionSet->selections as $selectionNode) {

View File

@ -5,6 +5,8 @@ declare(strict_types=1);
namespace GraphQL\Tests\Type; namespace GraphQL\Tests\Type;
use GraphQL\GraphQL; use GraphQL\GraphQL;
use GraphQL\Tests\Executor\TestClasses\Dog;
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\ObjectType; use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\QueryPlan; use GraphQL\Type\Definition\QueryPlan;
use GraphQL\Type\Definition\ResolveInfo; use GraphQL\Type\Definition\ResolveInfo;
@ -295,6 +297,117 @@ final class QueryPlanTest extends TestCase
self::assertFalse($queryPlan->hasType('Test')); self::assertFalse($queryPlan->hasType('Test'));
} }
public function testQueryPlanOnInterface() : void
{
$petType = new InterfaceType([
'name' => 'Pet',
'fields' => static function () {
return [
'name' => ['type' => Type::string()],
];
},
]);
$dogType = new ObjectType([
'name' => 'Dog',
'interfaces' => [$petType],
'isTypeOf' => static function ($obj) {
return $obj instanceof Dog;
},
'fields' => static function () {
return [
'name' => ['type' => Type::string()],
'woofs' => ['type' => Type::boolean()],
];
},
]);
$query = 'query Test {
pets {
name
... on Dog {
woofs
}
}
}';
$expectedQueryPlan = [
'woofs' => [
'type' => Type::boolean(),
'fields' => [],
'args' => [],
],
'name' => [
'type' => Type::string(),
'args' => [],
'fields' => [],
],
];
$expectedReferencedTypes = [
'Dog',
'Pet',
];
$expectedReferencedFields = [
'woofs',
'name',
];
/** @var QueryPlan $queryPlan */
$queryPlan = null;
$hasCalled = false;
$petsQuery = new ObjectType([
'name' => 'Query',
'fields' => [
'pets' => [
'type' => Type::listOf($petType),
'resolve' => static function (
$value,
$args,
$context,
ResolveInfo $info
) use (
&$hasCalled,
&$queryPlan
) {
$hasCalled = true;
$queryPlan = $info->lookAhead();
return [];
},
],
],
]);
$schema = new Schema([
'query' => $petsQuery,
'types' => [$dogType],
'typeLoader' => static function ($name) use ($dogType, $petType) {
switch ($name) {
case 'Dog':
return $dogType;
case 'Pet':
return $petType;
}
},
]);
$result = GraphQL::executeQuery($schema, $query)->toArray();
self::assertTrue($hasCalled);
self::assertEquals($expectedQueryPlan, $queryPlan->queryPlan());
self::assertEquals($expectedReferencedTypes, $queryPlan->getReferencedTypes());
self::assertEquals($expectedReferencedFields, $queryPlan->getReferencedFields());
self::assertEquals(['woofs'], $queryPlan->subFields('Dog'));
self::assertTrue($queryPlan->hasField('name'));
self::assertFalse($queryPlan->hasField('test'));
self::assertTrue($queryPlan->hasType('Dog'));
self::assertFalse($queryPlan->hasType('Test'));
}
public function testMergedFragmentsQueryPlan() : void public function testMergedFragmentsQueryPlan() : void
{ {
$image = new ObjectType([ $image = new ObjectType([