Skip to content

Commit

Permalink
Merge pull request #74 from ethanhann/v2
Browse files Browse the repository at this point in the history
v2 -> master
  • Loading branch information
ethanhann authored Mar 25, 2021
2 parents 51574ca + 1b7c583 commit 8f3b8c5
Show file tree
Hide file tree
Showing 19 changed files with 278 additions and 123 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
.idea/
.php_cs.cache
composer.lock
composer.phar
tests.log
/.phpunit.result.cache
5 changes: 2 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ before_install:
- docker run -d -p 6379:6379 redislabs/redisearch:edge --protected-mode no --loadmodule /usr/lib/redis/modules/redisearch.so
language: php
php:
- 7.0
- 7.1
- 7.2
- 7.3
- 7.4
- 8.0
before_script:
- printf "yes\n" | pecl install igbinary
- composer install
Expand Down
10 changes: 5 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,18 @@
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
"php": ">=7",
"php": ">=7.3||>=8.0",
"psr/log": "^1.0",
"ethanhann/redis-raw": "^0.3"
"ethanhann/redis-raw": "v1.x-dev"
},
"require-dev": {
"phpunit/phpunit": "^6.0",
"phpunit/phpunit": "^8.0",
"mockery/mockery": "^0.9.9",
"predis/predis": "^1.1",
"friendsofphp/php-cs-fixer": "^2.2",
"consolidation/robo": "^2.0",
"monolog/monolog": "^1.23",
"cheprasov/php-redis-client": "^1.8",
"ukko/phpredis-phpdoc": "^5.0@beta"
"ukko/phpredis-phpdoc": "^5.0@beta",
"cheprasov/php-redis-client": "^1.9"
}
}
14 changes: 14 additions & 0 deletions docs-src/indexing.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,17 @@ An alias can be deleted like this:
```php-inline
$index->deleteAlias('foo');
```

## Managing an Index

Whether or not an index exists can be checked:

```php-inline
$indexExists = $index->exists();
```

An index can be removed:

```php-inline
$index->drop();
```
2 changes: 1 addition & 1 deletion src/Aggregate/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public function load(array $fieldNames): BuilderInterface
* @param CanBecomeArrayInterface|array $reducer
* @return BuilderInterface
*/
public function groupBy($fieldName, CanBecomeArrayInterface $reducer = null): BuilderInterface
public function groupBy($fieldName = [], CanBecomeArrayInterface $reducer = null): BuilderInterface
{
$this->pipeline[] = new GroupBy(is_array($fieldName) ? $fieldName : [$fieldName]);
if (!is_null($reducer)) {
Expand Down
7 changes: 3 additions & 4 deletions src/Aggregate/Operations/AbstractFieldNameOperation.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ public function __construct(string $operationName, array $fieldNames)

public function toArray(): array
{
$count = count($this->fieldNames);
return $count > 0 ? array_merge(
[$this->operationName, $count],
return array_merge(
[$this->operationName, count($this->fieldNames)],
array_map(function ($fieldName) {
return "@$fieldName";
}, $this->fieldNames)
) : [];
);
}
}
13 changes: 13 additions & 0 deletions src/Exceptions/DocumentAlreadyInIndexException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Ehann\RediSearch\Exceptions;

use Exception;

class DocumentAlreadyInIndexException extends Exception
{
public function __construct($indexName, $documentId, $code = 0, Exception $previous = null)
{
parent::__construct("Document ($documentId) already in index ($indexName).", $code, $previous);
}
}
5 changes: 4 additions & 1 deletion src/Fields/FieldFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@

class FieldFactory
{
public static function make($name, $value)
public static function make($name, $value, $tagSeparator = ',')
{
if (is_array($value)) {
return (new TagField($name, implode($tagSeparator, $value)))->setSeparator($tagSeparator);
}
if ($value instanceof Tag) {
return new TagField($name, $value);
}
Expand Down
60 changes: 55 additions & 5 deletions src/Index.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Ehann\RediSearch\Document\AbstractDocumentFactory;
use Ehann\RediSearch\Document\DocumentInterface;
use Ehann\RediSearch\Exceptions\NoFieldsInIndexException;
use Ehann\RediSearch\Exceptions\UnknownIndexNameException;
use Ehann\RediSearch\Fields\FieldInterface;
use Ehann\RediSearch\Fields\GeoField;
use Ehann\RediSearch\Fields\NumericField;
Expand All @@ -15,6 +16,8 @@
use Ehann\RediSearch\Query\Builder as QueryBuilder;
use Ehann\RediSearch\Query\BuilderInterface as QueryBuilderInterface;
use Ehann\RediSearch\Query\SearchResult;
use Ehann\RedisRaw\Exceptions\RawCommandErrorException;
use RedisException;

class Index extends AbstractIndex implements IndexInterface
{
Expand Down Expand Up @@ -65,10 +68,23 @@ public function create()
return $this->rawCommand('FT.CREATE', array_merge($properties, $fieldDefinitions));
}

/**
* @return bool
*/
public function exists(): bool
{
try {
$this->info();
return true;
} catch (UnknownIndexNameException $exception) {
return false;
}
}

/**
* @return array
*/
protected function getFields(): array
public function getFields(): array
{
$fields = [];
foreach (get_object_vars($this) as $field) {
Expand Down Expand Up @@ -127,6 +143,15 @@ public function addTagField(string $name, bool $sortable = false, bool $noindex
return $this;
}

/**
* @param string $name
* @return array
*/
public function tagValues(string $name): array
{
return $this->rawCommand('FT.TAGVALS', [$this->getIndexName(), $name]);
}

/**
* @return mixed
*/
Expand Down Expand Up @@ -449,14 +474,30 @@ public function verbatim(): QueryBuilderInterface
/**
* @param array $documents
* @param bool $disableAtomicity
* @param bool $replace
*/
public function addMany(array $documents, $disableAtomicity = false)
public function addMany(array $documents, $disableAtomicity = false, $replace = false)
{
$result = null;

$pipe = $this->redisClient->multi($disableAtomicity);
foreach ($documents as $document) {
$this->_add($document);
if (is_array($document)) {
$document = $this->arrayToDocument($document);
}
$this->_add($document->setReplace($replace));
}
try {
$pipe->exec();
} catch (RedisException $exception) {
$result = $exception->getMessage();
} catch (RawCommandErrorException $exception) {
$result = $exception->getPrevious()->getMessage();
}

if ($result) {
$this->redisClient->validateRawCommandResults($result, 'PIPE', [$this->indexName, '*MANY']);
}
$pipe->exec();
}

/**
Expand All @@ -472,7 +513,7 @@ protected function _add(DocumentInterface $document, bool $isFromHash = false)

$properties = $isFromHash ? $document->getHashDefinition() : $document->getDefinition();
array_unshift($properties, $this->getIndexName());
return $this->rawCommand($isFromHash ? 'FT.ADDHASH' : 'FT.ADD', $properties);
return $this->rawCommand($isFromHash ? 'HSET' : 'FT.ADD', $properties);
}

/**
Expand Down Expand Up @@ -505,6 +546,15 @@ public function replace($document): bool
return $this->_add($this->arrayToDocument($document)->setReplace(true));
}

/**
* @param array $documents
* @param bool $disableAtomicity
*/
public function replaceMany(array $documents, $disableAtomicity = false)
{
$this->addMany($documents, $disableAtomicity, true);
}

/**
* @param $document
* @return bool
Expand Down
6 changes: 5 additions & 1 deletion src/IndexInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
interface IndexInterface extends BuilderInterface
{
public function create();
public function exists(): bool;
public function drop();
public function info();
public function delete($id, $deleteDocument = false);
public function getFields(): array;
public function makeDocument($id = null): DocumentInterface;
public function makeAggregateBuilder(): AggregateBuilderInterface;
public function getRedisClient(): RediSearchRedisClient;
Expand All @@ -29,9 +31,11 @@ public function addTextField(string $name, float $weight = 1.0, bool $sortable =
public function addNumericField(string $name, bool $sortable = false, bool $noindex = false): IndexInterface;
public function addGeoField(string $name, bool $noindex = false): IndexInterface;
public function addTagField(string $name, bool $sortable = false, bool $noindex = false, string $separator = ','): IndexInterface;
public function tagValues(string $name): array;
public function add($document): bool;
public function addMany(array $documents, $disableAtomicity = false);
public function addMany(array $documents, $disableAtomicity = false, $replace = false);
public function replace($document): bool;
public function replaceMany(array $documents, $disableAtomicity = false);
public function addHash($document): bool;
public function replaceHash($document): bool;
public function addAlias(string $name): bool;
Expand Down
27 changes: 22 additions & 5 deletions src/RediSearchRedisClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
namespace Ehann\RediSearch;

use Ehann\RediSearch\Exceptions\AliasDoesNotExistException;
use Ehann\RediSearch\Exceptions\DocumentAlreadyInIndexException;
use Ehann\RediSearch\Exceptions\RediSearchException;
use Ehann\RediSearch\Exceptions\UnknownIndexNameException;
use Ehann\RediSearch\Exceptions\UnknownIndexNameOrNameIsAnAliasItselfException;
use Ehann\RediSearch\Exceptions\UnknownRediSearchCommandException;
use Ehann\RediSearch\Exceptions\UnsupportedRediSearchLanguageException;
use Ehann\RedisRaw\AbstractRedisRawClient;
use Ehann\RedisRaw\Exceptions\RawCommandErrorException;
use Ehann\RedisRaw\RedisRawClientInterface;
use Exception;
use Psr\Log\LoggerInterface;
Expand All @@ -23,7 +25,7 @@ public function __construct(RedisRawClientInterface $redis)
$this->redis = $redis;
}

public function validateRawCommandResults($payload)
public function validateRawCommandResults($payload, string $command, array $arguments)
{
$isPayloadException = $payload instanceof Exception;
$message = $isPayloadException ? $payload->getMessage() : $payload;
Expand All @@ -38,7 +40,7 @@ public function validateRawCommandResults($payload)
throw new UnknownIndexNameException();
}

if (in_array($message, ['unsupported language', 'unsupported stemmer language', 'bad argument for `language`'])) {
if (in_array($message, ['no such language', 'unsupported language', 'unsupported stemmer language', 'bad argument for `language`'])) {
throw new UnsupportedRediSearchLanguageException();
}

Expand All @@ -54,6 +56,10 @@ public function validateRawCommandResults($payload)
throw new UnknownRediSearchCommandException($message);
}

if (in_array($message, ['document already in index', 'document already exists'])) {
throw new DocumentAlreadyInIndexException($arguments[0], $arguments[1]);
}

throw new RediSearchException($payload);
}

Expand All @@ -72,11 +78,22 @@ public function multi(bool $usePipeline = false)
return $this->redis->multi($usePipeline);
}

public function rawCommand(string $command, array $arguments)
public function rawCommand(string $command, array $arguments = [])
{
$result = $this->redis->rawCommand($command, $arguments);
try {
foreach ($arguments as $index => $value) {
/* The various RedisRaw clients have different expectations about arg types, but generally they all
* agree that they can be strings.
*/
$arguments[$index] = strval($value);
}
$result = $this->redis->rawCommand($command, $arguments);
} catch (RawCommandErrorException $exception) {
$result = $exception->getPrevious()->getMessage();
}

if ($command !== 'FT.EXPLAIN') {
$this->validateRawCommandResults($result);
$this->validateRawCommandResults($result, $command, $arguments);
}

return $result;
Expand Down
2 changes: 1 addition & 1 deletion tests/RediSearch/Aggregate/AggregationResultTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class AggregationResultTest extends RediSearchTestCase
protected $subject;
protected $expectedDocuments;

public function setUp()
public function setUp(): void
{
$this->expectedDocuments = [
['title' => 'part1'],
Expand Down
10 changes: 5 additions & 5 deletions tests/RediSearch/Aggregate/BuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class BuilderTest extends RediSearchTestCase
private $expectedResult3;
private $expectedResult4;

public function setUp()
public function setUp(): void
{
$this->indexName = 'AggregateBuilderTest';
$index = (new TestIndex($this->redisClient, $this->indexName))
Expand Down Expand Up @@ -67,7 +67,7 @@ public function setUp()
$this->subject = (new Builder($this->redisClient, $this->indexName));
}

public function tearDown()
public function tearDown(): void
{
$this->redisClient->flushAll();
}
Expand Down Expand Up @@ -244,7 +244,7 @@ public function testGetAbsoluteMin()
$expected = 9.99;

$result = $this->subject
->groupBy('_')
->groupBy()
->min('price')
->search();

Expand All @@ -256,7 +256,7 @@ public function testGetAbsoluteMax()
$expected = 38.85;

$result = $this->subject
->groupBy('_')
->groupBy()
->max('price')
->search();

Expand Down Expand Up @@ -284,7 +284,7 @@ public function testGetAbsoluteQuantile()
$expected = 38.85;

$result = $this->subject
->groupBy('_')
->groupBy()
->quantile('price', 0.5)
->search();

Expand Down
2 changes: 1 addition & 1 deletion tests/RediSearch/Fields/TextFieldTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class TextFieldTest extends TestCase
/** @var float */
private $defaultWeight = 1.0;

public function setUp()
public function setUp(): void
{
$this->subject = new TextField($this->fieldName);
}
Expand Down
Loading

0 comments on commit 8f3b8c5

Please sign in to comment.