diff --git a/src/AbstractDbValidator.php b/src/AbstractDbValidator.php index 7cec8f2..c3b704b 100644 --- a/src/AbstractDbValidator.php +++ b/src/AbstractDbValidator.php @@ -164,7 +164,7 @@ public function getTable(): string /** * Run query and returns matches, or null if no matches are found. * - * @return mixed when matches are found; null when there are none (PDO reports no rows as false). + * @return mixed when matches are found; null or false when there are none (PDO reports no rows as false). */ protected function query(mixed $value): mixed { @@ -179,8 +179,6 @@ protected function query(mixed $value): mixed $parameters['where1'] = $value; } - $row = $statement->execute()?->current(); - - return false === $row ? null : $row; + return $statement->execute()?->current(); } } diff --git a/src/NoRecordExists.php b/src/NoRecordExists.php index 97d6ed5..9df136f 100644 --- a/src/NoRecordExists.php +++ b/src/NoRecordExists.php @@ -19,7 +19,7 @@ public function isValid(mixed $value): bool $valid = true; $this->setValue($value); - if ($this->query($value) !== null) { + if ($this->query($value)) { $valid = false; $this->error(self::ERROR_RECORD_FOUND); } diff --git a/test/unit/NoRecordExistsTest.php b/test/unit/NoRecordExistsTest.php index 770106a..726d8de 100644 --- a/test/unit/NoRecordExistsTest.php +++ b/test/unit/NoRecordExistsTest.php @@ -14,6 +14,7 @@ use PhpDb\Adapter\ParameterContainer; use PhpDb\Adapter\Platform\Sql92; use PhpDb\Validator\NoRecordExists; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\MockObject\Exception; @@ -22,6 +23,16 @@ #[Group('unit')] final class NoRecordExistsTest extends TestCase { + /** @return array */ + public static function noRowShapes(): array + { + return [ + 'null' => [null], + 'false (PDO)' => [false], + 'empty array' => [[]], + ]; + } + /** * Test basic function of RecordExists (no exclusion) * @@ -138,17 +149,18 @@ public function excludeWithStringNoRecord() } /** - * PDO reports "no rows" as false rather than null; that must still count as no record. + * Every shape a driver uses for "no row" must count as no record. * * @throws Exception */ #[Test] - public function noRowsReportedAsFalseFindsNoRecord(): void + #[DataProvider('noRowShapes')] + public function noRowShapeFindsNoRecord(mixed $current): void { $validator = new NoRecordExists([ 'table' => 'users', 'field' => 'field1', - 'adapter' => $this->getMockNoResult(false), + 'adapter' => $this->getMockNoResult($current), ]); static::assertTrue($validator->isValid('nosuchvalue')); } diff --git a/test/unit/RecordExistsTest.php b/test/unit/RecordExistsTest.php index 1cecf1b..7a4cc33 100644 --- a/test/unit/RecordExistsTest.php +++ b/test/unit/RecordExistsTest.php @@ -18,6 +18,7 @@ use PhpDb\Sql\TableIdentifier; use PhpDb\Validator\RecordExists; use PhpDbTestAsset\Validator\TrustingSql92Platform; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Group; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\Attributes\TestDox; @@ -27,6 +28,16 @@ #[Group('unit')] final class RecordExistsTest extends TestCase { + /** @return array */ + public static function noRowShapes(): array + { + return [ + 'null' => [null], + 'false (PDO)' => [false], + 'empty array' => [[]], + ]; + } + /** * Test basic function of RecordExists (no exclusion) * @@ -214,6 +225,23 @@ public function getSelectWithSameValidatorTwice(): void ); } + /** + * Every shape a driver uses for "no row" must count as no record. + * + * @throws Exception + */ + #[Test] + #[DataProvider('noRowShapes')] + public function noRowShapeFindsNoRecord(mixed $current): void + { + $validator = new RecordExists([ + 'table' => 'users', + 'field' => 'field1', + 'adapter' => $this->getMockNoResult($current), + ]); + static::assertFalse($validator->isValid('nosuchvalue')); + } + /** * @throws Exception */ @@ -358,13 +386,13 @@ protected function getMockHasResult(): Adapter * * @throws Exception */ - protected function getMockNoResult(): Adapter + protected function getMockNoResult(mixed $current = null): Adapter { // mock the adapter, driver, and parts $mockConnection = $this->createMock(ConnectionInterface::class); $mockNoResult = $this->createMock(ResultInterface::class); - $mockNoResult->method('current')->willReturn(null); + $mockNoResult->method('current')->willReturn($current); $mockNoResultStatement = $this->createMock(StatementInterface::class); $mockNoResultStatement->method('execute')->willReturn($mockNoResult);