mirror of
https://github.com/predis/predis.git
synced 2026-09-15 12:57:10 +00:00
Added GEOSHAPE field and test polygon search (#1467)
* Added GEOSHAPE field and test polygon search * Added version restriction for test * Added edge to stack amtrix * Added same values assertion * Codestyle changes
This commit is contained in:
committed by
GitHub
parent
5d22ed775a
commit
8c2aac4f66
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Argument\Search\SchemaFields;
|
||||
|
||||
class GeoShapeField extends AbstractField
|
||||
{
|
||||
public const COORD_FLAT = 'FLAT';
|
||||
|
||||
/**
|
||||
* @param string $identifier
|
||||
* @param string $alias
|
||||
* @param bool|string $sortable
|
||||
* @param bool $noIndex
|
||||
* @param string|null $coordSystem Constants that represents available systems available on a class level.
|
||||
*/
|
||||
public function __construct(
|
||||
string $identifier,
|
||||
string $alias = '',
|
||||
$sortable = self::NOT_SORTABLE,
|
||||
bool $noIndex = false,
|
||||
?string $coordSystem = null
|
||||
) {
|
||||
$this->fieldArguments[] = $identifier;
|
||||
|
||||
if ($alias !== '') {
|
||||
$this->fieldArguments[] = 'AS';
|
||||
$this->fieldArguments[] = $alias;
|
||||
}
|
||||
|
||||
$this->fieldArguments[] = 'GEOSHAPE';
|
||||
|
||||
if (null !== $coordSystem) {
|
||||
$this->fieldArguments[] = $coordSystem;
|
||||
}
|
||||
|
||||
if ($sortable === self::SORTABLE) {
|
||||
$this->fieldArguments[] = 'SORTABLE';
|
||||
} elseif ($sortable === self::SORTABLE_UNF) {
|
||||
$this->fieldArguments[] = 'SORTABLE';
|
||||
$this->fieldArguments[] = 'UNF';
|
||||
}
|
||||
|
||||
if ($noIndex) {
|
||||
$this->fieldArguments[] = 'NOINDEX';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Predis package.
|
||||
*
|
||||
* (c) 2009-2020 Daniele Alessandri
|
||||
* (c) 2021-2023 Till Krüss
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Predis\Command\Argument\Search\SchemaFields;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class GeoShapeFieldTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider geoFieldsProvider
|
||||
* @param array $arguments
|
||||
* @param array $expectedSchema
|
||||
* @return void
|
||||
*/
|
||||
public function testReturnsCorrectFieldArgumentsArray(
|
||||
array $arguments,
|
||||
array $expectedSchema
|
||||
): void {
|
||||
$this->assertSame($expectedSchema, (new GeoShapeField(...$arguments))->toArray());
|
||||
}
|
||||
|
||||
public function geoFieldsProvider(): array
|
||||
{
|
||||
return [
|
||||
'with default arguments' => [
|
||||
['field_name'],
|
||||
['field_name', 'GEOSHAPE'],
|
||||
],
|
||||
'with alias' => [
|
||||
['field_name', 'fn'],
|
||||
['field_name', 'AS', 'fn', 'GEOSHAPE'],
|
||||
],
|
||||
'with sortable - no UNF' => [
|
||||
['field_name', '', AbstractField::SORTABLE],
|
||||
['field_name', 'GEOSHAPE', 'SORTABLE'],
|
||||
],
|
||||
'with sortable - with UNF' => [
|
||||
['field_name', '', AbstractField::SORTABLE_UNF],
|
||||
['field_name', 'GEOSHAPE', 'SORTABLE', 'UNF'],
|
||||
],
|
||||
'with NOINDEX modifier' => [
|
||||
['field_name', '', AbstractField::NOT_SORTABLE, true],
|
||||
['field_name', 'GEOSHAPE', 'NOINDEX'],
|
||||
],
|
||||
'with FLAT modifier' => [
|
||||
['field_name', '', AbstractField::NOT_SORTABLE, false, GeoShapeField::COORD_FLAT],
|
||||
['field_name', 'GEOSHAPE', 'FLAT'],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@
|
||||
namespace Predis\Command\Redis\Search;
|
||||
|
||||
use Predis\Command\Argument\Search\CreateArguments;
|
||||
use Predis\Command\Argument\Search\SchemaFields\AbstractField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\GeoShapeField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\NumericField;
|
||||
use Predis\Command\Argument\Search\SchemaFields\TextField;
|
||||
use Predis\Command\Argument\Search\SearchArguments;
|
||||
@@ -125,6 +127,123 @@ class FTSEARCH_Test extends PredisCommandTestCase
|
||||
$this->assertSame($expectedResponse, $actualResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @group relay-resp3
|
||||
* @return void
|
||||
* @requiresRediSearchVersion >= 2.9.0
|
||||
*/
|
||||
public function testGeoSearchQueriesIntersectsAndDisjoint(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->hset('geo:doc_point1', 'g', 'POINT (10 10)');
|
||||
$redis->hset('geo:doc_point2', 'g', 'POINT (50 50)');
|
||||
$redis->hset('geo:doc_polygon1', 'g', 'POLYGON ((20 20, 25 35, 35 25, 20 20))');
|
||||
$redis->hset('geo:doc_polygon2', 'g', 'POLYGON ((60 60, 65 75, 70 70, 65 55, 60 60))');
|
||||
|
||||
$ftCreateArguments = new CreateArguments();
|
||||
$ftCreateArguments->prefix(['geo:']);
|
||||
|
||||
$schema = [
|
||||
new GeoShapeField('g', '', AbstractField::NOT_SORTABLE, false, GeoShapeField::COORD_FLAT),
|
||||
];
|
||||
|
||||
$ftCreateResponse = $redis->ftcreate('idx_geo', $schema, $ftCreateArguments);
|
||||
$this->assertEquals('OK', $ftCreateResponse);
|
||||
|
||||
$ftSearchArguments = new SearchArguments();
|
||||
$ftSearchArguments->params(['shape', 'POLYGON ((15 15, 75 15, 50 70, 20 40, 15 15))']);
|
||||
$ftSearchArguments->noContent();
|
||||
$ftSearchArguments->dialect(3);
|
||||
|
||||
$actualResponse = $redis->ftsearch('idx_geo', '@g:[intersects $shape]', $ftSearchArguments);
|
||||
$this->assertSameValues(
|
||||
[
|
||||
2,
|
||||
'geo:doc_polygon1',
|
||||
'geo:doc_point2',
|
||||
], $actualResponse
|
||||
);
|
||||
|
||||
$actualResponse = $redis->ftsearch('idx_geo', '@g:[disjoint $shape]', $ftSearchArguments);
|
||||
$this->assertSameValues(
|
||||
[
|
||||
2,
|
||||
'geo:doc_polygon2',
|
||||
'geo:doc_point1',
|
||||
], $actualResponse
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group connected
|
||||
* @group relay-resp3
|
||||
* @return void
|
||||
* @requiresRediSearchVersion >= 2.9.0
|
||||
*/
|
||||
public function testGeoSearchQueriesContainsAndWithin(): void
|
||||
{
|
||||
$redis = $this->getClient();
|
||||
|
||||
$redis->hset('geo:doc_point1', 'g', 'POINT (10 10)');
|
||||
$redis->hset('geo:doc_point2', 'g', 'POINT (50 50)');
|
||||
$redis->hset('geo:doc_polygon1', 'g', 'POLYGON ((20 20, 25 35, 35 25, 20 20))');
|
||||
$redis->hset('geo:doc_polygon2', 'g', 'POLYGON ((60 60, 65 75, 70 70, 65 55, 60 60))');
|
||||
|
||||
$ftCreateArguments = new CreateArguments();
|
||||
$ftCreateArguments->prefix(['geo:']);
|
||||
|
||||
$schema = [
|
||||
new GeoShapeField('g', '',
|
||||
AbstractField::NOT_SORTABLE, false, GeoShapeField::COORD_FLAT
|
||||
),
|
||||
];
|
||||
|
||||
$ftCreateResponse = $redis->ftcreate('idx_geo', $schema, $ftCreateArguments);
|
||||
$this->assertEquals('OK', $ftCreateResponse);
|
||||
|
||||
$ftSearchArguments = new SearchArguments();
|
||||
$ftSearchArguments->params(['shape', 'POINT(25 25)']);
|
||||
$ftSearchArguments->noContent();
|
||||
$ftSearchArguments->dialect(3);
|
||||
|
||||
$actualResponse = $redis->ftsearch('idx_geo', '@g:[contains $shape]', $ftSearchArguments);
|
||||
$this->assertSameValues(
|
||||
[
|
||||
1,
|
||||
'geo:doc_polygon1',
|
||||
], $actualResponse
|
||||
);
|
||||
|
||||
$ftSearchArguments = new SearchArguments();
|
||||
$ftSearchArguments->params(['shape', 'POLYGON((24 24, 24 26, 25 25, 24 24))']);
|
||||
$ftSearchArguments->noContent();
|
||||
$ftSearchArguments->dialect(3);
|
||||
|
||||
$actualResponse = $redis->ftsearch('idx_geo', '@g:[contains $shape]', $ftSearchArguments);
|
||||
$this->assertSameValues(
|
||||
[
|
||||
1,
|
||||
'geo:doc_polygon1',
|
||||
], $actualResponse
|
||||
);
|
||||
|
||||
$ftSearchArguments = new SearchArguments();
|
||||
$ftSearchArguments->params(['shape', 'POLYGON((15 15, 75 15, 50 70, 20 40, 15 15))']);
|
||||
$ftSearchArguments->noContent();
|
||||
$ftSearchArguments->dialect(3);
|
||||
|
||||
$actualResponse = $redis->ftsearch('idx_geo', '@g:[within $shape]', $ftSearchArguments);
|
||||
$this->assertSameValues(
|
||||
[
|
||||
2,
|
||||
'geo:doc_polygon1',
|
||||
'geo:doc_point2',
|
||||
], $actualResponse
|
||||
);
|
||||
}
|
||||
|
||||
public function argumentsProvider(): array
|
||||
{
|
||||
return [
|
||||
|
||||
Reference in New Issue
Block a user