-
-
Notifications
You must be signed in to change notification settings - Fork 980
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added support for XINFO commands (#1331)
* Codestyle changes related to php-cs-fixer update (#1311) * Codestyle changes * Added missing type-hints * Added GETDEL command to KeyPrefixProcessor (#1306) * Added GETDEL command to KeyPrefixProcessor * Added test coverage * Codestyle fixes * Added timeout after FT.CREATE call * Added support for JSON.MERGE command (#1304) * Added support for JSON.MSET command (#1307) * Fixed subcommand test bug (#1313) * Update CHANGELOG.md * Update CHANGELOG.md * Added support for XGROUP container commands * Fixed bug with incorrect multiple words processing (#1325) * Fixed bug with incorrect multiple words processing * Convert subcommand string to lower case * Update SubcommandStrategyResolver.php * Added test coverage * Codestyle fixes --------- Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com> * Added split words handling * Fixed command id to be lowercase * Fixed test decorator * Added support for XINFO commands * Changed decorator to corresponding version * Updated tests to match server response * Updated test decorators * Added relay-incompatible decorator * Updated return type * Added support for FUNCTION DUMP, FUNCTION FLUSH, FUNCTION RESTORE commands (#1332) * Remove empty file * Added missing interface methods * Removed nullable type --------- Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com> Co-authored-by: Chayim <chayim@users.noreply.github.com>
- Loading branch information
1 parent
292bc43
commit d8da27b
Showing
5 changed files
with
358 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Predis package. | ||
* | ||
* (c) 2009-2020 Daniele Alessandri | ||
* (c) 2021-2023 Till Krüss | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Predis\Command\Argument\Stream; | ||
|
||
use Predis\Command\Argument\ArrayableArgument; | ||
|
||
class XInfoStreamOptions implements ArrayableArgument | ||
{ | ||
/** | ||
* @var array | ||
*/ | ||
protected $options = []; | ||
|
||
/** | ||
* Modifier provides a more verbose reply. | ||
* The COUNT option can be used to limit the number of stream and PEL entries that are returned. | ||
* | ||
* @param int|null $count | ||
* @return self | ||
*/ | ||
public function full(int $count = null): self | ||
{ | ||
$this->options[] = 'FULL'; | ||
|
||
if (null !== $count) { | ||
array_push($this->options, 'COUNT', $count); | ||
} | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
public function toArray(): array | ||
{ | ||
return $this->options; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Predis package. | ||
* | ||
* (c) 2009-2020 Daniele Alessandri | ||
* (c) 2021-2023 Till Krüss | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace Predis\Command\Container; | ||
|
||
use Predis\Command\Argument\Stream\XInfoStreamOptions; | ||
|
||
/** | ||
* @method array consumers(string $key, string $group) | ||
* @method array groups(string $key) | ||
* @method array stream(string $key, XInfoStreamOptions $options = null) | ||
*/ | ||
class XINFO extends AbstractContainer | ||
{ | ||
public function getContainerCommandId(): string | ||
{ | ||
return 'XINFO'; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Predis package. | ||
* | ||
* (c) 2009-2020 Daniele Alessandri | ||
* (c) 2021-2023 Till Krüss | ||
* | ||
* 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\Command\Argument\ArrayableArgument; | ||
use Predis\Command\Command as RedisCommand; | ||
|
||
class XINFO extends RedisCommand | ||
{ | ||
public function getId() | ||
{ | ||
return 'XINFO'; | ||
} | ||
|
||
public function setArguments(array $arguments) | ||
{ | ||
if ($arguments[0] === 'STREAM') { | ||
$this->setStreamArguments($arguments); | ||
} else { | ||
parent::setArguments($arguments); | ||
} | ||
} | ||
|
||
/** | ||
* @param array $arguments | ||
* @return void | ||
*/ | ||
private function setStreamArguments(array $arguments): void | ||
{ | ||
$processedArguments = [$arguments[0], $arguments[1]]; | ||
|
||
if (array_key_exists(2, $arguments) && $arguments[2] instanceof ArrayableArgument) { | ||
$processedArguments = array_merge($processedArguments, $arguments[2]->toArray()); | ||
} | ||
|
||
parent::setArguments($processedArguments); | ||
} | ||
|
||
public function parseResponse($data) | ||
{ | ||
$result = []; | ||
|
||
for ($i = 0, $iMax = count($data); $i < $iMax; $i++) { | ||
if (is_array($data[$i])) { | ||
$result[$i] = $this->parseResponse($data[$i]); | ||
} | ||
|
||
if (array_key_exists($i + 1, $data)) { | ||
if (is_array($data[$i + 1])) { | ||
$result[$data[$i]] = $this->parseResponse($data[++$i]); | ||
} else { | ||
$result[$data[$i]] = $data[++$i]; | ||
} | ||
} | ||
} | ||
|
||
return $result; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the Predis package. | ||
* | ||
* (c) 2009-2020 Daniele Alessandri | ||
* (c) 2021-2023 Till Krüss | ||
* | ||
* 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\Command\Argument\Stream\XInfoStreamOptions; | ||
|
||
class XINFO_Test extends PredisCommandTestCase | ||
{ | ||
/** | ||
* {@inheritDoc} | ||
*/ | ||
protected function getExpectedCommand(): string | ||
{ | ||
return XINFO::class; | ||
} | ||
|
||
/** | ||
* {@inheritDoc} | ||
*/ | ||
protected function getExpectedId(): string | ||
{ | ||
return 'XINFO'; | ||
} | ||
|
||
/** | ||
* @group disconnected | ||
*/ | ||
public function testConsumersFilterArguments(): void | ||
{ | ||
$arguments = ['CONSUMERS', 'key', 'group']; | ||
$expected = ['CONSUMERS', 'key', 'group']; | ||
|
||
$command = $this->getCommand(); | ||
$command->setArguments($arguments); | ||
|
||
$this->assertSameValues($expected, $command->getArguments()); | ||
} | ||
|
||
/** | ||
* @group disconnected | ||
*/ | ||
public function testGroupsFilterArguments(): void | ||
{ | ||
$arguments = ['GROUPS', 'key']; | ||
$expected = ['GROUPS', 'key']; | ||
|
||
$command = $this->getCommand(); | ||
$command->setArguments($arguments); | ||
|
||
$this->assertSameValues($expected, $command->getArguments()); | ||
} | ||
|
||
/** | ||
* @dataProvider streamArgumentsProvider | ||
* @group disconnected | ||
*/ | ||
public function testStreamFilterArguments(array $actualArguments, array $expectedResponse): void | ||
{ | ||
$command = $this->getCommand(); | ||
$command->setArguments($actualArguments); | ||
|
||
$this->assertSameValues($expectedResponse, $command->getArguments()); | ||
} | ||
|
||
/** | ||
* @dataProvider responseProvider | ||
* @group disconnected | ||
*/ | ||
public function testParseResponse(array $arguments, array $actualResponse, array $expectedResponse): void | ||
{ | ||
$command = $this->getCommand(); | ||
$command->setArguments($arguments); | ||
|
||
$this->assertSame($expectedResponse, $command->parseResponse($actualResponse)); | ||
} | ||
|
||
/** | ||
* @group connected | ||
* @group relay-incompatible | ||
* @return void | ||
* @requiresRedisVersion >= 6.2.0 | ||
*/ | ||
public function testReturnsConsumersOfGivenGroup(): void | ||
{ | ||
$redis = $this->getClient(); | ||
|
||
$entityId = $redis->xadd('stream', ['field' => 'value']); | ||
|
||
$this->assertEquals('OK', $redis->xgroup->create('stream', 'group', $entityId)); | ||
$this->assertSame(1, $redis->xgroup->createConsumer('stream', 'group', 'consumer')); | ||
|
||
$response = $redis->xinfo->consumers('stream', 'group'); | ||
|
||
foreach ($response as $consumer) { | ||
foreach (['name', 'pending', 'idle'] as $key) { | ||
$this->assertArrayHasKey($key, $consumer); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* @group connected | ||
* @group relay-incompatible | ||
* @return void | ||
* @requiresRedisVersion >= 7.0.0 | ||
*/ | ||
public function testReturnsConsumerGroupsOfGivenStream(): void | ||
{ | ||
$redis = $this->getClient(); | ||
|
||
$entityId = $redis->xadd('stream', ['field' => 'value']); | ||
|
||
$this->assertEquals('OK', $redis->xgroup->create('stream', 'group', $entityId)); | ||
|
||
$expectedResponse = [ | ||
[ | ||
'name' => 'group', | ||
'consumers' => 0, | ||
'pending' => 0, | ||
'last-delivered-id' => $entityId, | ||
'entries-read' => null, | ||
'lag' => 0, | ||
], | ||
]; | ||
|
||
$this->assertSame($expectedResponse, $redis->xinfo->groups('stream')); | ||
} | ||
|
||
/** | ||
* @group connected | ||
* @group relay-incompatible | ||
* @return void | ||
* @requiresRedisVersion >= 7.0.0 | ||
*/ | ||
public function testReturnsInformationAboutGivenStream(): void | ||
{ | ||
$redis = $this->getClient(); | ||
|
||
$entityId = $redis->xadd('stream', ['field' => 'value']); | ||
$expectedResponse = [ | ||
'length' => 1, | ||
'radix-tree-keys' => 1, | ||
'radix-tree-nodes' => 2, | ||
'last-generated-id' => $entityId, | ||
'max-deleted-entry-id' => '0-0', | ||
'entries-added' => 1, | ||
'recorded-first-entry-id' => $entityId, | ||
'entries' => [ | ||
[ | ||
$entityId => ['field' => 'value'], | ||
], | ||
], | ||
'groups' => [], | ||
]; | ||
|
||
$options = new XInfoStreamOptions(); | ||
$options->full(5); | ||
|
||
$this->assertSame($expectedResponse, $redis->xinfo->stream('stream', $options)); | ||
} | ||
|
||
public function streamArgumentsProvider(): array | ||
{ | ||
return [ | ||
'with default arguments' => [ | ||
['STREAM', 'key'], | ||
['STREAM', 'key'], | ||
], | ||
'with FULL modifier - no COUNT' => [ | ||
['STREAM', 'key', (new XInfoStreamOptions())->full()], | ||
['STREAM', 'key', 'FULL'], | ||
], | ||
'with FULL modifier - with COUNT' => [ | ||
['STREAM', 'key', (new XInfoStreamOptions())->full(15)], | ||
['STREAM', 'key', 'FULL', 'COUNT', 15], | ||
], | ||
]; | ||
} | ||
|
||
public function responseProvider(): array | ||
{ | ||
return [ | ||
'CONSUMERS response' => [ | ||
['CONSUMERS'], | ||
[['name', 'consumer', 'pending', 0, 'idle', 3, 'inactive', -1]], | ||
[['name' => 'consumer', 'pending' => 0, 'idle' => 3, 'inactive' => -1]], | ||
], | ||
'GROUPS response' => [ | ||
['GROUPS'], | ||
[['name', 'group', 'consumers', 0, 'pending', 0, 'last-delivered-id', 3]], | ||
[['name' => 'group', 'consumers' => 0, 'pending' => 0, 'last-delivered-id' => 3]], | ||
], | ||
'STREAM response' => [ | ||
['STREAM', 'key'], | ||
[['length', 1, 'entries-added', 1, 'entries', [['id', ['field', 'value']]]]], | ||
[['length' => 1, 'entries-added' => 1, 'entries' => [['id' => ['field' => 'value']]]]], | ||
], | ||
]; | ||
} | ||
} |