mirror of
https://github.com/predis/predis.git
synced 2026-08-31 20:53:09 +00:00
Added support for INDEXMISSING and INDEXEMPTY arguments (#1464)
* Added support for INDEXMISSING and INDEXEMPTY arguments * Added version restriction for test * Codestyle fixes * Updated test case to remove DIALECT 5 * Updated another test case * Added correct versions restriction --------- Co-authored-by: Till Krüss <tillkruss@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
52bdcf0c1f
commit
aaec13d074
@@ -29,6 +29,7 @@ abstract class AbstractField implements FieldInterface
|
||||
* @param string $alias
|
||||
* @param bool|string $sortable
|
||||
* @param bool $noIndex
|
||||
* @param bool $allowsMissing
|
||||
* @return void
|
||||
*/
|
||||
protected function setCommonOptions(
|
||||
@@ -36,7 +37,8 @@ abstract class AbstractField implements FieldInterface
|
||||
string $identifier,
|
||||
string $alias = '',
|
||||
$sortable = self::NOT_SORTABLE,
|
||||
bool $noIndex = false
|
||||
bool $noIndex = false,
|
||||
bool $allowsMissing = false
|
||||
): void {
|
||||
$this->fieldArguments[] = $identifier;
|
||||
|
||||
@@ -57,6 +59,10 @@ abstract class AbstractField implements FieldInterface
|
||||
if ($noIndex) {
|
||||
$this->fieldArguments[] = 'NOINDEX';
|
||||
}
|
||||
|
||||
if ($allowsMissing) {
|
||||
$this->fieldArguments[] = 'INDEXMISSING';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,13 +19,15 @@ class GeoField extends AbstractField
|
||||
* @param string $alias
|
||||
* @param bool|string $sortable
|
||||
* @param bool $noIndex
|
||||
* @param bool $allowsMissing
|
||||
*/
|
||||
public function __construct(
|
||||
string $identifier,
|
||||
string $alias = '',
|
||||
$sortable = self::NOT_SORTABLE,
|
||||
bool $noIndex = false
|
||||
bool $noIndex = false,
|
||||
bool $allowsMissing = false
|
||||
) {
|
||||
$this->setCommonOptions('GEO', $identifier, $alias, $sortable, $noIndex);
|
||||
$this->setCommonOptions('GEO', $identifier, $alias, $sortable, $noIndex, $allowsMissing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,13 +19,15 @@ class NumericField extends AbstractField
|
||||
* @param string $alias
|
||||
* @param bool|string $sortable
|
||||
* @param bool $noIndex
|
||||
* @param bool $allowsMissing
|
||||
*/
|
||||
public function __construct(
|
||||
string $identifier,
|
||||
string $alias = '',
|
||||
$sortable = self::NOT_SORTABLE,
|
||||
bool $noIndex = false
|
||||
bool $noIndex = false,
|
||||
bool $allowsMissing = false
|
||||
) {
|
||||
$this->setCommonOptions('NUMERIC', $identifier, $alias, $sortable, $noIndex);
|
||||
$this->setCommonOptions('NUMERIC', $identifier, $alias, $sortable, $noIndex, $allowsMissing);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ class TagField extends AbstractField
|
||||
* @param bool $noIndex
|
||||
* @param string $separator
|
||||
* @param bool $caseSensitive
|
||||
* @param bool $allowsEmpty
|
||||
*/
|
||||
public function __construct(
|
||||
string $identifier,
|
||||
@@ -28,9 +29,11 @@ class TagField extends AbstractField
|
||||
$sortable = self::NOT_SORTABLE,
|
||||
bool $noIndex = false,
|
||||
string $separator = ',',
|
||||
bool $caseSensitive = false
|
||||
bool $caseSensitive = false,
|
||||
bool $allowsEmpty = false,
|
||||
bool $allowsMissing = false
|
||||
) {
|
||||
$this->setCommonOptions('TAG', $identifier, $alias, $sortable, $noIndex);
|
||||
$this->setCommonOptions('TAG', $identifier, $alias, $sortable, $noIndex, $allowsMissing);
|
||||
|
||||
if ($separator !== ',') {
|
||||
$this->fieldArguments[] = 'SEPARATOR';
|
||||
@@ -40,5 +43,9 @@ class TagField extends AbstractField
|
||||
if ($caseSensitive) {
|
||||
$this->fieldArguments[] = 'CASESENSITIVE';
|
||||
}
|
||||
|
||||
if ($allowsEmpty) {
|
||||
$this->fieldArguments[] = 'INDEXEMPTY';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ class TextField extends AbstractField
|
||||
* @param string $phonetic
|
||||
* @param int $weight
|
||||
* @param bool $withSuffixTrie
|
||||
* @param bool $allowsEmpty
|
||||
* @param bool $allowsMissing
|
||||
*/
|
||||
public function __construct(
|
||||
string $identifier,
|
||||
@@ -32,9 +34,11 @@ class TextField extends AbstractField
|
||||
bool $noStem = false,
|
||||
string $phonetic = '',
|
||||
int $weight = 1,
|
||||
bool $withSuffixTrie = false
|
||||
bool $withSuffixTrie = false,
|
||||
bool $allowsEmpty = false,
|
||||
bool $allowsMissing = false
|
||||
) {
|
||||
$this->setCommonOptions('TEXT', $identifier, $alias, $sortable, $noIndex);
|
||||
$this->setCommonOptions('TEXT', $identifier, $alias, $sortable, $noIndex, $allowsMissing);
|
||||
|
||||
if ($noStem) {
|
||||
$this->fieldArguments[] = 'NOSTEM';
|
||||
@@ -53,5 +57,9 @@ class TextField extends AbstractField
|
||||
if ($withSuffixTrie) {
|
||||
$this->fieldArguments[] = 'WITHSUFFIXTRIE';
|
||||
}
|
||||
|
||||
if ($allowsEmpty) {
|
||||
$this->fieldArguments[] = 'INDEXEMPTY';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@ class GeoFieldTest extends TestCase
|
||||
['field_name', '', AbstractField::NOT_SORTABLE, true],
|
||||
['field_name', 'GEO', 'NOINDEX'],
|
||||
],
|
||||
'with INDEXMISSING modifier' => [
|
||||
['field_name', '', AbstractField::NOT_SORTABLE, false, true],
|
||||
['field_name', 'GEO', 'INDEXMISSING'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@ class NumericFieldTest extends TestCase
|
||||
['field_name', '', AbstractField::NOT_SORTABLE, true],
|
||||
['field_name', 'NUMERIC', 'NOINDEX'],
|
||||
],
|
||||
'with INDEXMISSING modifier' => [
|
||||
['field_name', '', AbstractField::NOT_SORTABLE, false, true],
|
||||
['field_name', 'NUMERIC', 'INDEXMISSING'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,14 @@ class TagFieldTest extends TestCase
|
||||
['field_name', '', AbstractField::NOT_SORTABLE, true],
|
||||
['field_name', 'TAG', 'NOINDEX'],
|
||||
],
|
||||
'with INDEXEMPTY modifier' => [
|
||||
['field_name', '', AbstractField::NOT_SORTABLE, false, ',', false, true],
|
||||
['field_name', 'TAG', 'INDEXEMPTY'],
|
||||
],
|
||||
'with INDEXMISSING modifier' => [
|
||||
['field_name', '', AbstractField::NOT_SORTABLE, false, ',', false, false, true],
|
||||
['field_name', 'TAG', 'INDEXMISSING'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,14 @@ class TextFieldTest extends TestCase
|
||||
['field_name', '', AbstractField::NOT_SORTABLE, true],
|
||||
['field_name', 'TEXT', 'NOINDEX'],
|
||||
],
|
||||
'with INDEXEMPTY modifier' => [
|
||||
['field_name', '', AbstractField::NOT_SORTABLE, false, false, '', 1, false, true],
|
||||
['field_name', 'TEXT', 'INDEXEMPTY'],
|
||||
],
|
||||
'with INDEXMISSING modifier' => [
|
||||
['field_name', '', AbstractField::NOT_SORTABLE, false, false, '', 1, false, false, true],
|
||||
['field_name', 'TEXT', 'INDEXMISSING'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
namespace Predis\Command\Redis\Search;
|
||||
|
||||
use Predis\Command\Argument\Search\CreateArguments;
|
||||
use Predis\Command\Argument\Search\SchemaFields\GeoField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\NumericField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TagField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TextField;
|
||||
@@ -113,6 +114,43 @@ class FTCREATE_Test extends PredisCommandTestCase
|
||||
$this->assertEquals('OK', $actualResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @group relay-resp3
|
||||
* @return void
|
||||
* @requiresRediSearchVersion >= 2.09.00
|
||||
*/
|
||||
public function testCreatesSearchIndexWithMissingAndEmptyFields(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$schema = [
|
||||
new TextField(
|
||||
'text_empty',
|
||||
'',
|
||||
false, false, false, '', 1, false, true
|
||||
),
|
||||
new TagField('tag_empty',
|
||||
'', false, false, ',', false, true
|
||||
),
|
||||
new NumericField('num_missing', '', false, false, true),
|
||||
new GeoField('geo_missing', '', false, false, true),
|
||||
new TextField(
|
||||
'text_empty_missing',
|
||||
'',
|
||||
false,
|
||||
false, false, '', 1, false, true, true
|
||||
),
|
||||
new TagField('tag_empty_missing',
|
||||
'', false, false, ',', false, true, true
|
||||
),
|
||||
];
|
||||
|
||||
$actualResponse = $redis->ftcreate('index', $schema);
|
||||
|
||||
$this->assertEquals('OK', $actualResponse);
|
||||
}
|
||||
|
||||
public function argumentsProvider(): array
|
||||
{
|
||||
return [
|
||||
|
||||
@@ -20,6 +20,7 @@ use Predis\Command\Argument\Search\SchemaFields\TagField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TextField;
|
||||
use Predis\Command\Argument\Search\SearchArguments;
|
||||
use Predis\Command\Redis\PredisCommandTestCase;
|
||||
use Predis\Response\ServerException;
|
||||
|
||||
/**
|
||||
* @group commands
|
||||
@@ -134,6 +135,98 @@ class FTSEARCH_Test extends PredisCommandTestCase
|
||||
* @return void
|
||||
* @requiresRediSearchVersion >= 2.09.00
|
||||
*/
|
||||
public function testSearchHashEmptyValues(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$hashResponse = $redis->hmset('test:1', ['text_empty' => '']);
|
||||
$this->assertEquals('OK', $hashResponse);
|
||||
|
||||
$schema = [
|
||||
new TextField(
|
||||
'text_empty',
|
||||
'',
|
||||
false, false, false, '', 1, false, true
|
||||
),
|
||||
new TextField(
|
||||
'text_not_empty',
|
||||
'',
|
||||
false, false, false, '', 1, false, false
|
||||
),
|
||||
];
|
||||
|
||||
$createArgs = new CreateArguments();
|
||||
$createArgs->prefix(['test:']);
|
||||
|
||||
$ftCreateResponse = $redis->ftcreate('idx', $schema, $createArgs);
|
||||
$this->assertEquals('OK', $ftCreateResponse);
|
||||
|
||||
// Timeout to make sure that index created before search performed.
|
||||
usleep(10000);
|
||||
|
||||
$searchArgs = new SearchArguments();
|
||||
$searchArgs->dialect(4);
|
||||
|
||||
$this->assertSame(
|
||||
[1, 'test:1', ['text_empty', '']],
|
||||
$redis->ftsearch('idx', '@text_empty:("")', $searchArgs)
|
||||
);
|
||||
|
||||
$this->expectException(ServerException::class);
|
||||
|
||||
$redis->ftsearch('idx', '@text_not_empty:("")', $searchArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @group relay-resp3
|
||||
* @return void
|
||||
* @requiresRediSearchVersion >= 2.09.00
|
||||
* @requiresRedisJsonVersion >= 1.0.0
|
||||
*/
|
||||
public function testSearchJsonEmptyValues(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$hashResponse = $redis->jsonset('test:1', '$', '{"text_empty":""}');
|
||||
$this->assertEquals('OK', $hashResponse);
|
||||
|
||||
$schema = [
|
||||
new TextField(
|
||||
'$.text_empty',
|
||||
'text_empty',
|
||||
false, false, false, '', 1, false, true
|
||||
),
|
||||
new TextField(
|
||||
'$.text_not_empty',
|
||||
'text_not_empty',
|
||||
false, false, false, '', 1, false, false
|
||||
),
|
||||
];
|
||||
|
||||
$createArgs = new CreateArguments();
|
||||
$createArgs->on('JSON');
|
||||
$createArgs->prefix(['test:']);
|
||||
|
||||
$ftCreateResponse = $redis->ftcreate('idx', $schema, $createArgs);
|
||||
$this->assertEquals('OK', $ftCreateResponse);
|
||||
|
||||
// Timeout to make sure that index created before search performed.
|
||||
usleep(10000);
|
||||
|
||||
$searchArgs = new SearchArguments();
|
||||
$searchArgs->dialect(4);
|
||||
|
||||
$this->assertSame(
|
||||
[1, 'test:1', ['$', '[{"text_empty":""}]']],
|
||||
$redis->ftsearch('idx', '@text_empty:("")', $searchArgs)
|
||||
);
|
||||
|
||||
$this->expectException(ServerException::class);
|
||||
|
||||
$redis->ftsearch('idx', '@text_not_empty:("")', $searchArgs);
|
||||
}
|
||||
|
||||
public function testSearchWithEnhancedMatchingCapabilities(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
@@ -243,7 +336,7 @@ class FTSEARCH_Test extends PredisCommandTestCase
|
||||
* @group connected
|
||||
* @group relay-resp3
|
||||
* @return void
|
||||
* @requiresRediSearchVersion >= 2.9.0
|
||||
* @requiresRediSearchVersion >= 2.09.00
|
||||
*/
|
||||
public function testGeoSearchQueriesContainsAndWithin(): void
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user