mirror of
https://github.com/predis/predis.git
synced 2026-08-30 12:15:03 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ccb48a1857 | |||
| 2fc80a5f0d | |||
| 49e151a3d0 | |||
| 7d181160a3 |
@@ -1,3 +1,64 @@
|
||||
v0.6.2 (2010-11-28)
|
||||
* Minor internal improvements and clean ups.
|
||||
|
||||
* New commands available in the Redis v2.2 profile (dev):
|
||||
- Strings: STRLEN
|
||||
- Lists : LINSERT, RPUSHX, LPUSHX
|
||||
- ZSets : ZREVRANGEBYSCORE
|
||||
- Misc. : PERSIST
|
||||
|
||||
* WATCH also accepts a single array parameter with the keys that should be
|
||||
monitored during a transaction.
|
||||
|
||||
* Improved the behaviour of Predis_MultiExecBlock in certain corner cases.
|
||||
|
||||
* Improved parameters checking for the SORT command.
|
||||
|
||||
* FIX: the STORE parameter for the SORT command didn't work correctly when
|
||||
using '0' as the target key (ISSUE #13).
|
||||
|
||||
* FIX: the methods for UNWATCH and DISCARD do not break anymore method
|
||||
chaining with Predis\MultiExecBlock.
|
||||
|
||||
v0.6.1 (2010-07-11)
|
||||
* Minor internal improvements and clean ups.
|
||||
|
||||
* New commands available in the Redis v2.2 profile (dev):
|
||||
- Misc. : WATCH, UNWATCH
|
||||
|
||||
* Optional modifiers for ZRANGE, ZREVRANGE and ZRANGEBYSCORE queries are
|
||||
supported using an associative array passed as the last argument of their
|
||||
respective methods.
|
||||
|
||||
* The LIMIT modifier for ZRANGEBYSCORE can be specified using either:
|
||||
- an indexed array: array($offset, $count)
|
||||
- an associative array: array('offset' => $offset, 'count' => $count)
|
||||
|
||||
* The method Predis_Client::__construct() now accepts also instances of
|
||||
Predis_ConnectionParameters.
|
||||
|
||||
* Predis_MultiExecBlock and Predis_PubSubContext now throw an exception
|
||||
when trying to create their instances using a profile that does not
|
||||
support the required Redis commands or when the client is connected to
|
||||
a cluster of connections.
|
||||
|
||||
* Various improvements to Predis_MultiExecBlock:
|
||||
- fixes and more consistent behaviour across various usage cases.
|
||||
- support for WATCH and UNWATCH when using the current development
|
||||
profile (Redis v2.2) and aborted transactions.
|
||||
|
||||
* New signature for Predis_Client::multiExec() which is now able to accept
|
||||
an array of options for the underlying instance of Predis_MultiExecBlock.
|
||||
Backwards compatibility with previous releases of Predis is ensured.
|
||||
|
||||
* New signature for Predis_Client::pipeline() which is now able to accept
|
||||
an array of options for the underlying instance of Predis_CommandPipeline.
|
||||
Backwards compatibility with previous releases of Predis is ensured.
|
||||
The method Predis_Client::pipelineSafe() is to be considered deprecated.
|
||||
|
||||
* FIX: The WEIGHT modifier for ZUNIONSTORE and ZINTERSTORE was handled
|
||||
incorrectly with more than two weights specified.
|
||||
|
||||
v0.6.0 (2010-05-24)
|
||||
* Switched to the new multi-bulk request protocol for all of the commands
|
||||
in the Redis 1.2 and Redis 2.0 profiles. Inline and bulk requests are now
|
||||
|
||||
+360
-100
@@ -4,6 +4,9 @@ class PredisException extends Exception { }
|
||||
// Client-side errors
|
||||
class Predis_ClientException extends PredisException { }
|
||||
|
||||
// Aborted multi/exec
|
||||
class Predis_AbortedMultiExec extends PredisException { }
|
||||
|
||||
// Server-side errors
|
||||
class Predis_ServerException extends PredisException {
|
||||
public function toResponseError() {
|
||||
@@ -53,7 +56,7 @@ class Predis_Client {
|
||||
throw new Predis_ClientException('Missing connection parameters');
|
||||
}
|
||||
|
||||
return new Predis_Client($argc === 1 ? $argv[0] : $argv, $serverProfile);
|
||||
return new Predis_Client($argc === 1 ? $argv[0] : $argv, $options);
|
||||
}
|
||||
|
||||
private static function filterClientOptions($options) {
|
||||
@@ -113,7 +116,9 @@ class Predis_Client {
|
||||
}
|
||||
|
||||
private function createConnection($parameters) {
|
||||
$params = new Predis_ConnectionParameters($parameters);
|
||||
$params = $parameters instanceof Predis_ConnectionParameters
|
||||
? $parameters
|
||||
: new Predis_ConnectionParameters($parameters);
|
||||
$connection = new Predis_Connection($params, $this->_responseReader);
|
||||
|
||||
if ($params->password !== null) {
|
||||
@@ -155,7 +160,7 @@ class Predis_Client {
|
||||
}
|
||||
|
||||
public function getClientFor($connectionAlias) {
|
||||
if (!($this->_connection instanceof Predis_ConnectionCluster)) {
|
||||
if (!Predis_Shared_Utils::isCluster($this->_connection)) {
|
||||
throw new Predis_ClientException(
|
||||
'This method is supported only when the client is connected to a cluster of connections'
|
||||
);
|
||||
@@ -170,7 +175,7 @@ class Predis_Client {
|
||||
|
||||
$newClient = new Predis_Client();
|
||||
$newClient->setupClient($this->_options);
|
||||
$newClient->setConnection($this->getConnection($connectionAlias));
|
||||
$newClient->setConnection($connection);
|
||||
return $newClient;
|
||||
}
|
||||
|
||||
@@ -191,7 +196,7 @@ class Predis_Client {
|
||||
return $this->_connection;
|
||||
}
|
||||
else {
|
||||
return $this->_connection instanceof Predis_ConnectionCluster
|
||||
return Predis_Shared_Utils::isCluster($this->_connection)
|
||||
? $this->_connection->getConnectionById($id)
|
||||
: $this->_connection;
|
||||
}
|
||||
@@ -212,7 +217,7 @@ class Predis_Client {
|
||||
|
||||
public function executeCommandOnShards(Predis_Command $command) {
|
||||
$replies = array();
|
||||
if ($this->_connection instanceof Predis_ConnectionCluster) {
|
||||
if (Predis_Shared_Utils::isCluster($this->_connection)) {
|
||||
foreach($this->_connection as $connection) {
|
||||
$replies[] = $connection->executeCommand($command);
|
||||
}
|
||||
@@ -224,22 +229,54 @@ class Predis_Client {
|
||||
}
|
||||
|
||||
public function rawCommand($rawCommandData, $closesConnection = false) {
|
||||
if ($this->_connection instanceof Predis_ConnectionCluster) {
|
||||
if (Predis_Shared_Utils::isCluster($this->_connection)) {
|
||||
throw new Predis_ClientException('Cannot send raw commands when connected to a cluster of Redis servers');
|
||||
}
|
||||
return $this->_connection->rawCommand($rawCommandData, $closesConnection);
|
||||
}
|
||||
|
||||
public function pipeline($pipelineBlock = null) {
|
||||
return $this->pipelineExecute(new Predis_CommandPipeline($this), $pipelineBlock);
|
||||
private function sharedInitializer($argv, $initializer) {
|
||||
$argc = count($argv);
|
||||
if ($argc === 0) {
|
||||
return $this->$initializer();
|
||||
}
|
||||
else if ($argc === 1) {
|
||||
list($arg0) = $argv;
|
||||
return is_array($arg0) ? $this->$initializer($arg0) : $this->$initializer(null, $arg0);
|
||||
}
|
||||
else if ($argc === 2) {
|
||||
list($arg0, $arg1) = $argv;
|
||||
return $this->$initializer($arg0, $arg1);
|
||||
}
|
||||
return $this->$initializer($this, $arguments);
|
||||
}
|
||||
|
||||
public function pipeline(/* arguments */) {
|
||||
$args = func_get_args();
|
||||
return $this->sharedInitializer($args, 'initPipeline');
|
||||
}
|
||||
|
||||
public function pipelineSafe($pipelineBlock = null) {
|
||||
$connection = $this->getConnection();
|
||||
$pipeline = new Predis_CommandPipeline($this, $connection instanceof Predis_Connection
|
||||
? new Predis_Pipeline_SafeExecutor($connection)
|
||||
: new Predis_Pipeline_SafeClusterExecutor($connection)
|
||||
);
|
||||
return $this->initPipeline(array('safe' => true), $pipelineBlock);
|
||||
}
|
||||
|
||||
private function initPipeline(Array $options = null, $pipelineBlock = null) {
|
||||
$pipeline = null;
|
||||
if (isset($options)) {
|
||||
if (isset($options['safe']) && $options['safe'] == true) {
|
||||
$connection = $this->getConnection();
|
||||
$pipeline = new Predis_CommandPipeline($this, $connection instanceof Predis_Connection
|
||||
? new Predis_Pipeline_SafeExecutor($connection)
|
||||
: new Predis_Pipeline_SafeClusterExecutor($connection)
|
||||
);
|
||||
}
|
||||
else {
|
||||
$pipeline = new Predis_CommandPipeline($this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$pipeline = new Predis_CommandPipeline($this);
|
||||
}
|
||||
return $this->pipelineExecute($pipeline, $pipelineBlock);
|
||||
}
|
||||
|
||||
@@ -247,9 +284,14 @@ class Predis_Client {
|
||||
return $block !== null ? $pipeline->execute($block) : $pipeline;
|
||||
}
|
||||
|
||||
public function multiExec($multiExecBlock = null) {
|
||||
$multiExec = new Predis_MultiExecBlock($this);
|
||||
return $multiExecBlock !== null ? $multiExec->execute($multiExecBlock) : $multiExec;
|
||||
public function multiExec(/* arguments */) {
|
||||
$args = func_get_args();
|
||||
return $this->sharedInitializer($args, 'initMultiExec');
|
||||
}
|
||||
|
||||
private function initMultiExec(Array $options = null, $transBlock = null) {
|
||||
$multi = isset($options) ? new Predis_MultiExecBlock($this, $options) : new Predis_MultiExecBlock($this);
|
||||
return $transBlock !== null ? $multi->execute($transBlock) : $multi;
|
||||
}
|
||||
|
||||
public function pubSubContext() {
|
||||
@@ -425,16 +467,15 @@ abstract class Predis_Command {
|
||||
|
||||
public function setArguments(/* arguments */) {
|
||||
$this->_arguments = $this->filterArguments(func_get_args());
|
||||
$this->_hash = null;
|
||||
unset($this->_hash);
|
||||
}
|
||||
|
||||
public function setArgumentsArray(Array $arguments) {
|
||||
$this->_arguments = $this->filterArguments($arguments);
|
||||
$this->_hash = null;
|
||||
unset($this->_hash);
|
||||
}
|
||||
|
||||
protected function getArguments() {
|
||||
// TODO: why getArguments is protected?
|
||||
public function getArguments() {
|
||||
return isset($this->_arguments) ? $this->_arguments : array();
|
||||
}
|
||||
|
||||
@@ -577,8 +618,9 @@ class Predis_ResponseMultiBulkHandler implements Predis_IResponseHandler {
|
||||
$list = array();
|
||||
|
||||
if ($listLength > 0) {
|
||||
$reader = $connection->getResponseReader();
|
||||
for ($i = 0; $i < $listLength; $i++) {
|
||||
$list[] = $connection->getResponseReader()->read($connection);
|
||||
$list[] = $reader->read($connection);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -770,23 +812,58 @@ class Predis_CommandPipeline {
|
||||
}
|
||||
|
||||
class Predis_MultiExecBlock {
|
||||
private $_redisClient, $_commands, $_initialized, $_discarded;
|
||||
private $_initialized, $_discarded, $_insideBlock;
|
||||
private $_redisClient, $_options, $_commands;
|
||||
private $_supportsWatch;
|
||||
|
||||
public function __construct(Predis_Client $redisClient) {
|
||||
public function __construct(Predis_Client $redisClient, Array $options = null) {
|
||||
$this->checkCapabilities($redisClient);
|
||||
$this->_initialized = false;
|
||||
$this->_discarded = false;
|
||||
$this->_insideBlock = false;
|
||||
$this->_redisClient = $redisClient;
|
||||
$this->_options = isset($options) ? $options : array();
|
||||
$this->_commands = array();
|
||||
}
|
||||
|
||||
private function checkCapabilities(Predis_Client $redisClient) {
|
||||
if (Predis_Shared_Utils::isCluster($redisClient->getConnection())) {
|
||||
throw new Predis_ClientException(
|
||||
'Cannot initialize a MULTI/EXEC context over a cluster of connections'
|
||||
);
|
||||
}
|
||||
$profile = $redisClient->getProfile();
|
||||
if ($profile->supportsCommands(array('multi', 'exec', 'discard')) === false) {
|
||||
throw new Predis_ClientException(
|
||||
'The current profile does not support MULTI, EXEC and DISCARD commands'
|
||||
);
|
||||
}
|
||||
$this->_supportsWatch = $profile->supportsCommands(array('watch', 'unwatch'));
|
||||
}
|
||||
|
||||
private function isWatchSupported() {
|
||||
if ($this->_supportsWatch === false) {
|
||||
throw new Predis_ClientException(
|
||||
'The current profile does not support WATCH and UNWATCH commands'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function initialize() {
|
||||
if ($this->_initialized === false) {
|
||||
if (isset($this->_options['watch'])) {
|
||||
$this->watch($this->_options['watch']);
|
||||
}
|
||||
$this->_redisClient->multi();
|
||||
$this->_initialized = true;
|
||||
$this->_discarded = false;
|
||||
}
|
||||
}
|
||||
|
||||
private function setInsideBlock($value) {
|
||||
$this->_insideBlock = $value;
|
||||
}
|
||||
|
||||
public function __call($method, $arguments) {
|
||||
$this->initialize();
|
||||
$command = $this->_redisClient->createCommand($method, $arguments);
|
||||
@@ -800,6 +877,34 @@ class Predis_MultiExecBlock {
|
||||
}
|
||||
}
|
||||
|
||||
public function watch($keys) {
|
||||
$this->isWatchSupported();
|
||||
if ($this->_initialized === true) {
|
||||
throw new Predis_ClientException('WATCH inside MULTI is not allowed');
|
||||
}
|
||||
|
||||
$reply = null;
|
||||
if (is_array($keys)) {
|
||||
$reply = array();
|
||||
foreach ($keys as $key) {
|
||||
$reply = $this->_redisClient->watch($keys);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$reply = $this->_redisClient->watch($keys);
|
||||
}
|
||||
return $reply;
|
||||
}
|
||||
|
||||
public function multi() {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
public function unwatch() {
|
||||
$this->isWatchSupported();
|
||||
$this->_redisClient->unwatch();
|
||||
}
|
||||
|
||||
public function discard() {
|
||||
$this->_redisClient->discard();
|
||||
$this->_commands = array();
|
||||
@@ -807,7 +912,17 @@ class Predis_MultiExecBlock {
|
||||
$this->_discarded = true;
|
||||
}
|
||||
|
||||
public function exec() {
|
||||
return $this->execute();
|
||||
}
|
||||
|
||||
public function execute($block = null) {
|
||||
if ($this->_insideBlock === true) {
|
||||
throw new Predis_ClientException(
|
||||
"Cannot invoke 'execute' or 'exec' inside an active client transaction block"
|
||||
);
|
||||
}
|
||||
|
||||
if ($block && !is_callable($block)) {
|
||||
throw new InvalidArgumentException('Argument passed must be a callable object');
|
||||
}
|
||||
@@ -815,40 +930,52 @@ class Predis_MultiExecBlock {
|
||||
$blockException = null;
|
||||
$returnValues = array();
|
||||
|
||||
try {
|
||||
if ($block !== null) {
|
||||
if ($block !== null) {
|
||||
$this->setInsideBlock(true);
|
||||
try {
|
||||
$block($this);
|
||||
}
|
||||
|
||||
if ($this->_discarded === true) {
|
||||
return;
|
||||
catch (Predis_CommunicationException $exception) {
|
||||
$blockException = $exception;
|
||||
}
|
||||
catch (Predis_ServerException $exception) {
|
||||
$blockException = $exception;
|
||||
}
|
||||
catch (Exception $exception) {
|
||||
$blockException = $exception;
|
||||
if ($this->_initialized === true) {
|
||||
$this->discard();
|
||||
}
|
||||
}
|
||||
$this->setInsideBlock(false);
|
||||
if ($blockException !== null) {
|
||||
throw $blockException;
|
||||
}
|
||||
}
|
||||
|
||||
$execReply = (($reply = $this->_redisClient->exec()) instanceof Iterator
|
||||
? iterator_to_array($reply)
|
||||
: $reply
|
||||
if ($this->_initialized === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
$reply = $this->_redisClient->exec();
|
||||
if ($reply === null) {
|
||||
throw new Predis_AbortedMultiExec('The current transaction has been aborted by the server');
|
||||
}
|
||||
|
||||
$execReply = $reply instanceof Iterator ? iterator_to_array($reply) : $reply;
|
||||
$commands = &$this->_commands;
|
||||
$sizeofReplies = count($execReply);
|
||||
|
||||
if ($sizeofReplies !== count($commands)) {
|
||||
$this->malformedServerResponse('Unexpected number of responses for a Predis_MultiExecBlock');
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $sizeofReplies; $i++) {
|
||||
$returnValues[] = $commands[$i]->parseResponse($execReply[$i] instanceof Iterator
|
||||
? iterator_to_array($execReply[$i])
|
||||
: $execReply[$i]
|
||||
);
|
||||
$commands = &$this->_commands;
|
||||
$sizeofReplies = count($execReply);
|
||||
|
||||
if ($sizeofReplies !== count($commands)) {
|
||||
$this->malformedServerResponse('Unexpected number of responses for a MultiExecBlock');
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $sizeofReplies; $i++) {
|
||||
$returnValues[] = $commands[$i]->parseResponse($execReply[$i] instanceof Iterator
|
||||
? iterator_to_array($execReply[$i])
|
||||
: $execReply[$i]
|
||||
);
|
||||
unset($commands[$i]);
|
||||
}
|
||||
}
|
||||
catch (Exception $exception) {
|
||||
$blockException = $exception;
|
||||
}
|
||||
|
||||
if ($blockException !== null) {
|
||||
throw $blockException;
|
||||
unset($commands[$i]);
|
||||
}
|
||||
|
||||
return $returnValues;
|
||||
@@ -863,25 +990,47 @@ class Predis_PubSubContext implements Iterator {
|
||||
const MESSAGE = 'message';
|
||||
const PMESSAGE = 'pmessage';
|
||||
|
||||
private $_redisClient, $_subscriptions, $_isStillValid, $_position;
|
||||
const STATUS_VALID = 0x0001;
|
||||
const STATUS_SUBSCRIBED = 0x0010;
|
||||
const STATUS_PSUBSCRIBED = 0x0100;
|
||||
|
||||
private $_redisClient, $_position;
|
||||
|
||||
public function __construct(Predis_Client $redisClient) {
|
||||
$this->_redisClient = $redisClient;
|
||||
$this->_isStillValid = true;
|
||||
$this->_subscriptions = false;
|
||||
$this->checkCapabilities($redisClient);
|
||||
$this->_redisClient = $redisClient;
|
||||
$this->_statusFlags = self::STATUS_VALID;
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
if ($this->valid()) {
|
||||
$this->_redisClient->unsubscribe();
|
||||
$this->_redisClient->punsubscribe();
|
||||
$this->closeContext();
|
||||
}
|
||||
}
|
||||
|
||||
private function checkCapabilities(Predis_Client $redisClient) {
|
||||
if (Predis_Shared_Utils::isCluster($redisClient->getConnection())) {
|
||||
throw new Predis_ClientException(
|
||||
'Cannot initialize a PUB/SUB context over a cluster of connections'
|
||||
);
|
||||
}
|
||||
$profile = $redisClient->getProfile();
|
||||
$commands = array('publish', 'subscribe', 'unsubscribe', 'psubscribe', 'punsubscribe');
|
||||
if ($profile->supportsCommands($commands) === false) {
|
||||
throw new Predis_ClientException(
|
||||
'The current profile does not support PUB/SUB related commands'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function isFlagSet($value) {
|
||||
return ($this->_statusFlags & $value) === $value;
|
||||
}
|
||||
|
||||
public function subscribe(/* arguments */) {
|
||||
$args = func_get_args();
|
||||
$this->writeCommand(self::SUBSCRIBE, $args);
|
||||
$this->_subscriptions = true;
|
||||
$this->_statusFlags |= self::STATUS_SUBSCRIBED;
|
||||
}
|
||||
|
||||
public function unsubscribe(/* arguments */) {
|
||||
@@ -892,7 +1041,7 @@ class Predis_PubSubContext implements Iterator {
|
||||
public function psubscribe(/* arguments */) {
|
||||
$args = func_get_args();
|
||||
$this->writeCommand(self::PSUBSCRIBE, $args);
|
||||
$this->_subscriptions = true;
|
||||
$this->_statusFlags |= self::STATUS_PSUBSCRIBED;
|
||||
}
|
||||
|
||||
public function punsubscribe(/* arguments */) {
|
||||
@@ -902,10 +1051,12 @@ class Predis_PubSubContext implements Iterator {
|
||||
|
||||
public function closeContext() {
|
||||
if ($this->valid()) {
|
||||
// TODO: as an optimization, we should not send both
|
||||
// commands if one of them has not been issued.
|
||||
$this->unsubscribe();
|
||||
$this->punsubscribe();
|
||||
if ($this->isFlagSet(self::STATUS_SUBSCRIBED)) {
|
||||
$this->unsubscribe();
|
||||
}
|
||||
if ($this->isFlagSet(self::STATUS_PSUBSCRIBED)) {
|
||||
$this->punsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -930,19 +1081,20 @@ class Predis_PubSubContext implements Iterator {
|
||||
}
|
||||
|
||||
public function next() {
|
||||
if ($this->_isStillValid) {
|
||||
if ($this->isFlagSet(self::STATUS_VALID)) {
|
||||
$this->_position++;
|
||||
}
|
||||
return $this->_position;
|
||||
}
|
||||
|
||||
public function valid() {
|
||||
return $this->_subscriptions && $this->_isStillValid;
|
||||
$subscriptions = self::STATUS_SUBSCRIBED + self::STATUS_PSUBSCRIBED;
|
||||
return $this->isFlagSet(self::STATUS_VALID)
|
||||
&& ($this->_statusFlags & $subscriptions) > 0;
|
||||
}
|
||||
|
||||
private function invalidate() {
|
||||
$this->_isStillValid = false;
|
||||
$this->_subscriptions = false;
|
||||
$this->_statusFlags = 0x0000;
|
||||
}
|
||||
|
||||
private function getValue() {
|
||||
@@ -1379,6 +1531,15 @@ abstract class Predis_RedisServerProfile {
|
||||
return new $profile();
|
||||
}
|
||||
|
||||
public function supportsCommands(Array $commands) {
|
||||
foreach ($commands as $command) {
|
||||
if ($this->supportsCommand($command) === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function supportsCommand($command) {
|
||||
return isset($this->_registeredCommands[$command]);
|
||||
}
|
||||
@@ -1656,6 +1817,27 @@ class Predis_RedisServer_v2_0 extends Predis_RedisServer_v1_2 {
|
||||
|
||||
class Predis_RedisServer_vNext extends Predis_RedisServer_v2_0 {
|
||||
public function getVersion() { return '2.1'; }
|
||||
public function getSupportedCommands() {
|
||||
return array_merge(parent::getSupportedCommands(), array(
|
||||
/* transactions */
|
||||
'watch' => 'Predis_Commands_Watch',
|
||||
'unwatch' => 'Predis_Commands_Unwatch',
|
||||
|
||||
/* commands operating on string values */
|
||||
'strlen' => 'Predis_Commands_Strlen',
|
||||
|
||||
/* commands operating on the key space */
|
||||
'persist' => 'Predis_Commands_Persist',
|
||||
|
||||
/* commands operating on lists */
|
||||
'rpushx' => 'Predis_Commands_ListPushTailX',
|
||||
'lpushx' => 'Predis_Commands_ListPushHeadX',
|
||||
'linsert' => 'Predis_Commands_ListInsert',
|
||||
|
||||
/* commands operating on sorted sets */
|
||||
'zrevrangebyscore' => 'Predis_Commands_ZSetReverseRangeByScore',
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
@@ -1693,7 +1875,6 @@ class Predis_Pipeline_StandardExecutor implements Predis_Pipeline_IPipelineExecu
|
||||
|
||||
class Predis_Pipeline_SafeExecutor implements Predis_Pipeline_IPipelineExecutor {
|
||||
public function execute(Predis_IConnection $connection, &$commands) {
|
||||
$firstServerException = null;
|
||||
$sizeofPipe = count($commands);
|
||||
$values = array();
|
||||
|
||||
@@ -1720,9 +1901,6 @@ class Predis_Pipeline_SafeExecutor implements Predis_Pipeline_IPipelineExecutor
|
||||
$values[] = $exception->toResponseError();
|
||||
}
|
||||
catch (Predis_CommunicationException $exception) {
|
||||
if ($throwExceptions) {
|
||||
throw $exception;
|
||||
}
|
||||
$toAdd = count($commands) - count($values);
|
||||
$values = array_merge($values, array_fill(0, $toAdd, $exception));
|
||||
break;
|
||||
@@ -1952,6 +2130,10 @@ class Predis_Distribution_KetamaPureRing extends Predis_Distribution_HashRing {
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
class Predis_Shared_Utils {
|
||||
public static function isCluster(Predis_IConnection $connection) {
|
||||
return $connection instanceof Predis_ConnectionCluster;
|
||||
}
|
||||
|
||||
public static function onCommunicationException(Predis_CommunicationException $exception) {
|
||||
if ($exception->shouldResetConnection()) {
|
||||
$connection = $exception->getConnection();
|
||||
@@ -2177,6 +2359,10 @@ class Predis_Commands_Substr extends Predis_MultiBulkCommand {
|
||||
public function getCommandId() { return 'SUBSTR'; }
|
||||
}
|
||||
|
||||
class Predis_Commands_Strlen extends Predis_MultiBulkCommand {
|
||||
public function getCommandId() { return 'STRLEN'; }
|
||||
}
|
||||
|
||||
/* commands operating on the key space */
|
||||
class Predis_Commands_Keys extends Predis_MultiBulkCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
@@ -2217,6 +2403,11 @@ class Predis_Commands_ExpireAt extends Predis_MultiBulkCommand {
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class Predis_Commands_Persist extends Predis_MultiBulkCommand {
|
||||
public function getCommandId() { return 'PERSIST'; }
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class Predis_Commands_DatabaseSize extends Predis_MultiBulkCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'DBSIZE'; }
|
||||
@@ -2231,10 +2422,18 @@ class Predis_Commands_ListPushTail extends Predis_MultiBulkCommand {
|
||||
public function getCommandId() { return 'RPUSH'; }
|
||||
}
|
||||
|
||||
class Predis_Commands_ListPushTailX extends Predis_MultiBulkCommand {
|
||||
public function getCommandId() { return 'RPUSHX'; }
|
||||
}
|
||||
|
||||
class Predis_Commands_ListPushHead extends Predis_MultiBulkCommand {
|
||||
public function getCommandId() { return 'LPUSH'; }
|
||||
}
|
||||
|
||||
class Predis_Commands_ListPushHeadX extends Predis_MultiBulkCommand {
|
||||
public function getCommandId() { return 'LPUSHX'; }
|
||||
}
|
||||
|
||||
class Predis_Commands_ListLength extends Predis_MultiBulkCommand {
|
||||
public function getCommandId() { return 'LLEN'; }
|
||||
}
|
||||
@@ -2283,6 +2482,10 @@ class Predis_Commands_ListPopLastBlocking extends Predis_MultiBulkCommand {
|
||||
public function getCommandId() { return 'BRPOP'; }
|
||||
}
|
||||
|
||||
class Predis_Commands_ListInsert extends Predis_MultiBulkCommand {
|
||||
public function getCommandId() { return 'LINSERT'; }
|
||||
}
|
||||
|
||||
/* commands operating on sets */
|
||||
class Predis_Commands_SetAdd extends Predis_MultiBulkCommand {
|
||||
public function getCommandId() { return 'SADD'; }
|
||||
@@ -2376,8 +2579,9 @@ class Predis_Commands_ZSetUnionStore extends Predis_MultiBulkCommand {
|
||||
$finalizedOpts = array();
|
||||
if (isset($opts['WEIGHTS']) && is_array($opts['WEIGHTS'])) {
|
||||
$finalizedOpts[] = 'WEIGHTS';
|
||||
$finalizedOpts[] = $opts['WEIGHTS'][0];
|
||||
$finalizedOpts[] = $opts['WEIGHTS'][1];
|
||||
foreach ($opts['WEIGHTS'] as $weight) {
|
||||
$finalizedOpts[] = $weight;
|
||||
}
|
||||
}
|
||||
if (isset($opts['AGGREGATE'])) {
|
||||
$finalizedOpts[] = 'AGGREGATE';
|
||||
@@ -2392,20 +2596,42 @@ class Predis_Commands_ZSetIntersectionStore extends Predis_Commands_ZSetUnionSto
|
||||
}
|
||||
|
||||
class Predis_Commands_ZSetRange extends Predis_MultiBulkCommand {
|
||||
private $_withScores = false;
|
||||
public function getCommandId() { return 'ZRANGE'; }
|
||||
public function parseResponse($data) {
|
||||
$arguments = $this->getArguments();
|
||||
public function filterArguments(Array $arguments) {
|
||||
if (count($arguments) === 4) {
|
||||
if (strtolower($arguments[3]) === 'withscores') {
|
||||
if ($data instanceof Iterator) {
|
||||
return new Predis_Shared_MultiBulkResponseKVIterator($data);
|
||||
}
|
||||
$result = array();
|
||||
for ($i = 0; $i < count($data); $i++) {
|
||||
$result[] = array($data[$i], $data[++$i]);
|
||||
}
|
||||
return $result;
|
||||
$lastType = gettype($arguments[3]);
|
||||
if ($lastType === 'string' && strtolower($arguments[3]) === 'withscores') {
|
||||
// used for compatibility with older versions
|
||||
$arguments[3] = array('WITHSCORES' => true);
|
||||
$lastType = 'array';
|
||||
}
|
||||
if ($lastType === 'array') {
|
||||
$options = $this->prepareOptions(array_pop($arguments));
|
||||
return array_merge($arguments, $options);
|
||||
}
|
||||
}
|
||||
return $arguments;
|
||||
}
|
||||
protected function prepareOptions($options) {
|
||||
$opts = array_change_key_case($options, CASE_UPPER);
|
||||
$finalizedOpts = array();
|
||||
if (isset($opts['WITHSCORES'])) {
|
||||
$finalizedOpts[] = 'WITHSCORES';
|
||||
$this->_withScores = true;
|
||||
}
|
||||
return $finalizedOpts;
|
||||
}
|
||||
public function parseResponse($data) {
|
||||
if ($this->_withScores) {
|
||||
if ($data instanceof Iterator) {
|
||||
return new Predis_Shared_MultiBulkResponseKVIterator($data);
|
||||
}
|
||||
$result = array();
|
||||
for ($i = 0; $i < count($data); $i++) {
|
||||
$result[] = array($data[$i], $data[++$i]);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
@@ -2417,6 +2643,21 @@ class Predis_Commands_ZSetReverseRange extends Predis_Commands_ZSetRange {
|
||||
|
||||
class Predis_Commands_ZSetRangeByScore extends Predis_Commands_ZSetRange {
|
||||
public function getCommandId() { return 'ZRANGEBYSCORE'; }
|
||||
protected function prepareOptions($options) {
|
||||
$opts = array_change_key_case($options, CASE_UPPER);
|
||||
$finalizedOpts = array();
|
||||
if (isset($opts['LIMIT']) && is_array($opts['LIMIT'])) {
|
||||
$limit = array_change_key_case($opts['LIMIT'], CASE_UPPER);
|
||||
$finalizedOpts[] = 'LIMIT';
|
||||
$finalizedOpts[] = isset($limit['OFFSET']) ? $limit['OFFSET'] : $limit[0];
|
||||
$finalizedOpts[] = isset($limit['COUNT']) ? $limit['COUNT'] : $limit[1];
|
||||
}
|
||||
return array_merge($finalizedOpts, parent::prepareOptions($options));
|
||||
}
|
||||
}
|
||||
|
||||
class Predis_Commands_ZSetReverseRangeByScore extends Predis_Commands_ZSetRangeByScore {
|
||||
public function getCommandId() { return 'ZREVRANGEBYSCORE'; }
|
||||
}
|
||||
|
||||
class Predis_Commands_ZSetCount extends Predis_MultiBulkCommand {
|
||||
@@ -2563,16 +2804,15 @@ class Predis_Commands_Sort extends Predis_MultiBulkCommand {
|
||||
return $arguments;
|
||||
}
|
||||
|
||||
// TODO: add more parameters checks
|
||||
$query = array($arguments[0]);
|
||||
$sortParams = $arguments[1];
|
||||
$sortParams = array_change_key_case($arguments[1], CASE_UPPER);
|
||||
|
||||
if (isset($sortParams['by'])) {
|
||||
if (isset($sortParams['BY'])) {
|
||||
$query[] = 'BY';
|
||||
$query[] = $sortParams['by'];
|
||||
$query[] = $sortParams['BY'];
|
||||
}
|
||||
if (isset($sortParams['get'])) {
|
||||
$getargs = $sortParams['get'];
|
||||
if (isset($sortParams['GET'])) {
|
||||
$getargs = $sortParams['GET'];
|
||||
if (is_array($getargs)) {
|
||||
foreach ($getargs as $getarg) {
|
||||
$query[] = 'GET';
|
||||
@@ -2584,20 +2824,22 @@ class Predis_Commands_Sort extends Predis_MultiBulkCommand {
|
||||
$query[] = $getargs;
|
||||
}
|
||||
}
|
||||
if (isset($sortParams['limit']) && is_array($sortParams['limit'])) {
|
||||
if (isset($sortParams['LIMIT']) && is_array($sortParams['LIMIT'])
|
||||
&& count($sortParams['LIMIT']) == 2) {
|
||||
|
||||
$query[] = 'LIMIT';
|
||||
$query[] = $sortParams['limit'][0];
|
||||
$query[] = $sortParams['limit'][1];
|
||||
$query[] = $sortParams['LIMIT'][0];
|
||||
$query[] = $sortParams['LIMIT'][1];
|
||||
}
|
||||
if (isset($sortParams['sort'])) {
|
||||
$query[] = strtoupper($sortParams['sort']);
|
||||
if (isset($sortParams['SORT'])) {
|
||||
$query[] = strtoupper($sortParams['SORT']);
|
||||
}
|
||||
if (isset($sortParams['alpha']) && $sortParams['alpha'] == true) {
|
||||
if (isset($sortParams['ALPHA']) && $sortParams['ALPHA'] == true) {
|
||||
$query[] = 'ALPHA';
|
||||
}
|
||||
if (isset($sortParams['store']) && $sortParams['store'] == true) {
|
||||
if (isset($sortParams['STORE'])) {
|
||||
$query[] = 'STORE';
|
||||
$query[] = $sortParams['store'];
|
||||
$query[] = $sortParams['STORE'];
|
||||
}
|
||||
|
||||
return $query;
|
||||
@@ -2646,6 +2888,24 @@ class Predis_Commands_Publish extends Predis_MultiBulkCommand {
|
||||
public function getCommandId() { return 'PUBLISH'; }
|
||||
}
|
||||
|
||||
class Predis_Commands_Watch extends Predis_MultiBulkCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'WATCH'; }
|
||||
public function filterArguments(Array $arguments) {
|
||||
if (isset($arguments[0]) && is_array($arguments[0])) {
|
||||
return $arguments[0];
|
||||
}
|
||||
return $arguments;
|
||||
}
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
class Predis_Commands_Unwatch extends Predis_MultiBulkCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
public function getCommandId() { return 'UNWATCH'; }
|
||||
public function parseResponse($data) { return (bool) $data; }
|
||||
}
|
||||
|
||||
/* persistence control commands */
|
||||
class Predis_Commands_Save extends Predis_MultiBulkCommand {
|
||||
public function canBeHashed() { return false; }
|
||||
|
||||
@@ -260,11 +260,15 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
|
||||
|
||||
function testConnection_WriteCommandAndCloseConnection() {
|
||||
$cmd = Predis_RedisServerProfile::getDefault()->createCommand('quit');
|
||||
$connection = new Predis_Connection(RC::getConnectionParameters());
|
||||
$connection->connect();
|
||||
$connection = new Predis_Connection(new Predis_ConnectionParameters(
|
||||
RC::getConnectionArguments() + array('read_write_timeout' => 0.5)
|
||||
));
|
||||
|
||||
$connection->connect();
|
||||
$this->assertTrue($connection->isConnected());
|
||||
$connection->writeCommand($cmd);
|
||||
$connection->disconnect();
|
||||
|
||||
$expectedMessage = 'Error while reading line from the server';
|
||||
$thrownException = null;
|
||||
try {
|
||||
@@ -275,7 +279,6 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
|
||||
}
|
||||
$this->assertType('Predis_CommunicationException', $thrownException);
|
||||
$this->assertEquals($expectedMessage, $thrownException->getMessage());
|
||||
//$this->assertFalse($connection->isConnected());
|
||||
}
|
||||
|
||||
function testConnection_GetSocketOpensConnection() {
|
||||
@@ -370,8 +373,8 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
|
||||
function testResponseReader_OptionExceptionOnError() {
|
||||
$connection = new Predis_Connection(RC::getConnectionParameters());
|
||||
$responseReader = $connection->getResponseReader();
|
||||
$connection->rawCommand("SET key 5\r\nvalue\r\n");
|
||||
$rawCmdUnexpected = "LPUSH key 5\r\nvalue\r\n";
|
||||
$connection->rawCommand("*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n");
|
||||
$rawCmdUnexpected = "*3\r\n$5\r\nLPUSH\r\n$3\r\nkey\r\n$5\r\nvalue\r\n";
|
||||
|
||||
$responseReader->setHandler(
|
||||
Predis_Protocol::PREFIX_ERROR,
|
||||
@@ -499,5 +502,147 @@ class PredisClientFeaturesTestSuite extends PHPUnit_Framework_TestCase {
|
||||
$this->assertEquals('bar', $replies[3][0]);
|
||||
$this->assertEquals('piyo', $replies[3][1]);
|
||||
}
|
||||
|
||||
|
||||
/* Client + MultiExecBlock */
|
||||
|
||||
function testMultiExecBlock_Simple() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
|
||||
$multi = $client->multiExec();
|
||||
|
||||
$this->assertType('Predis_MultiExecBlock', $multi);
|
||||
$this->assertType('Predis_MultiExecBlock', $multi->set('foo', 'bar'));
|
||||
$this->assertType('Predis_MultiExecBlock', $multi->set('hoge', 'piyo'));
|
||||
$this->assertType('Predis_MultiExecBlock', $multi->mset(array(
|
||||
'foofoo' => 'barbar', 'hogehoge' => 'piyopiyo'
|
||||
)));
|
||||
$this->assertType('Predis_MultiExecBlock', $multi->mget(array(
|
||||
'foo', 'hoge', 'foofoo', 'hogehoge'
|
||||
)));
|
||||
|
||||
$replies = $multi->execute();
|
||||
$this->assertType('array', $replies);
|
||||
$this->assertEquals(4, count($replies));
|
||||
$this->assertEquals(4, count($replies[3]));
|
||||
$this->assertEquals('barbar', $replies[3][2]);
|
||||
}
|
||||
|
||||
function testMultiExecBlock_FluentInterface() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
|
||||
$replies = $client->multiExec()->ping()->set('foo', 'bar')->get('foo')->execute();
|
||||
$this->assertType('array', $replies);
|
||||
$this->assertEquals('bar', $replies[2]);
|
||||
}
|
||||
|
||||
function testMultiExecBlock_CallableAnonymousBlock() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
|
||||
$replies = $client->multiExec(p_anon("\$multi", "
|
||||
\$multi->ping();
|
||||
\$multi->set('foo', 'bar');
|
||||
\$multi->get('foo');
|
||||
"));
|
||||
|
||||
$this->assertType('array', $replies);
|
||||
$this->assertEquals('bar', $replies[2]);
|
||||
}
|
||||
|
||||
function testMultiExecBlock_EmptyCallableBlock() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
|
||||
$replies = $client->multiExec(p_anon("\$multi", ""));
|
||||
|
||||
$this->assertEquals(0, count($replies));
|
||||
}
|
||||
|
||||
function testMultiExecBlock_ClientExceptionInCallableBlock() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
|
||||
$expectedMessage = 'TEST';
|
||||
$thrownException = null;
|
||||
try {
|
||||
$client->multiExec(p_anon("\$multi", "
|
||||
\$multi->ping();
|
||||
\$multi->set('foo', 'bar');
|
||||
throw new Predis_ClientException('$expectedMessage');
|
||||
"));
|
||||
}
|
||||
catch (Predis_ClientException $exception) {
|
||||
$thrownException = $exception;
|
||||
}
|
||||
$this->assertType('Predis_ClientException', $thrownException);
|
||||
$this->assertEquals($expectedMessage, $thrownException->getMessage());
|
||||
|
||||
$this->assertFalse($client->exists('foo'));
|
||||
}
|
||||
|
||||
function testMultiExecBlock_ServerExceptionInCallableBlock() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
$client->getResponseReader()->setHandler('-', new Predis_ResponseErrorSilentHandler());
|
||||
|
||||
$multi = $client->multiExec();
|
||||
$multi->set('foo', 'bar');
|
||||
$multi->lpush('foo', 'piyo'); // LIST operation on STRING type returns an ERROR
|
||||
$multi->set('hoge', 'piyo');
|
||||
$replies = $multi->execute();
|
||||
|
||||
$this->assertType('array', $replies);
|
||||
$this->assertType('Predis_ResponseError', $replies[1]);
|
||||
$this->assertTrue($client->exists('foo'));
|
||||
$this->assertTrue($client->exists('hoge'));
|
||||
}
|
||||
|
||||
function testMultiExecBlock_Discard() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
|
||||
$multi = $client->multiExec();
|
||||
$multi->set('foo', 'bar');
|
||||
$multi->discard();
|
||||
$multi->set('hoge', 'piyo');
|
||||
$replies = $multi->execute();
|
||||
|
||||
$this->assertEquals(1, count($replies));
|
||||
$this->assertFalse($client->exists('foo'));
|
||||
$this->assertTrue($client->exists('hoge'));
|
||||
}
|
||||
|
||||
function testMultiExecBlock_DiscardEmpty() {
|
||||
$client = RC::getConnection();
|
||||
$client->flushdb();
|
||||
|
||||
$replies = $client->multiExec()->discard()->execute();
|
||||
$this->assertEquals(0, count($replies));
|
||||
}
|
||||
|
||||
function testMultiExecBlock_Watch() {
|
||||
$client1 = RC::getConnection();
|
||||
$client2 = RC::getConnection(true);
|
||||
$client1->flushdb();
|
||||
|
||||
$thrownException = null;
|
||||
try {
|
||||
$multi = $client1->multiExec(array('watch' => 'sentinel'));
|
||||
$multi->set('sentinel', 'client1');
|
||||
$multi->get('sentinel');
|
||||
$client2->set('sentinel', 'client2');
|
||||
$multi->execute();
|
||||
}
|
||||
catch (PredisException $exception) {
|
||||
$thrownException = $exception;
|
||||
}
|
||||
$this->assertType('Predis_AbortedMultiExec', $thrownException);
|
||||
$this->assertEquals('The current transaction has been aborted by the server', $thrownException->getMessage());
|
||||
|
||||
$this->assertEquals('client2', $client1->get('sentinel'));
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -48,7 +48,10 @@ class RC {
|
||||
return $connection;
|
||||
}
|
||||
|
||||
public static function getConnection() {
|
||||
public static function getConnection($new = false) {
|
||||
if ($new == true) {
|
||||
return self::createConnection();
|
||||
}
|
||||
if (self::$_connection === null || !self::$_connection->isConnected()) {
|
||||
self::$_connection = self::createConnection();
|
||||
}
|
||||
|
||||
@@ -241,6 +241,18 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
|
||||
"));
|
||||
}
|
||||
|
||||
function testStrlen() {
|
||||
$this->redis->set('var', 'foobar');
|
||||
$this->assertEquals(6, $this->redis->strlen('var'));
|
||||
$this->assertEquals(9, $this->redis->append('var', '___'));
|
||||
$this->assertEquals(9, $this->redis->strlen('var'));
|
||||
|
||||
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, p_anon("\$test", "
|
||||
\$test->redis->rpush('metavars', 'foo');
|
||||
\$test->redis->strlen('metavars');
|
||||
"));
|
||||
}
|
||||
|
||||
|
||||
/* commands operating on the key space */
|
||||
|
||||
@@ -369,6 +381,20 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
|
||||
"));
|
||||
}
|
||||
|
||||
function testPushTailX() {
|
||||
$this->assertEquals(0, $this->redis->rpushx('numbers', 1));
|
||||
$this->assertEquals(1, $this->redis->rpush('numbers', 2));
|
||||
$this->assertEquals(2, $this->redis->rpushx('numbers', 3));
|
||||
|
||||
$this->assertEquals(2, $this->redis->llen('numbers'));
|
||||
$this->assertEquals(array(2, 3), $this->redis->lrange('numbers', 0, -1));
|
||||
|
||||
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, p_anon("\$test", "
|
||||
\$test->redis->set('foo', 'bar');
|
||||
\$test->redis->rpushx('foo', 'bar');
|
||||
"));
|
||||
}
|
||||
|
||||
function testPushHead() {
|
||||
// NOTE: List push operations return the list length since Redis commit 520b5a3
|
||||
$this->assertEquals(1, $this->redis->lpush('metavars', 'foo'));
|
||||
@@ -382,6 +408,20 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
|
||||
"));
|
||||
}
|
||||
|
||||
function testPushHeadX() {
|
||||
$this->assertEquals(0, $this->redis->lpushx('numbers', 1));
|
||||
$this->assertEquals(1, $this->redis->lpush('numbers', 2));
|
||||
$this->assertEquals(2, $this->redis->lpushx('numbers', 3));
|
||||
|
||||
$this->assertEquals(2, $this->redis->llen('numbers'));
|
||||
$this->assertEquals(array(3, 2), $this->redis->lrange('numbers', 0, -1));
|
||||
|
||||
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, p_anon("\$test", "
|
||||
\$test->redis->set('foo', 'bar');
|
||||
\$test->redis->lpushx('foo', 'bar');
|
||||
"));
|
||||
}
|
||||
|
||||
function testListLength() {
|
||||
$this->assertEquals(1, $this->redis->rpush('metavars', 'foo'));
|
||||
$this->assertEquals(2, $this->redis->rpush('metavars', 'hoge'));
|
||||
@@ -682,6 +722,22 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
|
||||
$this->assertEquals((float)(time() - $start), 2, '', 1);
|
||||
}
|
||||
|
||||
function testListInsert() {
|
||||
$numbers = RC::pushTailAndReturn($this->redis, 'numbers', RC::getArrayOfNumbers());
|
||||
|
||||
$this->assertEquals(11, $this->redis->linsert('numbers', 'before', 0, -2));
|
||||
$this->assertEquals(12, $this->redis->linsert('numbers', 'after', -2, -1));
|
||||
$this->assertEquals(array(-2, -1, 0, 1), $this->redis->lrange('numbers', 0, 3));
|
||||
|
||||
$this->assertEquals(-1, $this->redis->linsert('numbers', 'after', 100, 200));
|
||||
$this->assertEquals(-1, $this->redis->linsert('numbers', 'before', 100, 50));
|
||||
|
||||
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, p_anon("\$test", "
|
||||
\$test->redis->set('foo', 'bar');
|
||||
\$test->redis->lset('foo', 0, 0);
|
||||
"));
|
||||
}
|
||||
|
||||
|
||||
/* commands operating on sets */
|
||||
|
||||
@@ -1097,6 +1153,11 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
|
||||
$this->redis->zrange('zset', 0, 2, 'withscores')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('a', -10), array('b', 0), array('c', 10)),
|
||||
$this->redis->zrange('zset', 0, 2, array('withscores' => true))
|
||||
);
|
||||
|
||||
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, p_anon("\$test", "
|
||||
\$test->redis->set('foo', 'bar');
|
||||
\$test->redis->zrange('foo', 0, -1);
|
||||
@@ -1151,6 +1212,11 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
|
||||
$this->redis->zrevrange('zset', 0, 2, 'withscores')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('f', 30), array('e', 20), array('d', 20)),
|
||||
$this->redis->zrevrange('zset', 0, 2, array('withscores' => true))
|
||||
);
|
||||
|
||||
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, p_anon("\$test", "
|
||||
\$test->redis->set('foo', 'bar');
|
||||
\$test->redis->zrevrange('foo', 0, -1);
|
||||
@@ -1185,12 +1251,96 @@ class RedisCommandTestSuite extends PHPUnit_Framework_TestCase {
|
||||
$this->redis->zrangebyscore('zset', 10, 20, 'withscores')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('c', 10), array('d', 20), array('e', 20)),
|
||||
$this->redis->zrangebyscore('zset', 10, 20, array('withscores' => true))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('d', 'e'),
|
||||
$this->redis->zrangebyscore('zset', 10, 20, array('limit' => array(1, 2)))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('d', 'e'),
|
||||
$this->redis->zrangebyscore('zset', 10, 20, array(
|
||||
'limit' => array('offset' => 1, 'count' => 2)
|
||||
))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('d', 20), array('e', 20)),
|
||||
$this->redis->zrangebyscore('zset', 10, 20, array(
|
||||
'limit' => array(1, 2),
|
||||
'withscores' => true,
|
||||
))
|
||||
);
|
||||
|
||||
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, p_anon("\$test", "
|
||||
\$test->redis->set('foo', 'bar');
|
||||
\$test->redis->zrangebyscore('foo', 0, 0);
|
||||
"));
|
||||
}
|
||||
|
||||
function testZsetReverseRangeByScore() {
|
||||
$zset = RC::zsetAddAndReturn($this->redis, 'zset', RC::getZSetArray());
|
||||
|
||||
$this->assertEquals(
|
||||
array('a'),
|
||||
$this->redis->zrevrangebyscore('zset', -10, -10)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('b', 'a'),
|
||||
$this->redis->zrevrangebyscore('zset', 0, -10)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('e', 'd'),
|
||||
$this->redis->zrevrangebyscore('zset', 20, 20)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('f', 'e', 'd', 'c', 'b'),
|
||||
$this->redis->zrevrangebyscore('zset', 30, 0)
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('e', 20), array('d', 20), array('c', 10)),
|
||||
$this->redis->zrevrangebyscore('zset', 20, 10, 'withscores')
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('e', 20), array('d', 20), array('c', 10)),
|
||||
$this->redis->zrevrangebyscore('zset', 20, 10, array('withscores' => true))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('d', 'c'),
|
||||
$this->redis->zrevrangebyscore('zset', 20, 10, array('limit' => array(1, 2)))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array('d', 'c'),
|
||||
$this->redis->zrevrangebyscore('zset', 20, 10, array(
|
||||
'limit' => array('offset' => 1, 'count' => 2)
|
||||
))
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('d', 20), array('c', 10)),
|
||||
$this->redis->zrevrangebyscore('zset', 20, 10, array(
|
||||
'limit' => array(1, 2),
|
||||
'withscores' => true,
|
||||
))
|
||||
);
|
||||
|
||||
RC::testForServerException($this, RC::EXCEPTION_WRONG_TYPE, p_anon("\$test", "
|
||||
\$test->redis->set('foo', 'bar');
|
||||
\$test->redis->zrevrangebyscore('foo', 0, 0);
|
||||
"));
|
||||
}
|
||||
|
||||
function testZsetUnionStore() {
|
||||
$zsetA = RC::zsetAddAndReturn($this->redis, 'zseta', array('a' => 1, 'b' => 2, 'c' => 3));
|
||||
$zsetB = RC::zsetAddAndReturn($this->redis, 'zsetb', array('b' => 1, 'c' => 2, 'd' => 3));
|
||||
|
||||
Reference in New Issue
Block a user