Skip to content

Commit 0cdb8b3

Browse files
committed
setup and some first bloom filter commands
0 parents  commit 0cdb8b3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+2136
-0
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/build/
2+
/.idea/
3+
/vendor/
4+
composer.lock
5+
.phpunit.result.cache

Dockerfile

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM php:7.2-cli
2+
RUN pecl install redis-5.0.1 \
3+
&& pecl install xdebug-2.6.0 \
4+
&& docker-php-ext-enable redis xdebug
5+
6+
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
7+
WORKDIR /app
8+
CMD ["/bin/bash", "-c", "sleep infinity"]

LICENSE

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2019 Rafael Campoy <[email protected]>
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be
12+
included in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

composer.json

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
{
2+
"name": "averias/phpredis-bloom",
3+
"description": "A PHP client for RedisBloom module using phpredis extension",
4+
"keywords": [
5+
"redis",
6+
"redisbloom",
7+
"probabilistic",
8+
"php"
9+
],
10+
"license": "MIT",
11+
"authors": [
12+
{
13+
"name": "Rafael Campoy Villalta",
14+
"email": "[email protected]"
15+
}
16+
],
17+
"require": {
18+
"php": "^7.2",
19+
"ext-redis": "*",
20+
"myclabs/php-enum": "^1.7"
21+
},
22+
"require-dev": {
23+
"phpunit/phpunit": "^8.4",
24+
"squizlabs/php_codesniffer": "^3.5.0"
25+
},
26+
"autoload": {
27+
"psr-4": {
28+
"Averias\\RedisBloom\\": "src/RedisBloomClient"
29+
}
30+
},
31+
"autoload-dev": {
32+
"psr-4": {
33+
"Averias\\RedisBloom\\Tests\\": "tests"
34+
}
35+
},
36+
"config": {
37+
"optimize-autoloader": true
38+
},
39+
"scripts": {
40+
"manifest": [
41+
"@composer validate"
42+
],
43+
"autoload": [
44+
"@composer dump-autoload --optimize"
45+
],
46+
"run-tests": [
47+
"@manifest",
48+
"@autoload",
49+
"vendor/bin/phpunit"
50+
],
51+
"git-reset": [
52+
"git reset --hard"
53+
],
54+
"update-all": [
55+
"@composer self-update --no-interaction",
56+
"@composer update --optimize-autoloader --no-interaction"
57+
]
58+
}
59+
}

docker-compose.yml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
version: "3"
2+
3+
services:
4+
php:
5+
container_name: phpredis-bloom
6+
build:
7+
dockerfile: Dockerfile
8+
context: .
9+
volumes:
10+
- .:/app
11+
redisjson:
12+
container_name: redislab-rebloom
13+
image: redislabs/rebloom:2.0.3

phpunit.xml

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit backupGlobals="false"
3+
backupStaticAttributes="false"
4+
bootstrap="vendor/autoload.php"
5+
colors="true"
6+
convertErrorsToExceptions="true"
7+
convertNoticesToExceptions="true"
8+
convertWarningsToExceptions="true"
9+
processIsolation="false"
10+
stopOnError="true"
11+
stopOnFailure="true"
12+
verbose="true"
13+
>
14+
<testsuites>
15+
<testsuite name="PHP RedisBloom Integration Tests">
16+
<directory suffix="Test.php" >./tests/Integration/</directory>
17+
</testsuite>
18+
<testsuite name="PHP RedisBloom Unit Tests">
19+
<directory suffix="Test.php">./tests/Unit</directory>
20+
</testsuite>
21+
</testsuites>
22+
<filter>
23+
<whitelist processUncoveredFilesFromWhitelist="true">
24+
<directory suffix=".php">./src/</directory>
25+
<exclude>
26+
<directory>./src/RedisBloomClient/Exception</directory>
27+
<directory>./src/RedisBloomClient/Enum</directory>
28+
<directory suffix="Interface.php">./src/</directory>
29+
</exclude>
30+
</whitelist>
31+
</filter>
32+
<logging>
33+
<log type="coverage-html" target="build/coverage" />
34+
</logging>
35+
<php>
36+
<const name="REDIS_TEST_SERVER" value="127.0.0.1" />
37+
<const name="REDIS_TEST_PORT" value="6379" />
38+
</php>
39+
</phpunit>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
/**
3+
* @project phpredis-bloom
4+
* @author Rafael Campoy <[email protected]>
5+
* @copyright 2019 Rafael Campoy <[email protected]>
6+
* @license MIT
7+
* @link https://github.com/averias/php-rejson
8+
*
9+
* Copyright and license information, is included in
10+
* the LICENSE file that is distributed with this source code.
11+
*/
12+
13+
namespace Averias\RedisBloom\Adapter;
14+
15+
use Averias\RedisBloom\Connection\ConnectionOptions;
16+
use Averias\RedisBloom\Exception\ConnectionException;
17+
use Averias\RedisBloom\Exception\RedisBloomModuleNotInstalledException;
18+
use Averias\RedisBloom\Exception\ResponseException;
19+
use Averias\RedisBloom\Validator\RedisClientValidatorInterface;
20+
use Redis;
21+
22+
class AdapterProvider
23+
{
24+
/** @var RedisClientValidatorInterface */
25+
protected $validator;
26+
27+
public function __construct(RedisClientValidatorInterface $validator)
28+
{
29+
$this->validator = $validator;
30+
}
31+
32+
/**
33+
* @param array|null $config
34+
* @return RedisClientAdapterInterface
35+
* @throws ConnectionException
36+
* @throws RedisBloomModuleNotInstalledException
37+
* @throws ResponseException
38+
*/
39+
public function get(array $config = []): RedisClientAdapterInterface
40+
{
41+
$redisClient = $this->getRedisClient($config);
42+
43+
$modules = $redisClient->executeRawCommand('MODULE', 'list');
44+
if (!$this->validator->isRedisBloomModuleInstalled($modules)) {
45+
throw new RedisBloomModuleNotInstalledException('RedisBloom module not installed in Redis server.');
46+
}
47+
48+
return $redisClient;
49+
}
50+
51+
/**
52+
* @param array $config
53+
* @return RedisClientAdapter
54+
* @throws ConnectionException
55+
*/
56+
protected function getRedisClient(array $config = []): RedisClientAdapter
57+
{
58+
$connectionOptions = new ConnectionOptions($config);
59+
return new RedisClientAdapter(new Redis(), $connectionOptions);
60+
}
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
<?php
2+
/**
3+
* @project phpredis-bloom
4+
* @author Rafael Campoy <[email protected]>
5+
* @copyright 2019 Rafael Campoy <[email protected]>
6+
* @license MIT
7+
* @link https://github.com/averias/php-rejson
8+
*
9+
* Copyright and license information, is included in
10+
* the LICENSE file that is distributed with this source code.
11+
*/
12+
13+
namespace Averias\RedisBloom\Adapter;
14+
15+
use Averias\RedisBloom\Connection\ConnectionOptions;
16+
use Averias\RedisBloom\Enum\ResponseParser;
17+
use Averias\RedisBloom\Exception\ConnectionException;
18+
use Averias\RedisBloom\Exception\ResponseException;
19+
use Redis;
20+
use Exception;
21+
22+
class RedisClientAdapter implements RedisClientAdapterInterface
23+
{
24+
/** @var Redis */
25+
protected $redis;
26+
27+
/** @var ConnectionOptions */
28+
protected $connectionOptions;
29+
30+
/**
31+
* @param Redis $redis
32+
* @param ConnectionOptions $connectionOptions
33+
* @throws ConnectionException
34+
*/
35+
public function __construct(Redis $redis, ConnectionOptions $connectionOptions)
36+
{
37+
$this->redis = $redis;
38+
$this->connectionOptions = $connectionOptions;
39+
$this->setConnection();
40+
}
41+
42+
/**
43+
* @param string $command
44+
* @param string $key
45+
* @param array $params
46+
* @return mixed
47+
* @throws ResponseException
48+
*/
49+
public function executeBloomCommand(string $command, string $key, array $params = [])
50+
{
51+
$response = $this->executeRawCommand($command, $key, ...$params);
52+
53+
if ($response === false) {
54+
$error = $this->redis->getLastError() ?? 'unknown';
55+
throw new ResponseException(
56+
sprintf("something was wrong when executing %s command, possible reasons: %s", $command, $error)
57+
);
58+
}
59+
60+
return $this->parseResponse($command, $response);
61+
}
62+
63+
/**
64+
* @param string $commandName
65+
* @param mixed ...$arguments
66+
* @return mixed
67+
* @throws ResponseException
68+
*/
69+
public function executeRawCommand(string $commandName, ...$arguments)
70+
{
71+
try {
72+
$this->checkConnection();
73+
return $this->redis->rawCommand($commandName, ...$arguments);
74+
} catch (Exception $e) {
75+
throw new ResponseException(
76+
sprintf(
77+
'the following error happened when executing the command "%s": %s',
78+
$commandName,
79+
$e->getMessage()
80+
)
81+
);
82+
}
83+
}
84+
85+
/**
86+
* @param string $methodName
87+
* @param array $arguments
88+
* @return mixed
89+
* @throws ResponseException
90+
*/
91+
public function executeCommandByName(string $methodName, array $arguments = [])
92+
{
93+
try {
94+
$this->checkConnection();
95+
return call_user_func_array([$this->redis, $methodName], $arguments);
96+
} catch (Exception $e) {
97+
throw new ResponseException(
98+
sprintf(
99+
'the following error happened when executing command "%s" with param "%s": %s',
100+
$methodName,
101+
implode(' ', $arguments),
102+
$e->getMessage()
103+
)
104+
);
105+
}
106+
}
107+
108+
/**
109+
* @throws ConnectionException
110+
*/
111+
protected function setConnection(): void
112+
{
113+
if (!$this->connect()) {
114+
throw new ConnectionException(
115+
sprintf("connection to Redis server failed, reason: %s", $this->redis->getLastError())
116+
);
117+
}
118+
119+
if ($this->connectionOptions->getDatabase() != 0) {
120+
$this->redis->select($this->connectionOptions->getDatabase());
121+
}
122+
123+
$this->redis->setOption(Redis::OPT_REPLY_LITERAL, 1);
124+
}
125+
126+
/**
127+
* @return bool
128+
*/
129+
protected function connect(): bool
130+
{
131+
$connectionValues = $this->connectionOptions->getConnectionValues();
132+
if ($this->connectionOptions->isPersistent()) {
133+
return $this->redis->pconnect(...$connectionValues);
134+
}
135+
136+
return $this->redis->connect(...$connectionValues);
137+
}
138+
139+
/**
140+
* @throws ConnectionException
141+
*/
142+
protected function checkConnection(): void
143+
{
144+
if (!$this->redis->isConnected()) {
145+
$this->setConnection();
146+
}
147+
}
148+
149+
protected function parseResponse(string $command, $response)
150+
{
151+
$responseParsers = ResponseParser::RESPONSE_PARSER;
152+
if (isset($responseParsers[$command])) {
153+
$className = $responseParsers[$command];
154+
$parser = new $className();
155+
return $parser->parse($response);
156+
}
157+
158+
return $response;
159+
}
160+
}

0 commit comments

Comments
 (0)