diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 474c1755..542979c0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -42,7 +42,7 @@ jobs: run: | # Mapping of original redis versions to client test containers declare -A redis_clients_version_mapping=( - ["8.8"]="8.8-rc1" + ["8.8"]="custom-26235535976-debian" ["8.6"]="8.6.1" ["8.4"]="8.4.0" ["8.2"]="8.2.2" diff --git a/CHANGELOG.md b/CHANGELOG.md index 661087ad..18ae327d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ ### Changed - Include command name in unsupported container command error messages (#1653) - Updated arguments name for GCRA command (#1667) +- Updated INCREX arguments (#1677) ### Fixed - Fixed handling of gap slots in `SlotMap::offsetUnset()` (#1660) diff --git a/src/ClientContextInterface.php b/src/ClientContextInterface.php index ee431779..d3eada45 100644 --- a/src/ClientContextInterface.php +++ b/src/ClientContextInterface.php @@ -170,7 +170,7 @@ use Predis\Command\Redis\VADD; * @method $this incr($key) * @method $this incrby($key, $increment) * @method $this incrbyfloat($key, $increment) - * @method $this increx(string $key, int|float|string $value, ?int $lbound = null, ?int $ubound = null, ?string $overflow = null, ?string $expireType = null, $expireValue = null, bool $enx = false) + * @method $this increx(string $key, int|float|string $value, ?int $lbound = null, ?int $ubound = null, bool $saturate = false, ?string $expireType = null, $expireValue = null, bool $enx = false) * @method $this mget(array $keys) * @method $this mset(array $dictionary) * @method $this msetex(array $dictionary, ?string $existModifier = null, ?string $expireResolution = null, ?int $expireTTL = null) diff --git a/src/ClientInterface.php b/src/ClientInterface.php index 98d5953d..ceadec02 100644 --- a/src/ClientInterface.php +++ b/src/ClientInterface.php @@ -180,7 +180,7 @@ use Predis\Response\Status; * @method int incr(string $key) * @method int incrby(string $key, int $increment) * @method string incrbyfloat(string $key, int|float $increment) - * @method array increx(string $key, int|float|string $value, ?int $lbound = null, ?int $ubound = null, ?string $overflow = null, ?string $expireType = null, $expireValue = null, bool $enx = false) + * @method array increx(string $key, int|float|string $value, ?int $lbound = null, ?int $ubound = null, bool $saturate = false, ?string $expireType = null, $expireValue = null, bool $enx = false) * @method array mget(string[]|string $keyOrKeys, string ...$keys = null) * @method mixed mset(array $dictionary) * @method array msetex(array $dictionary, ?string $existModifier = null, ?string $expireResolution = null, ?int $expireTTL = null) diff --git a/src/Command/Redis/INCREX.php b/src/Command/Redis/INCREX.php index 2b625164..e42f3563 100644 --- a/src/Command/Redis/INCREX.php +++ b/src/Command/Redis/INCREX.php @@ -23,30 +23,12 @@ class INCREX extends RedisCommand public const BY_INT = 'BYINT'; public const BY_FLOAT = 'BYFLOAT'; - public const OVERFLOW_FAIL = 'FAIL'; - public const OVERFLOW_SAT = 'SAT'; - public const OVERFLOW_REJECT = 'REJECT'; - public const EXPIRE_EX = 'EX'; public const EXPIRE_PX = 'PX'; public const EXPIRE_EXAT = 'EXAT'; public const EXPIRE_PXAT = 'PXAT'; public const EXPIRE_PERSIST = 'PERSIST'; - /** - * @var string[] - */ - private static $byEnum = [self::BY_INT, self::BY_FLOAT]; - - /** - * @var string[] - */ - private static $overflowEnum = [ - self::OVERFLOW_FAIL, - self::OVERFLOW_SAT, - self::OVERFLOW_REJECT, - ]; - /** * @var string[] */ @@ -69,7 +51,7 @@ class INCREX extends RedisCommand /** * {@inheritdoc} * - * Arguments: [key, value, ?lbound, ?ubound, ?overflow, ?expireType, ?expireValue, ?enx] + * Arguments: [key, value, ?lbound, ?ubound, ?saturate, ?expireType, ?expireValue, ?enx] */ public function setArguments(array $arguments) { @@ -91,17 +73,8 @@ class INCREX extends RedisCommand $processed[] = $arguments[3]; } - $overflow = $arguments[4] ?? null; - if ($overflow !== null && $overflow !== '') { - $overflow = strtoupper($overflow); - - if (!in_array($overflow, self::$overflowEnum, true)) { - $allowed = implode(', ', self::$overflowEnum); - throw new UnexpectedValueException("Overflow policy accepts only: {$allowed} values"); - } - - $processed[] = 'OVERFLOW'; - $processed[] = $overflow; + if (!empty($arguments[4])) { + $processed[] = 'SATURATE'; } $expireType = $arguments[5] ?? null; diff --git a/tests/Predis/Command/Redis/INCREX_Test.php b/tests/Predis/Command/Redis/INCREX_Test.php index 9b04ee95..bbe12bfc 100644 --- a/tests/Predis/Command/Redis/INCREX_Test.php +++ b/tests/Predis/Command/Redis/INCREX_Test.php @@ -89,29 +89,33 @@ class INCREX_Test extends PredisCommandTestCase ['key', 1, null, 100], ['key', 'BYINT', 1, 'UBOUND', 100], ], - 'with OVERFLOW SAT' => [ - ['key', 5, null, 100, 'SAT'], - ['key', 'BYINT', 5, 'UBOUND', 100, 'OVERFLOW', 'SAT'], + 'with SATURATE' => [ + ['key', 5, null, 100, true], + ['key', 'BYINT', 5, 'UBOUND', 100, 'SATURATE'], + ], + 'without SATURATE (default reject)' => [ + ['key', 5, null, 100, false], + ['key', 'BYINT', 5, 'UBOUND', 100], ], 'with EX expiration' => [ - ['key', 1, null, null, null, 'EX', 60], + ['key', 1, null, null, false, 'EX', 60], ['key', 'BYINT', 1, 'EX', 60], ], 'with PERSIST' => [ - ['key', 1, null, null, null, 'PERSIST'], + ['key', 1, null, null, false, 'PERSIST'], ['key', 'BYINT', 1, 'PERSIST'], ], 'with ENX flag' => [ - ['key', 1, null, null, null, 'EX', 60, true], + ['key', 1, null, null, false, 'EX', 60, true], ['key', 'BYINT', 1, 'EX', 60, 'ENX'], ], 'all options with int' => [ - ['key', 5, 0, 100, 'REJECT', 'PX', 5000, true], - ['key', 'BYINT', 5, 'LBOUND', 0, 'UBOUND', 100, 'OVERFLOW', 'REJECT', 'PX', 5000, 'ENX'], + ['key', 5, 0, 100, true, 'PX', 5000, true], + ['key', 'BYINT', 5, 'LBOUND', 0, 'UBOUND', 100, 'SATURATE', 'PX', 5000, 'ENX'], ], 'all options with float' => [ - ['key', 1.5, 0, 100, 'REJECT', 'PX', 5000, true], - ['key', 'BYFLOAT', 1.5, 'LBOUND', 0, 'UBOUND', 100, 'OVERFLOW', 'REJECT', 'PX', 5000, 'ENX'], + ['key', 1.5, 0, 100, true, 'PX', 5000, true], + ['key', 'BYFLOAT', 1.5, 'LBOUND', 0, 'UBOUND', 100, 'SATURATE', 'PX', 5000, 'ENX'], ], ]; } @@ -150,17 +154,6 @@ class INCREX_Test extends PredisCommandTestCase $command->setArguments(['key', new stdClass()]); } - /** - * @group disconnected - */ - public function testThrowsExceptionOnInvalidOverflow(): void - { - $this->expectException(UnexpectedValueException::class); - - $command = $this->getCommand(); - $command->setArguments(['key', 1, null, null, 'INVALID']); - } - /** * @group disconnected */ @@ -169,7 +162,7 @@ class INCREX_Test extends PredisCommandTestCase $this->expectException(UnexpectedValueException::class); $command = $this->getCommand(); - $command->setArguments(['key', 1, null, null, null, 'INVALID', 60]); + $command->setArguments(['key', 1, null, null, false, 'INVALID', 60]); } /** @@ -181,7 +174,7 @@ class INCREX_Test extends PredisCommandTestCase $this->expectExceptionMessage('EX requires a value'); $command = $this->getCommand(); - $command->setArguments(['key', 1, null, null, null, 'EX']); + $command->setArguments(['key', 1, null, null, false, 'EX']); } /** @@ -291,44 +284,33 @@ class INCREX_Test extends PredisCommandTestCase * @group connected * @requiresRedisVersion >= 8.8.0 */ - public function testOverflowSatSaturatesToBound(): void + public function testSaturateClampsResultToBound(): void { $redis = $this->getClient(); $redis->set('cnt', 10); - $this->assertSame([50, 40], $redis->increx('cnt', 1000, null, 50, 'SAT')); + $this->assertSame([50, 40], $redis->increx('cnt', 1000, null, 50, true)); $this->assertSame('50', $redis->get('cnt')); } /** + * Without SATURATE, an out-of-bounds operation is rejected silently: + * the key value and TTL remain unchanged and the reply is [current_value, 0]. + * * @group connected * @requiresRedisVersion >= 8.8.0 */ - public function testOverflowRejectLeavesValueUnchanged(): void + public function testDefaultRejectLeavesValueUnchanged(): void { $redis = $this->getClient(); $redis->set('cnt', 10); - $redis->increx('cnt', 1000, null, 50, 'REJECT'); + $this->assertSame([10, 0], $redis->increx('cnt', 1000, null, 50)); $this->assertSame('10', $redis->get('cnt')); } - /** - * @group connected - * @requiresRedisVersion >= 8.8.0 - */ - public function testOverflowFailRaisesError(): void - { - $this->expectException('Predis\Response\ServerException'); - - $redis = $this->getClient(); - - $redis->set('cnt', 10); - $redis->increx('cnt', 1000, null, 50, 'FAIL'); - } - /** * @group connected * @requiresRedisVersion >= 8.8.0 @@ -339,7 +321,7 @@ class INCREX_Test extends PredisCommandTestCase $redis->set('cnt', 10); - $redis->increx('cnt', 1, null, null, null, 'PX', 60000); + $redis->increx('cnt', 1, null, null, false, 'PX', 60000); $this->assertGreaterThan(0, $redis->pttl('cnt')); } @@ -355,7 +337,7 @@ class INCREX_Test extends PredisCommandTestCase $future = (int) ((microtime(true) + 60) * 1000); - $redis->increx('cnt', 1, null, null, null, 'PXAT', $future); + $redis->increx('cnt', 1, null, null, false, 'PXAT', $future); $this->assertGreaterThan(0, $redis->pttl('cnt')); } @@ -371,7 +353,7 @@ class INCREX_Test extends PredisCommandTestCase $redis->expire('cnt', 60); $this->assertGreaterThan(0, $redis->ttl('cnt')); - $redis->increx('cnt', 1, null, null, null, 'PERSIST'); + $redis->increx('cnt', 1, null, null, false, 'PERSIST'); $this->assertSame(-1, $redis->ttl('cnt')); } @@ -385,11 +367,11 @@ class INCREX_Test extends PredisCommandTestCase $redis->set('cnt', 10); - $redis->increx('cnt', 1, null, null, null, 'EX', 60, true); + $redis->increx('cnt', 1, null, null, false, 'EX', 60, true); $firstTtl = $redis->ttl('cnt'); $this->assertGreaterThan(0, $firstTtl); - $redis->increx('cnt', 1, null, null, null, 'EX', 9999, true); + $redis->increx('cnt', 1, null, null, false, 'EX', 9999, true); $secondTtl = $redis->ttl('cnt'); $this->assertLessThanOrEqual($firstTtl, $secondTtl); }