mirror of
https://github.com/predis/predis.git
synced 2026-08-19 18:52:50 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ff59f74581 | |||
| 1a0eb7ee85 | |||
| bb6c1a7b6d | |||
| 42c33a406f | |||
| 7ad74217c2 | |||
| 72d7675563 | |||
| 8b5fa92856 | |||
| 076a62e3d3 | |||
| 85dc1752b7 |
@@ -20,7 +20,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1']
|
||||
php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2']
|
||||
redis-versions: ['3', '4', '5', '6', '7']
|
||||
|
||||
steps:
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
## Changelog
|
||||
|
||||
## v2.0.3 (2022-10-11)
|
||||
|
||||
- Improved PHP 8.2 support
|
||||
- Call `is_resource()` before reading/writing
|
||||
- Added partial support for Redis Stream commands
|
||||
- Fixed Sentinel authentication issue
|
||||
|
||||
## v2.0.2 (2022-09-06)
|
||||
|
||||
- Fixed PHP 8.2 deprecation notice: Use of "static" in callables
|
||||
|
||||
## v2.0.1 (2022-09-04)
|
||||
|
||||
- Added retry interval to `RedisCluster` with a default of `10ms`
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ use Predis\Transaction\MultiExec as MultiExecTransaction;
|
||||
*/
|
||||
class Client implements ClientInterface, \IteratorAggregate
|
||||
{
|
||||
const VERSION = '2.0.1';
|
||||
const VERSION = '2.0.3';
|
||||
|
||||
/** @var OptionsInterface */
|
||||
private $options;
|
||||
|
||||
@@ -116,6 +116,12 @@ use Predis\Response\Status;
|
||||
* @method string[] sunion(array|string $keys)
|
||||
* @method int sunionstore(string $destination, array|string $keys)
|
||||
* @method int touch(string[]|string $keyOrKeys, string ...$keys = null)
|
||||
* @method string xadd(string $key, array $dictionary, string $id = '*', array $options = null)
|
||||
* @method int xdel(string $key, string ...$id)
|
||||
* @method int xlen(string $key)
|
||||
* @method array xrevrange(string $key, string $end, string $start, ?int $count = null)
|
||||
* @method array xrange(string $key, string $start, string $end, ?int $count = null)
|
||||
* @method string xtrim(string $key, array|string $strategy, string $threshold, array $options = null)
|
||||
* @method int zadd(string $key, array $membersAndScoresDictionary)
|
||||
* @method int zcard(string $key)
|
||||
* @method string zcount(string $key, int|string $min, int|string $max)
|
||||
|
||||
@@ -31,142 +31,154 @@ class KeyPrefixProcessor implements ProcessorInterface
|
||||
public function __construct($prefix)
|
||||
{
|
||||
$this->prefix = $prefix;
|
||||
$this->commands = array(
|
||||
|
||||
$prefixFirst = static::class . '::first';
|
||||
$prefixAll = static::class . '::all';
|
||||
$prefixInterleaved = static::class . '::interleaved';
|
||||
$prefixSkipFirst = static::class . '::skipFirst';
|
||||
$prefixSkipLast = static::class . '::skipLast';
|
||||
$prefixSort = static::class . '::sort';
|
||||
$prefixEvalKeys = static::class . '::evalKeys';
|
||||
$prefixZsetStore = static::class . '::zsetStore';
|
||||
$prefixMigrate = static::class . '::migrate';
|
||||
$prefixGeoradius = static::class . '::georadius';
|
||||
|
||||
$this->commands = [
|
||||
/* ---------------- Redis 1.2 ---------------- */
|
||||
'EXISTS' => 'static::all',
|
||||
'DEL' => 'static::all',
|
||||
'TYPE' => 'static::first',
|
||||
'KEYS' => 'static::first',
|
||||
'RENAME' => 'static::all',
|
||||
'RENAMENX' => 'static::all',
|
||||
'EXPIRE' => 'static::first',
|
||||
'EXPIREAT' => 'static::first',
|
||||
'TTL' => 'static::first',
|
||||
'MOVE' => 'static::first',
|
||||
'SORT' => 'static::sort',
|
||||
'DUMP' => 'static::first',
|
||||
'RESTORE' => 'static::first',
|
||||
'SET' => 'static::first',
|
||||
'SETNX' => 'static::first',
|
||||
'MSET' => 'static::interleaved',
|
||||
'MSETNX' => 'static::interleaved',
|
||||
'GET' => 'static::first',
|
||||
'MGET' => 'static::all',
|
||||
'GETSET' => 'static::first',
|
||||
'INCR' => 'static::first',
|
||||
'INCRBY' => 'static::first',
|
||||
'DECR' => 'static::first',
|
||||
'DECRBY' => 'static::first',
|
||||
'RPUSH' => 'static::first',
|
||||
'LPUSH' => 'static::first',
|
||||
'LLEN' => 'static::first',
|
||||
'LRANGE' => 'static::first',
|
||||
'LTRIM' => 'static::first',
|
||||
'LINDEX' => 'static::first',
|
||||
'LSET' => 'static::first',
|
||||
'LREM' => 'static::first',
|
||||
'LPOP' => 'static::first',
|
||||
'RPOP' => 'static::first',
|
||||
'RPOPLPUSH' => 'static::all',
|
||||
'SADD' => 'static::first',
|
||||
'SREM' => 'static::first',
|
||||
'SPOP' => 'static::first',
|
||||
'SMOVE' => 'static::skipLast',
|
||||
'SCARD' => 'static::first',
|
||||
'SISMEMBER' => 'static::first',
|
||||
'SINTER' => 'static::all',
|
||||
'SINTERSTORE' => 'static::all',
|
||||
'SUNION' => 'static::all',
|
||||
'SUNIONSTORE' => 'static::all',
|
||||
'SDIFF' => 'static::all',
|
||||
'SDIFFSTORE' => 'static::all',
|
||||
'SMEMBERS' => 'static::first',
|
||||
'SRANDMEMBER' => 'static::first',
|
||||
'ZADD' => 'static::first',
|
||||
'ZINCRBY' => 'static::first',
|
||||
'ZREM' => 'static::first',
|
||||
'ZRANGE' => 'static::first',
|
||||
'ZREVRANGE' => 'static::first',
|
||||
'ZRANGEBYSCORE' => 'static::first',
|
||||
'ZCARD' => 'static::first',
|
||||
'ZSCORE' => 'static::first',
|
||||
'ZREMRANGEBYSCORE' => 'static::first',
|
||||
'EXISTS' => $prefixAll,
|
||||
'DEL' => $prefixAll,
|
||||
'TYPE' => $prefixFirst,
|
||||
'KEYS' => $prefixFirst,
|
||||
'RENAME' => $prefixAll,
|
||||
'RENAMENX' => $prefixAll,
|
||||
'EXPIRE' => $prefixFirst,
|
||||
'EXPIREAT' => $prefixFirst,
|
||||
'TTL' => $prefixFirst,
|
||||
'MOVE' => $prefixFirst,
|
||||
'SORT' => $prefixSort,
|
||||
'DUMP' => $prefixFirst,
|
||||
'RESTORE' => $prefixFirst,
|
||||
'SET' => $prefixFirst,
|
||||
'SETNX' => $prefixFirst,
|
||||
'MSET' => $prefixInterleaved,
|
||||
'MSETNX' => $prefixInterleaved,
|
||||
'GET' => $prefixFirst,
|
||||
'MGET' => $prefixAll,
|
||||
'GETSET' => $prefixFirst,
|
||||
'INCR' => $prefixFirst,
|
||||
'INCRBY' => $prefixFirst,
|
||||
'DECR' => $prefixFirst,
|
||||
'DECRBY' => $prefixFirst,
|
||||
'RPUSH' => $prefixFirst,
|
||||
'LPUSH' => $prefixFirst,
|
||||
'LLEN' => $prefixFirst,
|
||||
'LRANGE' => $prefixFirst,
|
||||
'LTRIM' => $prefixFirst,
|
||||
'LINDEX' => $prefixFirst,
|
||||
'LSET' => $prefixFirst,
|
||||
'LREM' => $prefixFirst,
|
||||
'LPOP' => $prefixFirst,
|
||||
'RPOP' => $prefixFirst,
|
||||
'RPOPLPUSH' => $prefixAll,
|
||||
'SADD' => $prefixFirst,
|
||||
'SREM' => $prefixFirst,
|
||||
'SPOP' => $prefixFirst,
|
||||
'SMOVE' => $prefixSkipLast,
|
||||
'SCARD' => $prefixFirst,
|
||||
'SISMEMBER' => $prefixFirst,
|
||||
'SINTER' => $prefixAll,
|
||||
'SINTERSTORE' => $prefixAll,
|
||||
'SUNION' => $prefixAll,
|
||||
'SUNIONSTORE' => $prefixAll,
|
||||
'SDIFF' => $prefixAll,
|
||||
'SDIFFSTORE' => $prefixAll,
|
||||
'SMEMBERS' => $prefixFirst,
|
||||
'SRANDMEMBER' => $prefixFirst,
|
||||
'ZADD' => $prefixFirst,
|
||||
'ZINCRBY' => $prefixFirst,
|
||||
'ZREM' => $prefixFirst,
|
||||
'ZRANGE' => $prefixFirst,
|
||||
'ZREVRANGE' => $prefixFirst,
|
||||
'ZRANGEBYSCORE' => $prefixFirst,
|
||||
'ZCARD' => $prefixFirst,
|
||||
'ZSCORE' => $prefixFirst,
|
||||
'ZREMRANGEBYSCORE' => $prefixFirst,
|
||||
/* ---------------- Redis 2.0 ---------------- */
|
||||
'SETEX' => 'static::first',
|
||||
'APPEND' => 'static::first',
|
||||
'SUBSTR' => 'static::first',
|
||||
'BLPOP' => 'static::skipLast',
|
||||
'BRPOP' => 'static::skipLast',
|
||||
'ZUNIONSTORE' => 'static::zsetStore',
|
||||
'ZINTERSTORE' => 'static::zsetStore',
|
||||
'ZCOUNT' => 'static::first',
|
||||
'ZRANK' => 'static::first',
|
||||
'ZREVRANK' => 'static::first',
|
||||
'ZREMRANGEBYRANK' => 'static::first',
|
||||
'HSET' => 'static::first',
|
||||
'HSETNX' => 'static::first',
|
||||
'HMSET' => 'static::first',
|
||||
'HINCRBY' => 'static::first',
|
||||
'HGET' => 'static::first',
|
||||
'HMGET' => 'static::first',
|
||||
'HDEL' => 'static::first',
|
||||
'HEXISTS' => 'static::first',
|
||||
'HLEN' => 'static::first',
|
||||
'HKEYS' => 'static::first',
|
||||
'HVALS' => 'static::first',
|
||||
'HGETALL' => 'static::first',
|
||||
'SUBSCRIBE' => 'static::all',
|
||||
'UNSUBSCRIBE' => 'static::all',
|
||||
'PSUBSCRIBE' => 'static::all',
|
||||
'PUNSUBSCRIBE' => 'static::all',
|
||||
'PUBLISH' => 'static::first',
|
||||
'SETEX' => $prefixFirst,
|
||||
'APPEND' => $prefixFirst,
|
||||
'SUBSTR' => $prefixFirst,
|
||||
'BLPOP' => $prefixSkipLast,
|
||||
'BRPOP' => $prefixSkipLast,
|
||||
'ZUNIONSTORE' => $prefixZsetStore,
|
||||
'ZINTERSTORE' => $prefixZsetStore,
|
||||
'ZCOUNT' => $prefixFirst,
|
||||
'ZRANK' => $prefixFirst,
|
||||
'ZREVRANK' => $prefixFirst,
|
||||
'ZREMRANGEBYRANK' => $prefixFirst,
|
||||
'HSET' => $prefixFirst,
|
||||
'HSETNX' => $prefixFirst,
|
||||
'HMSET' => $prefixFirst,
|
||||
'HINCRBY' => $prefixFirst,
|
||||
'HGET' => $prefixFirst,
|
||||
'HMGET' => $prefixFirst,
|
||||
'HDEL' => $prefixFirst,
|
||||
'HEXISTS' => $prefixFirst,
|
||||
'HLEN' => $prefixFirst,
|
||||
'HKEYS' => $prefixFirst,
|
||||
'HVALS' => $prefixFirst,
|
||||
'HGETALL' => $prefixFirst,
|
||||
'SUBSCRIBE' => $prefixAll,
|
||||
'UNSUBSCRIBE' => $prefixAll,
|
||||
'PSUBSCRIBE' => $prefixAll,
|
||||
'PUNSUBSCRIBE' => $prefixAll,
|
||||
'PUBLISH' => $prefixFirst,
|
||||
/* ---------------- Redis 2.2 ---------------- */
|
||||
'PERSIST' => 'static::first',
|
||||
'STRLEN' => 'static::first',
|
||||
'SETRANGE' => 'static::first',
|
||||
'GETRANGE' => 'static::first',
|
||||
'SETBIT' => 'static::first',
|
||||
'GETBIT' => 'static::first',
|
||||
'RPUSHX' => 'static::first',
|
||||
'LPUSHX' => 'static::first',
|
||||
'LINSERT' => 'static::first',
|
||||
'BRPOPLPUSH' => 'static::skipLast',
|
||||
'ZREVRANGEBYSCORE' => 'static::first',
|
||||
'WATCH' => 'static::all',
|
||||
'PERSIST' => $prefixFirst,
|
||||
'STRLEN' => $prefixFirst,
|
||||
'SETRANGE' => $prefixFirst,
|
||||
'GETRANGE' => $prefixFirst,
|
||||
'SETBIT' => $prefixFirst,
|
||||
'GETBIT' => $prefixFirst,
|
||||
'RPUSHX' => $prefixFirst,
|
||||
'LPUSHX' => $prefixFirst,
|
||||
'LINSERT' => $prefixFirst,
|
||||
'BRPOPLPUSH' => $prefixSkipLast,
|
||||
'ZREVRANGEBYSCORE' => $prefixFirst,
|
||||
'WATCH' => $prefixAll,
|
||||
/* ---------------- Redis 2.6 ---------------- */
|
||||
'PTTL' => 'static::first',
|
||||
'PEXPIRE' => 'static::first',
|
||||
'PEXPIREAT' => 'static::first',
|
||||
'PSETEX' => 'static::first',
|
||||
'INCRBYFLOAT' => 'static::first',
|
||||
'BITOP' => 'static::skipFirst',
|
||||
'BITCOUNT' => 'static::first',
|
||||
'HINCRBYFLOAT' => 'static::first',
|
||||
'EVAL' => 'static::evalKeys',
|
||||
'EVALSHA' => 'static::evalKeys',
|
||||
'MIGRATE' => 'static::migrate',
|
||||
'PTTL' => $prefixFirst,
|
||||
'PEXPIRE' => $prefixFirst,
|
||||
'PEXPIREAT' => $prefixFirst,
|
||||
'PSETEX' => $prefixFirst,
|
||||
'INCRBYFLOAT' => $prefixFirst,
|
||||
'BITOP' => $prefixSkipFirst,
|
||||
'BITCOUNT' => $prefixFirst,
|
||||
'HINCRBYFLOAT' => $prefixFirst,
|
||||
'EVAL' => $prefixEvalKeys,
|
||||
'EVALSHA' => $prefixEvalKeys,
|
||||
'MIGRATE' => $prefixMigrate,
|
||||
/* ---------------- Redis 2.8 ---------------- */
|
||||
'SSCAN' => 'static::first',
|
||||
'ZSCAN' => 'static::first',
|
||||
'HSCAN' => 'static::first',
|
||||
'PFADD' => 'static::first',
|
||||
'PFCOUNT' => 'static::all',
|
||||
'PFMERGE' => 'static::all',
|
||||
'ZLEXCOUNT' => 'static::first',
|
||||
'ZRANGEBYLEX' => 'static::first',
|
||||
'ZREMRANGEBYLEX' => 'static::first',
|
||||
'ZREVRANGEBYLEX' => 'static::first',
|
||||
'BITPOS' => 'static::first',
|
||||
'SSCAN' => $prefixFirst,
|
||||
'ZSCAN' => $prefixFirst,
|
||||
'HSCAN' => $prefixFirst,
|
||||
'PFADD' => $prefixFirst,
|
||||
'PFCOUNT' => $prefixAll,
|
||||
'PFMERGE' => $prefixAll,
|
||||
'ZLEXCOUNT' => $prefixFirst,
|
||||
'ZRANGEBYLEX' => $prefixFirst,
|
||||
'ZREMRANGEBYLEX' => $prefixFirst,
|
||||
'ZREVRANGEBYLEX' => $prefixFirst,
|
||||
'BITPOS' => $prefixFirst,
|
||||
/* ---------------- Redis 3.2 ---------------- */
|
||||
'HSTRLEN' => 'static::first',
|
||||
'BITFIELD' => 'static::first',
|
||||
'GEOADD' => 'static::first',
|
||||
'GEOHASH' => 'static::first',
|
||||
'GEOPOS' => 'static::first',
|
||||
'GEODIST' => 'static::first',
|
||||
'GEORADIUS' => 'static::georadius',
|
||||
'GEORADIUSBYMEMBER' => 'static::georadius',
|
||||
);
|
||||
'HSTRLEN' => $prefixFirst,
|
||||
'BITFIELD' => $prefixFirst,
|
||||
'GEOADD' => $prefixFirst,
|
||||
'GEOHASH' => $prefixFirst,
|
||||
'GEOPOS' => $prefixFirst,
|
||||
'GEODIST' => $prefixFirst,
|
||||
'GEORADIUS' => $prefixGeoradius,
|
||||
'GEORADIUSBYMEMBER' => $prefixGeoradius,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,7 +209,7 @@ class KeyPrefixProcessor implements ProcessorInterface
|
||||
if ($command instanceof PrefixableCommandInterface) {
|
||||
$command->prefixKeys($this->prefix);
|
||||
} elseif (isset($this->commands[$commandID = strtoupper($command->getId())])) {
|
||||
call_user_func($this->commands[$commandID], $command, $this->prefix);
|
||||
$this->commands[$commandID]($command, $this->prefix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/xadd
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class XADD extends RedisCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'XADD';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$args = array();
|
||||
|
||||
$args[] = $arguments[0];
|
||||
$options = $arguments[3] ?? [];
|
||||
|
||||
if (isset($options['nomkstream']) && $options['nomkstream']) {
|
||||
$args[] = 'NOMKSTREAM';
|
||||
}
|
||||
|
||||
if (isset($options['trim']) && is_array($options['trim'])) {
|
||||
array_push($args, ...$options['trim']);
|
||||
|
||||
if (isset($options['limit'])) {
|
||||
$args[] = 'LIMIT';
|
||||
$args[] = $options['limit'];
|
||||
}
|
||||
}
|
||||
|
||||
// ID, default to * to let Redis set it
|
||||
$args[] = $arguments[2] ?? '*';
|
||||
if (isset($arguments[1]) && is_array($arguments[1])) {
|
||||
foreach ($arguments[1] as $key => $val) {
|
||||
$args[] = $key;
|
||||
$args[] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
parent::setArguments($args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/xdel
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class XDEL extends RedisCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'XDEL';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$arguments = self::normalizeVariadic($arguments);
|
||||
|
||||
parent::setArguments($arguments);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/xlen
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class XLEN extends RedisCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'XLEN';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/xrange
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class XRANGE extends RedisCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'XRANGE';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
if (count($arguments) === 4) {
|
||||
$arguments[] = $arguments[3];
|
||||
$arguments[3] = 'COUNT';
|
||||
}
|
||||
|
||||
parent::setArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function parseResponse($data)
|
||||
{
|
||||
$result = array();
|
||||
foreach ($data as $entry) {
|
||||
$processed = array();
|
||||
$count = count($entry[1]);
|
||||
|
||||
for ($i = 0; $i < $count; ++$i) {
|
||||
$processed[$entry[1][$i]] = $entry[1][++$i];
|
||||
}
|
||||
|
||||
$result[$entry[0]] = $processed;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/xrevrange
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class XREVRANGE extends XRANGE
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'XREVRANGE';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
use Predis\Command\Command as RedisCommand;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/xtrim
|
||||
*
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class XTRIM extends RedisCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'XTRIM';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setArguments(array $arguments)
|
||||
{
|
||||
$args = [];
|
||||
$options = $arguments[3] ?? [];
|
||||
|
||||
$args[] = $arguments[0];
|
||||
// Either e.g. 'MAXLEN' or ['MAXLEN', '~']
|
||||
if (is_array($arguments[1])) {
|
||||
array_push($args, ...$arguments[1]);
|
||||
} else {
|
||||
$args[] = $arguments[1];
|
||||
}
|
||||
|
||||
$args[] = $arguments[2];
|
||||
if (isset($options['limit'])) {
|
||||
$args[] = 'LIMIT';
|
||||
$args[] = $options['limit'];
|
||||
}
|
||||
|
||||
parent::setArguments($args);
|
||||
}
|
||||
}
|
||||
@@ -269,6 +269,12 @@ class SentinelReplication implements ReplicationInterface
|
||||
$parameters['database'] = null;
|
||||
$parameters['username'] = null;
|
||||
|
||||
// don't leak password from between configurations
|
||||
// https://github.com/predis/predis/pull/807/#discussion_r985764770
|
||||
if (! isset($parameters['password'])) {
|
||||
$parameters['password'] = null;
|
||||
}
|
||||
|
||||
if (!isset($parameters['timeout'])) {
|
||||
$parameters['timeout'] = $this->sentinelTimeout;
|
||||
}
|
||||
|
||||
@@ -260,7 +260,7 @@ class StreamConnection extends AbstractConnection
|
||||
$socket = $this->getResource();
|
||||
|
||||
while (($length = strlen($buffer)) > 0) {
|
||||
$written = @fwrite($socket, $buffer);
|
||||
$written = is_resource($socket) ? @fwrite($socket, $buffer) : false;
|
||||
|
||||
if ($length === $written) {
|
||||
return;
|
||||
@@ -304,7 +304,7 @@ class StreamConnection extends AbstractConnection
|
||||
$bytesLeft = ($size += 2);
|
||||
|
||||
do {
|
||||
$chunk = fread($socket, min($bytesLeft, 4096));
|
||||
$chunk = is_resource($socket) ? fread($socket, min($bytesLeft, 4096)) : false;
|
||||
|
||||
if ($chunk === false || $chunk === '') {
|
||||
$this->onConnectionError('Error while reading bytes from the server.');
|
||||
|
||||
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-stream
|
||||
*/
|
||||
class XADD_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider dataFilterArguments
|
||||
*/
|
||||
public function testFilterArguments(array $arguments, array $expected): void
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
public function dataFilterArguments(): array
|
||||
{
|
||||
$data = [];
|
||||
$data[] = [
|
||||
[
|
||||
'stream',
|
||||
['key' => 'val'],
|
||||
'*',
|
||||
['trim' => ['MINID', '~', '0-1'], 'limit' => 5, 'nomkstream' => true]
|
||||
],
|
||||
['stream', 'NOMKSTREAM', 'MINID', '~', '0-1', 'LIMIT', 5, '*', 'key', 'val'],
|
||||
];
|
||||
|
||||
$data[] = [
|
||||
[
|
||||
'stream',
|
||||
['key1' => 'val1', 'key2' => 'val2'],
|
||||
'*',
|
||||
['trim' => ['MINID', '~', '0-1'], 'limit' => 5, 'nomkstream' => true]
|
||||
],
|
||||
['stream', 'NOMKSTREAM', 'MINID', '~', '0-1', 'LIMIT', 5, '*', 'key1', 'val1', 'key2', 'val2'],
|
||||
];
|
||||
|
||||
$data[] = [
|
||||
[
|
||||
'stream',
|
||||
['key' => 'val'],
|
||||
'*',
|
||||
['trim' => ['MINID', '~', '0-1'], 'limit' => 5]
|
||||
],
|
||||
['stream', 'MINID', '~', '0-1', 'LIMIT', 5, '*', 'key', 'val'],
|
||||
];
|
||||
|
||||
$data[] = [
|
||||
[
|
||||
'stream',
|
||||
['key' => 'val'],
|
||||
'*',
|
||||
['trim' => ['MINID', '~', '0-1']]
|
||||
],
|
||||
['stream', 'MINID', '~', '0-1', '*', 'key', 'val'],
|
||||
];
|
||||
|
||||
$data[] = [
|
||||
[
|
||||
'stream',
|
||||
['key' => 'val'],
|
||||
'*',
|
||||
['trim' => ['MINID', '0-1']]
|
||||
],
|
||||
['stream', 'MINID', '0-1', '*', 'key', 'val'],
|
||||
];
|
||||
|
||||
$data[] = [
|
||||
['stream', ['key' => 'val'], '2-3'],
|
||||
['stream', '2-3', 'key', 'val'],
|
||||
];
|
||||
|
||||
$data[] = [
|
||||
['stream', ['key' => 'val']],
|
||||
['stream', '*', 'key', 'val'],
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return 'Predis\Command\Redis\XADD';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'XADD';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testAddsToStreamWithDefaults(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
|
||||
$this->assertSame(1, $redis->xlen('stream'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testAddsToStreamWithSpecificId(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$id = time() . '-123';
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val'], $id);
|
||||
|
||||
$response = $redis->xrange('stream', $id, $id);
|
||||
$this->assertCount(1, $response);
|
||||
$this->assertNotNull($response[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testNomkstreamWhenStreamDoesNotExist(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->xadd('new-stream', ['key' => 'val'], '*', ['nomkstream' => true]);
|
||||
|
||||
$this->assertSame(0, $redis->exists('new-stream'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testNomkstreamWhenStreamExists(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val'], '*', ['nomkstream' => true]);
|
||||
|
||||
$this->assertSame(1, $redis->exists('stream'));
|
||||
$this->assertSame(2, $redis->xlen('stream'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testTrimOnMinidExact(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$id = $redis->xadd('stream', ['key' => 'val']);
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val'], '*', ['trim' => ['MINID', $id]]);
|
||||
|
||||
$this->assertSame(2, $redis->xlen('stream'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testTrimOnMinidInexact(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$config = $redis->config('get', 'stream-node-max-entries');
|
||||
$oldStreamNodeMaxEntries = (int) array_pop($config);
|
||||
$redis->config('set', 'stream-node-max-entries', 2);
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$id = $redis->xadd('stream', ['key' => 'val']);
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val'], '*', ['trim' => ['MINID', '~', $id]]);
|
||||
|
||||
$this->assertSame(3, $redis->xlen('stream'));
|
||||
$redis->config('set', 'stream-node-max-entries', $oldStreamNodeMaxEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testTrimOnMaxlenExact(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val'], '*', ['trim' => ['MAXLEN', 2]]);
|
||||
|
||||
$this->assertSame(2, $redis->xlen('stream'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testTrimOnMaxlenInexact(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$config = $redis->config('get', 'stream-node-max-entries');
|
||||
$oldStreamNodeMaxEntries = (int) array_pop($config);
|
||||
$redis->config('set', 'stream-node-max-entries', 2);
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val'], '*', ['trim' => ['MAXLEN', '~', 2]]);
|
||||
|
||||
$this->assertSame(3, $redis->xlen('stream'));
|
||||
$redis->config('set', 'stream-node-max-entries', $oldStreamNodeMaxEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testTrimOnMaxlenWithLimit(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$config = $redis->config('get', 'stream-node-max-entries');
|
||||
$oldStreamNodeMaxEntries = (int) array_pop($config);
|
||||
$redis->config('set', 'stream-node-max-entries', 2);
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
|
||||
$redis->xadd(
|
||||
'stream',
|
||||
['key' => 'val'],
|
||||
'*',
|
||||
['trim' => ['MAXLEN', '~', 2], 'limit' => 2]
|
||||
);
|
||||
|
||||
$this->assertSame(4, $redis->xlen('stream'));
|
||||
$redis->config('set', 'stream-node-max-entries', $oldStreamNodeMaxEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType(): void
|
||||
{
|
||||
$this->expectException('Predis\Response\ServerException');
|
||||
$this->expectExceptionMessage('Operation against a key holding the wrong kind of value');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('foo', 'bar');
|
||||
$redis->xadd('foo', ['key' => 'val']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-stream
|
||||
*/
|
||||
class XDEL_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return 'Predis\Command\Redis\XDEL';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'XDEL';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments(): void
|
||||
{
|
||||
$arguments = array('stream', 'id1', 'id2', 'id3');
|
||||
$expected = array('stream', 'id1', 'id2', 'id3');
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$this->assertSame(1, $this->getCommand()->parseResponse(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testRemovesSpecifiedMembers(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->xadd('stream', ['key0' => 'val0'], '0-1');
|
||||
$redis->xadd('stream', ['key1' => 'val1'], '1-1');
|
||||
$redis->xadd('stream', ['key2' => 'val2'], '2-1');
|
||||
|
||||
$this->assertSame(2, $redis->xdel('stream', '0-1', '2-1', '99-1'));
|
||||
$this->assertSame(['1-1' => ['key1' => 'val1']], $redis->xrange('stream', '-', '+'));
|
||||
|
||||
$this->assertSame(0, $redis->xdel('stream', '0-1'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType(): void
|
||||
{
|
||||
$this->expectException('Predis\Response\ServerException');
|
||||
$this->expectExceptionMessage('Operation against a key holding the wrong kind of value');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('foo', 'bar');
|
||||
$redis->xdel('foo', 'bar');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-stream
|
||||
*/
|
||||
class XLEN_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return 'Predis\Command\Redis\XLEN';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'XLEN';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments(): void
|
||||
{
|
||||
$arguments = array('key');
|
||||
$expected = array('key');
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$this->assertSame(1, $this->getCommand()->parseResponse(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testReturnsLengthOfList(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$this->assertSame(2, $redis->xlen('stream'));
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$this->assertSame(3, $redis->xlen('stream'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testReturnsZeroLengthOnNonExistingList(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$this->assertSame(0, $redis->llen('stream'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType(): void
|
||||
{
|
||||
$this->expectException('Predis\Response\ServerException');
|
||||
$this->expectExceptionMessage('Operation against a key holding the wrong kind of value');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('foo', 'bar');
|
||||
$redis->xlen('foo');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-stream
|
||||
*/
|
||||
class XRANGE_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return 'Predis\Command\Redis\XRANGE';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'XRANGE';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments(): void
|
||||
{
|
||||
$arguments = array('stream', '0-1', '1-2', 123);
|
||||
$expected = array('stream', '0-1', '1-2', 'COUNT', 123);
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArgumentsNoCount(): void
|
||||
{
|
||||
$arguments = array('stream', '0-1', '1-2');
|
||||
$expected = array('stream', '0-1', '1-2');
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$raw = array(array('0-1', ['key', 'val']));
|
||||
$expected = array('0-1' => ['key' => 'val']);
|
||||
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertSame($expected, $command->parseResponse($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponseMultipleKeys(): void
|
||||
{
|
||||
$raw = array(array('0-1', ['key1', 'val1', 'key2', 'val2']));
|
||||
$expected = array('0-1' => ['key1' => 'val1', 'key2' => 'val2']);
|
||||
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertSame($expected, $command->parseResponse($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testReturnsElementsInRange(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$redis->xadd('stream', ['key' . $i => 'val' . $i], $i . '-1');
|
||||
}
|
||||
|
||||
$this->assertSame(array(), $redis->xrange('stream', '1-1', '0-1'));
|
||||
$this->assertSame(
|
||||
array('0-1' => ['key0' => 'val0']),
|
||||
$redis->xrange('stream', '0-1', '0-1')
|
||||
);
|
||||
$this->assertSame(
|
||||
array('0-1' => ['key0' => 'val0'], '1-1' => ['key1' => 'val1']),
|
||||
$redis->xrange('stream', '0-1', '1-1')
|
||||
);
|
||||
$this->assertSame(
|
||||
array('0-1' => ['key0' => 'val0'], '1-1' => ['key1' => 'val1']),
|
||||
$redis->xrange('stream', '-', '1-1')
|
||||
);
|
||||
$this->assertSame(
|
||||
array('8-1' => ['key8' => 'val8'], '9-1' => ['key9' => 'val9']),
|
||||
$redis->xrange('stream', '8-1', '+')
|
||||
);
|
||||
$this->assertSame(
|
||||
array('5-1' => ['key5' => 'val5'], '6-1' => ['key6' => 'val6']),
|
||||
$redis->xrange('stream', '5-1', '6-1')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testMultipleKeys(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->xadd('stream', ['key1' => 'val1', 'key2' => 'val2'], '0-1');
|
||||
$redis->xadd('stream', ['key1' => 'val1', 'key2' => 'val2'], '1-1');
|
||||
|
||||
$this->assertSame(
|
||||
array(
|
||||
'0-1' => ['key1' => 'val1', 'key2' => 'val2'],
|
||||
'1-1' => ['key1' => 'val1', 'key2' => 'val2'],
|
||||
),
|
||||
$redis->xrange('stream', '-', '+')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType(): void
|
||||
{
|
||||
$this->expectException('Predis\Response\ServerException');
|
||||
$this->expectExceptionMessage('Operation against a key holding the wrong kind of value');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('foo', 'bar');
|
||||
$redis->xrange('foo', '0-1', '1-1');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-stream
|
||||
*/
|
||||
class XREVRANGE_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return 'Predis\Command\Redis\XREVRANGE';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'XREVRANGE';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments(): void
|
||||
{
|
||||
$arguments = array('stream', '1-1', '0-1', 123);
|
||||
$expected = array('stream', '1-1', '0-1', 'COUNT', 123);
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArgumentsNoCount(): void
|
||||
{
|
||||
$arguments = array('stream', '1-1', '0-1');
|
||||
$expected = array('stream', '1-1', '0-1');
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$raw = array(array('0-1', ['key', 'val']));
|
||||
$expected = array('0-1' => ['key' => 'val']);
|
||||
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertSame($expected, $command->parseResponse($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponseMultipleKeys(): void
|
||||
{
|
||||
$raw = array(array('0-1', ['key1', 'val1', 'key2', 'val2']));
|
||||
$expected = array('0-1' => ['key1' => 'val1', 'key2' => 'val2']);
|
||||
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertSame($expected, $command->parseResponse($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testReturnsElementsInRange(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$redis->xadd('stream', ['key' . $i => 'val' . $i], $i . '-1');
|
||||
}
|
||||
|
||||
$this->assertSame(array(), $redis->xrevrange('stream', '0-1', '1-1'));
|
||||
$this->assertSame(
|
||||
array('0-1' => ['key0' => 'val0']),
|
||||
$redis->xrevrange('stream', '0-1', '0-1')
|
||||
);
|
||||
$this->assertSame(
|
||||
array('1-1' => ['key1' => 'val1'], '0-1' => ['key0' => 'val0']),
|
||||
$redis->xrevrange('stream', '1-1', '0-1')
|
||||
);
|
||||
$this->assertSame(
|
||||
array('1-1' => ['key1' => 'val1'], '0-1' => ['key0' => 'val0']),
|
||||
$redis->xrevrange('stream', '1-1', '-')
|
||||
);
|
||||
$this->assertSame(
|
||||
array('9-1' => ['key9' => 'val9'], '8-1' => ['key8' => 'val8']),
|
||||
$redis->xrevrange('stream', '+', '8-1')
|
||||
);
|
||||
$this->assertSame(
|
||||
array('6-1' => ['key6' => 'val6'], '5-1' => ['key5' => 'val5']),
|
||||
$redis->xrevrange('stream', '6-1', '5-1')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testMultipleKeys(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->xadd('stream', ['key1' => 'val1', 'key2' => 'val2'], '0-1');
|
||||
$redis->xadd('stream', ['key1' => 'val1', 'key2' => 'val2'], '1-1');
|
||||
|
||||
$this->assertSame(
|
||||
array(
|
||||
'1-1' => ['key1' => 'val1', 'key2' => 'val2'],
|
||||
'0-1' => ['key1' => 'val1', 'key2' => 'val2'],
|
||||
),
|
||||
$redis->xrevrange('stream', '+', '-')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType(): void
|
||||
{
|
||||
$this->expectException('Predis\Response\ServerException');
|
||||
$this->expectExceptionMessage('Operation against a key holding the wrong kind of value');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('foo', 'bar');
|
||||
$redis->xrevrange('foo', '1-1', '0-1');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) Daniele Alessandri <suppakilla@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Redis;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-stream
|
||||
*/
|
||||
class XTRIM_Test extends PredisCommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand(): string
|
||||
{
|
||||
return 'Predis\Command\Redis\XTRIM';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId(): string
|
||||
{
|
||||
return 'XTRIM';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
* @dataProvider dataFilterArguments
|
||||
*/
|
||||
public function testFilterArguments(array $arguments, array $expected): void
|
||||
{
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
public function dataFilterArguments(): array
|
||||
{
|
||||
return [
|
||||
[
|
||||
['stream', ['MINID', '~'], '0-1', ['limit' => 10]],
|
||||
['stream', 'MINID', '~', '0-1', 'LIMIT', 10],
|
||||
],
|
||||
[
|
||||
['stream', ['MINID'], '0-1', ['limit' => 10]],
|
||||
['stream', 'MINID', '0-1', 'LIMIT', 10],
|
||||
],
|
||||
[
|
||||
['stream', 'MINID', '0-1', ['limit' => 10]],
|
||||
['stream', 'MINID', '0-1', 'LIMIT', 10],
|
||||
],
|
||||
[
|
||||
['stream', 'MINID', '0-1'],
|
||||
['stream', 'MINID', '0-1'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse(): void
|
||||
{
|
||||
$this->assertSame(1, $this->getCommand()->parseResponse(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testTrimOnMaxlenExact(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
|
||||
$res = $redis->xtrim('stream', 'MAXLEN', 2);
|
||||
|
||||
$this->assertSame(1, $res);
|
||||
$this->assertSame(2, $redis->xlen('stream'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testTrimOnMaxlenInexact(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$config = $redis->config('get', 'stream-node-max-entries');
|
||||
$oldStreamNodeMaxEntries = (int) array_pop($config);
|
||||
$redis->config('set', 'stream-node-max-entries', 2);
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
|
||||
$res = $redis->xtrim('stream', ['MAXLEN', '~'], 2);
|
||||
|
||||
$this->assertSame(2, $res);
|
||||
$this->assertSame(3, $redis->xlen('stream'));
|
||||
$redis->config('set', 'stream-node-max-entries', $oldStreamNodeMaxEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testTrimOnMinidExact(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$id = $redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
|
||||
$res = $redis->xtrim('stream', 'MINID', $id);
|
||||
|
||||
$this->assertSame(1, $res);
|
||||
$this->assertSame(2, $redis->xlen('stream'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testTrimOnMinidInexact(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$config = $redis->config('get', 'stream-node-max-entries');
|
||||
$oldStreamNodeMaxEntries = (int) array_pop($config);
|
||||
$redis->config('set', 'stream-node-max-entries', 2);
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$id = $redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
|
||||
$res = $redis->xtrim('stream', ['MINID', '~'], $id);
|
||||
|
||||
$this->assertSame(2, $res);
|
||||
$this->assertSame(3, $redis->xlen('stream'));
|
||||
$redis->config('set', 'stream-node-max-entries', $oldStreamNodeMaxEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 6.2.0
|
||||
*/
|
||||
public function testTrimOnMaxlenWithLimit(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
$config = $redis->config('get', 'stream-node-max-entries');
|
||||
$oldStreamNodeMaxEntries = (int) array_pop($config);
|
||||
$redis->config('set', 'stream-node-max-entries', 2);
|
||||
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
$redis->xadd('stream', ['key' => 'val']);
|
||||
|
||||
$res = $redis->xtrim('stream', ['MAXLEN', '~'], 2, ['limit' => 2]);
|
||||
|
||||
$this->assertSame(2, $res);
|
||||
$this->assertSame(4, $redis->xlen('stream'));
|
||||
$redis->config('set', 'stream-node-max-entries', $oldStreamNodeMaxEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @requiresRedisVersion >= 5.0.0
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType(): void
|
||||
{
|
||||
$this->expectException('Predis\Response\ServerException');
|
||||
$this->expectExceptionMessage('Operation against a key holding the wrong kind of value');
|
||||
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('key', 'foo');
|
||||
$redis->xtrim('key', 'MAXLEN', 2);
|
||||
}
|
||||
}
|
||||
@@ -62,6 +62,7 @@ class SentinelReplicationTest extends PredisTestCase
|
||||
|
||||
$this->assertArrayNotHasKey('database', $parameters, 'Parameter `database` was expected to not exist in connection parameters');
|
||||
$this->assertArrayNotHasKey('username', $parameters, 'Parameter `username` was expected to not exist in connection parameters');
|
||||
$this->assertArrayNotHasKey('password', $parameters, 'Parameter `password` was expected to not exist in connection parameters');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,6 +118,30 @@ class SentinelReplicationTest extends PredisTestCase
|
||||
$this->assertNotNull($parameters->database);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testConnectionParametersInstanceForSentinelConnectionIsNotModifiedEmptyPassword(): void
|
||||
{
|
||||
$sentinel1 = Connection\Parameters::create('tcp://127.0.0.1:5381?role=sentinel&database=1&password=');
|
||||
$sentinel2 = Connection\Parameters::create('tcp://127.0.0.1:5381?role=sentinel&database=1');
|
||||
|
||||
$replication1 = $this->getReplicationConnection('svc', array($sentinel1));
|
||||
$replication2 = $this->getReplicationConnection('svc', array($sentinel2));
|
||||
|
||||
$parameters1 = $replication1->getSentinelConnection()->getParameters();
|
||||
$parameters2 = $replication2->getSentinelConnection()->getParameters();
|
||||
|
||||
$this->assertSame($sentinel1, $parameters1);
|
||||
$this->assertSame($sentinel2, $parameters2);
|
||||
|
||||
$this->assertNull($parameters1->password);
|
||||
$this->assertNull($parameters2->password);
|
||||
|
||||
$this->assertNotNull($parameters1->database);
|
||||
$this->assertNotNull($parameters2->database);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
|
||||
@@ -57,6 +57,29 @@ class StreamConnectionTest extends PredisConnectionTestCase
|
||||
$connection->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testDoesntThrowErrorOnInvalidResource(): void
|
||||
{
|
||||
$this->expectException('Predis\Connection\ConnectionException');
|
||||
|
||||
$cmdSelect = RawCommand::create('SELECT', '1000');
|
||||
$invalidResource = null;
|
||||
|
||||
/** @var NodeConnectionInterface|MockObject */
|
||||
$connection = $this
|
||||
->getMockBuilder($this->getConnectionClass())
|
||||
->onlyMethods(array('getResource'))
|
||||
->setConstructorArgs(array(new Parameters()))
|
||||
->getMock();
|
||||
$connection
|
||||
->method('getResource')
|
||||
->willReturn($invalidResource);
|
||||
|
||||
$connection->writeRequest($cmdSelect);
|
||||
}
|
||||
|
||||
// ******************************************************************** //
|
||||
// ---- INTEGRATION TESTS --------------------------------------------- //
|
||||
// ******************************************************************** //
|
||||
|
||||
Reference in New Issue
Block a user