mirror of
https://github.com/retailcrm/graphql-php.git
synced 2024-11-22 04:46:04 +03:00
Merge pull request #486 from mcg-web/fix-coroutine-when-using-promise
Fix coroutine executor when using with promise
This commit is contained in:
commit
bd02ccd47e
@ -293,13 +293,17 @@ class CoroutineExecutor implements Runtime, ExecutorImplementation
|
||||
$strand->stack[$strand->depth++] = $strand->current;
|
||||
$strand->current = $value;
|
||||
goto START;
|
||||
} elseif ($this->promiseAdapter->isThenable($value)) {
|
||||
} elseif ($this->isPromise($value)) {
|
||||
// !!! increment pending before calling ->then() as it may invoke the callback right away
|
||||
++$this->pending;
|
||||
|
||||
if (! $value instanceof Promise) {
|
||||
$value = $this->promiseAdapter->convertThenable($value);
|
||||
}
|
||||
|
||||
$this->promiseAdapter
|
||||
->convertThenable($value)
|
||||
->then(
|
||||
$value,
|
||||
function ($value) use ($strand) {
|
||||
$strand->success = true;
|
||||
$strand->value = $value;
|
||||
@ -478,7 +482,7 @@ class CoroutineExecutor implements Runtime, ExecutorImplementation
|
||||
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
|
||||
if ($this->promiseAdapter->isThenable($value) || $value instanceof Throwable) {
|
||||
if ($this->isPromise($value) || $value instanceof Throwable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -574,7 +578,7 @@ class CoroutineExecutor implements Runtime, ExecutorImplementation
|
||||
|
||||
// !!! $value might be promise, yield to resolve
|
||||
try {
|
||||
if ($this->promiseAdapter->isThenable($value)) {
|
||||
if ($this->isPromise($value)) {
|
||||
$value = yield $value;
|
||||
}
|
||||
} catch (Throwable $reason) {
|
||||
@ -931,4 +935,14 @@ class CoroutineExecutor implements Runtime, ExecutorImplementation
|
||||
|
||||
return $selectedType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isPromise($value)
|
||||
{
|
||||
return $value instanceof Promise || $this->promiseAdapter->isThenable($value);
|
||||
}
|
||||
}
|
||||
|
47
tests/GraphQLTest.php
Normal file
47
tests/GraphQLTest.php
Normal 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());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user