palicao/phpRebloom

View on GitHub
src/BloomFilter.php

Summary

Maintainability
A
45 mins
Test Coverage
A
96%
<?php
declare(strict_types=1);

namespace Palicao\PhpRebloom;

use Palicao\PhpRebloom\Exception\KeyNotFoundException;
use Palicao\PhpRebloom\Exception\ErrorRateOutOfBoundsException;
use RedisException;

final class BloomFilter extends BaseFilter
{
    /**
     * @param string $key
     * @param float $error
     * @param int $capacity
     * @return bool
     * @throws RedisException
     */
    public function reserve(string $key, float $error, int $capacity): bool
    {
        $this->assertErrorRateIsInRange($error);
        return (bool)$this->client->executeCommand(['BF.RESERVE', $key, $error, $capacity]);
    }

    /**
     * @param string $key
     * @param string $value
     * @param float|null $error
     * @param int|null $capacity
     * @return bool
     * @throws RedisException
     */
    public function insert(string $key, string $value, ?float $error = null, ?int $capacity = null): bool
    {
        $result = $this->insertMany($key, [$value], $error, $capacity);
        return array_pop($result);
    }

    /**
     * @param string $key
     * @param string[] $values
     * @param float|null $error
     * @param int|null $capacity
     * @return bool[]
     * @throws RedisException
     */
    public function insertMany(string $key, array $values, ?float $error = null, ?int $capacity = null): array
    {
        $count = count($values);
        if ($count === 0) {
            return [];
        }
        if ($error === null && $capacity === null) {
            if ($count === 1) {
                $result = [$this->client->executeCommand(['BF.ADD', $key, array_pop($values)])];
            } else {
                $result = $this->client->executeCommand(array_merge(['BF.MADD', $key], $values));
            }
            return self::arrayToBool($result);
        }

        $params = ['BF.INSERT', $key];
        if ($capacity !== null) {
            $params[] = 'CAPACITY';
            $params[] = $capacity;
        }
        if ($error !== null) {
            $this->assertErrorRateIsInRange($error);
            $params[] = 'ERROR';
            $params[] = $error;
        }

        $result = $this->client->executeCommand(array_merge($params, ['ITEMS'], $values));
        return self::arrayToBool($result);
    }

    /**
     * @param string $key
     * @param string $value
     * @return bool
     * @throws RedisException
     */
    public function insertIfKeyExists(string $key, string $value): bool
    {
        $result = $this->insertManyIfKeyExists($key, [$value]);
        return array_pop($result);
    }

    /**
     * @param string $key
     * @param string[] $values
     * @return bool[]
     * @throws RedisException
     */
    public function insertManyIfKeyExists(string $key, array $values): array
    {
        if (count($values) === 0) {
            return [];
        }
        $result = $this->client->executeCommand(array_merge(['BF.INSERT', $key, 'NOCREATE', 'ITEMS'], $values));
        if ($result === false) {
            throw new KeyNotFoundException(sprintf('Key %s does not exist', $key));
        }
        return self::arrayToBool($result);
    }

    /**
     * @param string $key
     * @param string $value
     * @return bool
     * @throws RedisException
     */
    public function exists(string $key, string $value): bool
    {
        return (bool)$this->client->executeCommand(['BF.EXISTS', $key, $value]);
    }

    /**
     * @param string $key
     * @param string[] $values
     * @return bool[]
     * @throws RedisException
     */
    public function manyExist(string $key, array $values): array
    {
        if (count($values) === 0) {
            return [];
        }
        return self::arrayToBool($this->client->executeCommand(array_merge(['BF.MEXISTS', $key], $values)));
    }

    /**
     * @param string $key
     * @return array
     * @throws RedisException
     */
    public function scanDump(string $key): array
    {
        return $this->doScanDump($key, 'BF');
    }

    /**
     * @param string $key
     * @param array $chunks
     * @throws RedisException
     */
    public function loadChunks(string $key, array $chunks): void
    {
        $this->doLoadChunks($key, $chunks, 'BF');
    }

    /**
     * @param float $error
     * @throws ErrorRateOutOfBoundsException
     */
    private function assertErrorRateIsInRange(float $error): void
    {
        if ($error < 0 || $error > 1) {
            throw new ErrorRateOutOfBoundsException(sprintf('Error rate must be >= 0 and <= 1'));
        }
    }
}