Set consistent code style

This commit is contained in:
Timothy Warren 2023-03-17 15:18:33 -04:00
parent 94d1cbb09b
commit cf2255ce87
27 changed files with 285 additions and 290 deletions

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query; namespace Query;
use DomainException; use DomainException;
@ -22,8 +23,8 @@ use stdClass;
* Connection manager class to manage connections for the * Connection manager class to manage connections for the
* Query method * Query method
*/ */
final class ConnectionManager { final class ConnectionManager
{
/** /**
* Map of named database connections * Map of named database connections
*/ */
@ -91,7 +92,6 @@ final class ConnectionManager {
/** /**
* Returns the connection specified by the name given * Returns the connection specified by the name given
* *
* @param string $name
* @throws Exception\NonExistentConnectionException * @throws Exception\NonExistentConnectionException
*/ */
public function getConnection(string $name = ''): QueryBuilderInterface public function getConnection(string $name = ''): QueryBuilderInterface
@ -113,9 +113,6 @@ final class ConnectionManager {
/** /**
* Parse the passed parameters and return a connection * Parse the passed parameters and return a connection
*
* @param array|object $params
* @return QueryBuilderInterface
*/ */
public function connect(array|object $params): QueryBuilderInterface public function connect(array|object $params): QueryBuilderInterface
{ {
@ -138,7 +135,6 @@ final class ConnectionManager {
// Create Query Builder object // Create Query Builder object
$conn = new QueryBuilder($db, new QueryParser($db)); $conn = new QueryBuilder($db, new QueryParser($db));
// Save it for later // Save it for later
if (isset($params->alias)) if (isset($params->alias))
{ {
@ -155,9 +151,7 @@ final class ConnectionManager {
/** /**
* Parses params into a dsn and option array * Parses params into a dsn and option array
* *
* @param array|object $rawParams
* @throws Exception\BadDBDriverException * @throws Exception\BadDBDriverException
* @return array
*/ */
public function parseParams(array|object $rawParams): array public function parseParams(array|object $rawParams): array
{ {
@ -183,7 +177,6 @@ final class ConnectionManager {
// Create the dsn for the database to connect to // Create the dsn for the database to connect to
$dsn = strtolower($dbType) === 'sqlite' ? $params->file : $this->createDsn($dbType, $params); $dsn = strtolower($dbType) === 'sqlite' ? $params->file : $this->createDsn($dbType, $params);
return [$dsn, $dbType, $params, $options]; return [$dsn, $dbType, $params, $options];
} }
@ -209,12 +202,12 @@ final class ConnectionManager {
'prefix' => 'prefix', 'prefix' => 'prefix',
'options' => 'options', 'options' => 'options',
'database' => 'database', 'database' => 'database',
'alias' => 'alias' 'alias' => 'alias',
]; ];
foreach($params as $key => $val) foreach ($params as $key => $val)
{ {
if (( ! array_key_exists($key, $skip)) && ! empty($val)) if (( ! array_key_exists($key, $skip)) && ! empty($val))
{ {
$pairs[] = implode('=', [$key, $val]); $pairs[] = implode('=', [$key, $val]);
} }

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers; namespace Query\Drivers;
use InvalidArgumentException; use InvalidArgumentException;
@ -29,10 +30,8 @@ use function is_string;
* *
* Extends PDO to simplify cross-database issues * Extends PDO to simplify cross-database issues
*/ */
abstract class AbstractDriver abstract class AbstractDriver extends PDO implements DriverInterface
extends PDO {
implements DriverInterface {
/** /**
* Reference to the last executed query * Reference to the last executed query
*/ */
@ -76,7 +75,7 @@ abstract class AbstractDriver
/** /**
* PDO constructor wrapper * PDO constructor wrapper
*/ */
public function __construct(string $dsn, string $username=NULL, string $password=NULL, array $driverOptions=[]) public function __construct(string $dsn, ?string $username=NULL, ?string $password=NULL, array $driverOptions=[])
{ {
// Set PDO to display errors as exceptions, and apply driver options // Set PDO to display errors as exceptions, and apply driver options
$driverOptions[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION; $driverOptions[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
@ -85,23 +84,6 @@ abstract class AbstractDriver
$this->_loadSubClasses(); $this->_loadSubClasses();
} }
/**
* Loads the subclasses for the driver
*/
protected function _loadSubClasses(): void
{
// Load the sql and util class for the driver
$thisClass = $this::class;
$nsArray = explode("\\", $thisClass);
array_pop($nsArray);
$driver = array_pop($nsArray);
$sqlClass = __NAMESPACE__ . "\\{$driver}\\SQL";
$utilClass = __NAMESPACE__ . "\\{$driver}\\Util";
$this->driverSQL = new $sqlClass();
$this->util = new $utilClass($this);
}
/** /**
* Allow invoke to work on table object * Allow invoke to work on table object
* *
@ -114,14 +96,30 @@ abstract class AbstractDriver
isset($this->$name) isset($this->$name)
&& is_object($this->$name) && is_object($this->$name)
&& method_exists($this->$name, '__invoke') && method_exists($this->$name, '__invoke')
) ) {
{
return call_user_func_array([$this->$name, '__invoke'], $args); return call_user_func_array([$this->$name, '__invoke'], $args);
} }
return NULL; return NULL;
} }
/**
* Loads the subclasses for the driver
*/
protected function _loadSubClasses(): void
{
// Load the sql and util class for the driver
$thisClass = $this::class;
$nsArray = explode('\\', $thisClass);
array_pop($nsArray);
$driver = array_pop($nsArray);
$sqlClass = __NAMESPACE__ . "\\{$driver}\\SQL";
$utilClass = __NAMESPACE__ . "\\{$driver}\\Util";
$this->driverSQL = new $sqlClass();
$this->util = new $utilClass($this);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// ! Accessors / Mutators // ! Accessors / Mutators
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -177,11 +175,11 @@ abstract class AbstractDriver
$this->statement = $this->prepare($sql); $this->statement = $this->prepare($sql);
// Bind the parameters // Bind the parameters
foreach($data as $k => $value) foreach ($data as $k => $value)
{ {
// Parameters are 1-based, the data is 0-based // Parameters are 1-based, the data is 0-based
// So, if the key is numeric, add 1 // So, if the key is numeric, add 1
if(is_numeric($k)) if (is_numeric($k))
{ {
$k++; $k++;
} }
@ -282,7 +280,8 @@ abstract class AbstractDriver
// Fix functions // Fix functions
$funcs = []; $funcs = [];
preg_match_all("#{$this->escapeCharOpen}([a-zA-Z0-9_]+(\((.*?)\))){$this->escapeCharClose}#iu", $raw, $funcs, PREG_SET_ORDER); preg_match_all("#{$this->escapeCharOpen}([a-zA-Z0-9_]+(\((.*?)\))){$this->escapeCharClose}#iu", $raw, $funcs, PREG_SET_ORDER);
foreach($funcs as $f)
foreach ($funcs as $f)
{ {
// Unquote the function // Unquote the function
// Quote the inside identifiers // Quote the inside identifiers
@ -308,6 +307,7 @@ abstract class AbstractDriver
{ {
$tables = $this->driverQuery('tableList'); $tables = $this->driverQuery('tableList');
natsort($tables); natsort($tables);
return $tables; return $tables;
} }
@ -326,6 +326,7 @@ abstract class AbstractDriver
{ {
$views = $this->driverQuery('viewList'); $views = $this->driverQuery('viewList');
sort($views); sort($views);
return $views; return $views;
} }
@ -456,6 +457,7 @@ abstract class AbstractDriver
if (preg_match($regex, $this->lastQuery, $output) > 0) if (preg_match($regex, $this->lastQuery, $output) > 0)
{ {
$stmt = $this->query("SELECT COUNT(*) FROM {$output[1]}"); $stmt = $this->query("SELECT COUNT(*) FROM {$output[1]}");
return (int) $stmt->fetchColumn(); return (int) $stmt->fetchColumn();
} }
@ -472,7 +474,8 @@ abstract class AbstractDriver
// Values for insertion // Values for insertion
$vals = []; $vals = [];
foreach($data as $group)
foreach ($data as $group)
{ {
$vals = [...$vals, ...array_values($group)]; $vals = [...$vals, ...array_values($group)];
} }
@ -533,6 +536,7 @@ abstract class AbstractDriver
$line = $this->quoteIdent($field) . " = CASE\n"; $line = $this->quoteIdent($field) . " = CASE\n";
$cases = []; $cases = [];
foreach ($data as $case) foreach ($data as $case)
{ {
if (array_key_exists($field, $case)) if (array_key_exists($field, $case))
@ -553,6 +557,7 @@ abstract class AbstractDriver
$sql .= implode(",\n", $fieldLines) . "\n"; $sql .= implode(",\n", $fieldLines) . "\n";
$whereValues = array_column($data, $where); $whereValues = array_column($data, $where);
foreach ($whereValues as $value) foreach ($whereValues as $value)
{ {
$insertData[] = $value; $insertData[] = $value;
@ -579,6 +584,7 @@ abstract class AbstractDriver
$sql .= $this->quoteTable($table); $sql .= $this->quoteTable($table);
$this->statement = $this->query($sql); $this->statement = $this->query($sql);
return $this->statement; return $this->statement;
} }
@ -592,9 +598,6 @@ abstract class AbstractDriver
/** /**
* Helper method for quote_ident * Helper method for quote_ident
*
* @param mixed $str
* @return mixed
*/ */
public function _quote(mixed $str): mixed public function _quote(mixed $str): mixed
{ {
@ -608,7 +611,6 @@ abstract class AbstractDriver
) )
? "{$this->escapeCharOpen}{$str}{$this->escapeCharClose}" ? "{$this->escapeCharOpen}{$str}{$this->escapeCharClose}"
: $str; : $str;
} }
/** /**

View File

@ -13,13 +13,14 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers; namespace Query\Drivers;
/** /**
* Parent for database-specific syntax subclasses * Parent for database-specific syntax subclasses
*/ */
abstract class AbstractSQL implements SQLInterface { abstract class AbstractSQL implements SQLInterface
{
/** /**
* Limit clause * Limit clause
*/ */

View File

@ -13,13 +13,16 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers; namespace Query\Drivers;
use function arrayZipper;
/** /**
* Abstract class defining database / table creation methods * Abstract class defining database / table creation methods
*/ */
abstract class AbstractUtil { abstract class AbstractUtil
{
/** /**
* Save a reference to the connection object for later use * Save a reference to the connection object for later use
*/ */
@ -48,14 +51,15 @@ abstract class AbstractUtil {
// 'constraint' => ..., // 'constraint' => ...,
// 'index' => ..., // 'index' => ...,
// ] // ]
$columnArray = \arrayZipper([ $columnArray = arrayZipper([
'type' => $fields, 'type' => $fields,
'constraint' => $constraints 'constraint' => $constraints,
]); ]);
// Join column definitions together // Join column definitions together
$columns = []; $columns = [];
foreach($columnArray as $n => $props)
foreach ($columnArray as $n => $props)
{ {
$str = $this->getDriver()->quoteIdent($n); $str = $this->getDriver()->quoteIdent($n);
$str .= isset($props['type']) ? " {$props['type']}" : ''; $str .= isset($props['type']) ? " {$props['type']}" : '';
@ -65,7 +69,7 @@ abstract class AbstractUtil {
} }
// Generate the sql for the creation of the table // Generate the sql for the creation of the table
$sql = 'CREATE TABLE'.$existsStr.$this->getDriver()->quoteTable($name).' ('; $sql = 'CREATE TABLE' . $existsStr . $this->getDriver()->quoteTable($name) . ' (';
$sql .= implode(', ', $columns); $sql .= implode(', ', $columns);
$sql .= ')'; $sql .= ')';
@ -77,7 +81,7 @@ abstract class AbstractUtil {
*/ */
public function deleteTable(string $name): string public function deleteTable(string $name): string
{ {
return 'DROP TABLE IF EXISTS '.$this->getDriver()->quoteTable($name); return 'DROP TABLE IF EXISTS ' . $this->getDriver()->quoteTable($name);
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -85,16 +89,11 @@ abstract class AbstractUtil {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/** /**
* Return an SQL file with the database table structure * Return an SQL file with the database table structure
*
* @abstract
*/ */
abstract public function backupStructure(): string; abstract public function backupStructure(): string;
/** /**
* Return an SQL file with the database data as insert statements * Return an SQL file with the database data as insert statements
*
* @abstract
*/ */
abstract public function backupData(): string; abstract public function backupData(): string;
} }

View File

@ -13,9 +13,9 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers; namespace Query\Drivers;
use InvalidArgumentException;
use PDO; use PDO;
use PDOStatement; use PDOStatement;
@ -36,12 +36,12 @@ use PDOStatement;
* @method rollback(): bool * @method rollback(): bool
* @method setAttribute(int $attribute, $value): bool * @method setAttribute(int $attribute, $value): bool
*/ */
interface DriverInterface /* extends the interface of PDO */ { interface DriverInterface // extends the interface of PDO
{
/** /**
* Constructor/Connection method * Constructor/Connection method
*/ */
public function __construct(string $dsn, string $username=NULL, string $password=NULL, array $driverOptions = []); public function __construct(string $dsn, ?string $username=NULL, ?string $password=NULL, array $driverOptions = []);
/** /**
* Simplifies prepared statements for database queries * Simplifies prepared statements for database queries

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers\Mysql; namespace Query\Drivers\Mysql;
use PDO; use PDO;
@ -22,8 +23,8 @@ use function defined;
/** /**
* MySQL specific class * MySQL specific class
*/ */
class Driver extends AbstractDriver { class Driver extends AbstractDriver
{
/** /**
* Set the backtick as the MySQL escape character * Set the backtick as the MySQL escape character
*/ */
@ -39,7 +40,7 @@ class Driver extends AbstractDriver {
* *
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public function __construct(string $dsn, string $username=NULL, string $password=NULL, array $options=[]) public function __construct(string $dsn, ?string $username=NULL, ?string $password=NULL, array $options=[])
{ {
// Set the charset to UTF-8 // Set the charset to UTF-8
if (defined('\\PDO::MYSQL_ATTR_INIT_COMMAND')) if (defined('\\PDO::MYSQL_ATTR_INIT_COMMAND'))
@ -51,7 +52,7 @@ class Driver extends AbstractDriver {
if ( ! str_contains($dsn, 'mysql')) if ( ! str_contains($dsn, 'mysql'))
{ {
$dsn = 'mysql:'.$dsn; $dsn = 'mysql:' . $dsn;
} }
parent::__construct($dsn, $username, $password, $options); parent::__construct($dsn, $username, $password, $options);
@ -67,7 +68,7 @@ class Driver extends AbstractDriver {
if ( if (
stripos($query, 'insert') !== FALSE stripos($query, 'insert') !== FALSE
&& version_compare($this->getVersion(), '10.5.0', '>=') && version_compare($this->getVersion(), '10.5.0', '>=')
){ ) {
return parent::returning($query, $select); return parent::returning($query, $select);
} }
@ -75,7 +76,7 @@ class Driver extends AbstractDriver {
if ( if (
stripos($query, 'delete') !== FALSE stripos($query, 'delete') !== FALSE
&& version_compare($this->getVersion(), '10.0.5', '>=') && version_compare($this->getVersion(), '10.0.5', '>=')
){ ) {
return parent::returning($query, $select); return parent::returning($query, $select);
} }

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers\Mysql; namespace Query\Drivers\Mysql;
use Query\Drivers\AbstractSQL; use Query\Drivers\AbstractSQL;
@ -20,8 +21,8 @@ use Query\Drivers\AbstractSQL;
/** /**
* MySQL specific SQL * MySQL specific SQL
*/ */
class SQL extends AbstractSQL { class SQL extends AbstractSQL
{
/** /**
* Limit clause * Limit clause
*/ */
@ -29,10 +30,10 @@ class SQL extends AbstractSQL {
{ {
if ( ! is_numeric($offset)) if ( ! is_numeric($offset))
{ {
return $sql." LIMIT {$limit}"; return $sql . " LIMIT {$limit}";
} }
return $sql." LIMIT {$offset}, {$limit}"; return $sql . " LIMIT {$offset}, {$limit}";
} }
/** /**
@ -56,10 +57,9 @@ class SQL extends AbstractSQL {
*/ */
public function dbList(): string public function dbList(): string
{ {
return <<<SQL return <<<'SQL'
SHOW DATABASES WHERE `Database` NOT IN ('information_schema','mysql') SHOW DATABASES WHERE `Database` NOT IN ('information_schema','mysql')
SQL; SQL;
} }
/** /**
@ -82,7 +82,7 @@ SQL;
*/ */
public function systemTableList(): string public function systemTableList(): string
{ {
return <<<SQL return <<<'SQL'
SELECT `TABLE_NAME` FROM `information_schema`.`TABLES` SELECT `TABLE_NAME` FROM `information_schema`.`TABLES`
WHERE `TABLE_SCHEMA`='information_schema' WHERE `TABLE_SCHEMA`='information_schema'
SQL; SQL;

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers\Mysql; namespace Query\Drivers\Mysql;
use PDO; use PDO;
@ -21,8 +22,8 @@ use Query\Drivers\AbstractUtil;
/** /**
* MySQL-specific backup, import and creation methods * MySQL-specific backup, import and creation methods
*/ */
class Util extends AbstractUtil { class Util extends AbstractUtil
{
/** /**
* Create an SQL backup file for the current database's structure * Create an SQL backup file for the current database's structure
*/ */
@ -34,7 +35,7 @@ class Util extends AbstractUtil {
$driver = $this->getDriver(); $driver = $this->getDriver();
$dbs = $driver->getDbs(); $dbs = $driver->getDbs();
foreach($dbs as &$d) foreach ($dbs as &$d)
{ {
// Skip built-in dbs // Skip built-in dbs
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
@ -47,7 +48,7 @@ class Util extends AbstractUtil {
// Get the list of tables // Get the list of tables
$tables = $driver->driverQuery("SHOW TABLES FROM `{$d}`", TRUE); $tables = $driver->driverQuery("SHOW TABLES FROM `{$d}`", TRUE);
foreach($tables as $table) foreach ($tables as $table)
{ {
$array = $driver->driverQuery("SHOW CREATE TABLE `{$d}`.`{$table}`", FALSE); $array = $driver->driverQuery("SHOW CREATE TABLE `{$d}`.`{$table}`", FALSE);
$row = current($array); $row = current($array);
@ -57,7 +58,6 @@ class Util extends AbstractUtil {
continue; continue;
} }
$string[] = $row['Create Table']; $string[] = $row['Create Table'];
} }
} }
@ -74,7 +74,7 @@ class Util extends AbstractUtil {
$tables = $driver->getTables(); $tables = $driver->getTables();
// Filter out the tables you don't want // Filter out the tables you don't want
if( ! empty($exclude)) if ( ! empty($exclude))
{ {
$tables = array_diff($tables, $exclude); $tables = array_diff($tables, $exclude);
} }
@ -82,7 +82,7 @@ class Util extends AbstractUtil {
$outputSql = ''; $outputSql = '';
// Select the rows from each Table // Select the rows from each Table
foreach($tables as $t) foreach ($tables as $t)
{ {
$sql = "SELECT * FROM `{$t}`"; $sql = "SELECT * FROM `{$t}`";
$res = $driver->query($sql); $res = $driver->query($sql);
@ -100,22 +100,22 @@ class Util extends AbstractUtil {
$insertRows = []; $insertRows = [];
// Create the insert statements // Create the insert statements
foreach($rows as $row) foreach ($rows as $row)
{ {
$row = array_values($row); $row = array_values($row);
// Quote strings // Quote strings
$row = array_map(fn ($r) => is_string($r) ? $driver->quote($r) : $r, $row); $row = array_map(static fn ($r) => is_string($r) ? $driver->quote($r) : $r, $row);
$row = array_map('trim', $row); $row = array_map('trim', $row);
$rowString = 'INSERT INTO `'.trim($t).'` (`'.implode('`,`', $columns).'`) VALUES ('.implode(',', $row).');'; $rowString = 'INSERT INTO `' . trim($t) . '` (`' . implode('`,`', $columns) . '`) VALUES (' . implode(',', $row) . ');';
$row = NULL; $row = NULL;
$insertRows[] = $rowString; $insertRows[] = $rowString;
} }
$outputSql .= "\n\n".implode("\n", $insertRows)."\n"; $outputSql .= "\n\n" . implode("\n", $insertRows) . "\n";
} }
return $outputSql; return $outputSql;

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers\Pgsql; namespace Query\Drivers\Pgsql;
use Query\Drivers\AbstractDriver; use Query\Drivers\AbstractDriver;
@ -20,18 +21,18 @@ use Query\Drivers\AbstractDriver;
/** /**
* PostgreSQL specific class * PostgreSQL specific class
*/ */
class Driver extends AbstractDriver { class Driver extends AbstractDriver
{
/** /**
* Connect to a PosgreSQL database * Connect to a PosgreSQL database
* *
* @codeCoverageIgnore * @codeCoverageIgnore
*/ */
public function __construct(string $dsn, string $username=NULL, string $password=NULL, array $options=[]) public function __construct(string $dsn, ?string $username=NULL, ?string $password=NULL, array $options=[])
{ {
if ( ! str_contains($dsn, 'pgsql')) if ( ! str_contains($dsn, 'pgsql'))
{ {
$dsn = 'pgsql:'.$dsn; $dsn = 'pgsql:' . $dsn;
} }
parent::__construct($dsn, $username, $password, $options); parent::__construct($dsn, $username, $password, $options);
@ -63,9 +64,9 @@ SQL;
$keys = parent::getFks($table); $keys = parent::getFks($table);
foreach($keys as &$key) foreach ($keys as &$key)
{ {
foreach(['update', 'delete'] AS $type) foreach (['update', 'delete'] as $type)
{ {
if ( ! isset($valueMap[$key[$type]])) if ( ! isset($valueMap[$key[$type]]))
{ {

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers\Pgsql; namespace Query\Drivers\Pgsql;
use Query\Drivers\AbstractSQL; use Query\Drivers\AbstractSQL;
@ -20,8 +21,8 @@ use Query\Drivers\AbstractSQL;
/** /**
* PostgreSQL specific SQL * PostgreSQL specific SQL
*/ */
class SQL extends AbstractSQL { class SQL extends AbstractSQL
{
/** /**
* Get the query plan for the sql query * Get the query plan for the sql query
*/ */
@ -43,7 +44,7 @@ class SQL extends AbstractSQL {
*/ */
public function dbList(): string public function dbList(): string
{ {
return <<<SQL return <<<'SQL'
SELECT "datname" FROM "pg_database" SELECT "datname" FROM "pg_database"
WHERE "datname" NOT IN ('template0','template1') WHERE "datname" NOT IN ('template0','template1')
ORDER BY "datname" ASC ORDER BY "datname" ASC
@ -55,7 +56,7 @@ SQL;
*/ */
public function tableList(): string public function tableList(): string
{ {
return <<<SQL return <<<'SQL'
SELECT "table_name" SELECT "table_name"
FROM "information_schema"."tables" FROM "information_schema"."tables"
WHERE "table_type" = 'BASE TABLE' WHERE "table_type" = 'BASE TABLE'
@ -69,7 +70,7 @@ SQL;
*/ */
public function systemTableList(): string public function systemTableList(): string
{ {
return <<<SQL return <<<'SQL'
SELECT "table_name" SELECT "table_name"
FROM "information_schema"."tables" FROM "information_schema"."tables"
WHERE "table_type" = 'BASE TABLE' WHERE "table_type" = 'BASE TABLE'
@ -83,7 +84,7 @@ SQL;
*/ */
public function viewList(): string public function viewList(): string
{ {
return <<<SQL return <<<'SQL'
SELECT "viewname" FROM "pg_views" SELECT "viewname" FROM "pg_views"
WHERE "schemaname" NOT IN WHERE "schemaname" NOT IN
('pg_catalog', 'information_schema') ('pg_catalog', 'information_schema')
@ -97,7 +98,7 @@ SQL;
*/ */
public function triggerList(): string public function triggerList(): string
{ {
return <<<SQL return <<<'SQL'
SELECT * SELECT *
FROM "information_schema"."triggers" FROM "information_schema"."triggers"
WHERE "trigger_schema" NOT IN WHERE "trigger_schema" NOT IN
@ -118,7 +119,7 @@ SQL;
*/ */
public function procedureList(): string public function procedureList(): string
{ {
return <<<SQL return <<<'SQL'
SELECT "routine_name" SELECT "routine_name"
FROM "information_schema"."routines" FROM "information_schema"."routines"
WHERE "specific_schema" NOT IN WHERE "specific_schema" NOT IN
@ -132,7 +133,7 @@ SQL;
*/ */
public function sequenceList(): string public function sequenceList(): string
{ {
return <<<SQL return <<<'SQL'
SELECT "c"."relname" SELECT "c"."relname"
FROM "pg_class" "c" FROM "pg_class" "c"
WHERE "c"."relkind" = 'S' WHERE "c"."relkind" = 'S'
@ -164,7 +165,7 @@ SQL;
*/ */
public function typeList(): string public function typeList(): string
{ {
return <<<SQL return <<<'SQL'
SELECT "typname" FROM "pg_catalog"."pg_type" SELECT "typname" FROM "pg_catalog"."pg_type"
WHERE "typname" !~ '^pg_|_' WHERE "typname" !~ '^pg_|_'
AND "typtype" = 'b' AND "typtype" = 'b'

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers\Pgsql; namespace Query\Drivers\Pgsql;
use PDO; use PDO;
@ -21,8 +22,8 @@ use Query\Drivers\AbstractUtil;
/** /**
* Postgres-specific backup, import and creation methods * Postgres-specific backup, import and creation methods
*/ */
class Util extends AbstractUtil { class Util extends AbstractUtil
{
/** /**
* Create an SQL backup file for the current database's structure * Create an SQL backup file for the current database's structure
*/ */
@ -40,7 +41,7 @@ class Util extends AbstractUtil {
$tables = $this->getDriver()->getTables(); $tables = $this->getDriver()->getTables();
// Filter out the tables you don't want // Filter out the tables you don't want
if( ! empty($exclude)) if ( ! empty($exclude))
{ {
$tables = array_diff($tables, $exclude); $tables = array_diff($tables, $exclude);
} }
@ -48,9 +49,9 @@ class Util extends AbstractUtil {
$outputSql = ''; $outputSql = '';
// Get the data for each object // Get the data for each object
foreach($tables as $t) foreach ($tables as $t)
{ {
$sql = 'SELECT * FROM "'.trim($t).'"'; $sql = 'SELECT * FROM "' . trim($t) . '"';
$res = $this->getDriver()->query($sql); $res = $this->getDriver()->query($sql);
$objRes = $res->fetchAll(PDO::FETCH_ASSOC); $objRes = $res->fetchAll(PDO::FETCH_ASSOC);
@ -68,7 +69,7 @@ class Util extends AbstractUtil {
$insertRows = []; $insertRows = [];
// Create the insert statements // Create the insert statements
foreach($objRes as $row) foreach ($objRes as $row)
{ {
$row = array_values($row); $row = array_values($row);
@ -76,8 +77,7 @@ class Util extends AbstractUtil {
$row = array_map([$this->getDriver(), 'quote'], $row); $row = array_map([$this->getDriver(), 'quote'], $row);
$row = array_map('trim', $row); $row = array_map('trim', $row);
$rowString = 'INSERT INTO "' . trim($t) . '" ("' . implode('","', $columns) . '") VALUES (' . implode(',', $row) . ');';
$rowString = 'INSERT INTO "'.trim($t).'" ("'.implode('","', $columns).'") VALUES ('.implode(',', $row).');';
$row = NULL; $row = NULL;
@ -86,7 +86,7 @@ class Util extends AbstractUtil {
$objRes = NULL; $objRes = NULL;
$outputSql .= "\n\n".implode("\n", $insertRows)."\n"; $outputSql .= "\n\n" . implode("\n", $insertRows) . "\n";
} }
return $outputSql; return $outputSql;

View File

@ -13,13 +13,14 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers; namespace Query\Drivers;
/** /**
* Interface for database-specific syntax subclasses * Interface for database-specific syntax subclasses
*/ */
interface SQLInterface { interface SQLInterface
{
/** /**
* Get database specific sql for limit clause * Get database specific sql for limit clause
*/ */

View File

@ -13,18 +13,20 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers\Sqlite; namespace Query\Drivers\Sqlite;
use function is_array;
use InvalidArgumentException; use InvalidArgumentException;
use PDO; use PDO;
use Query\Drivers\AbstractDriver; use Query\Drivers\AbstractDriver;
use function is_array;
/** /**
* SQLite specific class * SQLite specific class
*/ */
class Driver extends AbstractDriver { class Driver extends AbstractDriver
{
/** /**
* SQLite has a truncate optimization, * SQLite has a truncate optimization,
* but no support for the actual keyword * but no support for the actual keyword
@ -34,7 +36,7 @@ class Driver extends AbstractDriver {
/** /**
* Open SQLite Database * Open SQLite Database
*/ */
public function __construct(string $dsn, string $user=NULL, string $pass=NULL, array $driverOptions=[]) public function __construct(string $dsn, ?string $user=NULL, ?string $pass=NULL, array $driverOptions=[])
{ {
if ( ! str_contains($dsn, 'sqlite:')) if ( ! str_contains($dsn, 'sqlite:'))
{ {
@ -59,6 +61,7 @@ class Driver extends AbstractDriver {
{ {
$sql = $this->getSql()->tableList(); $sql = $this->getSql()->tableList();
$res = $this->query($sql); $res = $this->query($sql);
return dbFilter($res->fetchAll(PDO::FETCH_ASSOC), 'name'); return dbFilter($res->fetchAll(PDO::FETCH_ASSOC), 'name');
} }
@ -69,14 +72,14 @@ class Driver extends AbstractDriver {
{ {
$returnRows = []; $returnRows = [];
foreach(parent::getFks($table) as $row) foreach (parent::getFks($table) as $row)
{ {
$returnRows[] = [ $returnRows[] = [
'child_column' => $row['from'], 'child_column' => $row['from'],
'parent_table' => $row['table'], 'parent_table' => $row['table'],
'parent_column' => $row['to'], 'parent_column' => $row['to'],
'update' => $row['on_update'], 'update' => $row['on_update'],
'delete' => $row['on_delete'] 'delete' => $row['on_delete'],
]; ];
} }
@ -87,7 +90,7 @@ class Driver extends AbstractDriver {
* Create sql for batch insert * Create sql for batch insert
* *
* @codeCoverageIgnore * @codeCoverageIgnore
* @return array[]|string[]|null[] * @return array[]|null[]|string[]
*/ */
public function insertBatch(string $table, array $data=[]): array public function insertBatch(string $table, array $data=[]): array
{ {
@ -115,13 +118,14 @@ class Driver extends AbstractDriver {
// Create a key-value mapping for each field // Create a key-value mapping for each field
$first = array_shift($data); $first = array_shift($data);
$cols = []; $cols = [];
foreach($first as $colName => $datum)
foreach ($first as $colName => $datum)
{ {
$cols[] = $this->_quote($datum) . ' AS ' . $this->quoteIdent($colName); $cols[] = $this->_quote($datum) . ' AS ' . $this->quoteIdent($colName);
} }
$sql .= 'SELECT ' . implode(', ', $cols) . "\n"; $sql .= 'SELECT ' . implode(', ', $cols) . "\n";
foreach($data as $union) foreach ($data as $union)
{ {
$vals = array_map([$this, 'quote'], $union); $vals = array_map([$this, 'quote'], $union);
$sql .= 'UNION SELECT ' . implode(',', $vals) . "\n"; $sql .= 'UNION SELECT ' . implode(',', $vals) . "\n";

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers\Sqlite; namespace Query\Drivers\Sqlite;
use Query\Drivers\AbstractSQL; use Query\Drivers\AbstractSQL;
@ -21,8 +22,8 @@ use Query\Exception\NotImplementedException;
/** /**
* SQLite Specific SQL * SQLite Specific SQL
*/ */
class SQL extends AbstractSQL { class SQL extends AbstractSQL
{
/** /**
* Get the query plan for the sql query * Get the query plan for the sql query
*/ */
@ -53,7 +54,7 @@ class SQL extends AbstractSQL {
*/ */
public function tableList(): string public function tableList(): string
{ {
return <<<SQL return <<<'SQL'
SELECT "name" FROM ( SELECT "name" FROM (
SELECT * FROM "sqlite_master" UNION ALL SELECT * FROM "sqlite_master" UNION ALL
SELECT * FROM "sqlite_temp_master" SELECT * FROM "sqlite_temp_master"
@ -74,7 +75,7 @@ SQL;
return [ return [
'sqlite_master', 'sqlite_master',
'sqlite_temp_master', 'sqlite_temp_master',
'sqlite_sequence' 'sqlite_sequence',
]; ];
} }
@ -83,7 +84,7 @@ SQL;
*/ */
public function viewList(): string public function viewList(): string
{ {
return <<<SQL return <<<'SQL'
SELECT "name" FROM "sqlite_master" WHERE "type" = 'view' SELECT "name" FROM "sqlite_master" WHERE "type" = 'view'
SQL; SQL;
} }
@ -93,7 +94,7 @@ SQL;
*/ */
public function triggerList(): string public function triggerList(): string
{ {
return <<<SQL return <<<'SQL'
SELECT "name" FROM "sqlite_master" WHERE "type"='trigger' SELECT "name" FROM "sqlite_master" WHERE "type"='trigger'
SQL; SQL;
} }
@ -157,7 +158,6 @@ SQL;
SQL; SQL;
} }
/** /**
* Get the list of indexes for the current table * Get the list of indexes for the current table
*/ */

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Drivers\Sqlite; namespace Query\Drivers\Sqlite;
use PDO; use PDO;
@ -21,8 +22,8 @@ use Query\Drivers\AbstractUtil;
/** /**
* SQLite-specific backup, import and creation methods * SQLite-specific backup, import and creation methods
*/ */
class Util extends AbstractUtil { class Util extends AbstractUtil
{
/** /**
* Create an SQL backup file for the current database's data * Create an SQL backup file for the current database's data
*/ */
@ -33,9 +34,9 @@ class Util extends AbstractUtil {
FROM "sqlite_master" FROM "sqlite_master"
WHERE "type"=\'table\''; WHERE "type"=\'table\'';
if( ! empty($excluded)) if ( ! empty($excluded))
{ {
$sql .= " AND \"name\" NOT IN('".implode("','", $excluded)."')"; $sql .= " AND \"name\" NOT IN('" . implode("','", $excluded) . "')";
} }
$res = $this->getDriver()->query($sql); $res = $this->getDriver()->query($sql);
@ -46,9 +47,9 @@ class Util extends AbstractUtil {
$outputSql = ''; $outputSql = '';
// Get the data for each object // Get the data for each object
foreach($result as $r) foreach ($result as $r)
{ {
$sql = 'SELECT * FROM "'.$r['name'].'"'; $sql = 'SELECT * FROM "' . $r['name'] . '"';
$res = $this->getDriver()->query($sql); $res = $this->getDriver()->query($sql);
$objRes = $res->fetchAll(PDO::FETCH_ASSOC); $objRes = $res->fetchAll(PDO::FETCH_ASSOC);
@ -66,7 +67,7 @@ class Util extends AbstractUtil {
$insertRows = []; $insertRows = [];
// Create the insert statements // Create the insert statements
foreach($objRes as $row) foreach ($objRes as $row)
{ {
$row = array_values($row); $row = array_values($row);
@ -78,7 +79,7 @@ class Util extends AbstractUtil {
: $this->getDriver()->quote($row[$i]); : $this->getDriver()->quote($row[$i]);
} }
$rowString = 'INSERT INTO "'.$r['name'].'" ("'.implode('","', $columns).'") VALUES ('.implode(',', $row).');'; $rowString = 'INSERT INTO "' . $r['name'] . '" ("' . implode('","', $columns) . '") VALUES (' . implode(',', $row) . ');';
unset($row); unset($row);
@ -87,7 +88,7 @@ class Util extends AbstractUtil {
unset($objRes); unset($objRes);
$outputSql .= "\n\n".implode("\n", $insertRows); $outputSql .= "\n\n" . implode("\n", $insertRows);
} }
return $outputSql; return $outputSql;
@ -105,7 +106,7 @@ class Util extends AbstractUtil {
$sqlArray = []; $sqlArray = [];
foreach($result as $r) foreach ($result as $r)
{ {
$sqlArray[] = $r['sql']; $sqlArray[] = $r['sql'];
} }

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Exception; namespace Query\Exception;
use InvalidArgumentException; use InvalidArgumentException;
@ -20,5 +21,6 @@ use InvalidArgumentException;
/** /**
* Generic exception for bad drivers * Generic exception for bad drivers
*/ */
class BadDBDriverException extends InvalidArgumentException { class BadDBDriverException extends InvalidArgumentException
{
} }

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Exception; namespace Query\Exception;
use InvalidArgumentException; use InvalidArgumentException;
@ -20,5 +21,6 @@ use InvalidArgumentException;
/** /**
* Exception for missing database connection * Exception for missing database connection
*/ */
class NonExistentConnectionException extends InvalidArgumentException { class NonExistentConnectionException extends InvalidArgumentException
{
} }

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query\Exception; namespace Query\Exception;
use BadMethodCallException; use BadMethodCallException;
@ -20,5 +21,6 @@ use BadMethodCallException;
/** /**
* Exception for non-implemented method * Exception for non-implemented method
*/ */
class NotImplementedException extends BadMethodCallException{ class NotImplementedException extends BadMethodCallException
{
} }

View File

@ -13,12 +13,14 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query; namespace Query;
/** /**
* Enum of join types * Enum of join types
*/ */
enum JoinType: string { enum JoinType: string
{
case CROSS = 'cross'; case CROSS = 'cross';
case INNER = 'inner'; case INNER = 'inner';
case OUTER = 'outer'; case OUTER = 'outer';
@ -35,4 +37,3 @@ enum JoinType: string {
return self::from($val); return self::from($val);
} }
} }

View File

@ -13,12 +13,14 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query; namespace Query;
/** /**
* 'Enum' of join types * 'Enum' of join types
*/ */
enum LikeType: string { enum LikeType: string
{
case BEFORE = 'before'; case BEFORE = 'before';
case AFTER = 'after'; case AFTER = 'after';
case BOTH = 'both'; case BOTH = 'both';

View File

@ -13,12 +13,14 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query; namespace Query;
/** /**
* Enum of query map types * Enum of query map types
*/ */
enum MapType: string { enum MapType: string
{
case GROUP_END = 'group_end'; case GROUP_END = 'group_end';
case GROUP_START = 'group_start'; case GROUP_START = 'group_start';
case JOIN = 'join'; case JOIN = 'join';

View File

@ -13,18 +13,20 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query; namespace Query;
use PDOStatement;
use function is_array; use function is_array;
use function is_int; use function is_int;
use function mb_trim;
use PDOStatement; use function mb_trim;
/** /**
* Convenience class for creating sql queries * Convenience class for creating sql queries
*/ */
class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface { class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface
{
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// ! Select Queries // ! Select Queries
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -69,48 +71,52 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
/** /**
* Selects the maximum value of a field from a query * Selects the maximum value of a field from a query
* *
* @param string|bool $as * @param bool|string $as
*/ */
public function selectMax(string $field, $as=FALSE): self public function selectMax(string $field, $as=FALSE): self
{ {
// Create the select string // Create the select string
$this->state->appendSelectString(' MAX'.$this->_select($field, $as)); $this->state->appendSelectString(' MAX' . $this->_select($field, $as));
return $this; return $this;
} }
/** /**
* Selects the minimum value of a field from a query * Selects the minimum value of a field from a query
* *
* @param string|bool $as * @param bool|string $as
*/ */
public function selectMin(string $field, $as=FALSE): self public function selectMin(string $field, $as=FALSE): self
{ {
// Create the select string // Create the select string
$this->state->appendSelectString(' MIN'.$this->_select($field, $as)); $this->state->appendSelectString(' MIN' . $this->_select($field, $as));
return $this; return $this;
} }
/** /**
* Selects the average value of a field from a query * Selects the average value of a field from a query
* *
* @param string|bool $as * @param bool|string $as
*/ */
public function selectAvg(string $field, $as=FALSE): self public function selectAvg(string $field, $as=FALSE): self
{ {
// Create the select string // Create the select string
$this->state->appendSelectString(' AVG'.$this->_select($field, $as)); $this->state->appendSelectString(' AVG' . $this->_select($field, $as));
return $this; return $this;
} }
/** /**
* Selects the sum of a field from a query * Selects the sum of a field from a query
* *
* @param string|bool $as * @param bool|string $as
*/ */
public function selectSum(string $field, $as=FALSE): self public function selectSum(string $field, $as=FALSE): self
{ {
// Create the select string // Create the select string
$this->state->appendSelectString(' SUM'.$this->_select($field, $as)); $this->state->appendSelectString(' SUM' . $this->_select($field, $as));
return $this; return $this;
} }
@ -139,6 +145,7 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
{ {
// Prepend the keyword to the select string // Prepend the keyword to the select string
$this->state->setSelectString(' DISTINCT' . $this->state->getSelectString()); $this->state->setSelectString(' DISTINCT' . $this->state->getSelectString());
return $this; return $this;
} }
@ -148,6 +155,7 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
public function explain(): self public function explain(): self
{ {
$this->explain = TRUE; $this->explain = TRUE;
return $this; return $this;
} }
@ -155,8 +163,6 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
* Specify the database table to select from * Specify the database table to select from
* *
* Alias of `from` method to better match CodeIgniter 4 * Alias of `from` method to better match CodeIgniter 4
*
* @param string $tableName
*/ */
public function table(string $tableName): self public function table(string $tableName): self
{ {
@ -383,15 +389,15 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
$orderClauses = []; $orderClauses = [];
// Flatten key/val pairs into an array of space-separated pairs // Flatten key/val pairs into an array of space-separated pairs
foreach($this->state->getOrderArray() as $k => $v) foreach ($this->state->getOrderArray() as $k => $v)
{ {
$orderClauses[] = $k . ' ' . strtoupper($v); $orderClauses[] = $k . ' ' . strtoupper($v);
} }
// Set the final string // Set the final string
$orderString = isset($rand) $orderString = isset($rand)
? "\nORDER BY".$rand ? "\nORDER BY" . $rand
: "\nORDER BY ".implode(', ', $orderClauses); : "\nORDER BY " . implode(', ', $orderClauses);
$this->state->setOrderString($orderString); $this->state->setOrderString($orderString);
@ -512,8 +518,9 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
*/ */
public function countAll(string $table): int public function countAll(string $table): int
{ {
$sql = 'SELECT * FROM '.$this->driver->quoteTable($table); $sql = 'SELECT * FROM ' . $this->driver->quoteTable($table);
$res = $this->driver->query($sql); $res = $this->driver->query($sql);
return (int) (is_countable($res->fetchAll()) ? count($res->fetchAll()) : 0); return (int) (is_countable($res->fetchAll()) ? count($res->fetchAll()) : 0);
} }
@ -589,6 +596,7 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
[$sql, $data, $affectedRows] = $this->driver->updateBatch($table, $data, $where); [$sql, $data, $affectedRows] = $this->driver->updateBatch($table, $data, $where);
$this->_run(QueryType::UPDATE_BATCH, $table, $sql, $data); $this->_run(QueryType::UPDATE_BATCH, $table, $sql, $data);
return $affectedRows; return $affectedRows;
} }

View File

@ -13,14 +13,16 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query; namespace Query;
use function regexInArray;
use BadMethodCallException; use BadMethodCallException;
use PDO; use PDO;
use PDOStatement; use PDOStatement;
use Query\Drivers\DriverInterface; use Query\Drivers\DriverInterface;
use function is_string;
use function regexInArray;
/** /**
* @method affectedRows(): int * @method affectedRows(): int
@ -56,8 +58,8 @@ use Query\Drivers\DriverInterface;
* @method setTablePrefix(string $prefix): void * @method setTablePrefix(string $prefix): void
* @method truncate(string $table): PDOStatement * @method truncate(string $table): PDOStatement
*/ */
class QueryBuilderBase { class QueryBuilderBase
{
/** /**
* Convenience property for connection management * Convenience property for connection management
*/ */
@ -67,7 +69,7 @@ class QueryBuilderBase {
* List of queries executed * List of queries executed
*/ */
public array $queries = [ public array $queries = [
'total_time' => 0 'total_time' => 0,
]; ];
/** /**
@ -110,8 +112,8 @@ class QueryBuilderBase {
* Calls a function further down the inheritance chain. * Calls a function further down the inheritance chain.
* 'Implements' methods on the driver object * 'Implements' methods on the driver object
* *
* @return mixed
* @throws BadMethodCallException * @throws BadMethodCallException
* @return mixed
*/ */
public function __call(string $name, array $params) public function __call(string $name, array $params)
{ {
@ -141,7 +143,7 @@ class QueryBuilderBase {
// Escape the identifiers // Escape the identifiers
$field = $this->driver->quoteIdent($field); $field = $this->driver->quoteIdent($field);
if ( ! \is_string($as)) if ( ! is_string($as))
{ {
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
return $field; return $field;
@ -149,6 +151,7 @@ class QueryBuilderBase {
} }
$as = $this->driver->quoteIdent($as); $as = $this->driver->quoteIdent($as);
return "({$field}) AS {$as} "; return "({$field}) AS {$as} ";
} }
@ -224,7 +227,7 @@ class QueryBuilderBase {
'conjunction' => empty($this->state->getHavingMap()) 'conjunction' => empty($this->state->getHavingMap())
? ' HAVING ' ? ' HAVING '
: " {$conj} ", : " {$conj} ",
'string' => $item 'string' => $item,
]); ]);
} }
@ -242,7 +245,8 @@ class QueryBuilderBase {
if (is_scalar($key)) if (is_scalar($key))
{ {
$pairs[$key] = $val; $pairs[$key] = $val;
} else }
else
{ {
$pairs = $key; $pairs = $key;
} }
@ -300,8 +304,6 @@ class QueryBuilderBase {
/** /**
* Simplify where_in methods * Simplify where_in methods
* *
* @param mixed $key
* @param mixed $val
* @param string $in - The (not) in fragment * @param string $in - The (not) in fragment
* @param string $conj - The where in conjunction * @param string $conj - The where in conjunction
*/ */
@ -321,10 +323,8 @@ class QueryBuilderBase {
/** /**
* Executes the compiled query * Executes the compiled query
*
* @param array|null $vals
*/ */
protected function _run(QueryType $type, string $table, string $sql = NULL, array $vals = NULL, bool $reset = TRUE): PDOStatement protected function _run(QueryType $type, string $table, ?string $sql = NULL, ?array $vals = NULL, bool $reset = TRUE): PDOStatement
{ {
if ($sql === NULL) if ($sql === NULL)
{ {
@ -346,7 +346,7 @@ class QueryBuilderBase {
$totalTime = number_format($endTime - $startTime, 5); $totalTime = number_format($endTime - $startTime, 5);
// Add this query to the list of executed queries // Add this query to the list of executed queries
$this->_appendQuery($vals, $sql, (int)$totalTime); $this->_appendQuery($vals, $sql, (int) $totalTime);
// Reset class state for next query // Reset class state for next query
if ($reset) if ($reset)
@ -368,7 +368,7 @@ class QueryBuilderBase {
// Quote string values // Quote string values
foreach ($evals as &$v) foreach ($evals as &$v)
{ {
$v = ( is_numeric($v)) $v = (is_numeric($v))
? $v ? $v
: htmlentities($this->driver->quote($v), ENT_NOQUOTES, 'utf-8'); : htmlentities($this->driver->quote($v), ENT_NOQUOTES, 'utf-8');
} }
@ -381,7 +381,7 @@ class QueryBuilderBase {
// Add the interpreted query to the list of executed queries // Add the interpreted query to the list of executed queries
$this->queries[] = [ $this->queries[] = [
'time' => $totalTime, 'time' => $totalTime,
'sql' => sprintf(...$evals) 'sql' => sprintf(...$evals),
]; ];
$this->queries['total_time'] += $totalTime; $this->queries['total_time'] += $totalTime;
@ -398,6 +398,7 @@ class QueryBuilderBase {
protected function _compileType(QueryType $type = QueryType::SELECT, string $table = ''): string protected function _compileType(QueryType $type = QueryType::SELECT, string $table = ''): string
{ {
$setArrayKeys = $this->state->getSetArrayKeys(); $setArrayKeys = $this->state->getSetArrayKeys();
switch ($type) switch ($type)
{ {
case QueryType::INSERT: case QueryType::INSERT:
@ -454,7 +455,7 @@ class QueryBuilderBase {
// Set each type of subclause // Set each type of subclause
foreach ($clauses as $clause) foreach ($clauses as $clause)
{ {
$func = 'get' . ucFirst($clause); $func = 'get' . ucfirst($clause);
$param = $this->state->$func(); $param = $this->state->$func();
if (is_array($param)) if (is_array($param))
{ {
@ -462,7 +463,8 @@ class QueryBuilderBase {
{ {
$sql .= $q['conjunction'] . $q['string']; $sql .= $q['conjunction'] . $q['string'];
} }
} else }
else
{ {
$sql .= $param; $sql .= $param;
} }

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query; namespace Query;
use PDO; use PDO;
@ -57,8 +58,8 @@ use PDOStatement;
* @method setTablePrefix(string $prefix): void * @method setTablePrefix(string $prefix): void
* @method truncate(string $table): PDOStatement * @method truncate(string $table): PDOStatement
*/ */
interface QueryBuilderInterface { interface QueryBuilderInterface
{
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// ! Select Queries // ! Select Queries
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -70,28 +71,28 @@ interface QueryBuilderInterface {
/** /**
* Selects the maximum value of a field from a query * Selects the maximum value of a field from a query
* *
* @param string|bool $as * @param bool|string $as
*/ */
public function selectMax(string $field, $as=FALSE): self; public function selectMax(string $field, $as=FALSE): self;
/** /**
* Selects the minimum value of a field from a query * Selects the minimum value of a field from a query
* *
* @param string|bool $as * @param bool|string $as
*/ */
public function selectMin(string $field, $as=FALSE): self; public function selectMin(string $field, $as=FALSE): self;
/** /**
* Selects the average value of a field from a query * Selects the average value of a field from a query
* *
* @param string|bool $as * @param bool|string $as
*/ */
public function selectAvg(string $field, $as=FALSE): self; public function selectAvg(string $field, $as=FALSE): self;
/** /**
* Selects the sum of a field from a query * Selects the sum of a field from a query
* *
* @param string|bool $as * @param bool|string $as
*/ */
public function selectSum(string $field, $as=FALSE): self; public function selectSum(string $field, $as=FALSE): self;
@ -109,8 +110,6 @@ interface QueryBuilderInterface {
* Specify the database table to select from * Specify the database table to select from
* *
* Alias of `from` method to better match CodeIgniter 4 * Alias of `from` method to better match CodeIgniter 4
*
* @param string $tableName
*/ */
public function table(string $tableName): self; public function table(string $tableName): self;
@ -124,29 +123,21 @@ interface QueryBuilderInterface {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/** /**
* Creates a Like clause in the sql statement * Creates a Like clause in the sql statement
*
* @param mixed $values
*/ */
public function like(string $field, mixed $values, LikeType|string $pos=LikeType::BOTH): self; public function like(string $field, mixed $values, LikeType|string $pos=LikeType::BOTH): self;
/** /**
* Generates an OR Like clause * Generates an OR Like clause
*
* @param mixed $values
*/ */
public function orLike(string $field, mixed $values, LikeType|string $pos=LikeType::BOTH): self; public function orLike(string $field, mixed $values, LikeType|string $pos=LikeType::BOTH): self;
/** /**
* Generates a NOT LIKE clause * Generates a NOT LIKE clause
*
* @param mixed $values
*/ */
public function notLike(string $field, mixed $values, LikeType|string $pos=LikeType::BOTH): self; public function notLike(string $field, mixed $values, LikeType|string $pos=LikeType::BOTH): self;
/** /**
* Generates a OR NOT LIKE clause * Generates a OR NOT LIKE clause
*
* @param mixed $values
*/ */
public function orNotLike(string $field, mixed $values, LikeType|string $pos=LikeType::BOTH): self; public function orNotLike(string $field, mixed $values, LikeType|string $pos=LikeType::BOTH): self;
@ -155,17 +146,11 @@ interface QueryBuilderInterface {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
/** /**
* Generates a 'Having' clause * Generates a 'Having' clause
*
* @param mixed $key
* @param mixed $values
*/ */
public function having(mixed $key, mixed $values=[]): self; public function having(mixed $key, mixed $values=[]): self;
/** /**
* Generates a 'Having' clause prefixed with 'OR' * Generates a 'Having' clause prefixed with 'OR'
*
* @param mixed $key
* @param mixed $values
*/ */
public function orHaving(mixed $key, mixed $values=[]): self; public function orHaving(mixed $key, mixed $values=[]): self;
@ -176,9 +161,6 @@ interface QueryBuilderInterface {
* Specify condition(s) in the where clause of a query * Specify condition(s) in the where clause of a query
* Note: this function works with key / value, or a * Note: this function works with key / value, or a
* passed array with key / value pairs * passed array with key / value pairs
*
* @param mixed $key
* @param mixed $values
*/ */
public function where(mixed $key, mixed $values=[]): self; public function where(mixed $key, mixed $values=[]): self;
@ -186,39 +168,26 @@ interface QueryBuilderInterface {
* Where clause prefixed with "OR" * Where clause prefixed with "OR"
* *
* @param string $key * @param string $key
* @param mixed $values
*/ */
public function orWhere(mixed $key, mixed $values=[]): self; public function orWhere(mixed $key, mixed $values=[]): self;
/** /**
* Where clause with 'IN' statement * Where clause with 'IN' statement
*
* @param string $field
* @param mixed $values
*/ */
public function whereIn(string $field, mixed $values=[]): self; public function whereIn(string $field, mixed $values=[]): self;
/** /**
* Where in statement prefixed with "or" * Where in statement prefixed with "or"
*
* @param string $field
* @param mixed $values
*/ */
public function orWhereIn(string $field, mixed $values=[]): self; public function orWhereIn(string $field, mixed $values=[]): self;
/** /**
* WHERE NOT IN (FOO) clause * WHERE NOT IN (FOO) clause
*
* @param string $field
* @param mixed $values
*/ */
public function whereNotIn(string $field, mixed $values=[]): self; public function whereNotIn(string $field, mixed $values=[]): self;
/** /**
* OR WHERE NOT IN (FOO) clause * OR WHERE NOT IN (FOO) clause
*
* @param string $field
* @param mixed $values
*/ */
public function orWhereNotIn(string $field, mixed $values=[]): self; public function orWhereNotIn(string $field, mixed $values=[]): self;
@ -228,7 +197,6 @@ interface QueryBuilderInterface {
/** /**
* Sets values for inserts / updates / deletes * Sets values for inserts / updates / deletes
* *
* @param mixed $key
* @param mixed $values * @param mixed $values
*/ */
public function set(mixed $key, mixed $values = NULL): self; public function set(mixed $key, mixed $values = NULL): self;
@ -240,8 +208,6 @@ interface QueryBuilderInterface {
/** /**
* Group the results by the selected field(s) * Group the results by the selected field(s)
*
* @param mixed $field
*/ */
public function groupBy(mixed $field): self; public function groupBy(mixed $field): self;
@ -297,8 +263,6 @@ interface QueryBuilderInterface {
/** /**
* Convenience method for get() with a where clause * Convenience method for get() with a where clause
*
* @param array $where
*/ */
public function getWhere(string $table, array $where=[], ?int $limit=NULL, ?int $offset=NULL): PDOStatement; public function getWhere(string $table, array $where=[], ?int $limit=NULL, ?int $offset=NULL): PDOStatement;
@ -317,8 +281,6 @@ interface QueryBuilderInterface {
/** /**
* Creates an insert clause, and executes it * Creates an insert clause, and executes it
*
* @param mixed $data
*/ */
public function insert(string $table, mixed $data=[]): PDOStatement; public function insert(string $table, mixed $data=[]): PDOStatement;
@ -331,8 +293,6 @@ interface QueryBuilderInterface {
/** /**
* Creates an update clause, and executes it * Creates an update clause, and executes it
*
* @param mixed $data
*/ */
public function update(string $table, mixed $data=[]): PDOStatement; public function update(string $table, mixed $data=[]): PDOStatement;
@ -348,8 +308,6 @@ interface QueryBuilderInterface {
/** /**
* Deletes data from a table * Deletes data from a table
*
* @param mixed $where
*/ */
public function delete(string $table, mixed $where=''): PDOStatement; public function delete(string $table, mixed $where=''): PDOStatement;

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query; namespace Query;
use Query\Drivers\DriverInterface; use Query\Drivers\DriverInterface;
@ -20,17 +21,8 @@ use Query\Drivers\DriverInterface;
/** /**
* Utility Class to parse sql clauses for properly escaping identifiers * Utility Class to parse sql clauses for properly escaping identifiers
*/ */
class QueryParser { class QueryParser
{
/**
* Regex patterns for various syntax components
*/
private array $matchPatterns = [
'function' => '([a-zA-Z0-9_]+\((.*?)\))',
'identifier' => '([a-zA-Z0-9_-]+\.?)+',
'operator' => '=|AND|&&?|~|\|\|?|\^|/|>=?|<=?|-|%|OR|\+|NOT|\!=?|<>|XOR'
];
/** /**
* Regex matches * Regex matches
*/ */
@ -41,6 +33,15 @@ class QueryParser {
'combined' => [], 'combined' => [],
]; ];
/**
* Regex patterns for various syntax components
*/
private array $matchPatterns = [
'function' => '([a-zA-Z0-9_]+\((.*?)\))',
'identifier' => '([a-zA-Z0-9_-]+\.?)+',
'operator' => '=|AND|&&?|~|\|\|?|\^|/|>=?|<=?|-|%|OR|\+|NOT|\!=?|<>|XOR',
];
/** /**
* Constructor/entry point into parser * Constructor/entry point into parser
*/ */
@ -56,12 +57,12 @@ class QueryParser {
public function parseJoin(string $sql): array public function parseJoin(string $sql): array
{ {
// Get sql clause components // Get sql clause components
preg_match_all('`'.$this->matchPatterns['function'].'`', $sql, $this->matches['functions'], PREG_SET_ORDER); preg_match_all('`' . $this->matchPatterns['function'] . '`', $sql, $this->matches['functions'], PREG_SET_ORDER);
preg_match_all('`'.$this->matchPatterns['identifier'].'`', $sql, $this->matches['identifiers'], PREG_SET_ORDER); preg_match_all('`' . $this->matchPatterns['identifier'] . '`', $sql, $this->matches['identifiers'], PREG_SET_ORDER);
preg_match_all('`'.$this->matchPatterns['operator'].'`', $sql, $this->matches['operators'], PREG_SET_ORDER); preg_match_all('`' . $this->matchPatterns['operator'] . '`', $sql, $this->matches['operators'], PREG_SET_ORDER);
// Get everything at once for ordering // Get everything at once for ordering
$fullPattern = '`'.$this->matchPatterns['function'].'+|'.$this->matchPatterns['identifier'].'|('.$this->matchPatterns['operator'].')+`i'; $fullPattern = '`' . $this->matchPatterns['function'] . '+|' . $this->matchPatterns['identifier'] . '|(' . $this->matchPatterns['operator'] . ')+`i';
preg_match_all($fullPattern, $sql, $this->matches['combined'], PREG_SET_ORDER); preg_match_all($fullPattern, $sql, $this->matches['combined'], PREG_SET_ORDER);
// Go through the matches, and get the most relevant matches // Go through the matches, and get the most relevant matches
@ -79,9 +80,9 @@ class QueryParser {
$count = is_countable($parts['identifiers']) ? count($parts['identifiers']) : 0; $count = is_countable($parts['identifiers']) ? count($parts['identifiers']) : 0;
// Go through and quote the identifiers // Go through and quote the identifiers
for($i=0; $i <= $count; $i++) for ($i=0; $i <= $count; $i++)
{ {
if (in_array($parts['combined'][$i], $parts['identifiers']) && ! is_numeric($parts['combined'][$i])) if (in_array($parts['combined'][$i], $parts['identifiers'], TRUE) && ! is_numeric($parts['combined'][$i]))
{ {
$parts['combined'][$i] = $this->db->quoteIdent($parts['combined'][$i]); $parts['combined'][$i] = $this->db->quoteIdent($parts['combined'][$i]);
} }
@ -92,14 +93,12 @@ class QueryParser {
/** /**
* Returns a more useful match array * Returns a more useful match array
*
* @return array
*/ */
protected function filterArray(array $array): array protected function filterArray(array $array): array
{ {
$newArray = []; $newArray = [];
foreach($array as $row) foreach ($array as $row)
{ {
$newArray[] = (is_array($row)) ? $row[0] : $row; $newArray[] = (is_array($row)) ? $row[0] : $row;
} }

View File

@ -13,12 +13,14 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query; namespace Query;
/** /**
* Enum of query types * Enum of query types
*/ */
enum QueryType: string { enum QueryType: string
{
case SELECT = 'select'; case SELECT = 'select';
case INSERT = 'insert'; case INSERT = 'insert';
case INSERT_BATCH = 'insert_batch'; case INSERT_BATCH = 'insert_batch';

View File

@ -13,6 +13,7 @@
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 4.0.0 * @version 4.0.0
*/ */
namespace Query; namespace Query;
use function is_array; use function is_array;
@ -20,32 +21,33 @@ use function is_array;
/** /**
* Query builder state * Query builder state
* *
* @method getSelectString(): string
* @method getFromString(): string * @method getFromString(): string
* @method getSetString(): string
* @method getOrderString(): string
* @method getGroupString(): string
* @method getSetArrayKeys(): array
* @method getOrderArray(): array
* @method getGroupArray(): array * @method getGroupArray(): array
* @method getValues(): array * @method getGroupString(): string
* @method getWhereValues(): array * @method getHavingMap(): array
* @method getLimit(): int|null * @method getLimit(): int|null
* @method getOffset() * @method getOffset()
* @method getOrderArray(): array
* @method getOrderString(): string
* @method getQueryMap(): array * @method getQueryMap(): array
* @method getHavingMap(): array * @method getSelectString(): string
* @method getSetArrayKeys(): array
* @method getSetString(): string
* @method getValues(): array
* @method getWhereValues(): array
* *
* @method setSelectString(string $selectString): self
* @method setFromString(string $fromString): self * @method setFromString(string $fromString): self
* @method setSetString(string $setString): self
* @method setOrderString(string $orderString): self
* @method setGroupString(string $groupString): self
* @method setSetArrayKeys(array $arrayKeys): self
* @method setGroupArray(array $array): self * @method setGroupArray(array $array): self
* @method setGroupString(string $groupString): self
* @method setLimit(int $limit): self * @method setLimit(int $limit): self
* @method setOffset(?int $offset): self * @method setOffset(?int $offset): self
* @method setOrderString(string $orderString): self
* @method setSelectString(string $selectString): self
* @method setSetArrayKeys(array $arrayKeys): self
* @method setSetString(string $setString): self
*/ */
class State { class State
{
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// ! SQL Clause Strings // ! SQL Clause Strings
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -150,6 +152,7 @@ class State {
if (isset($this->$maybeProp)) if (isset($this->$maybeProp))
{ {
$this->$maybeProp = $arguments[0]; $this->$maybeProp = $arguments[0];
return $this; return $this;
} }
} }
@ -160,30 +163,35 @@ class State {
public function appendSelectString(string $str): self public function appendSelectString(string $str): self
{ {
$this->selectString .= $str; $this->selectString .= $str;
return $this; return $this;
} }
public function appendSetArrayKeys(array $setArrayKeys): self public function appendSetArrayKeys(array $setArrayKeys): self
{ {
$this->setArrayKeys = array_merge($this->setArrayKeys, $setArrayKeys); $this->setArrayKeys = array_merge($this->setArrayKeys, $setArrayKeys);
return $this; return $this;
} }
public function setOrderArray(string $key, mixed $orderArray): self public function setOrderArray(string $key, mixed $orderArray): self
{ {
$this->orderArray[$key] = $orderArray; $this->orderArray[$key] = $orderArray;
return $this; return $this;
} }
public function appendGroupArray(string $groupArray): self public function appendGroupArray(string $groupArray): self
{ {
$this->groupArray[] = $groupArray; $this->groupArray[] = $groupArray;
return $this; return $this;
} }
public function appendValues(array $values): self public function appendValues(array $values): self
{ {
$this->values = array_merge($this->values, $values); $this->values = array_merge($this->values, $values);
return $this; return $this;
} }
@ -191,7 +199,7 @@ class State {
{ {
if (is_array($val)) if (is_array($val))
{ {
foreach($val as $v) foreach ($val as $v)
{ {
$this->whereValues[] = $v; $this->whereValues[] = $v;
} }
@ -200,6 +208,7 @@ class State {
} }
$this->whereValues[] = $val; $this->whereValues[] = $val;
return $this; return $this;
} }
@ -211,14 +220,16 @@ class State {
$this->queryMap[] = [ $this->queryMap[] = [
'type' => $type, 'type' => $type,
'conjunction' => $conjunction, 'conjunction' => $conjunction,
'string' => $string 'string' => $string,
]; ];
return $this; return $this;
} }
public function appendHavingMap(array $item): self public function appendHavingMap(array $item): self
{ {
$this->havingMap[] = $item; $this->havingMap[] = $item;
return $this; return $this;
} }
} }