From e86a90deb51e4ca3b68685d8ca4b72a31c6f131d Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 24 Sep 2024 12:06:58 +0300 Subject: [PATCH 1/3] Fix invalid count in `IterableDataReader` when limit or/and offset used --- CHANGELOG.md | 1 + src/Reader/Iterable/IterableDataReader.php | 39 +++++++++++-------- .../Iterable/IterableDataReaderTest.php | 14 +++++++ 3 files changed, 37 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e26494..38a3b4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ value meaning `return nothing` (@samdark) - Chg #163: Rename `FilterableDataInterface::withFilterHandlers()` to `FilterableDataInterface::withAddedFilterHandlers()` (@samdark) - Enh #190: Use `str_contains` for case-sensitive match in `LikeHandler` (@samdark) +- Bug #195: Fix invalid count in `IterableDataReader` when limit or/and offset used (@vjik) ## 1.0.1 January 25, 2023 diff --git a/src/Reader/Iterable/IterableDataReader.php b/src/Reader/Iterable/IterableDataReader.php index 7a8491d..b76a940 100644 --- a/src/Reader/Iterable/IterableDataReader.php +++ b/src/Reader/Iterable/IterableDataReader.php @@ -57,7 +57,7 @@ final class IterableDataReader implements DataReaderInterface /** * @psalm-var array */ - private array $iterableFilterHandlers = []; + private array $iterableFilterHandlers; /** * @param iterable $data Data to iterate. @@ -153,13 +153,31 @@ public function getSort(): ?Sort public function count(): int { - return count($this->read()); + return count($this->internalRead(useLimitAndOffset: false)); } /** * @psalm-return array */ public function read(): array + { + return $this->internalRead(useLimitAndOffset: true); + } + + public function readOne(): array|object|null + { + if ($this->limit === 0) { + return null; + } + + /** @infection-ignore-all Any value more one in `withLimit()` will be ignored because returned `current()` */ + return $this + ->withLimit(1) + ->getIterator() + ->current(); + } + + private function internalRead(bool $useLimitAndOffset): array { $data = []; $skipped = 0; @@ -167,13 +185,13 @@ public function read(): array foreach ($sortedData as $key => $item) { // Don't return more than limit items. - if ($this->limit > 0 && count($data) === $this->limit) { + if ($useLimitAndOffset && $this->limit > 0 && count($data) === $this->limit) { /** @infection-ignore-all Here continue === break */ break; } // Skip offset items. - if ($skipped < $this->offset) { + if ($useLimitAndOffset && $skipped < $this->offset) { ++$skipped; continue; } @@ -187,19 +205,6 @@ public function read(): array return $data; } - public function readOne(): array|object|null - { - if ($this->limit === 0) { - return null; - } - - /** @infection-ignore-all Any value more one in `withLimit()` will be ignored because returned `current()` */ - return $this - ->withLimit(1) - ->getIterator() - ->current(); - } - /** * Return whether an item matches iterable filter. * diff --git a/tests/Reader/Iterable/IterableDataReaderTest.php b/tests/Reader/Iterable/IterableDataReaderTest.php index 3b9b911..95978f8 100644 --- a/tests/Reader/Iterable/IterableDataReaderTest.php +++ b/tests/Reader/Iterable/IterableDataReaderTest.php @@ -169,6 +169,20 @@ public function testCounting(): void $this->assertCount(5, $reader); } + public function testCountWithLimit(): void + { + $reader = (new IterableDataReader(self::DEFAULT_DATASET))->withLimit(2); + $this->assertSame(5, $reader->count()); + $this->assertCount(5, $reader); + } + + public function testCountWithOffset(): void + { + $reader = (new IterableDataReader(self::DEFAULT_DATASET))->withOffset(3); + $this->assertSame(5, $reader->count()); + $this->assertCount(5, $reader); + } + public function testReadOne(): void { $data = self::DEFAULT_DATASET; From 87ec7ee2f380b75e62db9b742c39b4dfeb506d98 Mon Sep 17 00:00:00 2001 From: Sergei Predvoditelev Date: Tue, 24 Sep 2024 12:09:11 +0300 Subject: [PATCH 2/3] fix psalm --- src/Reader/Iterable/IterableDataReader.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Reader/Iterable/IterableDataReader.php b/src/Reader/Iterable/IterableDataReader.php index b76a940..017891f 100644 --- a/src/Reader/Iterable/IterableDataReader.php +++ b/src/Reader/Iterable/IterableDataReader.php @@ -177,6 +177,9 @@ public function readOne(): array|object|null ->current(); } + /** + * @psalm-return array + */ private function internalRead(bool $useLimitAndOffset): array { $data = []; From 7140184e392033469ef756814b3d258cda92e422 Mon Sep 17 00:00:00 2001 From: Alexander Makarov Date: Tue, 24 Sep 2024 13:49:44 +0300 Subject: [PATCH 3/3] Update src/Reader/Iterable/IterableDataReader.php --- src/Reader/Iterable/IterableDataReader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Reader/Iterable/IterableDataReader.php b/src/Reader/Iterable/IterableDataReader.php index 017891f..e5e49a6 100644 --- a/src/Reader/Iterable/IterableDataReader.php +++ b/src/Reader/Iterable/IterableDataReader.php @@ -170,7 +170,7 @@ public function readOne(): array|object|null return null; } - /** @infection-ignore-all Any value more one in `withLimit()` will be ignored because returned `current()` */ + /** @infection-ignore-all Any value more than one in `withLimit()` will be ignored because returned `current()` */ return $this ->withLimit(1) ->getIterator()