Added prefixable interface for HEXPIRE, HEXPIRETIME (#1592)

This commit is contained in:
Vladyslav Vildanov
2025-10-17 20:27:44 +03:00
committed by GitHub
parent d9dfefd247
commit 7a15da293b
9 changed files with 669 additions and 2 deletions
+1
View File
@@ -3,6 +3,7 @@
## Unreleased
### Added
- Added cluster support for `XADD`, `XDEL` and `XRANGE` (#1587)
- Added prefixable interface for HEXPIRE, HEXPIRETIME (#1592)
### Changed
- Refactor pipeline data writing depends on connection type (#1586)
+6 -1
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
use Predis\Command\PrefixableCommand as RedisCommand;
use UnexpectedValueException;
class HEXPIRE extends RedisCommand
@@ -48,4 +48,9 @@ class HEXPIRE extends RedisCommand
parent::setArguments($processedArguments);
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
+6 -1
View File
@@ -12,7 +12,7 @@
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
use Predis\Command\PrefixableCommand as RedisCommand;
class HEXPIRETIME extends RedisCommand
{
@@ -28,4 +28,9 @@ class HEXPIRETIME extends RedisCommand
parent::setArguments($processedArguments);
}
public function prefixKeys($prefix)
{
$this->applyPrefixForFirstArgument($prefix);
}
}
@@ -13,13 +13,23 @@
namespace Predis\Command\Processor;
use PHPUnit\Framework\MockObject\MockObject;
use Predis\ClientException;
use Predis\Command\CommandInterface;
use Predis\Command\RawCommand;
use Predis\Command\RedisFactory;
use PredisTestCase;
use stdClass;
class KeyPrefixProcessorTest extends PredisTestCase
{
/** @var RedisFactory */
private $commandsFactory;
public function setUp(): void
{
$this->commandsFactory = new RedisFactory();
}
/**
* @group disconnected
*/
@@ -175,6 +185,25 @@ class KeyPrefixProcessorTest extends PredisTestCase
$processor->setCommandHandler('NEWCMD', new stdClass());
}
/**
* @group disconnected
* @dataProvider commandArgumentsDataProvider
*
* @param string $commandID
* @param array $arguments
* @param array $expected
* @throws ClientException
*/
public function testApplyPrefixToCommand($commandID, array $arguments, array $expected): void
{
$processor = new KeyPrefixProcessor('prefix:');
$command = $this->commandsFactory->create($commandID, $arguments);
$processor->process($command);
$this->assertSame($expected, $command->getArguments());
}
// ******************************************************************** //
// ---- HELPER METHODS ------------------------------------------------ //
// ******************************************************************** //
@@ -194,4 +223,622 @@ class KeyPrefixProcessorTest extends PredisTestCase
return $command;
}
/**
* Data provider for key prefixing test.
*
* @return array
*/
public function commandArgumentsDataProvider(): array
{
return [
/* ---------------- Redis 1.2 ---------------- */
['EXISTS',
['key'],
['prefix:key'],
],
['DEL',
['key1', 'key2', 'key3'],
['prefix:key1', 'prefix:key2', 'prefix:key3'],
],
['TYPE',
['key'],
['prefix:key'],
],
['KEYS',
['pattern'],
['prefix:pattern'],
],
['RENAME',
['key', 'newkey'],
['prefix:key', 'prefix:newkey'],
],
['RENAMENX',
['key', 'newkey'],
['prefix:key', 'prefix:newkey'],
],
['EXPIRE',
['key', 'value'],
['prefix:key', 'value'],
],
['EXPIREAT',
['key', 'value'],
['prefix:key', 'value'],
],
['TTL',
['key', 10],
['prefix:key', 10],
],
['MOVE',
['key', 'db'],
['prefix:key', 'db'],
],
['SORT',
['key', ['by' => 'by_key_*', 'get' => ['object_*', '#'], 'limit' => [1, 4], 'sort' => 'asc', 'alpha' => true, 'store' => 'destination_key']],
['prefix:key', 'BY', 'prefix:by_key_*', 'GET', 'prefix:object_*', 'GET', '#', 'LIMIT', 1, 4, 'ASC', 'ALPHA', 'STORE', 'prefix:destination_key'],
],
['DUMP',
['key'],
['prefix:key'],
],
['RESTORE',
['key', 0, "\x00\xC0\n\x06\x00\xF8r?\xC5\xFB\xFB_("],
['prefix:key', 0, "\x00\xC0\n\x06\x00\xF8r?\xC5\xFB\xFB_("],
],
['SET',
['key', 'value'],
['prefix:key', 'value'],
],
['SET',
['key', 'value', 'EX', 10, 'NX'],
['prefix:key', 'value', 'EX', 10, 'NX'],
],
['SETNX',
['key', 'value'],
['prefix:key', 'value'],
],
['MSET',
['foo', 'bar', 'hoge', 'piyo'],
['prefix:foo', 'bar', 'prefix:hoge', 'piyo'],
],
['MSETNX',
['foo', 'bar', 'hoge', 'piyo'],
['prefix:foo', 'bar', 'prefix:hoge', 'piyo'],
],
['GET',
['key'],
['prefix:key'],
],
['MGET',
['key1', 'key2', 'key3'],
['prefix:key1', 'prefix:key2', 'prefix:key3'],
],
['GETSET',
['key', 'value'],
['prefix:key', 'value'],
],
['INCR',
['key'],
['prefix:key'],
],
['INCRBY',
['key', 5],
['prefix:key', 5],
],
['DECR',
['key'],
['prefix:key'],
],
['DECRBY',
['key', 5],
['prefix:key', 5],
],
['RPUSH',
['key', 'value1', 'value2', 'value3'],
['prefix:key', 'value1', 'value2', 'value3'],
],
['LPUSH',
['key', 'value1', 'value2', 'value3'],
['prefix:key', 'value1', 'value2', 'value3'],
],
['LLEN',
['key'],
['prefix:key'],
],
['LRANGE',
['key', 0, -1],
['prefix:key', 0, -1],
],
['LTRIM',
['key', 0, 1],
['prefix:key', 0, 1],
],
['LINDEX',
['key', 1],
['prefix:key', 1],
],
['LSET',
['key', 0, 'value'],
['prefix:key', 0, 'value'],
],
['LREM',
['key', 0, 'value'],
['prefix:key', 0, 'value'],
],
['LPOP',
['key'],
['prefix:key'],
],
['RPOP',
['key'],
['prefix:key'],
],
['RPOPLPUSH',
['key:source', 'key:destination'],
['prefix:key:source', 'prefix:key:destination'],
],
['SADD',
['key', 'member1', 'member2', 'member3'],
['prefix:key', 'member1', 'member2', 'member3'],
],
['SREM',
['key', 'member1', 'member2', 'member3'],
['prefix:key', 'member1', 'member2', 'member3'],
],
['SPOP',
['key'],
['prefix:key'],
],
['SMOVE',
['key:source', 'key:destination', 'member'],
['prefix:key:source', 'prefix:key:destination', 'member'],
],
['SCARD',
['key'],
['prefix:key'],
],
['SISMEMBER',
['key', 'member'],
['prefix:key', 'member'],
],
['SINTER',
['key1', 'key2', 'key3'],
['prefix:key1', 'prefix:key2', 'prefix:key3'],
],
['SINTERSTORE',
['key:destination', 'key1', 'key2'],
['prefix:key:destination', 'prefix:key1', 'prefix:key2'],
],
['SUNION',
['key1', 'key2', 'key3'],
['prefix:key1', 'prefix:key2', 'prefix:key3'],
],
['SUNIONSTORE',
['key:destination', 'key1', 'key2'],
['prefix:key:destination', 'prefix:key1', 'prefix:key2'],
],
['SDIFF',
['key1', 'key2', 'key3'],
['prefix:key1', 'prefix:key2', 'prefix:key3'],
],
['SDIFFSTORE',
['key:destination', 'key1', 'key2'],
['prefix:key:destination', 'prefix:key1', 'prefix:key2'],
],
['SMEMBERS',
['key'],
['prefix:key'],
],
['SMISMEMBER',
['key', 'member1', 'member2', 'member3'],
['prefix:key', 'member1', 'member2', 'member3'],
],
['SRANDMEMBER',
['key', 1],
['prefix:key', 1],
],
['ZADD',
['key', 'score1', 'member1', 'score2', 'member2'],
['prefix:key', 'score1', 'member1', 'score2', 'member2'],
],
['ZINCRBY',
['key', 1.0, 'member'],
['prefix:key', 1.0, 'member'],
],
['ZREM',
['key', 'member1', 'member2', 'member3'],
['prefix:key', 'member1', 'member2', 'member3'],
],
['ZRANGE',
['key', 0, 100, 'WITHSCORES'],
['prefix:key', 0, 100, 'WITHSCORES'],
],
['ZREVRANGE',
['key', 0, 100, 'WITHSCORES'],
['prefix:key', 0, 100, 'WITHSCORES'],
],
['ZRANGEBYSCORE',
['key', 0, 100, 'LIMIT', 0, 100, 'WITHSCORES'],
['prefix:key', 0, 100, 'LIMIT', 0, 100, 'WITHSCORES'],
],
['ZCARD',
['key'],
['prefix:key'],
],
['ZSCORE',
['key', 'member'],
['prefix:key', 'member'],
],
['ZREMRANGEBYSCORE',
['key', 0, 10],
['prefix:key', 0, 10],
],
/* ---------------- Redis 2.0 ---------------- */
['SETEX',
['key', 10, 'value'],
['prefix:key', 10, 'value'],
],
['APPEND',
['key', 'value'],
['prefix:key', 'value'],
],
['SUBSTR',
['key', 5, 10],
['prefix:key', 5, 10],
],
['BLPOP',
['key1', 'key2', 'key3', 10],
['prefix:key1', 'prefix:key2', 'prefix:key3', 10],
],
['BRPOP',
['key1', 'key2', 'key3', 10],
['prefix:key1', 'prefix:key2', 'prefix:key3', 10],
],
['ZUNIONSTORE',
['key:destination', ['key1', 'key2']],
['prefix:key:destination', 2, 'prefix:key1', 'prefix:key2'],
],
['ZINTERSTORE',
['key:destination', ['key1', 'key2']],
['prefix:key:destination', 2, 'prefix:key1', 'prefix:key2'],
],
['ZCOUNT',
['key', 0, 10],
['prefix:key', 0, 10],
],
['ZRANK',
['key', 'member'],
['prefix:key', 'member'],
],
['ZREVRANK',
['key', 'member'],
['prefix:key', 'member'],
],
['ZREMRANGEBYRANK',
['key', 0, 10],
['prefix:key', 0, 10],
],
['HSET',
['key', 'field', 'value'],
['prefix:key', 'field', 'value'],
],
['HSETNX',
['key', 'field', 'value'],
['prefix:key', 'field', 'value'],
],
['HMSET',
['key', 'field1', 'value1', 'field2', 'value2'],
['prefix:key', 'field1', 'value1', 'field2', 'value2'],
],
['HINCRBY',
['key', 'field', 10],
['prefix:key', 'field', 10],
],
['HGET',
['key', 'field'],
['prefix:key', 'field'],
],
['HMGET',
['key', 'field1', 'field2', 'field3'],
['prefix:key', 'field1', 'field2', 'field3'],
],
['HDEL',
['key', 'field1', 'field2', 'field3'],
['prefix:key', 'field1', 'field2', 'field3'],
],
['HEXISTS',
['key', 'field'],
['prefix:key', 'field'],
],
['HLEN',
['key'],
['prefix:key'],
],
['HKEYS',
['key'],
['prefix:key'],
],
['HVALS',
['key'],
['prefix:key'],
],
['HGETALL',
['key'],
['prefix:key'],
],
['SUBSCRIBE',
['channel:foo', 'channel:hoge'],
['prefix:channel:foo', 'prefix:channel:hoge'],
],
['UNSUBSCRIBE',
['channel:foo', 'channel:hoge'],
['prefix:channel:foo', 'prefix:channel:hoge'],
],
['PSUBSCRIBE',
['channel:foo:*', 'channel:hoge:*'],
['prefix:channel:foo:*', 'prefix:channel:hoge:*'],
],
['PUNSUBSCRIBE',
['channel:foo:*', 'channel:hoge:*'],
['prefix:channel:foo:*', 'prefix:channel:hoge:*'],
],
['PUBLISH',
['channel', 'message'],
['prefix:channel', 'message'],
],
/* ---------------- Redis 2.2 ---------------- */
['PERSIST',
['key'],
['prefix:key'],
],
['STRLEN',
['key'],
['prefix:key'],
],
['SETRANGE',
['key', 5, 'string'],
['prefix:key', 5, 'string'],
],
['GETRANGE',
['key', 5, 10],
['prefix:key', 5, 10],
],
['SETBIT',
['key', 7, 1],
['prefix:key', 7, 1],
],
['GETBIT',
['key', 100],
['prefix:key', 100],
],
['RPUSHX',
['key', 'value'],
['prefix:key', 'value'],
],
['LPUSHX',
['key', 'value'],
['prefix:key', 'value'],
],
['LINSERT',
['key', 'before', 'value1', 'value2'],
['prefix:key', 'before', 'value1', 'value2'],
],
['BRPOPLPUSH',
['key:source', 'key:destination', 10],
['prefix:key:source', 'prefix:key:destination', 10],
],
['ZREVRANGEBYSCORE',
['key', 0, 100, 'LIMIT', 0, 100, 'WITHSCORES'],
['prefix:key', 0, 100, 'LIMIT', 0, 100, 'WITHSCORES'],
],
['WATCH',
['key1', 'key2', 'key3'],
['prefix:key1', 'prefix:key2', 'prefix:key3'],
],
/* ---------------- Redis 2.6 ---------------- */
['PTTL',
['key', 10],
['prefix:key', 10],
],
['PEXPIRE',
['key', 1500],
['prefix:key', 1500],
],
['PEXPIREAT',
['key', 1555555555005],
['prefix:key', 1555555555005],
],
['PSETEX',
['key', 1500, 'value'],
['prefix:key', 1500, 'value'],
],
['INCRBYFLOAT',
['key', 10.5],
['prefix:key', 10.5],
],
['BITOP',
['AND', 'key:dst', 'key:01', 'key:02'],
['AND', 'prefix:key:dst', 'prefix:key:01', 'prefix:key:02'],
],
['BITCOUNT',
['key', 0, 10],
['prefix:key', 0, 10],
],
['HINCRBYFLOAT',
['key', 'field', 10.5],
['prefix:key', 'field', 10.5],
],
['EVAL',
['return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}', 2, 'foo', 'hoge', 'bar', 'piyo'],
['return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}', 2, 'prefix:foo', 'prefix:hoge', 'bar', 'piyo'],
],
['EVALSHA',
['a42059b356c875f0717db19a51f6aaca9ae659ea', 2, 'foo', 'hoge', 'bar', 'piyo'],
['a42059b356c875f0717db19a51f6aaca9ae659ea', 2, 'prefix:foo', 'prefix:hoge', 'bar', 'piyo'],
],
['BITPOS',
['key', 0],
['prefix:key', 0],
],
['MIGRATE',
['127.0.0.1', '6379', 'key', '0', '10'],
['127.0.0.1', '6379', 'prefix:key', '0', '10'],
],
/* ---------------- Redis 2.8 ---------------- */
['SSCAN',
['key', '0', 'MATCH', 'member:*', 'COUNT', 10],
['prefix:key', '0', 'MATCH', 'member:*', 'COUNT', 10],
],
['ZSCAN',
['key', '0', 'MATCH', 'member:*', 'COUNT', 10],
['prefix:key', '0', 'MATCH', 'member:*', 'COUNT', 10],
],
['HSCAN',
['key', '0', 'MATCH', 'field:*', 'COUNT', 10],
['prefix:key', '0', 'MATCH', 'field:*', 'COUNT', 10],
],
['PFADD',
['key', 'a', 'b', 'c'],
['prefix:key', 'a', 'b', 'c'],
],
['PFCOUNT',
['key:1', 'key:2', 'key:3'],
['prefix:key:1', 'prefix:key:2', 'prefix:key:3'],
],
['PFMERGE',
['key:1', 'key:2', 'key:3'],
['prefix:key:1', 'prefix:key:2', 'prefix:key:3'],
],
['ZLEXCOUNT',
['key', '-', '+'],
['prefix:key', '-', '+'],
],
['ZRANGEBYLEX',
['key', '-', '+', 'LIMIT', '0', '10'],
['prefix:key', '-', '+', 'LIMIT', '0', '10'],
],
['ZREMRANGEBYLEX',
['key', '-', '+'],
['prefix:key', '-', '+'],
],
['ZREVRANGEBYLEX',
['key', '+', '-', 'LIMIT', '0', '10'],
['prefix:key', '+', '-', 'LIMIT', '0', '10'],
],
/* ---------------- Redis 3.0 ---------------- */
['MIGRATE',
['127.0.0.1', '6379', 'key', '0', '10', 'COPY', 'REPLACE'],
['127.0.0.1', '6379', 'prefix:key', '0', '10', 'COPY', 'REPLACE'],
],
['EXISTS',
['key1', 'key2', 'key3'],
['prefix:key1', 'prefix:key2', 'prefix:key3'],
],
/* ---------------- Redis 3.2 ---------------- */
['HSTRLEN',
['key', 'field'],
['prefix:key', 'field'],
],
['BITFIELD',
['key', 'GET', 'u8', '0', 'SET', 'u8', '0', '1'],
['prefix:key', 'GET', 'u8', '0', 'SET', 'u8', '0', '1'],
],
['GEOADD',
['key', '13.361389', '38.115556', 'member:1', '15.087269', '37.502669', 'member:2'],
['prefix:key', '13.361389', '38.115556', 'member:1', '15.087269', '37.502669', 'member:2'],
],
['GEOHASH',
['key', 'member:1', 'member:2'],
['prefix:key', 'member:1', 'member:2'],
],
['GEOPOS',
['key', 'member:1', 'member:2'],
['prefix:key', 'member:1', 'member:2'],
],
['GEODIST',
['key', 'member:1', 'member:2', 'km'],
['prefix:key', 'member:1', 'member:2', 'km'],
],
['GEORADIUS',
['key', '15', '37', '200', 'km'],
['prefix:key', '15', '37', '200', 'km'],
],
['GEORADIUS',
['key', '15', '37', '200', 'km', 'WITHDIST', 'STORE', 'key:store', 'STOREDIST', 'key:storedist'],
['prefix:key', '15', '37', '200', 'km', 'WITHDIST', 'STORE', 'prefix:key:store', 'STOREDIST', 'prefix:key:storedist'],
],
['GEORADIUSBYMEMBER',
['key', 'member', '100', 'km'],
['prefix:key', 'member', '100', 'km'],
],
['GEORADIUSBYMEMBER',
['key', 'member', '100', 'km', 'WITHDIST', 'STORE', 'key:store', 'STOREDIST', 'key:storedist'],
['prefix:key', 'member', '100', 'km', 'WITHDIST', 'STORE', 'prefix:key:store', 'STOREDIST', 'prefix:key:storedist'],
],
/* ---------------- Redis 5.0 ---------------- */
['XADD',
['key', ['field' => 'value']],
['prefix:key', '*', 'field', 'value'],
],
['XRANGE',
['key', '-', '+'],
['prefix:key', '-', '+'],
],
['XREVRANGE',
['key', '+', '-'],
['prefix:key', '+', '-'],
],
['XDEL',
['key', 'id'],
['prefix:key', 'id'],
],
['XLEN',
['key'],
['prefix:key'],
],
['XACK',
['key', 'group', 'id'],
['prefix:key', 'group', 'id'],
],
['XTRIM',
['key', 'MAXLEN', 100],
['prefix:key', 'MAXLEN', 100],
],
['ZPOPMIN',
['key'],
['prefix:key'],
],
['ZPOPMAX',
['key'],
['prefix:key'],
],
/* ---------------- Redis 6.2 ---------------- */
['GETDEL',
['key'],
['prefix:key'],
],
['LMOVE',
['key:source', 'key:destination', 'left', 'right'],
['prefix:key:source', 'prefix:key:destination', 'left', 'right'],
],
['BLMOVE',
['key:source', 'key:destination', 'left', 'right', 10],
['prefix:key:source', 'prefix:key:destination', 'left', 'right', 10],
],
/* ---------------- Redis 7.0 ---------------- */
['EXPIRETIME',
['key'],
['prefix:key'],
],
/* ---------------- Redis 7.4 ---------------- */
['HEXPIRE',
['key', 10, ['field1', 'field2']],
['prefix:key', 10, 'FIELDS', 2, 'field1', 'field2'],
],
['HEXPIRETIME',
['key', ['field1', 'field2']],
['prefix:key', 'FIELDS', 2, 'field1', 'field2'],
],
];
}
}
+2
View File
@@ -66,6 +66,7 @@ class VEMB_Test extends PredisCommandTestCase
/**
* @dataProvider quantisationProvider
* @group connected
* @group relay-incompatible
* @return void
* @requiresRedisVersion >= 8.0.0
*/
@@ -98,6 +99,7 @@ class VEMB_Test extends PredisCommandTestCase
/**
* @dataProvider quantisationProvider
* @group connected
* @group relay-incompatible
* @return void
* @requiresRedisVersion >= 8.0.0
*/
@@ -62,6 +62,7 @@ class VGETATTR_Test extends PredisCommandTestCase
/**
* @group connected
* @group relay-incompatible
* @return void
* @requiresRedisVersion >= 8.0.0
*/
@@ -86,6 +87,7 @@ class VGETATTR_Test extends PredisCommandTestCase
/**
* @group connected
* @group relay-incompatible
* @return void
* @requiresRedisVersion >= 8.0.0
*/
@@ -95,6 +95,7 @@ class VLINKS_Test extends PredisCommandTestCase
/**
* @group connected
* @group relay-incompatible
* @return void
* @requiresRedisVersion >= 8.0.0
*/
+2
View File
@@ -54,6 +54,7 @@ class VREM_Test extends PredisCommandTestCase
/**
* @group connected
* @group relay-incompatible
* @return void
* @requiresRedisVersion >= 8.0.0
*/
@@ -78,6 +79,7 @@ class VREM_Test extends PredisCommandTestCase
/**
* @group connected
* @group relay-incompatible
* @return void
* @requiresRedisVersion >= 8.0.0
*/
@@ -59,6 +59,7 @@ class VSETATTR_Test extends PredisCommandTestCase
/**
* @group connected
* @group relay-incompatible
* @return void
* @requiresRedisVersion >= 8.0.0
*/
@@ -78,6 +79,7 @@ class VSETATTR_Test extends PredisCommandTestCase
/**
* @group connected
* @group relay-incompatible
* @return void
* @requiresRedisVersion >= 8.0.0
*/