Merge pull request #277 from danez/throwitall

Make Types throw instead of returning Utils::undefined()
This commit is contained in:
Vladimir Razuvaev 2018-05-27 18:08:39 +07:00 committed by GitHub
commit 2580750d4c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 118 additions and 106 deletions

View File

@ -30,11 +30,12 @@ class UrlType extends ScalarType
*
* @param mixed $value
* @return mixed
* @throws Error
*/
public function parseValue($value)
{
if (!is_string($value) || !filter_var($value, FILTER_VALIDATE_URL)) { // quite naive, but after all this is example
throw new \UnexpectedValueException("Cannot represent value as URL: " . Utils::printSafe($value));
throw new Error("Cannot represent value as URL: " . Utils::printSafe($value));
}
return $value;
}

View File

@ -1,7 +1,6 @@
<?php
namespace GraphQL\Executor;
use GraphQL\Error\Error;
use GraphQL\Error\FormattedError;
/**
@ -32,7 +31,7 @@ class ExecutionResult implements \JsonSerializable
* @var \GraphQL\Error\Error[]
*/
public $errors;
/**
* User-defined serializable array of extensions included in serialized result.
* Conforms to
@ -138,7 +137,7 @@ class ExecutionResult implements \JsonSerializable
if (null !== $this->data) {
$result['data'] = $this->data;
}
if (!empty($this->extensions)) {
$result['extensions'] = (array) $this->extensions;
}

View File

@ -1197,8 +1197,7 @@ class Executor
}
/**
* Complete a Scalar or Enum by serializing to a valid value, returning
* null if serialization is not possible.
* Complete a Scalar or Enum by serializing to a valid value, throwing if serialization is not possible.
*
* @param LeafType $returnType
* @param $result
@ -1207,14 +1206,21 @@ class Executor
*/
private function completeLeafValue(LeafType $returnType, &$result)
{
$serializedResult = $returnType->serialize($result);
if (Utils::isInvalid($serializedResult)) {
try {
return $returnType->serialize($result);
} catch (\Exception $error) {
throw new InvariantViolation(
'Expected a value of type "'. Utils::printSafe($returnType) . '" but received: ' . Utils::printSafe($result)
'Expected a value of type "'. Utils::printSafe($returnType) . '" but received: ' . Utils::printSafe($result),
0,
$error
);
} catch (\Throwable $error) {
throw new InvariantViolation(
'Expected a value of type "'. Utils::printSafe($returnType) . '" but received: ' . Utils::printSafe($result),
0,
$error
);
}
return $serializedResult;
}
/**

View File

@ -13,21 +13,16 @@ use GraphQL\Language\AST\NodeList;
use GraphQL\Language\AST\VariableNode;
use GraphQL\Language\AST\VariableDefinitionNode;
use GraphQL\Language\Printer;
use GraphQL\Type\Definition\EnumType;
use GraphQL\Type\Definition\ScalarType;
use GraphQL\Type\Schema;
use GraphQL\Type\Definition\Directive;
use GraphQL\Type\Definition\FieldDefinition;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\InputType;
use GraphQL\Type\Definition\ListOfType;
use GraphQL\Type\Definition\NonNull;
use GraphQL\Type\Definition\Type;
use GraphQL\Utils\AST;
use GraphQL\Utils\TypeInfo;
use GraphQL\Utils\Utils;
use GraphQL\Utils\Value;
use GraphQL\Validator\DocumentValidator;
class Values
{

View File

@ -1,7 +1,6 @@
<?php
namespace GraphQL\Language\AST;
use GraphQL\Error\InvariantViolation;
use GraphQL\Utils\Utils;
abstract class Node

View File

@ -1,7 +1,9 @@
<?php
namespace GraphQL\Type\Definition;
use GraphQL\Error\Error;
use GraphQL\Language\AST\BooleanValueNode;
use GraphQL\Language\AST\Node;
use GraphQL\Utils\Utils;
/**
@ -32,22 +34,30 @@ class BooleanType extends ScalarType
/**
* @param mixed $value
* @return bool
* @throws Error
*/
public function parseValue($value)
{
return is_bool($value) ? $value : Utils::undefined();
if (is_bool($value)) {
return $value;
}
throw new Error("Cannot represent value as boolean: " . Utils::printSafe($value));
}
/**
* @param $valueNode
* @param Node $valueNode
* @param array|null $variables
* @return bool|null
* @throws \Exception
*/
public function parseLiteral($valueNode, array $variables = null)
{
if ($valueNode instanceof BooleanValueNode) {
return (bool) $valueNode->value;
}
return Utils::undefined();
// Intentionally without message, as all information already in wrapped Exception
throw new \Exception();
}
}

View File

@ -1,6 +1,7 @@
<?php
namespace GraphQL\Type\Definition;
use GraphQL\Language\AST\Node;
use GraphQL\Utils\AST;
use GraphQL\Utils\Utils;
@ -25,10 +26,6 @@ class CustomScalarType extends ScalarType
*/
public function parseValue($value)
{
if (Utils::isInvalid($value)) {
return Utils::undefined();
}
if (isset($this->config['parseValue'])) {
return call_user_func($this->config['parseValue'], $value);
} else {
@ -37,9 +34,10 @@ class CustomScalarType extends ScalarType
}
/**
* @param $valueNode
* @param Node $valueNode
* @param array|null $variables
* @return mixed
* @throws \Exception
*/
public function parseLiteral(/* GraphQL\Language\AST\ValueNode */ $valueNode, array $variables = null)
{

View File

@ -1,6 +1,7 @@
<?php
namespace GraphQL\Type\Definition;
use GraphQL\Error\Error;
use GraphQL\Error\InvariantViolation;
use GraphQL\Language\AST\EnumTypeDefinitionNode;
use GraphQL\Language\AST\EnumValueNode;
@ -103,7 +104,8 @@ class EnumType extends Type implements InputType, OutputType, LeafType, NamedTyp
/**
* @param $value
* @return null
* @return mixed
* @throws Error
*/
public function serialize($value)
{
@ -112,36 +114,44 @@ class EnumType extends Type implements InputType, OutputType, LeafType, NamedTyp
return $lookup[$value]->name;
}
return Utils::undefined();
throw new Error("Cannot serialize value as enum: " . Utils::printSafe($value));
}
/**
* @param $value
* @return null
* @return mixed
* @throws Error
*/
public function parseValue($value)
{
$lookup = $this->getNameLookup();
return isset($lookup[$value]) ? $lookup[$value]->value : Utils::undefined();
if (isset($lookup[$value])) {
return $lookup[$value]->value;
}
throw new Error("Cannot represent value as enum: " . Utils::printSafe($value));
}
/**
* @param $value
* @param $valueNode
* @param array|null $variables
* @return null
* @throws \Exception
*/
public function parseLiteral($value, array $variables = null)
public function parseLiteral($valueNode, array $variables = null)
{
if ($value instanceof EnumValueNode) {
if ($valueNode instanceof EnumValueNode) {
$lookup = $this->getNameLookup();
if (isset($lookup[$value->value])) {
$enumValue = $lookup[$value->value];
if (isset($lookup[$valueNode->value])) {
$enumValue = $lookup[$valueNode->value];
if ($enumValue) {
return $enumValue->value;
}
}
}
return null;
// Intentionally without message, as all information already in wrapped Exception
throw new \Exception();
}
/**

View File

@ -49,13 +49,16 @@ values as specified by
* @param $valueNode
* @param array|null $variables
* @return float|null
* @throws \Exception
*/
public function parseLiteral($valueNode, array $variables = null)
{
if ($valueNode instanceof FloatValueNode || $valueNode instanceof IntValueNode) {
return (float) $valueNode->value;
}
return Utils::undefined();
// Intentionally without message, as all information already in wrapped Exception
throw new \Exception();
}
private function coerceFloat($value) {

View File

@ -3,6 +3,7 @@ namespace GraphQL\Type\Definition;
use GraphQL\Error\Error;
use GraphQL\Language\AST\IntValueNode;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\StringValueNode;
use GraphQL\Utils\Utils;
@ -30,6 +31,7 @@ When expected as an input type, any string (such as `"4"`) or integer
/**
* @param mixed $value
* @return string
* @throws Error
*/
public function serialize($value)
{
@ -51,22 +53,30 @@ When expected as an input type, any string (such as `"4"`) or integer
/**
* @param mixed $value
* @return string
* @throws Error
*/
public function parseValue($value)
{
return (is_string($value) || is_int($value)) ? (string) $value : Utils::undefined();
if (is_string($value) || is_int($value)) {
return (string) $value;
}
throw new Error("Cannot represent value as ID: " . Utils::printSafe($value));
}
/**
* @param $ast
* @param Node $valueNode
* @param array|null $variables
* @return null|string
* @throws \Exception
*/
public function parseLiteral($valueNode, array $variables = null)
{
if ($valueNode instanceof StringValueNode || $valueNode instanceof IntValueNode) {
return $valueNode->value;
}
return Utils::undefined();
// Intentionally without message, as all information already in wrapped Exception
throw new \Exception();
}
}

View File

@ -55,6 +55,7 @@ values. Int can represent values between -(2^31) and 2^31 - 1. ';
* @param $valueNode
* @param array|null $variables
* @return int|null
* @throws \Exception
*/
public function parseLiteral($valueNode, array $variables = null)
{
@ -64,7 +65,9 @@ values. Int can represent values between -(2^31) and 2^31 - 1. ';
return $val;
}
}
return Utils::undefined();
// Intentionally without message, as all information already in wrapped Exception
throw new \Exception();
}
private function coerceInt($value) {

View File

@ -1,6 +1,7 @@
<?php
namespace GraphQL\Type\Definition;
use GraphQL\Error\Error;
use \GraphQL\Language\AST\Node;
/*
@ -15,27 +16,30 @@ interface LeafType
*
* @param mixed $value
* @return mixed
* @throws Error
*/
public function serialize($value);
/**
* Parses an externally provided value (query variable) to use as an input
*
* In the case of an invalid value this method must return Utils::undefined()
* In the case of an invalid value this method must throw an Exception
*
* @param mixed $value
* @return mixed
* @throws Error
*/
public function parseValue($value);
/**
* Parses an externally provided literal value (hardcoded in GraphQL query) to use as an input
*
* In the case of an invalid value this method must return Utils::undefined()
* In the case of an invalid node or value this method must throw an Exception
*
* @param Node $valueNode
* @param array|null $variables
* @return mixed
* @throws \Exception
*/
public function parseLiteral($valueNode, array $variables = null);
}

View File

@ -60,13 +60,16 @@ represent free-form human-readable text.';
* @param $valueNode
* @param array|null $variables
* @return null|string
* @throws \Exception
*/
public function parseLiteral($valueNode, array $variables = null)
{
if ($valueNode instanceof StringValueNode) {
return $valueNode->value;
}
return Utils::undefined();
// Intentionally without message, as all information already in wrapped Exception
throw new \Exception();
}
private function coerceString($value) {

View File

@ -2,9 +2,6 @@
namespace GraphQL\Type\Definition;
use GraphQL\Error\InvariantViolation;
use GraphQL\Language\AST\ListType;
use GraphQL\Language\AST\NamedType;
use GraphQL\Language\AST\NonNullType;
use GraphQL\Language\AST\TypeDefinitionNode;
use GraphQL\Type\Introspection;
use GraphQL\Utils\Utils;

View File

@ -2,13 +2,10 @@
namespace GraphQL\Type;
use GraphQL\Type\Definition\AbstractType;
use GraphQL\Type\Definition\FieldArgument;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\UnionType;
use GraphQL\Type\Definition\WrappingType;
use GraphQL\Utils\TypeInfo;
use GraphQL\Utils\Utils;

View File

@ -28,7 +28,6 @@ use GraphQL\Type\Definition\EnumType;
use GraphQL\Type\Definition\IDType;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\InputType;
use GraphQL\Type\Definition\LeafType;
use GraphQL\Type\Definition\ListOfType;
use GraphQL\Type\Definition\NonNull;
use GraphQL\Type\Definition\ScalarType;
@ -209,9 +208,18 @@ class AST
if ($type instanceof ScalarType || $type instanceof EnumType) {
// Since value is an internally represented value, it must be serialized
// to an externally represented value before converting into an AST.
$serialized = $type->serialize($value);
if (null === $serialized || Utils::isInvalid($serialized)) {
return null;
try {
$serialized = $type->serialize($value);
} catch (\Exception $error) {
if ($error instanceof Error && $type instanceof EnumType) {
return null;
}
throw $error;
} catch (\Throwable $error) {
if ($error instanceof Error && $type instanceof EnumType) {
return null;
}
throw $error;
}
// Others serialize based on their corresponding PHP scalar types.
@ -400,18 +408,12 @@ class AST
// Invalid values represent a failure to parse correctly, in which case
// no value is returned.
try {
$result = $type->parseLiteral($valueNode, $variables);
return $type->parseLiteral($valueNode, $variables);
} catch (\Exception $error) {
return $undefined;
} catch (\Throwable $error) {
return $undefined;
}
if (Utils::isInvalid($result)) {
return $undefined;
}
return $result;
}
throw new Error('Unknown type: ' . Utils::printSafe($type) . '.');
@ -420,7 +422,7 @@ class AST
/**
* Produces a PHP value given a GraphQL Value AST.
*
* Unlike `valueFromAST()`, no type is provided. The resulting JavaScript value
* Unlike `valueFromAST()`, no type is provided. The resulting PHP value
* will reflect the provided GraphQL value AST.
*
* | GraphQL Value | PHP Value |
@ -471,7 +473,7 @@ class AST
);
case $valueNode instanceof VariableNode:
$variableName = $valueNode->name->value;
return ($variables && isset($variables[$variableName]) && !Utils::isInvalid($variables[$variableName]))
return ($variables && isset($variables[$variableName]))
? $variables[$variableName]
: null;
}

View File

@ -46,14 +46,7 @@ class Value
// throw to indicate failure. If it throws, maintain a reference to
// the original error.
try {
$parseResult = $type->parseValue($value);
if (Utils::isInvalid($parseResult)) {
return self::ofErrors([
self::coercionError("Expected type {$type->name}", $blameNode, $path),
]);
}
return self::ofValue($parseResult);
return self::ofValue($type->parseValue($value));
} catch (\Exception $error) {
return self::ofErrors([
self::coercionError(

View File

@ -1,7 +1,6 @@
<?php
namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Validator\ValidationContext;

View File

@ -4,11 +4,9 @@ namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Language\AST\FieldNode;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Type\Definition\InputObjectType;
use GraphQL\Type\Definition\InterfaceType;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Definition\UnionType;
use GraphQL\Type\Schema;
use GraphQL\Utils\Utils;
use GraphQL\Validator\ValidationContext;

View File

@ -1,10 +1,8 @@
<?php
namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Language\AST\FragmentSpreadNode;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Validator\ValidationContext;

View File

@ -5,7 +5,6 @@ use GraphQL\Error\Error;
use GraphQL\Language\AST\NamedTypeNode;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\Visitor;
use GraphQL\Type\Definition\Type;
use GraphQL\Utils\Utils;
use GraphQL\Validator\ValidationContext;

View File

@ -3,7 +3,6 @@ namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Language\AST\DocumentNode;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\AST\OperationDefinitionNode;
use GraphQL\Utils\Utils;

View File

@ -1,11 +1,8 @@
<?php
namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Language\AST\FragmentDefinitionNode;
use GraphQL\Language\AST\FragmentSpreadNode;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\Visitor;
use GraphQL\Utils\Utils;

View File

@ -1,7 +1,6 @@
<?php
namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Language\AST\FragmentSpreadNode;
use GraphQL\Language\AST\InlineFragmentNode;

View File

@ -1,15 +1,12 @@
<?php
namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Language\AST\DirectiveNode;
use GraphQL\Language\AST\FieldNode;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\Visitor;
use GraphQL\Type\Definition\NonNull;
use GraphQL\Utils\Utils;
use GraphQL\Validator\ValidationContext;
class ProvidedNonNullArguments extends AbstractValidationRule

View File

@ -1,5 +1,4 @@
<?php
namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;

View File

@ -2,9 +2,7 @@
namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Language\AST\ArgumentNode;
use GraphQL\Language\AST\FragmentDefinitionNode;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\Visitor;
use GraphQL\Validator\ValidationContext;

View File

@ -2,7 +2,6 @@
namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\AST\ObjectFieldNode;
use GraphQL\Language\Visitor;

View File

@ -2,7 +2,6 @@
namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\AST\OperationDefinitionNode;
use GraphQL\Language\Visitor;

View File

@ -2,7 +2,6 @@
namespace GraphQL\Validator\Rules;
use GraphQL\Error\Error;
use GraphQL\Language\AST\Node;
use GraphQL\Language\AST\NodeKind;
use GraphQL\Language\AST\VariableDefinitionNode;
use GraphQL\Validator\ValidationContext;

View File

@ -173,20 +173,9 @@ class ValuesOfCorrectType extends AbstractValidationRule
}
// Scalars determine if a literal value is valid via parseLiteral() which
// may throw or return an invalid value to indicate failure.
// may throw to indicate failure.
try {
$parseResult = $type->parseLiteral($node);
if (Utils::isInvalid($parseResult)) {
$context->reportError(
new Error(
self::badValueMessage(
(string) $locationType,
Printer::doPrint($node)
),
$node
)
);
}
$type->parseLiteral($node);
} catch (\Exception $error) {
// Ensure a reference to the original error is maintained.
$context->reportError(

View File

@ -1,6 +1,7 @@
<?php
namespace GraphQL\Tests\Executor;
use GraphQL\Error\Error;
use GraphQL\Type\Definition\ScalarType;
use GraphQL\Utils\Utils;
@ -53,28 +54,40 @@ class ComplexScalar extends ScalarType
public $name = 'ComplexScalar';
/**
* {@inheritdoc}
*/
public function serialize($value)
{
if ($value === 'DeserializedValue') {
return 'SerializedValue';
}
return null;
throw new Error("Cannot serialize value as ComplexScalar: " . Utils::printSafe($value));
}
/**
* {@inheritdoc}
*/
public function parseValue($value)
{
if ($value === 'SerializedValue') {
return 'DeserializedValue';
}
return Utils::undefined();
throw new Error("Cannot represent value as ComplexScalar: " . Utils::printSafe($value));
}
/**
* {@inheritdoc}
*/
public function parseLiteral($valueNode, array $variables = null)
{
if ($valueNode->value === 'SerializedValue') {
return 'DeserializedValue';
}
return Utils::undefined();
throw new Error("Cannot represent literal as ComplexScalar: " . Utils::printSafe($valueNode->value));
}
}