From 72bc11eb632924f640695850b23a8c8e932f3410 Mon Sep 17 00:00:00 2001 From: Vladyslav Vildanov <117659936+vladvildanov@users.noreply.github.com> Date: Wed, 14 Dec 2022 18:54:30 +0200 Subject: [PATCH] Extended Sorted Set support by adding ZINTER command (#859) * Refactored zinterstore, zunionstore commands and command traits * Merge conflicts resolve, update cluster strategy test with new arguments * Updated assertion in case if command executed faster then duration minimal threshold * Added support for ZINTER command * Added command link and description Co-authored-by: Vladyslav Vildanov --- src/ClientContextInterface.php | 1 + src/ClientInterface.php | 1 + src/Command/Redis/ZINTER.php | 25 +++ tests/Predis/Command/Redis/ZINTER_Test.php | 206 +++++++++++++++++++++ 4 files changed, 233 insertions(+) create mode 100644 src/Command/Redis/ZINTER.php create mode 100644 tests/Predis/Command/Redis/ZINTER_Test.php diff --git a/src/ClientContextInterface.php b/src/ClientContextInterface.php index 0b2d2f7a..48c53926 100644 --- a/src/ClientContextInterface.php +++ b/src/ClientContextInterface.php @@ -119,6 +119,7 @@ use Predis\Command\CommandInterface; * @method $this zincrby($key, $increment, $member) * @method $this zintercard(array $keys, int $limit = 0) * @method $this zinterstore(string $destination, array $keys, int[] $weights = [], string $aggregate = 'sum') + * @method $this zinter(array $keys, int[] $weights = [], string $aggregate = 'sum', bool $withScores = false) * @method $this zmpop(array $keys, string $modifier = 'min', int $count = 1) * @method $this zmscore(string $key, string ...$member) * @method $this zrandmember(string $key, int $count = 1, bool $withScores = false) diff --git a/src/ClientInterface.php b/src/ClientInterface.php index 2d7dd25c..5ec9ed03 100644 --- a/src/ClientInterface.php +++ b/src/ClientInterface.php @@ -135,6 +135,7 @@ use Predis\Response\Status; * @method string zincrby(string $key, int $increment, string $member) * @method int zintercard(array $keys, int $limit = 0) * @method int zinterstore(string $destination, array $keys, int[] $weights = [], string $aggregate = 'sum') + * @method array zinter(array $keys, int[] $weights = [], string $aggregate = 'sum', bool $withScores = false) * @method array zmpop(array $keys, string $modifier = 'min', int $count = 1) * @method array zmscore(string $key, string ...$member) * @method array zpopmin(string $key, int $count = 1) diff --git a/src/Command/Redis/ZINTER.php b/src/Command/Redis/ZINTER.php new file mode 100644 index 00000000..e0e2a9c1 --- /dev/null +++ b/src/Command/Redis/ZINTER.php @@ -0,0 +1,25 @@ +getCommand(); + $command->setArguments($actualArguments); + + $this->assertSame($expectedArguments, $command->getArguments()); + } + + public function argumentsProvider(): array + { + return [ + 'with required arguments only' => [ + [['key1', 'key2']], + [2, 'key1', 'key2'], + ], + 'with weights' => [ + [['key1', 'key2'], [1, 2]], + [2, 'key1', 'key2', 'WEIGHTS', 1, 2], + ], + 'with aggregate' => [ + [['key1', 'key2'], [], 'min'], + [2, 'key1', 'key2', 'AGGREGATE', 'MIN'], + ], + 'with withscores' => [ + [['key1', 'key2'], [], 'min', true], + [2, 'key1', 'key2', 'AGGREGATE', 'MIN', 'WITHSCORES'], + ], + 'with all arguments' => [ + [['key1', 'key2'], [1, 2], 'min', true], + [ 2, 'key1', 'key2', 'WEIGHTS', 1, 2, 'AGGREGATE', 'MIN', 'WITHSCORES'], + ] + ]; + } + + /** + * @group connected + * @dataProvider sortedSetsProvider + * @param array $firstSortedSet + * @param array $secondSortedSet + * @param array $weights + * @param string $aggregate + * @param bool $withScores + * @param array $expectedResponse + * @return void + * @requiresRedisVersion >= 6.2.0 + */ + public function testReturnsIntersectedValuesOnSortedSets( + array $firstSortedSet, + array $secondSortedSet, + array $weights, + string $aggregate, + bool $withScores, + array $expectedResponse + ): void { + $redis = $this->getClient(); + + $redis->zadd('test-zinter1', ...$firstSortedSet); + $redis->zadd('test-zinter2', ...$secondSortedSet); + + $actualResponse = $redis->zinter( + ['test-zinter1', 'test-zinter2'], + $weights, + $aggregate, + $withScores + ); + + $this->assertSame($expectedResponse, $actualResponse); + } + + /** + * @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('foo', 'bar'); + $redis->zinter(['foo']); + } + + /** + * @dataProvider unexpectedValueProvider + * @param $keys + * @param $weights + * @param string $aggregate + * @param bool $withScores + * @param string $expectedExceptionMessage + * @return void + * @requiresRedisVersion >= 6.2.0 + */ + public function testThrowsExceptionOnUnexpectedValueGiven( + $keys, + $weights, + string $aggregate, + bool $withScores, + string $expectedExceptionMessage + ): void { + $redis = $this->getClient(); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessage($expectedExceptionMessage); + + $redis->zinter($keys, $weights, $aggregate, $withScores); + } + + public function sortedSetsProvider(): array + { + return [ + 'with required arguments' => [ + [1, 'member1', 2, 'member2', 3, 'member3'], + [1, 'member1', 2, 'member2'], + [], + 'sum', + false, + ['member1', 'member2'], + ], + 'with weights and withscores' => [ + [1, 'member1', 2, 'member2', 3, 'member3'], + [1, 'member1', 2, 'member2'], + [2, 3], + 'sum', + true, + ['member1' => '5', 'member2' => '10'], + ], + 'with aggregate and withscores' => [ + [1, 'member1', 4, 'member2', 3, 'member3'], + [2, 'member1', 2, 'member2'], + [], + 'max', + true, + ['member1' => '2', 'member2' => '4'], + ], + 'with all arguments' => [ + [1, 'member1', 5, 'member2', 4, 'member3'], + [2, 'member1', 2, 'member2'], + [2, 3], + 'max', + true, + ['member1' => '6', 'member2' => '10'], + ], + ]; + } + + public function unexpectedValueProvider(): array + { + return [ + 'with unexpected keys argument' => [ + 1, + [], + 'sum', + false, + 'Wrong keys argument type or position offset' + ], + 'with unexpected weights argument' => [ + ['key1'], + 1, + 'sum', + false, + 'Wrong weights argument type' + ], + 'with unexpected aggregate argument' => [ + ['key1'], + [], + 'wrong', + false, + 'Aggregate argument accepts only: min, max, sum values' + ], + ]; + } +}