mirror of
https://github.com/predis/predis.git
synced 2026-08-21 23:21:01 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4bc6f588fc | |||
| 2522a249f3 | |||
| b4e1cfcee7 | |||
| 105bf8a2ee | |||
| 4f16e232a8 | |||
| 703c3ceb90 | |||
| ca2e4aa4a1 | |||
| 477056b862 | |||
| b94e002e90 | |||
| 3aff21f8cc | |||
| 1e142a63e6 | |||
| b67dab9ab1 | |||
| 6ba1890da9 | |||
| ca8ba35fb5 | |||
| 5af2b628f1 | |||
| f4c58b926b | |||
| cb390cf292 |
@@ -1,3 +1,25 @@
|
||||
v0.7.3 (2012-06-01)
|
||||
===============================================================================
|
||||
|
||||
- New commands available in the Redis v2.6 profile (dev): `BITOP`, `BITCOUNT`.
|
||||
|
||||
- When the number of keys `Predis\Commands\ScriptedCommand` is negative, Predis
|
||||
will count from the end of the arguments list to calculate the actual number
|
||||
of keys that will be interpreted as elements for `KEYS` by the underlying
|
||||
`EVAL` command.
|
||||
|
||||
- __FIX__: `examples\CustomDistributionStrategy.php` had a mistyped constructor
|
||||
call and produced a bad distribution due to an error as pointed in ISSUE #63.
|
||||
This bug is limited to the above mentioned example and does not affect the
|
||||
classes implemented in the `Predis\Distribution` namespace.
|
||||
|
||||
- __FIX__: `Predis\Commands\ServerEvalSHA::getScriptHash()` was calculating the
|
||||
hash while it just needs to return the first argument of the command.
|
||||
|
||||
- __FIX__: `Predis\Autoloader` has been modified to allow cascading autoloaders
|
||||
for the `Predis` namespace.
|
||||
|
||||
|
||||
v0.7.2 (2012-04-01)
|
||||
===============================================================================
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ class NaiveDistributionStrategy implements IDistributionStrategy
|
||||
private $nodes;
|
||||
private $nodesCount;
|
||||
|
||||
public function __constructor()
|
||||
public function __construct()
|
||||
{
|
||||
$this->nodes = array();
|
||||
$this->nodesCount = 0;
|
||||
@@ -51,7 +51,7 @@ class NaiveDistributionStrategy implements IDistributionStrategy
|
||||
throw new RuntimeException('No connections');
|
||||
}
|
||||
|
||||
return $this->nodes[$count > 1 ? abs(crc32($key) % $count) : 0];
|
||||
return $this->nodes[$count > 1 ? abs($key % $count) : 0];
|
||||
}
|
||||
|
||||
public function generateKey($value)
|
||||
|
||||
@@ -20,30 +20,47 @@ require 'SharedConfigurations.php';
|
||||
|
||||
use Predis\Commands\ScriptedCommand;
|
||||
|
||||
class IncrementExistingKey extends ScriptedCommand
|
||||
class IncrementExistingKeysBy extends ScriptedCommand
|
||||
{
|
||||
public function getKeysCount()
|
||||
{
|
||||
return 1;
|
||||
// Tell Predis to use all the arguments but the last one as arguments
|
||||
// for KEYS. The last one will be used to populate ARGV.
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function getScript()
|
||||
{
|
||||
return
|
||||
<<<LUA
|
||||
local cmd = redis.call
|
||||
if cmd('exists', KEYS[1]) == 1 then
|
||||
return cmd('incr', KEYS[1])
|
||||
end
|
||||
local cmd, insert = redis.call, table.insert
|
||||
local increment, results = ARGV[1], { }
|
||||
|
||||
for idx, key in ipairs(KEYS) do
|
||||
if cmd('exists', key) == 1 then
|
||||
insert(results, idx, cmd('incrby', key, increment))
|
||||
else
|
||||
insert(results, idx, false)
|
||||
end
|
||||
end
|
||||
|
||||
return results
|
||||
LUA;
|
||||
}
|
||||
}
|
||||
|
||||
$client = new Predis\Client($single_server, '2.6');
|
||||
|
||||
$client->getProfile()->defineCommand('increx', 'IncrementExistingKey');
|
||||
$client->getProfile()->defineCommand('increxby', 'IncrementExistingKeysBy');
|
||||
|
||||
$client->set('foo', 10);
|
||||
$client->mset('foo', 10, 'foobar', 100);
|
||||
|
||||
var_dump($client->increx('foo')); // int(11)
|
||||
var_dump($client->increx('bar')); // NULL
|
||||
var_export($client->increxby('foo', 'foofoo', 'foobar', 50));
|
||||
|
||||
/*
|
||||
array (
|
||||
0 => 60,
|
||||
1 => NULL,
|
||||
2 => 150,
|
||||
)
|
||||
*/
|
||||
|
||||
@@ -52,7 +52,10 @@ class Autoloader
|
||||
{
|
||||
if (0 === strpos($className, $this->prefix)) {
|
||||
$parts = explode('\\', substr($className, $this->prefixLength));
|
||||
require($this->directory.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $parts).'.php');
|
||||
$filepath = $this->directory.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR, $parts).'.php';
|
||||
if (is_file($filepath)) {
|
||||
require($filepath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ use Predis\Transaction\MultiExecContext;
|
||||
*/
|
||||
class Client
|
||||
{
|
||||
const VERSION = '0.7.2';
|
||||
const VERSION = '0.7.3';
|
||||
|
||||
private $options;
|
||||
private $profile;
|
||||
|
||||
@@ -67,6 +67,24 @@ class PrefixHelpers
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the specified prefix to all the arguments but the first one.
|
||||
*
|
||||
* @param ICommand $command Command instance.
|
||||
* @param string $prefix Prefix string.
|
||||
*/
|
||||
public static function skipFirst(ICommand $command, $prefix)
|
||||
{
|
||||
$arguments = $command->getArguments();
|
||||
$length = count($arguments);
|
||||
|
||||
for ($i = 1; $i < $length; $i++) {
|
||||
$arguments[$i] = "$prefix{$arguments[$i]}";
|
||||
}
|
||||
|
||||
$command->setRawArguments($arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the specified prefix to all the arguments but the last one.
|
||||
*
|
||||
|
||||
@@ -60,8 +60,13 @@ abstract class ScriptedCommand extends ServerEval
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
$header = array($this->getScript(), ($keys = $this->getKeysCount()) !== false ? $keys : count($arguments));
|
||||
if (false !== $numkeys = $this->getKeysCount()) {
|
||||
$numkeys = $numkeys >= 0 ? $numkeys : count($arguments) + $numkeys;
|
||||
}
|
||||
else {
|
||||
$numkeys = count($arguments);
|
||||
}
|
||||
|
||||
return array_merge($header, $arguments);
|
||||
return array_merge(array($this->getScript(), $numkeys), $arguments);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +24,14 @@ class ServerEvalSHA extends ServerEval
|
||||
{
|
||||
return 'EVALSHA';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SHA1 hash of the body of the script.
|
||||
*
|
||||
* @return string SHA1 hash.
|
||||
*/
|
||||
public function getScriptHash()
|
||||
{
|
||||
return $this->getArgument(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?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\Commands;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/bitcount
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class StringBitCount extends PrefixableCommand
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'BITCOUNT';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?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\Commands;
|
||||
|
||||
/**
|
||||
* @link http://redis.io/commands/bitop
|
||||
* @author Daniele Alessandri <suppakilla@gmail.com>
|
||||
*/
|
||||
class StringBitOp extends Command implements IPrefixable
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getId()
|
||||
{
|
||||
return 'BITOP';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function filterArguments(Array $arguments)
|
||||
{
|
||||
if (count($arguments) === 3 && is_array($arguments[2])) {
|
||||
list($operation, $destination, ) = $arguments;
|
||||
$arguments = $arguments[2];
|
||||
array_unshift($arguments, $operation, $destination);
|
||||
}
|
||||
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function prefixKeys($prefix)
|
||||
{
|
||||
PrefixHelpers::skipFirst($this, $prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function canBeHashed()
|
||||
{
|
||||
return $this->checkSameHashForKeys(
|
||||
array_slice(($args = $this->getArguments()), 1, count($args))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,16 @@ abstract class MultiBulkResponse implements \Iterator, \Countable
|
||||
return $this->replySize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current position of the iterator.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPosition()
|
||||
{
|
||||
return $this->position;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
||||
@@ -28,7 +28,7 @@ class MultiBulkResponseTuple extends MultiBulkResponse implements \OuterIterator
|
||||
{
|
||||
$virtualSize = count($iterator) / 2;
|
||||
$this->iterator = $iterator;
|
||||
$this->position = 0;
|
||||
$this->position = $iterator->getPosition();
|
||||
$this->current = $virtualSize > 0 ? $this->getValue() : null;
|
||||
$this->replySize = $virtualSize;
|
||||
}
|
||||
|
||||
@@ -409,6 +409,8 @@ class MasterSlaveReplication implements IConnectionReplication
|
||||
'ECHO' => true,
|
||||
'QUIT' => true,
|
||||
'OBJECT' => true,
|
||||
'BITCOUNT' => true,
|
||||
'TIME' => true,
|
||||
'SORT' => array($this, 'isSortReadOnly'),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -257,7 +257,8 @@ class PhpiredisConnection extends ConnectionBase
|
||||
* @param IConnectionParameters $parameters Parameters used to initialize the connection.
|
||||
* @return string
|
||||
*/
|
||||
private function connectWithTimeout(IConnectionParameters $parameters) {
|
||||
private function connectWithTimeout(IConnectionParameters $parameters)
|
||||
{
|
||||
$host = self::getAddress($parameters);
|
||||
$socket = $this->getResource();
|
||||
|
||||
|
||||
@@ -186,7 +186,8 @@ class StreamConnection extends ConnectionBase
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read() {
|
||||
public function read()
|
||||
{
|
||||
$socket = $this->getResource();
|
||||
|
||||
$chunk = fgets($socket);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
namespace Predis\Pipeline;
|
||||
|
||||
use Predis\Network\IConnection;
|
||||
use Predis\Network\IConnectionReplication;
|
||||
|
||||
/**
|
||||
* Implements a pipeline executor strategy that writes a list of commands to
|
||||
@@ -21,11 +22,27 @@ use Predis\Network\IConnection;
|
||||
*/
|
||||
class FireAndForgetExecutor implements IPipelineExecutor
|
||||
{
|
||||
/**
|
||||
* Allows the pipeline executor to perform operations on the
|
||||
* connection before starting to execute the commands stored
|
||||
* in the pipeline.
|
||||
*
|
||||
* @param IConnection Connection instance.
|
||||
*/
|
||||
protected function checkConnection(IConnection $connection)
|
||||
{
|
||||
if ($connection instanceof IConnectionReplication) {
|
||||
$connection->switchTo('master');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function execute(IConnection $connection, &$commands)
|
||||
{
|
||||
$this->checkConnection($connection);
|
||||
|
||||
foreach ($commands as $command) {
|
||||
$connection->writeCommand($command);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ use Predis\Client;
|
||||
use Predis\Helpers;
|
||||
use Predis\ClientException;
|
||||
use Predis\Commands\ICommand;
|
||||
use Predis\Network\IConnectionReplication;
|
||||
|
||||
/**
|
||||
* Abstraction of a pipeline context where write and read operations
|
||||
@@ -121,13 +120,6 @@ class PipelineContext
|
||||
if (count($this->pipeline) > 0) {
|
||||
if ($send) {
|
||||
$connection = $this->client->getConnection();
|
||||
|
||||
// TODO: it would be better to use a dedicated pipeline executor
|
||||
// for classes implementing master/slave replication.
|
||||
if ($connection instanceof IConnectionReplication) {
|
||||
$connection->switchTo('master');
|
||||
}
|
||||
|
||||
$replies = $this->executor->execute($connection, $this->pipeline);
|
||||
$this->replies = array_merge($this->replies, $replies);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Predis\Pipeline;
|
||||
|
||||
use Predis\ServerException;
|
||||
use Predis\Network\IConnection;
|
||||
use Predis\Network\IConnectionReplication;
|
||||
|
||||
/**
|
||||
* Implements the standard pipeline executor strategy used
|
||||
@@ -23,6 +24,20 @@ use Predis\Network\IConnection;
|
||||
*/
|
||||
class StandardExecutor implements IPipelineExecutor
|
||||
{
|
||||
/**
|
||||
* Allows the pipeline executor to perform operations on the
|
||||
* connection before starting to execute the commands stored
|
||||
* in the pipeline.
|
||||
*
|
||||
* @param IConnection Connection instance.
|
||||
*/
|
||||
protected function checkConnection(IConnection $connection)
|
||||
{
|
||||
if ($connection instanceof IConnectionReplication) {
|
||||
$connection->switchTo('master');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
@@ -31,6 +46,8 @@ class StandardExecutor implements IPipelineExecutor
|
||||
$sizeofPipe = count($commands);
|
||||
$values = array();
|
||||
|
||||
$this->checkConnection($connection);
|
||||
|
||||
foreach ($commands as $command) {
|
||||
$connection->writeCommand($command);
|
||||
}
|
||||
|
||||
@@ -217,6 +217,8 @@ class ServerVersion26 extends ServerProfile
|
||||
/* commands operating on string values */
|
||||
'psetex' => 'Predis\Commands\StringPreciseSetExpire',
|
||||
'incrbyfloat' => 'Predis\Commands\StringIncrementByFloat',
|
||||
'bitop' => 'Predis\Commands\StringBitOp',
|
||||
'bitcount' => 'Predis\Commands\StringBitCount',
|
||||
|
||||
/* commands operating on hashes */
|
||||
'hincrbyfloat' => 'Predis\Commands\HashIncrementByFloat',
|
||||
|
||||
+4
-5
@@ -1,9 +1,8 @@
|
||||
; This file is meant to be used with Onion http://c9s.github.com/Onion/
|
||||
; In order to be able to build a PEAR package of Predis, open a new terminal
|
||||
; session and follow these two easy steps:
|
||||
; For instructions on how to build a PEAR package of Predis please follow
|
||||
; the instructions at this URL:
|
||||
;
|
||||
; $ wget https://github.com/c9s/Onion/raw/master/onion.phar
|
||||
; $ /usr/bin/env php onion.phar build
|
||||
; https://github.com/c9s/Onion#a-quick-tutorial-for-building-pear-package
|
||||
;
|
||||
|
||||
[package]
|
||||
@@ -11,7 +10,7 @@ name = "Predis"
|
||||
desc = "Flexible and feature-complete PHP client library for Redis"
|
||||
homepage = "http://github.com/nrk/predis"
|
||||
license = "MIT"
|
||||
version = "0.7.2"
|
||||
version = "0.7.3"
|
||||
stability = "stable"
|
||||
channel = "pear.nrk.io"
|
||||
|
||||
|
||||
@@ -39,6 +39,25 @@ class ScriptedCommandTest extends StandardTestCase
|
||||
$this->assertSame(array_merge(array(self::LUA_SCRIPT, 2), $arguments), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testGetArgumentsWithNegativeKeysCount()
|
||||
{
|
||||
$arguments = array('key1', 'key2', 'value1', 'value2');
|
||||
|
||||
$command = $this->getMock('Predis\Commands\ScriptedCommand', array('getScript', 'getKeysCount'));
|
||||
$command->expects($this->once())
|
||||
->method('getScript')
|
||||
->will($this->returnValue(self::LUA_SCRIPT));
|
||||
$command->expects($this->once())
|
||||
->method('getKeysCount')
|
||||
->will($this->returnValue(-2));
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame(array_merge(array(self::LUA_SCRIPT, 2), $arguments), $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
@@ -58,6 +77,25 @@ class ScriptedCommandTest extends StandardTestCase
|
||||
$this->assertSame(array('key1', 'key2'), $command->getKeys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testGetKeysWithNegativeKeysCount()
|
||||
{
|
||||
$arguments = array('key1', 'key2', 'value1', 'value2');
|
||||
|
||||
$command = $this->getMock('Predis\Commands\ScriptedCommand', array('getScript', 'getKeysCount'));
|
||||
$command->expects($this->once())
|
||||
->method('getScript')
|
||||
->will($this->returnValue(self::LUA_SCRIPT));
|
||||
$command->expects($this->exactly(2))
|
||||
->method('getKeysCount')
|
||||
->will($this->returnValue(-2));
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame(array('key1', 'key2'), $command->getKeys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
@@ -80,6 +118,28 @@ class ScriptedCommandTest extends StandardTestCase
|
||||
$this->assertSame($expected, $command->getKeys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeysWithNegativeKeysCount()
|
||||
{
|
||||
$arguments = array('foo', 'hoge', 'bar', 'piyo');
|
||||
$expected = array('prefix:foo', 'prefix:hoge');
|
||||
|
||||
$command = $this->getMock('Predis\Commands\ScriptedCommand', array('getScript', 'getKeysCount'));
|
||||
$command->expects($this->once())
|
||||
->method('getScript')
|
||||
->will($this->returnValue(self::LUA_SCRIPT));
|
||||
$command->expects($this->exactly(2))
|
||||
->method('getKeysCount')
|
||||
->will($this->returnValue(-2));
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame($expected, $command->getKeys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
|
||||
@@ -75,6 +75,15 @@ class ServerEvalSHATest extends CommandTestCase
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testGetScriptHash()
|
||||
{
|
||||
$command = $this->getCommandWithArgumentsArray(array($sha1 = sha1('return true')), 0);
|
||||
$this->assertSame($sha1, $command->getScriptHash());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
<?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\Commands;
|
||||
|
||||
use \PHPUnit_Framework_TestCase as StandardTestCase;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-string
|
||||
*/
|
||||
class StringBitCountTest extends CommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand()
|
||||
{
|
||||
return 'Predis\Commands\StringBitCount';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId()
|
||||
{
|
||||
return 'BITCOUNT';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments()
|
||||
{
|
||||
$arguments = array('key', 0, 10);
|
||||
$expected = array('key', 0, 10);
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse()
|
||||
{
|
||||
$raw = 10;
|
||||
$expected = 10;
|
||||
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertSame($expected, $command->parseResponse($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeys()
|
||||
{
|
||||
$arguments = array('key', 0, 10);
|
||||
$expected = array('prefix:key', 0, 10);
|
||||
|
||||
$command = $this->getCommandWithArgumentsArray($arguments);
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testReturnsNumberOfBitsSet()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->setbit('key', 1, 1);
|
||||
$redis->setbit('key', 10, 1);
|
||||
$redis->setbit('key', 16, 1);
|
||||
$redis->setbit('key', 22, 1);
|
||||
$redis->setbit('key', 32, 1);
|
||||
|
||||
$this->assertSame(5, $redis->bitcount('key'), 'Count bits set (without range)');
|
||||
$this->assertSame(3, $redis->bitcount('key', 2, 4), 'Count bits set (with range)');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnWrongType()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->lpush('key', 'list');
|
||||
$redis->bitcount('key');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
<?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\Commands;
|
||||
|
||||
use \PHPUnit_Framework_TestCase as StandardTestCase;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
* @group realm-string
|
||||
*/
|
||||
class StringBitOpTest extends CommandTestCase
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedCommand()
|
||||
{
|
||||
return 'Predis\Commands\StringBitOp';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function getExpectedId()
|
||||
{
|
||||
return 'BITOP';
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArguments()
|
||||
{
|
||||
$arguments = array('AND', 'key:dst', 'key:01', 'key:02');
|
||||
$expected = array('AND', 'key:dst', 'key:01', 'key:02');
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testFilterArgumentsKeysAsSingleArray()
|
||||
{
|
||||
$arguments = array('AND', 'key:dst', array('key:01', 'key:02'));
|
||||
$expected = array('AND', 'key:dst', 'key:01', 'key:02');
|
||||
|
||||
$command = $this->getCommand();
|
||||
$command->setArguments($arguments);
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testParseResponse()
|
||||
{
|
||||
$raw = 10;
|
||||
$expected = 10;
|
||||
|
||||
$command = $this->getCommand();
|
||||
|
||||
$this->assertSame($expected, $command->parseResponse($raw));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group disconnected
|
||||
*/
|
||||
public function testPrefixKeys()
|
||||
{
|
||||
$arguments = array('AND', 'key:dst', 'key:01', 'key:02');
|
||||
$expected = array('AND', 'prefix:key:dst', 'prefix:key:01', 'prefix:key:02');
|
||||
|
||||
$command = $this->getCommandWithArgumentsArray($arguments);
|
||||
$command->prefixKeys('prefix:');
|
||||
|
||||
$this->assertSame($expected, $command->getArguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testCanPerformBitwiseAND()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('key:src:1', "h\x80");
|
||||
$redis->set('key:src:2', "R");
|
||||
|
||||
$this->assertSame(2, $redis->bitop('AND', 'key:dst', 'key:src:1', 'key:src:2'));
|
||||
$this->assertSame("@\x00", $redis->get('key:dst'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testCanPerformBitwiseOR()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('key:src:1', "h\x80");
|
||||
$redis->set('key:src:2', "R");
|
||||
|
||||
$this->assertSame(2, $redis->bitop('OR', 'key:dst', 'key:src:1', 'key:src:2'));
|
||||
$this->assertSame("z\x80", $redis->get('key:dst'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testCanPerformBitwiseXOR()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('key:src:1', "h\x80");
|
||||
$redis->set('key:src:2', "R");
|
||||
|
||||
$this->assertSame(2, $redis->bitop('XOR', 'key:dst', 'key:src:1', 'key:src:2'));
|
||||
$this->assertSame(":\x80", $redis->get('key:dst'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testCanPerformBitwiseNOT()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->set('key:src:1', "h\x80");
|
||||
|
||||
$this->assertSame(2, $redis->bitop('NOT', 'key:dst', 'key:src:1'));
|
||||
$this->assertSame("\x97\x7f", $redis->get('key:dst'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR BITOP NOT must be called with a single source key.
|
||||
*/
|
||||
public function testBitwiseNOTAcceptsOnlyOneSourceKey()
|
||||
{
|
||||
$this->getClient()->bitop('NOT', 'key:dst', 'key:src:1', 'key:src:2');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR syntax error
|
||||
*/
|
||||
public function testThrowsExceptionOnInvalidOperation()
|
||||
{
|
||||
$this->getClient()->bitop('NOOP', 'key:dst', 'key:src:1', 'key:src:2');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @expectedException Predis\ServerException
|
||||
* @expectedExceptionMessage ERR Operation against a key holding the wrong kind of value
|
||||
*/
|
||||
public function testThrowsExceptionOnInvalidSourceKey()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->lpush('key:src:1', 'list');
|
||||
$redis->bitop('AND', 'key:dst', 'key:src:1', 'key:src:2');
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
*/
|
||||
public function testDoesNotThrowExceptionOnInvalidDestinationKey()
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->lpush('key:dst', 'list');
|
||||
$redis->bitop('AND', 'key:dst', 'key:src:1', 'key:src:2');
|
||||
|
||||
$this->assertSame('none', $redis->type('key:dst'));
|
||||
}
|
||||
}
|
||||
@@ -164,11 +164,13 @@ class ServerVersion26Test extends ServerVersionTestCase
|
||||
123 => 'pexpireat',
|
||||
124 => 'psetex',
|
||||
125 => 'incrbyfloat',
|
||||
126 => 'hincrbyfloat',
|
||||
127 => 'eval',
|
||||
128 => 'evalsha',
|
||||
129 => 'script',
|
||||
130 => 'time',
|
||||
126 => 'bitop',
|
||||
127 => 'bitcount',
|
||||
128 => 'hincrbyfloat',
|
||||
129 => 'eval',
|
||||
130 => 'evalsha',
|
||||
131 => 'script',
|
||||
132 => 'time',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,11 +164,13 @@ class ServerVersionNextTest extends ServerVersionTestCase
|
||||
123 => 'pexpireat',
|
||||
124 => 'psetex',
|
||||
125 => 'incrbyfloat',
|
||||
126 => 'hincrbyfloat',
|
||||
127 => 'eval',
|
||||
128 => 'evalsha',
|
||||
129 => 'script',
|
||||
130 => 'time',
|
||||
126 => 'bitop',
|
||||
127 => 'bitcount',
|
||||
128 => 'hincrbyfloat',
|
||||
129 => 'eval',
|
||||
130 => 'evalsha',
|
||||
131 => 'script',
|
||||
132 => 'time',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user