diff --git a/src/ClientContextInterface.php b/src/ClientContextInterface.php index e3521156..c6708fd2 100644 --- a/src/ClientContextInterface.php +++ b/src/ClientContextInterface.php @@ -68,8 +68,10 @@ use Predis\Command\CommandInterface; * @method $this cfmexists(string $key, ...$item) * @method $this cfinfo(string $key) * @method $this cfinsert(string $key, int $capacity = -1, bool $noCreate = false, string ...$item) + * @method $this cfinsertnx(string $key, int $capacity = -1, bool $noCreate = false, string ...$item) * @method $this cfreserve(string $key, int $capacity, int $bucketSize = -1, int $maxIterations = -1, int $expansion = -1) * @method $this cfscandump(string $key, int $iterator) * @method $this decr($key) + * @method $this decr($key) * @method $this decrby($key, $decrement) * @method $this failover(?To $to = null, bool $abort = false, int $timeout = -1) * @method $this get($key) diff --git a/src/ClientInterface.php b/src/ClientInterface.php index af26e273..6d000d1d 100644 --- a/src/ClientInterface.php +++ b/src/ClientInterface.php @@ -77,6 +77,7 @@ use Predis\Response\Status; * @method int cfmexists(string $key, ...$item) * @method array cfinfo(string $key) * @method array cfinsert(string $key, int $capacity = -1, bool $noCreate = false, string ...$item) + * @method array cfinsertnx(string $key, int $capacity = -1, bool $noCreate = false, string ...$item) * @method Status cfreserve(string $key, int $capacity, int $bucketSize = -1, int $maxIterations = -1, int $expansion = -1) * @method array cfscandump(string $key, int $iterator) * @method int decr(string $key) diff --git a/src/Command/Redis/CuckooFilter/CFINSERTNX.php b/src/Command/Redis/CuckooFilter/CFINSERTNX.php new file mode 100644 index 00000000..629327b4 --- /dev/null +++ b/src/Command/Redis/CuckooFilter/CFINSERTNX.php @@ -0,0 +1,27 @@ +getCommand(); + $command->setArguments($actualArguments); + + $this->assertSameValues($expectedArguments, $command->getArguments()); + } + + /** + * @group connected + * @dataProvider filtersProvider + * @param array $filterArguments + * @param string $key + * @param int $expectedCapacity + * @param array $expectedResponse + * @return void + * @requiresRedisBfVersion >= 1.0.0 + */ + public function testInsertItemsIntoNonExistingCuckooFilter( + array $filterArguments, + string $key, + int $expectedCapacity, + array $expectedResponse + ): void { + $redis = $this->getClient(); + + $actualResponse = $redis->cfinsertnx(...$filterArguments); + $info = $redis->cfinfo($key); + + $this->assertSame($expectedResponse, $actualResponse); + $this->assertSame($expectedCapacity, $info['Size']); + } + + /** + * @group connected + * @return void + * @requiresRedisBfVersion >= 1.0.0 + */ + public function testDoNotInsertAlreadyExistingItems(): void + { + $redis = $this->getClient(); + + $redis->cfadd('filter', 'item1'); + $redis->cfadd('filter', 'item2'); + + $actualResponse = $redis->cfinsertnx('filter', -1, false, 'item1', 'item2'); + $this->assertSame([0, 0], $actualResponse); + } + + /** + * @group connected + * @return void + * @requiresRedisBfVersion >= 1.0.0 + */ + public function testInsertThrowsErrorOnInsertingIntoNonExistingFilterWithNoCreateModifier(): void + { + $redis = $this->getClient(); + + $this->expectException(ServerException::class); + $this->expectExceptionMessage('ERR not found'); + + $redis->cfinsertnx('key', -1, true, 'item'); + } + + /** + * @group connected + * @return void + * @requiresRedisBfVersion >= 1.0.0 + */ + public function testInsertIntoAlreadyExistingFilterWithNoCreateModifier(): void + { + $redis = $this->getClient(); + + $redis->cfadd('filter', 'item'); + + $actualResponse = $redis->cfinsertnx('filter', -1, true, 'item1'); + $this->assertSame([1], $actualResponse); + } + + public function argumentsProvider(): array + { + return [ + 'with default arguments' => [ + ['key', -1, false, 'item1'], + ['key', 'ITEMS', 'item1'], + ], + 'with CAPACITY modifier' => [ + ['key', 500, false, 'item1'], + ['key', 'CAPACITY', 500, 'ITEMS', 'item1'], + ], + 'with NOCREATE modifier' => [ + ['key', -1, true, 'item1'], + ['key', 'NOCREATE', 'ITEMS', 'item1'], + ], + 'with all arguments' => [ + ['key', 500, true, 'item1', 'item2'], + ['key', 'CAPACITY', 500, 'NOCREATE', 'ITEMS', 'item1', 'item2'], + ], + ]; + } + + public function filtersProvider(): array + { + return [ + 'with default arguments' => [ + ['key', -1, false, 'item1'], + 'key', + 1080, + [1], + ], + 'with modified CAPACITY' => [ + ['key', 500, false, 'item1'], + 'key', + 568, + [1], + ], + 'with multiple items' => [ + ['key', -1, false, 'item1', 'item2'], + 'key', + 1080, + [1, 1], + ], + ]; + } +}