From 6ea67aae698cae33d6c63e2ed3357308320730fc Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Mon, 30 Mar 2026 15:25:37 +0100 Subject: [PATCH 1/3] fix: allow working on live query files closes #248 --- src/Query/QueryFactory.php | 15 ++++++-- test/phpunit/Query/QueryFactoryTest.php | 48 +++++++++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/Query/QueryFactory.php b/src/Query/QueryFactory.php index abfe753..e1d8fe0 100644 --- a/src/Query/QueryFactory.php +++ b/src/Query/QueryFactory.php @@ -60,19 +60,30 @@ protected function findQueryFilePathInDirectory( string $directory, string $name, ):?string { + $invalidMatchExtension = null; + foreach(new DirectoryIterator($directory) as $fileInfo) { if($fileInfo->isDot() || $fileInfo->isDir()) { continue; } - $this->getExtensionIfValid($fileInfo); $fileNameNoExtension = strtok($fileInfo->getFilename(), "."); if($fileNameNoExtension !== $name) { continue; } - return $fileInfo->getRealPath(); + try { + $this->getExtensionIfValid($fileInfo); + return $fileInfo->getRealPath(); + } + catch(QueryFileExtensionException) { + $invalidMatchExtension = strtolower($fileInfo->getExtension()); + } + } + + if(!is_null($invalidMatchExtension)) { + throw new QueryFileExtensionException($invalidMatchExtension); } return null; diff --git a/test/phpunit/Query/QueryFactoryTest.php b/test/phpunit/Query/QueryFactoryTest.php index b708ba4..6bc1605 100644 --- a/test/phpunit/Query/QueryFactoryTest.php +++ b/test/phpunit/Query/QueryFactoryTest.php @@ -255,4 +255,52 @@ public function getById():string { Helper::deleteDir($basePath); } } + + public function testFindQueryFilePathIgnoresUnrelatedInvalidExtensions():void { + $basePath = Helper::getTmpDir(); + $queryDirectory = implode(DIRECTORY_SEPARATOR, [ + $basePath, + "query", + ]); + mkdir($queryDirectory, 0775, true); + file_put_contents("$queryDirectory/valid.sql", "select 1"); + file_put_contents("$queryDirectory/other.sql~", "select 2"); + + try { + $sut = new QueryFactory($queryDirectory, new Driver(new DefaultSettings())); + $queryFilePath = $sut->findQueryFilePath("valid"); + + self::assertSame( + realpath("$queryDirectory/valid.sql"), + $queryFilePath + ); + } + finally { + Helper::deleteDir($basePath); + } + } + + public function testFindQueryFilePathPrefersSupportedExtensionOverEditorBackup():void { + $basePath = Helper::getTmpDir(); + $queryDirectory = implode(DIRECTORY_SEPARATOR, [ + $basePath, + "query", + ]); + mkdir($queryDirectory, 0775, true); + file_put_contents("$queryDirectory/report.sql", "select 1"); + file_put_contents("$queryDirectory/report.sql~", "select 2"); + + try { + $sut = new QueryFactory($queryDirectory, new Driver(new DefaultSettings())); + $queryFilePath = $sut->findQueryFilePath("report"); + + self::assertSame( + realpath("$queryDirectory/report.sql"), + $queryFilePath + ); + } + finally { + Helper::deleteDir($basePath); + } + } } From c19f3f160d7f75ee184620bd54e5f3d08c8baa5b Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Mon, 30 Mar 2026 15:52:12 +0100 Subject: [PATCH 2/3] tidy: reduce complexity --- src/Query/QueryFactory.php | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/src/Query/QueryFactory.php b/src/Query/QueryFactory.php index e1d8fe0..40b4cea 100644 --- a/src/Query/QueryFactory.php +++ b/src/Query/QueryFactory.php @@ -218,20 +218,12 @@ protected function getExtensionIfValid(SplFileInfo $fileInfo):string { protected function throwCorrectException(Exception $exception):void { $message = $exception->getMessage(); - - switch(get_class($exception)) { - case InvalidArgumentException::class: - $matches = []; - if(1 !== preg_match( - "/Database \[(.+)\] not configured/", $message, $matches)) { - throw $exception; - } - - $connectionName = $matches[1]; - throw new ConnectionNotConfiguredException($connectionName); - - default: + $matches = []; + if(1 !== preg_match("/Database \[(.+)\] not configured/", $message, $matches)) { throw $exception; } + + $connectionName = $matches[1]; + throw new ConnectionNotConfiguredException($connectionName); } } From 05bd5d75a1b54fd9b9500ceaaf239557fe604f80 Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Mon, 30 Mar 2026 16:59:18 +0100 Subject: [PATCH 3/3] test: increase coverage of key areas --- src/Query/QueryFactory.php | 12 ++- test/phpunit/Query/QueryFactoryTest.php | 99 +++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/src/Query/QueryFactory.php b/src/Query/QueryFactory.php index 40b4cea..94c8521 100644 --- a/src/Query/QueryFactory.php +++ b/src/Query/QueryFactory.php @@ -61,10 +61,10 @@ protected function findQueryFilePathInDirectory( string $name, ):?string { $invalidMatchExtension = null; + $validQueryFilePath = null; foreach(new DirectoryIterator($directory) as $fileInfo) { - if($fileInfo->isDot() - || $fileInfo->isDir()) { + if(!$fileInfo->isFile()) { continue; } @@ -75,13 +75,17 @@ protected function findQueryFilePathInDirectory( try { $this->getExtensionIfValid($fileInfo); - return $fileInfo->getRealPath(); + $validQueryFilePath ??= $fileInfo->getRealPath(); } catch(QueryFileExtensionException) { $invalidMatchExtension = strtolower($fileInfo->getExtension()); } } + if(!is_null($validQueryFilePath)) { + return $validQueryFilePath; + } + if(!is_null($invalidMatchExtension)) { throw new QueryFileExtensionException($invalidMatchExtension); } @@ -92,7 +96,7 @@ protected function findQueryFilePathInDirectory( protected function locateOverrideDirectory(string $classFilePath):?string { $baseName = pathinfo($classFilePath, PATHINFO_FILENAME); foreach(new DirectoryIterator(dirname($classFilePath)) as $fileInfo) { - if($fileInfo->isDot() || !$fileInfo->isDir()) { + if(!$fileInfo->isDir()) { continue; } diff --git a/test/phpunit/Query/QueryFactoryTest.php b/test/phpunit/Query/QueryFactoryTest.php index 6bc1605..a9939ae 100644 --- a/test/phpunit/Query/QueryFactoryTest.php +++ b/test/phpunit/Query/QueryFactoryTest.php @@ -3,6 +3,7 @@ use Gt\Database\Connection\DefaultSettings; use Gt\Database\Connection\Driver; +use Gt\Database\Connection\ConnectionNotConfiguredException; use Gt\Database\Query\PhpQuery; use Gt\Database\Query\Query; use Gt\Database\Query\QueryFactory; @@ -214,6 +215,52 @@ public function testCreatePhpPrefersOverrideDirectoryWhenClassIsLowerCase():void } } + public function testCreatePhpPrefersOverrideDirectoryWhenMethodIsNotPublic():void { + $basePath = Helper::getTmpDir(); + $classPath = implode(DIRECTORY_SEPARATOR, [ + $basePath, + "query", + "User.php", + ]); + $overrideDirectory = implode(DIRECTORY_SEPARATOR, [ + $basePath, + "query", + "User", + ]); + mkdir($overrideDirectory, 0775, true); + file_put_contents( + $classPath, + <<create("getById"); + + self::assertInstanceOf(SqlQuery::class, $query); + self::assertSame( + realpath("$overrideDirectory/getById.sql"), + $query->getFilePath() + ); + } + finally { + Helper::deleteDir($basePath); + } + } + public function testCreatePhpThrowsWhenOverrideConflictsWithPublicMethod():void { $basePath = Helper::getTmpDir(); $classPath = implode(DIRECTORY_SEPARATOR, [ @@ -256,6 +303,58 @@ public function getById():string { } } + public function testCreateTranslatesConnectionNotConfiguredException():void { + $basePath = Helper::getTmpDir(); + $queryDirectory = implode(DIRECTORY_SEPARATOR, [ + $basePath, + "query", + ]); + mkdir($queryDirectory, 0775, true); + file_put_contents("$queryDirectory/users.sql", "select 1"); + + $driver = $this->createMock(Driver::class); + $driver->method("getConnection") + ->willThrowException( + new \InvalidArgumentException("Database [reporting] not configured") + ); + + try { + $sut = new QueryFactory($queryDirectory, $driver); + + self::expectException(ConnectionNotConfiguredException::class); + self::expectExceptionMessage("reporting"); + $sut->create("users"); + } + finally { + Helper::deleteDir($basePath); + } + } + + public function testCreateRethrowsUnexpectedInvalidArgumentException():void { + $basePath = Helper::getTmpDir(); + $queryDirectory = implode(DIRECTORY_SEPARATOR, [ + $basePath, + "query", + ]); + mkdir($queryDirectory, 0775, true); + file_put_contents("$queryDirectory/users.sql", "select 1"); + + $driver = $this->createMock(Driver::class); + $driver->method("getConnection") + ->willThrowException(new \InvalidArgumentException("Unexpected error")); + + try { + $sut = new QueryFactory($queryDirectory, $driver); + + self::expectException(\InvalidArgumentException::class); + self::expectExceptionMessage("Unexpected error"); + $sut->create("users"); + } + finally { + Helper::deleteDir($basePath); + } + } + public function testFindQueryFilePathIgnoresUnrelatedInvalidExtensions():void { $basePath = Helper::getTmpDir(); $queryDirectory = implode(DIRECTORY_SEPARATOR, [