Implement basic 'returning' method for Postgres

This commit is contained in:
Timothy Warren 2020-03-19 11:53:08 -04:00
parent 54a6054728
commit 77df254a0c
11 changed files with 342 additions and 272 deletions

View File

@ -1,4 +1,7 @@
<?php declare(strict_types=1); <?php declare(strict_types=1);
use Robo\Tasks;
if ( ! function_exists('glob_recursive')) if ( ! function_exists('glob_recursive'))
{ {
// Does not support flag GLOB_BRACE // Does not support flag GLOB_BRACE
@ -20,7 +23,7 @@ if ( ! function_exists('glob_recursive'))
* *
* @see http://robo.li/ * @see http://robo.li/
*/ */
class RoboFile extends \Robo\Tasks { class RoboFile extends Tasks {
/** /**
* Directories used by analysis tools * Directories used by analysis tools
@ -51,20 +54,20 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Do static analysis tasks * Do static analysis tasks
*/ */
public function analyze() public function analyze(): void
{ {
$this->prepare(); $this->prepare();
$this->lint(); $this->lint();
$this->phploc(TRUE); $this->phploc(TRUE);
$this->phpcs(TRUE); $this->phpcs(TRUE);
$this->dependencyReport(); $this->phpmd(TRUE);
$this->phpcpdReport(); $this->phpcpdReport();
} }
/** /**
* Run all tests, generate coverage, generate docs, generate code statistics * Run all tests, generate coverage, generate docs, generate code statistics
*/ */
public function build() public function build(): void
{ {
$this->analyze(); $this->analyze();
$this->coverage(); $this->coverage();
@ -74,11 +77,11 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Cleanup temporary files * Cleanup temporary files
*/ */
public function clean() public function clean(): void
{ {
// So the task doesn't complain, // So the task doesn't complain,
// make any 'missing' dirs to cleanup // make any 'missing' dirs to cleanup
array_map(function ($dir) { array_map(static function ($dir) {
if ( ! is_dir($dir)) if ( ! is_dir($dir))
{ {
`mkdir -p {$dir}`; `mkdir -p {$dir}`;
@ -92,19 +95,15 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Run unit tests and generate coverage reports * Run unit tests and generate coverage reports
*/ */
public function coverage() public function coverage(): void
{ {
$this->taskPhpUnit() $this->_run(['phpdbg -qrr -- vendor/bin/phpunit -c build']);
->configFile('build/phpunit.xml')
->run();
// $this->_run(['phpdbg -qrr -- vendor/bin/phpunit -c build']);
} }
/** /**
* Generate documentation with phpdox * Generate documentation with phpdox
*/ */
public function docs() public function docs(): void
{ {
$this->_run(['vendor/bin/phpdox']); $this->_run(['vendor/bin/phpdox']);
} }
@ -112,11 +111,11 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Verify that source files are valid * Verify that source files are valid
*/ */
public function lint() public function lint(): void
{ {
$files = $this->getAllSourceFiles(); $files = $this->getAllSourceFiles();
$chunks = array_chunk($files, (int)`getconf _NPROCESSORS_ONLN`); $chunks = array_chunk($files, (int)shell_exec('getconf _NPROCESSORS_ONLN'));
foreach($chunks as $chunk) foreach($chunks as $chunk)
{ {
@ -129,7 +128,7 @@ class RoboFile extends \Robo\Tasks {
* *
* @param bool $report - if true, generates reports instead of direct output * @param bool $report - if true, generates reports instead of direct output
*/ */
public function phpcs($report = FALSE) public function phpcs($report = FALSE): void
{ {
$dir = __DIR__; $dir = __DIR__;
@ -149,12 +148,36 @@ class RoboFile extends \Robo\Tasks {
$this->_run($cmd_parts); $this->_run($cmd_parts);
} }
public function phpmd($report = FALSE): void
{
$report_cmd_parts = [
'vendor/bin/phpmd',
'./src',
'xml',
'cleancode,codesize,controversial,design,naming,unusedcode',
'--exclude ParallelAPIRequest',
'--reportfile ./build/logs/phpmd.xml'
];
$normal_cmd_parts = [
'vendor/bin/phpmd',
'./src',
'ansi',
'cleancode,codesize,controversial,design,naming,unusedcode',
'--exclude ParallelAPIRequest'
];
$cmd_parts = ($report) ? $report_cmd_parts : $normal_cmd_parts;
$this->_run($cmd_parts);
}
/** /**
* Run the phploc tool * Run the phploc tool
* *
* @param bool $report - if true, generates reports instead of direct output * @param bool $report - if true, generates reports instead of direct output
*/ */
public function phploc($report = FALSE) public function phploc($report = FALSE): void
{ {
// Command for generating reports // Command for generating reports
$report_cmd_parts = [ $report_cmd_parts = [
@ -182,7 +205,7 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Create temporary directories * Create temporary directories
*/ */
public function prepare() public function prepare(): void
{ {
array_map([$this, '_mkdir'], $this->taskDirs); array_map([$this, '_mkdir'], $this->taskDirs);
} }
@ -190,7 +213,7 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Lint php files and run unit tests * Lint php files and run unit tests
*/ */
public function test() public function test(): void
{ {
$this->lint(); $this->lint();
$this->taskPhpUnit() $this->taskPhpUnit()
@ -202,7 +225,7 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Watches for file updates, and automatically runs appropriate actions * Watches for file updates, and automatically runs appropriate actions
*/ */
public function watch() public function watch(): void
{ {
$this->taskWatch() $this->taskWatch()
->monitor('composer.json', function() { ->monitor('composer.json', function() {
@ -217,27 +240,12 @@ class RoboFile extends \Robo\Tasks {
->run(); ->run();
} }
/**
* Create pdepend reports
*/
protected function dependencyReport()
{
$cmd_parts = [
'vendor/bin/pdepend',
'--jdepend-xml=build/logs/jdepend.xml',
'--jdepend-chart=build/pdepend/dependencies.svg',
'--overview-pyramid=build/pdepend/overview-pyramid.svg',
'src'
];
$this->_run($cmd_parts);
}
/** /**
* Get the total list of source files, including tests * Get the total list of source files, including tests
* *
* @return array * @return array
*/ */
protected function getAllSourceFiles() protected function getAllSourceFiles(): array
{ {
$files = array_merge( $files = array_merge(
glob_recursive('build/*.php'), glob_recursive('build/*.php'),
@ -256,7 +264,7 @@ class RoboFile extends \Robo\Tasks {
* *
* @param array $chunk * @param array $chunk
*/ */
protected function parallelLint(array $chunk) protected function parallelLint(array $chunk): void
{ {
$task = $this->taskParallelExec() $task = $this->taskParallelExec()
->timeout(5) ->timeout(5)
@ -273,7 +281,7 @@ class RoboFile extends \Robo\Tasks {
/** /**
* Generate copy paste detector report * Generate copy paste detector report
*/ */
protected function phpcpdReport() protected function phpcpdReport(): void
{ {
$cmd_parts = [ $cmd_parts = [
'vendor/bin/phpcpd', 'vendor/bin/phpcpd',
@ -290,7 +298,7 @@ class RoboFile extends \Robo\Tasks {
* @param array $cmd_parts - command arguments * @param array $cmd_parts - command arguments
* @param string $join_on - what to join the command arguments with * @param string $join_on - what to join the command arguments with
*/ */
protected function _run(array $cmd_parts, $join_on = ' ') protected function _run(array $cmd_parts, $join_on = ' '): void
{ {
$this->taskExec(implode($join_on, $cmd_parts))->run(); $this->taskExec(implode($join_on, $cmd_parts))->run();
} }

View File

@ -3,7 +3,7 @@
* *
* SQL Query Builder / Database Abstraction Layer * SQL Query Builder / Database Abstraction Layer
* *
* PHP version 7.2 * PHP version 7.3
* *
* @package Query * @package Query
* @author Timothy J. Warren <tim@timshomepage.net> * @author Timothy J. Warren <tim@timshomepage.net>

View File

@ -1,8 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<phpunit <phpunit
beStrictAboutOutputDuringTests="false"
colors="true" colors="true"
stopOnFailure="false" stopOnFailure="false"
bootstrap="./../tests/bootstrap.php"> bootstrap="./../tests/bootstrap.php"
verbose="true"
>
<filter> <filter>
<whitelist> <whitelist>
<directory suffix=".php">./../src/</directory> <directory suffix=".php">./../src/</directory>

View File

@ -1,60 +1,71 @@
{ {
"name":"aviat/query", "name": "aviat/query",
"type":"library", "type": "library",
"description":"Database Query Builder and Abstraction layer", "description": "Database Query Builder and Abstraction layer",
"keywords":[ "keywords": [
"database", "database",
"query builder", "query builder",
"codeigniter", "codeigniter",
"mysql", "mysql",
"sqlite", "sqlite",
"postgres", "postgres",
"pdo" "pdo"
], ],
"homepage":"https://git.timshomepage.net/aviat/Query", "homepage": "https://git.timshomepage.net/aviat/Query",
"license":"MIT", "license": "MIT",
"authors": [{ "authors": [
"name": "Timothy J. Warren", {
"email": "tim@timshomepage.net", "name": "Timothy J. Warren",
"homepage": "https://timshomepage.net", "email": "tim@timshomepage.net",
"role": "Developer" "homepage": "https://timshomepage.net",
}], "role": "Developer"
"require": {
"php": "^7.2",
"ext-pdo": "*"
},
"require-dev": {
"consolidation/robo": "^2.0.0",
"monolog/monolog": "^2.0.1",
"pdepend/pdepend": "^2.5",
"phploc/phploc": "^5.0",
"phpstan/phpstan": "^0.12.2",
"phpunit/phpunit": "^8.5",
"sebastian/phpcpd": "^4.1",
"simpletest/simpletest": "^1.1",
"squizlabs/php_codesniffer": "^3.0.0",
"theseer/phpdox": "^0.12.0"
},
"autoload": {
"psr-4": {
"Query\\": "src"
},
"files": ["src/common.php"]
},
"autoload-dev": {
"psr-4": {
"Query\\Tests\\": "tests"
}
},
"scripts": {
"build": "robo build",
"clean": "robo clean",
"coverage": "phpdbg -qrr -- vendor/bin/phpunit -c build",
"phpstan": "phpstan analyse -l 3 -c phpstan.neon src tests",
"test": "phpunit -c build --no-coverage"
},
"scripts-descriptions": {
"coverage": "Generate test coverage report",
"test": "Run unit tests"
} }
],
"config": {
"lock": false,
"platform": {
"php": "7.3"
}
},
"require": {
"php": ">=7.3",
"ext-pdo": "*"
},
"require-dev": {
"consolidation/robo": "^2.0.0",
"monolog/monolog": "^2.0.1",
"phploc/phploc": "^5.0",
"phpmd/phpmd": "^2.8",
"phpstan/phpstan": "^0.12.2",
"phpunit/phpunit": "^8.5",
"sebastian/phpcpd": "^4.1",
"simpletest/simpletest": "^1.1",
"squizlabs/php_codesniffer": "^3.0.0",
"theseer/phpdox": "*"
},
"autoload": {
"psr-4": {
"Query\\": "src"
},
"files": [
"src/common.php"
]
},
"autoload-dev": {
"psr-4": {
"Query\\Tests\\": "tests"
}
},
"scripts": {
"build": "robo build",
"clean": "robo clean",
"coverage": "phpdbg -qrr -- vendor/bin/phpunit -c build",
"pcov": "vendor/bin/phpunit -c build",
"phpstan": "phpstan analyse -l 3 -c phpstan.neon src tests",
"test": "phpunit -c build --no-coverage"
},
"scripts-descriptions": {
"coverage": "Generate test coverage report",
"test": "Run unit tests"
}
} }

View File

@ -78,24 +78,20 @@
</source> </source>
<!-- git vcs information --> <!-- git vcs information -->
<source type="git"> <!-- <source type="git">
<git binary="/usr/bin/git" /> <git binary="/usr/bin/git" />
<history enabled="true" limit="15" cache="${phpDox.project.workdir}/gitlog.xml" /> <history enabled="true" limit="15" cache="${phpDox.project.workdir}/gitlog.xml" />
</source> </source> -->
<!-- PHP Code Sniffer findings --> <!-- PHP Code Sniffer findings -->
<!-- <source type="checkstyle">
<source type="phpcs">
<file name="phpcs.xml" /> <file name="phpcs.xml" />
</source> </source>
-->
<!-- PHPMessDetector --> <!-- PHPMessDetector -->
<!--
<source type="pmd"> <source type="pmd">
<file name="pmd.xml" /> <file name="phpmd.xml" />
</source> </source>
-->
<!-- PHPUnit Coverage XML --> <!-- PHPUnit Coverage XML -->
<!-- <!--

View File

@ -15,6 +15,7 @@
*/ */
namespace Query; namespace Query;
use function is_array;
use function regexInArray; use function regexInArray;
use BadMethodCallException; use BadMethodCallException;
@ -46,6 +47,7 @@ use Query\Drivers\DriverInterface;
* @method getTriggers(): array | null * @method getTriggers(): array | null
* @method getTypes(): array | null * @method getTypes(): array | null
* @method getUtil(): \Query\Drivers\AbstractUtil * @method getUtil(): \Query\Drivers\AbstractUtil
* @method getVersion(): string
* @method getViews(): array | null * @method getViews(): array | null
* @method inTransaction(): bool * @method inTransaction(): bool
* @method lastInsertId(string $name = NULL): string * @method lastInsertId(string $name = NULL): string
@ -78,10 +80,16 @@ class QueryBuilder implements QueryBuilderInterface {
/** /**
* Whether to do only an explain on the query * Whether to do only an explain on the query
* @var boolean * @var bool
*/ */
protected $explain = FALSE; protected $explain = FALSE;
/**
* Whether to return data from a modification query
* @var bool
*/
protected $returning = FALSE;
/** /**
* The current database driver * The current database driver
* @var DriverInterface * @var DriverInterface
@ -142,7 +150,7 @@ class QueryBuilder implements QueryBuilderInterface {
{ {
if (method_exists($this->driver, $name)) if (method_exists($this->driver, $name))
{ {
return \call_user_func_array([$this->driver, $name], $params); return $this->driver->$name(...$params);
} }
throw new BadMethodCallException('Method does not exist'); throw new BadMethodCallException('Method does not exist');
@ -180,11 +188,11 @@ class QueryBuilder implements QueryBuilderInterface {
unset($fieldsArray); unset($fieldsArray);
// Join the strings back together // Join the strings back together
for($i = 0, $c = count($safeArray); $i < $c; $i++) foreach ($safeArray as $i => $iValue)
{ {
if (\is_array($safeArray[$i])) if (is_array($iValue))
{ {
$safeArray[$i] = implode(' AS ', $safeArray[$i]); $safeArray[$i] = implode(' AS ', $iValue);
} }
} }
@ -250,12 +258,21 @@ class QueryBuilder implements QueryBuilderInterface {
} }
/** /**
* @todo implement * Add a 'returning' clause to an insert,update, or delete query
*
* @param string $fields * @param string $fields
* @return $this * @return $this
*/ */
public function returning(string $fields = '*'): QueryBuilderInterface public function returning(string $fields = ''): QueryBuilderInterface
{ {
$this->returning = TRUE;
// Re-use the string select field for generating the returning type clause
if ($fields !== '')
{
return $this->select($fields);
}
return $this; return $this;
} }
@ -762,7 +779,7 @@ class QueryBuilder implements QueryBuilderInterface {
$this->from($table); $this->from($table);
} }
$result = $this->_run('get', $table, NULL, NULL, $reset); $result = $this->_run(QueryType::SELECT, $table, NULL, NULL, $reset);
$rows = $result->fetchAll(); $rows = $result->fetchAll();
return (int) count($rows); return (int) count($rows);
@ -782,7 +799,7 @@ class QueryBuilder implements QueryBuilderInterface {
$this->set($data); $this->set($data);
} }
return $this->_run('insert', $table); return $this->_run(QueryType::INSERT, $table);
} }
/** /**
@ -797,6 +814,8 @@ class QueryBuilder implements QueryBuilderInterface {
// Get the generated values and sql string // Get the generated values and sql string
[$sql, $data] = $this->driver->insertBatch($table, $data); [$sql, $data] = $this->driver->insertBatch($table, $data);
return $sql !== NULL return $sql !== NULL
? $this->_run('', $table, $sql, $data) ? $this->_run('', $table, $sql, $data)
: NULL; : NULL;
@ -816,7 +835,7 @@ class QueryBuilder implements QueryBuilderInterface {
$this->set($data); $this->set($data);
} }
return $this->_run('update', $table); return $this->_run(QueryType::UPDATE, $table);
} }
/** /**
@ -857,7 +876,7 @@ class QueryBuilder implements QueryBuilderInterface {
$this->where($where); $this->where($where);
} }
return $this->_run('delete', $table); return $this->_run(QueryType::DELETE, $table);
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -879,7 +898,7 @@ class QueryBuilder implements QueryBuilderInterface {
$this->from($table); $this->from($table);
} }
return $this->_getCompile('select', $table, $reset); return $this->_getCompile(QueryType::SELECT, $table, $reset);
} }
/** /**
@ -891,7 +910,7 @@ class QueryBuilder implements QueryBuilderInterface {
*/ */
public function getCompiledInsert(string $table, bool $reset=TRUE): string public function getCompiledInsert(string $table, bool $reset=TRUE): string
{ {
return $this->_getCompile('insert', $table, $reset); return $this->_getCompile(QueryType::INSERT, $table, $reset);
} }
/** /**
@ -903,7 +922,7 @@ class QueryBuilder implements QueryBuilderInterface {
*/ */
public function getCompiledUpdate(string $table='', bool $reset=TRUE): string public function getCompiledUpdate(string $table='', bool $reset=TRUE): string
{ {
return $this->_getCompile('update', $table, $reset); return $this->_getCompile(QueryType::UPDATE, $table, $reset);
} }
/** /**
@ -915,7 +934,7 @@ class QueryBuilder implements QueryBuilderInterface {
*/ */
public function getCompiledDelete(string $table='', bool $reset=TRUE): string public function getCompiledDelete(string $table='', bool $reset=TRUE): string
{ {
return $this->_getCompile('delete', $table, $reset); return $this->_getCompile(QueryType::DELETE, $table, $reset);
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -931,6 +950,7 @@ class QueryBuilder implements QueryBuilderInterface {
{ {
$this->state = new State(); $this->state = new State();
$this->explain = FALSE; $this->explain = FALSE;
$this->returning = FALSE;
} }
/** /**
@ -1204,7 +1224,7 @@ class QueryBuilder implements QueryBuilderInterface {
*/ */
protected function _appendQuery(array $values, string $sql, int $totalTime): void protected function _appendQuery(array $values, string $sql, int $totalTime): void
{ {
$evals = \is_array($values) ? $values : []; $evals = is_array($values) ? $values : [];
$esql = str_replace('?', '%s', $sql); $esql = str_replace('?', '%s', $sql);
// Quote string values // Quote string values
@ -1240,29 +1260,29 @@ class QueryBuilder implements QueryBuilderInterface {
* @param string $table * @param string $table
* @return string * @return string
*/ */
protected function _compileType(string $type='', string $table=''): string protected function _compileType(string $type=QueryType::SELECT, string $table=''): string
{ {
$setArrayKeys = $this->state->getSetArrayKeys(); $setArrayKeys = $this->state->getSetArrayKeys();
switch($type) switch($type)
{ {
case 'insert': case QueryType::INSERT:
$paramCount = count($setArrayKeys); $paramCount = count($setArrayKeys);
$params = array_fill(0, $paramCount, '?'); $params = array_fill(0, $paramCount, '?');
$sql = "INSERT INTO {$table} (" $sql = "INSERT INTO {$table} ("
. implode(',', $setArrayKeys) . implode(',', $setArrayKeys)
. ")\nVALUES (".implode(',', $params).')'; . ")\nVALUES (".implode(',', $params).')';
break; break;
case 'update': case QueryType::UPDATE:
$setString = $this->state->getSetString(); $setString = $this->state->getSetString();
$sql = "UPDATE {$table}\nSET {$setString}"; $sql = "UPDATE {$table}\nSET {$setString}";
break; break;
case 'delete': case QueryType::DELETE:
$sql = "DELETE FROM {$table}"; $sql = "DELETE FROM {$table}";
break; break;
// Get queries case QueryType::SELECT:
default: default:
$fromString = $this->state->getFromString(); $fromString = $this->state->getFromString();
$selectString = $this->state->getSelectString(); $selectString = $this->state->getSelectString();
@ -1275,7 +1295,7 @@ class QueryBuilder implements QueryBuilderInterface {
// Replace the star with the selected fields // Replace the star with the selected fields
$sql = str_replace('*', $selectString, $sql); $sql = str_replace('*', $selectString, $sql);
} }
break; break;
} }
return $sql; return $sql;
@ -1305,7 +1325,7 @@ class QueryBuilder implements QueryBuilderInterface {
{ {
$func = 'get' . ucFirst($clause); $func = 'get' . ucFirst($clause);
$param = $this->state->$func(); $param = $this->state->$func();
if (\is_array($param)) if (is_array($param))
{ {
foreach($param as $q) foreach($param as $q)
{ {
@ -1325,6 +1345,9 @@ class QueryBuilder implements QueryBuilderInterface {
$sql = $this->driver->getSql()->limit($sql, $limit, $this->state->getOffset()); $sql = $this->driver->getSql()->limit($sql, $limit, $this->state->getOffset());
} }
// Set the returning clause, if applicable
$sql = $this->_compileReturning($sql, $type);
// See if the query plan, rather than the // See if the query plan, rather than the
// query data should be returned // query data should be returned
if ($this->explain === TRUE) if ($this->explain === TRUE)
@ -1334,4 +1357,51 @@ class QueryBuilder implements QueryBuilderInterface {
return $sql; return $sql;
} }
/**
* Generate returning clause of query
*
* @param string $sql
* @param string $type
* @return string
*/
protected function _compileReturning(string $sql, string $type): string
{
if ($this->returning === FALSE)
{
return $sql;
}
$rawSelect = $this->state->getSelectString();
$selectString = ($rawSelect === '') ? '*' : $rawSelect;
$returningSQL = $this->driver->returning($sql, $selectString);
if ($returningSQL === $sql)
{
// If the driver doesn't support the returning clause, it returns the original query.
// Fake the same result with a transaction and a select query
if ( ! $this->inTransaction())
{
$this->beginTransaction();
}
// Generate the appropriate select query for the returning clause fallback
switch ($type)
{
case QueryType::INSERT:
// @TODO figure out a good response for insert query
break;
case QueryType::UPDATE:
// @TODO figure out a good response for update query
break;
case QueryType::DELETE:
// @TODO Figure out a good response for delete query
break;
}
}
return $returningSQL;
}
} }

View File

@ -42,6 +42,7 @@ use PDOStatement;
* @method getTriggers(): array | null * @method getTriggers(): array | null
* @method getTypes(): array | null * @method getTypes(): array | null
* @method getUtil(): \Query\Drivers\AbstractUtil * @method getUtil(): \Query\Drivers\AbstractUtil
* @method getVersion(): string
* @method getViews(): array | null * @method getViews(): array | null
* @method inTransaction(): bool * @method inTransaction(): bool
* @method lastInsertId(string $name = NULL): string * @method lastInsertId(string $name = NULL): string
@ -106,6 +107,14 @@ interface QueryBuilderInterface {
*/ */
public function selectSum(string $field, $as=FALSE): self; public function selectSum(string $field, $as=FALSE): self;
/**
* Add a 'returning' clause to an insert,update, or delete query
*
* @param string $fields
* @return self
*/
public function returning(string $fields = '*'): self;
/** /**
* Adds the 'distinct' keyword to a query * Adds the 'distinct' keyword to a query
* *

View File

@ -17,6 +17,25 @@ namespace Query;
/** /**
* Query builder state * 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 getLimit(): int
* @method getOffset()
* @method getQueryMap(): array
* @method getHavingMap(): array
*
* @method setSelectString(string): self
* @method setFromString(string): self
* @method setSetString(string): self
*/ */
class State { class State {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -124,22 +143,28 @@ class State {
*/ */
protected $havingMap = []; protected $havingMap = [];
/** public function __call(string $name, array $arguments)
* @param string $str
* @return State
*/
public function setSelectString(string $str): self
{ {
$this->selectString = $str; if (strpos($name, 'get', 0) === 0)
return $this; {
} $maybeProp = lcfirst(substr($name, 3));
if (isset($this->$maybeProp))
{
return $this->$maybeProp;
}
}
/** if (strpos($name, 'set', 0) === 0)
* @return string {
*/ $maybeProp = lcfirst(substr($name, 3));
public function getSelectString(): string if (isset($this->$maybeProp))
{ {
return $this->selectString; $this->$maybeProp = $arguments[0];
return $this;
}
}
return NULL;
} }
/** /**
@ -152,50 +177,6 @@ class State {
return $this; return $this;
} }
/**
* @return string
*/
public function getFromString(): string
{
return $this->fromString;
}
/**
* @param string $fromString
* @return State
*/
public function setFromString(string $fromString): self
{
$this->fromString = $fromString;
return $this;
}
/**
* @return string
*/
public function getSetString(): string
{
return $this->setString;
}
/**
* @param string $setString
* @return State
*/
public function setSetString(string $setString): self
{
$this->setString = $setString;
return $this;
}
/**
* @return string
*/
public function getOrderString(): string
{
return $this->orderString;
}
/** /**
* @param string $orderString * @param string $orderString
* @return State * @return State
@ -206,14 +187,6 @@ class State {
return $this; return $this;
} }
/**
* @return string
*/
public function getGroupString(): string
{
return $this->groupString;
}
/** /**
* @param string $groupString * @param string $groupString
* @return State * @return State
@ -224,14 +197,6 @@ class State {
return $this; return $this;
} }
/**
* @return array
*/
public function getSetArrayKeys(): array
{
return $this->setArrayKeys;
}
/** /**
* @param array $setArrayKeys * @param array $setArrayKeys
* @return State * @return State
@ -252,14 +217,6 @@ class State {
return $this; return $this;
} }
/**
* @return array
*/
public function getOrderArray(): array
{
return $this->orderArray;
}
/** /**
* @param string $key * @param string $key
* @param mixed $orderArray * @param mixed $orderArray
@ -271,14 +228,6 @@ class State {
return $this; return $this;
} }
/**
* @return array
*/
public function getGroupArray(): array
{
return $this->groupArray;
}
/** /**
* @param array $groupArray * @param array $groupArray
* @return State * @return State
@ -299,14 +248,6 @@ class State {
return $this; return $this;
} }
/**
* @return array
*/
public function getValues(): array
{
return $this->values;
}
/** /**
* @param array $values * @param array $values
* @return State * @return State
@ -317,14 +258,6 @@ class State {
return $this; return $this;
} }
/**
* @return array
*/
public function getWhereValues(): array
{
return $this->whereValues;
}
/** /**
* @param mixed $val * @param mixed $val
* @return State * @return State
@ -345,14 +278,6 @@ class State {
return $this; return $this;
} }
/**
* @return int
*/
public function getLimit(): ?int
{
return $this->limit;
}
/** /**
* @param int $limit * @param int $limit
* @return State * @return State
@ -363,14 +288,6 @@ class State {
return $this; return $this;
} }
/**
* @return string|false
*/
public function getOffset()
{
return $this->offset;
}
/** /**
* @param string|false $offset * @param string|false $offset
* @return State * @return State
@ -381,14 +298,6 @@ class State {
return $this; return $this;
} }
/**
* @return array
*/
public function getQueryMap(): array
{
return $this->queryMap;
}
/** /**
* Add an additional set of mapping pairs to a internal map * Add an additional set of mapping pairs to a internal map
* *
@ -407,14 +316,6 @@ class State {
return $this; return $this;
} }
/**
* @return array
*/
public function getHavingMap(): array
{
return $this->havingMap;
}
/** /**
* @param array $item * @param array $item
* @return State * @return State

View File

@ -557,6 +557,24 @@ abstract class BaseQueryBuilderTest extends TestCase {
$this->assertIsA($query, 'PDOStatement'); $this->assertIsA($query, 'PDOStatement');
} }
public function testInsertReturning(): void
{
$query = self::$db->set('id', 99)
->set('key', 84)
->set('val', 120)
->returning()
->insert('test');
$row = $query->fetch(PDO::FETCH_ASSOC);
$this->assertIsA($query, 'PDOStatement');
$this->assertEqual([
'id' => 99,
'key' => 84,
'val' => 120,
], $row);
}
public function testInsertBatch(): void public function testInsertBatch(): void
{ {
$data = [ $data = [
@ -594,6 +612,33 @@ abstract class BaseQueryBuilderTest extends TestCase {
$this->assertIsA($query, 'PDOStatement'); $this->assertIsA($query, 'PDOStatement');
} }
public function testUpdateReturning(): void
{
// Make sure the id exists so there isn't an error for that reason
self::$db->insert('test', [
'id' => 7,
'key' => 'kjsgarik yugasdikh',
'val' => 'alkfiasghdfdhs',
]);
$query = self::$db->where('id', 7)
->set([
'id' => 7,
'key' => 'gogle',
'val' => 'non-word'
])
->returning('key')
->update('test');
$this->assertIsA($query, 'PDOStatement');
$row = $query->fetch(PDO::FETCH_ASSOC);
$this->assertEqual([
'key' => 'gogle',
], $row, json_encode($query->errorInfo()));
// $this->assertNotEqual(FALSE, $row, $query->errorInfo());
}
public function testUpdateBatchNull(): void public function testUpdateBatchNull(): void
{ {
$query = self::$db->updateBatch('test', [], ''); $query = self::$db->updateBatch('test', [], '');
@ -652,6 +697,13 @@ abstract class BaseQueryBuilderTest extends TestCase {
$this->assertIsA($query, 'PDOStatement'); $this->assertIsA($query, 'PDOStatement');
} }
public function testDeleteReturning():void
{
$query = self::$db->returning()->delete('test', ['id' => 99]);
$this->assertIsA($query, 'PDOStatement');
}
public function testDeleteWithMultipleWhereValues(): void public function testDeleteWithMultipleWhereValues(): void
{ {
$query = self::$db->delete('test', [ $query = self::$db->delete('test', [

View File

@ -8,7 +8,7 @@
* *
* @package Query * @package Query
* @author Timothy J. Warren <tim@timshomepage.net> * @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2012 - 2020 Timothy J. Warren * @copyright 2012 - 2019 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 3.0.0 * @version 3.0.0
@ -72,4 +72,14 @@ class MySQLQueryBuilderTest extends BaseQueryBuilderTest {
$this->assertTrue(count(array_keys($res[0])) > 1); $this->assertTrue(count(array_keys($res[0])) > 1);
$this->assertTrue(array_key_exists('table', $res[0])); $this->assertTrue(array_key_exists('table', $res[0]));
} }
public function testInsertReturning(): void
{
$this->markTestSkipped();
}
public function testUpdateReturning(): void
{
$this->markTestSkipped();
}
} }

View File

@ -8,7 +8,7 @@
* *
* @package Query * @package Query
* @author Timothy J. Warren <tim@timshomepage.net> * @author Timothy J. Warren <tim@timshomepage.net>
* @copyright 2012 - 2020 Timothy J. Warren * @copyright 2012 - 2019 Timothy J. Warren
* @license http://www.opensource.org/licenses/mit-license.html MIT License * @license http://www.opensource.org/licenses/mit-license.html MIT License
* @link https://git.timshomepage.net/aviat/Query * @link https://git.timshomepage.net/aviat/Query
* @version 3.0.0 * @version 3.0.0
@ -113,4 +113,14 @@ use Query\Tests\BaseQueryBuilderTest;
$this->assertTrue(FALSE); $this->assertTrue(FALSE);
} }
} }
public function testInsertReturning(): void
{
$this->markTestSkipped();
}
public function testUpdateReturning(): void
{
$this->markTestSkipped();
}
} }