SQL expression rewrite, Pagination, some frontend stuff
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
namespace Core\Driver\SQL\Column;
|
||||
|
||||
use Core\Driver\SQL\Expression\Expression;
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class Column extends Expression {
|
||||
|
||||
@@ -20,4 +21,7 @@ class Column extends Expression {
|
||||
public function notNull(): bool { return !$this->nullable; }
|
||||
public function getDefaultValue() { return $this->defaultValue; }
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
return $sql->columnName($this->name);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Core\Driver\SQL\Condition;
|
||||
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class Compare extends Condition {
|
||||
|
||||
private string $operator;
|
||||
@@ -18,4 +20,16 @@ class Compare extends Condition {
|
||||
public function getValue() { return $this->value; }
|
||||
public function getOperator(): string { return $this->operator; }
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
|
||||
if ($this->value === null) {
|
||||
if ($this->operator === "=") {
|
||||
return $sql->columnName($this->column) . " IS NULL";
|
||||
} else if ($this->operator === "!=") {
|
||||
return $sql->columnName($this->column) . " IS NOT NULL";
|
||||
}
|
||||
}
|
||||
|
||||
return $sql->columnName($this->column) . $this->operator . $sql->addValue($this->value, $params);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Core\Driver\SQL\Condition;
|
||||
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class CondAnd extends Condition {
|
||||
|
||||
private array $conditions;
|
||||
@@ -11,4 +13,12 @@ class CondAnd extends Condition {
|
||||
}
|
||||
|
||||
public function getConditions(): array { return $this->conditions; }
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
$conditions = array();
|
||||
foreach($this->getConditions() as $cond) {
|
||||
$conditions[] = $sql->addValue($cond, $params);
|
||||
}
|
||||
return "(" . implode(" AND ", $conditions) . ")";
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Core\Driver\SQL\Condition;
|
||||
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class CondBool extends Condition {
|
||||
|
||||
private $value;
|
||||
@@ -12,4 +14,11 @@ class CondBool extends Condition {
|
||||
|
||||
public function getValue() { return $this->value; }
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
if (is_string($this->value)) {
|
||||
return $sql->columnName($this->value);
|
||||
} else {
|
||||
return $sql->addValue($this->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace Core\Driver\SQL\Condition;
|
||||
|
||||
use Core\Driver\SQL\Query\Select;
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class CondIn extends Condition {
|
||||
|
||||
private $needle;
|
||||
@@ -14,4 +17,25 @@ class CondIn extends Condition {
|
||||
|
||||
public function getNeedle() { return $this->needle; }
|
||||
public function getHaystack() { return $this->haystack; }
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
|
||||
$haystack = $this->getHaystack();
|
||||
if (is_array($haystack)) {
|
||||
$values = array();
|
||||
foreach ($haystack as $value) {
|
||||
$values[] = $sql->addValue($value, $params);
|
||||
}
|
||||
|
||||
$values = implode(",", $values);
|
||||
$values = "($values)";
|
||||
} else if($haystack instanceof Select) {
|
||||
$values = $haystack->build($params);
|
||||
} else {
|
||||
$sql->getLogger()->error("Unsupported in-expression value: " . get_class($haystack));
|
||||
return false;
|
||||
}
|
||||
|
||||
return $sql->addValue($this->needle, $params) . " IN $values";
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Core\Driver\SQL\Condition;
|
||||
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
abstract class CondKeyword extends Condition {
|
||||
|
||||
private $leftExpression;
|
||||
@@ -17,4 +19,11 @@ abstract class CondKeyword extends Condition {
|
||||
public function getLeftExp() { return $this->leftExpression; }
|
||||
public function getRightExp() { return $this->rightExpression; }
|
||||
public function getKeyword(): string { return $this->keyword; }
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
$keyword = $this->getKeyword();
|
||||
$left = $sql->addValue($this->getLeftExp(), $params);
|
||||
$right = $sql->addValue($this->getRightExp(), $params);
|
||||
return "$left $keyword $right";
|
||||
}
|
||||
}
|
||||
@@ -7,4 +7,5 @@ class CondLike extends CondKeyword {
|
||||
public function __construct($leftExpression, $rightExpression) {
|
||||
parent::__construct("LIKE", $leftExpression, $rightExpression);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,15 +2,21 @@
|
||||
|
||||
namespace Core\Driver\SQL\Condition;
|
||||
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class CondNot extends Condition {
|
||||
|
||||
private $expression; // string or condition
|
||||
private mixed $expression; // string or condition
|
||||
|
||||
public function __construct($expression) {
|
||||
public function __construct(mixed $expression) {
|
||||
$this->expression = $expression;
|
||||
}
|
||||
|
||||
public function getExpression() {
|
||||
return $this->expression;
|
||||
public function getExpression(SQL $sql, array &$params): string {
|
||||
if (is_string($this->expression)) {
|
||||
return "NOT " . $sql->columnName($this->expression);
|
||||
} else {
|
||||
return "NOT " . $sql->addValue($this->expression, $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Core\Driver\SQL\Condition;
|
||||
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class CondNull extends Condition {
|
||||
|
||||
private string $column;
|
||||
@@ -11,4 +13,8 @@ class CondNull extends Condition {
|
||||
}
|
||||
|
||||
public function getColumn(): string { return $this->column; }
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
return $sql->columnName($this->getColumn()) . " IS NULL";
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Core\Driver\SQL\Condition;
|
||||
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class CondOr extends Condition {
|
||||
|
||||
private array $conditions;
|
||||
@@ -11,4 +13,12 @@ class CondOr extends Condition {
|
||||
}
|
||||
|
||||
public function getConditions(): array { return $this->conditions; }
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
$conditions = array();
|
||||
foreach($this->getConditions() as $cond) {
|
||||
$conditions[] = $sql->addValue($cond, $params);
|
||||
}
|
||||
return "(" . implode(" OR ", $conditions) . ")";
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,23 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Core\Driver\SQL\Condition;
|
||||
|
||||
|
||||
use Core\Driver\SQL\Query\Select;
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class Exists extends Condition {
|
||||
|
||||
class Exists extends Condition
|
||||
{
|
||||
private Select $subQuery;
|
||||
|
||||
public function __construct(Select $subQuery)
|
||||
{
|
||||
public function __construct(Select $subQuery) {
|
||||
$this->subQuery = $subQuery;
|
||||
}
|
||||
|
||||
public function getSubQuery(): Select
|
||||
{
|
||||
public function getSubQuery(): Select {
|
||||
return $this->subQuery;
|
||||
}
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
return "EXISTS(" .$this->getSubQuery()->build($params) . ")";
|
||||
}
|
||||
}
|
||||
32
Core/Driver/SQL/Expression/Alias.class.php
Normal file
32
Core/Driver/SQL/Expression/Alias.class.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Driver\SQL\Expression;
|
||||
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class Alias extends Expression {
|
||||
|
||||
private mixed $value;
|
||||
private string $alias;
|
||||
|
||||
public function __construct(mixed $value, string $alias) {
|
||||
$this->value = $value;
|
||||
$this->alias = $alias;
|
||||
}
|
||||
|
||||
public function getAlias(): string {
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function getValue(): mixed {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
protected function addValue(SQL $sql, array &$params): string {
|
||||
return $sql->addValue($this->value, $params);
|
||||
}
|
||||
|
||||
public function getExpression(SQL $sql, array &$params): string {
|
||||
return $this->addValue($sql, $params) . " AS " . $this->getAlias();
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Core\Driver\SQL\Expression;
|
||||
|
||||
use Core\Driver\SQL\Condition\Condition;
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class CaseWhen extends Expression {
|
||||
|
||||
@@ -20,4 +21,13 @@ class CaseWhen extends Expression {
|
||||
public function getTrueCase() { return $this->trueCase; }
|
||||
public function getFalseCase() { return $this->falseCase; }
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
$condition = $sql->buildCondition($this->getCondition(), $params);
|
||||
|
||||
// psql requires constant values here
|
||||
$trueCase = $sql->addValue($this->getTrueCase(), $params, true);
|
||||
$falseCase = $sql->addValue($this->getFalseCase(), $params, true);
|
||||
|
||||
return "CASE WHEN $condition THEN $trueCase ELSE $falseCase END";
|
||||
}
|
||||
}
|
||||
24
Core/Driver/SQL/Expression/Count.class.php
Normal file
24
Core/Driver/SQL/Expression/Count.class.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Driver\SQL\Expression;
|
||||
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class Count extends Alias {
|
||||
public function __construct(mixed $value = "*", string $alias = "count") {
|
||||
parent::__construct($value, $alias);
|
||||
}
|
||||
|
||||
function addValue(SQL $sql, array &$params): string {
|
||||
$value = $this->getValue();
|
||||
if (is_string($value)) {
|
||||
if ($value === "*") {
|
||||
return "COUNT(*)";
|
||||
} else {
|
||||
return "COUNT(" . $sql->columnName($value) . ")";
|
||||
}
|
||||
} else {
|
||||
return "COUNT(" . $sql->addValue($value, $params) . ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
namespace Core\Driver\SQL\Expression;
|
||||
|
||||
use Core\Driver\SQL\MySQL;
|
||||
use Core\Driver\SQL\PostgreSQL;
|
||||
use Core\Driver\SQL\SQL;
|
||||
use Exception;
|
||||
|
||||
class CurrentTimeStamp extends Expression {
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
if ($sql instanceof MySQL) {
|
||||
return "NOW()";
|
||||
} else if ($sql instanceof PostgreSQL) {
|
||||
return "CURRENT_TIMESTAMP";
|
||||
} else {
|
||||
throw new Exception("CurrentTimeStamp Not implemented for driver type: " . get_class($sql));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
namespace Core\Driver\SQL\Expression;
|
||||
|
||||
use Core\Driver\SQL\Column\Column;
|
||||
use Core\Driver\SQL\MySQL;
|
||||
use Core\Driver\SQL\PostgreSQL;
|
||||
use Core\Driver\SQL\SQL;
|
||||
use Core\External\PHPMailer\Exception;
|
||||
|
||||
class DateAdd extends Expression {
|
||||
|
||||
private Expression $lhs;
|
||||
@@ -18,4 +24,26 @@ class DateAdd extends Expression {
|
||||
public function getRHS(): Expression { return $this->rhs; }
|
||||
public function getUnit(): string { return $this->unit; }
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
if ($sql instanceof MySQL) {
|
||||
$lhs = $sql->addValue($this->getLHS(), $params);
|
||||
$rhs = $sql->addValue($this->getRHS(), $params);
|
||||
$unit = $this->getUnit();
|
||||
return "DATE_ADD($lhs, INTERVAL $rhs $unit)";
|
||||
} else if ($sql instanceof PostgreSQL) {
|
||||
$lhs = $sql->addValue($this->getLHS(), $params);
|
||||
$rhs = $sql->addValue($this->getRHS(), $params);
|
||||
$unit = $this->getUnit();
|
||||
|
||||
if ($this->getRHS() instanceof Column) {
|
||||
$rhs = "$rhs * INTERVAL '1 $unit'";
|
||||
} else {
|
||||
$rhs = "$rhs $unit";
|
||||
}
|
||||
|
||||
return "$lhs - $rhs";
|
||||
} else {
|
||||
throw new Exception("DateAdd Not implemented for driver type: " . get_class($sql));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
namespace Core\Driver\SQL\Expression;
|
||||
|
||||
use Core\Driver\SQL\Column\Column;
|
||||
use Core\Driver\SQL\MySQL;
|
||||
use Core\Driver\SQL\PostgreSQL;
|
||||
use Core\Driver\SQL\SQL;
|
||||
use Core\External\PHPMailer\Exception;
|
||||
|
||||
class DateSub extends Expression {
|
||||
|
||||
private Expression $lhs;
|
||||
@@ -18,4 +24,26 @@ class DateSub extends Expression {
|
||||
public function getRHS(): Expression { return $this->rhs; }
|
||||
public function getUnit(): string { return $this->unit; }
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
if ($sql instanceof MySQL) {
|
||||
$lhs = $sql->addValue($this->getLHS(), $params);
|
||||
$rhs = $sql->addValue($this->getRHS(), $params);
|
||||
$unit = $this->getUnit();
|
||||
return "DATE_SUB($lhs, INTERVAL $rhs $unit)";
|
||||
} else if ($sql instanceof PostgreSQL) {
|
||||
$lhs = $sql->addValue($this->getLHS(), $params);
|
||||
$rhs = $sql->addValue($this->getRHS(), $params);
|
||||
$unit = $this->getUnit();
|
||||
|
||||
if ($this->getRHS() instanceof Column) {
|
||||
$rhs = "$rhs * INTERVAL '1 $unit'";
|
||||
} else {
|
||||
$rhs = "$rhs $unit";
|
||||
}
|
||||
|
||||
return "$lhs - $rhs";
|
||||
} else {
|
||||
throw new Exception("DateSub Not implemented for driver type: " . get_class($sql));
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Core/Driver/SQL/Expression/Distinct.class.php
Normal file
22
Core/Driver/SQL/Expression/Distinct.class.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace Core\Driver\SQL\Expression;
|
||||
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class Distinct extends Expression {
|
||||
|
||||
private mixed $value;
|
||||
|
||||
public function __construct(mixed $value) {
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getValue(): mixed {
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
return "DISTINCT(" . $sql->addValue($this->getValue(), $params) . ")";
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
namespace Core\Driver\SQL\Expression;
|
||||
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
abstract class Expression {
|
||||
|
||||
abstract function getExpression(SQL $sql, array &$params): string;
|
||||
|
||||
}
|
||||
@@ -2,17 +2,29 @@
|
||||
|
||||
namespace Core\Driver\SQL\Expression;
|
||||
|
||||
use Core\Driver\SQL\Column\Column;
|
||||
use Core\Driver\SQL\MySQL;
|
||||
use Core\Driver\SQL\PostgreSQL;
|
||||
use Core\Driver\SQL\SQL;
|
||||
use Exception;
|
||||
|
||||
class JsonArrayAgg extends Expression {
|
||||
|
||||
private $value;
|
||||
private string $alias;
|
||||
private mixed $value;
|
||||
|
||||
public function __construct($value, string $alias) {
|
||||
public function __construct(mixed $value) {
|
||||
$this->value = $value;
|
||||
$this->alias = $alias;
|
||||
}
|
||||
|
||||
public function getValue() { return $this->value; }
|
||||
public function getAlias(): string { return $this->alias; }
|
||||
|
||||
public function getExpression(SQL $sql, array &$params): string {
|
||||
$value = is_string($this->value) ? new Column($this->value) : $this->value;
|
||||
$value = $sql->addValue($value, $params);
|
||||
if ($sql instanceof MySQL) {
|
||||
return "JSON_ARRAYAGG($value)";
|
||||
} else if ($sql instanceof PostgreSQL) {
|
||||
return "JSON_AGG($value)";
|
||||
} else {
|
||||
throw new Exception("JsonArrayAgg not implemented for driver type: " . get_class($sql));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,17 +2,15 @@
|
||||
|
||||
namespace Core\Driver\SQL\Expression;
|
||||
|
||||
class Sum extends Expression {
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
private $value;
|
||||
private string $alias;
|
||||
class Sum extends Alias {
|
||||
|
||||
public function __construct($value, string $alias) {
|
||||
$this->value = $value;
|
||||
$this->alias = $alias;
|
||||
public function __construct(mixed $value, string $alias) {
|
||||
parent::__construct($value, $alias);
|
||||
}
|
||||
|
||||
public function getValue() { return $this->value; }
|
||||
public function getAlias(): string { return $this->alias; }
|
||||
|
||||
protected function addValue(SQL $sql, array &$params): string {
|
||||
return "SUM(" . $sql->addValue($this->getValue(), $params) . ")";
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace Core\Driver\SQL;
|
||||
|
||||
use Core\Driver\SQL\Expression\Expression;
|
||||
|
||||
// Unsafe sql
|
||||
class Keyword extends Expression {
|
||||
|
||||
private string $value;
|
||||
@@ -14,4 +15,7 @@ class Keyword extends Expression {
|
||||
|
||||
public function getValue(): string { return $this->value; }
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
return $this->value;
|
||||
}
|
||||
}
|
||||
@@ -17,10 +17,7 @@ use Core\Driver\SQL\Column\JsonColumn;
|
||||
|
||||
use Core\Driver\SQL\Expression\Add;
|
||||
use Core\Driver\SQL\Expression\CurrentTimeStamp;
|
||||
use Core\Driver\SQL\Expression\DateAdd;
|
||||
use Core\Driver\SQL\Expression\DateSub;
|
||||
use Core\Driver\SQL\Expression\Expression;
|
||||
use Core\Driver\SQL\Expression\JsonArrayAgg;
|
||||
use Core\Driver\SQL\Query\CreateProcedure;
|
||||
use Core\Driver\SQL\Query\CreateTrigger;
|
||||
use Core\Driver\SQL\Query\Query;
|
||||
@@ -337,14 +334,8 @@ class MySQL extends SQL {
|
||||
}
|
||||
|
||||
public function addValue($val, &$params = NULL, bool $unsafe = false) {
|
||||
if ($val instanceof Keyword) {
|
||||
return $val->getValue();
|
||||
} else if ($val instanceof CurrentColumn) {
|
||||
return $val->getName();
|
||||
} else if ($val instanceof Column) {
|
||||
return $this->columnName($val->getName());
|
||||
} else if ($val instanceof Expression) {
|
||||
return $this->createExpression($val, $params);
|
||||
if ($val instanceof Expression) {
|
||||
return $val->getExpression($this, $params);
|
||||
} else {
|
||||
if ($unsafe) {
|
||||
return $this->getUnsafeValue($val);
|
||||
@@ -460,24 +451,6 @@ class MySQL extends SQL {
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
protected function createExpression(Expression $exp, array &$params): ?string {
|
||||
if ($exp instanceof DateAdd || $exp instanceof DateSub) {
|
||||
$lhs = $this->addValue($exp->getLHS(), $params);
|
||||
$rhs = $this->addValue($exp->getRHS(), $params);
|
||||
$unit = $exp->getUnit();
|
||||
$dateFunction = ($exp instanceof DateAdd ? "DATE_ADD" : "DATE_SUB");
|
||||
return "$dateFunction($lhs, INTERVAL $rhs $unit)";
|
||||
} else if ($exp instanceof CurrentTimeStamp) {
|
||||
return "NOW()";
|
||||
} else if ($exp instanceof JsonArrayAgg) {
|
||||
$value = $this->addValue($exp->getValue(), $params);
|
||||
$alias = $this->columnName($exp->getAlias());
|
||||
return "JSON_ARRAYAGG($value) as $alias";
|
||||
} else {
|
||||
return parent::createExpression($exp, $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RowIteratorMySQL extends RowIterator {
|
||||
|
||||
@@ -17,10 +17,7 @@ use Core\Driver\SQL\Column\JsonColumn;
|
||||
use Core\Driver\SQL\Condition\CondRegex;
|
||||
use Core\Driver\SQL\Expression\Add;
|
||||
use Core\Driver\SQL\Expression\CurrentTimeStamp;
|
||||
use Core\Driver\SQL\Expression\DateAdd;
|
||||
use Core\Driver\SQL\Expression\DateSub;
|
||||
use Core\Driver\SQL\Expression\Expression;
|
||||
use Core\Driver\SQL\Expression\JsonArrayAgg;
|
||||
use Core\Driver\SQL\Query\CreateProcedure;
|
||||
use Core\Driver\SQL\Query\CreateTrigger;
|
||||
use Core\Driver\SQL\Query\Insert;
|
||||
@@ -301,16 +298,13 @@ class PostgreSQL extends SQL {
|
||||
}
|
||||
|
||||
public function addValue($val, &$params = NULL, bool $unsafe = false) {
|
||||
if ($val instanceof Keyword) {
|
||||
return $val->getValue();
|
||||
} else if ($val instanceof CurrentTable) {
|
||||
// I don't remember we need this here?
|
||||
/*if ($val instanceof CurrentTable) {
|
||||
return "TG_TABLE_NAME";
|
||||
} else if ($val instanceof CurrentColumn) {
|
||||
return "NEW." . $this->columnName($val->getName());
|
||||
} else if ($val instanceof Column) {
|
||||
return $this->columnName($val->getName());
|
||||
} else if ($val instanceof Expression) {
|
||||
return $this->createExpression($val, $params);
|
||||
} else */if ($val instanceof Expression) {
|
||||
return $val->getExpression($this, $params);
|
||||
} else {
|
||||
if ($unsafe) {
|
||||
return $this->getUnsafeValue($val);
|
||||
@@ -450,31 +444,6 @@ class PostgreSQL extends SQL {
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
protected function createExpression(Expression $exp, array &$params): ?string {
|
||||
if ($exp instanceof DateAdd || $exp instanceof DateSub) {
|
||||
$lhs = $this->addValue($exp->getLHS(), $params);
|
||||
$rhs = $this->addValue($exp->getRHS(), $params);
|
||||
$unit = $exp->getUnit();
|
||||
|
||||
if ($exp->getRHS() instanceof Column) {
|
||||
$rhs = "$rhs * INTERVAL '1 $unit'";
|
||||
} else {
|
||||
$rhs = "$rhs $unit";
|
||||
}
|
||||
|
||||
$operator = ($exp instanceof DateAdd ? "+" : "-");
|
||||
return "$lhs $operator $rhs";
|
||||
} else if ($exp instanceof CurrentTimeStamp) {
|
||||
return "CURRENT_TIMESTAMP";
|
||||
} else if ($exp instanceof JsonArrayAgg) {
|
||||
$value = $this->addValue($exp->getValue(), $params);
|
||||
$alias = $this->columnName($exp->getAlias());
|
||||
return "JSON_AGG($value) as $alias";
|
||||
} else {
|
||||
return parent::createExpression($exp, $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RowIteratorPostgreSQL extends RowIterator {
|
||||
|
||||
@@ -26,4 +26,8 @@ abstract class Query extends Expression {
|
||||
}
|
||||
|
||||
public abstract function build(array &$params): ?string;
|
||||
|
||||
public function getExpression(SQL $sql, array &$params): string {
|
||||
return "(" . $this->build($params) . ")";
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Core\Driver\SQL\Query;
|
||||
|
||||
use Core\Driver\SQL\Condition\CondOr;
|
||||
use Core\Driver\SQL\Expression\Expression;
|
||||
use Core\Driver\SQL\Expression\JsonArrayAgg;
|
||||
use Core\Driver\SQL\Join\InnerJoin;
|
||||
use Core\Driver\SQL\Join\Join;
|
||||
@@ -38,8 +39,13 @@ class Select extends ConditionalQuery {
|
||||
$this->fetchType = SQL::FETCH_ALL;
|
||||
}
|
||||
|
||||
public function addColumn(string $columnName): Select {
|
||||
$this->selectValues[] = $columnName;
|
||||
public function select(...$selectValues): Select {
|
||||
$this->selectValues = (!empty($selectValues) && is_array($selectValues[0])) ? $selectValues[0] : $selectValues;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addSelectValue(...$selectValues): Select {
|
||||
$this->selectValues = array_merge($this->selectValues, $selectValues);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -142,25 +148,6 @@ class Select extends ConditionalQuery {
|
||||
foreach ($this->selectValues as $value) {
|
||||
if (is_string($value)) {
|
||||
$selectValues[] = $this->sql->columnName($value);
|
||||
} else if ($value instanceof Select) {
|
||||
$subSelect = $value->build($params);
|
||||
if (count($value->getSelectValues()) !== 1) {
|
||||
$selectValues[] = "($subSelect)";
|
||||
} else {
|
||||
$columnAlias = null;
|
||||
$subSelectColumn = $value->getSelectValues()[0];
|
||||
if (is_string($subSelectColumn) && ($index = stripos($subSelectColumn, " as ")) !== FALSE) {
|
||||
$columnAlias = substr($subSelectColumn, $index + 4);
|
||||
} else if ($subSelectColumn instanceof JsonArrayAgg) {
|
||||
$columnAlias = $subSelectColumn->getAlias();
|
||||
}
|
||||
|
||||
if ($columnAlias) {
|
||||
$selectValues[] = "($subSelect) as $columnAlias";
|
||||
} else {
|
||||
$selectValues[] = "($subSelect)";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$selectValues[] = $this->sql->addValue($value, $params);
|
||||
}
|
||||
|
||||
@@ -4,24 +4,12 @@ namespace Core\Driver\SQL;
|
||||
|
||||
use Core\Driver\Logger\Logger;
|
||||
use Core\Driver\SQL\Column\Column;
|
||||
use Core\Driver\SQL\Condition\Compare;
|
||||
use Core\Driver\SQL\Condition\CondAnd;
|
||||
use Core\Driver\SQL\Condition\CondBool;
|
||||
use Core\Driver\SQL\Condition\CondIn;
|
||||
use Core\Driver\SQL\Condition\Condition;
|
||||
use Core\Driver\SQL\Condition\CondKeyword;
|
||||
use Core\Driver\SQL\Condition\CondNot;
|
||||
use Core\Driver\Sql\Condition\CondNull;
|
||||
use Core\Driver\SQL\Condition\CondOr;
|
||||
use Core\Driver\SQL\Condition\Exists;
|
||||
use Core\Driver\SQL\Constraint\Constraint;
|
||||
use Core\Driver\SQL\Constraint\Unique;
|
||||
use Core\Driver\SQL\Constraint\PrimaryKey;
|
||||
use Core\Driver\SQL\Constraint\ForeignKey;
|
||||
use Core\Driver\SQL\Expression\CaseWhen;
|
||||
use Core\Driver\SQL\Expression\CurrentTimeStamp;
|
||||
use Core\Driver\SQL\Expression\Expression;
|
||||
use Core\Driver\SQL\Expression\Sum;
|
||||
use Core\Driver\SQL\Query\AlterTable;
|
||||
use Core\Driver\SQL\Query\Commit;
|
||||
use Core\Driver\SQL\Query\CreateProcedure;
|
||||
@@ -236,6 +224,7 @@ abstract class SQL {
|
||||
public abstract function createTriggerBody(CreateTrigger $trigger, array $params = []): ?string;
|
||||
public abstract function getProcedureHead(CreateProcedure $procedure): ?string;
|
||||
public abstract function getColumnType(Column $column): ?string;
|
||||
public abstract function getStatus();
|
||||
public function getProcedureTail(): string { return ""; }
|
||||
public function getReturning(?string $columns): string { return ""; }
|
||||
|
||||
@@ -247,6 +236,10 @@ abstract class SQL {
|
||||
return $statements;
|
||||
}
|
||||
|
||||
public function getLogger(): Logger {
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
protected function getUnsafeValue($value): ?string {
|
||||
if (is_string($value)) {
|
||||
return "'" . addslashes("$value") . "'"; // unsafe operation here...
|
||||
@@ -273,60 +266,15 @@ abstract class SQL {
|
||||
public function now(): CurrentTimeStamp { return new CurrentTimeStamp(); }
|
||||
public function currentTimestamp(): CurrentTimeStamp { return new CurrentTimeStamp(); }
|
||||
|
||||
public function count($col = NULL): Keyword {
|
||||
if (is_null($col)) {
|
||||
return new Keyword("COUNT(*) AS count");
|
||||
} else if($col instanceof Keyword) {
|
||||
return new Keyword("COUNT(" . $col->getValue() . ") AS count");
|
||||
} else {
|
||||
$countCol = strtolower(str_replace(".","_", $col)) . "_count";
|
||||
$col = $this->columnName($col);
|
||||
return new Keyword("COUNT($col) AS $countCol");
|
||||
}
|
||||
}
|
||||
|
||||
public function distinct($col): Keyword {
|
||||
$col = $this->columnName($col);
|
||||
return new Keyword("DISTINCT($col)");
|
||||
}
|
||||
|
||||
// Statements
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
protected abstract function execute($query, $values = NULL, int $fetchType = self::FETCH_NONE);
|
||||
|
||||
public function buildCondition($condition, &$params) {
|
||||
public function buildCondition(Condition|array $condition, &$params): string {
|
||||
|
||||
if ($condition instanceof CondOr) {
|
||||
$conditions = array();
|
||||
foreach($condition->getConditions() as $cond) {
|
||||
$conditions[] = $this->buildCondition($cond, $params);
|
||||
}
|
||||
return "(" . implode(" OR ", $conditions) . ")";
|
||||
} else if ($condition instanceof CondAnd) {
|
||||
$conditions = array();
|
||||
foreach($condition->getConditions() as $cond) {
|
||||
$conditions[] = $this->buildCondition($cond, $params);
|
||||
}
|
||||
return "(" . implode(" AND ", $conditions) . ")";
|
||||
} else if ($condition instanceof Compare) {
|
||||
$column = $this->columnName($condition->getColumn());
|
||||
$value = $condition->getValue();
|
||||
$operator = $condition->getOperator();
|
||||
|
||||
if ($value === null) {
|
||||
if ($operator === "=") {
|
||||
return "$column IS NULL";
|
||||
} else if ($operator === "!=") {
|
||||
return "$column IS NOT NULL";
|
||||
}
|
||||
}
|
||||
|
||||
return $column . $operator . $this->addValue($value, $params);
|
||||
} else if ($condition instanceof CondBool) {
|
||||
return $this->columnName($condition->getValue());
|
||||
} else if (is_array($condition)) {
|
||||
if (is_array($condition)) {
|
||||
if (count($condition) === 1) {
|
||||
return $this->buildCondition($condition[0], $params);
|
||||
} else {
|
||||
@@ -336,77 +284,8 @@ abstract class SQL {
|
||||
}
|
||||
return implode(" AND ", $conditions);
|
||||
}
|
||||
} else if($condition instanceof CondIn) {
|
||||
|
||||
$needle = $condition->getNeedle();
|
||||
$haystack = $condition->getHaystack();
|
||||
if (is_array($haystack)) {
|
||||
$values = array();
|
||||
foreach ($haystack as $value) {
|
||||
$values[] = $this->addValue($value, $params);
|
||||
}
|
||||
|
||||
$values = implode(",", $values);
|
||||
} else if($haystack instanceof Select) {
|
||||
$values = $haystack->build($params);
|
||||
} else {
|
||||
$this->lastError = $this->logger->error("Unsupported in-expression value: " . get_class($condition));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($needle instanceof Column) {
|
||||
$lhs = $this->createExpression($needle, $params);
|
||||
} else {
|
||||
$lhs = $this->addValue($needle, $params);
|
||||
}
|
||||
|
||||
return "$lhs IN ($values)";
|
||||
} else if($condition instanceof CondKeyword) {
|
||||
$left = $condition->getLeftExp();
|
||||
$right = $condition->getRightExp();
|
||||
$keyword = $condition->getKeyword();
|
||||
$left = ($left instanceof Column) ? $this->columnName($left->getName()) : $this->addValue($left, $params);
|
||||
$right = ($right instanceof Column) ? $this->columnName($right->getName()) : $this->addValue($right, $params);
|
||||
return "$left $keyword $right ";
|
||||
} else if($condition instanceof CondNot) {
|
||||
$expression = $condition->getExpression();
|
||||
if ($expression instanceof Condition) {
|
||||
$expression = $this->buildCondition($expression, $params);
|
||||
} else {
|
||||
$expression = $this->columnName($expression);
|
||||
}
|
||||
|
||||
return "NOT $expression";
|
||||
} else if ($condition instanceof CondNull) {
|
||||
return $this->columnName($condition->getColumn()) . " IS NULL";
|
||||
} else if ($condition instanceof Exists) {
|
||||
return "EXISTS(" .$condition->getSubQuery()->build($params) . ")";
|
||||
} else {
|
||||
$this->lastError = $this->logger->error("Unsupported condition type: " . gettype($condition));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected function createExpression(Expression $exp, array &$params): ?string {
|
||||
if ($exp instanceof Column) {
|
||||
return $this->columnName($exp->getName());
|
||||
} else if ($exp instanceof Query) {
|
||||
return "(" . $exp->build($params) . ")";
|
||||
} else if ($exp instanceof CaseWhen) {
|
||||
$condition = $this->buildCondition($exp->getCondition(), $params);
|
||||
|
||||
// psql requires constant values here
|
||||
$trueCase = $this->addValue($exp->getTrueCase(), $params, true);
|
||||
$falseCase = $this->addValue($exp->getFalseCase(), $params, true);
|
||||
|
||||
return "CASE WHEN $condition THEN $trueCase ELSE $falseCase END";
|
||||
} else if ($exp instanceof Sum) {
|
||||
$value = $this->addValue($exp->getValue(), $params);
|
||||
$alias = $this->columnName($exp->getAlias());
|
||||
return "SUM($value) AS $alias";
|
||||
} else {
|
||||
$this->lastError = $this->logger->error("Unsupported expression type: " . get_class($exp));
|
||||
return null;
|
||||
return $this->addValue($condition, $params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,8 +320,6 @@ abstract class SQL {
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public abstract function getStatus();
|
||||
|
||||
public function parseBool($val) : bool {
|
||||
return in_array($val, array(true, 1, '1', 't', 'true', 'TRUE'), true);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use Core\Driver\SQL\Column\Column;
|
||||
|
||||
class CurrentColumn extends Column {
|
||||
|
||||
public function __construct(string $string) {
|
||||
parent::__construct($string);
|
||||
public function __construct(string $name) {
|
||||
parent::__construct($name);
|
||||
}
|
||||
}
|
||||
@@ -2,10 +2,23 @@
|
||||
|
||||
namespace Core\Driver\SQL\Type;
|
||||
|
||||
use Core\Driver\SQL\Column\StringColumn;
|
||||
use Core\Driver\SQL\Expression\Expression;
|
||||
use Core\Driver\SQL\MySQL;
|
||||
use Core\Driver\SQL\PostgreSQL;
|
||||
use Core\Driver\SQL\SQL;
|
||||
|
||||
class CurrentTable extends Expression {
|
||||
|
||||
class CurrentTable extends StringColumn {
|
||||
public function __construct() {
|
||||
parent::__construct("CURRENT_TABLE");
|
||||
}
|
||||
|
||||
function getExpression(SQL $sql, array &$params): string {
|
||||
if ($sql instanceof MySQL) {
|
||||
// CURRENT_TABLE
|
||||
} else if ($sql instanceof PostgreSQL) {
|
||||
return "TG_TABLE_NAME";
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user