mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-22 21:06:05 +03:00
Support for NullValue
This commit is contained in:
parent
9bf8e82d7c
commit
8a676cde99
@ -5,17 +5,16 @@ namespace GraphQL\Executor;
|
|||||||
use GraphQL\Error\Error;
|
use GraphQL\Error\Error;
|
||||||
use GraphQL\Error\InvariantViolation;
|
use GraphQL\Error\InvariantViolation;
|
||||||
use GraphQL\Language\AST\Argument;
|
use GraphQL\Language\AST\Argument;
|
||||||
|
use GraphQL\Language\AST\NullValue;
|
||||||
use GraphQL\Language\AST\VariableDefinition;
|
use GraphQL\Language\AST\VariableDefinition;
|
||||||
use GraphQL\Language\Printer;
|
use GraphQL\Language\Printer;
|
||||||
use GraphQL\Schema;
|
use GraphQL\Schema;
|
||||||
use GraphQL\Type\Definition\EnumType;
|
|
||||||
use GraphQL\Type\Definition\FieldArgument;
|
use GraphQL\Type\Definition\FieldArgument;
|
||||||
use GraphQL\Type\Definition\InputObjectType;
|
use GraphQL\Type\Definition\InputObjectType;
|
||||||
use GraphQL\Type\Definition\InputType;
|
use GraphQL\Type\Definition\InputType;
|
||||||
use GraphQL\Type\Definition\LeafType;
|
use GraphQL\Type\Definition\LeafType;
|
||||||
use GraphQL\Type\Definition\ListOfType;
|
use GraphQL\Type\Definition\ListOfType;
|
||||||
use GraphQL\Type\Definition\NonNull;
|
use GraphQL\Type\Definition\NonNull;
|
||||||
use GraphQL\Type\Definition\ScalarType;
|
|
||||||
use GraphQL\Type\Definition\Type;
|
use GraphQL\Type\Definition\Type;
|
||||||
use GraphQL\Utils;
|
use GraphQL\Utils;
|
||||||
|
|
||||||
@ -65,16 +64,29 @@ class Values
|
|||||||
$valueAST = isset($argASTMap[$name]) ? $argASTMap[$name]->value : null;
|
$valueAST = isset($argASTMap[$name]) ? $argASTMap[$name]->value : null;
|
||||||
$value = Utils\AST::valueFromAST($valueAST, $argDef->getType(), $variableValues);
|
$value = Utils\AST::valueFromAST($valueAST, $argDef->getType(), $variableValues);
|
||||||
|
|
||||||
|
if (null === $value && null === $argDef->defaultValue && !$argDef->defaultValueExists()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (null === $value) {
|
if (null === $value) {
|
||||||
$value = $argDef->defaultValue;
|
$value = $argDef->defaultValue;
|
||||||
}
|
}
|
||||||
if (null !== $value) {
|
if (NullValue::getNullValue() === $value) {
|
||||||
$result[$name] = $value;
|
$value = null;
|
||||||
}
|
}
|
||||||
|
$result[$name] = $value;
|
||||||
}
|
}
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Moved to Utils\AST::valueFromAST
|
||||||
|
*
|
||||||
|
* @param $valueAST
|
||||||
|
* @param InputType $type
|
||||||
|
* @param null $variables
|
||||||
|
* @return array|null|\stdClass
|
||||||
|
*/
|
||||||
public static function valueFromAST($valueAST, InputType $type, $variables = null)
|
public static function valueFromAST($valueAST, InputType $type, $variables = null)
|
||||||
{
|
{
|
||||||
return Utils\AST::valueFromAST($valueAST, $type, $variables);
|
return Utils\AST::valueFromAST($valueAST, $type, $variables);
|
||||||
@ -105,7 +117,8 @@ class Values
|
|||||||
if (null === $input) {
|
if (null === $input) {
|
||||||
$defaultValue = $definitionAST->defaultValue;
|
$defaultValue = $definitionAST->defaultValue;
|
||||||
if ($defaultValue) {
|
if ($defaultValue) {
|
||||||
return Utils\AST::valueFromAST($defaultValue, $inputType);
|
$value = Utils\AST::valueFromAST($defaultValue, $inputType);
|
||||||
|
return $value === NullValue::getNullValue() ? null : $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self::coerceValue($inputType, $input);
|
return self::coerceValue($inputType, $input);
|
||||||
|
@ -31,6 +31,7 @@ class NodeType
|
|||||||
const STRING = 'StringValue';
|
const STRING = 'StringValue';
|
||||||
const BOOLEAN = 'BooleanValue';
|
const BOOLEAN = 'BooleanValue';
|
||||||
const ENUM = 'EnumValue';
|
const ENUM = 'EnumValue';
|
||||||
|
const NULL = 'NullValue';
|
||||||
const LST = 'ListValue';
|
const LST = 'ListValue';
|
||||||
const OBJECT = 'ObjectValue';
|
const OBJECT = 'ObjectValue';
|
||||||
const OBJECT_FIELD = 'ObjectField';
|
const OBJECT_FIELD = 'ObjectField';
|
||||||
|
13
src/Language/AST/NullValue.php
Normal file
13
src/Language/AST/NullValue.php
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?php
|
||||||
|
namespace GraphQL\Language\AST;
|
||||||
|
|
||||||
|
class NullValue extends Node implements Value
|
||||||
|
{
|
||||||
|
public $kind = NodeType::NULL;
|
||||||
|
|
||||||
|
public static function getNullValue()
|
||||||
|
{
|
||||||
|
static $nullValue;
|
||||||
|
return $nullValue ?: $nullValue = new \stdClass();
|
||||||
|
}
|
||||||
|
}
|
@ -27,6 +27,7 @@ use GraphQL\Language\AST\Location;
|
|||||||
use GraphQL\Language\AST\Name;
|
use GraphQL\Language\AST\Name;
|
||||||
use GraphQL\Language\AST\NamedType;
|
use GraphQL\Language\AST\NamedType;
|
||||||
use GraphQL\Language\AST\NonNullType;
|
use GraphQL\Language\AST\NonNullType;
|
||||||
|
use GraphQL\Language\AST\NullValue;
|
||||||
use GraphQL\Language\AST\ObjectField;
|
use GraphQL\Language\AST\ObjectField;
|
||||||
use GraphQL\Language\AST\ObjectTypeDefinition;
|
use GraphQL\Language\AST\ObjectTypeDefinition;
|
||||||
use GraphQL\Language\AST\ObjectValue;
|
use GraphQL\Language\AST\ObjectValue;
|
||||||
@ -610,16 +611,19 @@ class Parser
|
|||||||
* - FloatValue
|
* - FloatValue
|
||||||
* - StringValue
|
* - StringValue
|
||||||
* - BooleanValue
|
* - BooleanValue
|
||||||
|
* - NullValue
|
||||||
* - EnumValue
|
* - EnumValue
|
||||||
* - ListValue[?Const]
|
* - ListValue[?Const]
|
||||||
* - ObjectValue[?Const]
|
* - ObjectValue[?Const]
|
||||||
*
|
*
|
||||||
* BooleanValue : one of `true` `false`
|
* BooleanValue : one of `true` `false`
|
||||||
*
|
*
|
||||||
|
* NullValue : `null`
|
||||||
|
*
|
||||||
* EnumValue : Name but not `true`, `false` or `null`
|
* EnumValue : Name but not `true`, `false` or `null`
|
||||||
*
|
*
|
||||||
* @param $isConst
|
* @param $isConst
|
||||||
* @return BooleanValue|EnumValue|FloatValue|IntValue|StringValue|Variable|ListValue|ObjectValue
|
* @return BooleanValue|EnumValue|FloatValue|IntValue|StringValue|Variable|ListValue|ObjectValue|NullValue
|
||||||
* @throws SyntaxError
|
* @throws SyntaxError
|
||||||
*/
|
*/
|
||||||
function parseValueLiteral($isConst)
|
function parseValueLiteral($isConst)
|
||||||
@ -655,7 +659,12 @@ class Parser
|
|||||||
'value' => $token->value === 'true',
|
'value' => $token->value === 'true',
|
||||||
'loc' => $this->loc($token)
|
'loc' => $this->loc($token)
|
||||||
]);
|
]);
|
||||||
} else if ($token->value !== 'null') {
|
} else if ($token->value === 'null') {
|
||||||
|
$this->lexer->advance();
|
||||||
|
return new NullValue([
|
||||||
|
'loc' => $this->loc($token)
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
$this->lexer->advance();
|
$this->lexer->advance();
|
||||||
return new EnumValue([
|
return new EnumValue([
|
||||||
'value' => $token->value,
|
'value' => $token->value,
|
||||||
|
@ -21,11 +21,11 @@ use GraphQL\Language\AST\FragmentSpread;
|
|||||||
use GraphQL\Language\AST\InlineFragment;
|
use GraphQL\Language\AST\InlineFragment;
|
||||||
use GraphQL\Language\AST\IntValue;
|
use GraphQL\Language\AST\IntValue;
|
||||||
use GraphQL\Language\AST\ListType;
|
use GraphQL\Language\AST\ListType;
|
||||||
use GraphQL\Language\AST\Name;
|
|
||||||
use GraphQL\Language\AST\NamedType;
|
use GraphQL\Language\AST\NamedType;
|
||||||
use GraphQL\Language\AST\Node;
|
use GraphQL\Language\AST\Node;
|
||||||
use GraphQL\Language\AST\NodeType;
|
use GraphQL\Language\AST\NodeType;
|
||||||
use GraphQL\Language\AST\NonNullType;
|
use GraphQL\Language\AST\NonNullType;
|
||||||
|
use GraphQL\Language\AST\NullValue;
|
||||||
use GraphQL\Language\AST\ObjectField;
|
use GraphQL\Language\AST\ObjectField;
|
||||||
use GraphQL\Language\AST\ObjectTypeDefinition;
|
use GraphQL\Language\AST\ObjectTypeDefinition;
|
||||||
use GraphQL\Language\AST\ObjectValue;
|
use GraphQL\Language\AST\ObjectValue;
|
||||||
@ -112,14 +112,33 @@ class Printer
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Value
|
// Value
|
||||||
NodeType::INT => function(IntValue $node) {return $node->value;},
|
NodeType::INT => function(IntValue $node) {
|
||||||
NodeType::FLOAT => function(FloatValue $node) {return $node->value;},
|
return $node->value;
|
||||||
NodeType::STRING => function(StringValue $node) {return json_encode($node->value);},
|
},
|
||||||
NodeType::BOOLEAN => function(BooleanValue $node) {return $node->value ? 'true' : 'false';},
|
NodeType::FLOAT => function(FloatValue $node) {
|
||||||
NodeType::ENUM => function(EnumValue $node) {return $node->value;},
|
return $node->value;
|
||||||
NodeType::LST => function(ListValue $node) {return '[' . $this->join($node->values, ', ') . ']';},
|
},
|
||||||
NodeType::OBJECT => function(ObjectValue $node) {return '{' . $this->join($node->fields, ', ') . '}';},
|
NodeType::STRING => function(StringValue $node) {
|
||||||
NodeType::OBJECT_FIELD => function(ObjectField $node) {return $node->name . ': ' . $node->value;},
|
return json_encode($node->value);
|
||||||
|
},
|
||||||
|
NodeType::BOOLEAN => function(BooleanValue $node) {
|
||||||
|
return $node->value ? 'true' : 'false';
|
||||||
|
},
|
||||||
|
NodeType::NULL => function(NullValue $node) {
|
||||||
|
return 'null';
|
||||||
|
},
|
||||||
|
NodeType::ENUM => function(EnumValue $node) {
|
||||||
|
return $node->value;
|
||||||
|
},
|
||||||
|
NodeType::LST => function(ListValue $node) {
|
||||||
|
return '[' . $this->join($node->values, ', ') . ']';
|
||||||
|
},
|
||||||
|
NodeType::OBJECT => function(ObjectValue $node) {
|
||||||
|
return '{' . $this->join($node->fields, ', ') . '}';
|
||||||
|
},
|
||||||
|
NodeType::OBJECT_FIELD => function(ObjectField $node) {
|
||||||
|
return $node->name . ': ' . $node->value;
|
||||||
|
},
|
||||||
|
|
||||||
// Directive
|
// Directive
|
||||||
NodeType::DIRECTIVE => function(Directive $node) {
|
NodeType::DIRECTIVE => function(Directive $node) {
|
||||||
@ -127,9 +146,15 @@ class Printer
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Type
|
// Type
|
||||||
NodeType::NAMED_TYPE => function(NamedType $node) {return $node->name;},
|
NodeType::NAMED_TYPE => function(NamedType $node) {
|
||||||
NodeType::LIST_TYPE => function(ListType $node) {return '[' . $node->type . ']';},
|
return $node->name;
|
||||||
NodeType::NON_NULL_TYPE => function(NonNullType $node) {return $node->type . '!';},
|
},
|
||||||
|
NodeType::LIST_TYPE => function(ListType $node) {
|
||||||
|
return '[' . $node->type . ']';
|
||||||
|
},
|
||||||
|
NodeType::NON_NULL_TYPE => function(NonNullType $node) {
|
||||||
|
return $node->type . '!';
|
||||||
|
},
|
||||||
|
|
||||||
// Type System Definitions
|
// Type System Definitions
|
||||||
NodeType::SCHEMA_DEFINITION => function(SchemaDefinition $def) {
|
NodeType::SCHEMA_DEFINITION => function(SchemaDefinition $def) {
|
||||||
@ -139,7 +164,9 @@ class Printer
|
|||||||
$this->block($def->operationTypes)
|
$this->block($def->operationTypes)
|
||||||
], ' ');
|
], ' ');
|
||||||
},
|
},
|
||||||
NodeType::OPERATION_TYPE_DEFINITION => function(OperationTypeDefinition $def) {return $def->operation . ': ' . $def->type;},
|
NodeType::OPERATION_TYPE_DEFINITION => function(OperationTypeDefinition $def) {
|
||||||
|
return $def->operation . ': ' . $def->type;
|
||||||
|
},
|
||||||
|
|
||||||
NodeType::SCALAR_TYPE_DEFINITION => function(ScalarTypeDefinition $def) {
|
NodeType::SCALAR_TYPE_DEFINITION => function(ScalarTypeDefinition $def) {
|
||||||
return $this->join(['scalar', $def->name, $this->join($def->directives, ' ')], ' ');
|
return $this->join(['scalar', $def->name, $this->join($def->directives, ' ')], ' ');
|
||||||
|
@ -65,6 +65,7 @@ class Visitor
|
|||||||
NodeType::FLOAT => [],
|
NodeType::FLOAT => [],
|
||||||
NodeType::STRING => [],
|
NodeType::STRING => [],
|
||||||
NodeType::BOOLEAN => [],
|
NodeType::BOOLEAN => [],
|
||||||
|
NodeType::NULL => [],
|
||||||
NodeType::ENUM => [],
|
NodeType::ENUM => [],
|
||||||
NodeType::LST => ['values'],
|
NodeType::LST => ['values'],
|
||||||
NodeType::OBJECT => ['fields'],
|
NodeType::OBJECT => ['fields'],
|
||||||
|
@ -40,6 +40,11 @@ class FieldArgument
|
|||||||
*/
|
*/
|
||||||
private $resolvedType;
|
private $resolvedType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $defaultValueExists = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $config
|
* @param array $config
|
||||||
* @return array
|
* @return array
|
||||||
@ -62,17 +67,23 @@ class FieldArgument
|
|||||||
*/
|
*/
|
||||||
public function __construct(array $def)
|
public function __construct(array $def)
|
||||||
{
|
{
|
||||||
$def += [
|
foreach ($def as $key => $value) {
|
||||||
'type' => null,
|
switch ($key) {
|
||||||
'name' => null,
|
case 'type':
|
||||||
'defaultValue' => null,
|
$this->type = $value;
|
||||||
'description' => null
|
break;
|
||||||
];
|
case 'name':
|
||||||
|
$this->name = $value;
|
||||||
$this->type = $def['type'];
|
break;
|
||||||
$this->name = $def['name'];
|
case 'defaultValue':
|
||||||
$this->description = $def['description'];
|
$this->defaultValue = $value;
|
||||||
$this->defaultValue = $def['defaultValue'];
|
$this->defaultValueExists = true;
|
||||||
|
break;
|
||||||
|
case 'description':
|
||||||
|
$this->description = $value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
$this->config = $def;
|
$this->config = $def;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -87,4 +98,12 @@ class FieldArgument
|
|||||||
}
|
}
|
||||||
return $this->resolvedType;
|
return $this->resolvedType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function defaultValueExists()
|
||||||
|
{
|
||||||
|
return $this->defaultValueExists;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,13 @@ class InputObjectField
|
|||||||
*/
|
*/
|
||||||
public $type;
|
public $type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helps to differentiate when `defaultValue` is `null` and when it was not even set initially
|
||||||
|
*
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
private $defaultValueExists = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* InputObjectField constructor.
|
* InputObjectField constructor.
|
||||||
* @param array $opts
|
* @param array $opts
|
||||||
@ -34,7 +41,16 @@ class InputObjectField
|
|||||||
public function __construct(array $opts)
|
public function __construct(array $opts)
|
||||||
{
|
{
|
||||||
foreach ($opts as $k => $v) {
|
foreach ($opts as $k => $v) {
|
||||||
$this->{$k} = $v;
|
switch ($k) {
|
||||||
|
case 'defaultValue':
|
||||||
|
$this->defaultValue = $v;
|
||||||
|
$this->defaultValueExists = true;
|
||||||
|
break;
|
||||||
|
case 'defaultValueExists':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$this->{$k} = $v;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,4 +61,12 @@ class InputObjectField
|
|||||||
{
|
{
|
||||||
return Type::resolve($this->type);
|
return Type::resolve($this->type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function defaultValueExists()
|
||||||
|
{
|
||||||
|
return $this->defaultValueExists;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ use GraphQL\Language\AST\FloatValue;
|
|||||||
use GraphQL\Language\AST\IntValue;
|
use GraphQL\Language\AST\IntValue;
|
||||||
use GraphQL\Language\AST\ListValue;
|
use GraphQL\Language\AST\ListValue;
|
||||||
use GraphQL\Language\AST\Name;
|
use GraphQL\Language\AST\Name;
|
||||||
|
use GraphQL\Language\AST\NullValue;
|
||||||
use GraphQL\Language\AST\ObjectField;
|
use GraphQL\Language\AST\ObjectField;
|
||||||
use GraphQL\Language\AST\ObjectValue;
|
use GraphQL\Language\AST\ObjectValue;
|
||||||
use GraphQL\Language\AST\StringValue;
|
use GraphQL\Language\AST\StringValue;
|
||||||
@ -43,21 +44,24 @@ class AST
|
|||||||
* | Int | Int |
|
* | Int | Int |
|
||||||
* | Float | Int / Float |
|
* | Float | Int / Float |
|
||||||
* | Mixed | Enum Value |
|
* | Mixed | Enum Value |
|
||||||
|
* | null | NullValue |
|
||||||
*
|
*
|
||||||
* @param $value
|
* @param $value
|
||||||
* @param InputType $type
|
* @param InputType $type
|
||||||
* @return ObjectValue|ListValue|BooleanValue|IntValue|FloatValue|EnumValue|StringValue
|
* @return ObjectValue|ListValue|BooleanValue|IntValue|FloatValue|EnumValue|StringValue|NullValue
|
||||||
*/
|
*/
|
||||||
static function astFromValue($value, InputType $type)
|
static function astFromValue($value, InputType $type)
|
||||||
{
|
{
|
||||||
if ($type instanceof NonNull) {
|
if ($type instanceof NonNull) {
|
||||||
// Note: we're not checking that the result is non-null.
|
$astValue = self::astFromValue($value, $type->getWrappedType());
|
||||||
// This function is not responsible for validating the input value.
|
if ($astValue instanceof NullValue) {
|
||||||
return self::astFromValue($value, $type->getWrappedType());
|
return null;
|
||||||
|
}
|
||||||
|
return $astValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($value === null) {
|
if ($value === null) {
|
||||||
return null;
|
return new NullValue([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert PHP array to GraphQL list. If the GraphQLType is a list, but
|
// Convert PHP array to GraphQL list. If the GraphQLType is a list, but
|
||||||
@ -80,7 +84,8 @@ class AST
|
|||||||
// Populate the fields of the input object by creating ASTs from each value
|
// Populate the fields of the input object by creating ASTs from each value
|
||||||
// in the PHP object according to the fields in the input type.
|
// in the PHP object according to the fields in the input type.
|
||||||
if ($type instanceof InputObjectType) {
|
if ($type instanceof InputObjectType) {
|
||||||
$isArrayLike = is_array($value) || $value instanceof \ArrayAccess;
|
$isArray = is_array($value);
|
||||||
|
$isArrayLike = $isArray || $value instanceof \ArrayAccess;
|
||||||
if ($value === null || (!$isArrayLike && !is_object($value))) {
|
if ($value === null || (!$isArrayLike && !is_object($value))) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -92,13 +97,29 @@ class AST
|
|||||||
} else {
|
} else {
|
||||||
$fieldValue = isset($value->{$fieldName}) ? $value->{$fieldName} : null;
|
$fieldValue = isset($value->{$fieldName}) ? $value->{$fieldName} : null;
|
||||||
}
|
}
|
||||||
$fieldValue = self::astFromValue($fieldValue, $field->getType());
|
|
||||||
|
|
||||||
if ($fieldValue) {
|
// Have to check additionally if key exists, since we differentiate between
|
||||||
$fieldASTs[] = new ObjectField([
|
// "no key" and "value is null":
|
||||||
'name' => new Name(['value' => $fieldName]),
|
if (null !== $fieldValue) {
|
||||||
'value' => $fieldValue
|
$fieldExists = true;
|
||||||
]);
|
} else if ($isArray) {
|
||||||
|
$fieldExists = array_key_exists($fieldName, $value);
|
||||||
|
} else if ($isArrayLike) {
|
||||||
|
/** @var \ArrayAccess $value */
|
||||||
|
$fieldExists = $value->offsetExists($fieldName);
|
||||||
|
} else {
|
||||||
|
$fieldExists = property_exists($value, $fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($fieldExists) {
|
||||||
|
$fieldNode = self::astFromValue($fieldValue, $field->getType());
|
||||||
|
|
||||||
|
if ($fieldNode) {
|
||||||
|
$fieldASTs[] = new ObjectField([
|
||||||
|
'name' => new Name(['value' => $fieldName]),
|
||||||
|
'value' => $fieldNode
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return new ObjectValue(['fields' => $fieldASTs]);
|
return new ObjectValue(['fields' => $fieldASTs]);
|
||||||
@ -165,11 +186,12 @@ class AST
|
|||||||
* | String | String |
|
* | String | String |
|
||||||
* | Int / Float | Int / Float |
|
* | Int / Float | Int / Float |
|
||||||
* | Enum Value | Mixed |
|
* | Enum Value | Mixed |
|
||||||
|
* | Null Value | null |
|
||||||
*
|
*
|
||||||
* @param $valueAST
|
* @param $valueAST
|
||||||
* @param InputType $type
|
* @param InputType $type
|
||||||
* @param null $variables
|
* @param null $variables
|
||||||
* @return array|null
|
* @return array|null|\stdClass
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public static function valueFromAST($valueAST, InputType $type, $variables = null)
|
public static function valueFromAST($valueAST, InputType $type, $variables = null)
|
||||||
@ -182,14 +204,22 @@ class AST
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$valueAST) {
|
if (!$valueAST) {
|
||||||
return null;
|
// When there is no AST, then there is also no value.
|
||||||
|
// Importantly, this is different from returning the GraphQL null value.
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($valueAST instanceof NullValue) {
|
||||||
|
// This is explicitly returning the value null.
|
||||||
|
return NullValue::getNullValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($valueAST instanceof Variable) {
|
if ($valueAST instanceof Variable) {
|
||||||
$variableName = $valueAST->name->value;
|
$variableName = $valueAST->name->value;
|
||||||
|
|
||||||
if (!$variables || !isset($variables[$variableName])) {
|
if (!$variables || !isset($variables[$variableName])) {
|
||||||
return null;
|
// No valid return value.
|
||||||
|
return ;
|
||||||
}
|
}
|
||||||
// Note: we're not doing any checking that this variable is correct. We're
|
// Note: we're not doing any checking that this variable is correct. We're
|
||||||
// assuming that this query has been validated and the variable usage here
|
// assuming that this query has been validated and the variable usage here
|
||||||
@ -199,19 +229,23 @@ class AST
|
|||||||
|
|
||||||
if ($type instanceof ListOfType) {
|
if ($type instanceof ListOfType) {
|
||||||
$itemType = $type->getWrappedType();
|
$itemType = $type->getWrappedType();
|
||||||
if ($valueAST instanceof ListValue) {
|
$items = $valueAST instanceof ListValue ? $valueAST->values : [$valueAST];
|
||||||
return array_map(function($itemAST) use ($itemType, $variables) {
|
$result = [];
|
||||||
return self::valueFromAST($itemAST, $itemType, $variables);
|
foreach ($items as $itemAST) {
|
||||||
}, $valueAST->values);
|
$value = self::valueFromAST($itemAST, $itemType, $variables);
|
||||||
} else {
|
if ($value === NullValue::getNullValue()) {
|
||||||
return [self::valueFromAST($valueAST, $itemType, $variables)];
|
$value = null;
|
||||||
|
}
|
||||||
|
$result[] = $value;
|
||||||
}
|
}
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($type instanceof InputObjectType) {
|
if ($type instanceof InputObjectType) {
|
||||||
$fields = $type->getFields();
|
$fields = $type->getFields();
|
||||||
if (!$valueAST instanceof ObjectValue) {
|
if (!$valueAST instanceof ObjectValue) {
|
||||||
return null;
|
// No valid return value.
|
||||||
|
return ;
|
||||||
}
|
}
|
||||||
$fieldASTs = Utils::keyMap($valueAST->fields, function($field) {return $field->name->value;});
|
$fieldASTs = Utils::keyMap($valueAST->fields, function($field) {return $field->name->value;});
|
||||||
$values = [];
|
$values = [];
|
||||||
@ -219,12 +253,19 @@ class AST
|
|||||||
$fieldAST = isset($fieldASTs[$field->name]) ? $fieldASTs[$field->name] : null;
|
$fieldAST = isset($fieldASTs[$field->name]) ? $fieldASTs[$field->name] : null;
|
||||||
$fieldValue = self::valueFromAST($fieldAST ? $fieldAST->value : null, $field->getType(), $variables);
|
$fieldValue = self::valueFromAST($fieldAST ? $fieldAST->value : null, $field->getType(), $variables);
|
||||||
|
|
||||||
if (null === $fieldValue) {
|
// If field is not in AST and defaultValue was never set for this field - do not include it in result
|
||||||
|
if (null === $fieldValue && null === $field->defaultValue && !$field->defaultValueExists()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Explicit null value or default value:
|
||||||
|
if (NullValue::getNullValue() === $fieldValue) {
|
||||||
|
$fieldValue = null;
|
||||||
|
} else if (null === $fieldValue) {
|
||||||
$fieldValue = $field->defaultValue;
|
$fieldValue = $field->defaultValue;
|
||||||
}
|
}
|
||||||
if (null !== $fieldValue) {
|
|
||||||
$values[$field->name] = $fieldValue;
|
$values[$field->name] = $fieldValue;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return $values;
|
return $values;
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ use GraphQL\Language\AST\Document;
|
|||||||
use GraphQL\Language\AST\FragmentSpread;
|
use GraphQL\Language\AST\FragmentSpread;
|
||||||
use GraphQL\Language\AST\Node;
|
use GraphQL\Language\AST\Node;
|
||||||
use GraphQL\Language\AST\NodeType;
|
use GraphQL\Language\AST\NodeType;
|
||||||
|
use GraphQL\Language\AST\NullValue;
|
||||||
use GraphQL\Language\AST\Value;
|
use GraphQL\Language\AST\Value;
|
||||||
use GraphQL\Language\AST\Variable;
|
use GraphQL\Language\AST\Variable;
|
||||||
use GraphQL\Language\Printer;
|
use GraphQL\Language\Printer;
|
||||||
@ -155,7 +156,7 @@ class DocumentValidator
|
|||||||
// A value must be provided if the type is non-null.
|
// A value must be provided if the type is non-null.
|
||||||
if ($type instanceof NonNull) {
|
if ($type instanceof NonNull) {
|
||||||
$wrappedType = $type->getWrappedType();
|
$wrappedType = $type->getWrappedType();
|
||||||
if (!$valueAST) {
|
if (!$valueAST || $valueAST instanceof NullValue) {
|
||||||
if ($wrappedType->name) {
|
if ($wrappedType->name) {
|
||||||
return [ "Expected \"{$wrappedType->name}!\", found null." ];
|
return [ "Expected \"{$wrappedType->name}!\", found null." ];
|
||||||
}
|
}
|
||||||
@ -164,7 +165,7 @@ class DocumentValidator
|
|||||||
return static::isValidLiteralValue($wrappedType, $valueAST);
|
return static::isValidLiteralValue($wrappedType, $valueAST);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$valueAST) {
|
if (!$valueAST || $valueAST instanceof NullValue) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -836,7 +836,7 @@ class ExecutorTest extends \PHPUnit_Framework_TestCase
|
|||||||
$result = Executor::execute($schema, $query);
|
$result = Executor::execute($schema, $query);
|
||||||
$expected = [
|
$expected = [
|
||||||
'data' => [
|
'data' => [
|
||||||
'field' => '{"a":1,"c":0,"d":false,"e":"0","f":"some-string","h":{"a":1,"b":"test"}}'
|
'field' => '{"a":1,"b":null,"c":0,"d":false,"e":"0","f":"some-string","h":{"a":1,"b":"test"}}'
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -49,6 +49,28 @@ class VariablesTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$this->assertEquals($expected, Executor::execute($this->schema(), $ast)->toArray());
|
$this->assertEquals($expected, Executor::execute($this->schema(), $ast)->toArray());
|
||||||
|
|
||||||
|
// properly parses null value to null
|
||||||
|
$doc = '
|
||||||
|
{
|
||||||
|
fieldWithObjectInput(input: {a: null, b: null, c: "C", d: null})
|
||||||
|
}
|
||||||
|
';
|
||||||
|
$ast = Parser::parse($doc);
|
||||||
|
$expected = ['data' => ['fieldWithObjectInput' => '{"a":null,"b":null,"c":"C","d":null}']];
|
||||||
|
|
||||||
|
$this->assertEquals($expected, Executor::execute($this->schema(), $ast)->toArray());
|
||||||
|
|
||||||
|
// properly parses null value in list
|
||||||
|
$doc = '
|
||||||
|
{
|
||||||
|
fieldWithObjectInput(input: {b: ["A",null,"C"], c: "C"})
|
||||||
|
}
|
||||||
|
';
|
||||||
|
$ast = Parser::parse($doc);
|
||||||
|
$expected = ['data' => ['fieldWithObjectInput' => '{"b":["A",null,"C"],"c":"C"}']];
|
||||||
|
|
||||||
|
$this->assertEquals($expected, Executor::execute($this->schema(), $ast)->toArray());
|
||||||
|
|
||||||
// does not use incorrect value
|
// does not use incorrect value
|
||||||
$doc = '
|
$doc = '
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,7 @@ use GraphQL\Language\AST\Field;
|
|||||||
use GraphQL\Language\AST\Name;
|
use GraphQL\Language\AST\Name;
|
||||||
use GraphQL\Language\AST\Node;
|
use GraphQL\Language\AST\Node;
|
||||||
use GraphQL\Language\AST\NodeType;
|
use GraphQL\Language\AST\NodeType;
|
||||||
|
use GraphQL\Language\AST\NullValue;
|
||||||
use GraphQL\Language\AST\SelectionSet;
|
use GraphQL\Language\AST\SelectionSet;
|
||||||
use GraphQL\Language\AST\StringValue;
|
use GraphQL\Language\AST\StringValue;
|
||||||
use GraphQL\Language\Parser;
|
use GraphQL\Language\Parser;
|
||||||
@ -106,15 +107,6 @@ fragment MissingOn Type
|
|||||||
Parser::parse('{ ...on }');
|
Parser::parse('{ ...on }');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @it does not allow null as value
|
|
||||||
*/
|
|
||||||
public function testDoesNotAllowNullAsValue()
|
|
||||||
{
|
|
||||||
$this->setExpectedException('GraphQL\Error\SyntaxError', 'Syntax Error GraphQL (1:39) Unexpected Name "null"');
|
|
||||||
Parser::parse('{ fieldWithNullableStringInput(input: null) }');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @it parses multi-byte characters
|
* @it parses multi-byte characters
|
||||||
*/
|
*/
|
||||||
@ -393,6 +385,17 @@ fragment $fragmentName on Type {
|
|||||||
|
|
||||||
// Describe: parseValue
|
// Describe: parseValue
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it parses null value
|
||||||
|
*/
|
||||||
|
public function testParsesNullValues()
|
||||||
|
{
|
||||||
|
$this->assertEquals([
|
||||||
|
'kind' => NodeType::NULL,
|
||||||
|
'loc' => ['start' => 0, 'end' => 4]
|
||||||
|
], $this->nodeToArray(Parser::parseValue('null')));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @it parses list values
|
* @it parses list values
|
||||||
*/
|
*/
|
||||||
|
@ -154,7 +154,7 @@ fragment frag on Friend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
unnamed(truthy: true, falsey: false)
|
unnamed(truthy: true, falsey: false, nullish: null)
|
||||||
query
|
query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ type Foo implements Bar {
|
|||||||
four(argument: String = "string"): String
|
four(argument: String = "string"): String
|
||||||
five(argument: [String] = ["string", "string"]): String
|
five(argument: [String] = ["string", "string"]): String
|
||||||
six(argument: InputType = {key: "value"}): Type
|
six(argument: InputType = {key: "value"}): Type
|
||||||
|
seven(argument: Int = null): Type
|
||||||
}
|
}
|
||||||
|
|
||||||
type AnnotatedObject @onObject(arg: "value") {
|
type AnnotatedObject @onObject(arg: "value") {
|
||||||
|
@ -636,6 +636,12 @@ class VisitorTest extends \PHPUnit_Framework_TestCase
|
|||||||
[ 'enter', 'BooleanValue', 'value', 'Argument' ],
|
[ 'enter', 'BooleanValue', 'value', 'Argument' ],
|
||||||
[ 'leave', 'BooleanValue', 'value', 'Argument' ],
|
[ 'leave', 'BooleanValue', 'value', 'Argument' ],
|
||||||
[ 'leave', 'Argument', 1, null ],
|
[ 'leave', 'Argument', 1, null ],
|
||||||
|
[ 'enter', 'Argument', 2, null ],
|
||||||
|
[ 'enter', 'Name', 'name', 'Argument' ],
|
||||||
|
[ 'leave', 'Name', 'name', 'Argument' ],
|
||||||
|
[ 'enter', 'NullValue', 'value', 'Argument' ],
|
||||||
|
[ 'leave', 'NullValue', 'value', 'Argument' ],
|
||||||
|
[ 'leave', 'Argument', 2, null ],
|
||||||
[ 'leave', 'Field', 0, null ],
|
[ 'leave', 'Field', 0, null ],
|
||||||
[ 'enter', 'Field', 1, null ],
|
[ 'enter', 'Field', 1, null ],
|
||||||
[ 'enter', 'Name', 'name', 'Field' ],
|
[ 'enter', 'Name', 'name', 'Field' ],
|
||||||
|
@ -52,6 +52,6 @@ fragment frag on Friend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
unnamed(truthy: true, falsey: false),
|
unnamed(truthy: true, falsey: false, nullish: null),
|
||||||
query
|
query
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ type Foo implements Bar {
|
|||||||
four(argument: String = "string"): String
|
four(argument: String = "string"): String
|
||||||
five(argument: [String] = ["string", "string"]): String
|
five(argument: [String] = ["string", "string"]): String
|
||||||
six(argument: InputType = {key: "value"}): Type
|
six(argument: InputType = {key: "value"}): Type
|
||||||
|
seven(argument: Int = null): Type
|
||||||
}
|
}
|
||||||
|
|
||||||
type AnnotatedObject @onObject(arg: "value") {
|
type AnnotatedObject @onObject(arg: "value") {
|
||||||
|
@ -7,6 +7,7 @@ use GraphQL\Language\AST\FloatValue;
|
|||||||
use GraphQL\Language\AST\IntValue;
|
use GraphQL\Language\AST\IntValue;
|
||||||
use GraphQL\Language\AST\ListValue;
|
use GraphQL\Language\AST\ListValue;
|
||||||
use GraphQL\Language\AST\Name;
|
use GraphQL\Language\AST\Name;
|
||||||
|
use GraphQL\Language\AST\NullValue;
|
||||||
use GraphQL\Language\AST\ObjectField;
|
use GraphQL\Language\AST\ObjectField;
|
||||||
use GraphQL\Language\AST\ObjectValue;
|
use GraphQL\Language\AST\ObjectValue;
|
||||||
use GraphQL\Language\AST\StringValue;
|
use GraphQL\Language\AST\StringValue;
|
||||||
@ -26,9 +27,11 @@ class ASTFromValueTest extends \PHPUnit_Framework_TestCase
|
|||||||
{
|
{
|
||||||
$this->assertEquals(new BooleanValue(['value' => true]), AST::astFromValue(true, Type::boolean()));
|
$this->assertEquals(new BooleanValue(['value' => true]), AST::astFromValue(true, Type::boolean()));
|
||||||
$this->assertEquals(new BooleanValue(['value' => false]), AST::astFromValue(false, Type::boolean()));
|
$this->assertEquals(new BooleanValue(['value' => false]), AST::astFromValue(false, Type::boolean()));
|
||||||
$this->assertEquals(null, AST::astFromValue(null, Type::boolean()));
|
$this->assertEquals(new NullValue([]), AST::astFromValue(null, Type::boolean()));
|
||||||
$this->assertEquals(new BooleanValue(['value' => false]), AST::astFromValue(0, Type::boolean()));
|
$this->assertEquals(new BooleanValue(['value' => false]), AST::astFromValue(0, Type::boolean()));
|
||||||
$this->assertEquals(new BooleanValue(['value' => true]), AST::astFromValue(1, Type::boolean()));
|
$this->assertEquals(new BooleanValue(['value' => true]), AST::astFromValue(1, Type::boolean()));
|
||||||
|
$this->assertEquals(new BooleanValue(['value' => false]), AST::astFromValue(0, Type::nonNull(Type::boolean())));
|
||||||
|
$this->assertEquals(null, AST::astFromValue(null, Type::nonNull(Type::boolean()))); // Note: null means that AST cannot
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -70,7 +73,8 @@ class ASTFromValueTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals(new StringValue(['value' => 'VA\\nLUE']), AST::astFromValue("VA\nLUE", Type::string()));
|
$this->assertEquals(new StringValue(['value' => 'VA\\nLUE']), AST::astFromValue("VA\nLUE", Type::string()));
|
||||||
$this->assertEquals(new StringValue(['value' => '123']), AST::astFromValue(123, Type::string()));
|
$this->assertEquals(new StringValue(['value' => '123']), AST::astFromValue(123, Type::string()));
|
||||||
$this->assertEquals(new StringValue(['value' => 'false']), AST::astFromValue(false, Type::string()));
|
$this->assertEquals(new StringValue(['value' => 'false']), AST::astFromValue(false, Type::string()));
|
||||||
$this->assertEquals(null, AST::astFromValue(null, Type::string()));
|
$this->assertEquals(new NullValue([]), AST::astFromValue(null, Type::string()));
|
||||||
|
$this->assertEquals(null, AST::astFromValue(null, Type::nonNull(Type::string())));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -83,7 +87,16 @@ class ASTFromValueTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals(new StringValue(['value' => 'VA\\nLUE']), AST::astFromValue("VA\nLUE", Type::id()));
|
$this->assertEquals(new StringValue(['value' => 'VA\\nLUE']), AST::astFromValue("VA\nLUE", Type::id()));
|
||||||
$this->assertEquals(new IntValue(['value' => '123']), AST::astFromValue(123, Type::id()));
|
$this->assertEquals(new IntValue(['value' => '123']), AST::astFromValue(123, Type::id()));
|
||||||
$this->assertEquals(new StringValue(['value' => 'false']), AST::astFromValue(false, Type::id()));
|
$this->assertEquals(new StringValue(['value' => 'false']), AST::astFromValue(false, Type::id()));
|
||||||
$this->assertEquals(null, AST::astFromValue(null, Type::id()));
|
$this->assertEquals(new NullValue([]), AST::astFromValue(null, Type::id()));
|
||||||
|
$this->assertEquals(null, AST::astFromValue(null, Type::nonNull(Type::id())));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it does not converts NonNull values to NullValue
|
||||||
|
*/
|
||||||
|
public function testDoesNotConvertsNonNullValuestoNullValue()
|
||||||
|
{
|
||||||
|
$this->assertSame(null, AST::astFromValue(null, Type::nonNull(Type::boolean())));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -156,6 +169,44 @@ class ASTFromValueTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertEquals($expected, AST::astFromValue((object) $data, $inputObj));
|
$this->assertEquals($expected, AST::astFromValue((object) $data, $inputObj));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testConvertsInputObjectsWithExplicitNulls()
|
||||||
|
{
|
||||||
|
$inputObj = new InputObjectType([
|
||||||
|
'name' => 'MyInputObj',
|
||||||
|
'fields' => [
|
||||||
|
'foo' => Type::float(),
|
||||||
|
'bar' => $this->myEnum()
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
$this->assertEquals(new ObjectValue([
|
||||||
|
'fields' => [
|
||||||
|
$this->objectField('foo', new NullValue([]))
|
||||||
|
]
|
||||||
|
]), AST::astFromValue(['foo' => null], $inputObj));
|
||||||
|
/*
|
||||||
|
const inputObj = new GraphQLInputObjectType({
|
||||||
|
name: 'MyInputObj',
|
||||||
|
fields: {
|
||||||
|
foo: { type: GraphQLFloat },
|
||||||
|
bar: { type: myEnum },
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(astFromValue(
|
||||||
|
{ foo: null },
|
||||||
|
inputObj
|
||||||
|
)).to.deep.equal(
|
||||||
|
{ kind: 'ObjectValue',
|
||||||
|
fields: [
|
||||||
|
{ kind: 'ObjectField',
|
||||||
|
name: { kind: 'Name', value: 'foo' },
|
||||||
|
value: { kind: 'NullValue' } } ] }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
private $complexValue;
|
private $complexValue;
|
||||||
|
|
||||||
private function complexValue()
|
private function complexValue()
|
||||||
|
@ -132,6 +132,28 @@ class ArgumentsOfCorrectTypeTest extends TestCase
|
|||||||
');
|
');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it null into nullable type
|
||||||
|
*/
|
||||||
|
public function testNullIntoNullableType()
|
||||||
|
{
|
||||||
|
$this->expectPassesRule(new ArgumentsOfCorrectType(), '
|
||||||
|
{
|
||||||
|
complicatedArgs {
|
||||||
|
intArgField(intArg: null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
');
|
||||||
|
|
||||||
|
$this->expectPassesRule(new ArgumentsOfCorrectType(), '
|
||||||
|
{
|
||||||
|
dog(a: null, b: null, c:{ requiredField: true, intField: null }) {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
');
|
||||||
|
}
|
||||||
|
|
||||||
// Invalid String values
|
// Invalid String values
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -574,6 +596,20 @@ class ArgumentsOfCorrectTypeTest extends TestCase
|
|||||||
');
|
');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it Null value
|
||||||
|
*/
|
||||||
|
public function testNullValue()
|
||||||
|
{
|
||||||
|
$this->expectPassesRule(new ArgumentsOfCorrectType(), '
|
||||||
|
{
|
||||||
|
complicatedArgs {
|
||||||
|
stringListArgField(stringListArg: null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @it Single value into List
|
* @it Single value into List
|
||||||
*/
|
*/
|
||||||
@ -801,6 +837,24 @@ class ArgumentsOfCorrectTypeTest extends TestCase
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it Null value
|
||||||
|
*/
|
||||||
|
public function testNullValue2()
|
||||||
|
{
|
||||||
|
$this->expectFailsRule(new ArgumentsOfCorrectType(), '
|
||||||
|
{
|
||||||
|
complicatedArgs {
|
||||||
|
multipleReqs(req1: null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
', [
|
||||||
|
$this->badValue('req1', 'Int!', 'null', 4, 32, [
|
||||||
|
'Expected "Int!", found null.'
|
||||||
|
]),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Valid input object value
|
// Valid input object value
|
||||||
|
|
||||||
|
@ -50,6 +50,52 @@ class DefaultValuesOfCorrectTypeTest extends TestCase
|
|||||||
');
|
');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it variables with valid default null values
|
||||||
|
*/
|
||||||
|
public function testVariablesWithValidDefaultNullValues()
|
||||||
|
{
|
||||||
|
$this->expectPassesRule(new DefaultValuesOfCorrectType(), '
|
||||||
|
query WithDefaultValues(
|
||||||
|
$a: Int = null,
|
||||||
|
$b: String = null,
|
||||||
|
$c: ComplexInput = { requiredField: true, intField: null }
|
||||||
|
) {
|
||||||
|
dog { name }
|
||||||
|
}
|
||||||
|
');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @it variables with invalid default null values
|
||||||
|
*/
|
||||||
|
public function testVariablesWithInvalidDefaultNullValues()
|
||||||
|
{
|
||||||
|
$this->expectFailsRule(new DefaultValuesOfCorrectType(), '
|
||||||
|
query WithDefaultValues(
|
||||||
|
$a: Int! = null,
|
||||||
|
$b: String! = null,
|
||||||
|
$c: ComplexInput = { requiredField: null, intField: null }
|
||||||
|
) {
|
||||||
|
dog { name }
|
||||||
|
}
|
||||||
|
', [
|
||||||
|
$this->defaultForNonNullArg('a', 'Int!', 'Int', 3, 20),
|
||||||
|
$this->badValue('a', 'Int!', 'null', 3, 20, [
|
||||||
|
'Expected "Int!", found null.'
|
||||||
|
]),
|
||||||
|
$this->defaultForNonNullArg('b', 'String!', 'String', 4, 23),
|
||||||
|
$this->badValue('b', 'String!', 'null', 4, 23, [
|
||||||
|
'Expected "String!", found null.'
|
||||||
|
]),
|
||||||
|
$this->badValue('c', 'ComplexInput', '{requiredField: null, intField: null}',
|
||||||
|
5, 28, [
|
||||||
|
'In field "requiredField": Expected "Boolean!", found null.'
|
||||||
|
]
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @it no required variables with default values
|
* @it no required variables with default values
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user