Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for hash field expiration commands #1456

Open
wants to merge 14 commits into
base: v2.x
Choose a base branch
from
Open
2 changes: 1 addition & 1 deletion .codespellrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ skip=./.git
check-hidden=
check-filenames=
builtin=clear,rare,informal,usage,code,names
ignore-words-list=master,masters,slave,slaves,whitelist,cas,exat,smove,SUGGET,sugget,ro
ignore-words-list=master,masters,slave,slaves,whitelist,cas,exat,smove,SUGGET,sugget,ro,DOF,dof
2 changes: 1 addition & 1 deletion examples/transaction_using_cas.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function zpop($client, $key)
'cas' => true, // Initialize with support for CAS operations
'watch' => $key, // Key that needs to be WATCHed to detect changes
'retry' => 3, // Number of retries on aborted transactions, after
// which the client bails out with an exception.
// which the client bails out with an exception.
];

$client->transaction($options, function ($tx) use ($key, &$element) {
Expand Down
6 changes: 3 additions & 3 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ public function pipeline(...$arguments)
*
* @return Pipeline|array
*/
protected function createPipeline(array $options = null, $callable = null)
protected function createPipeline(?array $options = null, $callable = null)
{
if (isset($options['atomic']) && $options['atomic']) {
$class = Atomic::class;
Expand Down Expand Up @@ -525,7 +525,7 @@ public function transaction(...$arguments)
*
* @return MultiExecTransaction|array
*/
protected function createTransaction(array $options = null, $callable = null)
protected function createTransaction(?array $options = null, $callable = null)
{
$transaction = new MultiExecTransaction($this, $options);

Expand Down Expand Up @@ -557,7 +557,7 @@ public function pubSubLoop(...$arguments)
*
* @return PubSubConsumer|null
*/
protected function createPubSub(array $options = null, $callable = null)
protected function createPubSub(?array $options = null, $callable = null)
{
if ($this->connection instanceof RelayConnection) {
$pubsub = new RelayPubSubConsumer($this, $options);
Expand Down
13 changes: 13 additions & 0 deletions src/ClientContextInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

use Predis\Command\Argument\Geospatial\ByInterface;
use Predis\Command\Argument\Geospatial\FromInterface;
use Predis\Command\Argument\Hash\HGetFArguments;
use Predis\Command\Argument\Hash\HSetFArguments;
use Predis\Command\Argument\Search\AggregateArguments;
use Predis\Command\Argument\Search\AlterArguments;
use Predis\Command\Argument\Search\CreateArguments;
Expand Down Expand Up @@ -154,7 +156,15 @@
* @method $this strlen($key)
* @method $this hdel($key, array $fields)
* @method $this hexists($key, $field)
* @method $this hexpire(string $key, int $seconds, array $fields, string $flag = null)
* @method $this hexpireat(string $key, int $unixTimeSeconds, array $fields, string $flag = null)
* @method $this hexpiretime(string $key, array $fields)
* @method $this hpersist(string $key, array $fields)
* @method $this hpexpire(string $key, int $milliseconds, array $fields, string $flag = null)
* @method $this hpexpireat(string $key, int $unixTimeMilliseconds, array $fields, string $flag = null)
* @method $this hpexpiretime(string $key, array $fields)
* @method $this hget($key, $field)
* @method $this hgetf(string $key, array $fields, HGetFArguments $arguments = null)
* @method $this hgetall($key)
* @method $this hincrby($key, $field, $increment)
* @method $this hincrbyfloat($key, $field, $increment)
Expand All @@ -165,7 +175,10 @@
* @method $this hrandfield(string $key, int $count = 1, bool $withValues = false)
* @method $this hscan($key, $cursor, array $options = null)
* @method $this hset($key, $field, $value)
* @method $this hsetf(string $key, array $keyValuePairs, HSetFArguments $arguments = null)
vladvildanov marked this conversation as resolved.
Show resolved Hide resolved
* @method $this hsetnx($key, $field, $value)
* @method $this httl(string $key, array $fields)
* @method $this hpttl(string $key, array $fields)
* @method $this hvals($key)
* @method $this hstrlen($key, $field)
* @method $this jsonarrappend(string $key, string $path = '$', ...$value)
Expand Down
13 changes: 13 additions & 0 deletions src/ClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

use Predis\Command\Argument\Geospatial\ByInterface;
use Predis\Command\Argument\Geospatial\FromInterface;
use Predis\Command\Argument\Hash\HGetFArguments;
use Predis\Command\Argument\Hash\HSetFArguments;
use Predis\Command\Argument\Search\AggregateArguments;
use Predis\Command\Argument\Search\AlterArguments;
use Predis\Command\Argument\Search\CreateArguments;
Expand Down Expand Up @@ -163,7 +165,15 @@
* @method int strlen(string $key)
* @method int hdel(string $key, array $fields)
* @method int hexists(string $key, string $field)
* @method array|null hexpire(string $key, int $seconds, array $fields, string $flag = null)
* @method array|null hexpireat(string $key, int $unixTimeSeconds, array $fields, string $flag = null)
* @method array|null hexpiretime(string $key, array $fields)
* @method array|null hpersist(string $key, array $fields)
* @method array|null hpexpire(string $key, int $milliseconds, array $fields, string $flag = null)
* @method array|null hpexpireat(string $key, int $unixTimeMilliseconds, array $fields, string $flag = null)
* @method array|null hpexpiretime(string $key, array $fields)
* @method string|null hget(string $key, string $field)
* @method array|null hgetf(string $key, array $fields, HGetFArguments $arguments = null)
* @method array hgetall(string $key)
* @method int hincrby(string $key, string $field, int $increment)
* @method string hincrbyfloat(string $key, string $field, int|float $increment)
Expand All @@ -174,7 +184,10 @@
* @method array hrandfield(string $key, int $count = 1, bool $withValues = false)
* @method array hscan(string $key, $cursor, array $options = null)
* @method int hset(string $key, string $field, string $value)
* @method mixed hsetf(string $key, array $keyValuePairs, HSetFArguments $arguments = null)
* @method int hsetnx(string $key, string $field, string $value)
* @method array|null httl(string $key, array $fields)
* @method array|null hpttl(string $key, array $fields)
* @method array hvals(string $key)
* @method int hstrlen(string $key, string $field)
* @method array jsonarrappend(string $key, string $path = '$', ...$value)
Expand Down
2 changes: 1 addition & 1 deletion src/Cluster/PredisStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class PredisStrategy extends ClusterStrategy
/**
* @param DistributorInterface $distributor Optional distributor instance.
*/
public function __construct(DistributorInterface $distributor = null)
public function __construct(?DistributorInterface $distributor = null)
{
parent::__construct();

Expand Down
2 changes: 1 addition & 1 deletion src/Cluster/RedisStrategy.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class RedisStrategy extends ClusterStrategy
/**
* @param HashGeneratorInterface $hashGenerator Hash generator instance.
*/
public function __construct(HashGeneratorInterface $hashGenerator = null)
public function __construct(?HashGeneratorInterface $hashGenerator = null)
{
parent::__construct();

Expand Down
14 changes: 7 additions & 7 deletions src/Collection/Iterator/CursorBasedIterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,13 +176,13 @@ public function next()
$this->fetch();
}

if ($this->elements) {
$this->extractNext();
} elseif ($this->cursor) {
goto tryFetch;
} else {
$this->valid = false;
}
if ($this->elements) {
$this->extractNext();
} elseif ($this->cursor) {
goto tryFetch;
} else {
$this->valid = false;
}
}

/**
Expand Down
100 changes: 100 additions & 0 deletions src/Command/Argument/Hash/CommonExpiration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php

/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2023 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Predis\Command\Argument\Hash;

use Predis\Command\Argument\ArrayableArgument;
use UnexpectedValueException;

abstract class CommonExpiration implements ArrayableArgument
{
/**
* @var array
*/
protected $expireModifierEnum = [
vladvildanov marked this conversation as resolved.
Show resolved Hide resolved
'NX', 'XX', 'GT', 'LT',
];

/**
* @var array
*/
protected $ttlModifierEnum = [
'EX', 'PX', 'EXAT', 'PXAT',
];

/**
* @var array
*/
protected $arguments = [];

/**
* Set the modifier that defines a behaviour on expiration.
*
* NX for each specified field set expiration only when the field has no expiration
vladvildanov marked this conversation as resolved.
Show resolved Hide resolved
*
* XX for each specified field set expiration only when the field has an existing expiration
*
* GT for each specified field set expiration only when the new expiration time is greater than the field's current one.
* A field with no expiration is treated as an infinite expiration.
*
* LT for each specified field set expiration only when the new expiration time is less than the field's current one.
* A field with no expiration is treated as an infinite expiration.
*
* @param string $modifier
* @return $this
*/
public function setExpirationModifier(string $modifier): self
{
if (!in_array(strtoupper($modifier), $this->expireModifierEnum, true)) {
throw new UnexpectedValueException('Incorrect expire modifier value');
}

$this->arguments[] = strtoupper($modifier);

return $this;
}

/**
* Set the TTL for each specified field.
*
* EX seconds for each specified field set the remaining time to live in seconds
*
* PX milliseconds for each specified field set the remaining time to live in milliseconds
*
* EXAT unix-time-seconds for each specified field set the expiration time to a UNIX timestamp specified in seconds since the Unix epoch
*
* PXAT unix-time-milliseconds for each specified field set the expiration time to a UNIX timestamp specified in milliseconds since the Unix epoch
*
* @param string $modifier
* @param int $value
* @return $this
*/
public function setTTLModifier(string $modifier, int $value): self
{
if (!in_array(strtoupper($modifier), $this->ttlModifierEnum, true)) {
throw new UnexpectedValueException('Incorrect TTL modifier');
}

$this->arguments[] = strtoupper($modifier);
$this->arguments[] = $value;

return $this;
}

/**
* {@inheritDoc}
*/
public function toArray(): array
{
return $this->arguments;
}
}
34 changes: 34 additions & 0 deletions src/Command/Argument/Hash/HGetFArguments.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2023 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Predis\Command\Argument\Hash;

use UnexpectedValueException;

class HGetFArguments extends CommonExpiration
{
/**
* Removes current expiration time from given fields.
*
* @return $this
*/
public function setPersist(): self
{
if (!empty(array_intersect($this->ttlModifierEnum, $this->arguments))) {
vladvildanov marked this conversation as resolved.
Show resolved Hide resolved
throw new UnexpectedValueException('PERSIST argument cannot be mixed with one of TTL modifiers');
}

$this->arguments[] = 'PERSIST';

return $this;
}
}
102 changes: 102 additions & 0 deletions src/Command/Argument/Hash/HSetFArguments.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

/*
* This file is part of the Predis package.
*
* (c) 2009-2020 Daniele Alessandri
* (c) 2021-2023 Till Krüss
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Predis\Command\Argument\Hash;

use UnexpectedValueException;

class HSetFArguments extends CommonExpiration
{
/**
* @var array
*/
protected $fieldModifierEnum = [
'DCF', 'DOF',
];

/**
* @var array
*/
protected $getModifierEnum = [
'GETNEW', 'GETOLD',
];

/**
* Restricts to create a key if given key does not exist.
*
* @return $this
*/
public function setDontCreate(): self
{
$this->arguments[] = 'DC';

return $this;
}

/**
* Set the modifier that define a behaviour on already existing/non-existing fields.
*
* DCF for each specified field if the field already exists set the field's value and expiration time ignore fields that do not exist
*
* DOF for each specified field if such field does not exist create field and set its value and expiration time ignore fields that already exists
*
* @param string $modifier
* @return $this
*/
public function setFieldModifier(string $modifier): self
{
if (!in_array(strtoupper($modifier), $this->fieldModifierEnum, true)) {
throw new UnexpectedValueException('Incorrect field modifier value');
}

$this->arguments[] = strtoupper($modifier);

return $this;
}

/**
* Set the modifier that define a return value to be old/new field value.
*
* GETNEW new value of field or null if field does not exist and DCF specified.
*
* GETOLD old value of field or null if no such field existed before the command execution.
*
* @param string $modifier
* @return $this
*/
public function setGetModifier(string $modifier): self
{
if (!in_array(strtoupper($modifier), $this->getModifierEnum, true)) {
throw new UnexpectedValueException('Incorrect get modifier value');
}

$this->arguments[] = strtoupper($modifier);

return $this;
}

/**
* For each specified field retain the previous expiration time.
*
* @return $this
*/
public function enableKeepTTL(): self
{
if (!empty(array_intersect($this->ttlModifierEnum, $this->arguments))) {
throw new UnexpectedValueException('Keep TTL argument cannot be mixed with one of TTL modifiers');
}

$this->arguments[] = 'KEEPTTL';

return $this;
}
}