Skip to content

Commit

Permalink
Update: 修复对静态调用 scan 的支持
Browse files Browse the repository at this point in the history
  • Loading branch information
NHZEX committed Mar 7, 2024
1 parent 5b769e9 commit 7f89a57
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 197 deletions.
62 changes: 48 additions & 14 deletions src/Components/redis/src/Redis.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
namespace Imi\Redis;

use Imi\ConnectionCenter\Contract\IConnection;
use Imi\Pool\Interfaces\IPoolResource;
use Imi\Redis\Handler\IRedisClusterHandler;
use Imi\Redis\Handler\IRedisHandler;
use Imi\Redis\Handler\PhpRedisClusterHandler;
use Imi\Redis\Handler\PhpRedisHandler;
use Imi\Redis\Handler\PredisClusterHandler;
use Imi\Redis\Handler\PredisHandler;

/**
* Redis 快捷操作类.
Expand Down Expand Up @@ -265,17 +269,26 @@ public static function __callStatic(string $name, array $arguments): mixed
*/
public static function use(callable $callable, ?string $poolName = null): mixed
{
return RedisManager::use($poolName, static fn (IConnection $resource, IRedisHandler $redis) => $callable($redis));
return RedisManager::use($poolName, static fn (IConnection $connection, IRedisHandler $redis) => $callable($redis));
}

/**
* scan.
*/
public static function scan(?int &$iterator, ?string $pattern = null, int $count = 0): mixed
{
// todo 只适用于 phpredis
return RedisManager::use(null, static function (IPoolResource $resource, IRedisHandler $redis) use (&$iterator, $pattern, $count) {
return $redis->scan($iterator, $pattern, $count);
return RedisManager::use(null, static function (IConnection $connection, IRedisHandler $redis) use (&$iterator, $pattern, $count) {
if ($redis instanceof PhpRedisHandler) {
return $redis->scan($iterator, $pattern, $count);
} elseif ($redis instanceof PredisHandler) {
[$cursor, $keys] = $redis->scan($iterator, ['match' => $pattern, 'count' => $count]);
$iterator = (int) $cursor;
return $keys;
} elseif ($redis instanceof IRedisClusterHandler) {
throw new \RuntimeException('redis cluster handler not support scan proxy, please use scanEach method');
} else {
throw new \RuntimeException('unknown redis handler');
}
});
}

Expand All @@ -284,9 +297,16 @@ public static function scan(?int &$iterator, ?string $pattern = null, int $count
*/
public static function hscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): mixed
{
// todo 只适用于 phpredis
return RedisManager::use(null, static function (IPoolResource $resource, IRedisHandler $redis) use ($key, &$iterator, $pattern, $count) {
return $redis->hscan($key, $iterator, $pattern, $count);
return RedisManager::use(null, static function (IConnection $connection, IRedisHandler $redis) use ($key, &$iterator, $pattern, $count) {
if ($redis instanceof PhpRedisHandler || $redis instanceof PhpRedisClusterHandler) {
return $redis->hscan($key, $iterator, $pattern, $count);
} else if ($redis instanceof PredisHandler || $redis instanceof PredisClusterHandler) {
[$cursor, $keys] = $redis->hscan($key, $iterator, ['match' => $pattern, 'count' => $count]);
$iterator = (int) $cursor;
return $keys;
} else {
throw new \RuntimeException('redis handler not support');
}
});
}

Expand All @@ -295,9 +315,16 @@ public static function hscan(string $key, ?int &$iterator, ?string $pattern = nu
*/
public static function sscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): mixed
{
// todo 只适用于 phpredis
return RedisManager::use(null, static function (IPoolResource $resource, IRedisHandler $redis) use ($key, &$iterator, $pattern, $count) {
return $redis->sscan($key, $iterator, $pattern, $count);
return RedisManager::use(null, static function (IConnection $connection, IRedisHandler $redis) use ($key, &$iterator, $pattern, $count) {
if ($redis instanceof PhpRedisHandler || $redis instanceof PhpRedisClusterHandler) {
return $redis->sscan($key, $iterator, $pattern, $count);
} else if ($redis instanceof PredisHandler || $redis instanceof PredisClusterHandler) {
[$cursor, $keys] = $redis->sscan($key, $iterator, ['match' => $pattern, 'count' => $count]);
$iterator = (int) $cursor;
return $keys;
} else {
throw new \RuntimeException('redis handler not support');
}
});
}

Expand All @@ -306,9 +333,16 @@ public static function sscan(string $key, ?int &$iterator, ?string $pattern = nu
*/
public static function zscan(string $key, ?int &$iterator, ?string $pattern = null, int $count = 0): mixed
{
// todo 只适用于 phpredis
return RedisManager::use(null, static function (IPoolResource $resource, IRedisHandler $redis) use ($key, &$iterator, $pattern, $count) {
return $redis->zscan($key, $iterator, $pattern, $count);
return RedisManager::use(null, static function (IConnection $connection, IRedisHandler $redis) use ($key, &$iterator, $pattern, $count) {
if ($redis instanceof PhpRedisHandler || $redis instanceof PhpRedisClusterHandler) {
return $redis->zscan($key, $iterator, $pattern, $count);
} else if ($redis instanceof PredisHandler || $redis instanceof PredisClusterHandler) {
[$cursor, $keys] = $redis->zscan($key, $iterator, ['match' => $pattern, 'count' => $count]);
$iterator = (int) $cursor;
return $keys;
} else {
throw new \RuntimeException('redis handler not support');
}
});
}
}
165 changes: 165 additions & 0 deletions src/Components/redis/tests/Tests/PhpRedisTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@

namespace Imi\Redis\Test\Tests;

use Imi\Config;
use Imi\Redis\Handler\IRedisClusterHandler;
use Imi\Redis\Handler\IRedisHandler;
use Imi\Redis\Handler\PhpRedisHandler;
use Imi\Redis\Redis;
use Imi\Redis\RedisManager;
use Imi\RequestContext;
use PHPUnit\Framework\Attributes\Depends;
use PHPUnit\Framework\Attributes\TestDox;
use PHPUnit\Framework\TestCase;
use Predis\Collection\Iterator\Keyspace;

/**
* @template T of PhpRedisHandler
Expand Down Expand Up @@ -183,4 +188,164 @@ public function testGeoAdd(IRedisHandler $redis): void

$redis->setOption(\Redis::OPT_SERIALIZER, $oriOption);
}

protected function staticContextWarp(callable $fn): void
{
$defaultName = RedisManager::getDefaultPoolName();
// Config::get()
self::assertTrue(Config::set('@app.redis.defaultPool', $this->driveName));
self::assertEquals($this->driveName, RedisManager::getDefaultPoolName());
try {
$fn();
} finally {
Config::set('@app.redis.defaultPool', $defaultName);
}
}

#[Depends('testGetDrive')]
public function testStaticCall(): void
{
$prefix = __FUNCTION__ . bin2hex(random_bytes(4));
$this->staticContextWarp(function () use ($prefix) {
Redis::set($prefix, '123456');
self::assertEquals('123456', Redis::get($prefix));
self::assertTrue(Redis::del($prefix) > 0);
});
}

/**
* @phpstan-param PhpRedisHandler $redis
*/
#[Depends('testGetDrive')]
public function testStaticCallScan(IRedisHandler $redis): void
{
if ($redis instanceof IRedisClusterHandler) {
self::markTestSkipped('RedisClusterHandler does not support hscan');
}

$prefix = __FUNCTION__ . bin2hex(random_bytes(4));
$this->staticContextWarp(function () use ($redis, $prefix) {
$excepted = $map = [];
for ($i = 0; $i < 100; ++$i)
{
$key = $prefix . ':scanEach:' . $i;
$excepted[$key] = 1;
$map[$key] = 0;
$redis->set($key, $i);
}

$map = [];
do {
$keys = Redis::scan($it, $prefix . ':scanEach:*', 10);
foreach ($keys as $key) {
$map[$key] = 1;
}
} while ($it != 0);
self::assertEquals($excepted, $map);
self::assertTrue(Redis::del(\array_keys($excepted)) > 0);
});
}

/**
* @phpstan-param PhpRedisHandler $redis
*/
#[Depends('testGetDrive')]
public function testStaticCallHScan(IRedisHandler $redis): void
{
if ($redis instanceof IRedisClusterHandler) {
self::markTestSkipped('RedisClusterHandler does not support hscan');
}

$prefix = __FUNCTION__ . bin2hex(random_bytes(4));
$this->staticContextWarp(function () use ($redis, $prefix) {
$excepted = $map = $values = $exceptedValues = [];
$key = $prefix . ':hscanEach';
$redis->del($key);
for ($i = 0; $i < 100; ++$i)
{
$member = 'value:' . $i;
$excepted[$member] = 1;
$map[$member] = 0;
$values[$member] = -1;
$exceptedValues[$member] = $i;
$redis->hSet($key, $member, $i);
}
do {
$items = Redis::hscan($key, $it, 'value:*', 10);
foreach ($items as $k => $value) {
$map[$k] = 1;
$values[$k] = $value;
}
} while ($it > 0);
self::assertEquals($excepted, $map);
self::assertEquals($exceptedValues, $values);
self::assertTrue(Redis::del($key) > 0);
});
}

/**
* @phpstan-param PhpRedisHandler $redis
*/
#[Depends('testGetDrive')]
public function testStaticCallSScan(IRedisHandler $redis): void
{
if ($redis instanceof IRedisClusterHandler) {
self::markTestSkipped('RedisClusterHandler does not support sscan');
}

$prefix = __FUNCTION__ . bin2hex(random_bytes(4));
$this->staticContextWarp(function () use ($redis, $prefix) {
$excepted = $map = [];
$key = $prefix . ':sscanEach';
$redis->del($key);
for ($i = 0; $i < 100; ++$i)
{
$value = 'value:' . $i;
$excepted[$value] = 1;
$map[$value] = 0;
$redis->sAdd($key, $value);
}
do {
$items = Redis::sscan($key, $it, '*', 10);
foreach ($items as $value) {
$map[$value] = 1;
}
} while ($it > 0);
self::assertEquals($excepted, $map);
self::assertTrue(Redis::del($key) > 0);
});
}

/**
* @phpstan-param PhpRedisHandler $redis
*/
#[Depends('testGetDrive')]
public function testStaticCallZScan(IRedisHandler $redis): void
{
if ($redis instanceof IRedisClusterHandler) {
self::markTestSkipped('RedisClusterHandler does not support zscan');
}

$prefix = __FUNCTION__ . bin2hex(random_bytes(4));
$this->staticContextWarp(function () use ($redis, $prefix) {
$excepted = $map = [];
$key = $prefix . ':zscanEach';
$redis->del($key);
for ($i = 0; $i < 100; ++$i)
{
$value = 'value:' . $i;
$excepted[$i] = 1;
$map[$i] = 0;
$redis->zAdd($key, $i, $value);
}
do {
$items = Redis::zscan($key, $it, '*', 10);
foreach ($items as $score) {
$map[$score] = 1;
}
} while ($it > 0);
self::assertEquals($excepted, $map);
self::assertTrue(Redis::del($key) > 0);
});
}
}
104 changes: 0 additions & 104 deletions src/Components/redis/tests/Tests/RedisManagerTest.php

This file was deleted.

Loading

0 comments on commit 7f89a57

Please sign in to comment.