diff --git a/CHANGELOG.md b/CHANGELOG.md index 567d1be..6fa2860 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ - New #200: Add matching mode parameter to `Like` filter (@samdark, @vjik) - New #232: Add `All` and `None` filters (@vjik) - Chg #233: Remove nullable types from `withFilter()` and `getFilter()` methods of `FilterableDataInterface` (@vjik) +- Bug #234: Fix handling of `null` values in `IterableDataReader` (@vjik) ## 1.0.1 January 25, 2023 diff --git a/src/Reader/Iterable/FilterHandler/BetweenHandler.php b/src/Reader/Iterable/FilterHandler/BetweenHandler.php index ec4721e..a83cadc 100644 --- a/src/Reader/Iterable/FilterHandler/BetweenHandler.php +++ b/src/Reader/Iterable/FilterHandler/BetweenHandler.php @@ -4,7 +4,6 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; -use DateTimeInterface; use Yiisoft\Data\Reader\Filter\Between; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Iterable\Context; @@ -29,13 +28,6 @@ public function match(object|array $item, FilterInterface $filter, Context $cont $min = $filter->minValue; $max = $filter->maxValue; - if (!$value instanceof DateTimeInterface) { - return $value >= $min && $value <= $max; - } - - return $min instanceof DateTimeInterface - && $max instanceof DateTimeInterface - && $value->getTimestamp() >= $min->getTimestamp() - && $value->getTimestamp() <= $max->getTimestamp(); + return $value >= $min && $value <= $max; } } diff --git a/src/Reader/Iterable/FilterHandler/EqualsHandler.php b/src/Reader/Iterable/FilterHandler/EqualsHandler.php index bc6539c..0e4b6cf 100644 --- a/src/Reader/Iterable/FilterHandler/EqualsHandler.php +++ b/src/Reader/Iterable/FilterHandler/EqualsHandler.php @@ -4,7 +4,6 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; -use DateTimeInterface; use Yiisoft\Data\Reader\Filter\Equals; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Iterable\Context; @@ -27,11 +26,6 @@ public function match(object|array $item, FilterInterface $filter, Context $cont $itemValue = $context->readValue($item, $filter->field); $argumentValue = $filter->value; - if (!$itemValue instanceof DateTimeInterface) { - return $itemValue == $argumentValue; - } - - return $argumentValue instanceof DateTimeInterface - && $itemValue->getTimestamp() === $argumentValue->getTimestamp(); + return $itemValue == $argumentValue; } } diff --git a/src/Reader/Iterable/FilterHandler/GreaterThanHandler.php b/src/Reader/Iterable/FilterHandler/GreaterThanHandler.php index 8032f4f..77d5342 100644 --- a/src/Reader/Iterable/FilterHandler/GreaterThanHandler.php +++ b/src/Reader/Iterable/FilterHandler/GreaterThanHandler.php @@ -4,7 +4,6 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; -use DateTimeInterface; use Yiisoft\Data\Reader\Filter\GreaterThan; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Iterable\Context; @@ -27,11 +26,6 @@ public function match(object|array $item, FilterInterface $filter, Context $cont $itemValue = $context->readValue($item, $filter->field); $argumentValue = $filter->value; - if (!$itemValue instanceof DateTimeInterface) { - return $itemValue > $argumentValue; - } - - return $argumentValue instanceof DateTimeInterface - && $itemValue->getTimestamp() > $argumentValue->getTimestamp(); + return $itemValue > $argumentValue; } } diff --git a/src/Reader/Iterable/FilterHandler/GreaterThanOrEqualHandler.php b/src/Reader/Iterable/FilterHandler/GreaterThanOrEqualHandler.php index 8065cce..ea61ee3 100644 --- a/src/Reader/Iterable/FilterHandler/GreaterThanOrEqualHandler.php +++ b/src/Reader/Iterable/FilterHandler/GreaterThanOrEqualHandler.php @@ -4,7 +4,6 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; -use DateTimeInterface; use Yiisoft\Data\Reader\Filter\GreaterThanOrEqual; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Iterable\Context; @@ -28,11 +27,6 @@ public function match(object|array $item, FilterInterface $filter, Context $cont $itemValue = $context->readValue($item, $filter->field); $argumentValue = $filter->value; - if (!$itemValue instanceof DateTimeInterface) { - return $itemValue >= $argumentValue; - } - - return $argumentValue instanceof DateTimeInterface - && $itemValue->getTimestamp() >= $argumentValue->getTimestamp(); + return $itemValue >= $argumentValue; } } diff --git a/src/Reader/Iterable/FilterHandler/LessThanHandler.php b/src/Reader/Iterable/FilterHandler/LessThanHandler.php index 4ef0f34..beb8207 100644 --- a/src/Reader/Iterable/FilterHandler/LessThanHandler.php +++ b/src/Reader/Iterable/FilterHandler/LessThanHandler.php @@ -4,7 +4,6 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; -use DateTimeInterface; use Yiisoft\Data\Reader\Filter\LessThan; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Iterable\Context; @@ -27,11 +26,10 @@ public function match(object|array $item, FilterInterface $filter, Context $cont $itemValue = $context->readValue($item, $filter->field); $argumentValue = $filter->value; - if (!$itemValue instanceof DateTimeInterface) { - return $itemValue < $argumentValue; + if ($itemValue === null) { + return false; } - return $argumentValue instanceof DateTimeInterface - && $itemValue->getTimestamp() < $argumentValue->getTimestamp(); + return $itemValue < $argumentValue; } } diff --git a/src/Reader/Iterable/FilterHandler/LessThanOrEqualHandler.php b/src/Reader/Iterable/FilterHandler/LessThanOrEqualHandler.php index f6c0120..1a16734 100644 --- a/src/Reader/Iterable/FilterHandler/LessThanOrEqualHandler.php +++ b/src/Reader/Iterable/FilterHandler/LessThanOrEqualHandler.php @@ -4,7 +4,6 @@ namespace Yiisoft\Data\Reader\Iterable\FilterHandler; -use DateTimeInterface; use Yiisoft\Data\Reader\Filter\LessThanOrEqual; use Yiisoft\Data\Reader\FilterInterface; use Yiisoft\Data\Reader\Iterable\Context; @@ -28,11 +27,10 @@ public function match(object|array $item, FilterInterface $filter, Context $cont $itemValue = $context->readValue($item, $filter->field); $argumentValue = $filter->value; - if (!$itemValue instanceof DateTimeInterface) { - return $itemValue <= $argumentValue; + if ($itemValue === null) { + return false; } - return $argumentValue instanceof DateTimeInterface - && $itemValue->getTimestamp() <= $argumentValue->getTimestamp(); + return $itemValue <= $argumentValue; } } diff --git a/tests/Common/FixtureTrait.php b/tests/Common/FixtureTrait.php index 5764500..0f4f954 100644 --- a/tests/Common/FixtureTrait.php +++ b/tests/Common/FixtureTrait.php @@ -4,16 +4,10 @@ namespace Yiisoft\Data\Tests\Common; +use DateTimeImmutable; + trait FixtureTrait { - protected static $fixtures = [ - ['number' => 1, 'email' => 'foo@bar\\baz', 'balance' => 10.25, 'born_at' => null], - ['number' => 2, 'email' => 'bar@foo', 'balance' => 1.0, 'born_at' => null], - ['number' => 3, 'email' => 'seed@beat', 'balance' => 100.0, 'born_at' => null], - ['number' => 4, 'email' => 'the@best', 'balance' => 500.0, 'born_at' => null], - ['number' => 5, 'email' => 'test@test', 'balance' => 42.0, 'born_at' => '1990-01-01'], - ]; - protected function assertFixtures(array $expectedFixtureIndexes, array $actualFixtures): void { $expectedFixtures = []; @@ -21,11 +15,22 @@ protected function assertFixtures(array $expectedFixtureIndexes, array $actualFi $expectedFixtures[$index] = $this->getFixture($index); } - $this->assertSame($expectedFixtures, $actualFixtures); + $this->assertEquals($expectedFixtures, $actualFixtures); } protected function getFixture(int $index): array { - return self::$fixtures[$index]; + return $this->getFixtures()[$index]; + } + + protected function getFixtures(): array + { + return [ + ['number' => 1, 'email' => 'foo@bar\\baz', 'balance' => 10.25, 'born_at' => null], + ['number' => 2, 'email' => 'bar@foo', 'balance' => 1.0, 'born_at' => null], + ['number' => 3, 'email' => 'seed@beat', 'balance' => 100.0, 'born_at' => null], + ['number' => 4, 'email' => 'the@best', 'balance' => 500.0, 'born_at' => null], + ['number' => 5, 'email' => 'test@test', 'balance' => 42.0, 'born_at' => new DateTimeImmutable('1990-01-01')], + ]; } } diff --git a/tests/Common/Reader/ReaderWithFilter/BaseReaderWithBetweenTestCase.php b/tests/Common/Reader/ReaderWithFilter/BaseReaderWithBetweenTestCase.php index 22f286d..1d50992 100644 --- a/tests/Common/Reader/ReaderWithFilter/BaseReaderWithBetweenTestCase.php +++ b/tests/Common/Reader/ReaderWithFilter/BaseReaderWithBetweenTestCase.php @@ -4,14 +4,30 @@ namespace Yiisoft\Data\Tests\Common\Reader\ReaderWithFilter; +use DateTimeImmutable; +use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\Between; use Yiisoft\Data\Tests\Common\Reader\BaseReaderTestCase; abstract class BaseReaderWithBetweenTestCase extends BaseReaderTestCase { - public function testWithReader(): void + public static function dataWithReader(): iterable { - $reader = $this->getReader()->withFilter(new Between('balance', 10.25, 100.0)); - $this->assertFixtures([0, 2, 4], $reader->read()); + yield 'float' => [new Between('balance', 10.25, 100.0), [1, 3, 5]]; + yield 'datetime' => [new Between('born_at', new DateTimeImmutable('1989-01-01'), new DateTimeImmutable('1991-01-01')), [5]]; + yield 'datetime 2' => [new Between('born_at', new DateTimeImmutable('1990-01-02'), new DateTimeImmutable('1990-01-03')), []]; + } + + #[DataProvider('dataWithReader')] + public function testWithReader(Between $filter, array $expectedFixtureNumbers): void + { + $expectedFixtureIndexes = array_map( + static fn(int $number): int => $number - 1, + $expectedFixtureNumbers, + ); + $this->assertFixtures( + $expectedFixtureIndexes, + $this->getReader()->withFilter($filter)->read(), + ); } } diff --git a/tests/Common/Reader/ReaderWithFilter/BaseReaderWithEqualsTestCase.php b/tests/Common/Reader/ReaderWithFilter/BaseReaderWithEqualsTestCase.php index f949781..75dc26c 100644 --- a/tests/Common/Reader/ReaderWithFilter/BaseReaderWithEqualsTestCase.php +++ b/tests/Common/Reader/ReaderWithFilter/BaseReaderWithEqualsTestCase.php @@ -4,14 +4,31 @@ namespace Yiisoft\Data\Tests\Common\Reader\ReaderWithFilter; +use DateTimeImmutable; +use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\Equals; use Yiisoft\Data\Tests\Common\Reader\BaseReaderTestCase; abstract class BaseReaderWithEqualsTestCase extends BaseReaderTestCase { - public function testWithReader(): void + public static function dataWithReader(): iterable { - $reader = $this->getReader()->withFilter(new Equals('number', 2)); - $this->assertFixtures([1], $reader->read()); + yield 'integer' => [new Equals('number', 2), [2]]; + yield 'float' => [new Equals('balance', 10.25), [1]]; + yield 'string' => [new Equals('email', 'the@best'), [4]]; + yield 'datetime' => [new Equals('born_at', new DateTimeImmutable('1990-01-01')), [5]]; + } + + #[DataProvider('dataWithReader')] + public function testWithReader(Equals $filter, array $expectedFixtureNumbers): void + { + $expectedFixtureIndexes = array_map( + static fn(int $number): int => $number - 1, + $expectedFixtureNumbers, + ); + $this->assertFixtures( + $expectedFixtureIndexes, + $this->getReader()->withFilter($filter)->read(), + ); } } diff --git a/tests/Common/Reader/ReaderWithFilter/BaseReaderWithGreaterThanOrEqualTestCase.php b/tests/Common/Reader/ReaderWithFilter/BaseReaderWithGreaterThanOrEqualTestCase.php index 298fa1d..1edca0f 100644 --- a/tests/Common/Reader/ReaderWithFilter/BaseReaderWithGreaterThanOrEqualTestCase.php +++ b/tests/Common/Reader/ReaderWithFilter/BaseReaderWithGreaterThanOrEqualTestCase.php @@ -4,14 +4,31 @@ namespace Yiisoft\Data\Tests\Common\Reader\ReaderWithFilter; +use DateTimeImmutable; +use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\GreaterThanOrEqual; use Yiisoft\Data\Tests\Common\Reader\BaseReaderTestCase; abstract class BaseReaderWithGreaterThanOrEqualTestCase extends BaseReaderTestCase { - public function testWithReader(): void + public static function dataWithReader(): iterable { - $reader = $this->getReader()->withFilter(new GreaterThanOrEqual('balance', 500)); - $this->assertFixtures([3], $reader->read()); + yield 'integer' => [new GreaterThanOrEqual('number', 3), [3, 4, 5]]; + yield 'float' => [new GreaterThanOrEqual('balance', 100.0), [3, 4]]; + yield 'datetime' => [new GreaterThanOrEqual('born_at', new DateTimeImmutable('1990-01-01')), [5]]; + yield 'datetime 2' => [new GreaterThanOrEqual('born_at', new DateTimeImmutable('1991-01-01')), []]; + } + + #[DataProvider('dataWithReader')] + public function testWithReader(GreaterThanOrEqual $filter, array $expectedFixtureNumbers): void + { + $expectedFixtureIndexes = array_map( + static fn(int $number): int => $number - 1, + $expectedFixtureNumbers, + ); + $this->assertFixtures( + $expectedFixtureIndexes, + $this->getReader()->withFilter($filter)->read(), + ); } } diff --git a/tests/Common/Reader/ReaderWithFilter/BaseReaderWithGreaterThanTestCase.php b/tests/Common/Reader/ReaderWithFilter/BaseReaderWithGreaterThanTestCase.php index 6bc7d3f..513d3b9 100644 --- a/tests/Common/Reader/ReaderWithFilter/BaseReaderWithGreaterThanTestCase.php +++ b/tests/Common/Reader/ReaderWithFilter/BaseReaderWithGreaterThanTestCase.php @@ -4,14 +4,31 @@ namespace Yiisoft\Data\Tests\Common\Reader\ReaderWithFilter; +use DateTimeImmutable; +use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\GreaterThan; use Yiisoft\Data\Tests\Common\Reader\BaseReaderTestCase; abstract class BaseReaderWithGreaterThanTestCase extends BaseReaderTestCase { - public function testWithReader(): void + public static function dataWithReader(): iterable { - $reader = $this->getReader()->withFilter(new GreaterThan('balance', 499)); - $this->assertFixtures([3], $reader->read()); + yield 'integer' => [new GreaterThan('number', 3), [4, 5]]; + yield 'float' => [new GreaterThan('balance', 50.0), [3, 4]]; + yield 'datetime' => [new GreaterThan('born_at', new DateTimeImmutable('1989-01-01')), [5]]; + yield 'datetime 2' => [new GreaterThan('born_at', new DateTimeImmutable('1990-01-01')), []]; + } + + #[DataProvider('dataWithReader')] + public function testWithReader(GreaterThan $filter, array $expectedFixtureNumbers): void + { + $expectedFixtureIndexes = array_map( + static fn(int $number): int => $number - 1, + $expectedFixtureNumbers, + ); + $this->assertFixtures( + $expectedFixtureIndexes, + $this->getReader()->withFilter($filter)->read(), + ); } } diff --git a/tests/Common/Reader/ReaderWithFilter/BaseReaderWithLessThanOrEqualTestCase.php b/tests/Common/Reader/ReaderWithFilter/BaseReaderWithLessThanOrEqualTestCase.php index e8b4ea3..adddc6c 100644 --- a/tests/Common/Reader/ReaderWithFilter/BaseReaderWithLessThanOrEqualTestCase.php +++ b/tests/Common/Reader/ReaderWithFilter/BaseReaderWithLessThanOrEqualTestCase.php @@ -4,14 +4,32 @@ namespace Yiisoft\Data\Tests\Common\Reader\ReaderWithFilter; +use DateTimeImmutable; +use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\LessThanOrEqual; use Yiisoft\Data\Tests\Common\Reader\BaseReaderTestCase; abstract class BaseReaderWithLessThanOrEqualTestCase extends BaseReaderTestCase { - public function testWithReader(): void + public static function dataWithReader(): iterable { - $reader = $this->getReader()->withFilter(new LessThanOrEqual('balance', 1.0)); - $this->assertFixtures([1], $reader->read()); + yield 'integer' => [new LessThanOrEqual('number', 3), [1, 2, 3]]; + yield 'float' => [new LessThanOrEqual('balance', 42.0), [1, 2, 5]]; + yield 'datetime' => [new LessThanOrEqual('born_at', new DateTimeImmutable('1990-01-01')), [5]]; + yield 'datetime 2' => [new LessThanOrEqual('born_at', new DateTimeImmutable('1990-01-02')), [5]]; + yield 'datetime 3' => [new LessThanOrEqual('born_at', new DateTimeImmutable('1989-01-01')), []]; + } + + #[DataProvider('dataWithReader')] + public function testWithReader(LessThanOrEqual $filter, array $expectedFixtureNumbers): void + { + $expectedFixtureIndexes = array_map( + static fn(int $number): int => $number - 1, + $expectedFixtureNumbers, + ); + $this->assertFixtures( + $expectedFixtureIndexes, + $this->getReader()->withFilter($filter)->read(), + ); } } diff --git a/tests/Common/Reader/ReaderWithFilter/BaseReaderWithLessThanTestCase.php b/tests/Common/Reader/ReaderWithFilter/BaseReaderWithLessThanTestCase.php index a53e9e7..3203197 100644 --- a/tests/Common/Reader/ReaderWithFilter/BaseReaderWithLessThanTestCase.php +++ b/tests/Common/Reader/ReaderWithFilter/BaseReaderWithLessThanTestCase.php @@ -4,14 +4,31 @@ namespace Yiisoft\Data\Tests\Common\Reader\ReaderWithFilter; +use DateTimeImmutable; +use PHPUnit\Framework\Attributes\DataProvider; use Yiisoft\Data\Reader\Filter\LessThan; use Yiisoft\Data\Tests\Common\Reader\BaseReaderTestCase; abstract class BaseReaderWithLessThanTestCase extends BaseReaderTestCase { - public function testWithReader(): void + public static function dataWithReader(): iterable { - $reader = $this->getReader()->withFilter(new LessThan('balance', 1.1)); - $this->assertFixtures([1], $reader->read()); + yield 'integer' => [new LessThan('number', 3), [1, 2]]; + yield 'float' => [new LessThan('balance', 50.0), [1, 2, 5]]; + yield 'datetime' => [new LessThan('born_at', new DateTimeImmutable('1991-01-01')), [5]]; + yield 'datetime 2' => [new LessThan('born_at', new DateTimeImmutable('1990-01-01')), []]; + } + + #[DataProvider('dataWithReader')] + public function testWithReader(LessThan $filter, array $expectedFixtureNumbers): void + { + $expectedFixtureIndexes = array_map( + static fn(int $number): int => $number - 1, + $expectedFixtureNumbers, + ); + $this->assertFixtures( + $expectedFixtureIndexes, + $this->getReader()->withFilter($filter)->read(), + ); } } diff --git a/tests/Reader/Iterable/ReaderWithFilter/ReaderTrait.php b/tests/Reader/Iterable/ReaderWithFilter/ReaderTrait.php index eba664f..0408dcc 100644 --- a/tests/Reader/Iterable/ReaderWithFilter/ReaderTrait.php +++ b/tests/Reader/Iterable/ReaderWithFilter/ReaderTrait.php @@ -11,6 +11,6 @@ trait ReaderTrait { protected function getReader(): DataReaderInterface { - return new IterableDataReader(self::$fixtures); + return new IterableDataReader($this->getFixtures()); } }