From b671bfb1c7ebcc4ff1cd423ec6c0e9bc2e71da03 Mon Sep 17 00:00:00 2001 From: Jake Barnby Date: Wed, 21 Jan 2026 18:55:20 +1300 Subject: [PATCH] Fix Swoole adapter all() to work directly with GQLPromise objects Instead of extracting adopted promises and delegating to SwoolePromise::all(), implement the batch handling logic directly to properly work with GQLPromise wrappers. Uses Swoole Channel for synchronization. Co-Authored-By: Claude Opus 4.5 --- .../GraphQL/Promises/Adapter/Swoole.php | 58 ++++++++++++++++--- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/src/Appwrite/GraphQL/Promises/Adapter/Swoole.php b/src/Appwrite/GraphQL/Promises/Adapter/Swoole.php index b8a6a1151b..eff7a3b51b 100644 --- a/src/Appwrite/GraphQL/Promises/Adapter/Swoole.php +++ b/src/Appwrite/GraphQL/Promises/Adapter/Swoole.php @@ -5,6 +5,7 @@ namespace Appwrite\GraphQL\Promises\Adapter; use Appwrite\GraphQL\Promises\Adapter; use Appwrite\Promises\Swoole as SwoolePromise; use GraphQL\Executor\Promise\Promise as GQLPromise; +use Swoole\Coroutine\Channel; class Swoole extends Adapter { @@ -37,14 +38,55 @@ class Swoole extends Adapter public function all(iterable $promisesOrValues): GQLPromise { - $swoolePromises = []; - foreach ($promisesOrValues as $promise) { - if ($promise instanceof GQLPromise) { - $swoolePromises[] = $promise->adoptedPromise; - } else { - $swoolePromises[] = $promise; + $promisesOrValues = \is_array($promisesOrValues) ? $promisesOrValues : \iterator_to_array($promisesOrValues); + + return $this->create(function (callable $resolve, callable $reject) use ($promisesOrValues) { + $total = \count($promisesOrValues); + if ($total === 0) { + $resolve([]); + return; } - } - return new GQLPromise(SwoolePromise::all($swoolePromises), $this); + + $result = []; + $completed = 0; + $rejected = false; + $channel = new Channel($total); + + foreach ($promisesOrValues as $index => $promiseOrValue) { + if ($promiseOrValue instanceof GQLPromise) { + $result[$index] = null; + $promiseOrValue->then( + function ($value) use ($index, &$result, &$completed, $channel) { + $result[$index] = $value; + $completed++; + $channel->push(true); + return $value; + }, + function ($error) use (&$rejected, $channel, $reject) { + if (!$rejected) { + $rejected = true; + $reject($error); + } + $channel->push(false); + } + ); + } else { + $result[$index] = $promiseOrValue; + $completed++; + $channel->push(true); + } + } + + // Wait for all promises to complete + for ($i = 0; $i < $total; $i++) { + $channel->pop(); + } + $channel->close(); + + if (!$rejected) { + \ksort($result); + $resolve($result); + } + }); } }