Merge pull request #503 from simPod/fix-reference-executor

Fix ReferenceExecutor
This commit is contained in:
Vladimir Razuvaev 2019-07-12 16:31:29 +07:00 committed by GitHub
commit 974258b352
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 38 deletions

View File

@ -134,16 +134,16 @@ class ReferenceExecutor implements ExecutorImplementation
) { ) {
$errors = []; $errors = [];
$fragments = []; $fragments = [];
/** @var OperationDefinitionNode $operation */ /** @var OperationDefinitionNode|null $operation */
$operation = null; $operation = null;
$hasMultipleAssumedOperations = false; $hasMultipleAssumedOperations = false;
foreach ($documentNode->definitions as $definition) { foreach ($documentNode->definitions as $definition) {
switch (true) { switch (true) {
case $definition instanceof OperationDefinitionNode: case $definition instanceof OperationDefinitionNode:
if (! $operationName && $operation) { if ($operationName === null && $operation !== null) {
$hasMultipleAssumedOperations = true; $hasMultipleAssumedOperations = true;
} }
if (! $operationName || if ($operationName === null ||
(isset($definition->name) && $definition->name->value === $operationName)) { (isset($definition->name) && $definition->name->value === $operationName)) {
$operation = $definition; $operation = $definition;
} }
@ -154,10 +154,10 @@ class ReferenceExecutor implements ExecutorImplementation
} }
} }
if ($operation === null) { if ($operation === null) {
if ($operationName) { if ($operationName === null) {
$errors[] = new Error(sprintf('Unknown operation named "%s".', $operationName));
} else {
$errors[] = new Error('Must provide an operation.'); $errors[] = new Error('Must provide an operation.');
} else {
$errors[] = new Error(sprintf('Unknown operation named "%s".', $operationName));
} }
} elseif ($hasMultipleAssumedOperations) { } elseif ($hasMultipleAssumedOperations) {
$errors[] = new Error( $errors[] = new Error(
@ -288,7 +288,7 @@ class ReferenceExecutor implements ExecutorImplementation
switch ($operation->operation) { switch ($operation->operation) {
case 'query': case 'query':
$queryType = $schema->getQueryType(); $queryType = $schema->getQueryType();
if (! $queryType) { if ($queryType === null) {
throw new Error( throw new Error(
'Schema does not define the required query root type.', 'Schema does not define the required query root type.',
[$operation] [$operation]
@ -298,7 +298,7 @@ class ReferenceExecutor implements ExecutorImplementation
return $queryType; return $queryType;
case 'mutation': case 'mutation':
$mutationType = $schema->getMutationType(); $mutationType = $schema->getMutationType();
if (! $mutationType) { if ($mutationType === null) {
throw new Error( throw new Error(
'Schema is not configured for mutations.', 'Schema is not configured for mutations.',
[$operation] [$operation]
@ -308,7 +308,7 @@ class ReferenceExecutor implements ExecutorImplementation
return $mutationType; return $mutationType;
case 'subscription': case 'subscription':
$subscriptionType = $schema->getSubscriptionType(); $subscriptionType = $schema->getSubscriptionType();
if (! $subscriptionType) { if ($subscriptionType === null) {
throw new Error( throw new Error(
'Schema is not configured for subscriptions.', 'Schema is not configured for subscriptions.',
[$operation] [$operation]
@ -377,7 +377,7 @@ class ReferenceExecutor implements ExecutorImplementation
$visitedFragmentNames[$fragName] = true; $visitedFragmentNames[$fragName] = true;
/** @var FragmentDefinitionNode|null $fragment */ /** @var FragmentDefinitionNode|null $fragment */
$fragment = $exeContext->fragments[$fragName] ?? null; $fragment = $exeContext->fragments[$fragName] ?? null;
if (! $fragment || ! $this->doesFragmentConditionMatch($fragment, $runtimeType)) { if ($fragment === null || ! $this->doesFragmentConditionMatch($fragment, $runtimeType)) {
break; break;
} }
$this->collectFields( $this->collectFields(
@ -398,10 +398,8 @@ class ReferenceExecutor implements ExecutorImplementation
* directives, where @skip has higher precedence than @include. * directives, where @skip has higher precedence than @include.
* *
* @param FragmentSpreadNode|FieldNode|InlineFragmentNode $node * @param FragmentSpreadNode|FieldNode|InlineFragmentNode $node
*
* @return bool
*/ */
private function shouldIncludeNode($node) private function shouldIncludeNode($node) : bool
{ {
$variableValues = $this->exeContext->variableValues; $variableValues = $this->exeContext->variableValues;
$skipDirective = Directive::skipDirective(); $skipDirective = Directive::skipDirective();
@ -425,12 +423,10 @@ class ReferenceExecutor implements ExecutorImplementation
/** /**
* Implements the logic to compute the key of a given fields entry * Implements the logic to compute the key of a given fields entry
*
* @return string
*/ */
private static function getFieldEntryKey(FieldNode $node) private static function getFieldEntryKey(FieldNode $node) : string
{ {
return $node->alias ? $node->alias->value : $node->name->value; return $node->alias === null ? $node->name->value : $node->alias->value;
} }
/** /**
@ -482,7 +478,7 @@ class ReferenceExecutor implements ExecutorImplementation
return $results; return $results;
} }
$promise = $this->getPromise($result); $promise = $this->getPromise($result);
if ($promise) { if ($promise !== null) {
return $promise->then(static function ($resolvedResult) use ($responseName, $results) { return $promise->then(static function ($resolvedResult) use ($responseName, $results) {
$results[$responseName] = $resolvedResult; $results[$responseName] = $resolvedResult;
@ -523,7 +519,7 @@ class ReferenceExecutor implements ExecutorImplementation
$fieldNode = $fieldNodes[0]; $fieldNode = $fieldNodes[0];
$fieldName = $fieldNode->name->value; $fieldName = $fieldNode->name->value;
$fieldDef = $this->getFieldDef($exeContext->schema, $parentType, $fieldName); $fieldDef = $this->getFieldDef($exeContext->schema, $parentType, $fieldName);
if (! $fieldDef) { if ($fieldDef === null) {
return self::$UNDEFINED; return self::$UNDEFINED;
} }
$returnType = $fieldDef->getType(); $returnType = $fieldDef->getType();
@ -582,12 +578,8 @@ class ReferenceExecutor implements ExecutorImplementation
* are allowed, like on a Union. __schema could get automatically * are allowed, like on a Union. __schema could get automatically
* added to the query type, but that would require mutating type * added to the query type, but that would require mutating type
* definitions, which would cause issues. * definitions, which would cause issues.
*
* @param string $fieldName
*
* @return FieldDefinition
*/ */
private function getFieldDef(Schema $schema, ObjectType $parentType, $fieldName) private function getFieldDef(Schema $schema, ObjectType $parentType, string $fieldName) : ?FieldDefinition
{ {
static $schemaMetaFieldDef, $typeMetaFieldDef, $typeNameMetaFieldDef; static $schemaMetaFieldDef, $typeMetaFieldDef, $typeNameMetaFieldDef;
$schemaMetaFieldDef = $schemaMetaFieldDef ?: Introspection::schemaMetaFieldDef(); $schemaMetaFieldDef = $schemaMetaFieldDef ?: Introspection::schemaMetaFieldDef();
@ -681,7 +673,7 @@ class ReferenceExecutor implements ExecutorImplementation
$result $result
); );
$promise = $this->getPromise($completed); $promise = $this->getPromise($completed);
if ($promise) { if ($promise !== null) {
return $promise->then( return $promise->then(
null, null,
function ($error) use ($exeContext) { function ($error) use ($exeContext) {
@ -730,7 +722,7 @@ class ReferenceExecutor implements ExecutorImplementation
$result $result
); );
$promise = $this->getPromise($completed); $promise = $this->getPromise($completed);
if ($promise) { if ($promise !== null) {
return $promise->then( return $promise->then(
null, null,
function ($error) use ($fieldNodes, $path) { function ($error) use ($fieldNodes, $path) {
@ -790,7 +782,7 @@ class ReferenceExecutor implements ExecutorImplementation
) { ) {
$promise = $this->getPromise($result); $promise = $this->getPromise($result);
// If result is a Promise, apply-lift over completeValue. // If result is a Promise, apply-lift over completeValue.
if ($promise) { if ($promise !== null) {
return $promise->then(function (&$resolved) use ($returnType, $fieldNodes, $info, $path) { return $promise->then(function (&$resolved) use ($returnType, $fieldNodes, $info, $path) {
return $this->completeValue($returnType, $fieldNodes, $info, $path, $resolved); return $this->completeValue($returnType, $fieldNodes, $info, $path, $resolved);
}); });
@ -828,7 +820,7 @@ class ReferenceExecutor implements ExecutorImplementation
// instance than `resolveType` or $field->getType() or $arg->getType() // instance than `resolveType` or $field->getType() or $arg->getType()
if ($returnType !== $this->exeContext->schema->getType($returnType->name)) { if ($returnType !== $this->exeContext->schema->getType($returnType->name)) {
$hint = ''; $hint = '';
if ($this->exeContext->schema->getConfig()->typeLoader) { if ($this->exeContext->schema->getConfig()->typeLoader !== null) {
$hint = sprintf( $hint = sprintf(
'Make sure that type loader returns the same instance as defined in %s.%s', 'Make sure that type loader returns the same instance as defined in %s.%s',
$info->parentType, $info->parentType,
@ -908,7 +900,7 @@ class ReferenceExecutor implements ExecutorImplementation
* @param mixed[] $values * @param mixed[] $values
* @param Promise|mixed|null $initialValue * @param Promise|mixed|null $initialValue
* *
* @return mixed[] * @return mixed
*/ */
private function promiseReduce(array $values, callable $callback, $initialValue) private function promiseReduce(array $values, callable $callback, $initialValue)
{ {
@ -916,7 +908,7 @@ class ReferenceExecutor implements ExecutorImplementation
$values, $values,
function ($previous, $value) use ($callback) { function ($previous, $value) use ($callback) {
$promise = $this->getPromise($previous); $promise = $this->getPromise($previous);
if ($promise) { if ($promise !== null) {
return $promise->then(static function ($resolved) use ($callback, $value) { return $promise->then(static function ($resolved) use ($callback, $value) {
return $callback($resolved, $value); return $callback($resolved, $value);
}); });
@ -954,7 +946,7 @@ class ReferenceExecutor implements ExecutorImplementation
$fieldPath[] = $i++; $fieldPath[] = $i++;
$info->path = $fieldPath; $info->path = $fieldPath;
$completedItem = $this->completeValueCatchingError($itemType, $fieldNodes, $info, $fieldPath, $item); $completedItem = $this->completeValueCatchingError($itemType, $fieldNodes, $info, $fieldPath, $item);
if (! $containsPromise && $this->getPromise($completedItem)) { if (! $containsPromise && $this->getPromise($completedItem) !== null) {
$containsPromise = true; $containsPromise = true;
} }
$completedItems[] = $completedItem; $completedItems[] = $completedItem;
@ -1013,7 +1005,7 @@ class ReferenceExecutor implements ExecutorImplementation
$runtimeType = self::defaultTypeResolver($result, $exeContext->contextValue, $info, $returnType); $runtimeType = self::defaultTypeResolver($result, $exeContext->contextValue, $info, $returnType);
} }
$promise = $this->getPromise($runtimeType); $promise = $this->getPromise($runtimeType);
if ($promise) { if ($promise !== null) {
return $promise->then(function ($resolvedRuntimeType) use ( return $promise->then(function ($resolvedRuntimeType) use (
$returnType, $returnType,
$fieldNodes, $fieldNodes,
@ -1075,7 +1067,8 @@ class ReferenceExecutor implements ExecutorImplementation
) { ) {
return $value['__typename']; return $value['__typename'];
} }
if ($abstractType instanceof InterfaceType && $info->schema->getConfig()->typeLoader) {
if ($abstractType instanceof InterfaceType && $info->schema->getConfig()->typeLoader !== null) {
Warning::warnOnce( Warning::warnOnce(
sprintf( sprintf(
'GraphQL Interface Type `%s` returned `null` from its `resolveType` function ' . 'GraphQL Interface Type `%s` returned `null` from its `resolveType` function ' .
@ -1097,7 +1090,7 @@ class ReferenceExecutor implements ExecutorImplementation
continue; continue;
} }
$promise = $this->getPromise($isTypeOfResult); $promise = $this->getPromise($isTypeOfResult);
if ($promise) { if ($promise !== null) {
$promisedIsTypeOfResults[$index] = $promise; $promisedIsTypeOfResults[$index] = $promise;
} elseif ($isTypeOfResult) { } elseif ($isTypeOfResult) {
return $type; return $type;
@ -1138,7 +1131,7 @@ class ReferenceExecutor implements ExecutorImplementation
$isTypeOf = $returnType->isTypeOf($result, $this->exeContext->contextValue, $info); $isTypeOf = $returnType->isTypeOf($result, $this->exeContext->contextValue, $info);
if ($isTypeOf !== null) { if ($isTypeOf !== null) {
$promise = $this->getPromise($isTypeOf); $promise = $this->getPromise($isTypeOf);
if ($promise) { if ($promise !== null) {
return $promise->then(function ($isTypeOfResult) use ( return $promise->then(function ($isTypeOfResult) use (
$returnType, $returnType,
$fieldNodes, $fieldNodes,
@ -1254,7 +1247,7 @@ class ReferenceExecutor implements ExecutorImplementation
if ($result === self::$UNDEFINED) { if ($result === self::$UNDEFINED) {
continue; continue;
} }
if (! $containsPromise && $this->getPromise($result)) { if (! $containsPromise && $this->getPromise($result) !== null) {
$containsPromise = true; $containsPromise = true;
} }
$finalResults[$responseName] = $result; $finalResults[$responseName] = $result;
@ -1316,7 +1309,6 @@ class ReferenceExecutor implements ExecutorImplementation
/** /**
* @param string|ObjectType|null $runtimeTypeOrName * @param string|ObjectType|null $runtimeTypeOrName
* @param FieldNode[] $fieldNodes
* @param mixed $result * @param mixed $result
* *
* @return ObjectType * @return ObjectType

View File

@ -21,7 +21,7 @@ class Directive
public const REASON_ARGUMENT_NAME = 'reason'; public const REASON_ARGUMENT_NAME = 'reason';
/** @var Directive[] */ /** @var Directive[] */
public static $internalDirectives; public static $internalDirectives = [];
// Schema Definitions // Schema Definitions