Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generics for Promise. #1170

Closed
wants to merge 39 commits into from
Closed
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
32b4f1d
Add generics
Warxcell Nov 29, 2022
0b65301
Apply php-cs-fixer changes
Warxcell Nov 29, 2022
d15eea5
Update src/Executor/Promise/Promise.php
Warxcell Nov 29, 2022
d5fa644
Add generics
Warxcell Nov 30, 2022
77b7e84
Prettify docs
Warxcell Nov 30, 2022
2b6c898
Add generics
Warxcell Nov 30, 2022
1121827
Apply php-cs-fixer changes
Warxcell Nov 30, 2022
abd57fe
Add generics
Warxcell Nov 30, 2022
032ed9f
Prettify docs
Warxcell Nov 30, 2022
9c9323b
Add generics
Warxcell Nov 30, 2022
9e26ed2
Prettify docs
Warxcell Nov 30, 2022
ca0812a
Add generics
Warxcell Dec 2, 2022
78a442f
Apply php-cs-fixer changes
Warxcell Dec 2, 2022
f0f32c5
Update src/Executor/Promise/PromiseAdapter.php
Warxcell Dec 14, 2022
7aa1041
Prettify docs
Warxcell Dec 14, 2022
923bfc8
Update src/Executor/Promise/Adapter/SyncPromiseAdapter.php
Warxcell Dec 14, 2022
85e0377
Add generics
Warxcell Dec 14, 2022
dddbb7f
Prettify docs
Warxcell Dec 14, 2022
af10463
Add generics
Warxcell Dec 14, 2022
1b31ae6
Apply php-cs-fixer changes
Warxcell Dec 14, 2022
b560281
Add generics
Warxcell Dec 14, 2022
4e03770
Prettify docs
Warxcell Dec 14, 2022
9e2f954
Add generics
Warxcell Dec 14, 2022
d8f5830
Apply php-cs-fixer changes
Warxcell Dec 14, 2022
70e342b
Merge branch 'master' into generics-for-promise
spawnia Dec 19, 2022
61561a3
restore iterable interface
spawnia Dec 19, 2022
820d73c
improve ReactPromiseAdapterTest.php
spawnia Dec 19, 2022
506834b
minimize diff in SyncPromise
spawnia Dec 19, 2022
0f34cf3
improve phpdoc in PromiseAdapter.php
spawnia Dec 19, 2022
50a6a8f
improve whitespace in Helper.php
spawnia Dec 19, 2022
5382360
Merge branch 'master' into generics-for-promise
spawnia Dec 19, 2022
2a1e365
fully qualified throwable
spawnia Dec 19, 2022
d796e4a
Prettify docs
spawnia Dec 19, 2022
c7fdf5c
remove unnecessary generic
spawnia Dec 19, 2022
1b42a7b
Merge remote-tracking branch 'upstream/master'
Warxcell Dec 19, 2022
a6212de
Add generics
Warxcell Dec 20, 2022
fecb03e
Apply php-cs-fixer changes
Warxcell Dec 20, 2022
531e03b
...
Warxcell Jan 4, 2023
56796ea
Apply php-cs-fixer changes
Warxcell Jan 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 38 additions & 11 deletions docs/class-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ static function executeQuery(
* @param mixed $context
* @param array<string, mixed>|null $variableValues
* @param array<ValidationRule>|null $validationRules
* @return Promise<ExecutionResult>
*
* @api
*/
Expand Down Expand Up @@ -1305,6 +1306,8 @@ static function execute(
* @param mixed $contextValue
* @param array<string, mixed>|null $variableValues
*
* @return Promise<ExecutionResult>
*
* @phpstan-param FieldResolver|null $fieldResolver
*
* @api
Expand Down Expand Up @@ -1471,6 +1474,20 @@ function convertThenable($thenable): GraphQL\Executor\Promise\Promise
* Accepts our Promise wrapper, extracts adopted promise out of it and executes actual `then` logic described
* in Promises/A+ specs. Then returns new wrapped instance of GraphQL\Executor\Promise\Promise.
*
* @template T
* @template TFulfilled of mixed
* @template TRejected of mixed
*
* @param Promise<T> $promise
* @param (callable(T): (Promise<TFulfilled>|TFulfilled))|null $onFulfilled
* @param (callable(mixed): (Promise<TRejected>|TRejected))|null $onRejected
*
* @return Promise<(
* $onFulfilled is not null
* ? ($onRejected is not null ? TFulfilled|TRejected : TFulfilled)
* : ($onRejected is not null ? TRejected : T)
* )>
*
* @api
*/
function then(
Expand All @@ -1484,7 +1501,9 @@ function then(
/**
* Creates a Promise from the given resolver callable.
*
* @param callable(callable $resolve, callable $reject): void $resolver
* @template V
* @param callable(callable(V): void $resolve, callable(\Throwable): void $reject): void $resolver
* @return Promise<V>
*
* @api
*/
Expand All @@ -1495,7 +1514,11 @@ function create(callable $resolver): GraphQL\Executor\Promise\Promise
/**
* Creates a fulfilled Promise for a value if the value is not a promise.
*
* @param mixed $value
* @template V
*
* @param V $value
*
* @return Promise<V>
*
* @api
*/
Expand All @@ -1518,7 +1541,11 @@ function createRejected(Throwable $reason): GraphQL\Executor\Promise\Promise
* Given an iterable of promises (or values), returns a promise that is fulfilled when all the
* items in the iterable are fulfilled.
*
* @param iterable<Promise|mixed> $promisesOrValues
* @template V
*
* @param iterable<Promise<V>|V> $promisesOrValues
*
* @return Promise<V[]>
*
* @api
*/
Expand Down Expand Up @@ -1876,7 +1903,7 @@ function handleRequest($parsedBody = null): void
*
* @param OperationParams|array<OperationParams> $parsedBody
*
* @return ExecutionResult|array<int, ExecutionResult>|Promise
* @return ExecutionResult|array<ExecutionResult>|Promise<ExecutionResult>|Promise<array<ExecutionResult>>
*
* @api
*/
Expand All @@ -1890,7 +1917,7 @@ function executeRequest($parsedBody = null)
* See `executePsrRequest()` if you prefer to create response yourself
* (e.g. using specific JsonResponse instance of some framework).
*
* @return ResponseInterface|Promise
* @return ResponseInterface|Promise<ResponseInterface>
*
* @api
*/
Expand All @@ -1906,7 +1933,7 @@ function processPsrRequest(
* Executes GraphQL operation and returns execution result
* (or promise when promise adapter is different from SyncPromiseAdapter).
*
* @return ExecutionResult|array<int, ExecutionResult>|Promise
* @return ExecutionResult|array<ExecutionResult>|Promise<ExecutionResult>|Promise<array<ExecutionResult>>
*
* @api
*/
Expand Down Expand Up @@ -2118,7 +2145,7 @@ function validateOperationParams(GraphQL\Server\OperationParams $params): array
* Executes GraphQL operation with given server configuration and returns execution result
* (or promise when promise adapter is different from SyncPromiseAdapter).
*
* @return ExecutionResult|Promise
* @return ExecutionResult|Promise<ExecutionResult>
*
* @api
*/
Expand All @@ -2132,7 +2159,7 @@ function executeOperation(GraphQL\Server\ServerConfig $config, GraphQL\Server\Op
*
* @param array<OperationParams> $operations
*
* @return array<int, ExecutionResult>|Promise
* @return array<ExecutionResult>|Promise<array<ExecutionResult>>
*
* @api
*/
Expand All @@ -2143,7 +2170,7 @@ function executeBatch(GraphQL\Server\ServerConfig $config, array $operations)
/**
* Send response using standard PHP `header()` and `echo`.
*
* @param Promise|ExecutionResult|array<ExecutionResult> $result
* @param Promise<ExecutionResult>|Promise<array<ExecutionResult>>|ExecutionResult|array<ExecutionResult> $result
*
* @api
*/
Expand All @@ -2167,9 +2194,9 @@ function parsePsrRequest(Psr\Http\Message\RequestInterface $request)
/**
* Converts query execution result to PSR-7 response.
*
* @param Promise|ExecutionResult|array<ExecutionResult> $result
* @param Promise<ExecutionResult>|Promise<array<ExecutionResult>>|ExecutionResult|array<ExecutionResult> $result
*
* @return Promise|ResponseInterface
* @return Promise<ResponseInterface>|ResponseInterface
*
* @api
*/
Expand Down
2 changes: 2 additions & 0 deletions src/Executor/Executor.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ public static function execute(
* @param mixed $contextValue
* @param array<string, mixed>|null $variableValues
*
* @return Promise<ExecutionResult>
*
* @phpstan-param FieldResolver|null $fieldResolver
*
* @api
Expand Down
2 changes: 2 additions & 0 deletions src/Executor/ExecutorImplementation.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ interface ExecutorImplementation
{
/**
* Returns promise of {@link ExecutionResult}. Promise should always resolve, never reject.
*
* @return Promise<ExecutionResult>
*/
public function doExecute(): Promise;
}
52 changes: 51 additions & 1 deletion src/Executor/Promise/Adapter/SyncPromiseAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,21 @@ public function convertThenable($thenable): Promise
return new Promise($thenable, $this);
}

/**
* @template T
* @template TFulfilled of mixed
* @template TRejected of mixed
*
* @param Promise<T> $promise
* @param (callable(T): (Promise<TFulfilled>|TFulfilled))|null $onFulfilled
* @param (callable(mixed): (Promise<TRejected>|TRejected))|null $onRejected
*
* @return Promise<(
* $onFulfilled is not null
* ? ($onRejected is not null ? TFulfilled|TRejected : TFulfilled)
* : ($onRejected is not null ? TRejected : T)
* )>
*/
public function then(Promise $promise, ?callable $onFulfilled = null, ?callable $onRejected = null): Promise
{
$adoptedPromise = $promise->adoptedPromise;
Expand All @@ -55,20 +70,41 @@ public function create(callable $resolver): Promise
return new Promise($promise, $this);
}

/**
* @template V
*
* @param V $value
*
* @return Promise<V>
*/
public function createFulfilled($value = null): Promise
{
$promise = new SyncPromise();

return new Promise($promise->resolve($value), $this);
}

/**
* @template V of \Throwable
*
* @param V $reason
*
* @return Promise<V>
*/
public function createRejected(\Throwable $reason): Promise
{
$promise = new SyncPromise();

return new Promise($promise->reject($reason), $this);
}

/**
* @template V
*
* @param iterable<Promise<V>|V> $promisesOrValues
*
* @return Promise<V[]>
*/
public function all(iterable $promisesOrValues): Promise
{
\assert(
Expand Down Expand Up @@ -113,7 +149,13 @@ static function ($value) use ($index, &$count, $total, &$result, $all): void {
/**
* Synchronously wait when promise completes.
*
* @return mixed
* @template V
*
* @param Promise<V> $promise
*
* @throws InvariantViolation
*
* @return V
*/
public function wait(Promise $promise)
{
Expand Down Expand Up @@ -144,13 +186,21 @@ public function wait(Promise $promise)

/**
* Execute just before starting to run promise completion.
*
* @template V
*
* @param Promise<V> $promise
Warxcell marked this conversation as resolved.
Show resolved Hide resolved
*/
protected function beforeWait(Promise $promise): void
{
}

/**
* Execute while running promise completion.
*
* @template V
*
* @param Promise<V> $promise
*/
protected function onWait(Promise $promise): void
{
Expand Down
15 changes: 15 additions & 0 deletions src/Executor/Promise/Promise.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

/**
* Convenience wrapper for promises represented by Promise Adapter.
*
* @template T
Warxcell marked this conversation as resolved.
Show resolved Hide resolved
*/
class Promise
{
Expand All @@ -30,6 +32,19 @@ public function __construct($adoptedPromise, PromiseAdapter $adapter)
$this->adapter = $adapter;
}

/**
* @template TFulfilled
* @template TRejected
*
* @param (callable(T): (Promise<TFulfilled>|TFulfilled))|null $onFulfilled
* @param (callable(mixed): (Promise<TRejected>|TRejected))|null $onRejected
*
* @return Promise<(
* $onFulfilled is not null
* ? ($onRejected is not null ? TFulfilled|TRejected : TFulfilled)
* : ($onRejected is not null ? TRejected : T)
* )>
*/
public function then(?callable $onFulfilled = null, ?callable $onRejected = null): Promise
{
return $this->adapter->then($this, $onFulfilled, $onRejected);
Expand Down
32 changes: 29 additions & 3 deletions src/Executor/Promise/PromiseAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,32 @@ public function convertThenable($thenable): Promise;
* Accepts our Promise wrapper, extracts adopted promise out of it and executes actual `then` logic described
* in Promises/A+ specs. Then returns new wrapped instance of GraphQL\Executor\Promise\Promise.
*
* @template T
* @template TFulfilled of mixed
* @template TRejected of mixed
*
* @param Promise<T> $promise
* @param (callable(T): (Promise<TFulfilled>|TFulfilled))|null $onFulfilled
* @param (callable(mixed): (Promise<TRejected>|TRejected))|null $onRejected
*
* @return Promise<(
* $onFulfilled is not null
* ? ($onRejected is not null ? TFulfilled|TRejected : TFulfilled)
* : ($onRejected is not null ? TRejected : T)
* )>
*
* @api
*/
public function then(Promise $promise, ?callable $onFulfilled = null, ?callable $onRejected = null): Promise;

/**
* Creates a Promise from the given resolver callable.
*
* @param callable(callable $resolve, callable $reject): void $resolver
* @template V
*
* @param callable(callable(V): void $resolve, callable(\Throwable): void $reject): void $resolver
*
* @return Promise<V>
*
* @api
*/
Expand All @@ -45,7 +63,11 @@ public function create(callable $resolver): Promise;
/**
* Creates a fulfilled Promise for a value if the value is not a promise.
*
* @param mixed $value
* @template V
*
* @param V $value
*
* @return Promise<V>
*
* @api
*/
Expand All @@ -64,7 +86,11 @@ public function createRejected(\Throwable $reason): Promise;
* Given an iterable of promises (or values), returns a promise that is fulfilled when all the
* items in the iterable are fulfilled.
*
* @param iterable<Promise|mixed> $promisesOrValues
* @template V
*
* @param iterable<Promise<V>|V> $promisesOrValues
*
* @return Promise<V[]>
Warxcell marked this conversation as resolved.
Show resolved Hide resolved
*
* @api
*/
Expand Down
Loading