Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 955da8d

Browse files
committedApr 5, 2022
Improve paginated response
Rework paginated response (close #31) Throw exception is client is not defined in Paginated response (close #30) Increase the code coverage
1 parent 61eefb6 commit 955da8d

30 files changed

+893
-45
lines changed
 

‎.gitignore

+1-4
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,5 @@
99
### PHPUnit
1010
/.phpunit.result.cache
1111

12-
### Documentation
13-
/docs
14-
1512
### Local test
16-
/test*.php
13+
/test*.php

‎CHANGELOG.md

+6
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
66

77
## [Unreleased v2.x]
88

9+
### Added
10+
11+
- Documentation on paginated responses
12+
- Throw custom exception is client is missing
13+
914
### Changed
1015

16+
- Rework paginated responses
1117
- (dev) Update version and rules of PHP-CS-Fixer and PHPStan
1218

1319
## [2.1.1]

‎docs/BuildQuery.md

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Building a Query
2+
3+
To help create RediSearch, the library offer a builder.
4+
5+
It all start with the class `\MacFJA\RediSearch\Query\Builder`. From there you can add groups and query elements.
6+
7+
---
8+
9+
For example, for search all people named `John`, and preferably with the last name `Doe` that work as an accountant in the 10 km around Washington DC, and the resume contain text `cake` the request will be:
10+
```php
11+
use MacFJA\RediSearch\Query\Builder;
12+
use MacFJA\RediSearch\Query\Builder\GeoFacet;
13+
use MacFJA\RediSearch\Query\Builder\TextFacet;
14+
use MacFJA\RediSearch\Query\Builder\Optional;
15+
use MacFJA\RediSearch\Redis\Command\SearchCommand\GeoFilterOption;
16+
17+
$queryBuilder = new Builder();
18+
$query = $queryBuilder
19+
->addTextFacet('firstname', 'John') // people named `John`
20+
->addElement(new Optional(new TextFacet(['lastname'], 'Doe'))) // preferably with the last name `Doe`
21+
->addTextFacet('job', 'accountant') // work as an accountant
22+
->addGeoFacet('address', -77.0365427, 38.8950368, 10, GeoFilterOption::UNIT_KILOMETERS) // in the 10 km around Washington DC
23+
->addString('cake') // the resume contain text `cake`
24+
->render();
25+
26+
// @firstname:John ~@lastname:Doe @job:accountant @address:[-77.0365427 38.8950368 10 km] cake
27+
```

‎docs/UsingResult.md

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Using result
2+
3+
As you can set an offset and limit on `FT.SEARCH` and `FT.AGGREGATE`, they are paginated commands.
4+
The result of those commands is a page, that can contain one or more document.
5+
6+
---
7+
8+
So in this library, the result of `\MacFJA\RediSearch\Redis\Command\Search` and `\MacFJA\RediSearch\Redis\Command\Aggregate` is also a paginated object:
9+
either a `\MacFJA\RediSearch\Redis\Response\PaginatedResponse` (for Search and Aggregate) or a `\MacFJA\RediSearch\Redis\Response\CursorResponse` (for Aggregate)
10+
11+
The 2 classes are representing a page.
12+
13+
Both `\MacFJA\RediSearch\Redis\Response\PaginatedResponse` and `\MacFJA\RediSearch\Redis\Response\CursorResponse` can be read inside a `foreach` loop or with any iterator function.
14+
(As they implement the [`\Iterator` interface](https://www.php.net/manual/en/class.iterator.php))
15+
What you are iterating over, are the pages (not the documents inside the page).
16+
17+
```php
18+
// If your RediSearch search have 15 results in total, but you set the pagination to 10 per page:
19+
/** @var PaginatedResponse $results */
20+
21+
/** @var array<SearchResponseItem> $items */
22+
$items = $results->current();
23+
// $items is a list of 10 SearchResponseItem
24+
25+
$results->next(); // To be able to class `->next()`, you need to call `->setClient()` first !
26+
27+
/** @var array<SearchResponseItem> $items */
28+
$items = $results->current();
29+
// $items is a list of 5 SearchResponseItem
30+
```
31+
32+
## Get all items on all pages
33+
34+
```php
35+
/** @var \MacFJA\RediSearch\Redis\Client $client */
36+
/** @var \MacFJA\RediSearch\Redis\Command\Search $search */
37+
38+
/** @var \MacFJA\RediSearch\Redis\Response\PaginatedResponse $results */
39+
$results = $client->execute($search);
40+
$results->setClient($client);
41+
42+
$items = [];
43+
foreach ($results as $pageIndex => $pageContent) {
44+
$items = array_merge($items, $pageContent);
45+
}
46+
/** @var \MacFJA\RediSearch\Redis\Response\SearchResponseItem $item */
47+
foreach ($items as $item) {
48+
doSomething($item);
49+
}
50+
```
51+
Be careful, this will load all items in the memory.
52+
This will also call Redis multiple time if there are several pages.
53+
54+
---
55+
56+
If you need to avoid loading all items in the memory, you can use [`ResponseItemIterator`](https://github.com/MacFJA/php-redisearch-integration/blob/main/src/Iterator/ResponseItemIterator.php) from the sister project [macfja/redisearch-integration](https://github.com/MacFJA/php-redisearch-integration).
57+
This class it a custom iterator that will load in memory only one page at the time.
58+
59+
```php
60+
/** @var \MacFJA\RediSearch\Redis\Client $client */
61+
/** @var \MacFJA\RediSearch\Redis\Command\Search $search */
62+
63+
$results = $client->execute($search);
64+
$allItems = new \MacFJA\RediSearch\Integration\Iterator\ResponseItemIterator($results, $client);
65+
/** @var \MacFJA\RediSearch\Redis\Response\SearchResponseItem $item */
66+
foreach ($allItems as $item) {
67+
// Only one page exist in the memory
68+
doSomething($item);
69+
}
70+
```
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* Copyright MacFJA
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
9+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
10+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
11+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
14+
* Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
namespace MacFJA\RediSearch\Exception;
23+
24+
use RuntimeException;
25+
use Throwable;
26+
27+
class MissingClientException extends RuntimeException
28+
{
29+
public function __construct(Throwable $previous = null)
30+
{
31+
parent::__construct('The Redis client is missing. You need to manually set it.', 0, $previous);
32+
}
33+
}

‎src/Redis/Client/AmpRedisClient.php

+6
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class AmpRedisClient extends AbstractClient
3333
/** @var Redis */
3434
private $redis;
3535

36+
/**
37+
* @codeCoverageIgnore
38+
*/
3639
private function __construct(Redis $redis)
3740
{
3841
if (!static::supports($redis)) {
@@ -77,6 +80,9 @@ public function pipeline(Command ...$commands): array
7780
}, $commands);
7881
}
7982

83+
/**
84+
* @codeCoverageIgnore
85+
*/
8086
protected function doPipeline(Command ...$commands): array
8187
{
8288
return [];

‎src/Redis/Client/CheprasovRedisClient.php

+3
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class CheprasovRedisClient extends AbstractClient
3333
/** @var AbstractRedisClient */
3434
private $redis;
3535

36+
/**
37+
* @codeCoverageIgnore
38+
*/
3639
private function __construct(AbstractRedisClient $redis)
3740
{
3841
if (!static::supports($redis)) {

‎src/Redis/Client/CredisClient.php

+3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ class CredisClient extends AbstractClient
3232
/** @var Credis_Client */
3333
private $redis;
3434

35+
/**
36+
* @codeCoverageIgnore
37+
*/
3538
private function __construct(Credis_Client $redis)
3639
{
3740
if (!self::supports($redis)) {

‎src/Redis/Client/PredisClient.php

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ class PredisClient extends AbstractClient
3434
/** @var ClientInterface */
3535
private $redis;
3636

37+
/**
38+
* @codeCoverageIgnore
39+
*/
3740
private function __construct(ClientInterface $redis)
3841
{
3942
if (!static::supports($redis)) {

‎src/Redis/Client/RedisentClient.php

+3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class RedisentClient extends AbstractClient
3131
/** @var Redis */
3232
private $redis;
3333

34+
/**
35+
* @codeCoverageIgnore
36+
*/
3437
private function __construct(Redis $redis)
3538
{
3639
if (!static::supports($redis)) {

‎src/Redis/Client/Rediska/RediskaRediSearchCommand.php

+3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
use Rediska_Command_Abstract;
2727
use Rediska_Connection_Exec;
2828

29+
/**
30+
* @codeCoverageIgnore
31+
*/
2932
class RediskaRediSearchCommand extends Rediska_Command_Abstract
3033
{
3134
public function create(): Rediska_Connection_Exec

‎src/Redis/Client/RediskaClient.php

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ class RediskaClient extends AbstractClient
3636
/** @var Rediska */
3737
private $redis;
3838

39+
/**
40+
* @codeCoverageIgnore
41+
*/
3942
private function __construct(Rediska $redis)
4043
{
4144
if (!static::supports($redis)) {

‎src/Redis/Client/TinyRedisClient.php

+3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ class TinyRedisClient extends AbstractClient
3030
/** @var \TinyRedisClient */
3131
private $redis;
3232

33+
/**
34+
* @codeCoverageIgnore
35+
*/
3336
public function __construct(\TinyRedisClient $redis)
3437
{
3538
if (!self::supports($redis)) {

‎src/Redis/Response/AggregateResponseItem.php

+17-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
/**
2525
* @codeCoverageIgnore Simple value object
2626
*/
27-
class AggregateResponseItem
27+
class AggregateResponseItem implements ResponseItem
2828
{
2929
/** @var array<string,null|array<mixed>|float|int|string> */
3030
private $fields = [];
@@ -49,8 +49,24 @@ public function getFields(): array
4949
* @param null|array<mixed>|float|int|string $default
5050
*
5151
* @return null|array<mixed>|float|int|string
52+
*
53+
* @deprecated Use ::getFieldValue instead
54+
* @codeCoverageIgnore
55+
* @psalm-suppress
56+
* @SuppressWarnings
5257
*/
5358
public function getValue(string $fieldName, $default = null)
59+
{
60+
trigger_error(sprintf(
61+
'Method %s is deprecated from version 2.2.0, use %s::getFieldValue instead',
62+
__METHOD__,
63+
__CLASS__
64+
), E_USER_DEPRECATED);
65+
// @phpstan-ignore-next-line
66+
return $this->getFieldValue($fieldName, $default);
67+
}
68+
69+
public function getFieldValue(string $fieldName, $default = null)
5470
{
5571
return $this->fields[$fieldName] ?? $default;
5672
}

‎src/Redis/Response/ArrayResponseTrait.php

+5-2
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,12 @@ private static function getNextValue(array $notKeyedArray, string $key)
8686
*/
8787
private static function getKeys(array $notKeyedArray): array
8888
{
89-
$keys = array_filter(array_values($notKeyedArray), static function (int $key): bool {
89+
if (count($notKeyedArray) % 2 > 0) {
90+
array_pop($notKeyedArray);
91+
}
92+
$keys = array_values(array_filter(array_values($notKeyedArray), static function (int $key): bool {
9093
return 0 === $key % 2;
91-
}, ARRAY_FILTER_USE_KEY);
94+
}, ARRAY_FILTER_USE_KEY));
9295

9396
return array_map(static function ($key): string {
9497
return (string) $key;

‎src/Redis/Response/ClientAware.php

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* Copyright MacFJA
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
9+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
10+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
11+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
14+
* Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
namespace MacFJA\RediSearch\Redis\Response;
23+
24+
use MacFJA\RediSearch\Redis\Client;
25+
26+
interface ClientAware
27+
{
28+
public function setClient(Client $client): ClientAware;
29+
30+
public function getClient(): ?Client;
31+
}
+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* Copyright MacFJA
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
9+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
10+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
11+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
14+
* Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
namespace MacFJA\RediSearch\Redis\Response;
23+
24+
use MacFJA\RediSearch\Redis\Client;
25+
26+
trait ClientAwareTrait
27+
{
28+
/** @var null|Client */
29+
private $client;
30+
31+
public function getClient(): ?Client
32+
{
33+
return $this->client;
34+
}
35+
36+
public function setClient(Client $client): ClientAware
37+
{
38+
$this->client = $client;
39+
40+
return $this;
41+
}
42+
}

‎src/Redis/Response/CursorResponse.php

+15-12
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
namespace MacFJA\RediSearch\Redis\Response;
2323

2424
use function count;
25+
use Countable;
2526
use Iterator;
27+
use MacFJA\RediSearch\Exception\MissingClientException;
2628
use MacFJA\RediSearch\Redis\Client;
2729
use MacFJA\RediSearch\Redis\Command\AbstractCommand;
2830
use MacFJA\RediSearch\Redis\Command\CursorRead;
@@ -31,17 +33,16 @@
3133
/**
3234
* @implements Iterator<int,AggregateResponseItem[]>
3335
*/
34-
class CursorResponse implements Response, Iterator
36+
class CursorResponse implements Response, Iterator, Countable, ClientAware
3537
{
38+
use ClientAwareTrait;
39+
3640
/** @var array<AggregateResponseItem> */
3741
private $items;
3842

3943
/** @var int */
4044
private $totalCount;
4145

42-
/** @var Client */
43-
private $client;
44-
4546
/** @var bool */
4647
private $doNext = false;
4748

@@ -73,26 +74,23 @@ public function __construct(int $cursorId, int $totalCount, array $items, int $s
7374
$this->cursorId = $cursorId;
7475
}
7576

76-
public function setClient(Client $client): self
77-
{
78-
$this->client = $client;
79-
80-
return $this;
81-
}
82-
8377
/**
8478
* @return array<AggregateResponseItem>
8579
*/
8680
public function current()
8781
{
8882
if ($this->doNext) {
83+
if (!($this->getClient() instanceof Client)) {
84+
throw new MissingClientException();
85+
}
86+
8987
$cursorRead = new CursorRead($this->redisVersion);
9088
$cursorRead->setIndex($this->index);
9189
$cursorRead->setCursorId($this->cursorId);
9290
$cursorRead->setCount($this->getPageSize());
9391

9492
/** @var CursorResponse $next */
95-
$next = $this->client->execute($cursorRead);
93+
$next = $this->getClient()->execute($cursorRead);
9694
$this->cursorId = $next->cursorId;
9795
$this->offset += count($this->items);
9896
$this->items = $next->items;
@@ -145,4 +143,9 @@ public function getTotalCount(): int
145143
{
146144
return $this->totalCount;
147145
}
146+
147+
public function count()
148+
{
149+
return $this->getPageCount();
150+
}
148151
}

‎src/Redis/Response/PaginatedResponse.php

+14-17
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,19 @@
2525
use Countable;
2626
use function is_int;
2727
use Iterator;
28+
use MacFJA\RediSearch\Exception\MissingClientException;
2829
use MacFJA\RediSearch\Redis\Client;
2930
use MacFJA\RediSearch\Redis\Command\PaginatedCommand;
3031
use MacFJA\RediSearch\Redis\Response;
3132

3233
/**
33-
* @implements Iterator<int,AggregateResponseItem[]|SearchResponseItem[]>
34+
* @implements Iterator<int,ResponseItem[]|AggregateResponseItem[]|SearchResponseItem[]>
3435
*/
35-
class PaginatedResponse implements Response, Iterator, Countable
36+
class PaginatedResponse implements Response, Iterator, Countable, ClientAware
3637
{
37-
/** @var array<AggregateResponseItem>|array<SearchResponseItem> */
38+
use ClientAwareTrait;
39+
40+
/** @var array<ResponseItem> */
3841
private $items;
3942

4043
/** @var PaginatedCommand */
@@ -43,17 +46,14 @@ class PaginatedResponse implements Response, Iterator, Countable
4346
/** @var int */
4447
private $totalCount;
4548

46-
/** @var Client */
47-
private $client;
48-
4949
/** @var null|int */
5050
private $requestedOffset;
5151

5252
/** @var null|int */
5353
private $requestedSize;
5454

5555
/**
56-
* @param AggregateResponseItem[]|SearchResponseItem[] $items
56+
* @param ResponseItem[] $items
5757
*/
5858
public function __construct(PaginatedCommand $command, int $totalCount, array $items)
5959
{
@@ -62,15 +62,8 @@ public function __construct(PaginatedCommand $command, int $totalCount, array $i
6262
$this->lastCommand = $command;
6363
}
6464

65-
public function setClient(Client $client): PaginatedResponse
66-
{
67-
$this->client = $client;
68-
69-
return $this;
70-
}
71-
7265
/**
73-
* @return array<AggregateResponseItem>|array<SearchResponseItem>
66+
* @return array<ResponseItem>
7467
*/
7568
public function current()
7669
{
@@ -141,17 +134,21 @@ public function getTotalCount(): int
141134

142135
public function count()
143136
{
144-
return $this->getTotalCount();
137+
return $this->getPageCount();
145138
}
146139

147140
private function updateWithLimit(int $offset, int $size): void
148141
{
142+
if (!($this->getClient() instanceof Client)) {
143+
throw new MissingClientException();
144+
}
145+
149146
/** @var PaginatedCommand $nextCommand */
150147
$nextCommand = clone $this->lastCommand;
151148
$nextCommand->setLimit($offset, $size);
152149

153150
/** @var PaginatedResponse $paginated */
154-
$paginated = $this->client->execute($nextCommand);
151+
$paginated = $this->getClient()->execute($nextCommand);
155152
$this->lastCommand = $nextCommand;
156153
$this->totalCount = $paginated->totalCount;
157154
$this->items = $paginated->items;

‎src/Redis/Response/ResponseItem.php

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* Copyright MacFJA
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
9+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
10+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
11+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
14+
* Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
namespace MacFJA\RediSearch\Redis\Response;
23+
24+
interface ResponseItem
25+
{
26+
/**
27+
* @return array<string,null|array<mixed>|float|int|string>
28+
*/
29+
public function getFields(): array;
30+
31+
/**
32+
* @param null|array<mixed>|bool|float|int|string $default
33+
*
34+
* @return null|array<mixed>|bool|float|int|string
35+
*/
36+
public function getFieldValue(string $fieldName, $default = null);
37+
}

‎src/Redis/Response/SearchResponseItem.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
/**
2525
* @codeCoverageIgnore Simple value object
2626
*/
27-
class SearchResponseItem
27+
class SearchResponseItem implements ResponseItem
2828
{
2929
/** @var string */
3030
private $hash;

‎tests/Redis/Command/CursorReadTest.php

+37
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@
2121

2222
namespace MacFJA\RediSearch\tests\Redis\Command;
2323

24+
use MacFJA\RediSearch\Exception\UnexpectedServerResponseException;
2425
use MacFJA\RediSearch\Redis\Command\CursorRead;
26+
use MacFJA\RediSearch\Redis\Response\CursorResponse;
2527
use PHPUnit\Framework\TestCase;
2628

2729
/**
@@ -32,6 +34,8 @@
3234
* @uses \MacFJA\RediSearch\Redis\Command\Option\NamelessOption
3335
* @uses \MacFJA\RediSearch\Redis\Command\Option\NamedOption
3436
* @uses \MacFJA\RediSearch\Redis\Command\Option\FlagOption
37+
* @uses \MacFJA\RediSearch\Redis\Response\CursorResponse
38+
* @uses \MacFJA\RediSearch\Exception\UnexpectedServerResponseException
3539
*
3640
* @internal
3741
*/
@@ -63,4 +67,37 @@ public function testFullOption(): void
6367
$command->setCount(30);
6468
static::assertSame(['READ', 'idx', 398, 'COUNT', 30], $command->getArguments());
6569
}
70+
71+
public function testParseResponseWithError(): void
72+
{
73+
$this->expectException(UnexpectedServerResponseException::class);
74+
75+
$command = new CursorRead();
76+
$command->parseResponse('');
77+
}
78+
79+
public function testParseResponse(): void
80+
{
81+
$rawResponse = [
82+
0 => [
83+
0 => 0,
84+
1 => [
85+
0 => 'f1',
86+
1 => 'bar',
87+
],
88+
2 => [
89+
0 => 'f1',
90+
1 => 'baz',
91+
],
92+
],
93+
1 => 976015094,
94+
];
95+
$command = new CursorRead();
96+
$command->setIndex('idx')
97+
->setCursorId(976015094)
98+
;
99+
$response = $command->parseResponse($rawResponse);
100+
101+
static::assertInstanceOf(CursorResponse::class, $response);
102+
}
66103
}

‎tests/Redis/Command/IndexListTest.php

+9
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,13 @@ public function testGetId(): void
3636
$command = new IndexList();
3737
static::assertSame('FT._LIST', $command->getId());
3838
}
39+
40+
public function testGetRediSearchVersion(): void
41+
{
42+
$command = new IndexList();
43+
44+
static::assertSame('2.0.0', $command->getRediSearchVersion());
45+
$command->setRediSearchVersion('2.2.0');
46+
static::assertSame('2.2.0', $command->getRediSearchVersion());
47+
}
3948
}

‎tests/Redis/Command/Option/CustomValidatorOptionTest.php

+19
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
namespace MacFJA\RediSearch\tests\Redis\Command\Option;
2323

24+
use BadMethodCallException;
2425
use Generator;
2526
use MacFJA\RediSearch\Redis\Command\Option\CustomValidatorOption;
2627
use MacFJA\RediSearch\Redis\Command\Option\NamelessOption;
@@ -61,6 +62,24 @@ public function testShorthands(): void
6162
static::assertFalse($invalidList->isValid());
6263
}
6364

65+
public function testInvalidMethodName(): void
66+
{
67+
$this->expectException(BadMethodCallException::class);
68+
$this->expectExceptionMessage('Call undefined method invalidName');
69+
70+
$decorator = new CustomValidatorOption(new NamelessOption('foo'), new Length(4));
71+
// @phpstan-ignore-next-line
72+
$decorator->invalidName();
73+
}
74+
75+
public function testVersionConstraint(): void
76+
{
77+
$decorator = new CustomValidatorOption(new NamelessOption('foo'), new Length(4));
78+
static::assertSame('*', $decorator->getVersionConstraint());
79+
$decorator = new CustomValidatorOption(new NamelessOption('foo', '>=1.0.0'), new Length(4));
80+
static::assertSame('>=1.0.0', $decorator->getVersionConstraint());
81+
}
82+
6483
public function dataProvider(string $testName): Generator
6584
{
6685
$invalidMinLengthOption = new CustomValidatorOption(new NamelessOption('foo'), new Length(4));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* Copyright MacFJA
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
9+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
10+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
11+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
14+
* Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
namespace MacFJA\RediSearch\tests\Redis\Response;
23+
24+
use MacFJA\RediSearch\tests\fixtures\Redis\Response\ArrayResponseTraitTester;
25+
use PHPUnit\Framework\TestCase;
26+
27+
/**
28+
* @covers \MacFJA\RediSearch\Redis\Response\ArrayResponseTrait
29+
*
30+
* @internal
31+
*/
32+
class ArrayResponseTraitTest extends TestCase
33+
{
34+
public function testOddGetPairs(): void
35+
{
36+
$data = [1, 2, 3];
37+
38+
$inlineArrayResponse = $this->getInlineArrayResponse();
39+
40+
static::assertSame(['1' => 2], $inlineArrayResponse->publicGetPairs($data));
41+
}
42+
43+
public function testEvenGetPairs(): void
44+
{
45+
$data = [1, 2, 3, 4];
46+
47+
$inlineArrayResponse = $this->getInlineArrayResponse();
48+
49+
static::assertSame(['1' => 2, '3' => 4], $inlineArrayResponse->publicGetPairs($data));
50+
}
51+
52+
public function testOddGetKeys(): void
53+
{
54+
$data = [1, 2, 3];
55+
56+
$inlineArrayResponse = $this->getInlineArrayResponse();
57+
58+
static::assertSame(['1'], $inlineArrayResponse->publicGetKeys($data));
59+
}
60+
61+
public function testEvenGetKeys(): void
62+
{
63+
$data = [1, 2, 3, 4];
64+
65+
$inlineArrayResponse = $this->getInlineArrayResponse();
66+
67+
static::assertSame(['1', '3'], $inlineArrayResponse->publicGetKeys($data));
68+
}
69+
70+
public function testOddGetValue(): void
71+
{
72+
$data = [1, 2, 3];
73+
74+
$inlineArrayResponse = $this->getInlineArrayResponse();
75+
76+
static::assertSame(2, $inlineArrayResponse->publicGetValue($data, '1'));
77+
static::assertNull($inlineArrayResponse->publicGetValue($data, '3'));
78+
}
79+
80+
public function testEvenGetValue(): void
81+
{
82+
$data = [1, 2, 3, 4];
83+
84+
$inlineArrayResponse = $this->getInlineArrayResponse();
85+
86+
static::assertSame(2, $inlineArrayResponse->publicGetValue($data, '1'));
87+
static::assertSame(4, $inlineArrayResponse->publicGetValue($data, '3'));
88+
static::assertNull($inlineArrayResponse->publicGetValue($data, '6'));
89+
}
90+
91+
public function testOddGetNextValue(): void
92+
{
93+
$data = [1, 2, 3];
94+
95+
$inlineArrayResponse = $this->getInlineArrayResponse();
96+
97+
static::assertSame(2, $inlineArrayResponse->publicGetNextValue($data, '1'));
98+
static::assertSame(3, $inlineArrayResponse->publicGetNextValue($data, '2'));
99+
static::assertNull($inlineArrayResponse->publicGetNextValue($data, '3'));
100+
}
101+
102+
public function testEvenGetNextValue(): void
103+
{
104+
$data = [1, 2, 3, 4];
105+
106+
$inlineArrayResponse = $this->getInlineArrayResponse();
107+
108+
static::assertSame(2, $inlineArrayResponse->publicGetNextValue($data, '1'));
109+
static::assertSame(3, $inlineArrayResponse->publicGetNextValue($data, '2'));
110+
static::assertSame(4, $inlineArrayResponse->publicGetNextValue($data, '3'));
111+
static::assertNull($inlineArrayResponse->publicGetNextValue($data, '6'));
112+
}
113+
114+
private function getInlineArrayResponse(): ArrayResponseTraitTester
115+
{
116+
return new ArrayResponseTraitTester();
117+
}
118+
}

‎tests/Redis/Response/InfoResponseTest.php

+54
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323

2424
use BadMethodCallException;
2525
use InvalidArgumentException;
26+
use MacFJA\RediSearch\Redis\Command\CreateCommand\GeoFieldOption;
27+
use MacFJA\RediSearch\Redis\Command\CreateCommand\NumericFieldOption;
28+
use MacFJA\RediSearch\Redis\Command\CreateCommand\TagFieldOption;
29+
use MacFJA\RediSearch\Redis\Command\CreateCommand\TextFieldOption;
2630
use MacFJA\RediSearch\Redis\Command\Info;
2731
use MacFJA\RediSearch\Redis\Response\InfoResponse;
2832
use PHPUnit\Framework\TestCase;
@@ -36,6 +40,9 @@
3640
* @uses \MacFJA\RediSearch\Redis\Command\Option\NamelessOption
3741
* @uses \MacFJA\RediSearch\Redis\Command\AbstractCommand::__construct
3842
* @uses \MacFJA\RediSearch\Redis\Command\Option\AbstractCommandOption
43+
* @uses \MacFJA\RediSearch\Redis\Command\CreateCommand\GeoFieldOption
44+
* @uses \MacFJA\RediSearch\Redis\Command\CreateCommand\NumericFieldOption
45+
* @uses \MacFJA\RediSearch\Redis\Command\CreateCommand\TagFieldOption
3946
* @uses \MacFJA\RediSearch\Redis\Command\CreateCommand\TextFieldOption
4047
* @uses \MacFJA\RediSearch\Redis\Command\Option\CustomValidatorOption
4148
* @uses \MacFJA\RediSearch\Redis\Command\Option\DecoratedOptionAwareTrait
@@ -79,6 +86,22 @@ public function testResponse(): void
7986
3 => new Status('WEIGHT'),
8087
4 => '1',
8188
],
89+
1 => [
90+
0 => new Status('labels'),
91+
1 => new Status('type'),
92+
2 => new Status('TAG'),
93+
],
94+
2 => [
95+
0 => new Status('place'),
96+
1 => new Status('type'),
97+
2 => new Status('GEO'),
98+
],
99+
3 => [
100+
0 => new Status('count'),
101+
1 => new Status('type'),
102+
2 => new Status('NUMERIC'),
103+
3 => new Status('NOINDEX'),
104+
],
82105
],
83106
8 => new Status('num_docs'),
84107
9 => '4',
@@ -176,6 +199,13 @@ public function doTestGetFieldsAsOption(InfoResponse $parsed): void
176199
$response = $parsed->getFieldsAsOption();
177200

178201
static::assertSame(['text', 'TEXT', 'WEIGHT', '1'], $response[0]->render());
202+
static::assertInstanceOf(TextFieldOption::class, $response[0]);
203+
static::assertSame(['labels', 'TAG'], $response[1]->render());
204+
static::assertInstanceOf(TagFieldOption::class, $response[1]);
205+
static::assertSame(['place', 'GEO'], $response[2]->render());
206+
static::assertInstanceOf(GeoFieldOption::class, $response[2]);
207+
static::assertSame(['count', 'NUMERIC', 'NOINDEX'], $response[3]->render());
208+
static::assertInstanceOf(NumericFieldOption::class, $response[3]);
179209
}
180210

181211
public function doTestGetIndexDefinition(InfoResponse $parsed): void
@@ -232,4 +262,28 @@ public function testNotANumber(): void
232262

233263
static::assertNull($response->getNumDocs());
234264
}
265+
266+
public function testDataCasting(): void
267+
{
268+
$response = new InfoResponse([
269+
'records_per_doc_avg', '1.5',
270+
'max_doc_id', '50',
271+
'index_name', 'idx',
272+
'indexing', '1',
273+
'non_existent_string', 'hello',
274+
'non_existent_float', 1.2,
275+
'non_existent_int', 1,
276+
]);
277+
278+
static::assertSame(1.5, $response->getRecordsPerDocAvg());
279+
static::assertSame(50, $response->getMaxDocId());
280+
static::assertSame('idx', $response->getIndexName());
281+
static::assertTrue($response->getIndexing());
282+
// @phpstan-ignore-next-line
283+
static::assertSame('hello', $response->getNonExistentString());
284+
// @phpstan-ignore-next-line
285+
static::assertSame(1.2, $response->getNonExistentFloat());
286+
// @phpstan-ignore-next-line
287+
static::assertSame(1, $response->getNonExistentInt());
288+
}
235289
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* Copyright MacFJA
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
9+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
10+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
11+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
14+
* Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
namespace MacFJA\RediSearch\tests\Redis\Response;
23+
24+
use function array_slice;
25+
use MacFJA\RediSearch\Exception\MissingClientException;
26+
use MacFJA\RediSearch\Redis\Client;
27+
use MacFJA\RediSearch\Redis\Command\PaginatedCommand;
28+
use MacFJA\RediSearch\Redis\Response\PaginatedResponse;
29+
use MacFJA\RediSearch\Redis\Response\SearchResponseItem;
30+
use MacFJA\RediSearch\tests\fixtures\Redis\Command\FakePaginatedCommand;
31+
use PHPUnit\Framework\TestCase;
32+
33+
/**
34+
* @covers \MacFJA\RediSearch\Exception\MissingClientException
35+
* @covers \MacFJA\RediSearch\Redis\Response\PaginatedResponse
36+
*
37+
* @uses \MacFJA\RediSearch\Redis\Command\AbstractCommand
38+
*
39+
* @internal
40+
*/
41+
class PaginatedResponseTest extends TestCase
42+
{
43+
public function testMultiplePages(): void
44+
{
45+
[$client, $command] = $this->getClientAndCommand();
46+
47+
/** @var PaginatedResponse $response */
48+
$response = $client->execute($command);
49+
50+
static::assertInstanceOf(PaginatedResponse::class, $response);
51+
52+
static::assertTrue($response->valid());
53+
static::assertSame('foo', $response->current()[0]->getFieldValue('f1'));
54+
static::assertCount(4, $response);
55+
static::assertEquals(2, $response->getPageSize());
56+
static::assertEquals(4, $response->getPageCount());
57+
static::assertEquals(7, $response->getTotalCount());
58+
static::assertEquals(0, $response->key());
59+
60+
$response->setClient($client);
61+
62+
$response->next();
63+
64+
static::assertTrue($response->valid());
65+
static::assertSame('bob', $response->current()[0]->getFieldValue('f1'));
66+
static::assertCount(4, $response);
67+
static::assertEquals(2, $response->getPageSize());
68+
static::assertEquals(4, $response->getPageCount());
69+
static::assertEquals(7, $response->getTotalCount());
70+
static::assertEquals(1, $response->key());
71+
72+
$response->next();
73+
74+
static::assertTrue($response->valid());
75+
static::assertSame('lorem', $response->current()[0]->getFieldValue('f1'));
76+
static::assertCount(4, $response);
77+
static::assertEquals(2, $response->getPageSize());
78+
static::assertEquals(4, $response->getPageCount());
79+
static::assertEquals(7, $response->getTotalCount());
80+
static::assertEquals(2, $response->key());
81+
82+
$response->next();
83+
84+
static::assertTrue($response->valid());
85+
static::assertSame('odd', $response->current()[0]->getFieldValue('f1'));
86+
static::assertCount(4, $response);
87+
static::assertEquals(2, $response->getPageSize());
88+
static::assertEquals(4, $response->getPageCount());
89+
static::assertEquals(7, $response->getTotalCount());
90+
static::assertEquals(3, $response->key());
91+
92+
$response->next();
93+
94+
static::assertFalse($response->valid());
95+
}
96+
97+
public function testMultiplePagesIterator(): void
98+
{
99+
[$client, $command] = $this->getClientAndCommand();
100+
101+
/** @var PaginatedResponse $response */
102+
$response = $client->execute($command);
103+
104+
static::assertInstanceOf(PaginatedResponse::class, $response);
105+
$response->setClient($client);
106+
107+
foreach ($response as $index => $page) {
108+
if (0 === $index) {
109+
static::assertSame('foo', $response->current()[0]->getFieldValue('f1'));
110+
}
111+
if (1 === $index) {
112+
static::assertSame('bob', $response->current()[0]->getFieldValue('f1'));
113+
}
114+
if (2 === $index) {
115+
static::assertSame('lorem', $response->current()[0]->getFieldValue('f1'));
116+
}
117+
if (3 === $index) {
118+
static::assertSame('odd', $response->current()[0]->getFieldValue('f1'));
119+
}
120+
121+
static::assertEquals(2, $response->getPageSize());
122+
static::assertEquals(4, $response->getPageCount());
123+
static::assertEquals(7, $response->getTotalCount());
124+
}
125+
}
126+
127+
public function testMissingClient(): void
128+
{
129+
$this->expectException(MissingClientException::class);
130+
[$client, $command] = $this->getClientAndCommand();
131+
132+
/** @var PaginatedResponse $response */
133+
$response = $client->execute($command);
134+
135+
static::assertInstanceOf(PaginatedResponse::class, $response);
136+
137+
static::assertTrue($response->valid());
138+
139+
$response->next();
140+
$response->current();
141+
}
142+
143+
public function testPageSizeSetToZero(): void
144+
{
145+
$command = new FakePaginatedCommand([]);
146+
$command->setLimit(0, 0);
147+
$response = new PaginatedResponse($command, 2, []);
148+
149+
static::assertSame(0, $response->key());
150+
static::assertSame(0, $response->getPageCount());
151+
static::assertCount(0, $response);
152+
}
153+
154+
/**
155+
* @return array{0:Client,1:FakePaginatedCommand}
156+
*/
157+
private function getClientAndCommand(): array
158+
{
159+
$command = new FakePaginatedCommand([]);
160+
161+
$client = $this->createMock(Client::class);
162+
$client->method('execute')->willReturnOnConsecutiveCalls(
163+
self::getResponses($command, 0, 2),
164+
self::getResponses($command, 2, 4),
165+
self::getResponses($command, 4, 6),
166+
self::getResponses($command, 6, 7)
167+
);
168+
169+
return [$client, $command];
170+
}
171+
172+
private static function getResponses(PaginatedCommand $command, int $from, int $to): PaginatedResponse
173+
{
174+
$response = [
175+
new SearchResponseItem('foobar1', ['f1' => 'foo', 'f2' => 'bar']),
176+
new SearchResponseItem('foobar2', ['f1' => 'baz', 'f2' => 'alice']),
177+
new SearchResponseItem('foobar3', ['f1' => 'bob', 'f2' => 'charlie']),
178+
new SearchResponseItem('foobar4', ['f1' => 'john', 'f2' => 'doe']),
179+
new SearchResponseItem('foobar5', ['f1' => 'lorem', 'f2' => 'ipsum']),
180+
new SearchResponseItem('foobar6', ['f1' => 'foobar', 'f2' => 'foobaz']),
181+
new SearchResponseItem('foobar7', ['f1' => 'odd', 'f2' => 'page']),
182+
];
183+
184+
return new PaginatedResponse(
185+
$command,
186+
7,
187+
array_slice($response, $from, $to - $from, false)
188+
);
189+
}
190+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* Copyright MacFJA
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
9+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
10+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
11+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
14+
* Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
namespace MacFJA\RediSearch\tests\fixtures\Redis\Command;
23+
24+
use MacFJA\RediSearch\Redis\Command;
25+
use MacFJA\RediSearch\Redis\Command\PaginatedCommand;
26+
27+
class FakePaginatedCommand extends Command\AbstractCommand implements PaginatedCommand
28+
{
29+
/** @var null|int */
30+
private $size;
31+
32+
/** @var null|int */
33+
private $offset;
34+
35+
public function getId(): string
36+
{
37+
return 'fake';
38+
}
39+
40+
public function getOffset(): ?int
41+
{
42+
return $this->offset;
43+
}
44+
45+
public function getSize(): ?int
46+
{
47+
return $this->size;
48+
}
49+
50+
public function setLimit(int $offset, int $size): PaginatedCommand
51+
{
52+
$this->offset = $offset;
53+
$this->size = $size;
54+
55+
return $this;
56+
}
57+
58+
protected function getRequiredOptions(): array
59+
{
60+
return [];
61+
}
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* Copyright MacFJA
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
9+
* documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
10+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
11+
* permit persons to whom the Software is furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
14+
* Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17+
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19+
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20+
*/
21+
22+
namespace MacFJA\RediSearch\tests\fixtures\Redis\Response;
23+
24+
use MacFJA\RediSearch\Redis\Response\ArrayResponseTrait;
25+
26+
class ArrayResponseTraitTester
27+
{
28+
use ArrayResponseTrait;
29+
30+
/**
31+
* @param array<float|int|mixed|string> $notKeyedArray
32+
*
33+
* @return array<string,mixed>
34+
*/
35+
public function publicGetPairs($notKeyedArray)
36+
{
37+
return self::getPairs($notKeyedArray);
38+
}
39+
40+
/**
41+
* @param array<float|int|mixed|string> $notKeyedArray
42+
*
43+
* @return array<string>
44+
*/
45+
public function publicGetKeys($notKeyedArray)
46+
{
47+
return self::getKeys($notKeyedArray);
48+
}
49+
50+
/**
51+
* @param array<array|mixed> $notKeyedArray
52+
*
53+
* @return null|array<mixed>|bool|float|int|string
54+
*/
55+
public function publicGetValue(array $notKeyedArray, string $key)
56+
{
57+
return self::getValue($notKeyedArray, $key);
58+
}
59+
60+
/**
61+
* @param array<array|mixed> $notKeyedArray
62+
*
63+
* @return null|bool|float|int|string
64+
*/
65+
public function publicGetNextValue(array $notKeyedArray, string $key)
66+
{
67+
return self::getNextValue($notKeyedArray, $key);
68+
}
69+
}

‎tests/integration/DockerTest.php

+9-8
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@
5858
* @covers \MacFJA\RediSearch\Redis\Client\CredisClient
5959
* @covers \MacFJA\RediSearch\Redis\Client\PredisClient
6060
* @covers \MacFJA\RediSearch\Redis\Client\RedisentClient
61-
* @covers \MacFJA\RediSearch\Redis\Client\Rediska\RediskaRediSearchCommand
6261
* @covers \MacFJA\RediSearch\Redis\Client\RediskaClient
6362
* @covers \MacFJA\RediSearch\Redis\Client\TinyRedisClient
6463
* @covers \MacFJA\RediSearch\Redis\Command\Aggregate
@@ -214,8 +213,9 @@ public function testIntegration($clientBuilder): void
214213

215214
/** @var PaginatedResponse $result */
216215
$result = $client->execute($search);
217-
static::assertCount(3, $result);
216+
static::assertCount(1, $result);
218217
static::assertSame(1, $result->getPageCount());
218+
static::assertSame(3, $result->getTotalCount());
219219

220220
/** @var array<SearchResponseItem> $page */
221221
foreach ($result as $page) {
@@ -255,12 +255,13 @@ public function testIntegration($clientBuilder): void
255255
->addGroupBy(new GroupByOption([], [ReduceOption::toList('age', 'list')]))
256256
);
257257

258-
static::assertCount(3, $result[0]);
259-
static::assertEquals('1', current($result[1])[0]->getValue('count'));
260-
static::assertEquals('2', current($result[1])[1]->getValue('count'));
261-
static::assertEquals('3', current($result[2])[0]->getValue('count'));
262-
static::assertEquals('3', current($result[3])[0]->getValue('count'));
263-
static::assertEquals(['30'], current($result[4])[0]->getValue('list'));
258+
static::assertCount(1, $result[0]);
259+
static::assertSame(3, $result[0]->getTotalCount());
260+
static::assertEquals('1', current($result[1])[0]->getFieldValue('count'));
261+
static::assertEquals('2', current($result[1])[1]->getFieldValue('count'));
262+
static::assertEquals('3', current($result[2])[0]->getFieldValue('count'));
263+
static::assertEquals('3', current($result[3])[0]->getFieldValue('count'));
264+
static::assertEquals(['30'], current($result[4])[0]->getFieldValue('list'));
264265

265266
$client->execute((new DropIndex())->setIndex('testDoc')->setDeleteDocument());
266267
$client->executeRaw('del', ...$docToRemove);

0 commit comments

Comments
 (0)
Please sign in to comment.