From 2bf8897918db79570c0ee46b643b268a1295d31c Mon Sep 17 00:00:00 2001 From: Timothy J Warren Date: Fri, 13 Dec 2019 15:11:49 -0500 Subject: [PATCH] Prepwork for 'returning' method of Query builder --- README.md | 30 +++++++++++------------ src/Drivers/AbstractDriver.php | 22 +++++++++++++++++ src/Drivers/DriverInterface.php | 7 ++++++ src/Drivers/Mysql/Driver.php | 30 +++++++++++++++++++++++ src/Drivers/Pgsql/Driver.php | 2 ++ src/Drivers/Sqlite/Driver.php | 15 +++++++++++- src/QueryType.php | 26 ++++++++++++++++++++ tests/BaseDriverTest.php | 7 ++++++ tests/ConnectionManagerTest.php | 1 + tests/Drivers/MySQL/MySQLDriverTest.php | 1 - tests/Drivers/PgSQL/PgSQLDriverTest.php | 1 - tests/Drivers/SQLite/SQLiteDriverTest.php | 4 ++- tests/index.php | 6 ++++- 13 files changed, 131 insertions(+), 21 deletions(-) create mode 100644 src/QueryType.php diff --git a/README.md b/README.md index cd276f0..822c032 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,20 @@ A query builder/database abstraction layer, using prepared statements for security. -[![Build Status](https://jenkins.timshomepage.net/buildStatus/icon?job=query)](https://jenkins.timshomepage.net/job/query/) [![Code Coverage](https://scrutinizer-ci.com/g/aviat4ion/Query/badges/coverage.png?b=develop)](https://scrutinizer-ci.com/g/aviat4ion/Query/?branch=develop) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/aviat4ion/Query/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/aviat4ion/Query/?branch=develop) [![Latest Stable Version](https://poser.pugx.org/aviat/query/v/stable.png)](https://packagist.org/packages/aviat/query) [![Total Downloads](https://poser.pugx.org/aviat/query/downloads.png)](https://packagist.org/packages/aviat/query) [![Latest Unstable Version](https://poser.pugx.org/aviat/query/v/unstable.png)](https://packagist.org/packages/aviat/query) -[![License](https://poser.pugx.org/aviat/query/license.png)](http://www.dbad-license.org/) ## Requirements -* PDO extensions for the databases you wish to use (unless it's Firebird, in which case, the interbase extension is required) -* PHP 7.1 or later - +* PDO extensions for the databases you wish to use +* PHP 7.2 or later + ## Databases Supported -* MySQL -* PostgreSQL +* MySQL 5+ / MariaDB +* PostgreSQL 8.4+ * SQLite ## Including Query in your application @@ -40,7 +38,7 @@ $params = array( 'database' => 'test_db', // Only required for - // SQLite + // SQLite 'file' => '/path/to/db/file', // Optional parameters @@ -78,12 +76,12 @@ Query('old')->query($sql); ``` ### Running Queries -Query is based on CodeIgniter's [Query Builder](http://www.codeigniter.com/user_guide/database/query_builder.html) class. -However, it has camelCased method names, and does not implement the caching methods. +Query is based on CodeIgniter's [Query Builder](http://www.codeigniter.com/user_guide/database/query_builder.html) class. +However, it has camelCased method names, and does not implement the caching methods. For specific query builder methods, see the [class documentation](https://gitdev.timshomepage.net/Query/apiDocumentation/classes/Query_QueryBuilder.html#methods). -Other database methods not directly involved in building queries, are also available from the query builder object. -The methods available depend on the database, but common methods are documented +Other database methods not directly involved in building queries, are also available from the query builder object. +The methods available depend on the database, but common methods are documented [here](https://gitdev.timshomepage.net/Query/apiDocumentation/classes/Query_Drivers_AbstractDriver.html#methods). #### You can also run queries manually. @@ -102,7 +100,7 @@ An example of a moderately complex query: $query = $db->select('id, key as k, val') ->from('table t') ->where('k >', 3) - ->orWhere('id !=' 5) + ->orWhere('id !=', 5) ->orderBy('val', 'DESC') ->limit(3, 1) ->get(); @@ -120,9 +118,9 @@ LIMIT 3 OFFSET 1 ``` The query execution methods `get`, `getWhere`, `insert`, - `insertBatch`,`update`, and `delete` return a native [PDOStatemnt](http://php.net/manual/en/class.pdostatement.php) object. -To retrieve the results of a query, use the PDOStatement method [fetch](http://php.net/manual/en/pdostatement.fetch.php) and/or -[fetchAll](http://php.net/manual/en/pdostatement.fetchall.php). + `insertBatch`,`update`, and `delete` return a native [PDOStatement](http://php.net/manual/en/class.pdostatement.php) object. +To retrieve the results of a query, use the PDOStatement method [fetch](http://php.net/manual/en/pdostatement.fetch.php) and/or +[fetchAll](http://php.net/manual/en/pdostatement.fetchall.php). ```php driverQuery('typeList', FALSE); } + /** + * Get the version of the database engine + * + * @return string + */ + public function getVersion(): string + { + return $this->getAttribute(PDO::ATTR_SERVER_VERSION); + } + /** * Method to simplify retrieving db results for meta-data queries * @@ -653,6 +663,18 @@ abstract class AbstractDriver return $this->statement; } + /** + * Generate the returning clause for the current database + * + * @param string $query + * @param string $select + * @return string + */ + public function returning(string $query, string $select): string + { + return "{$query} RETURNING {$select}"; + } + /** * Helper method for quote_ident * diff --git a/src/Drivers/DriverInterface.php b/src/Drivers/DriverInterface.php index 606be26..4e02abe 100644 --- a/src/Drivers/DriverInterface.php +++ b/src/Drivers/DriverInterface.php @@ -253,6 +253,13 @@ interface DriverInterface /* extends the interface of PDO */ { */ public function getUtil(): AbstractUtil; + /** + * Get the version of the database engine + * + * @return string + */ + public function getVersion(): string; + /** * Get the last sql query executed * diff --git a/src/Drivers/Mysql/Driver.php b/src/Drivers/Mysql/Driver.php index 220d5d0..32c984f 100644 --- a/src/Drivers/Mysql/Driver.php +++ b/src/Drivers/Mysql/Driver.php @@ -63,4 +63,34 @@ class Driver extends AbstractDriver { parent::__construct($dsn, $username, $password, $options); } + + /** + * Generate the returning clause for the current database + * + * @param string $query + * @param string $select + * @return string + */ + public function returning(string $query, string $select): string + { + // @TODO add checks for MariaDB for future-proofing + // MariaDB 10.5.0+ supports the returning clause for insert + if ( + stripos($query, 'insert') !== FALSE + && version_compare($this->getVersion(), '10.5.0', '>=') + ){ + return parent::returning($query, $select); + } + + // MariaDB 10.0.5+ supports the returning clause for delete + if ( + stripos($query, 'delete') !== FALSE + && version_compare($this->getVersion(), '10.0.5', '>=') + ){ + return parent::returning($query, $select); + } + + // Just return the same SQL if the returning clause is not supported + return $query; + } } \ No newline at end of file diff --git a/src/Drivers/Pgsql/Driver.php b/src/Drivers/Pgsql/Driver.php index b841798..3de596f 100644 --- a/src/Drivers/Pgsql/Driver.php +++ b/src/Drivers/Pgsql/Driver.php @@ -78,7 +78,9 @@ SQL; { if ( ! isset($valueMap[$key[$type]])) { + // @codeCoverageIgnoreStart continue; + // @codeCoverageIgnoreEnd } $key[$type] = $valueMap[$key[$type]]; diff --git a/src/Drivers/Sqlite/Driver.php b/src/Drivers/Sqlite/Driver.php index 26747b1..8b4ae67 100644 --- a/src/Drivers/Sqlite/Driver.php +++ b/src/Drivers/Sqlite/Driver.php @@ -109,7 +109,7 @@ class Driver extends AbstractDriver { { // If greater than version 3.7.11, supports the same syntax as // MySQL and Postgres - if (version_compare($this->getAttribute(PDO::ATTR_SERVER_VERSION), '3.7.11', '>=')) + if (version_compare($this->getVersion(), '3.7.11', '>=')) { return parent::insertBatch($table, $data); } @@ -145,4 +145,17 @@ class Driver extends AbstractDriver { return [$sql, NULL]; } + + /** + * Generate the returning clause for the current database + * + * @param string $query + * @param string $select + * @return string + */ + public function returning(string $query, string $select): string + { + // Return the same query, as the returning clause is not supported + return $query; + } } \ No newline at end of file diff --git a/src/QueryType.php b/src/QueryType.php new file mode 100644 index 0000000..cfcc47f --- /dev/null +++ b/src/QueryType.php @@ -0,0 +1,26 @@ + + * @copyright 2012 - 2019 Timothy J. Warren + * @license http://www.opensource.org/licenses/mit-license.html MIT License + * @link https://git.timshomepage.net/aviat/Query + * @version 3.0.0 + */ +namespace Query; + +/** + * 'Enum' of query types + */ +class QueryType { + public const SELECT = 'select'; + public const INSERT = 'insert'; + public const UPDATE = 'update'; + public const DELETE = 'delete'; +} \ No newline at end of file diff --git a/tests/BaseDriverTest.php b/tests/BaseDriverTest.php index 438af35..950daa4 100644 --- a/tests/BaseDriverTest.php +++ b/tests/BaseDriverTest.php @@ -131,5 +131,12 @@ abstract class BaseDriverTest extends TestCase { $funcs = self::$db->getFunctions(); $this->assertTrue(\is_array($funcs)); } + + public function testGetVersion(): void + { + $version = self::$db->getVersion(); + $this->assertTrue(is_string($version)); + $this->assertTrue(strlen($version) > 0); + } } // End of db_test.php \ No newline at end of file diff --git a/tests/ConnectionManagerTest.php b/tests/ConnectionManagerTest.php index 9e79868..1790f83 100644 --- a/tests/ConnectionManagerTest.php +++ b/tests/ConnectionManagerTest.php @@ -24,6 +24,7 @@ class ConnectionManagerTest extends TestCase { public static function setUpBeforeClass(): void { + ConnectionManager::getInstance(); self::$instance = ConnectionManager::getInstance(); } diff --git a/tests/Drivers/MySQL/MySQLDriverTest.php b/tests/Drivers/MySQL/MySQLDriverTest.php index b04c7f1..a5c1f94 100644 --- a/tests/Drivers/MySQL/MySQLDriverTest.php +++ b/tests/Drivers/MySQL/MySQLDriverTest.php @@ -23,7 +23,6 @@ use TypeError; /** * MySQLTest class. * - * @covers \Query\Drivers\Mysql\Driver * @requires extension pdo_mysql */ class MySQLDriverTest extends BaseDriverTest { diff --git a/tests/Drivers/PgSQL/PgSQLDriverTest.php b/tests/Drivers/PgSQL/PgSQLDriverTest.php index 7becb0c..17f4029 100644 --- a/tests/Drivers/PgSQL/PgSQLDriverTest.php +++ b/tests/Drivers/PgSQL/PgSQLDriverTest.php @@ -25,7 +25,6 @@ use TypeError; * * @extends DBTest * @requires extension pdo_pgsql - * @covers \Query\Drivers\Pgsql\Driver */ class PgSQLDriverTest extends BaseDriverTest { diff --git a/tests/Drivers/SQLite/SQLiteDriverTest.php b/tests/Drivers/SQLite/SQLiteDriverTest.php index c14af25..a74bb20 100644 --- a/tests/Drivers/SQLite/SQLiteDriverTest.php +++ b/tests/Drivers/SQLite/SQLiteDriverTest.php @@ -25,7 +25,6 @@ use Query\Tests\BaseDriverTest; * * @extends DBTest * @requires extension pdo_sqlite - * @covers \Query\Drivers\Sqlite\Driver */ class SQLiteDriverTest extends BaseDriverTest { @@ -253,6 +252,9 @@ SQL; public function testGetDBs(): void { + $driverSQL = self::$db->getSql()->dbList(); + $this->assertEqual('', $driverSQL); + $this->assertNull(self::$db->getDbs()); } diff --git a/tests/index.php b/tests/index.php index b54b763..f8bac45 100644 --- a/tests/index.php +++ b/tests/index.php @@ -35,7 +35,11 @@ namespace Query\Tests { { $class = \get_class($this); - echo 'Ran test suite: ' . $class . '
'; + if (PHP_SAPI !== 'cli') + { + echo 'Running test suite: ' . $class . '
'; + flush(); + } if (method_exists($class, 'setupBeforeClass')) { $class::setupBeforeClass();