mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-25 06:16:05 +03:00
Support for union types when using buildSchema
* Adds support for resolving union/interface types when using a generated schema * Move resolveType __typename checking into defaultResolveType * Clean up existing tests and improve error messages ref: graphql/graphql-js#947 # Conflicts: # src/Utils/BuildSchema.php # tests/Utils/BuildSchemaTest.php
This commit is contained in:
parent
7705e50e44
commit
4e26de3588
@ -1053,15 +1053,6 @@ class Executor
|
||||
$runtimeType = $returnType->resolveType($result, $exeContext->contextValue, $info);
|
||||
|
||||
if (null === $runtimeType) {
|
||||
if ($returnType instanceof InterfaceType && $info->schema->getConfig()->typeLoader) {
|
||||
Warning::warnOnce(
|
||||
"GraphQL Interface Type `{$returnType->name}` returned `null` from it`s `resolveType` function ".
|
||||
'for value: ' . Utils::printSafe($result) . '. Switching to slow resolution method using `isTypeOf` ' .
|
||||
'of all possible implementations. It requires full schema scan and degrades query performance significantly. '.
|
||||
' Make sure your `resolveType` always returns valid implementation or throws.',
|
||||
Warning::WARNING_FULL_SCHEMA_SCAN
|
||||
);
|
||||
}
|
||||
$runtimeType = self::defaultTypeResolver($result, $exeContext->contextValue, $info, $returnType);
|
||||
}
|
||||
|
||||
@ -1122,9 +1113,11 @@ class Executor
|
||||
|
||||
if (!$runtimeType instanceof ObjectType) {
|
||||
throw new InvariantViolation(
|
||||
"Abstract type {$returnType} must resolve to an Object type at runtime " .
|
||||
"for field {$info->parentType}.{$info->fieldName} with " .
|
||||
'value "' . Utils::printSafe($result) . '", received "'. Utils::printSafe($runtimeType) . '".'
|
||||
"Abstract type {$returnType} must resolve to an Object type at " .
|
||||
"runtime for field {$info->parentType}.{$info->fieldName} with " .
|
||||
'value "' . Utils::printSafe($result) . '", received "'. Utils::printSafe($runtimeType) . '".' .
|
||||
'Either the ' . $returnType . ' type should provide a "resolveType" ' .
|
||||
'function or each possible types should provide an "isTypeOf" function.'
|
||||
);
|
||||
}
|
||||
|
||||
@ -1307,7 +1300,12 @@ class Executor
|
||||
|
||||
/**
|
||||
* If a resolveType function is not given, then a default resolve behavior is
|
||||
* used which tests each possible type for the abstract type by calling
|
||||
* used which attempts two strategies:
|
||||
*
|
||||
* First, See if the provided value has a `__typename` field defined, if so, use
|
||||
* that value as name of the resolved type.
|
||||
*
|
||||
* Otherwise, test each possible type for the abstract type by calling
|
||||
* isTypeOf for the object being coerced, returning the first type that matches.
|
||||
*
|
||||
* @param $value
|
||||
@ -1318,6 +1316,27 @@ class Executor
|
||||
*/
|
||||
private function defaultTypeResolver($value, $context, ResolveInfo $info, AbstractType $abstractType)
|
||||
{
|
||||
// First, look for `__typename`.
|
||||
if (
|
||||
$value !== null &&
|
||||
is_array($value) &&
|
||||
isset($value['__typename']) &&
|
||||
is_string($value['__typename'])
|
||||
) {
|
||||
return $value['__typename'];
|
||||
}
|
||||
|
||||
if ($abstractType instanceof InterfaceType && $info->schema->getConfig()->typeLoader) {
|
||||
Warning::warnOnce(
|
||||
"GraphQL Interface Type `{$abstractType->name}` returned `null` from it`s `resolveType` function ".
|
||||
'for value: ' . Utils::printSafe($value) . '. Switching to slow resolution method using `isTypeOf` ' .
|
||||
'of all possible implementations. It requires full schema scan and degrades query performance significantly. '.
|
||||
' Make sure your `resolveType` always returns valid implementation or throws.',
|
||||
Warning::WARNING_FULL_SCHEMA_SCAN
|
||||
);
|
||||
}
|
||||
|
||||
// Otherwise, test each possible type.
|
||||
$possibleTypes = $info->schema->getPossibleTypes($abstractType);
|
||||
$promisedIsTypeOfResults = [];
|
||||
|
||||
|
@ -240,15 +240,6 @@ class ObjectType extends Type implements OutputType, CompositeType
|
||||
"{$this->name} may declare it implements {$iface->name} only once."
|
||||
);
|
||||
$implemented[$iface->name] = true;
|
||||
if (!isset($iface->config['resolveType'])) {
|
||||
Utils::invariant(
|
||||
isset($this->config['isTypeOf']),
|
||||
"Interface Type {$iface->name} does not provide a \"resolveType\" " .
|
||||
"function and implementing Type {$this->name} does not provide a " .
|
||||
'"isTypeOf" function. There is no way to resolve this implementing ' .
|
||||
'type during execution.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,15 +158,6 @@ class UnionType extends Type implements AbstractType, OutputType, CompositeType
|
||||
"{$this->name} can include {$objType->name} type only once."
|
||||
);
|
||||
$includedTypeNames[$objType->name] = true;
|
||||
if (!isset($this->config['resolveType'])) {
|
||||
Utils::invariant(
|
||||
isset($objType->config['isTypeOf']) && is_callable($objType->config['isTypeOf']),
|
||||
"Union type \"{$this->name}\" does not provide a \"resolveType\" " .
|
||||
"function and possible type \"{$objType->name}\" does not provide an " .
|
||||
'"isTypeOf" function. There is no way to resolve this possible type ' .
|
||||
'during execution.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -504,10 +504,7 @@ class BuildSchema
|
||||
'fields' => function () use ($def) {
|
||||
return $this->makeFieldDefMap($def);
|
||||
},
|
||||
'astNode' => $def,
|
||||
'resolveType' => function() {
|
||||
$this->cannotExecuteSchema();
|
||||
}
|
||||
'astNode' => $def
|
||||
];
|
||||
}
|
||||
|
||||
@ -541,8 +538,7 @@ class BuildSchema
|
||||
'types' => Utils::map($def->types, function ($typeNode) {
|
||||
return $this->produceObjectType($typeNode);
|
||||
}),
|
||||
'astNode' => $def,
|
||||
'resolveType' => [$this, 'cannotExecuteSchema']
|
||||
'astNode' => $def
|
||||
];
|
||||
}
|
||||
|
||||
@ -573,7 +569,9 @@ class BuildSchema
|
||||
return [
|
||||
'name' => $def->name->value,
|
||||
'description' => $this->getDescription($def),
|
||||
'fields' => function() use ($def) { return $this->makeInputValues($def->fields); },
|
||||
'fields' => function () use ($def) {
|
||||
return $this->makeInputValues($def->fields);
|
||||
},
|
||||
'astNode' => $def,
|
||||
];
|
||||
}
|
||||
@ -644,12 +642,4 @@ class BuildSchema
|
||||
$doc = $source instanceof DocumentNode ? $source : Parser::parse($source);
|
||||
return self::buildAST($doc, $typeConfigDecorator);
|
||||
}
|
||||
|
||||
public function cannotExecuteSchema()
|
||||
{
|
||||
throw new Error(
|
||||
'Generated Schema cannot use Interface or Union types for execution.'
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -87,9 +87,7 @@ class AbstractPromiseTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
}';
|
||||
|
||||
Warning::suppress(Warning::WARNING_FULL_SCHEMA_SCAN);
|
||||
$result = GraphQL::execute($schema, $query);
|
||||
Warning::enable(Warning::WARNING_FULL_SCHEMA_SCAN);
|
||||
|
||||
$expected = [
|
||||
'data' => [
|
||||
@ -174,9 +172,7 @@ class AbstractPromiseTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
}';
|
||||
|
||||
Warning::suppress(Warning::WARNING_FULL_SCHEMA_SCAN);
|
||||
$result = GraphQL::execute($schema, $query);
|
||||
Warning::enable(Warning::WARNING_FULL_SCHEMA_SCAN);
|
||||
|
||||
$expected = [
|
||||
'data' => [
|
||||
|
@ -256,9 +256,7 @@ class UnionInterfaceTest extends \PHPUnit_Framework_TestCase
|
||||
]
|
||||
];
|
||||
|
||||
Warning::suppress(Warning::WARNING_FULL_SCHEMA_SCAN);
|
||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
||||
Warning::enable(Warning::WARNING_FULL_SCHEMA_SCAN);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -294,9 +292,7 @@ class UnionInterfaceTest extends \PHPUnit_Framework_TestCase
|
||||
]
|
||||
];
|
||||
|
||||
Warning::suppress(Warning::WARNING_FULL_SCHEMA_SCAN);
|
||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
||||
Warning::enable(Warning::WARNING_FULL_SCHEMA_SCAN);
|
||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray(true));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -351,9 +347,7 @@ class UnionInterfaceTest extends \PHPUnit_Framework_TestCase
|
||||
]
|
||||
];
|
||||
|
||||
Warning::suppress(Warning::WARNING_FULL_SCHEMA_SCAN);
|
||||
$this->assertEquals($expected, Executor::execute($this->schema, $ast, $this->john)->toArray());
|
||||
Warning::enable(Warning::WARNING_FULL_SCHEMA_SCAN);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,10 +74,7 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->objectType = new ObjectType([
|
||||
'name' => 'Object',
|
||||
'isTypeOf' => function() {return true;}
|
||||
]);
|
||||
$this->objectType = new ObjectType(['name' => 'Object']);
|
||||
$this->interfaceType = new InterfaceType(['name' => 'Interface']);
|
||||
$this->unionType = new UnionType(['name' => 'Union', 'types' => [$this->objectType]]);
|
||||
$this->enumType = new EnumType(['name' => 'Enum']);
|
||||
@ -363,7 +360,6 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
|
||||
'f' => ['type' => Type::int()]
|
||||
],
|
||||
'interfaces' => [$someInterface],
|
||||
'isTypeOf' => function() {return true;}
|
||||
]);
|
||||
|
||||
$schema = new Schema([
|
||||
@ -391,7 +387,6 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase
|
||||
'f' => ['type' => Type::int()]
|
||||
],
|
||||
'interfaces' => function() use (&$someInterface) { return [$someInterface]; },
|
||||
'isTypeOf' => function() {return true;}
|
||||
]);
|
||||
|
||||
$someInterface = new InterfaceType([
|
||||
|
@ -58,24 +58,15 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$this->ObjectWithIsTypeOf = new ObjectType([
|
||||
'name' => 'ObjectWithIsTypeOf',
|
||||
'isTypeOf' => function() {
|
||||
return true;
|
||||
},
|
||||
'fields' => [ 'f' => [ 'type' => Type::string() ]]
|
||||
]);
|
||||
$this->SomeUnionType = new UnionType([
|
||||
'name' => 'SomeUnion',
|
||||
'resolveType' => function() {
|
||||
return null;
|
||||
},
|
||||
'types' => [ $this->SomeObjectType ]
|
||||
]);
|
||||
|
||||
$this->SomeInterfaceType = new InterfaceType([
|
||||
'name' => 'SomeInterface',
|
||||
'resolveType' => function() {
|
||||
return null;
|
||||
},
|
||||
'fields' => [ 'f' => ['type' => Type::string() ]]
|
||||
]);
|
||||
|
||||
@ -404,7 +395,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function() {},
|
||||
'fields' => [ 'f' => [ 'type' => Type::string() ]],
|
||||
]);
|
||||
|
||||
@ -736,8 +726,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterfaceType = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => ['f' => ['type' => Type::string()]]
|
||||
]);
|
||||
|
||||
@ -756,8 +744,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterfaceType = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => ['f' => ['type' => Type::string()]]
|
||||
]);
|
||||
|
||||
@ -795,14 +781,11 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$NonUniqInterface = new InterfaceType([
|
||||
'name' => 'NonUniqInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => ['f' => ['type' => Type::string()]],
|
||||
]);
|
||||
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function(){},
|
||||
'fields' => ['f' => ['type' => Type::string()]],
|
||||
]);
|
||||
|
||||
@ -851,9 +834,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$schema = $this->schemaWithFieldType(new UnionType([
|
||||
'name' => 'SomeUnion',
|
||||
'resolveType' => function () {
|
||||
return null;
|
||||
},
|
||||
'types' => [$this->SomeObjectType],
|
||||
]));
|
||||
$schema->assertValid();
|
||||
@ -866,9 +846,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$schema = $this->schemaWithFieldType(new UnionType([
|
||||
'name' => 'SomeUnion',
|
||||
'resolveType' => function () {
|
||||
return null;
|
||||
},
|
||||
'types' => function () {
|
||||
return [$this->SomeObjectType];
|
||||
},
|
||||
@ -887,7 +864,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
);
|
||||
$this->schemaWithFieldType(new UnionType([
|
||||
'name' => 'SomeUnion',
|
||||
'resolveType' => function() {return null;}
|
||||
]));
|
||||
}
|
||||
|
||||
@ -898,8 +874,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$schema = $this->schemaWithFieldType(new UnionType([
|
||||
'name' => 'SomeUnion',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'types' => []
|
||||
]));
|
||||
|
||||
@ -921,8 +895,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
);
|
||||
$this->schemaWithFieldType(new UnionType([
|
||||
'name' => 'SomeUnion',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'types' => $this->SomeObjectType
|
||||
]));
|
||||
}
|
||||
@ -934,7 +906,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$schema = $this->schemaWithFieldType(new UnionType([
|
||||
'name' => 'SomeUnion',
|
||||
'resolveType' => function(){},
|
||||
'types' => [
|
||||
$this->SomeObjectType,
|
||||
$this->SomeObjectType,
|
||||
@ -1193,8 +1164,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterfaceType = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => ['f' => ['type' => Type::string()]]
|
||||
]);
|
||||
|
||||
@ -1234,8 +1203,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterfaceType = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => ['f' => ['type' => Type::string()]]
|
||||
]);
|
||||
|
||||
@ -1270,32 +1237,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
$type->assertValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* @it rejects an Interface type not defining resolveType with implementing type not defining isTypeOf
|
||||
*/
|
||||
public function testRejectsAnInterfaceTypeNotDefiningResolveTypeWithImplementingTypeNotDefiningIsTypeOf()
|
||||
{
|
||||
$InterfaceTypeWithoutResolveType = new InterfaceType([
|
||||
'name' => 'InterfaceTypeWithoutResolveType',
|
||||
'fields' => ['f' => ['type' => Type::string()]]
|
||||
]);
|
||||
|
||||
$schema = $this->schemaWithFieldType(new ObjectType([
|
||||
'name' => 'SomeObject',
|
||||
'interfaces' => [$InterfaceTypeWithoutResolveType],
|
||||
'fields' => ['f' => ['type' => Type::string()]]
|
||||
]));
|
||||
|
||||
$this->setExpectedException(
|
||||
InvariantViolation::class,
|
||||
'Interface Type InterfaceTypeWithoutResolveType does not provide a "resolveType" function and implementing '.
|
||||
'Type SomeObject does not provide a "isTypeOf" function. There is no way to resolve this implementing type '.
|
||||
'during execution.'
|
||||
);
|
||||
|
||||
$schema->assertValid();
|
||||
}
|
||||
|
||||
// DESCRIBE: Type System: Union types must be resolvable
|
||||
|
||||
/**
|
||||
@ -1305,8 +1246,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$schema = $this->schemaWithFieldType(new UnionType([
|
||||
'name' => 'SomeUnion',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'types' => [$this->SomeObjectType],
|
||||
]));
|
||||
$schema->assertValid();
|
||||
@ -1332,8 +1271,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$schema = $this->schemaWithFieldType(new UnionType([
|
||||
'name' => 'SomeUnion',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'types' => [$this->ObjectWithIsTypeOf],
|
||||
]));
|
||||
$schema->assertValid();
|
||||
@ -1358,25 +1295,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
$schema->assertValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* @it rejects a Union type not defining resolveType of Object types not defining isTypeOf
|
||||
*/
|
||||
public function testRejectsAUnionTypeNotDefiningResolveTypeOfObjectTypesNotDefiningIsTypeOf()
|
||||
{
|
||||
$schema = $this->schemaWithFieldType(new UnionType([
|
||||
'name' => 'SomeUnion',
|
||||
'types' => [$this->SomeObjectType],
|
||||
]));
|
||||
|
||||
$this->setExpectedException(
|
||||
InvariantViolation::class,
|
||||
'Union type "SomeUnion" does not provide a "resolveType" function and possible type "SomeObject" '.
|
||||
'does not provide an "isTypeOf" function. There is no way to resolve this possible type during execution.'
|
||||
);
|
||||
|
||||
$schema->assertValid();
|
||||
}
|
||||
|
||||
// DESCRIBE: Type System: Scalar types must be serializable
|
||||
|
||||
/**
|
||||
@ -1747,8 +1665,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterfaceType = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => ['f' => ['type' => Type::string()]]
|
||||
]);
|
||||
|
||||
@ -2085,8 +2001,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => [
|
||||
'type' => Type::string(),
|
||||
@ -2121,8 +2035,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => [
|
||||
'type' => Type::string(),
|
||||
@ -2158,8 +2070,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => [
|
||||
'type' => Type::string(),
|
||||
@ -2195,8 +2105,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => [
|
||||
'type' => Type::string(),
|
||||
@ -2238,8 +2146,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => [
|
||||
'type' => Type::string(),
|
||||
@ -2274,8 +2180,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => ['type' => Type::string()]
|
||||
]
|
||||
@ -2318,8 +2222,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => ['type' => $TypeA]
|
||||
]
|
||||
@ -2350,8 +2252,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => function () use (&$AnotherInterface) {
|
||||
return [
|
||||
'field' => ['type' => $AnotherInterface]
|
||||
@ -2380,8 +2280,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => ['type' => $this->SomeUnionType]
|
||||
]
|
||||
@ -2406,8 +2304,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => [
|
||||
'type' => Type::string(),
|
||||
@ -2445,8 +2341,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => [
|
||||
'type' => Type::string(),
|
||||
@ -2487,8 +2381,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => ['type' => Type::nonNull(Type::listOf(Type::string()))]
|
||||
]
|
||||
@ -2513,8 +2405,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => ['type' => Type::listOf(Type::string())]
|
||||
]
|
||||
@ -2545,8 +2435,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => ['type' => Type::string()]
|
||||
]
|
||||
@ -2575,8 +2463,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => ['type' => Type::string()]
|
||||
]
|
||||
@ -2601,8 +2487,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$AnotherInterface = new InterfaceType([
|
||||
'name' => 'AnotherInterface',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'fields' => [
|
||||
'field' => ['type' => Type::nonNull(Type::string())]
|
||||
]
|
||||
@ -2820,8 +2704,6 @@ class ValidationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$BadUnionType = new UnionType([
|
||||
'name' => 'BadUnion',
|
||||
'resolveType' => function () {
|
||||
},
|
||||
'types' => [$type],
|
||||
]);
|
||||
return new Schema([
|
||||
|
@ -36,8 +36,8 @@ class BuildSchemaTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
'));
|
||||
|
||||
$result = GraphQL::execute($schema, '{ str }', ['str' => 123]);
|
||||
$this->assertEquals($result['data'], ['str' => 123]);
|
||||
$result = GraphQL::executeQuery($schema, '{ str }', ['str' => 123]);
|
||||
$this->assertEquals(['str' => 123], $result->toArray(true)['data']);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,7 +52,7 @@ class BuildSchemaTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
");
|
||||
|
||||
$result = GraphQL::execute(
|
||||
$result = GraphQL::executeQuery(
|
||||
$schema,
|
||||
'{ add(x: 34, y: 55) }',
|
||||
[
|
||||
@ -61,7 +61,7 @@ class BuildSchemaTest extends \PHPUnit_Framework_TestCase
|
||||
}
|
||||
]
|
||||
);
|
||||
$this->assertEquals($result, ['data' => ['add' => 89]]);
|
||||
$this->assertEquals(['data' => ['add' => 89]], $result->toArray(true));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -447,6 +447,135 @@ type WorldTwo {
|
||||
$this->assertEquals($output, $body);
|
||||
}
|
||||
|
||||
/**
|
||||
* @it Specifying Union type using __typename
|
||||
*/
|
||||
public function testSpecifyingUnionTypeUsingTypename()
|
||||
{
|
||||
$schema = BuildSchema::buildAST(Parser::parse('
|
||||
schema {
|
||||
query: Root
|
||||
}
|
||||
|
||||
type Root {
|
||||
fruits: [Fruit]
|
||||
}
|
||||
|
||||
union Fruit = Apple | Banana
|
||||
|
||||
type Apple {
|
||||
color: String
|
||||
}
|
||||
|
||||
type Banana {
|
||||
length: Int
|
||||
}
|
||||
'));
|
||||
$query = '
|
||||
{
|
||||
fruits {
|
||||
... on Apple {
|
||||
color
|
||||
}
|
||||
... on Banana {
|
||||
length
|
||||
}
|
||||
}
|
||||
}
|
||||
';
|
||||
$root = [
|
||||
'fruits' => [
|
||||
[
|
||||
'color' => 'green',
|
||||
'__typename' => 'Apple',
|
||||
],
|
||||
[
|
||||
'length' => 5,
|
||||
'__typename' => 'Banana',
|
||||
]
|
||||
]
|
||||
];
|
||||
$expected = [
|
||||
'data' => [
|
||||
'fruits' => [
|
||||
['color' => 'green'],
|
||||
['length' => 5],
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$result = GraphQL::executeQuery($schema, $query, $root);
|
||||
$this->assertEquals($expected, $result->toArray(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @it Specifying Interface type using __typename
|
||||
*/
|
||||
public function testSpecifyingInterfaceUsingTypename()
|
||||
{
|
||||
$schema = BuildSchema::buildAST(Parser::parse('
|
||||
schema {
|
||||
query: Root
|
||||
}
|
||||
|
||||
type Root {
|
||||
characters: [Character]
|
||||
}
|
||||
|
||||
interface Character {
|
||||
name: String!
|
||||
}
|
||||
|
||||
type Human implements Character {
|
||||
name: String!
|
||||
totalCredits: Int
|
||||
}
|
||||
|
||||
type Droid implements Character {
|
||||
name: String!
|
||||
primaryFunction: String
|
||||
}
|
||||
'));
|
||||
$query = '
|
||||
{
|
||||
characters {
|
||||
name
|
||||
... on Human {
|
||||
totalCredits
|
||||
}
|
||||
... on Droid {
|
||||
primaryFunction
|
||||
}
|
||||
}
|
||||
}
|
||||
';
|
||||
$root = [
|
||||
'characters' => [
|
||||
[
|
||||
'name' => 'Han Solo',
|
||||
'totalCredits' => 10,
|
||||
'__typename' => 'Human',
|
||||
],
|
||||
[
|
||||
'name' => 'R2-D2',
|
||||
'primaryFunction' => 'Astromech',
|
||||
'__typename' => 'Droid',
|
||||
]
|
||||
]
|
||||
];
|
||||
$expected = [
|
||||
'data' => [
|
||||
'characters' => [
|
||||
['name' => 'Han Solo', 'totalCredits' => 10],
|
||||
['name' => 'R2-D2', 'primaryFunction' => 'Astromech'],
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
$result = GraphQL::executeQuery($schema, $query, $root);
|
||||
$this->assertEquals($expected, $result->toArray(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @it CustomScalar
|
||||
*/
|
||||
@ -1093,9 +1222,8 @@ interface Hello {
|
||||
$this->assertInstanceOf(InterfaceTypeDefinitionNode::class, $node);
|
||||
$this->assertEquals('Hello', $defaultConfig['name']);
|
||||
$this->assertInstanceOf(\Closure::class, $defaultConfig['fields']);
|
||||
$this->assertInstanceOf(\Closure::class, $defaultConfig['resolveType']);
|
||||
$this->assertArrayHasKey('description', $defaultConfig);
|
||||
$this->assertCount(5, $defaultConfig);
|
||||
$this->assertCount(4, $defaultConfig);
|
||||
$this->assertEquals(array_keys($allNodesMap), ['Query', 'Color', 'Hello']);
|
||||
$this->assertEquals('My description of Hello', $schema->getType('Hello')->description);
|
||||
}
|
||||
|
@ -1,8 +1,4 @@
|
||||
<?php
|
||||
/**
|
||||
* FindBreakingChanges tests
|
||||
*/
|
||||
|
||||
namespace GraphQL\Tests\Utils;
|
||||
|
||||
use GraphQL\Type\Definition\EnumType;
|
||||
@ -16,7 +12,6 @@ use GraphQL\Utils\FindBreakingChanges;
|
||||
|
||||
class FindBreakingChangesTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
private $queryType;
|
||||
|
||||
public function setUp()
|
||||
@ -88,7 +83,7 @@ class FindBreakingChangesTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$unionType = new UnionType([
|
||||
'name' => 'Type1',
|
||||
'types' => [new ObjectType(['name' => 'blah'])],
|
||||
'types' => [$objectType],
|
||||
]);
|
||||
|
||||
$oldSchema = new Schema([
|
||||
@ -510,16 +505,12 @@ class FindBreakingChangesTest extends \PHPUnit_Framework_TestCase
|
||||
$oldUnionType = new UnionType([
|
||||
'name' => 'UnionType1',
|
||||
'types' => [$type1, $type2],
|
||||
'resolveType' => function () {
|
||||
}
|
||||
]);
|
||||
|
||||
|
||||
$newUnionType = new UnionType([
|
||||
'name' => 'UnionType1',
|
||||
'types' => [$type1a, $type3],
|
||||
'resolveType' => function () {
|
||||
}
|
||||
]);
|
||||
|
||||
$oldSchema = new Schema([
|
||||
@ -978,8 +969,6 @@ class FindBreakingChangesTest extends \PHPUnit_Framework_TestCase
|
||||
'fields' => [
|
||||
'field1' => Type::string()
|
||||
],
|
||||
'resolveType' => function () {
|
||||
}
|
||||
]);
|
||||
$oldType = new ObjectType([
|
||||
'name' => 'Type1',
|
||||
@ -1099,15 +1088,11 @@ class FindBreakingChangesTest extends \PHPUnit_Framework_TestCase
|
||||
$unionTypeThatLosesATypeOld = new UnionType([
|
||||
'name' => 'UnionTypeThatLosesAType',
|
||||
'types' => [$typeInUnion1, $typeInUnion2],
|
||||
'resolveType' => function () {
|
||||
}
|
||||
]);
|
||||
|
||||
$unionTypeThatLosesATypeNew = new UnionType([
|
||||
'name' => 'UnionTypeThatLosesAType',
|
||||
'types' => [$typeInUnion1],
|
||||
'resolveType' => function () {
|
||||
}
|
||||
]);
|
||||
|
||||
$enumTypeThatLosesAValueOld = new EnumType([
|
||||
@ -1132,8 +1117,6 @@ class FindBreakingChangesTest extends \PHPUnit_Framework_TestCase
|
||||
'fields' => [
|
||||
'field1' => Type::string()
|
||||
],
|
||||
'resolveType' => function () {
|
||||
}
|
||||
]);
|
||||
|
||||
$typeThatLosesInterfaceOld = new ObjectType([
|
||||
@ -1353,15 +1336,11 @@ class FindBreakingChangesTest extends \PHPUnit_Framework_TestCase
|
||||
$oldUnionType = new UnionType([
|
||||
'name' => 'UnionType1',
|
||||
'types' => [$type1],
|
||||
'resolveType' => function () {
|
||||
}
|
||||
]);
|
||||
|
||||
$newUnionType = new UnionType([
|
||||
'name' => 'UnionType1',
|
||||
'types' => [$type1a, $type2],
|
||||
'resolveType' => function () {
|
||||
}
|
||||
]);
|
||||
|
||||
$oldSchema = new Schema([
|
||||
@ -1452,15 +1431,11 @@ class FindBreakingChangesTest extends \PHPUnit_Framework_TestCase
|
||||
$unionTypeThatGainsATypeOld = new UnionType([
|
||||
'name' => 'UnionType1',
|
||||
'types' => [$typeInUnion1],
|
||||
'resolveType' => function () {
|
||||
}
|
||||
]);
|
||||
|
||||
$unionTypeThatGainsATypeNew = new UnionType([
|
||||
'name' => 'UnionType1',
|
||||
'types' => [$typeInUnion1, $typeInUnion2],
|
||||
'resolveType' => function () {
|
||||
}
|
||||
]);
|
||||
|
||||
$oldSchema = new Schema([
|
||||
|
@ -360,7 +360,6 @@ type Root {
|
||||
{
|
||||
$fooType = new InterfaceType([
|
||||
'name' => 'Foo',
|
||||
'resolveType' => function() { return null; },
|
||||
'fields' => ['str' => ['type' => Type::string()]]
|
||||
]);
|
||||
|
||||
@ -406,13 +405,11 @@ type Root {
|
||||
{
|
||||
$fooType = new InterfaceType([
|
||||
'name' => 'Foo',
|
||||
'resolveType' => function() { return null; },
|
||||
'fields' => ['str' => ['type' => Type::string()]]
|
||||
]);
|
||||
|
||||
$baazType = new InterfaceType([
|
||||
'name' => 'Baaz',
|
||||
'resolveType' => function() { return null; },
|
||||
'fields' => ['int' => ['type' => Type::int()]]
|
||||
]);
|
||||
|
||||
@ -476,13 +473,11 @@ type Root {
|
||||
|
||||
$singleUnion = new UnionType([
|
||||
'name' => 'SingleUnion',
|
||||
'resolveType' => function() { return null; },
|
||||
'types' => [$fooType]
|
||||
]);
|
||||
|
||||
$multipleUnion = new UnionType([
|
||||
'name' => 'MultipleUnion',
|
||||
'resolveType' => function() { return null; },
|
||||
'types' => [$fooType, $barType]
|
||||
]);
|
||||
|
||||
|
@ -795,7 +795,6 @@ class OverlappingFieldsCanBeMergedTest extends TestCase
|
||||
|
||||
$SomeBox = new InterfaceType([
|
||||
'name' => 'SomeBox',
|
||||
'resolveType' => function() use (&$StringBox) {return $StringBox;},
|
||||
'fields' => function() use (&$SomeBox) {
|
||||
return [
|
||||
'deepBox' => ['type' => $SomeBox],
|
||||
@ -837,7 +836,6 @@ class OverlappingFieldsCanBeMergedTest extends TestCase
|
||||
|
||||
$NonNullStringBox1 = new InterfaceType([
|
||||
'name' => 'NonNullStringBox1',
|
||||
'resolveType' => function() use (&$StringBox) {return $StringBox;},
|
||||
'fields' => [
|
||||
'scalar' => [ 'type' => Type::nonNull(Type::string()) ]
|
||||
]
|
||||
@ -855,7 +853,6 @@ class OverlappingFieldsCanBeMergedTest extends TestCase
|
||||
|
||||
$NonNullStringBox2 = new InterfaceType([
|
||||
'name' => 'NonNullStringBox2',
|
||||
'resolveType' => function() use (&$StringBox) {return $StringBox;},
|
||||
'fields' => [
|
||||
'scalar' => ['type' => Type::nonNull(Type::string())]
|
||||
]
|
||||
|
@ -67,7 +67,6 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$Dog = new ObjectType([
|
||||
'name' => 'Dog',
|
||||
'isTypeOf' => function() {return true;},
|
||||
'fields' => [
|
||||
'name' => [
|
||||
'type' => Type::string(),
|
||||
@ -94,7 +93,6 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$Cat = new ObjectType([
|
||||
'name' => 'Cat',
|
||||
'isTypeOf' => function() {return true;},
|
||||
'fields' => function() use (&$FurColor) {
|
||||
return [
|
||||
'name' => [
|
||||
@ -113,10 +111,6 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||
$CatOrDog = new UnionType([
|
||||
'name' => 'CatOrDog',
|
||||
'types' => [$Dog, $Cat],
|
||||
'resolveType' => function($value) {
|
||||
// not used for validation
|
||||
return null;
|
||||
}
|
||||
]);
|
||||
|
||||
$Intelligent = new InterfaceType([
|
||||
@ -129,7 +123,6 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||
$Human = null;
|
||||
$Human = new ObjectType([
|
||||
'name' => 'Human',
|
||||
'isTypeOf' => function() {return true;},
|
||||
'interfaces' => [$Being, $Intelligent],
|
||||
'fields' => function() use (&$Human, $Pet) {
|
||||
return [
|
||||
@ -146,7 +139,6 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$Alien = new ObjectType([
|
||||
'name' => 'Alien',
|
||||
'isTypeOf' => function() {return true;},
|
||||
'interfaces' => [$Being, $Intelligent],
|
||||
'fields' => [
|
||||
'iq' => ['type' => Type::int()],
|
||||
@ -161,19 +153,11 @@ abstract class TestCase extends \PHPUnit_Framework_TestCase
|
||||
$DogOrHuman = new UnionType([
|
||||
'name' => 'DogOrHuman',
|
||||
'types' => [$Dog, $Human],
|
||||
'resolveType' => function() {
|
||||
// not used for validation
|
||||
return null;
|
||||
}
|
||||
]);
|
||||
|
||||
$HumanOrAlien = new UnionType([
|
||||
'name' => 'HumanOrAlien',
|
||||
'types' => [$Human, $Alien],
|
||||
'resolveType' => function() {
|
||||
// not used for validation
|
||||
return null;
|
||||
}
|
||||
]);
|
||||
|
||||
$FurColor = new EnumType([
|
||||
|
Loading…
Reference in New Issue
Block a user