diff --git a/lib/Predis/Cluster/PredisStrategy.php b/lib/Predis/Cluster/PredisStrategy.php index f75b043a..e239dae7 100644 --- a/lib/Predis/Cluster/PredisStrategy.php +++ b/lib/Predis/Cluster/PredisStrategy.php @@ -139,6 +139,7 @@ class PredisStrategy implements StrategyInterface 'ZSCORE' => $keyIsFirstArgument, 'ZUNIONSTORE' => array($this, 'getKeyFromZsetAggregationCommands'), 'ZSCAN' => $keyIsFirstArgument, + 'ZLEXCOUNT' => $keyIsFirstArgument, /* commands operating on hashes */ 'HDEL' => $keyIsFirstArgument, diff --git a/lib/Predis/Cluster/RedisStrategy.php b/lib/Predis/Cluster/RedisStrategy.php index 97e7ce0b..e3fcd9fe 100644 --- a/lib/Predis/Cluster/RedisStrategy.php +++ b/lib/Predis/Cluster/RedisStrategy.php @@ -124,6 +124,7 @@ class RedisStrategy implements StrategyInterface 'ZREVRANK' => $keyIsFirstArgument, 'ZSCORE' => $keyIsFirstArgument, 'ZSCAN' => $keyIsFirstArgument, + 'ZLEXCOUNT' => $keyIsFirstArgument, /* commands operating on hashes */ 'HDEL' => $keyIsFirstArgument, diff --git a/lib/Predis/Command/Processor/KeyPrefixProcessor.php b/lib/Predis/Command/Processor/KeyPrefixProcessor.php index 64bac06b..dd19d9af 100644 --- a/lib/Predis/Command/Processor/KeyPrefixProcessor.php +++ b/lib/Predis/Command/Processor/KeyPrefixProcessor.php @@ -152,6 +152,7 @@ class KeyPrefixProcessor implements ProcessorInterface 'PFADD' => 'self::first', 'PFCOUNT' => 'self::all', 'PFMERGE' => 'self::all', + 'ZLEXCOUNT' => 'self::first', ); } diff --git a/lib/Predis/Command/ZSetLexCount.php b/lib/Predis/Command/ZSetLexCount.php new file mode 100644 index 00000000..8af2c1fa --- /dev/null +++ b/lib/Predis/Command/ZSetLexCount.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Command; + +/** + * @link http://redis.io/commands/zlexcount + * @author Daniele Alessandri + */ +class ZSetLexCount extends Command +{ + /** + * {@inheritdoc} + */ + public function getId() + { + return 'ZLEXCOUNT'; + } +} diff --git a/lib/Predis/Profile/RedisVersion280.php b/lib/Predis/Profile/RedisVersion280.php index 8707388b..4c40a755 100644 --- a/lib/Predis/Profile/RedisVersion280.php +++ b/lib/Predis/Profile/RedisVersion280.php @@ -240,6 +240,7 @@ class RedisVersion280 extends RedisProfile /* commands operating on sorted sets */ 'ZSCAN' => 'Predis\Command\ZSetScan', + 'ZLEXCOUNT' => 'Predis\Command\ZSetLexCount', /* commands operating on hashes */ 'HSCAN' => 'Predis\Command\HashScan', diff --git a/lib/Predis/Replication/ReplicationStrategy.php b/lib/Predis/Replication/ReplicationStrategy.php index a8cbdd08..d4006209 100644 --- a/lib/Predis/Replication/ReplicationStrategy.php +++ b/lib/Predis/Replication/ReplicationStrategy.php @@ -204,6 +204,7 @@ class ReplicationStrategy 'ZRANK' => true, 'ZREVRANK' => true, 'ZSCAN' => true, + 'ZLEXCOUNT' => true, 'HGET' => true, 'HMGET' => true, 'HEXISTS' => true, diff --git a/tests/Predis/Cluster/PredisStrategyTest.php b/tests/Predis/Cluster/PredisStrategyTest.php index f9b4730f..488f0afd 100644 --- a/tests/Predis/Cluster/PredisStrategyTest.php +++ b/tests/Predis/Cluster/PredisStrategyTest.php @@ -345,6 +345,7 @@ class PredisStrategyTest extends PredisTestCase 'ZSCORE' => 'keys-first', 'ZUNIONSTORE' => 'keys-zaggregated', 'ZSCAN' => 'keys-first', + 'ZLEXCOUNT' => 'keys-first', /* commands operating on hashes */ 'HDEL' => 'keys-first', diff --git a/tests/Predis/Cluster/RedisStrategyTest.php b/tests/Predis/Cluster/RedisStrategyTest.php index ff3da933..73f5a516 100644 --- a/tests/Predis/Cluster/RedisStrategyTest.php +++ b/tests/Predis/Cluster/RedisStrategyTest.php @@ -342,6 +342,7 @@ class RedisStrategyTest extends PredisTestCase 'ZREVRANK' => 'keys-first', 'ZSCORE' => 'keys-first', 'ZSCAN' => 'keys-first', + 'ZLEXCOUNT' => 'keys-first', /* commands operating on hashes */ 'HDEL' => 'keys-first', diff --git a/tests/Predis/Command/Processor/KeyPrefixProcessorTest.php b/tests/Predis/Command/Processor/KeyPrefixProcessorTest.php index b9c70909..4ad1c674 100644 --- a/tests/Predis/Command/Processor/KeyPrefixProcessorTest.php +++ b/tests/Predis/Command/Processor/KeyPrefixProcessorTest.php @@ -811,6 +811,10 @@ class KeyPrefixProcessorTest extends PredisTestCase array('key:1', 'key:2', 'key:3'), array('prefix:key:1', 'prefix:key:2', 'prefix:key:3'), ), + array('ZLEXCOUNT', + array('key', '-', '+'), + array('prefix:key', '-', '+'), + ), ); } } diff --git a/tests/Predis/Command/ZSetLexCountTest.php b/tests/Predis/Command/ZSetLexCountTest.php new file mode 100644 index 00000000..2cc389bf --- /dev/null +++ b/tests/Predis/Command/ZSetLexCountTest.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Predis\Command; + +/** + * @group commands + * @group realm-zset + */ +class ZSetLexCountTest extends PredisCommandTestCase +{ + /** + * {@inheritdoc} + */ + protected function getExpectedCommand() + { + return 'Predis\Command\ZSetLexCount'; + } + + /** + * {@inheritdoc} + */ + protected function getExpectedId() + { + return 'ZLEXCOUNT'; + } + + /** + * @group disconnected + */ + public function testFilterArguments() + { + $arguments = array('key', '+', '-'); + $expected = array('key', '+', '-'); + + $command = $this->getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse() + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group connected + */ + public function testExclusiveIntervalRange() + { + $this->markTestSkippedOnRedisVersionBelow('2.8.9', 'Lexicographical operations on sorted sets require Redis >= 2.8.9.', true); + + $redis = $this->getClient(); + + $redis->zadd('letters', 0, 'a', 0, 'b', 0, 'c', 0, 'd', 0, 'e', 0, 'f', 0, 'g'); + + $this->assertSame(3, $redis->zlexcount('letters', '(b', '(f')); + $this->assertSame(5, $redis->zlexcount('letters', '(b', '(z')); + $this->assertSame(4, $redis->zlexcount('letters', '(0', '(e')); + $this->assertSame(0, $redis->zlexcount('letters', '(f', '(b')); + } + + /** + * @group connected + */ + public function testInclusiveIntervalRange() + { + $this->markTestSkippedOnRedisVersionBelow('2.8.9', 'Lexicographical operations on sorted sets require Redis >= 2.8.9.', true); + + $redis = $this->getClient(); + + $redis->zadd('letters', 0, 'a', 0, 'b', 0, 'c', 0, 'd', 0, 'e', 0, 'f', 0, 'g'); + + $this->assertSame(5, $redis->zlexcount('letters', '[b', '[f')); + $this->assertSame(6, $redis->zlexcount('letters', '[b', '[z')); + $this->assertSame(5, $redis->zlexcount('letters', '[0', '[e')); + $this->assertSame(0, $redis->zlexcount('letters', '[f', '[b')); + } + + /** + * @group connected + */ + public function testWholeRangeInterval() + { + $this->markTestSkippedOnRedisVersionBelow('2.8.9', 'Lexicographical operations on sorted sets require Redis >= 2.8.9.', true); + + $redis = $this->getClient(); + + $redis->zadd('letters', 0, 'a', 0, 'b', 0, 'c', 0, 'd', 0, 'e', 0, 'f', 0, 'g'); + + $this->assertSame(7, $redis->zlexcount('letters', '-', '+')); + $this->assertSame(0, $redis->zlexcount('letters', '+', '-')); + } + + /** + * @group connected + * @expectedException Predis\Response\ServerException + * @expectedExceptionMessage min or max not valid string range item + */ + public function testThrowsExceptionOnInvalidRangeFormat() + { + $this->markTestSkippedOnRedisVersionBelow('2.8.9', 'Lexicographical operations on sorted sets require Redis >= 2.8.9.', true); + + $redis = $this->getClient(); + + $redis->zadd('letters', 0, 'a', 0, 'b', 0, 'c', 0, 'd', 0, 'e', 0, 'f', 0, 'g'); + $redis->zlexcount('letters', 'b', 'f'); + } + + /** + * @group connected + * @expectedException Predis\Response\ServerException + * @expectedExceptionMessage Operation against a key holding the wrong kind of value + */ + public function testThrowsExceptionOnWrongType() + { + $this->markTestSkippedOnRedisVersionBelow('2.8.9', 'Lexicographical operations on sorted sets require Redis >= 2.8.9.', true); + + $redis = $this->getClient(); + + $redis->set('foo', 'bar'); + $redis->zlexcount('foo', '+', '-'); + } +} diff --git a/tests/Predis/Profile/RedisUnstableTest.php b/tests/Predis/Profile/RedisUnstableTest.php index 2d4ac7e0..9f80dc5b 100644 --- a/tests/Predis/Profile/RedisUnstableTest.php +++ b/tests/Predis/Profile/RedisUnstableTest.php @@ -177,11 +177,12 @@ class RedisUnstableTest extends PredisProfileTestCase 136 => 'SCAN', 137 => 'SSCAN', 138 => 'ZSCAN', - 139 => 'HSCAN', - 140 => 'PUBSUB', - 141 => 'PFADD', - 142 => 'PFCOUNT', - 143 => 'PFMERGE', + 139 => 'ZLEXCOUNT', + 140 => 'HSCAN', + 141 => 'PUBSUB', + 142 => 'PFADD', + 143 => 'PFCOUNT', + 144 => 'PFMERGE', ); } } diff --git a/tests/Predis/Profile/RedisVersion280Test.php b/tests/Predis/Profile/RedisVersion280Test.php index 2063182d..954f5156 100644 --- a/tests/Predis/Profile/RedisVersion280Test.php +++ b/tests/Predis/Profile/RedisVersion280Test.php @@ -177,11 +177,12 @@ class RedisVersion280Test extends PredisProfileTestCase 136 => 'SCAN', 137 => 'SSCAN', 138 => 'ZSCAN', - 139 => 'HSCAN', - 140 => 'PUBSUB', - 141 => 'PFADD', - 142 => 'PFCOUNT', - 143 => 'PFMERGE', + 139 => 'ZLEXCOUNT', + 140 => 'HSCAN', + 141 => 'PUBSUB', + 142 => 'PFADD', + 143 => 'PFCOUNT', + 144 => 'PFMERGE', ); } } diff --git a/tests/Predis/Replication/ReplicationStrategyTest.php b/tests/Predis/Replication/ReplicationStrategyTest.php index 79f4aa36..c306d522 100644 --- a/tests/Predis/Replication/ReplicationStrategyTest.php +++ b/tests/Predis/Replication/ReplicationStrategyTest.php @@ -342,6 +342,7 @@ class ReplicationStrategyTest extends PredisTestCase 'ZREVRANK' => 'read', 'ZSCORE' => 'read', 'ZSCAN' => 'read', + 'ZLEXCOUNT' => 'read', /* commands operating on hashes */ 'HDEL' => 'write',