Merged branch 0.13.x into master

This commit is contained in:
Vladimir Razuvaev 2019-06-12 15:45:44 +07:00
commit acc0442152
5 changed files with 87 additions and 8 deletions

View File

@ -3,6 +3,24 @@
## Unreleased ## Unreleased
- Add schema validation: Input Objects must not contain non-nullable circular references (#492) - Add schema validation: Input Objects must not contain non-nullable circular references (#492)
#### v0.13.5
- Fix coroutine executor when using with promise (#486)
#### v0.13.4
- Force int when setting max query depth (#477)
#### v0.13.3
- Reverted minor possible breaking change (#476)
#### v0.13.2
- Added QueryPlan support (#436)
- Fixed an issue with NodeList iteration over missing keys (#475)
#### v0.13.1
- Better validation of field/directive arguments
- Support for apollo client/server persisted queries
- Minor tweaks and fixes
## v0.13.0 ## v0.13.0
This release brings several breaking changes. Please refer to [UPGRADE](UPGRADE.md) document for details. This release brings several breaking changes. Please refer to [UPGRADE](UPGRADE.md) document for details.

View File

@ -44,8 +44,8 @@ existing PHP frameworks, add support for Relay, etc.
## Current Status ## Current Status
The first version of this library (v0.1) was released on August 10th 2015. The first version of this library (v0.1) was released on August 10th 2015.
The current version (v0.10) supports all features described by GraphQL specification The current version supports all features described by GraphQL specification
(including April 2016 add-ons) as well as some experimental features like as well as some experimental features like
[Schema Language parser](type-system/type-language.md) and [Schema Language parser](type-system/type-language.md) and
[Schema printer](reference.md#graphqlutilsschemaprinter). [Schema printer](reference.md#graphqlutilsschemaprinter).

View File

@ -293,13 +293,17 @@ class CoroutineExecutor implements Runtime, ExecutorImplementation
$strand->stack[$strand->depth++] = $strand->current; $strand->stack[$strand->depth++] = $strand->current;
$strand->current = $value; $strand->current = $value;
goto START; goto START;
} elseif ($this->promiseAdapter->isThenable($value)) { } elseif ($this->isPromise($value)) {
// !!! increment pending before calling ->then() as it may invoke the callback right away // !!! increment pending before calling ->then() as it may invoke the callback right away
++$this->pending; ++$this->pending;
if (! $value instanceof Promise) {
$value = $this->promiseAdapter->convertThenable($value);
}
$this->promiseAdapter $this->promiseAdapter
->convertThenable($value)
->then( ->then(
$value,
function ($value) use ($strand) { function ($value) use ($strand) {
$strand->success = true; $strand->success = true;
$strand->value = $value; $strand->value = $value;
@ -478,7 +482,7 @@ class CoroutineExecutor implements Runtime, ExecutorImplementation
private function completeValueFast(CoroutineContext $ctx, Type $type, $value, array $path, &$returnValue) : bool private function completeValueFast(CoroutineContext $ctx, Type $type, $value, array $path, &$returnValue) : bool
{ {
// special handling of Throwable inherited from JS reference implementation, but makes no sense in this PHP // special handling of Throwable inherited from JS reference implementation, but makes no sense in this PHP
if ($this->promiseAdapter->isThenable($value) || $value instanceof Throwable) { if ($this->isPromise($value) || $value instanceof Throwable) {
return false; return false;
} }
@ -574,7 +578,7 @@ class CoroutineExecutor implements Runtime, ExecutorImplementation
// !!! $value might be promise, yield to resolve // !!! $value might be promise, yield to resolve
try { try {
if ($this->promiseAdapter->isThenable($value)) { if ($this->isPromise($value)) {
$value = yield $value; $value = yield $value;
} }
} catch (Throwable $reason) { } catch (Throwable $reason) {
@ -931,4 +935,14 @@ class CoroutineExecutor implements Runtime, ExecutorImplementation
return $selectedType; return $selectedType;
} }
/**
* @param mixed $value
*
* @return bool
*/
private function isPromise($value)
{
return $value instanceof Promise || $this->promiseAdapter->isThenable($value);
}
} }

View File

@ -99,11 +99,11 @@ class QueryDepth extends QuerySecurityRule
/** /**
* Set max query depth. If equal to 0 no check is done. Must be greater or equal to 0. * Set max query depth. If equal to 0 no check is done. Must be greater or equal to 0.
*/ */
public function setMaxQueryDepth(int $maxQueryDepth) public function setMaxQueryDepth($maxQueryDepth)
{ {
$this->checkIfGreaterOrEqualToZero('maxQueryDepth', $maxQueryDepth); $this->checkIfGreaterOrEqualToZero('maxQueryDepth', $maxQueryDepth);
$this->maxQueryDepth = $maxQueryDepth; $this->maxQueryDepth = (int) $maxQueryDepth;
} }
public static function maxQueryDepthErrorMessage($max, $count) public static function maxQueryDepthErrorMessage($max, $count)

47
tests/GraphQLTest.php Normal file
View File

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace GraphQL\Tests;
use GraphQL\Executor\Promise\Adapter\SyncPromiseAdapter;
use GraphQL\GraphQL;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;
use PHPUnit\Framework\TestCase;
use function sprintf;
class GraphQLTest extends TestCase
{
public function testPromiseToExecute() : void
{
$promiseAdapter = new SyncPromiseAdapter();
$schema = new Schema(
[
'query' => new ObjectType(
[
'name' => 'Query',
'fields' => [
'sayHi' => [
'type' => Type::nonNull(Type::string()),
'args' => [
'name' => [
'type' => Type::nonNull(Type::string()),
],
],
'resolve' => static function ($value, $args) use ($promiseAdapter) {
return $promiseAdapter->createFulfilled(sprintf('Hi %s!', $args['name']));
},
],
],
]
),
]
);
$promise = GraphQL::promiseToExecute($promiseAdapter, $schema, '{ sayHi(name: "John") }');
$result = $promiseAdapter->wait($promise);
self::assertSame(['data' => ['sayHi' => 'Hi John!']], $result->toArray());
}
}