From 316e5926f3b5dfb3b8269569f76490fd34a6f4ed Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Wed, 23 May 2018 16:31:24 +0100 Subject: [PATCH 1/5] Pass tests after rename Client->Database --- src/Client.php | 157 --------------------------- src/Migration/Migrator.php | 9 +- test/unit/ClientTest.php | 8 +- test/unit/IntegrationTest.php | 4 +- test/unit/Migration/MigratorTest.php | 8 +- 5 files changed, 16 insertions(+), 170 deletions(-) delete mode 100644 src/Client.php diff --git a/src/Client.php b/src/Client.php deleted file mode 100644 index 2233867..0000000 --- a/src/Client.php +++ /dev/null @@ -1,157 +0,0 @@ -storeConnectionDriverFromSettings($connectionSettings); - $this->storeQueryCollectionFactoryFromSettings($connectionSettings); - } - - public function fetch(string $queryName, ...$bindings):?Row { - $result = $this->query($queryName, $bindings); - - return $result->fetch(); - } - - public function fetchAll(string $queryName, ...$bindings):ResultSet { - return $this->query($queryName, $bindings); - } - - public function insert(string $queryName, ...$bindings):int { - $result = $this->query($queryName, $bindings); - - return $result->lastInsertId(); - } - - public function delete(string $queryName, ...$bindings):int { - $result = $this->query($queryName, $bindings); - - return $result->affectedRows(); - } - - public function update(string $queryName, ...$bindings):int { - $result = $this->query($queryName, $bindings); - - return $result->affectedRows(); - } - - public function query(string $queryName, ...$bindings):ResultSet { - while(isset($bindings[0]) - && is_array($bindings[0])) { - $bindings = $bindings[0]; - } - - $queryCollectionName = substr( - $queryName, - 0, - strrpos($queryName, "/") - ); - $queryFile = substr( - $queryName, - strrpos($queryName, "/") + 1 - ); - - $connectionName = $this->currentConnectionName ?? DefaultSettings::DEFAULT_NAME; - $queryCollection = $this->queryCollection( - $queryCollectionName, - $connectionName - ); - - return $queryCollection->query($queryFile, $bindings); - } - - public function setCurrentConnectionName(string $connectionName) { - $this->currentConnectionName = $this->getNamedConnection( - $connectionName - ); - } - - public function executeSql( - string $query, - array $bindings = [], - string $connectionName = DefaultSettings::DEFAULT_NAME - ):ResultSet { - $connection = $this->getNamedConnection($connectionName); - try { - $statement = $connection->prepare($query); - } - catch(PDOException $exception) { - throw new DatabaseException( - $exception->getMessage(), - intval($exception->getCode()) - ); - } - - $statement->execute($bindings); - - return new ResultSet($statement, $connection->lastInsertId()); - } - - protected function getNamedConnection(string $connectionName):Connection { - $driver = $this->driverArray[$connectionName]; - - return $driver->getConnection(); - } - - protected function storeConnectionDriverFromSettings(array $settingsArray) { - foreach($settingsArray as $settings) { - $connectionName = $settings->getConnectionName(); - $this->driverArray[$connectionName] = new Driver($settings); - } - } - - protected function storeQueryCollectionFactoryFromSettings(array $settingsArray) { - foreach($settingsArray as $settings) { - $connectionName = $settings->getConnectionName(); - $this->queryCollectionFactoryArray[$connectionName] = - new QueryCollectionFactory($this->driverArray[$connectionName]); - } - } - - public function queryCollection( - string $queryCollectionName, - string $connectionName = DefaultSettings::DEFAULT_NAME - ):QueryCollection { - return $this->queryCollectionFactoryArray[$connectionName]->create($queryCollectionName); - } - - public function getDriver( - string $connectionName = DefaultSettings::DEFAULT_NAME - ):Driver { - return $this->driverArray[$connectionName]; - } - - protected function getFirstConnectionName():string { - reset($this->driverArray); - - return key($this->driverArray); - } -} \ No newline at end of file diff --git a/src/Migration/Migrator.php b/src/Migration/Migrator.php index 15ae638..9d131bf 100644 --- a/src/Migration/Migrator.php +++ b/src/Migration/Migrator.php @@ -2,9 +2,10 @@ namespace Gt\Database\Migration; use DirectoryIterator; -use Gt\Database\Client; +use Gt\Database\Database; use Gt\Database\Connection\Settings; use Gt\Database\DatabaseException; +use PDOException; use SplFileInfo; class Migrator { @@ -33,7 +34,7 @@ public function __construct( $settings = $settings->withoutSchema(); // @codeCoverageIgnore } - $this->dbClient = new Client($settings); + $this->dbClient = new Database($settings); if($forced) { $this->deleteAndRecreateSchema(); @@ -72,7 +73,7 @@ public function checkMigrationTableExists():bool { public function createMigrationTable():void { $this->dbClient->executeSql(implode("\n", [ - "create table `{$this->tableName}` (", + "create table if not exists `{$this->tableName}` (", "`" . self::COLUMN_QUERY_NUMBER . "` int primary key,", "`" . self::COLUMN_QUERY_HASH . "` varchar(32) not null,", "`" . self::COLUMN_MIGRATED_AT . "` datetime not null )", @@ -88,7 +89,7 @@ public function getMigrationCount():int { ); $row = $result->fetch(); } - catch(DatabaseException $exception) { + catch(PDOException $exception) { return 0; } diff --git a/test/unit/ClientTest.php b/test/unit/ClientTest.php index b075aeb..1e44b87 100644 --- a/test/unit/ClientTest.php +++ b/test/unit/ClientTest.php @@ -7,8 +7,8 @@ class ClientTest extends TestCase { public function testInterface() { - $db = new Client(); - static::assertInstanceOf(Client::class, $db); + $db = new Database(); + static::assertInstanceOf(Database::class, $db); } /** @@ -21,7 +21,7 @@ public function testQueryCollectionPathExists(string $name, string $path) { Settings::DRIVER_SQLITE, Settings::SCHEMA_IN_MEMORY ); - $db = new Client($settings); + $db = new Database($settings); $queryCollection = $db->queryCollection($name); static::assertInstanceOf(QueryCollection::class, $queryCollection); @@ -39,7 +39,7 @@ public function testQueryCollectionPathNotExists(string $name, string $path) { Settings::DRIVER_SQLITE, Settings::SCHEMA_IN_MEMORY ); - $db = new Client($settings); + $db = new Database($settings); $db->queryCollection($name); } } \ No newline at end of file diff --git a/test/unit/IntegrationTest.php b/test/unit/IntegrationTest.php index 19fba2c..c8de04a 100644 --- a/test/unit/IntegrationTest.php +++ b/test/unit/IntegrationTest.php @@ -14,13 +14,13 @@ class IntegrationTest extends TestCase { private $settings; /** @var string */ private $queryBase; - /** @var Client */ + /** @var Database */ private $db; public function setUp() { $this->queryBase = Helper::getTmpDir() . "/query"; - $this->db = new Client($this->settingsSingleton()); + $this->db = new Database($this->settingsSingleton()); $driver = $this->db->getDriver(); $connection = $driver->getConnection(); diff --git a/test/unit/Migration/MigratorTest.php b/test/unit/Migration/MigratorTest.php index 1e2c357..6a25f55 100644 --- a/test/unit/Migration/MigratorTest.php +++ b/test/unit/Migration/MigratorTest.php @@ -2,7 +2,7 @@ namespace Gt\Database\Test\Migration; use Exception; -use Gt\Database\Client; +use Gt\Database\Database; use Gt\Database\Connection\Settings; use Gt\Database\Migration\MigrationDirectoryNotFoundException; use Gt\Database\Migration\MigrationFileNameFormatException; @@ -34,6 +34,7 @@ public function testMigrationZeroAtStartWithoutTable() { $path = $this->getMigrationDirectory(); $settings = $this->createSettings($path); $migrator = new Migrator($settings, $path); + $migrator->createMigrationTable(); self::assertEquals(0, $migrator->getMigrationCount()); } @@ -197,6 +198,7 @@ public function testMigrationCountZeroAtStart() { $path = $this->getMigrationDirectory(); $settings = $this->createSettings($path); $migrator = new Migrator($settings, $path); + $migrator->createMigrationTable(); self::assertEquals(0, $migrator->getMigrationCount()); } @@ -304,7 +306,7 @@ public function testPerformMigrationGood(array $fileList):void { } catch(Exception $exception) {} - $db = new Client($settings); + $db = new Database($settings); $result = $db->executeSql("PRAGMA table_info(test);"); // There should be one more column than the number of files, due to the fact that the first // migration creates the table with two columns. @@ -375,7 +377,7 @@ protected function hashMigrationToDb( } $settings = $this->createSettings($path); - $db = new Client($settings); + $db = new Database($settings); $db->executeSql(implode("\n", [ "create table `_migration` (", "`" . Migrator::COLUMN_QUERY_NUMBER . "` int primary key,", From 65e7a137cfe4adf651cee1a91dd7c12fcc016fe7 Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Wed, 23 May 2018 16:31:52 +0100 Subject: [PATCH 2/5] Update db-migrate to work with new features --- bin/db-migrate | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) diff --git a/bin/db-migrate b/bin/db-migrate index a854f7b..14b80c9 100755 --- a/bin/db-migrate +++ b/bin/db-migrate @@ -7,43 +7,32 @@ use Gt\Database\Migration\Migrator; * Database migration iterates over a set of incremental schema changes and * stores the currently-migrated schema version within the database itself. */ -$autoloadPath = ""; -$currentDir = __DIR__; - -// The bin directory may be in multiple places, depending on how this library -// was installed. Iterate up the tree until either the autoloader or the root -// directory is found: -while((empty($autoloadPath)) && $currentDir !== "/") { - $currentDir = realpath($currentDir . "/.."); - if(is_file("$currentDir/autoload.php")) { - $autoloadPath = "$currentDir/autoload.php"; - } -} -if(empty($autoloadPath)) { - $autoloadPath = realpath(__DIR__ . "/../vendor/autoload.php"); -} +// The script must be run from the context of a project's root directory. +$repoBasePath = getcwd(); +$autoloadPath = implode(DIRECTORY_SEPARATOR, [ + $repoBasePath, + "vendor", + "autoload.php", +]); require($autoloadPath); -// Repository will always be the parent directory above autoload.php. -$repoBasePath = dirname(dirname($autoloadPath)); - $forced = false; if(!empty($argv[1]) && ($argv[1] === "--force" || $argv[1] === "-f")) { $forced = true; } -$config = new Config("$repoBasePath/config.ini", [ - "database" => [ - "query_path" => "src/query", - "migration_path" => "_migration", - "migration_table" => "_migration", - ] +// Load the default config supplied by WebEngine, if available: +$webEngineConfig = new Config("$repoBasePath/vendor/phpgt/webengine/config.default.ini"); +$config = new Config( + "$repoBasePath/config.ini", + [ + "database" => $webEngineConfig["database"] ?? [], ] ); $settings = new Settings( - implode("/", [ + implode(DIRECTORY_SEPARATOR, [ $repoBasePath, $config["database"]["query_path"] ]), @@ -55,7 +44,7 @@ $settings = new Settings( $config["database"]["password"] ); -$migrationPath = implode("/", [ +$migrationPath = implode(DIRECTORY_SEPARATOR, [ $repoBasePath, $config["database"]["query_path"], $config["database"]["migration_path"], @@ -63,7 +52,8 @@ $migrationPath = implode("/", [ $migrationTable = $config["database"]["migration_table"]; $migrator = new Migrator($settings, $migrationPath, $migrationTable, $forced); +$migrator->createMigrationTable(); $migrationCount = $migrator->getMigrationCount(); $migrationFileList = $migrator->getMigrationFileList(); -$migrator->checkIntegrity($migrationCount, $migrationFileList); +$migrator->checkIntegrity($migrationFileList, $migrationCount); $migrator->performMigration($migrationFileList, $migrationCount); \ No newline at end of file From c85b273b65a9fad2af00816d3174021b500aafec Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Wed, 23 May 2018 16:36:22 +0100 Subject: [PATCH 3/5] Rename Client->Database --- src/Database.php | 157 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 src/Database.php diff --git a/src/Database.php b/src/Database.php new file mode 100644 index 0000000..51e26c5 --- /dev/null +++ b/src/Database.php @@ -0,0 +1,157 @@ +storeConnectionDriverFromSettings($connectionSettings); + $this->storeQueryCollectionFactoryFromSettings($connectionSettings); + } + + public function fetch(string $queryName, ...$bindings):?Row { + $result = $this->query($queryName, $bindings); + + return $result->fetch(); + } + + public function fetchAll(string $queryName, ...$bindings):ResultSet { + return $this->query($queryName, $bindings); + } + + public function insert(string $queryName, ...$bindings):int { + $result = $this->query($queryName, $bindings); + + return $result->lastInsertId(); + } + + public function delete(string $queryName, ...$bindings):int { + $result = $this->query($queryName, $bindings); + + return $result->affectedRows(); + } + + public function update(string $queryName, ...$bindings):int { + $result = $this->query($queryName, $bindings); + + return $result->affectedRows(); + } + + public function query(string $queryName, ...$bindings):ResultSet { + while(isset($bindings[0]) + && is_array($bindings[0])) { + $bindings = $bindings[0]; + } + + $queryCollectionName = substr( + $queryName, + 0, + strrpos($queryName, "/") + ); + $queryFile = substr( + $queryName, + strrpos($queryName, "/") + 1 + ); + + $connectionName = $this->currentConnectionName ?? DefaultSettings::DEFAULT_NAME; + $queryCollection = $this->queryCollection( + $queryCollectionName, + $connectionName + ); + + return $queryCollection->query($queryFile, $bindings); + } + + public function setCurrentConnectionName(string $connectionName) { + $this->currentConnectionName = $this->getNamedConnection( + $connectionName + ); + } + + public function executeSql( + string $query, + array $bindings = [], + string $connectionName = DefaultSettings::DEFAULT_NAME + ):ResultSet { + $connection = $this->getNamedConnection($connectionName); + try { + $statement = $connection->prepare($query); + } + catch(PDOException $exception) { + throw new DatabaseException( + $exception->getMessage(), + intval($exception->getCode()) + ); + } + + $statement->execute($bindings); + + return new ResultSet($statement, $connection->lastInsertId()); + } + + protected function getNamedConnection(string $connectionName):Connection { + $driver = $this->driverArray[$connectionName]; + + return $driver->getConnection(); + } + + protected function storeConnectionDriverFromSettings(array $settingsArray) { + foreach($settingsArray as $settings) { + $connectionName = $settings->getConnectionName(); + $this->driverArray[$connectionName] = new Driver($settings); + } + } + + protected function storeQueryCollectionFactoryFromSettings(array $settingsArray) { + foreach($settingsArray as $settings) { + $connectionName = $settings->getConnectionName(); + $this->queryCollectionFactoryArray[$connectionName] = + new QueryCollectionFactory($this->driverArray[$connectionName]); + } + } + + public function queryCollection( + string $queryCollectionName, + string $connectionName = DefaultSettings::DEFAULT_NAME + ):QueryCollection { + return $this->queryCollectionFactoryArray[$connectionName]->create($queryCollectionName); + } + + public function getDriver( + string $connectionName = DefaultSettings::DEFAULT_NAME + ):Driver { + return $this->driverArray[$connectionName]; + } + + protected function getFirstConnectionName():string { + reset($this->driverArray); + + return key($this->driverArray); + } +} \ No newline at end of file From fc8a25c87fefd383dcdca56e3ed4be83f02f12ac Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Wed, 23 May 2018 19:21:07 +0100 Subject: [PATCH 4/5] Pass tests after variable-argument refactor --- src/Database.php | 17 +++----- src/Query/QueryCollection.php | 39 +++++++++++++------ .../unit/{ClientTest.php => DatabaseTest.php} | 2 +- test/unit/Query/QueryCollectionCRUDsTest.php | 6 ++- test/unit/Query/QueryCollectionTest.php | 5 ++- 5 files changed, 44 insertions(+), 25 deletions(-) rename test/unit/{ClientTest.php => DatabaseTest.php} (96%) diff --git a/src/Database.php b/src/Database.php index 51e26c5..9114fff 100644 --- a/src/Database.php +++ b/src/Database.php @@ -36,39 +36,34 @@ public function __construct(SettingsInterface...$connectionSettings) { } public function fetch(string $queryName, ...$bindings):?Row { - $result = $this->query($queryName, $bindings); + $result = $this->query($queryName, ...$bindings); return $result->fetch(); } public function fetchAll(string $queryName, ...$bindings):ResultSet { - return $this->query($queryName, $bindings); + return $this->query($queryName, ...$bindings); } public function insert(string $queryName, ...$bindings):int { - $result = $this->query($queryName, $bindings); + $result = $this->query($queryName, ...$bindings); return $result->lastInsertId(); } public function delete(string $queryName, ...$bindings):int { - $result = $this->query($queryName, $bindings); + $result = $this->query($queryName, ...$bindings); return $result->affectedRows(); } public function update(string $queryName, ...$bindings):int { - $result = $this->query($queryName, $bindings); + $result = $this->query($queryName, ...$bindings); return $result->affectedRows(); } public function query(string $queryName, ...$bindings):ResultSet { - while(isset($bindings[0]) - && is_array($bindings[0])) { - $bindings = $bindings[0]; - } - $queryCollectionName = substr( $queryName, 0, @@ -85,7 +80,7 @@ public function query(string $queryName, ...$bindings):ResultSet { $connectionName ); - return $queryCollection->query($queryFile, $bindings); + return $queryCollection->query($queryFile, ...$bindings); } public function setCurrentConnectionName(string $connectionName) { diff --git a/src/Query/QueryCollection.php b/src/Query/QueryCollection.php index 001f849..6bc9473 100644 --- a/src/Query/QueryCollection.php +++ b/src/Query/QueryCollection.php @@ -40,49 +40,66 @@ public function __call($name, $args) { public function query( string $name, - iterable $placeholderMap = [] + ...$placeholderMap ):ResultSet { $query = $this->queryFactory->create($name); + while(isset($placeholderMap[0]) + && is_array($placeholderMap[0])) { + $placeholderMap = $placeholderMap[0]; + } + return $query->execute($placeholderMap); } public function insert( string $name, - iterable $placeholderMap = [] + ...$placeholderMap ):int { return (int)$this->query( $name, - $placeholderMap + ...$placeholderMap )->lastInsertId(); } public function fetch( string $name, - iterable $placeholderMap = [] + ...$placeholderMap ):?Row { - return $this->query($name, $placeholderMap)->current(); + return $this->query( + $name, + ...$placeholderMap + )->current(); } public function fetchAll( string $name, - iterable $placeholderMap = [] + ...$placeholderMap ):ResultSet { - return $this->query($name, $placeholderMap); + return $this->query( + $name, + ...$placeholderMap + ); } public function update( string $name, - iterable $placeholderMap = [] + ...$placeholderMap ):int { - return $this->query($name, $placeholderMap)->affectedRows(); + return $this->query( + $name, + ...$placeholderMap + )->affectedRows(); } public function delete( string $name, - iterable $placeholderMap = [] + ...$placeholderMap ):int { - return $this->query($name, $placeholderMap)->affectedRows(); + return $this->query( + $name, + ...$placeholderMap + )->affectedRows(); } public function getDirectoryPath():string { diff --git a/test/unit/ClientTest.php b/test/unit/DatabaseTest.php similarity index 96% rename from test/unit/ClientTest.php rename to test/unit/DatabaseTest.php index 1e44b87..f2daa26 100644 --- a/test/unit/ClientTest.php +++ b/test/unit/DatabaseTest.php @@ -5,7 +5,7 @@ use Gt\Database\Query\QueryCollection; use PHPUnit\Framework\TestCase; -class ClientTest extends TestCase { +class DatabaseTest extends TestCase { public function testInterface() { $db = new Database(); static::assertInstanceOf(Database::class, $db); diff --git a/test/unit/Query/QueryCollectionCRUDsTest.php b/test/unit/Query/QueryCollectionCRUDsTest.php index 1cb1bcd..411699a 100644 --- a/test/unit/Query/QueryCollectionCRUDsTest.php +++ b/test/unit/Query/QueryCollectionCRUDsTest.php @@ -46,7 +46,11 @@ public function testCreate() { static::assertEquals( $lastInsertID, - $this->queryCollection->insert("something", $placeholderVars)); + $this->queryCollection->insert( + "something", + $placeholderVars + ) + ); } public function testCreateNoParams() { diff --git a/test/unit/Query/QueryCollectionTest.php b/test/unit/Query/QueryCollectionTest.php index 0a7201e..317390c 100644 --- a/test/unit/Query/QueryCollectionTest.php +++ b/test/unit/Query/QueryCollectionTest.php @@ -20,7 +20,10 @@ public function testQueryCollectionQuery() { ->method("execute") ->with($placeholderVars); - $resultSet = $this->queryCollection->query("something", $placeholderVars); + $resultSet = $this->queryCollection->query( + "something", + $placeholderVars + ); static::assertInstanceOf( ResultSet::class, From 24d61b16d1565829c605776ab7876dd877175e66 Mon Sep 17 00:00:00 2001 From: Greg Bowler Date: Wed, 23 May 2018 21:10:42 +0100 Subject: [PATCH 5/5] Simplify variable arguments and named placeholder usage, stronger tests --- src/Database.php | 12 +++---- src/Query/QueryCollection.php | 6 ---- src/Query/SqlQuery.php | 30 ++++++++++++++++ test/unit/IntegrationTest.php | 36 ++++++++++++++++++-- test/unit/Query/QueryCollectionCRUDsTest.php | 10 +++--- test/unit/Query/QueryCollectionTest.php | 4 +-- 6 files changed, 76 insertions(+), 22 deletions(-) diff --git a/src/Database.php b/src/Database.php index 9114fff..fb721a3 100644 --- a/src/Database.php +++ b/src/Database.php @@ -36,29 +36,29 @@ public function __construct(SettingsInterface...$connectionSettings) { } public function fetch(string $queryName, ...$bindings):?Row { - $result = $this->query($queryName, ...$bindings); + $result = $this->query($queryName, $bindings); return $result->fetch(); } public function fetchAll(string $queryName, ...$bindings):ResultSet { - return $this->query($queryName, ...$bindings); + return $this->query($queryName, $bindings); } public function insert(string $queryName, ...$bindings):int { - $result = $this->query($queryName, ...$bindings); + $result = $this->query($queryName, $bindings); return $result->lastInsertId(); } public function delete(string $queryName, ...$bindings):int { - $result = $this->query($queryName, ...$bindings); + $result = $this->query($queryName, $bindings); return $result->affectedRows(); } public function update(string $queryName, ...$bindings):int { - $result = $this->query($queryName, ...$bindings); + $result = $this->query($queryName, $bindings); return $result->affectedRows(); } @@ -80,7 +80,7 @@ public function query(string $queryName, ...$bindings):ResultSet { $connectionName ); - return $queryCollection->query($queryFile, ...$bindings); + return $queryCollection->query($queryFile, $bindings); } public function setCurrentConnectionName(string $connectionName) { diff --git a/src/Query/QueryCollection.php b/src/Query/QueryCollection.php index 6bc9473..bc591ed 100644 --- a/src/Query/QueryCollection.php +++ b/src/Query/QueryCollection.php @@ -43,12 +43,6 @@ public function query( ...$placeholderMap ):ResultSet { $query = $this->queryFactory->create($name); - - while(isset($placeholderMap[0]) - && is_array($placeholderMap[0])) { - $placeholderMap = $placeholderMap[0]; - } - return $query->execute($placeholderMap); } diff --git a/src/Query/SqlQuery.php b/src/Query/SqlQuery.php index 94d0d0c..747d03c 100644 --- a/src/Query/SqlQuery.php +++ b/src/Query/SqlQuery.php @@ -23,6 +23,8 @@ public function getSql(array $bindings = []):string { } public function execute(array $bindings = []):ResultSet { + $bindings = $this->flattenBindings($bindings); + $pdo = $this->preparePdo(); $sql = $this->getSql($bindings); $statement = $this->prepareStatement($pdo, $sql); @@ -126,4 +128,32 @@ protected function bindingsEmptyOrNonAssociative(array $bindings):bool { $bindings === [] || array_keys($bindings) === range(0, count($bindings) - 1); } + + /** + * $bindings can either be : + * 1) An array of individual values for binding to the question mark placeholder, + * passed in as variable arguments. + * 2) An array containing one single subarray containing key-value-pairs for binding to + * named placeholders. + * + * Due to the use of variable arguments on the Database and QueryCollection classes, + * key-value-pair bindings may be double or triple nested. + */ + protected function flattenBindings(array $bindings):array { + if(!isset($bindings[0])) { + return $bindings; + } + + $flatArray = []; + foreach($bindings as $i => $b) { + while(isset($b[0]) + && is_array($b[0])) { + $b = $b[0]; + } + + $flatArray = array_merge($flatArray, $b); + } + + return $flatArray; + } } diff --git a/test/unit/IntegrationTest.php b/test/unit/IntegrationTest.php index c8de04a..05b7bcd 100644 --- a/test/unit/IntegrationTest.php +++ b/test/unit/IntegrationTest.php @@ -24,14 +24,14 @@ public function setUp() { $driver = $this->db->getDriver(); $connection = $driver->getConnection(); - $output = $connection->exec("CREATE TABLE test_table ( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(32), timestamp DATETIME DEFAULT current_timestamp); CREATE UNIQUE INDEX test_table_name_uindex ON test_table (name);"); + $output = $connection->exec("CREATE TABLE test_table ( id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR(32), number integer, timestamp DATETIME DEFAULT current_timestamp); CREATE UNIQUE INDEX test_table_name_uindex ON test_table (name);"); if($output === false) { $error = $connection->errorInfo(); throw new Exception($error[2]); } - $insertStatement = $connection->prepare("INSERT INTO test_table (name) VALUES ('one'), ('two'), ('three')"); + $insertStatement = $connection->prepare("INSERT INTO test_table (name, number) VALUES ('one', 1), ('two', 2), ('three', 3)"); $success = $insertStatement->execute(); if($success === false) { $error = $connection->errorInfo(); @@ -94,7 +94,7 @@ public function testQuestionMarkParameter() { mkdir($queryCollectionPath, 0775, true); file_put_contents( $getByIdQueryPath, - "SELECT id, name FROM test_table WHERE id = ?" + "SELECT id, name, number FROM test_table WHERE id = ?" ); $result2 = $this->db->fetch("exampleCollection/getById", 2); @@ -107,6 +107,36 @@ public function testQuestionMarkParameter() { static::assertCount(3, $rqr); } + public function testMultipleParameterUsage() { + $queryCollectionPath = $this->queryBase . "/exampleCollection"; + $getByNameNumberQueryPath = $queryCollectionPath . "/getByNameNumber.sql"; + + mkdir($queryCollectionPath, 0775, true); + file_put_contents( + $getByNameNumberQueryPath, + "SELECT id, name, number FROM test_table WHERE name = :name and number = :number" + ); + + $result1 = $this->db->fetch("exampleCollection/getByNameNumber", [ + "name" => "one", + "number" => 1, + ]); + $result2 = $this->db->fetch("exampleCollection/getByNameNumber", [ + "name" => "two", + "number" => 2, + ]); + $resultNull = $this->db->fetch("exampleCollection/getByNameNumber", [ + "name" => "three", + "number" => 55, + ]); + + $rqr = $this->db->executeSql("SELECT id, name FROM test_table"); + + static::assertEquals(1, $result1->id); + static::assertEquals(2, $result2->id); + static::assertNull($resultNull); + } + private function settingsSingleton():Settings { if(is_null($this->settings)) { $this->settings = new Settings( diff --git a/test/unit/Query/QueryCollectionCRUDsTest.php b/test/unit/Query/QueryCollectionCRUDsTest.php index 411699a..d6570f7 100644 --- a/test/unit/Query/QueryCollectionCRUDsTest.php +++ b/test/unit/Query/QueryCollectionCRUDsTest.php @@ -41,7 +41,7 @@ public function testCreate() { $this->mockQuery ->expects(static::once()) ->method("execute") - ->with($placeholderVars) + ->with([$placeholderVars]) ->willReturn($mockResultSet); static::assertEquals( @@ -82,7 +82,7 @@ public function testRetrieve() { $this->mockQuery ->expects(static::once()) ->method("execute") - ->with($placeholderVars) + ->with([$placeholderVars]) ->willReturn($mockResultSet); $actual = $this->queryCollection->fetch("something", $placeholderVars); @@ -137,7 +137,7 @@ public function testRetrieveAll() { $this->mockQuery ->expects(static::once()) ->method("execute") - ->with($placeholderVars) + ->with([$placeholderVars]) ->willReturn($mockResultSet); $actual = $this->queryCollection->fetchAll("something", $placeholderVars); @@ -192,7 +192,7 @@ public function testUpdate() { $this->mockQuery ->expects(static::once()) ->method("execute") - ->with($placeholderVars) + ->with([$placeholderVars]) ->willReturn($mockResultSet); static::assertEquals($recordsUpdatedCount, $this->queryCollection->update("something", $placeholderVars)); @@ -227,7 +227,7 @@ public function testDelete() { $this->mockQuery ->expects(static::once()) ->method("execute") - ->with($placeholderVars) + ->with([$placeholderVars]) ->willReturn($mockResultSet); static::assertEquals( diff --git a/test/unit/Query/QueryCollectionTest.php b/test/unit/Query/QueryCollectionTest.php index 317390c..c753ef9 100644 --- a/test/unit/Query/QueryCollectionTest.php +++ b/test/unit/Query/QueryCollectionTest.php @@ -18,7 +18,7 @@ public function testQueryCollectionQuery() { $this->mockQuery ->expects(static::once()) ->method("execute") - ->with($placeholderVars); + ->with([$placeholderVars]); $resultSet = $this->queryCollection->query( "something", @@ -47,7 +47,7 @@ public function testQueryShorthand() { $this->mockQuery ->expects(static::once()) ->method("execute") - ->with($placeholderVars); + ->with([$placeholderVars]); static::assertInstanceOf( ResultSet::class,