From 169604bf7443b08fd6284390ebd9e444c6a9f085 Mon Sep 17 00:00:00 2001 From: Vladyslav Vildanov <117659936+vladvildanov@users.noreply.github.com> Date: Mon, 21 Nov 2022 18:37:04 +0200 Subject: [PATCH] Extend Sorted Set support by implementing ZRANDMEMBER command (#825) * Added support for ZRANDMEMBER, added test coverage * Changed key to more specific on exception testing Co-authored-by: Vladislav --- src/ClientContextInterface.php | 1 + src/ClientInterface.php | 1 + src/Command/Redis/ZRANDMEMBER.php | 39 ++++++ .../Predis/Command/Redis/ZRANDMEMBER_test.php | 131 ++++++++++++++++++ 4 files changed, 172 insertions(+) create mode 100644 src/Command/Redis/ZRANDMEMBER.php create mode 100644 tests/Predis/Command/Redis/ZRANDMEMBER_test.php diff --git a/src/ClientContextInterface.php b/src/ClientContextInterface.php index a24704e0..5fef3748 100644 --- a/src/ClientContextInterface.php +++ b/src/ClientContextInterface.php @@ -112,6 +112,7 @@ use Predis\Command\CommandInterface; * @method $this zincrby($key, $increment, $member) * @method $this zinterstore($destination, array|string $keys, array $options = null) * @method $this zmscore(string $key, string ...$member) + * @method $this zrandmember(string $key, int $count = 1, bool $withScores = false) * @method $this zrange($key, $start, $stop, array $options = null) * @method $this zrangebyscore($key, $min, $max, array $options = null) * @method $this zrank($key, $member) diff --git a/src/ClientInterface.php b/src/ClientInterface.php index 6e4ebdb4..bb5a1d98 100644 --- a/src/ClientInterface.php +++ b/src/ClientInterface.php @@ -130,6 +130,7 @@ use Predis\Response\Status; * @method array zmscore(string $key, string ...$member) * @method array zpopmin(string $key, int $count = 1) * @method array zpopmax(string $key, int $count = 1) + * @method mixed zrandmember(string $key, int $count = 1, bool $withScores = false) * @method array zrange(string $key, int|string $start, int|string $stop, array $options = null) * @method array zrangebyscore(string $key, int|string $min, int|string $max, array $options = null) * @method int|null zrank(string $key, string $member) diff --git a/src/Command/Redis/ZRANDMEMBER.php b/src/Command/Redis/ZRANDMEMBER.php new file mode 100644 index 00000000..d4387160 --- /dev/null +++ b/src/Command/Redis/ZRANDMEMBER.php @@ -0,0 +1,39 @@ += 6.2.0 + */ +class ZRANDMEMBER extends RedisCommand +{ + + public function getId() + { + return 'ZRANDMEMBER'; + } + + public function setArguments(array $arguments) + { + $withScores = (count($arguments) === 3) + ? array_pop($arguments) + : false; + + if (is_bool($withScores) && $withScores) { + $arguments[] = 'WITHSCORES'; + } + + parent::setArguments($arguments); + } +} diff --git a/tests/Predis/Command/Redis/ZRANDMEMBER_test.php b/tests/Predis/Command/Redis/ZRANDMEMBER_test.php new file mode 100644 index 00000000..b1a89842 --- /dev/null +++ b/tests/Predis/Command/Redis/ZRANDMEMBER_test.php @@ -0,0 +1,131 @@ +getCommand(); + $command->setArguments($actualArguments); + + $this->assertSame($expectedArguments, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse(): void + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group connected + * @param string $key + * @param int $count + * @param array $membersDictionary + * @param array $expectedResponse + * @param bool $withScores + * @return void + * @dataProvider membersProvider + * @requiresRedisVersion >= 6.2.0 + */ + public function testReturnsRandomMembersFromSortedSet( + string $key, + int $count, + array $membersDictionary, + array $expectedResponse, + bool $withScores + ): void { + $redis = $this->getClient(); + $notExpectedKey = 'not_expected'; + + $redis->zadd($key, ...$membersDictionary); + $this->assertSameValues($redis->zrandmember($key, $count, $withScores), $expectedResponse); + $this->assertNull($redis->zrandmember($notExpectedKey)); + } + + /** + * @group connected + * @requiresRedisVersion >= 6.2.0 + */ + public function testThrowsExceptionOnWrongType(): void + { + $this->expectException(ServerException::class); + $this->expectExceptionMessage('Operation against a key holding the wrong kind of value'); + + $redis = $this->getClient(); + + $redis->set('zrandmember_foo', 'bar'); + $redis->zrandmember('zrandmember_foo', 1, true); + } + + public function argumentsProvider(): array + { + return [ + 'with scores' => [['zset', 5, 'withScores' => true], ['zset', 5, 'WITHSCORES']], + 'without scores' => [['zset', 5], ['zset', 5]], + 'without scores - false value' => [['zset', 5, 'withScores' => false], ['zset', 5]], + ]; + } + + public function membersProvider(): array + { + return [ + 'one member - without score' => ['test-zset', 1, [1, 'member1'], ['member1'], false], + 'multiple members - positive count - without score' => [ + 'test-zset', + 2, + [1, 'member1', 2, 'member2'], + ['member1', 'member2'], + false + ], + 'multiple members - negative count - without score' => [ + 'test-zset', + -2, + [1, 'member1'], + ['member1', 'member1'], + false + ], + 'one member - with score' => ['test-zset', 1, [1, 'member1'], ['member1', 1], true], + 'multiple members - positive count - with score' => [ + 'test-zset', + 2, + [1, 'member1', 2, 'member2'], + ['member1', 1, 'member2', 2], + true + ], + 'multiple members - negative count - with score' => [ + 'test-zset', + -2, + [1, 'member1'], + ['member1', 1, 'member1', 1], + true + ], + ]; + } +}