- Added the HAVING and TRUNCATE keyword

- Fixed GroupBy which was not implemented yet
- Added a new SQL raw() function
- From statement now accepts subqueries
This commit is contained in:
Dave Mc Nicoll committed 2020-10-06 11:00:12 -04:00
1 parent 538af38769
commit 139504f8dd
17 files changed
+566 -251

No files matched your search

+16
View File
@@ -12,4 +12,20 @@ abstract class Fragment {
{
return implode($glue, array_filter($segments, function($i) { return ! is_null($i) && $i !== false && $i !== ""; }));
}
protected function renderTables(/*array|string*/ $tableList, ? int $maxTableCount = null) : string
{
$i = 0;
$list = [];
foreach((array) $tableList as $alias => $table) {
$list[] = ! is_numeric($alias) ? "$table $alias" : $table;
if ( ++$i === $maxTableCount ) {
break;
}
}
return implode(", ", $list);
}
}
+3 -12
View File
@@ -10,6 +10,8 @@ class From extends Fragment {
public array $tables = [];
public string $sql;
public function set(array $tables) : self
{
$this->tables = $tables;
@@ -29,18 +31,7 @@ class From extends Fragment {
public function render() : string
{
return $this->renderSegments([
static::SQL_TOKEN, $this->renderTables(),
static::SQL_TOKEN, $this->sql ?? $this->renderTables($this->tables),
]);
}
protected function renderTables() : string
{
$list = [];
foreach((array) $this->tables as $alias => $table) {
$list[] = ! is_numeric($alias) ? "$table $alias" : $table;
}
return implode(", ", $list);
}
}
+7 -6
View File
@@ -3,22 +3,23 @@
namespace Ulmus\Query;
class GroupBy extends Fragment {
const SQL_TOKEN = "GROUP BY";
public int $order = 70;
public int $order = 75;
public array $groupBy = [];
const SQL_TOKEN = "GROUP BY";
public function set(array $order) : self
{
$this->groupBy = $order;
$this->groupBy = [ $order ];
return $this;
}
public function add(string $field, ? string $direction = null) : self
public function add(string $field) : self
{
$this->groupBy[] = $field;
return $this;
}
+138 -3
View File
@@ -2,7 +2,142 @@
namespace Ulmus\Query;
class Having extends Where {
const SQL_TOKEN = "HAVING";
public int $order = 75;
use Ulmus\QueryBuilder;
use Ulmus\Common\EntityField,
Ulmus\Common\Sql;
class Having extends Fragment {
const SQL_TOKEN = "HAVING";
public int $order = 80;
public array $conditionList;
public QueryBuilder $queryBuilder;
public ? Having $parent = null;
public string $condition = Where::CONDITION_AND;
public function __construct(? QueryBuilder $queryBuilder, $condition = Where::CONDITION_AND)
{
$this->queryBuilder = $queryBuilder;
$this->condition = $condition;
$this->parent = $queryBuilder->having ?? null;
}
public function add($field, $value, string $operator, string $condition, bool $not = false) : self
{
$this->conditionList[] = [
$field,
$value,
$operator ?: $this->queryBuilder->conditionOperator,
$condition,
$not
];
return $this;
}
public function render(bool $skipToken = false) : string
{
$stack = [];
foreach ($this->conditionList ?? [] as $key => $item) {
if ( $item instanceof static ) {
if ( $item->conditionList ?? false ) {
$stack[] = ( $key !== 0 ? "{$item->condition} " : "" ) . "(" . $item->render($skipToken) . ")";
}
}
else {
list($field, $value, $operator, $condition, $not) = $item;
$stack[] = $latest = $this->havingCondition($field, $value, $operator, $key !== 0 ? $condition : "", $not);
}
}
return $this->renderSegments([
! $this->parent && ! $skipToken ? static::SQL_TOKEN : "",
implode(" ", $stack)
]);
}
protected function havingCondition($field, $value, string $operator = Where::OPERATOR_EQUAL, string $condition = Where::CONDITION_AND, bool $not = false) {
return new class($this->queryBuilder, $field, $value, $operator, $condition, $not) {
public $value;
public bool $not = false;
public string $field;
public string $operator;
public string $condition;
public QueryBuilder $queryBuilder;
protected string $content = "";
public function __construct(QueryBuilder $queryBuilder, string $field, $value, string $operator, string $condition, bool $not) {
$this->queryBuilder = $queryBuilder;
$this->field = $field;
$this->value = $value;
$this->condition = $condition;
$this->operator = $operator;
$this->not = $not;
}
public function render() : string
{
$value = $this->value();
return $this->content ?: $this->content = implode(" ", array_filter([
$this->condition,
$this->not ? Where::CONDITION_NOT : "",
$this->field,
$this->operator(),
$value,
]));
}
protected function operator() : string
{
if ( is_array($this->value) ) {
return (in_array($this->operator, [ '!=', '<>' ]) ? Where::CONDITION_NOT . " " : "") . Where::COMPARISON_IN;
}
return $this->operator;
}
protected function value()
{
if ( is_array($this->value) ) {
$stack = [];
foreach($this->value as $item) {
$stack[] = $this->filterValue($item);
}
return "(" . implode(", ", $stack) . ")";
}
return $this->filterValue($this->value);
}
protected function filterValue($value)
{
if ( $value === null ) {
$this->operator = in_array($this->operator, [ '!=', '<>' ]) ? Where::COMPARISON_IS . " " . Where::CONDITION_NOT : Where::COMPARISON_IS;
return Where::COMPARISON_NULL;
}
elseif ( is_object($value) && ( $value instanceof EntityField ) ) {
return $value->name();
}
else {
return $this->queryBuilder->addParameter($value);
}
}
public function __toString() : string
{
return $this->render();
}
};
}
}
+18 -6
View File
@@ -3,9 +3,13 @@
namespace Ulmus\Query;
use Ulmus\QueryBuilder;
use Ulmus\Repository\ConditionTrait;
class Join extends Fragment {
class Join extends Fragment
{
use ConditionTrait;
const SQL_OUTER = "OUTER";
const SQL_TOKEN = "JOIN";
const TYPE_LEFT = "LEFT";
@@ -33,8 +37,10 @@ class Join extends Fragment {
public /* QueryBuilder */ $queryBuilder;
public function __construct(QueryBuilder $queryBuilder) {
$this->queryBuilder = $queryBuilder;
public function __construct(QueryBuilder $queryBuilder)
{
$this->queryBuilder = new QueryBuilder();
$this->queryBuilder->parent = $queryBuilder;
}
public function set(string $side, /* QueryBuilder|string */ $table, string $field, /* QueryBuilder|string */ $value)
@@ -44,9 +50,15 @@ class Join extends Fragment {
$this->field = $field;
$this->value = $value;
}
public function render() : string
{
return $this->renderSegments([ strtoupper($this->side), static::SQL_TOKEN, $this->table, $this->alias ?? "", $this->attachment, $this->field, "=", $this->value ]);
if ($this->queryBuilder->where ?? false ) {
$where = $this->renderSegments([Where::CONDITION_AND, $this->queryBuilder->render(true)]);
}
return $this->renderSegments([
strtoupper($this->side), $this->outer ? static::SQL_OUTER : "", static::SQL_TOKEN, $this->table, $this->alias ?? "", $this->attachment, $this->field, "=", $this->value, $where ?? ""
]);
}
}
}
+1 -1
View File
@@ -3,7 +3,7 @@
namespace Ulmus\Query;
class OrderBy extends Fragment {
public int $order = 80;
public int $order = 85;
public array $orderBy = [];
+9
View File
@@ -4,6 +4,8 @@ namespace Ulmus\Query;
class Select extends Fragment {
const FIELD_AS = "%s as %s";
public int $order = -100;
public bool $distinct = false;
@@ -36,6 +38,13 @@ class Select extends Fragment {
public function render() : string
{
foreach($this->fields as $key => &$value) {
if ( ! is_numeric($key) ) {
$value = sprintf(static::FIELD_AS, $value, $key);
}
}
return $this->renderSegments([
( $this->union ? 'UNION' : false ),
static::SQL_TOKEN,
+26
View File
@@ -0,0 +1,26 @@
<?php
namespace Ulmus\Query;
class Truncate extends Fragment {
const SQL_TOKEN = "TRUNCATE TABLE";
public int $order = -100;
public string $table;
public function set(string $tableName) : self
{
$this->table = $tableName;
return $this;
}
public function render() : string
{
return $this->renderSegments([
static::SQL_TOKEN, $this->table,
]);
}
}
+3 -3
View File
@@ -50,14 +50,14 @@ class Where extends Fragment {
return $this;
}
public function render() : string
public function render(bool $skipToken = false) : string
{
$stack = [];
foreach ($this->conditionList ?? [] as $key => $item) {
if ( $item instanceof Where ) {
if ( $item->conditionList ?? false ) {
$stack[] = ( $key !== 0 ? "{$item->condition} " : "" ) . "(" . $item->render() . ")";
$stack[] = ( $key !== 0 ? "{$item->condition} " : "" ) . "(" . $item->render($skipToken) . ")";
}
}
else {
@@ -67,7 +67,7 @@ class Where extends Fragment {
}
return $this->renderSegments([
! $this->parent ? static::SQL_TOKEN : "",
! $this->parent && ! $skipToken ? static::SQL_TOKEN : "",
implode(" ", $stack)
]);
}