Set consistent code style
This commit is contained in:
parent
94d1cbb09b
commit
cf2255ce87
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query;
|
||||
|
||||
use DomainException;
|
||||
@ -22,8 +23,8 @@ use stdClass;
|
||||
* Connection manager class to manage connections for the
|
||||
* Query method
|
||||
*/
|
||||
final class ConnectionManager {
|
||||
|
||||
final class ConnectionManager
|
||||
{
|
||||
/**
|
||||
* Map of named database connections
|
||||
*/
|
||||
@ -91,7 +92,6 @@ final class ConnectionManager {
|
||||
/**
|
||||
* Returns the connection specified by the name given
|
||||
*
|
||||
* @param string $name
|
||||
* @throws Exception\NonExistentConnectionException
|
||||
*/
|
||||
public function getConnection(string $name = ''): QueryBuilderInterface
|
||||
@ -113,9 +113,6 @@ final class ConnectionManager {
|
||||
|
||||
/**
|
||||
* Parse the passed parameters and return a connection
|
||||
*
|
||||
* @param array|object $params
|
||||
* @return QueryBuilderInterface
|
||||
*/
|
||||
public function connect(array|object $params): QueryBuilderInterface
|
||||
{
|
||||
@ -138,7 +135,6 @@ final class ConnectionManager {
|
||||
// Create Query Builder object
|
||||
$conn = new QueryBuilder($db, new QueryParser($db));
|
||||
|
||||
|
||||
// Save it for later
|
||||
if (isset($params->alias))
|
||||
{
|
||||
@ -155,9 +151,7 @@ final class ConnectionManager {
|
||||
/**
|
||||
* Parses params into a dsn and option array
|
||||
*
|
||||
* @param array|object $rawParams
|
||||
* @throws Exception\BadDBDriverException
|
||||
* @return array
|
||||
*/
|
||||
public function parseParams(array|object $rawParams): array
|
||||
{
|
||||
@ -183,7 +177,6 @@ final class ConnectionManager {
|
||||
// Create the dsn for the database to connect to
|
||||
$dsn = strtolower($dbType) === 'sqlite' ? $params->file : $this->createDsn($dbType, $params);
|
||||
|
||||
|
||||
return [$dsn, $dbType, $params, $options];
|
||||
}
|
||||
|
||||
@ -209,12 +202,12 @@ final class ConnectionManager {
|
||||
'prefix' => 'prefix',
|
||||
'options' => 'options',
|
||||
'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]);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers;
|
||||
|
||||
use InvalidArgumentException;
|
||||
@ -29,10 +30,8 @@ use function is_string;
|
||||
*
|
||||
* Extends PDO to simplify cross-database issues
|
||||
*/
|
||||
abstract class AbstractDriver
|
||||
extends PDO
|
||||
implements DriverInterface {
|
||||
|
||||
abstract class AbstractDriver extends PDO implements DriverInterface
|
||||
{
|
||||
/**
|
||||
* Reference to the last executed query
|
||||
*/
|
||||
@ -76,7 +75,7 @@ abstract class AbstractDriver
|
||||
/**
|
||||
* 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
|
||||
$driverOptions[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
|
||||
@ -85,23 +84,6 @@ abstract class AbstractDriver
|
||||
$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
|
||||
*
|
||||
@ -114,14 +96,30 @@ abstract class AbstractDriver
|
||||
isset($this->$name)
|
||||
&& is_object($this->$name)
|
||||
&& method_exists($this->$name, '__invoke')
|
||||
)
|
||||
{
|
||||
) {
|
||||
return call_user_func_array([$this->$name, '__invoke'], $args);
|
||||
}
|
||||
|
||||
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
|
||||
// --------------------------------------------------------------------------
|
||||
@ -177,11 +175,11 @@ abstract class AbstractDriver
|
||||
$this->statement = $this->prepare($sql);
|
||||
|
||||
// Bind the parameters
|
||||
foreach($data as $k => $value)
|
||||
foreach ($data as $k => $value)
|
||||
{
|
||||
// Parameters are 1-based, the data is 0-based
|
||||
// So, if the key is numeric, add 1
|
||||
if(is_numeric($k))
|
||||
if (is_numeric($k))
|
||||
{
|
||||
$k++;
|
||||
}
|
||||
@ -282,7 +280,8 @@ abstract class AbstractDriver
|
||||
// Fix functions
|
||||
$funcs = [];
|
||||
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
|
||||
// Quote the inside identifiers
|
||||
@ -308,6 +307,7 @@ abstract class AbstractDriver
|
||||
{
|
||||
$tables = $this->driverQuery('tableList');
|
||||
natsort($tables);
|
||||
|
||||
return $tables;
|
||||
}
|
||||
|
||||
@ -326,6 +326,7 @@ abstract class AbstractDriver
|
||||
{
|
||||
$views = $this->driverQuery('viewList');
|
||||
sort($views);
|
||||
|
||||
return $views;
|
||||
}
|
||||
|
||||
@ -456,6 +457,7 @@ abstract class AbstractDriver
|
||||
if (preg_match($regex, $this->lastQuery, $output) > 0)
|
||||
{
|
||||
$stmt = $this->query("SELECT COUNT(*) FROM {$output[1]}");
|
||||
|
||||
return (int) $stmt->fetchColumn();
|
||||
}
|
||||
|
||||
@ -472,7 +474,8 @@ abstract class AbstractDriver
|
||||
|
||||
// Values for insertion
|
||||
$vals = [];
|
||||
foreach($data as $group)
|
||||
|
||||
foreach ($data as $group)
|
||||
{
|
||||
$vals = [...$vals, ...array_values($group)];
|
||||
}
|
||||
@ -533,6 +536,7 @@ abstract class AbstractDriver
|
||||
$line = $this->quoteIdent($field) . " = CASE\n";
|
||||
|
||||
$cases = [];
|
||||
|
||||
foreach ($data as $case)
|
||||
{
|
||||
if (array_key_exists($field, $case))
|
||||
@ -553,6 +557,7 @@ abstract class AbstractDriver
|
||||
$sql .= implode(",\n", $fieldLines) . "\n";
|
||||
|
||||
$whereValues = array_column($data, $where);
|
||||
|
||||
foreach ($whereValues as $value)
|
||||
{
|
||||
$insertData[] = $value;
|
||||
@ -579,6 +584,7 @@ abstract class AbstractDriver
|
||||
$sql .= $this->quoteTable($table);
|
||||
|
||||
$this->statement = $this->query($sql);
|
||||
|
||||
return $this->statement;
|
||||
}
|
||||
|
||||
@ -592,9 +598,6 @@ abstract class AbstractDriver
|
||||
|
||||
/**
|
||||
* Helper method for quote_ident
|
||||
*
|
||||
* @param mixed $str
|
||||
* @return mixed
|
||||
*/
|
||||
public function _quote(mixed $str): mixed
|
||||
{
|
||||
@ -608,7 +611,6 @@ abstract class AbstractDriver
|
||||
)
|
||||
? "{$this->escapeCharOpen}{$str}{$this->escapeCharClose}"
|
||||
: $str;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -13,13 +13,14 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers;
|
||||
|
||||
/**
|
||||
* Parent for database-specific syntax subclasses
|
||||
*/
|
||||
abstract class AbstractSQL implements SQLInterface {
|
||||
|
||||
abstract class AbstractSQL implements SQLInterface
|
||||
{
|
||||
/**
|
||||
* Limit clause
|
||||
*/
|
||||
|
@ -13,13 +13,16 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers;
|
||||
|
||||
use function arrayZipper;
|
||||
|
||||
/**
|
||||
* Abstract class defining database / table creation methods
|
||||
*/
|
||||
abstract class AbstractUtil {
|
||||
|
||||
abstract class AbstractUtil
|
||||
{
|
||||
/**
|
||||
* Save a reference to the connection object for later use
|
||||
*/
|
||||
@ -48,14 +51,15 @@ abstract class AbstractUtil {
|
||||
// 'constraint' => ...,
|
||||
// 'index' => ...,
|
||||
// ]
|
||||
$columnArray = \arrayZipper([
|
||||
$columnArray = arrayZipper([
|
||||
'type' => $fields,
|
||||
'constraint' => $constraints
|
||||
'constraint' => $constraints,
|
||||
]);
|
||||
|
||||
// Join column definitions together
|
||||
$columns = [];
|
||||
foreach($columnArray as $n => $props)
|
||||
|
||||
foreach ($columnArray as $n => $props)
|
||||
{
|
||||
$str = $this->getDriver()->quoteIdent($n);
|
||||
$str .= isset($props['type']) ? " {$props['type']}" : '';
|
||||
@ -65,7 +69,7 @@ abstract class AbstractUtil {
|
||||
}
|
||||
|
||||
// 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 .= ')';
|
||||
|
||||
@ -77,7 +81,7 @@ abstract class AbstractUtil {
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @abstract
|
||||
*/
|
||||
abstract public function backupStructure(): string;
|
||||
|
||||
/**
|
||||
* Return an SQL file with the database data as insert statements
|
||||
*
|
||||
* @abstract
|
||||
*/
|
||||
abstract public function backupData(): string;
|
||||
|
||||
}
|
@ -13,9 +13,9 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use PDO;
|
||||
use PDOStatement;
|
||||
|
||||
@ -36,12 +36,12 @@ use PDOStatement;
|
||||
* @method rollback(): bool
|
||||
* @method setAttribute(int $attribute, $value): bool
|
||||
*/
|
||||
interface DriverInterface /* extends the interface of PDO */ {
|
||||
|
||||
interface DriverInterface // extends the interface of PDO
|
||||
{
|
||||
/**
|
||||
* 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
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers\Mysql;
|
||||
|
||||
use PDO;
|
||||
@ -22,8 +23,8 @@ use function defined;
|
||||
/**
|
||||
* MySQL specific class
|
||||
*/
|
||||
class Driver extends AbstractDriver {
|
||||
|
||||
class Driver extends AbstractDriver
|
||||
{
|
||||
/**
|
||||
* Set the backtick as the MySQL escape character
|
||||
*/
|
||||
@ -39,7 +40,7 @@ class Driver extends AbstractDriver {
|
||||
*
|
||||
* @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
|
||||
if (defined('\\PDO::MYSQL_ATTR_INIT_COMMAND'))
|
||||
@ -51,7 +52,7 @@ class Driver extends AbstractDriver {
|
||||
|
||||
if ( ! str_contains($dsn, 'mysql'))
|
||||
{
|
||||
$dsn = 'mysql:'.$dsn;
|
||||
$dsn = 'mysql:' . $dsn;
|
||||
}
|
||||
|
||||
parent::__construct($dsn, $username, $password, $options);
|
||||
@ -67,7 +68,7 @@ class Driver extends AbstractDriver {
|
||||
if (
|
||||
stripos($query, 'insert') !== FALSE
|
||||
&& version_compare($this->getVersion(), '10.5.0', '>=')
|
||||
){
|
||||
) {
|
||||
return parent::returning($query, $select);
|
||||
}
|
||||
|
||||
@ -75,7 +76,7 @@ class Driver extends AbstractDriver {
|
||||
if (
|
||||
stripos($query, 'delete') !== FALSE
|
||||
&& version_compare($this->getVersion(), '10.0.5', '>=')
|
||||
){
|
||||
) {
|
||||
return parent::returning($query, $select);
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers\Mysql;
|
||||
|
||||
use Query\Drivers\AbstractSQL;
|
||||
@ -20,8 +21,8 @@ use Query\Drivers\AbstractSQL;
|
||||
/**
|
||||
* MySQL specific SQL
|
||||
*/
|
||||
class SQL extends AbstractSQL {
|
||||
|
||||
class SQL extends AbstractSQL
|
||||
{
|
||||
/**
|
||||
* Limit clause
|
||||
*/
|
||||
@ -29,10 +30,10 @@ class SQL extends AbstractSQL {
|
||||
{
|
||||
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
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SHOW DATABASES WHERE `Database` NOT IN ('information_schema','mysql')
|
||||
SQL;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,7 +82,7 @@ SQL;
|
||||
*/
|
||||
public function systemTableList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SELECT `TABLE_NAME` FROM `information_schema`.`TABLES`
|
||||
WHERE `TABLE_SCHEMA`='information_schema'
|
||||
SQL;
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers\Mysql;
|
||||
|
||||
use PDO;
|
||||
@ -21,8 +22,8 @@ use Query\Drivers\AbstractUtil;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@ -34,7 +35,7 @@ class Util extends AbstractUtil {
|
||||
$driver = $this->getDriver();
|
||||
$dbs = $driver->getDbs();
|
||||
|
||||
foreach($dbs as &$d)
|
||||
foreach ($dbs as &$d)
|
||||
{
|
||||
// Skip built-in dbs
|
||||
// @codeCoverageIgnoreStart
|
||||
@ -47,7 +48,7 @@ class Util extends AbstractUtil {
|
||||
// Get the list of tables
|
||||
$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);
|
||||
$row = current($array);
|
||||
@ -57,7 +58,6 @@ class Util extends AbstractUtil {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
$string[] = $row['Create Table'];
|
||||
}
|
||||
}
|
||||
@ -74,7 +74,7 @@ class Util extends AbstractUtil {
|
||||
$tables = $driver->getTables();
|
||||
|
||||
// Filter out the tables you don't want
|
||||
if( ! empty($exclude))
|
||||
if ( ! empty($exclude))
|
||||
{
|
||||
$tables = array_diff($tables, $exclude);
|
||||
}
|
||||
@ -82,7 +82,7 @@ class Util extends AbstractUtil {
|
||||
$outputSql = '';
|
||||
|
||||
// Select the rows from each Table
|
||||
foreach($tables as $t)
|
||||
foreach ($tables as $t)
|
||||
{
|
||||
$sql = "SELECT * FROM `{$t}`";
|
||||
$res = $driver->query($sql);
|
||||
@ -100,22 +100,22 @@ class Util extends AbstractUtil {
|
||||
$insertRows = [];
|
||||
|
||||
// Create the insert statements
|
||||
foreach($rows as $row)
|
||||
foreach ($rows as $row)
|
||||
{
|
||||
$row = array_values($row);
|
||||
|
||||
// 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);
|
||||
|
||||
$rowString = 'INSERT INTO `'.trim($t).'` (`'.implode('`,`', $columns).'`) VALUES ('.implode(',', $row).');';
|
||||
$rowString = 'INSERT INTO `' . trim($t) . '` (`' . implode('`,`', $columns) . '`) VALUES (' . implode(',', $row) . ');';
|
||||
|
||||
$row = NULL;
|
||||
|
||||
$insertRows[] = $rowString;
|
||||
}
|
||||
|
||||
$outputSql .= "\n\n".implode("\n", $insertRows)."\n";
|
||||
$outputSql .= "\n\n" . implode("\n", $insertRows) . "\n";
|
||||
}
|
||||
|
||||
return $outputSql;
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers\Pgsql;
|
||||
|
||||
use Query\Drivers\AbstractDriver;
|
||||
@ -20,18 +21,18 @@ use Query\Drivers\AbstractDriver;
|
||||
/**
|
||||
* PostgreSQL specific class
|
||||
*/
|
||||
class Driver extends AbstractDriver {
|
||||
|
||||
class Driver extends AbstractDriver
|
||||
{
|
||||
/**
|
||||
* Connect to a PosgreSQL database
|
||||
*
|
||||
* @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'))
|
||||
{
|
||||
$dsn = 'pgsql:'.$dsn;
|
||||
$dsn = 'pgsql:' . $dsn;
|
||||
}
|
||||
|
||||
parent::__construct($dsn, $username, $password, $options);
|
||||
@ -63,9 +64,9 @@ SQL;
|
||||
|
||||
$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]]))
|
||||
{
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers\Pgsql;
|
||||
|
||||
use Query\Drivers\AbstractSQL;
|
||||
@ -20,8 +21,8 @@ use Query\Drivers\AbstractSQL;
|
||||
/**
|
||||
* PostgreSQL specific SQL
|
||||
*/
|
||||
class SQL extends AbstractSQL {
|
||||
|
||||
class SQL extends AbstractSQL
|
||||
{
|
||||
/**
|
||||
* Get the query plan for the sql query
|
||||
*/
|
||||
@ -43,7 +44,7 @@ class SQL extends AbstractSQL {
|
||||
*/
|
||||
public function dbList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SELECT "datname" FROM "pg_database"
|
||||
WHERE "datname" NOT IN ('template0','template1')
|
||||
ORDER BY "datname" ASC
|
||||
@ -55,7 +56,7 @@ SQL;
|
||||
*/
|
||||
public function tableList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SELECT "table_name"
|
||||
FROM "information_schema"."tables"
|
||||
WHERE "table_type" = 'BASE TABLE'
|
||||
@ -69,7 +70,7 @@ SQL;
|
||||
*/
|
||||
public function systemTableList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SELECT "table_name"
|
||||
FROM "information_schema"."tables"
|
||||
WHERE "table_type" = 'BASE TABLE'
|
||||
@ -83,7 +84,7 @@ SQL;
|
||||
*/
|
||||
public function viewList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SELECT "viewname" FROM "pg_views"
|
||||
WHERE "schemaname" NOT IN
|
||||
('pg_catalog', 'information_schema')
|
||||
@ -97,7 +98,7 @@ SQL;
|
||||
*/
|
||||
public function triggerList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SELECT *
|
||||
FROM "information_schema"."triggers"
|
||||
WHERE "trigger_schema" NOT IN
|
||||
@ -118,7 +119,7 @@ SQL;
|
||||
*/
|
||||
public function procedureList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SELECT "routine_name"
|
||||
FROM "information_schema"."routines"
|
||||
WHERE "specific_schema" NOT IN
|
||||
@ -132,7 +133,7 @@ SQL;
|
||||
*/
|
||||
public function sequenceList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SELECT "c"."relname"
|
||||
FROM "pg_class" "c"
|
||||
WHERE "c"."relkind" = 'S'
|
||||
@ -164,7 +165,7 @@ SQL;
|
||||
*/
|
||||
public function typeList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SELECT "typname" FROM "pg_catalog"."pg_type"
|
||||
WHERE "typname" !~ '^pg_|_'
|
||||
AND "typtype" = 'b'
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers\Pgsql;
|
||||
|
||||
use PDO;
|
||||
@ -21,8 +22,8 @@ use Query\Drivers\AbstractUtil;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@ -40,7 +41,7 @@ class Util extends AbstractUtil {
|
||||
$tables = $this->getDriver()->getTables();
|
||||
|
||||
// Filter out the tables you don't want
|
||||
if( ! empty($exclude))
|
||||
if ( ! empty($exclude))
|
||||
{
|
||||
$tables = array_diff($tables, $exclude);
|
||||
}
|
||||
@ -48,9 +49,9 @@ class Util extends AbstractUtil {
|
||||
$outputSql = '';
|
||||
|
||||
// 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);
|
||||
$objRes = $res->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
@ -68,7 +69,7 @@ class Util extends AbstractUtil {
|
||||
$insertRows = [];
|
||||
|
||||
// Create the insert statements
|
||||
foreach($objRes as $row)
|
||||
foreach ($objRes as $row)
|
||||
{
|
||||
$row = array_values($row);
|
||||
|
||||
@ -76,8 +77,7 @@ class Util extends AbstractUtil {
|
||||
$row = array_map([$this->getDriver(), 'quote'], $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;
|
||||
|
||||
@ -86,7 +86,7 @@ class Util extends AbstractUtil {
|
||||
|
||||
$objRes = NULL;
|
||||
|
||||
$outputSql .= "\n\n".implode("\n", $insertRows)."\n";
|
||||
$outputSql .= "\n\n" . implode("\n", $insertRows) . "\n";
|
||||
}
|
||||
|
||||
return $outputSql;
|
||||
|
@ -13,13 +13,14 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers;
|
||||
|
||||
/**
|
||||
* Interface for database-specific syntax subclasses
|
||||
*/
|
||||
interface SQLInterface {
|
||||
|
||||
interface SQLInterface
|
||||
{
|
||||
/**
|
||||
* Get database specific sql for limit clause
|
||||
*/
|
||||
|
@ -13,18 +13,20 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers\Sqlite;
|
||||
|
||||
use function is_array;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
use PDO;
|
||||
use Query\Drivers\AbstractDriver;
|
||||
use function is_array;
|
||||
|
||||
/**
|
||||
* SQLite specific class
|
||||
*/
|
||||
class Driver extends AbstractDriver {
|
||||
class Driver extends AbstractDriver
|
||||
{
|
||||
/**
|
||||
* SQLite has a truncate optimization,
|
||||
* but no support for the actual keyword
|
||||
@ -34,7 +36,7 @@ class Driver extends AbstractDriver {
|
||||
/**
|
||||
* 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:'))
|
||||
{
|
||||
@ -59,6 +61,7 @@ class Driver extends AbstractDriver {
|
||||
{
|
||||
$sql = $this->getSql()->tableList();
|
||||
$res = $this->query($sql);
|
||||
|
||||
return dbFilter($res->fetchAll(PDO::FETCH_ASSOC), 'name');
|
||||
}
|
||||
|
||||
@ -69,14 +72,14 @@ class Driver extends AbstractDriver {
|
||||
{
|
||||
$returnRows = [];
|
||||
|
||||
foreach(parent::getFks($table) as $row)
|
||||
foreach (parent::getFks($table) as $row)
|
||||
{
|
||||
$returnRows[] = [
|
||||
'child_column' => $row['from'],
|
||||
'parent_table' => $row['table'],
|
||||
'parent_column' => $row['to'],
|
||||
'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
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @return array[]|string[]|null[]
|
||||
* @return array[]|null[]|string[]
|
||||
*/
|
||||
public function insertBatch(string $table, array $data=[]): array
|
||||
{
|
||||
@ -115,13 +118,14 @@ class Driver extends AbstractDriver {
|
||||
// Create a key-value mapping for each field
|
||||
$first = array_shift($data);
|
||||
$cols = [];
|
||||
foreach($first as $colName => $datum)
|
||||
|
||||
foreach ($first as $colName => $datum)
|
||||
{
|
||||
$cols[] = $this->_quote($datum) . ' AS ' . $this->quoteIdent($colName);
|
||||
}
|
||||
$sql .= 'SELECT ' . implode(', ', $cols) . "\n";
|
||||
|
||||
foreach($data as $union)
|
||||
foreach ($data as $union)
|
||||
{
|
||||
$vals = array_map([$this, 'quote'], $union);
|
||||
$sql .= 'UNION SELECT ' . implode(',', $vals) . "\n";
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers\Sqlite;
|
||||
|
||||
use Query\Drivers\AbstractSQL;
|
||||
@ -21,8 +22,8 @@ use Query\Exception\NotImplementedException;
|
||||
/**
|
||||
* SQLite Specific SQL
|
||||
*/
|
||||
class SQL extends AbstractSQL {
|
||||
|
||||
class SQL extends AbstractSQL
|
||||
{
|
||||
/**
|
||||
* Get the query plan for the sql query
|
||||
*/
|
||||
@ -53,7 +54,7 @@ class SQL extends AbstractSQL {
|
||||
*/
|
||||
public function tableList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SELECT "name" FROM (
|
||||
SELECT * FROM "sqlite_master" UNION ALL
|
||||
SELECT * FROM "sqlite_temp_master"
|
||||
@ -74,7 +75,7 @@ SQL;
|
||||
return [
|
||||
'sqlite_master',
|
||||
'sqlite_temp_master',
|
||||
'sqlite_sequence'
|
||||
'sqlite_sequence',
|
||||
];
|
||||
}
|
||||
|
||||
@ -83,7 +84,7 @@ SQL;
|
||||
*/
|
||||
public function viewList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SELECT "name" FROM "sqlite_master" WHERE "type" = 'view'
|
||||
SQL;
|
||||
}
|
||||
@ -93,7 +94,7 @@ SQL;
|
||||
*/
|
||||
public function triggerList(): string
|
||||
{
|
||||
return <<<SQL
|
||||
return <<<'SQL'
|
||||
SELECT "name" FROM "sqlite_master" WHERE "type"='trigger'
|
||||
SQL;
|
||||
}
|
||||
@ -157,7 +158,6 @@ SQL;
|
||||
SQL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the list of indexes for the current table
|
||||
*/
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Drivers\Sqlite;
|
||||
|
||||
use PDO;
|
||||
@ -21,8 +22,8 @@ use Query\Drivers\AbstractUtil;
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@ -33,9 +34,9 @@ class Util extends AbstractUtil {
|
||||
FROM "sqlite_master"
|
||||
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);
|
||||
@ -46,9 +47,9 @@ class Util extends AbstractUtil {
|
||||
$outputSql = '';
|
||||
|
||||
// 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);
|
||||
$objRes = $res->fetchAll(PDO::FETCH_ASSOC);
|
||||
|
||||
@ -66,7 +67,7 @@ class Util extends AbstractUtil {
|
||||
$insertRows = [];
|
||||
|
||||
// Create the insert statements
|
||||
foreach($objRes as $row)
|
||||
foreach ($objRes as $row)
|
||||
{
|
||||
$row = array_values($row);
|
||||
|
||||
@ -78,7 +79,7 @@ class Util extends AbstractUtil {
|
||||
: $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);
|
||||
|
||||
@ -87,7 +88,7 @@ class Util extends AbstractUtil {
|
||||
|
||||
unset($objRes);
|
||||
|
||||
$outputSql .= "\n\n".implode("\n", $insertRows);
|
||||
$outputSql .= "\n\n" . implode("\n", $insertRows);
|
||||
}
|
||||
|
||||
return $outputSql;
|
||||
@ -105,7 +106,7 @@ class Util extends AbstractUtil {
|
||||
|
||||
$sqlArray = [];
|
||||
|
||||
foreach($result as $r)
|
||||
foreach ($result as $r)
|
||||
{
|
||||
$sqlArray[] = $r['sql'];
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
@ -20,5 +21,6 @@ use InvalidArgumentException;
|
||||
/**
|
||||
* Generic exception for bad drivers
|
||||
*/
|
||||
class BadDBDriverException extends InvalidArgumentException {
|
||||
class BadDBDriverException extends InvalidArgumentException
|
||||
{
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
@ -20,5 +21,6 @@ use InvalidArgumentException;
|
||||
/**
|
||||
* Exception for missing database connection
|
||||
*/
|
||||
class NonExistentConnectionException extends InvalidArgumentException {
|
||||
class NonExistentConnectionException extends InvalidArgumentException
|
||||
{
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query\Exception;
|
||||
|
||||
use BadMethodCallException;
|
||||
@ -20,5 +21,6 @@ use BadMethodCallException;
|
||||
/**
|
||||
* Exception for non-implemented method
|
||||
*/
|
||||
class NotImplementedException extends BadMethodCallException{
|
||||
class NotImplementedException extends BadMethodCallException
|
||||
{
|
||||
}
|
@ -13,12 +13,14 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query;
|
||||
|
||||
/**
|
||||
* Enum of join types
|
||||
*/
|
||||
enum JoinType: string {
|
||||
enum JoinType: string
|
||||
{
|
||||
case CROSS = 'cross';
|
||||
case INNER = 'inner';
|
||||
case OUTER = 'outer';
|
||||
@ -35,4 +37,3 @@ enum JoinType: string {
|
||||
return self::from($val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,14 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query;
|
||||
|
||||
/**
|
||||
* 'Enum' of join types
|
||||
*/
|
||||
enum LikeType: string {
|
||||
enum LikeType: string
|
||||
{
|
||||
case BEFORE = 'before';
|
||||
case AFTER = 'after';
|
||||
case BOTH = 'both';
|
||||
|
@ -13,12 +13,14 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query;
|
||||
|
||||
/**
|
||||
* Enum of query map types
|
||||
*/
|
||||
enum MapType: string {
|
||||
enum MapType: string
|
||||
{
|
||||
case GROUP_END = 'group_end';
|
||||
case GROUP_START = 'group_start';
|
||||
case JOIN = 'join';
|
||||
|
@ -13,18 +13,20 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query;
|
||||
|
||||
use PDOStatement;
|
||||
use function is_array;
|
||||
use function is_int;
|
||||
use function mb_trim;
|
||||
|
||||
use PDOStatement;
|
||||
use function mb_trim;
|
||||
|
||||
/**
|
||||
* Convenience class for creating sql queries
|
||||
*/
|
||||
class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
|
||||
class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface
|
||||
{
|
||||
// --------------------------------------------------------------------------
|
||||
// ! Select Queries
|
||||
// --------------------------------------------------------------------------
|
||||
@ -69,48 +71,52 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
// Create the select string
|
||||
$this->state->appendSelectString(' MAX'.$this->_select($field, $as));
|
||||
$this->state->appendSelectString(' MAX' . $this->_select($field, $as));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
// Create the select string
|
||||
$this->state->appendSelectString(' MIN'.$this->_select($field, $as));
|
||||
$this->state->appendSelectString(' MIN' . $this->_select($field, $as));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
// Create the select string
|
||||
$this->state->appendSelectString(' AVG'.$this->_select($field, $as));
|
||||
$this->state->appendSelectString(' AVG' . $this->_select($field, $as));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
// Create the select string
|
||||
$this->state->appendSelectString(' SUM'.$this->_select($field, $as));
|
||||
$this->state->appendSelectString(' SUM' . $this->_select($field, $as));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -139,6 +145,7 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
|
||||
{
|
||||
// Prepend the keyword to the select string
|
||||
$this->state->setSelectString(' DISTINCT' . $this->state->getSelectString());
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -148,6 +155,7 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
|
||||
public function explain(): self
|
||||
{
|
||||
$this->explain = TRUE;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -155,8 +163,6 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
|
||||
* Specify the database table to select from
|
||||
*
|
||||
* Alias of `from` method to better match CodeIgniter 4
|
||||
*
|
||||
* @param string $tableName
|
||||
*/
|
||||
public function table(string $tableName): self
|
||||
{
|
||||
@ -383,15 +389,15 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
|
||||
$orderClauses = [];
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Set the final string
|
||||
$orderString = isset($rand)
|
||||
? "\nORDER BY".$rand
|
||||
: "\nORDER BY ".implode(', ', $orderClauses);
|
||||
? "\nORDER BY" . $rand
|
||||
: "\nORDER BY " . implode(', ', $orderClauses);
|
||||
|
||||
$this->state->setOrderString($orderString);
|
||||
|
||||
@ -512,8 +518,9 @@ class QueryBuilder extends QueryBuilderBase implements QueryBuilderInterface {
|
||||
*/
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
$this->_run(QueryType::UPDATE_BATCH, $table, $sql, $data);
|
||||
|
||||
return $affectedRows;
|
||||
}
|
||||
|
||||
|
@ -13,14 +13,16 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query;
|
||||
|
||||
use function regexInArray;
|
||||
|
||||
use BadMethodCallException;
|
||||
|
||||
use PDO;
|
||||
use PDOStatement;
|
||||
use Query\Drivers\DriverInterface;
|
||||
use function is_string;
|
||||
use function regexInArray;
|
||||
|
||||
/**
|
||||
* @method affectedRows(): int
|
||||
@ -56,8 +58,8 @@ use Query\Drivers\DriverInterface;
|
||||
* @method setTablePrefix(string $prefix): void
|
||||
* @method truncate(string $table): PDOStatement
|
||||
*/
|
||||
class QueryBuilderBase {
|
||||
|
||||
class QueryBuilderBase
|
||||
{
|
||||
/**
|
||||
* Convenience property for connection management
|
||||
*/
|
||||
@ -67,7 +69,7 @@ class QueryBuilderBase {
|
||||
* List of queries executed
|
||||
*/
|
||||
public array $queries = [
|
||||
'total_time' => 0
|
||||
'total_time' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
@ -110,8 +112,8 @@ class QueryBuilderBase {
|
||||
* Calls a function further down the inheritance chain.
|
||||
* 'Implements' methods on the driver object
|
||||
*
|
||||
* @return mixed
|
||||
* @throws BadMethodCallException
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call(string $name, array $params)
|
||||
{
|
||||
@ -141,7 +143,7 @@ class QueryBuilderBase {
|
||||
// Escape the identifiers
|
||||
$field = $this->driver->quoteIdent($field);
|
||||
|
||||
if ( ! \is_string($as))
|
||||
if ( ! is_string($as))
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
return $field;
|
||||
@ -149,6 +151,7 @@ class QueryBuilderBase {
|
||||
}
|
||||
|
||||
$as = $this->driver->quoteIdent($as);
|
||||
|
||||
return "({$field}) AS {$as} ";
|
||||
}
|
||||
|
||||
@ -224,7 +227,7 @@ class QueryBuilderBase {
|
||||
'conjunction' => empty($this->state->getHavingMap())
|
||||
? ' HAVING '
|
||||
: " {$conj} ",
|
||||
'string' => $item
|
||||
'string' => $item,
|
||||
]);
|
||||
}
|
||||
|
||||
@ -242,7 +245,8 @@ class QueryBuilderBase {
|
||||
if (is_scalar($key))
|
||||
{
|
||||
$pairs[$key] = $val;
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
$pairs = $key;
|
||||
}
|
||||
@ -300,8 +304,6 @@ class QueryBuilderBase {
|
||||
/**
|
||||
* Simplify where_in methods
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $val
|
||||
* @param string $in - The (not) in fragment
|
||||
* @param string $conj - The where in conjunction
|
||||
*/
|
||||
@ -321,10 +323,8 @@ class QueryBuilderBase {
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
@ -346,7 +346,7 @@ class QueryBuilderBase {
|
||||
$totalTime = number_format($endTime - $startTime, 5);
|
||||
|
||||
// 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
|
||||
if ($reset)
|
||||
@ -368,7 +368,7 @@ class QueryBuilderBase {
|
||||
// Quote string values
|
||||
foreach ($evals as &$v)
|
||||
{
|
||||
$v = ( is_numeric($v))
|
||||
$v = (is_numeric($v))
|
||||
? $v
|
||||
: 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
|
||||
$this->queries[] = [
|
||||
'time' => $totalTime,
|
||||
'sql' => sprintf(...$evals)
|
||||
'sql' => sprintf(...$evals),
|
||||
];
|
||||
|
||||
$this->queries['total_time'] += $totalTime;
|
||||
@ -398,6 +398,7 @@ class QueryBuilderBase {
|
||||
protected function _compileType(QueryType $type = QueryType::SELECT, string $table = ''): string
|
||||
{
|
||||
$setArrayKeys = $this->state->getSetArrayKeys();
|
||||
|
||||
switch ($type)
|
||||
{
|
||||
case QueryType::INSERT:
|
||||
@ -454,7 +455,7 @@ class QueryBuilderBase {
|
||||
// Set each type of subclause
|
||||
foreach ($clauses as $clause)
|
||||
{
|
||||
$func = 'get' . ucFirst($clause);
|
||||
$func = 'get' . ucfirst($clause);
|
||||
$param = $this->state->$func();
|
||||
if (is_array($param))
|
||||
{
|
||||
@ -462,7 +463,8 @@ class QueryBuilderBase {
|
||||
{
|
||||
$sql .= $q['conjunction'] . $q['string'];
|
||||
}
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
$sql .= $param;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query;
|
||||
|
||||
use PDO;
|
||||
@ -57,8 +58,8 @@ use PDOStatement;
|
||||
* @method setTablePrefix(string $prefix): void
|
||||
* @method truncate(string $table): PDOStatement
|
||||
*/
|
||||
interface QueryBuilderInterface {
|
||||
|
||||
interface QueryBuilderInterface
|
||||
{
|
||||
// --------------------------------------------------------------------------
|
||||
// ! Select Queries
|
||||
// --------------------------------------------------------------------------
|
||||
@ -70,28 +71,28 @@ interface QueryBuilderInterface {
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@ -109,8 +110,6 @@ interface QueryBuilderInterface {
|
||||
* Specify the database table to select from
|
||||
*
|
||||
* Alias of `from` method to better match CodeIgniter 4
|
||||
*
|
||||
* @param string $tableName
|
||||
*/
|
||||
public function table(string $tableName): self;
|
||||
|
||||
@ -124,29 +123,21 @@ interface QueryBuilderInterface {
|
||||
// --------------------------------------------------------------------------
|
||||
/**
|
||||
* Creates a Like clause in the sql statement
|
||||
*
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function like(string $field, mixed $values, LikeType|string $pos=LikeType::BOTH): self;
|
||||
|
||||
/**
|
||||
* Generates an OR Like clause
|
||||
*
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function orLike(string $field, mixed $values, LikeType|string $pos=LikeType::BOTH): self;
|
||||
|
||||
/**
|
||||
* Generates a NOT LIKE clause
|
||||
*
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function notLike(string $field, mixed $values, LikeType|string $pos=LikeType::BOTH): self;
|
||||
|
||||
/**
|
||||
* Generates a OR NOT LIKE clause
|
||||
*
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function orNotLike(string $field, mixed $values, LikeType|string $pos=LikeType::BOTH): self;
|
||||
|
||||
@ -155,17 +146,11 @@ interface QueryBuilderInterface {
|
||||
// --------------------------------------------------------------------------
|
||||
/**
|
||||
* Generates a 'Having' clause
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function having(mixed $key, mixed $values=[]): self;
|
||||
|
||||
/**
|
||||
* Generates a 'Having' clause prefixed with 'OR'
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function orHaving(mixed $key, mixed $values=[]): self;
|
||||
|
||||
@ -176,9 +161,6 @@ interface QueryBuilderInterface {
|
||||
* Specify condition(s) in the where clause of a query
|
||||
* Note: this function works with key / value, or a
|
||||
* passed array with key / value pairs
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function where(mixed $key, mixed $values=[]): self;
|
||||
|
||||
@ -186,39 +168,26 @@ interface QueryBuilderInterface {
|
||||
* Where clause prefixed with "OR"
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function orWhere(mixed $key, mixed $values=[]): self;
|
||||
|
||||
/**
|
||||
* Where clause with 'IN' statement
|
||||
*
|
||||
* @param string $field
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function whereIn(string $field, mixed $values=[]): self;
|
||||
|
||||
/**
|
||||
* Where in statement prefixed with "or"
|
||||
*
|
||||
* @param string $field
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function orWhereIn(string $field, mixed $values=[]): self;
|
||||
|
||||
/**
|
||||
* WHERE NOT IN (FOO) clause
|
||||
*
|
||||
* @param string $field
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function whereNotIn(string $field, mixed $values=[]): self;
|
||||
|
||||
/**
|
||||
* OR WHERE NOT IN (FOO) clause
|
||||
*
|
||||
* @param string $field
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function orWhereNotIn(string $field, mixed $values=[]): self;
|
||||
|
||||
@ -228,7 +197,6 @@ interface QueryBuilderInterface {
|
||||
/**
|
||||
* Sets values for inserts / updates / deletes
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param mixed $values
|
||||
*/
|
||||
public function set(mixed $key, mixed $values = NULL): self;
|
||||
@ -240,8 +208,6 @@ interface QueryBuilderInterface {
|
||||
|
||||
/**
|
||||
* Group the results by the selected field(s)
|
||||
*
|
||||
* @param mixed $field
|
||||
*/
|
||||
public function groupBy(mixed $field): self;
|
||||
|
||||
@ -297,8 +263,6 @@ interface QueryBuilderInterface {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
@ -317,8 +281,6 @@ interface QueryBuilderInterface {
|
||||
|
||||
/**
|
||||
* Creates an insert clause, and executes it
|
||||
*
|
||||
* @param mixed $data
|
||||
*/
|
||||
public function insert(string $table, mixed $data=[]): PDOStatement;
|
||||
|
||||
@ -331,8 +293,6 @@ interface QueryBuilderInterface {
|
||||
|
||||
/**
|
||||
* Creates an update clause, and executes it
|
||||
*
|
||||
* @param mixed $data
|
||||
*/
|
||||
public function update(string $table, mixed $data=[]): PDOStatement;
|
||||
|
||||
@ -348,8 +308,6 @@ interface QueryBuilderInterface {
|
||||
|
||||
/**
|
||||
* Deletes data from a table
|
||||
*
|
||||
* @param mixed $where
|
||||
*/
|
||||
public function delete(string $table, mixed $where=''): PDOStatement;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query;
|
||||
|
||||
use Query\Drivers\DriverInterface;
|
||||
@ -20,17 +21,8 @@ use Query\Drivers\DriverInterface;
|
||||
/**
|
||||
* Utility Class to parse sql clauses for properly escaping identifiers
|
||||
*/
|
||||
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'
|
||||
];
|
||||
|
||||
class QueryParser
|
||||
{
|
||||
/**
|
||||
* Regex matches
|
||||
*/
|
||||
@ -41,6 +33,15 @@ class QueryParser {
|
||||
'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
|
||||
*/
|
||||
@ -56,12 +57,12 @@ class QueryParser {
|
||||
public function parseJoin(string $sql): array
|
||||
{
|
||||
// Get sql clause components
|
||||
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['operator'].'`', $sql, $this->matches['operators'], 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['operator'] . '`', $sql, $this->matches['operators'], PREG_SET_ORDER);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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;
|
||||
|
||||
// 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]);
|
||||
}
|
||||
@ -92,14 +93,12 @@ class QueryParser {
|
||||
|
||||
/**
|
||||
* Returns a more useful match array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function filterArray(array $array): array
|
||||
{
|
||||
$newArray = [];
|
||||
|
||||
foreach($array as $row)
|
||||
foreach ($array as $row)
|
||||
{
|
||||
$newArray[] = (is_array($row)) ? $row[0] : $row;
|
||||
}
|
||||
|
@ -13,12 +13,14 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query;
|
||||
|
||||
/**
|
||||
* Enum of query types
|
||||
*/
|
||||
enum QueryType: string {
|
||||
enum QueryType: string
|
||||
{
|
||||
case SELECT = 'select';
|
||||
case INSERT = 'insert';
|
||||
case INSERT_BATCH = 'insert_batch';
|
||||
|
@ -13,6 +13,7 @@
|
||||
* @link https://git.timshomepage.net/aviat/Query
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
namespace Query;
|
||||
|
||||
use function is_array;
|
||||
@ -20,32 +21,33 @@ use function is_array;
|
||||
/**
|
||||
* Query builder state
|
||||
*
|
||||
* @method getSelectString(): string
|
||||
* @method getFromString(): string
|
||||
* @method getSetString(): string
|
||||
* @method getOrderString(): string
|
||||
* @method getGroupString(): string
|
||||
* @method getSetArrayKeys(): array
|
||||
* @method getOrderArray(): array
|
||||
* @method getGroupArray(): array
|
||||
* @method getValues(): array
|
||||
* @method getWhereValues(): array
|
||||
* @method getGroupString(): string
|
||||
* @method getHavingMap(): array
|
||||
* @method getLimit(): int|null
|
||||
* @method getOffset()
|
||||
* @method getOrderArray(): array
|
||||
* @method getOrderString(): string
|
||||
* @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 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 setGroupString(string $groupString): self
|
||||
* @method setLimit(int $limit): 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
|
||||
// --------------------------------------------------------------------------
|
||||
@ -150,6 +152,7 @@ class State {
|
||||
if (isset($this->$maybeProp))
|
||||
{
|
||||
$this->$maybeProp = $arguments[0];
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@ -160,30 +163,35 @@ class State {
|
||||
public function appendSelectString(string $str): self
|
||||
{
|
||||
$this->selectString .= $str;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function appendSetArrayKeys(array $setArrayKeys): self
|
||||
{
|
||||
$this->setArrayKeys = array_merge($this->setArrayKeys, $setArrayKeys);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setOrderArray(string $key, mixed $orderArray): self
|
||||
{
|
||||
$this->orderArray[$key] = $orderArray;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function appendGroupArray(string $groupArray): self
|
||||
{
|
||||
$this->groupArray[] = $groupArray;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function appendValues(array $values): self
|
||||
{
|
||||
$this->values = array_merge($this->values, $values);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -191,7 +199,7 @@ class State {
|
||||
{
|
||||
if (is_array($val))
|
||||
{
|
||||
foreach($val as $v)
|
||||
foreach ($val as $v)
|
||||
{
|
||||
$this->whereValues[] = $v;
|
||||
}
|
||||
@ -200,6 +208,7 @@ class State {
|
||||
}
|
||||
|
||||
$this->whereValues[] = $val;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -211,14 +220,16 @@ class State {
|
||||
$this->queryMap[] = [
|
||||
'type' => $type,
|
||||
'conjunction' => $conjunction,
|
||||
'string' => $string
|
||||
'string' => $string,
|
||||
];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function appendHavingMap(array $item): self
|
||||
{
|
||||
$this->havingMap[] = $item;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user