Skip to content

Commit

Permalink
Simplify Query Error tree
Browse files Browse the repository at this point in the history
  • Loading branch information
nyamsprod committed May 20, 2024
1 parent 8461092 commit 898eca9
Show file tree
Hide file tree
Showing 15 changed files with 60 additions and 78 deletions.
16 changes: 6 additions & 10 deletions src/Query/Constraint/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
use IteratorIterator;
use League\Csv\Query\Predicate;
use League\Csv\Query\Row;
use League\Csv\InvalidArgument;
use League\Csv\StatementError;
use League\Csv\Query\QueryError;
use ReflectionException;

use function is_array;
Expand All @@ -37,15 +36,15 @@
final class Column implements Predicate
{
/**
* @throws InvalidArgument
* @throws \League\Csv\Query\QueryError
*/
private function __construct(
public readonly string|int $column,
public readonly Comparison $operator,
public readonly mixed $value,
) {
if (!$this->operator->accept($this->value)) {
throw new InvalidArgument('The value used for comparison with the `'.$this->operator->name.'` operator is not valid.');
throw new QueryError('The value used for comparison with the `'.$this->operator->name.'` operator is not valid.');
}
}

Expand All @@ -62,9 +61,8 @@ public static function filterOn(
}

/**
* @throws InvalidArgument
* @throws ReflectionException
* @throws StatementError
* @throws \League\Csv\Query\QueryError
*/
public function __invoke(mixed $value, int|string $key): bool
{
Expand All @@ -73,13 +71,11 @@ public function __invoke(mixed $value, int|string $key): bool

public function filter(iterable $value): Iterator
{
$value = match (true) {
return new CallbackFilterIterator(match (true) {
is_array($value) => new ArrayIterator($value),
$value instanceof Iterator => $value,
default => new IteratorIterator($value),
};

return new CallbackFilterIterator($value, $this);
}, $this);
}

public function filterArray(iterable $value): array
Expand Down
5 changes: 2 additions & 3 deletions src/Query/Constraint/ColumnTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
namespace League\Csv\Query\Constraint;

use League\Csv\Query\QueryTestCase;
use League\Csv\StatementError;
use League\Csv\Query\QueryError;
use PHPUnit\Framework\Attributes\Test;

final class ColumnTest extends QueryTestCase

{
#[Test]
public function it_can_filter_the_tabular_data_based_on_the_column_value(): void
Expand Down Expand Up @@ -51,7 +50,7 @@ public function it_can_not_filter_the_tabular_data_based_on_the_column_name(): v
public function it_will_throw_if_the_column_does_not_exist(): void
{
$predicate = Column::filterOn('Ville', '=', 'Dakar');
$this->expectExceptionObject(StatementError::dueToUnknownColumn('Ville', []));
$this->expectExceptionObject(QueryError::dueToUnknownColumn('Ville', []));

[...$this->stmt->where($predicate)->process($this->document)];
}
Expand Down
29 changes: 14 additions & 15 deletions src/Query/Constraint/Comparison.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@

namespace League\Csv\Query\Constraint;


use League\Csv\InvalidArgument;
use League\Csv\Query\QueryError;

use function array_is_list;
use function count;
Expand Down Expand Up @@ -69,15 +68,15 @@ public static function tryFromOperator(string $operator): ?self
}

/**
* @throws InvalidArgument
* @throws QueryError
*/
public static function fromOperator(string $operator): self
{
return self::tryFromOperator($operator) ?? throw new InvalidArgument('Unknown or unsupported comparison operator `'.$operator.'`');
return self::tryFromOperator($operator) ?? throw new QueryError('Unknown or unsupported comparison operator `'.$operator.'`');
}

/**
* @throws InvalidArgument
* @throws QueryError
*/
public function compare(mixed $needle, mixed $haystack): bool
{
Expand All @@ -88,16 +87,16 @@ public function compare(mixed $needle, mixed $haystack): bool
self::GreaterThanOrEqual => $needle >= $haystack,
self::LesserThan => $needle < $haystack,
self::LesserThanOrEqual => $needle <= $haystack,
self::Between => (is_array($haystack) && array_is_list($haystack) && 2 === count($haystack)) ? $needle >= $haystack[0] && $needle <= $haystack[1] : throw new InvalidArgument('The value used for comparison with the `'.$this->name.'` operator must be an list containing 2 values, the minimum and maximum values.'),
self::NotBetween => (is_array($haystack) && array_is_list($haystack) && 2 === count($haystack)) ? $needle < $haystack[0] || $needle > $haystack[1] : throw new InvalidArgument('The value used for comparison with the `'.$this->name.'` operator must be an list containing 2 values, the minimum and maximum values.'),
self::Regexp => is_string($haystack) ? (is_string($needle) && 1 === preg_match($haystack, $needle)) : throw new InvalidArgument('The value used for comparison with the `'.$this->name.'` operator must be a string.'),
self::NotRegexp => is_string($haystack) ? (is_string($needle) && 1 !== preg_match($haystack, $needle)) : throw new InvalidArgument('The value used for comparison with the `'.$this->name.'` operator must be a string.'),
self::In => is_array($haystack) ? in_array($needle, $haystack, self::isStrict($needle)) : throw new InvalidArgument('The value used for comparison with the `'.$this->name.'` operator must be an array.'), /* @phpstan-ignore-line */
self::NotIn => is_array($haystack) ? !in_array($needle, $haystack, self::isStrict($needle)) : throw new InvalidArgument('The value used for comparison with the `'.$this->name.'` operator must be an array.'), /* @phpstan-ignore-line */
self::Contains => is_string($haystack) ? (is_string($needle) && str_contains($needle, $haystack)) : throw new InvalidArgument('The value used for comparison with the `'.$this->name.'` operator must be a string.'),
self::NotContain => is_string($haystack) ? (is_string($needle) && !str_contains($needle, $haystack)) : throw new InvalidArgument('The value used for comparison with the `'.$this->name.'` operator must be a string.'),
self::StartsWith => is_string($haystack) ? (is_string($needle) && str_starts_with($needle, $haystack)) : throw new InvalidArgument('The value used for comparison with the `'.$this->name.'` operator must be a string.'),
self::EndsWith => is_string($haystack) ? (is_string($needle) && str_ends_with($needle, $haystack)) : throw new InvalidArgument('The value used for comparison with the `'.$this->name.'` operator must be a string.'),
self::Between => (is_array($haystack) && array_is_list($haystack) && 2 === count($haystack)) ? $needle >= $haystack[0] && $needle <= $haystack[1] : throw new QueryError('The value used for comparison with the `'.$this->name.'` operator must be an list containing 2 values, the minimum and maximum values.'),
self::NotBetween => (is_array($haystack) && array_is_list($haystack) && 2 === count($haystack)) ? $needle < $haystack[0] || $needle > $haystack[1] : throw new QueryError('The value used for comparison with the `'.$this->name.'` operator must be an list containing 2 values, the minimum and maximum values.'),
self::Regexp => is_string($haystack) ? (is_string($needle) && 1 === preg_match($haystack, $needle)) : throw new QueryError('The value used for comparison with the `'.$this->name.'` operator must be a string.'),
self::NotRegexp => is_string($haystack) ? (is_string($needle) && 1 !== preg_match($haystack, $needle)) : throw new QueryError('The value used for comparison with the `'.$this->name.'` operator must be a string.'),
self::In => is_array($haystack) ? in_array($needle, $haystack, self::isStrict($needle)) : throw new QueryError('The value used for comparison with the `'.$this->name.'` operator must be an array.'), /* @phpstan-ignore-line */
self::NotIn => is_array($haystack) ? !in_array($needle, $haystack, self::isStrict($needle)) : throw new QueryError('The value used for comparison with the `'.$this->name.'` operator must be an array.'), /* @phpstan-ignore-line */
self::Contains => is_string($haystack) ? (is_string($needle) && str_contains($needle, $haystack)) : throw new QueryError('The value used for comparison with the `'.$this->name.'` operator must be a string.'),
self::NotContain => is_string($haystack) ? (is_string($needle) && !str_contains($needle, $haystack)) : throw new QueryError('The value used for comparison with the `'.$this->name.'` operator must be a string.'),
self::StartsWith => is_string($haystack) ? (is_string($needle) && str_starts_with($needle, $haystack)) : throw new QueryError('The value used for comparison with the `'.$this->name.'` operator must be a string.'),
self::EndsWith => is_string($haystack) ? (is_string($needle) && str_ends_with($needle, $haystack)) : throw new QueryError('The value used for comparison with the `'.$this->name.'` operator must be a string.'),
};
}

Expand Down
7 changes: 3 additions & 4 deletions src/Query/Constraint/ComparisonTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@

namespace League\Csv\Query\Constraint;


use League\Csv\InvalidArgument;
use League\Csv\Query\QueryError;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
Expand All @@ -24,7 +23,7 @@ final class ComparisonTest extends TestCase
#[Test]
public function it_will_throw_if_the_comparison_operator_is_unknown(): void
{
$this->expectException(InvalidArgument::class);
$this->expectException(QueryError::class);

Comparison::fromOperator('foobar');
}
Expand All @@ -40,7 +39,7 @@ public function it_can_compare_two_values(mixed $needle, mixed $haystack, string
#[DataProvider('provideInvalidComparisons')]
public function it_fails_to_compare_two_values(mixed $needle, mixed $haystack, string $operator): void
{
$this->expectException(InvalidArgument::class);
$this->expectException(QueryError::class);

Comparison::fromOperator($operator)->compare($needle, $haystack);
}
Expand Down
16 changes: 7 additions & 9 deletions src/Query/Constraint/Criteria.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,22 +115,20 @@ public function __invoke(mixed $value, int|string $key): bool

public function filter(iterable $value): Iterator
{
$value = match (true) {
return new CallbackFilterIterator(match (true) {
is_array($value) => new ArrayIterator($value),
$value instanceof Iterator => $value,
default => new IteratorIterator($value),
};

return new CallbackFilterIterator($value, $this);
}, $this);
}

public function filterArray(iterable $values): array
{
if (!is_array($values)) {
return array_filter(iterator_to_array($values), $this, ARRAY_FILTER_USE_BOTH);
}

return array_filter($values, $this, ARRAY_FILTER_USE_BOTH);
return array_filter(
!is_array($values) ? iterator_to_array($values) : $values,
$this,
ARRAY_FILTER_USE_BOTH
);
}

/**
Expand Down
1 change: 0 additions & 1 deletion src/Query/Constraint/CriteriaTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
use const ARRAY_FILTER_USE_BOTH;

final class CriteriaTest extends QueryTestCase

{
#[Test]
public function it_returns_a_value_when_no_predicate_is_given(): void
Expand Down
13 changes: 5 additions & 8 deletions src/Query/Constraint/TwoColumns.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
use IteratorIterator;
use League\Csv\Query\Predicate;
use League\Csv\Query\Row;
use League\Csv\InvalidArgument;
use League\Csv\StatementError;
use League\Csv\Query\QueryError;
use ReflectionException;

use function array_filter;
Expand All @@ -39,7 +38,7 @@
final class TwoColumns implements Predicate
{
/**
* @throws StatementError
* @throws QueryError
*/
private function __construct(
public readonly string|int $first,
Expand All @@ -49,14 +48,13 @@ private function __construct(
if (is_array($this->second)) {
$res = array_filter($this->second, fn (mixed $value): bool => !is_string($value) && !is_int($value));
if ([] !== $res) {
throw new StatementError('The second column must be a string, an integer or a list of strings and/or integer.');
throw new QueryError('The second column must be a string, an integer or a list of strings and/or integer.');
}
}
}

/**
* @throws InvalidArgument
* @throws StatementError
* @throws QueryError
*/
public static function filterOn(
string|int $firstColumn,
Expand All @@ -71,8 +69,7 @@ public static function filterOn(
}

/**
* @throws InvalidArgument
* @throws StatementError
* @throws QueryError
* @throws ReflectionException
*/
public function __invoke(mixed $value, int|string $key): bool
Expand Down
4 changes: 2 additions & 2 deletions src/Query/Constraint/TwoColumnsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace League\Csv\Query\Constraint;

use League\Csv\StatementError;
use League\Csv\Query\QueryError;
use PHPUnit\Framework\Attributes\Test;
use League\Csv\Query\QueryTestCase;

Expand Down Expand Up @@ -41,7 +41,7 @@ public function it_can_filter_the_tabular_data_based_on_the_column_value_and_the
public function it_will_throw_if_the_column_does_not_exist(): void
{
$predicate = TwoColumns::filterOn('City', '=', 'Dakar');
$this->expectExceptionObject(StatementError::dueToUnknownColumn('City', []));
$this->expectExceptionObject(QueryError::dueToUnknownColumn('City', []));

$this->stmt->where($predicate)->process($this->document);
}
Expand Down
7 changes: 3 additions & 4 deletions src/Query/Limit.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@
use ArrayIterator;
use Iterator;
use IteratorIterator;
use League\Csv\InvalidArgument;
use LimitIterator;

use Traversable;

use function array_slice;
use function is_array;
use function iterator_to_array;
Expand All @@ -31,11 +30,11 @@ private function __construct(
public readonly int $length,
){
if (0 > $this->offset) {
throw InvalidArgument::dueToInvalidRecordOffset($this->offset, __METHOD__);
throw new QueryError(__METHOD__.'() expects the offset to be greater or equal to 0, '.$this->offset.' given.');
}

if (-1 > $this->length) {
throw InvalidArgument::dueToInvalidLimit($this->length, __METHOD__);
throw new QueryError(__METHOD__.'() expects the length to be greater or equal to -1, '.$this->length.' given.');
}
}

Expand Down
11 changes: 4 additions & 7 deletions src/Query/Ordering/Column.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,12 @@
use ArrayIterator;
use Closure;
use Iterator;
use IteratorIterator;
use League\Csv\Query\Row;
use League\Csv\InvalidArgument;
use League\Csv\Query\Sort;
use League\Csv\StatementError;
use League\Csv\Query\QueryError;
use OutOfBoundsException;
use ReflectionException;

use Traversable;
use function strtoupper;
use function trim;

Expand Down Expand Up @@ -61,9 +58,9 @@ public static function sortBy(
is_string($direction) => match (strtoupper(trim($direction))) {
'ASC', 'ASCENDING', 'UP' => self::ASCENDING,
'DESC', 'DESCENDING', 'DOWN' => self::DESCENDING,
default => throw new InvalidArgument('Unknown or unsupported ordering operator value: '.$direction),
default => throw new QueryError('Unknown or unsupported ordering operator value: '.$direction),
},
default => throw new InvalidArgument('Unknown or unsupported ordering operator value: '.$direction),
default => throw new QueryError('Unknown or unsupported ordering operator value: '.$direction),
};

return new self(
Expand All @@ -75,7 +72,7 @@ public static function sortBy(

/**
* @throws ReflectionException
* @throws StatementError
* @throws QueryError
*/
public function __invoke(mixed $valueA, mixed $valueB): int
{
Expand Down
1 change: 0 additions & 1 deletion src/Query/PredicateCombinator.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

namespace League\Csv\Query;


use Closure;
use League\Csv\Query\Predicate;

Expand Down
5 changes: 3 additions & 2 deletions src/StatementError.php → src/Query/QueryError.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@

declare(strict_types=1);

namespace League\Csv;
namespace League\Csv\Query;

use League\Csv\UnableToProcessCsv;
use RuntimeException;

final class StatementError extends RuntimeException implements UnableToProcessCsv
final class QueryError extends RuntimeException implements UnableToProcessCsv
{
public static function dueToUnknownColumn(string|int $column, array|object $value): self
{
Expand Down
1 change: 0 additions & 1 deletion src/Query/QueryTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

namespace League\Csv\Query;


use League\Csv\Reader;
use League\Csv\Statement;
use PHPUnit\Framework\TestCase;
Expand Down

0 comments on commit 898eca9

Please sign in to comment.