Skip to content

Commit

Permalink
Fix bug with Statement implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed Jan 13, 2024
1 parent ecef445 commit b376188
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
37 changes: 35 additions & 2 deletions docs/9.0/reader/statement.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,39 @@ $records = Statement::create()
// $records is a League\Csv\ResultSet instance with only 3 fields
```

While we explain each method separately it is understood that you could use them all together to query your
CSV document as you want like in the following example.

```php
use League\Csv\Reader;
use League\Csv\Statement;

$constraints = Statement::create()
->select('Integer', 'Text', 'Date and Time')
->where(fn (array $record): bool => (float) $record['Float'] < 1.3)
->orderBy(fn (array $r1, array $r2): int => (int) $r2['Integer'] <=> (int) $r1['Integer'])
->limit(5)
->offset(2);

$document = <<<CSV
Integer,Float,Text,Multiline Text,Date and Time
1,1.11,Foo,"Foo
Bar",2020-01-01 01:01:01
2,1.22,Bar,"Bar
Baz",2020-02-02 02:02:02
3,1.33,Baz,"Baz
Foo",2020-03-03 03:03:03
CSV;

$csv = Reader::createFromString($document);
$csv->setHeaderOffset(0);
$records = $constraints->process($csv);
//returns a ResultSet containing records which validates all the constraints.
```

Since the `Statement` instance is created independent of the CSV document you can re-use it on different CSV
document or `TabularDataReader` instances if needed.

## FragmentFinder

<p class="message-info">This mechanism is introduced with version <code>9.12.0</code>.</p>
Expand Down Expand Up @@ -174,8 +207,8 @@ use League\Csv\FragmentFinder;
$reader = Reader::createFromPath('/path/to/file.csv');
$finder = FragmentFinder::create();

$finder->findAll('row=7-5;8-9', $reader); // return an Iterator<TabulatDataReader>
$finder->findFirst('row=7-5;8-9', $reader); // return an TabulatDataReader
$finder->findAll('row=7-5;8-9', $reader); // return an Iterator<TabularDataReader>
$finder->findFirst('row=7-5;8-9', $reader); // return an TabularDataReader
$finder->findFirstOrFail('row=7-5;8-9', $reader); // will throw
```

Expand Down
21 changes: 17 additions & 4 deletions src/Statement.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
use Iterator;
use LimitIterator;

use OutOfBoundsException;

use function array_key_exists;
use function array_reduce;
use function array_search;
Expand Down Expand Up @@ -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<array-key, array<array-key, string|null>> $iterator */
$iterator = new LimitIterator($iterator, $this->offset, $this->limit);

Expand Down Expand Up @@ -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<array-key, array<string|null>> $it */
$it = new ArrayIterator([...$iterator]);
$it = new $class([...$iterator]);
$it->uasort($compare);

return $it;
Expand Down
24 changes: 24 additions & 0 deletions src/StatementTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,28 @@ public function testHeaderMapperOnStatement(): void
'does not exists' => null,
], $results->first());
}

public function testOrderByDoesNotThrowOnInvalidOffsetOrLimit(): void
{
$document = <<<CSV
Integer,Float,Text,Multiline Text,Date and Time
1,1.11,Foo,"Foo
Bar",2020-01-01 01:01:01
2,1.22,Bar,"Bar
Baz",2020-02-02 02:02:02
3,1.33,Baz,"Baz
Foo",2020-03-03 03:03:03
CSV;

$csv = Reader::createFromString($document);
$csv->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));
}
}

0 comments on commit b376188

Please sign in to comment.