Skip to content

Commit

Permalink
Add client for ReactPHP Redis
Browse files Browse the repository at this point in the history
  • Loading branch information
MacFJA committed Oct 21, 2022
1 parent 837bf52 commit a8c55d4
Show file tree
Hide file tree
Showing 14 changed files with 142 additions and 66 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add client for ReactPHP Redis
- Path validation for JSON fields
- Helper function get current RedisJSON version + (abstraction)
- (dev) More unit tests
Expand Down
2 changes: 2 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"ext-mbstring": "*",
"amphp/redis": "^1.0",
"cheprasov/php-redis-client": "^1.10",
"clue/redis-react": "^2.6",
"colinmollenhour/credis": "^1.12",
"enlightn/security-checker": "^1.9",
"ergebnis/composer-normalize": "^2.13",
Expand All @@ -42,6 +43,7 @@
"phpunit/phpunit": "^8.5 || ^9.3",
"predis/predis": "^1.1 || ^2.0",
"ptrofimov/tinyredisclient": "^1.1",
"react/async": "^3.0",
"redisent/redisent": "dev-master",
"roave/security-advisories": "dev-latest",
"rskuipers/php-assumptions": "^0.8.0",
Expand Down
12 changes: 12 additions & 0 deletions src/Redis/Client/AbstractClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,18 @@ public function pipeline(Command ...$commands): array
}, $results, array_keys($results));
}

public function execute(Command $command)
{
$args = [$command->getId()];
$commandArgs = $command->getArguments();
if (count($commandArgs) > 0) {
array_push($args, ...$commandArgs);
}
$result = $this->executeRaw(...$args);

return $command->parseResponse($result);
}

/**
* @return array<mixed>
*/
Expand Down
12 changes: 3 additions & 9 deletions src/Redis/Client/AmpRedisClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,6 @@ public static function make($redis): Client
return new self($redis);
}

public function execute(Command $command)
{
/** @var Promise<mixed> $query */
$query = $this->redis->query($command->getId(), ...array_map('strval', $command->getArguments()));
$result = wait($query);

return $command->parseResponse($result);
}

public function executeRaw(...$args)
{
/** @var Promise<mixed> $query */
Expand All @@ -77,6 +68,9 @@ public static function supports($redis): bool
&& function_exists('\\Amp\\Promise\\wait');
}

/**
* @codeCoverageIgnore
*/
public function pipeline(Command ...$commands): array
{
false === static::$disableNotice
Expand Down
7 changes: 0 additions & 7 deletions src/Redis/Client/CheprasovRedisClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,6 @@ public static function make($redis): Client
return new self($redis);
}

public function execute(Command $command)
{
$response = $this->redis->executeRaw(array_merge([$command->getId()], $command->getArguments()));

return $command->parseResponse($response);
}

public function executeRaw(...$args)
{
return $this->redis->executeRaw(array_map('strval', $args));
Expand Down
5 changes: 4 additions & 1 deletion src/Redis/Client/ClientFacade.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@
namespace MacFJA\RediSearch\Redis\Client;

use Amp\Redis\Redis as AmpRedis;
use Clue\React\Redis\Client as ReactClient;
use Credis_Client as CredisRedis;
use MacFJA\RediSearch\Redis\Client;
use Predis\ClientInterface as PredisRedis;
use React\Promise\Promise as ReactPromise;
use Redis as PhpredisRedis;
use RedisClient\Client\AbstractRedisClient as CheprasovRedis;
use redisent\Redis as RedisentRedis;
Expand All @@ -44,10 +46,11 @@ class ClientFacade
RediskaClient::class,
AmpRedisClient::class,
TinyRedisClient::class,
ReactRedisClient::class,
];

/**
* @param AmpRedis|CheprasovRedis|CredisRedis|mixed|PhpredisRedis|PredisRedis|RedisentRedis|RediskaRedis|resource $redis
* @param AmpRedis|CheprasovRedis|CredisRedis|mixed|PhpredisRedis|PredisRedis|ReactClient|ReactPromise|RedisentRedis|RediskaRedis|resource $redis
*/
public function getClient($redis): Client
{
Expand Down
7 changes: 0 additions & 7 deletions src/Redis/Client/CredisClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,6 @@ public static function make($redis): Client
return new self($redis);
}

public function execute(Command $command)
{
$result = $this->redis->__call($command->getId(), $command->getArguments());

return $command->parseResponse($this->fixFalseToNull($result));
}

public function executeRaw(...$args)
{
$command = array_shift($args);
Expand Down
7 changes: 0 additions & 7 deletions src/Redis/Client/PhpiredisClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,6 @@ private function __construct($redis)
$this->redis = $redis;
}

public function execute(Command $command)
{
$rawResponse = phpiredis_command_bs($this->redis, array_merge([$command->getId()], $command->getArguments()));

return $command->parseResponse($rawResponse);
}

public static function supports($redis): bool
{
if (!is_resource($redis)
Expand Down
7 changes: 0 additions & 7 deletions src/Redis/Client/PredisClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,6 @@ private function __construct(ClientInterface $redis)
$this->redis = $redis;
}

public function execute(Command $command)
{
$rawResponse = $this->redis->executeCommand(self::createRawCommand(array_merge([$command->getId()], $command->getArguments())));

return $command->parseResponse($rawResponse);
}

public static function supports($redis): bool
{
if (
Expand Down
102 changes: 102 additions & 0 deletions src/Redis/Client/ReactRedisClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

declare(strict_types=1);

/*
* Copyright MacFJA
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

namespace MacFJA\RediSearch\Redis\Client;

use function function_exists;
use function React\Async\await;

use Clue\React\Redis\Client;
use MacFJA\RediSearch\Redis\Command;
use React\Promise\Promise;
use React\Promise\PromiseInterface;
use RuntimeException;

class ReactRedisClient extends AbstractClient
{
/**
* @var Client
*/
private $redis;

/**
* @codeCoverageIgnore
*
* @param mixed $redis
*/
private function __construct($redis)
{
if (!static::supports($redis)) {
throw new RuntimeException($this->getMissingMessage('Clue Redis React and/or React\\Async', false, [
Client::class => [],
PromiseInterface::class => [],
], ['\React\Async\await']));
}
if ($redis instanceof Promise) {
$realRedis = await($redis);
if (!$realRedis instanceof Client) {
throw new RuntimeException('The provided $redis parameter is not a valid Redis client');
}
$this->redis = $realRedis;

return;
}
$this->redis = $redis;
}

/**
* @codeCoverageIgnore
*/
public function pipeline(Command ...$commands): array
{
false === static::$disableNotice
&& trigger_error('Warning, Clue\\React\\Redis\\Client don\'t use a real Redis Pipeline', E_USER_NOTICE);

return array_map(function (Command $command) {
return $this->execute($command);
}, $commands);
}

public static function make($redis): \MacFJA\RediSearch\Redis\Client
{
return new self($redis);
}

public function executeRaw(...$args)
{
$command = array_shift($args);

return await($this->redis->__call((string) $command, array_map('strval', $args)));
}

public static function supports($redis): bool
{
return ($redis instanceof Client || $redis instanceof PromiseInterface) && function_exists('\React\Async\await');
}

/**
* @codeCoverageIgnore
*/
protected function doPipeline(Command ...$commands): array
{
return [];
}
}
7 changes: 0 additions & 7 deletions src/Redis/Client/RedisentClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,6 @@ public static function make($redis): Client
return new self($redis);
}

public function execute(Command $command)
{
$result = $this->redis->__call($command->getId(), $command->getArguments());

return $command->parseResponse($result);
}

public function executeRaw(...$args)
{
$command = array_shift($args);
Expand Down
7 changes: 0 additions & 7 deletions src/Redis/Client/TinyRedisClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,6 @@ public function pipeline(Command ...$commands): array
}, $commands);
}

public function execute(Command $command)
{
$result = $this->redis->__call($command->getId(), $command->getArguments());

return $command->parseResponse($result);
}

public function executeRaw(...$args)
{
$command = array_shift($args);
Expand Down
1 change: 1 addition & 0 deletions tests/Redis/Client/ClientFacadeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
* @uses \MacFJA\RediSearch\Redis\Client\RediskaClient
* @uses \MacFJA\RediSearch\Redis\Client\CredisClient
* @uses \MacFJA\RediSearch\Redis\Client\TinyRedisClient
* @uses \MacFJA\RediSearch\Redis\Client\ReactRedisClient
*
* @internal
*/
Expand Down
31 changes: 17 additions & 14 deletions tests/integration/DockerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
* @covers \MacFJA\RediSearch\Redis\Client\ClientFacade
* @covers \MacFJA\RediSearch\Redis\Client\CredisClient
* @covers \MacFJA\RediSearch\Redis\Client\PredisClient
* @covers \MacFJA\RediSearch\Redis\Client\ReactRedisClient
* @covers \MacFJA\RediSearch\Redis\Client\RedisentClient
* @covers \MacFJA\RediSearch\Redis\Client\RediskaClient
* @covers \MacFJA\RediSearch\Redis\Client\TinyRedisClient
Expand Down Expand Up @@ -277,24 +278,26 @@ public function dataProvider(string $testName): array
{
if (in_array($testName, ['testIntegration', 'testAddDocument'])) {
return [
[static function () { return Client\PredisClient::make(new \Predis\Client(['scheme' => 'tcp', 'host' => 'localhost', 'port' => '16379', 'db' => 0])); }],
[static function () { return Client\RediskaClient::make(new Rediska(['servers' => [['host' => 'localhost', 'port' => '16379', 'db' => 0]]])); }],
[static function () { return Client\RedisentClient::make(new \redisent\Redis('redis://localhost:16379')); }],
[static function () { return Client\CheprasovRedisClient::make(new \RedisClient\Client\Version\RedisClient6x0(['server' => 'localhost:16379', 'database' => 0])); }],
[static function () { return Client\AmpRedisClient::make(new \Amp\Redis\Redis(new RemoteExecutor(Config::fromUri('redis://localhost:16379')))); }],
[static function () { return Client\TinyRedisClient::make(new TinyRedisClient('localhost:16379')); }],
[static function () { return Client\CredisClient::make(new Credis_Client('localhost', 16379, null, '', 0)); }],
'Predis' => [static function () { return Client\PredisClient::make(new \Predis\Client(['scheme' => 'tcp', 'host' => 'localhost', 'port' => '16379', 'db' => 0])); }],
'Rediska' => [static function () { return Client\RediskaClient::make(new Rediska(['servers' => [['host' => 'localhost', 'port' => '16379', 'db' => 0]]])); }],
'Redisent' => [static function () { return Client\RedisentClient::make(new \redisent\Redis('redis://localhost:16379')); }],
'CheprasovRedis' => [static function () { return Client\CheprasovRedisClient::make(new \RedisClient\Client\Version\RedisClient6x0(['server' => 'localhost:16379', 'database' => 0])); }],
'AmpRedis' => [static function () { return Client\AmpRedisClient::make(new \Amp\Redis\Redis(new RemoteExecutor(Config::fromUri('redis://localhost:16379')))); }],
'TinyRedis' => [static function () { return Client\TinyRedisClient::make(new TinyRedisClient('localhost:16379')); }],
'Credis' => [static function () { return Client\CredisClient::make(new Credis_Client('localhost', 16379, null, '', 0)); }],
'ReactRedis' => [static function () { return Client\ReactRedisClient::make((new \Clue\React\Redis\Factory())->createClient('localhost:16379')); }],
];
}

return [
[Client\PredisClient::class, static function () { return new \Predis\Client(['scheme' => 'tcp', 'host' => 'localhost', 'port' => '16379', 'db' => 0]); }],
[Client\RediskaClient::class, static function () { return new Rediska(['servers' => [['host' => 'localhost', 'port' => '16379', 'db' => 0]]]); }],
[Client\RedisentClient::class, static function () { return new \redisent\Redis('redis://localhost:16379'); }],
[Client\CheprasovRedisClient::class, static function () { return new \RedisClient\Client\Version\RedisClient6x0(['server' => 'localhost:16379', 'database' => 0]); }],
[Client\AmpRedisClient::class, static function () { return new \Amp\Redis\Redis(new RemoteExecutor(Config::fromUri('redis://localhost:16379'))); }],
[Client\TinyRedisClient::class, static function () { return new TinyRedisClient('localhost:16379'); }],
[Client\CredisClient::class, static function () { return new Credis_Client('localhost', 16379, null, '', 0); }],
'Predis' => [Client\PredisClient::class, static function () { return new \Predis\Client(['scheme' => 'tcp', 'host' => 'localhost', 'port' => '16379', 'db' => 0]); }],
'Rediska' => [Client\RediskaClient::class, static function () { return new Rediska(['servers' => [['host' => 'localhost', 'port' => '16379', 'db' => 0]]]); }],
'Redisent' => [Client\RedisentClient::class, static function () { return new \redisent\Redis('redis://localhost:16379'); }],
'CheprasovRedis' => [Client\CheprasovRedisClient::class, static function () { return new \RedisClient\Client\Version\RedisClient6x0(['server' => 'localhost:16379', 'database' => 0]); }],
'AmpRedis' => [Client\AmpRedisClient::class, static function () { return new \Amp\Redis\Redis(new RemoteExecutor(Config::fromUri('redis://localhost:16379'))); }],
'TinyRedis' => [Client\TinyRedisClient::class, static function () { return new TinyRedisClient('localhost:16379'); }],
'Credis' => [Client\CredisClient::class, static function () { return new Credis_Client('localhost', 16379, null, '', 0); }],
'ReactRedis' => [Client\ReactRedisClient::class, static function () { return (new \Clue\React\Redis\Factory())->createClient('localhost:16379'); }],
];
}

Expand Down

0 comments on commit a8c55d4

Please sign in to comment.