From c075ed4aae44b27257ad38a86ffb38ba1bd276a0 Mon Sep 17 00:00:00 2001 From: ignace nyamagana butera Date: Sat, 13 Jan 2024 10:47:41 +0100 Subject: [PATCH] Fix bug with Statement implementation --- CHANGELOG.md | 1 + src/Statement.php | 21 +++++++++++++++++---- src/StatementTest.php | 24 ++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a4e47696..96c82373 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ All Notable changes to `Csv` will be documented in this file ### Fixed - `Reader::select` and `ResultSet::select` now internally use `Statement::select` +- `Statement` should not throw when `LimitIterator` is used in combinaison with `ArrayIterator`. ### Removed diff --git a/src/Statement.php b/src/Statement.php index e6b1aa1f..10ed55ac 100644 --- a/src/Statement.php +++ b/src/Statement.php @@ -18,6 +18,8 @@ use Iterator; use LimitIterator; +use OutOfBoundsException; + use function array_key_exists; use function array_reduce; use function array_search; @@ -153,9 +155,8 @@ public function process(TabularDataReader $tabular_data, array $header = []): Ta $header = $tabular_data->getHeader(); } - $iterator = $this->buildOrderBy( - array_reduce($this->where, $this->filter(...), $tabular_data->getRecords($header)) - ); + $iterator = array_reduce($this->where, $this->filter(...), $tabular_data->getRecords($header)); + $iterator = $this->buildOrderBy($iterator); /** @var Iterator> $iterator */ $iterator = new LimitIterator($iterator, $this->offset, $this->limit); @@ -189,8 +190,20 @@ protected function buildOrderBy(Iterator $iterator): Iterator return $cmp ?? 0; }; + + $class = new class () extends ArrayIterator { + public function seek(int $offset): void + { + try { + parent::seek($offset); + } catch (OutOfBoundsException) { + return; + } + } + }; + /** @var ArrayIterator> $it */ - $it = new ArrayIterator([...$iterator]); + $it = new $class([...$iterator]); $it->uasort($compare); return $it; diff --git a/src/StatementTest.php b/src/StatementTest.php index 11adc2ea..2c3a035c 100644 --- a/src/StatementTest.php +++ b/src/StatementTest.php @@ -156,4 +156,28 @@ public function testHeaderMapperOnStatement(): void 'does not exists' => null, ], $results->first()); } + + public function testOrderByDoesNotThrowOnInvalidOffsetOrLimit(): void + { + $document = <<setHeaderOffset(0); + $constraints = Statement::create() + ->select('Integer', 'Text', 'Date and Time') + ->where(fn (array $record): bool => (float) $record['Float'] < 1.3) + ->orderBy(fn (array $record1, array $record2): int => (int) $record2['Integer'] <=> (int) $record1['Integer']) + ->limit(5) + ->offset(2); + + self::assertSame([], $constraints->process($csv)->nth(42)); + } }