From 5418cd5813e28adf3c2fc41bd54a92391b0b47a4 Mon Sep 17 00:00:00 2001 From: Vladyslav Vildanov <117659936+vladvildanov@users.noreply.github.com> Date: Tue, 13 Dec 2022 18:38:35 +0200 Subject: [PATCH] Extended Sorted Set support by adding BLMOVE command (#865) * Added support for LMOVE command * Added support for BLMOVE command Co-authored-by: Vladyslav Vildanov --- src/ClientContextInterface.php | 1 + src/ClientInterface.php | 1 + src/Command/Redis/BLMOVE.php | 11 ++ tests/Predis/Command/Redis/BLMOVE_Test.php | 200 +++++++++++++++++++++ 4 files changed, 213 insertions(+) create mode 100644 src/Command/Redis/BLMOVE.php create mode 100644 tests/Predis/Command/Redis/BLMOVE_Test.php diff --git a/src/ClientContextInterface.php b/src/ClientContextInterface.php index 9a884fb3..c907be64 100644 --- a/src/ClientContextInterface.php +++ b/src/ClientContextInterface.php @@ -76,6 +76,7 @@ use Predis\Command\CommandInterface; * @method $this hsetnx($key, $field, $value) * @method $this hvals($key) * @method $this hstrlen($key, $field) + * @method $this blmove(string $source, string $destination, string $where, string $to, int $timeout) * @method $this blpop(array|string $keys, $timeout) * @method $this brpop(array|string $keys, $timeout) * @method $this brpoplpush($source, $destination, $timeout) diff --git a/src/ClientInterface.php b/src/ClientInterface.php index 463d3eae..a6690a72 100644 --- a/src/ClientInterface.php +++ b/src/ClientInterface.php @@ -85,6 +85,7 @@ use Predis\Response\Status; * @method int hsetnx(string $key, string $field, string $value) * @method array hvals(string $key) * @method int hstrlen(string $key, string $field) + * @method string blmove(string $source, string $destination, string $where, string $to, int $timeout) * @method array|null blpop(array|string $keys, int|float $timeout) * @method array|null brpop(array|string $keys, int|float $timeout) * @method string|null brpoplpush(string $source, string $destination, int|float $timeout) diff --git a/src/Command/Redis/BLMOVE.php b/src/Command/Redis/BLMOVE.php new file mode 100644 index 00000000..57a57109 --- /dev/null +++ b/src/Command/Redis/BLMOVE.php @@ -0,0 +1,11 @@ +getCommand(); + $command->setArguments($arguments); + + $this->assertSame($expected, $command->getArguments()); + } + + /** + * @group disconnected + */ + public function testParseResponse(): void + { + $this->assertSame(1, $this->getCommand()->parseResponse(1)); + } + + /** + * @group connected + * @dataProvider listsProvider + * @param array $firstList + * @param array $secondList + * @param string $where + * @param string $to + * @param string $expectedResponse + * @param array $expectedModifiedFirstList + * @param array $expectedModifiedSecondList + * @return void + * @requiresRedisVersion >= 6.2.0 + */ + public function testReturnsCorrectListElement( + array $firstList, + array $secondList, + string $where, + string $to, + string $expectedResponse, + array $expectedModifiedFirstList, + array $expectedModifiedSecondList + ): void { + $redis = $this->getClient(); + + $redis->rpush('test-blmove1', $firstList); + $redis->rpush('test-blmove2', $secondList); + + $actualResponse = $redis->blmove('test-blmove1', 'test-blmove2', $where, $to, 0); + + $this->assertSame($expectedResponse, $actualResponse); + $this->assertSame($expectedModifiedFirstList, $redis->lrange('test-blmove1', 0, -1)); + $this->assertSame($expectedModifiedSecondList, $redis->lrange('test-blmove2', 0, -1)); + } + + /** + * @group connected + * @dataProvider sameListProvider + * @param array $list + * @param string $where + * @param string $to + * @param string $expectedResponse + * @param array $expectedModifiedList + * @return void + * @requiresRedisVersion >= 6.2.0 + */ + public function testReturnsCorrectListElementAndListRotationPerformedOnTheSameListOperation( + array $list, + string $where, + string $to, + string $expectedResponse, + array $expectedModifiedList + ): void { + $redis = $this->getClient(); + + $redis->rpush('test-blmove1', $list); + + $actualResponse = $redis->blmove('test-blmove1', 'test-blmove1', $where, $to, 0); + + $this->assertSame($expectedResponse, $actualResponse); + $this->assertSame($expectedModifiedList, $redis->lrange('test-blmove1', 0, -1)); + } + + /** + * @group connected + * @return void + * @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->blmove('foo', 'test-lmove', 'LEFT', 'LEFT', 0); + } + + public function listsProvider(): array + { + return [ + 'move first element from list into head of another list' => [ + ['element1', 'element2', 'element3'], + ['element4', 'element5', 'element6'], + 'LEFT', + 'LEFT', + 'element1', + ['element2', 'element3'], + ['element1', 'element4', 'element5', 'element6'], + ], + 'move first element from list into tail of another list' => [ + ['element1', 'element2', 'element3'], + ['element4', 'element5', 'element6'], + 'LEFT', + 'RIGHT', + 'element1', + ['element2', 'element3'], + ['element4', 'element5', 'element6', 'element1'], + ], + 'move last element from list into head of another list' => [ + ['element1', 'element2', 'element3'], + ['element4', 'element5', 'element6'], + 'RIGHT', + 'LEFT', + 'element3', + ['element1', 'element2'], + ['element3', 'element4', 'element5', 'element6'], + ], + 'move last element from list into tail of another list' => [ + ['element1', 'element2', 'element3'], + ['element4', 'element5', 'element6'], + 'RIGHT', + 'RIGHT', + 'element3', + ['element1', 'element2'], + ['element4', 'element5', 'element6', 'element3'], + ], + ]; + } + + public function sameListProvider(): array + { + return [ + 'list rotation - head into tail' => [ + ['element1', 'element2', 'element3'], + 'LEFT', + 'RIGHT', + 'element1', + ['element2', 'element3', 'element1'], + ], + 'list rotation - tail into head' => [ + ['element1', 'element2', 'element3'], + 'RIGHT', + 'LEFT', + 'element3', + ['element3', 'element1', 'element2'], + ], + 'list rotation - head into head' => [ + ['element1', 'element2', 'element3'], + 'LEFT', + 'LEFT', + 'element1', + ['element1', 'element2', 'element3'], + ], + 'list rotation - tail into tail' => [ + ['element1', 'element2', 'element3'], + 'RIGHT', + 'RIGHT', + 'element3', + ['element1', 'element2', 'element3'], + ], + ]; + } +}