Added support for LMPOP command (#1013)

Co-authored-by: Vladyslav Vildanov <vladyslavvildanov@Vladyslav-Vildanov-MacBook-Pro.local>
This commit is contained in:
Vladyslav Vildanov
2023-01-16 18:45:04 +02:00
committed by GitHub
parent 721c829042
commit d1acca607e
6 changed files with 343 additions and 0 deletions
+1
View File
@@ -93,6 +93,7 @@ use Predis\Command\CommandInterface;
* @method $this linsert($key, $whence, $pivot, $value)
* @method $this llen($key)
* @method $this lmove(string $source, string $destination, string $where, string $to)
* @method $this lmpop(array $keys, string $modifier = 'left', int $count = 1)
* @method $this lpop($key)
* @method $this lpush($key, array $values)
* @method $this lpushx($key, array $values)
+1
View File
@@ -102,6 +102,7 @@ use Predis\Response\Status;
* @method int linsert(string $key, $whence, $pivot, $value)
* @method int llen(string $key)
* @method string lmove(string $source, string $destination, string $where, string $to)
* @method array|null lmpop(array $keys, string $modifier = 'left', int $count = 1)
* @method string|null lpop(string $key)
* @method int lpush(string $key, array $values)
* @method int lpushx(string $key, array $values)
+51
View File
@@ -0,0 +1,51 @@
<?php
namespace Predis\Command\Redis;
use Predis\Command\Command as RedisCommand;
use Predis\Command\Traits\Count;
use \Predis\Command\Traits\Keys;
use Predis\Command\Traits\LeftRight;
class LMPOP extends RedisCommand
{
use Keys {
Keys::setArguments as setKeys;
}
use LeftRight {
LeftRight::setArguments as setLeftRight;
}
use Count {
Count::setArguments as setCount;
}
protected static $keysArgumentPositionOffset = 0;
protected static $leftRightArgumentPositionOffset = 1;
protected static $countArgumentPositionOffset = 2;
public function getId()
{
return 'LMPOP';
}
public function setArguments(array $arguments)
{
$this->setCount($arguments);
$arguments = $this->getArguments();
$this->setLeftRight($arguments);
$arguments = $this->getArguments();
$this->setKeys($arguments);
$this->filterArguments();
}
public function parseResponse($data)
{
if (null !== $data) {
return [$data[0] => $data[1]];
}
return null;
}
}
+49
View File
@@ -0,0 +1,49 @@
<?php
namespace Predis\Command\Traits;
use Predis\Command\Command;
use UnexpectedValueException;
/**
* @mixin Command
*/
trait LeftRight
{
/**
* @var array{string: string}
*/
private static $leftRightEnum = [
'left' => 'LEFT',
'right' => 'RIGHT',
];
public function setArguments(array $arguments)
{
$argumentsLength = count($arguments);
if (static::$leftRightArgumentPositionOffset >= $argumentsLength) {
$arguments[] = 'LEFT';
parent::setArguments($arguments);
return;
}
$argument = $arguments[static::$leftRightArgumentPositionOffset];
if (is_string($argument) && in_array(strtoupper($argument), self::$leftRightEnum, true)) {
$argument = self::$leftRightEnum[$argument];
} else {
$enumValues = implode(', ', array_keys(self::$leftRightEnum));
throw new UnexpectedValueException("Left/Right argument accepts only: {$enumValues} values");
}
$argumentsBefore = array_slice($arguments, 0, static::$leftRightArgumentPositionOffset);
$argumentsAfter = array_slice($arguments, static::$leftRightArgumentPositionOffset + 1);
parent::setArguments(array_merge(
$argumentsBefore,
[$argument],
$argumentsAfter
));
}
}
+151
View File
@@ -0,0 +1,151 @@
<?php
/*
* This file is part of the Predis package.
*
* (c) Daniele Alessandri <suppakilla@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Predis\Command\Redis;
use Predis\Response\ServerException;
/**
* @group commands
* @group realm-list
*/
class LMPOP_Test extends PredisCommandTestCase
{
/**
* {@inheritdoc}
*/
protected function getExpectedCommand(): string
{
return LMPOP::class;
}
/**
* {@inheritdoc}
*/
protected function getExpectedId(): string
{
return 'LMPOP';
}
/**
* @group disconnected
* @dataProvider argumentsProvider
*/
public function testFilterArguments(array $actualArguments, array $expectedArguments): void
{
$command = $this->getCommand();
$command->setArguments($actualArguments);
$this->assertSame($expectedArguments, $command->getArguments());
}
/**
* @group disconnected
*/
public function testParseResponse(): void
{
$raw = ['key', ['elem1', 'elem2']];
$expected = ['key' => ['elem1', 'elem2']];
$command = $this->getCommand();
$this->assertSame($expected, $command->parseResponse($raw));
}
/**
* @group connected
* @dataProvider listProvider
* @param array $listArguments
* @param string $key
* @param string $modifier
* @param int $count
* @param array|null $expectedResponse
* @param array $expectedModifiedList
* @return void
* @requiresRedisVersion >= 7.0.0
*/
public function testPopElementsFromGivenList(
array $listArguments,
string $key,
string $modifier,
int $count,
?array $expectedResponse,
array $expectedModifiedList
): void {
$redis = $this->getClient();
$redis->lpush(...$listArguments);
$actualResponse = $redis->lmpop(['key1', $key], $modifier, $count);
$this->assertSame($expectedResponse, $actualResponse);
$this->assertSame($expectedModifiedList, $redis->lrange($key, 0, -1));
}
public function argumentsProvider(): array
{
return [
'with default arguments' => [
[['key']],
[1, 'key', 'LEFT']
],
'with LEFT/RIGHT argument' => [
[['key'], 'right'],
[1, 'key', 'RIGHT']
],
'with COUNT argument' => [
[['key'], 'left', 2],
[1, 'key', 'LEFT', 'COUNT', 2]
],
'with all arguments' => [
[['key1', 'key2'], 'right', 2],
[2, 'key1', 'key2', 'RIGHT', 'COUNT', 2]
]
];
}
public function listProvider(): array
{
return [
'pops single element - left' => [
['key', 'elem1', 'elem2', 'elem3'],
'key',
'left',
1,
['key' => ['elem3']],
['elem2', 'elem1']
],
'pops single element - right' => [
['key', 'elem1', 'elem2', 'elem3'],
'key',
'right',
1,
['key' => ['elem1']],
['elem3', 'elem2']
],
'pops multiple elements' => [
['key', 'elem1', 'elem2', 'elem3'],
'key',
'right',
2,
['key' => ['elem1', 'elem2']],
['elem3'],
],
'with empty list' => [
['key', 'elem1', 'elem2', 'elem3'],
'key2',
'right',
2,
null,
[],
],
];
}
}
@@ -0,0 +1,90 @@
<?php
namespace Predis\Command\Traits;
use PredisTestCase;
use Predis\Command\Command as RedisCommand;
use UnexpectedValueException;
class LeftRightTest extends PredisTestCase
{
private $testClass;
protected function setUp(): void
{
$this->testClass = new class extends RedisCommand {
use LeftRight;
public static $leftRightArgumentPositionOffset = 0;
public function getId()
{
return 'test';
}
};
}
/**
* @dataProvider argumentsProvider
* @param int $offset
* @param array $actualArguments
* @param array $expectedArguments
* @return void
*/
public function testReturnsCorrectArguments(int $offset, array $actualArguments, array $expectedArguments): void
{
$this->testClass::$leftRightArgumentPositionOffset = $offset;
$this->testClass->setArguments($actualArguments);
$this->assertSame($expectedArguments, $this->testClass->getArguments());
}
/**
* @dataProvider unexpectedValuesProvider
* @param array $actualArguments
* @return void
*/
public function testThrowsExceptionOnUnexpectedValueGiven(array $actualArguments): void
{
$this->expectException(UnexpectedValueException::class);
$this->expectExceptionMessage('Left/Right argument accepts only: left, right values');
$this->testClass->setArguments($actualArguments);
}
public function argumentsProvider(): array
{
return [
'with wrong offset' => [2, ['argument1'], ['argument1', 'LEFT']],
'left/right argument first and there is arguments after' => [
0,
['left', 'second argument', 'third argument'],
['LEFT', 'second argument', 'third argument']
],
'left/right argument last and there is arguments before' => [
2,
['first argument', 'second argument', 'right'],
['first argument', 'second argument', 'RIGHT']
],
'left/right argument not the first and not the last' => [
1,
['first argument', 'left', 'third argument'],
['first argument', 'LEFT','third argument']
],
'aggregate argument the only argument' => [
0,
['right'],
['RIGHT']
]
];
}
public function unexpectedValuesProvider(): array
{
return [
'with non-string argument' => [[1]],
'with non enum value' => [['wrong']],
];
}
}