mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-29 00:25:17 +03:00
365 lines
9.2 KiB
PHP
365 lines
9.2 KiB
PHP
|
<?php
|
||
|
namespace GraphQL\Executor;
|
||
|
|
||
|
use GraphQL\Language\Parser;
|
||
|
use GraphQL\Schema;
|
||
|
use GraphQL\Type\Definition\Config;
|
||
|
use GraphQL\Type\Definition\InterfaceType;
|
||
|
use GraphQL\Type\Definition\ObjectType;
|
||
|
use GraphQL\Type\Definition\Type;
|
||
|
use GraphQL\Type\Definition\UnionType;
|
||
|
|
||
|
class UnionInterfaceTest extends \PHPUnit_Framework_TestCase
|
||
|
{
|
||
|
public $schema;
|
||
|
public $garfield;
|
||
|
public $odie;
|
||
|
public $liz;
|
||
|
public $john;
|
||
|
|
||
|
public function setUp()
|
||
|
{
|
||
|
$NamedType = new InterfaceType([
|
||
|
'name' => 'Named',
|
||
|
'fields' => [
|
||
|
'name' => ['type' => Type::string()]
|
||
|
]
|
||
|
]);
|
||
|
|
||
|
$DogType = new ObjectType([
|
||
|
'name' => 'Dog',
|
||
|
'interfaces' => [$NamedType],
|
||
|
'fields' => [
|
||
|
'name' => ['type' => Type::string()],
|
||
|
'barks' => ['type' => Type::boolean()]
|
||
|
],
|
||
|
'isTypeOf' => function ($value) {
|
||
|
return $value instanceof Dog;
|
||
|
}
|
||
|
]);
|
||
|
|
||
|
$CatType = new ObjectType([
|
||
|
'name' => 'Cat',
|
||
|
'interfaces' => [$NamedType],
|
||
|
'fields' => [
|
||
|
'name' => ['type' => Type::string()],
|
||
|
'meows' => ['type' => Type::boolean()]
|
||
|
],
|
||
|
'isTypeOf' => function ($value) {
|
||
|
return $value instanceof Cat;
|
||
|
}
|
||
|
]);
|
||
|
|
||
|
$PetType = new UnionType([
|
||
|
'name' => 'Pet',
|
||
|
'types' => [$DogType, $CatType],
|
||
|
'resolveType' => function ($value) use ($DogType, $CatType) {
|
||
|
if ($value instanceof Dog) {
|
||
|
return $DogType;
|
||
|
}
|
||
|
if ($value instanceof Cat) {
|
||
|
return $CatType;
|
||
|
}
|
||
|
}
|
||
|
]);
|
||
|
|
||
|
$PersonType = new ObjectType([
|
||
|
'name' => 'Person',
|
||
|
'interfaces' => [$NamedType],
|
||
|
'fields' => [
|
||
|
'name' => ['type' => Type::string()],
|
||
|
'pets' => ['type' => Type::listOf($PetType)],
|
||
|
'friends' => ['type' => Type::listOf($NamedType)]
|
||
|
],
|
||
|
'isTypeOf' => 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]);
|
||
|
|
||
|
}
|
||
|
|
||
|
// Execute: Union and intersection types
|
||
|
public function testCanIntrospectOnUnionAndIntersectionTypes()
|
||
|
{
|
||
|
|
||
|
$ast = Parser::parse('
|
||
|
{
|
||
|
Named: __type(name: "Named") {
|
||
|
kind
|
||
|
name
|
||
|
fields { name }
|
||
|
interfaces { name }
|
||
|
possibleTypes { name }
|
||
|
enumValues { name }
|
||
|
inputFields { name }
|
||
|
}
|
||
|
Pet: __type(name: "Pet") {
|
||
|
kind
|
||
|
name
|
||
|
fields { name }
|
||
|
interfaces { name }
|
||
|
possibleTypes { name }
|
||
|
enumValues { name }
|
||
|
inputFields { name }
|
||
|
}
|
||
|
}
|
||
|
');
|
||
|
|
||
|
$expected = [
|
||
|
'data' => [
|
||
|
'Named' => [
|
||
|
'kind' => 'INTERFACE',
|
||
|
'name' => 'Named',
|
||
|
'fields' => [
|
||
|
['name' => 'name']
|
||
|
],
|
||
|
'interfaces' => null,
|
||
|
'possibleTypes' => [
|
||
|
['name' => 'Dog'],
|
||
|
['name' => 'Cat'],
|
||
|
['name' => 'Person']
|
||
|
],
|
||
|
'enumValues' => null,
|
||
|
'inputFields' => null
|
||
|
],
|
||
|
'Pet' => [
|
||
|
'kind' => 'UNION',
|
||
|
'name' => 'Pet',
|
||
|
'fields' => null,
|
||
|
'interfaces' => null,
|
||
|
'possibleTypes' => [
|
||
|
['name' => 'Dog'],
|
||
|
['name' => 'Cat']
|
||
|
],
|
||
|
'enumValues' => null,
|
||
|
'inputFields' => null
|
||
|
]
|
||
|
]
|
||
|
];
|
||
|
$this->assertEquals($expected, Executor::execute($this->schema, null, $ast));
|
||
|
}
|
||
|
|
||
|
public function testExecutesUsingUnionTypes()
|
||
|
{
|
||
|
// NOTE: This is an *invalid* query, but it should be an *executable* query.
|
||
|
$ast = Parser::parse('
|
||
|
{
|
||
|
__typename
|
||
|
name
|
||
|
pets {
|
||
|
__typename
|
||
|
name
|
||
|
barks
|
||
|
meows
|
||
|
}
|
||
|
}
|
||
|
');
|
||
|
$expected = [
|
||
|
'data' => [
|
||
|
'__typename' => 'Person',
|
||
|
'name' => 'John',
|
||
|
'pets' => [
|
||
|
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
||
|
['__typename' => 'Dog', 'name' => 'Odie', 'barks' => true]
|
||
|
]
|
||
|
]
|
||
|
];
|
||
|
|
||
|
$this->assertEquals($expected, Executor::execute($this->schema, $this->john, $ast));
|
||
|
}
|
||
|
|
||
|
public function testExecutesUnionTypesWithInlineFragments()
|
||
|
{
|
||
|
// This is the valid version of the query in the above test.
|
||
|
$ast = Parser::parse('
|
||
|
{
|
||
|
__typename
|
||
|
name
|
||
|
pets {
|
||
|
__typename
|
||
|
... on Dog {
|
||
|
name
|
||
|
barks
|
||
|
}
|
||
|
... on Cat {
|
||
|
name
|
||
|
meows
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
');
|
||
|
$expected = [
|
||
|
'data' => [
|
||
|
'__typename' => 'Person',
|
||
|
'name' => 'John',
|
||
|
'pets' => [
|
||
|
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
||
|
['__typename' => 'Dog', 'name' => 'Odie', 'barks' => true]
|
||
|
]
|
||
|
|
||
|
]
|
||
|
];
|
||
|
$this->assertEquals($expected, Executor::execute($this->schema, $this->john, $ast));
|
||
|
}
|
||
|
|
||
|
public function testExecutesUsingInterfaceTypes()
|
||
|
{
|
||
|
// NOTE: This is an *invalid* query, but it should be an *executable* query.
|
||
|
$ast = Parser::parse('
|
||
|
{
|
||
|
__typename
|
||
|
name
|
||
|
friends {
|
||
|
__typename
|
||
|
name
|
||
|
barks
|
||
|
meows
|
||
|
}
|
||
|
}
|
||
|
');
|
||
|
$expected = [
|
||
|
'data' => [
|
||
|
'__typename' => 'Person',
|
||
|
'name' => 'John',
|
||
|
'friends' => [
|
||
|
['__typename' => 'Person', 'name' => 'Liz'],
|
||
|
['__typename' => 'Dog', 'name' => 'Odie', 'barks' => true]
|
||
|
]
|
||
|
]
|
||
|
];
|
||
|
|
||
|
$this->assertEquals($expected, Executor::execute($this->schema, $this->john, $ast));
|
||
|
}
|
||
|
|
||
|
public function testExecutesInterfaceTypesWithInlineFragments()
|
||
|
{
|
||
|
// This is the valid version of the query in the above test.
|
||
|
$ast = Parser::parse('
|
||
|
{
|
||
|
__typename
|
||
|
name
|
||
|
friends {
|
||
|
__typename
|
||
|
name
|
||
|
... on Dog {
|
||
|
barks
|
||
|
}
|
||
|
... on Cat {
|
||
|
meows
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
');
|
||
|
$expected = [
|
||
|
'data' => [
|
||
|
'__typename' => 'Person',
|
||
|
'name' => 'John',
|
||
|
'friends' => [
|
||
|
['__typename' => 'Person', 'name' => 'Liz'],
|
||
|
['__typename' => 'Dog', 'name' => 'Odie', 'barks' => true]
|
||
|
]
|
||
|
]
|
||
|
];
|
||
|
|
||
|
$this->assertEquals($expected, Executor::execute($this->schema, $this->john, $ast));
|
||
|
}
|
||
|
|
||
|
public function testAllowsFragmentConditionsToBeAbstractTypes()
|
||
|
{
|
||
|
$ast = Parser::parse('
|
||
|
{
|
||
|
__typename
|
||
|
name
|
||
|
pets { ...PetFields }
|
||
|
friends { ...FriendFields }
|
||
|
}
|
||
|
|
||
|
fragment PetFields on Pet {
|
||
|
__typename
|
||
|
... on Dog {
|
||
|
name
|
||
|
barks
|
||
|
}
|
||
|
... on Cat {
|
||
|
name
|
||
|
meows
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fragment FriendFields on Named {
|
||
|
__typename
|
||
|
name
|
||
|
... on Dog {
|
||
|
barks
|
||
|
}
|
||
|
... on Cat {
|
||
|
meows
|
||
|
}
|
||
|
}
|
||
|
');
|
||
|
|
||
|
$expected = [
|
||
|
'data' => [
|
||
|
'__typename' => 'Person',
|
||
|
'name' => 'John',
|
||
|
'pets' => [
|
||
|
['__typename' => 'Cat', 'name' => 'Garfield', 'meows' => false],
|
||
|
['__typename' => 'Dog', 'name' => 'Odie', 'barks' => true]
|
||
|
],
|
||
|
'friends' => [
|
||
|
['__typename' => 'Person', 'name' => 'Liz'],
|
||
|
['__typename' => 'Dog', 'name' => 'Odie', 'barks' => true]
|
||
|
]
|
||
|
]
|
||
|
];
|
||
|
|
||
|
$this->assertEquals($expected, Executor::execute($this->schema, $this->john, $ast));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
class Dog
|
||
|
{
|
||
|
public $name;
|
||
|
public $barks;
|
||
|
|
||
|
function __construct($name, $barks)
|
||
|
{
|
||
|
$this->name = $name;
|
||
|
$this->barks = $barks;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Cat
|
||
|
{
|
||
|
public $name;
|
||
|
public $meows;
|
||
|
|
||
|
function __construct($name, $meows)
|
||
|
{
|
||
|
$this->name = $name;
|
||
|
$this->meows = $meows;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class Person
|
||
|
{
|
||
|
public $name;
|
||
|
public $pets;
|
||
|
public $friends;
|
||
|
|
||
|
function __construct($name, $pets = null, $friends = null)
|
||
|
{
|
||
|
$this->name = $name;
|
||
|
$this->pets = $pets;
|
||
|
$this->friends = $friends;
|
||
|
}
|
||
|
}
|