- First draft of current WIP
This commit is contained in:
commit
b73d046e0a
47 files changed
+2797
No files matched your search
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
class Explain extends Fragment {
|
||||
|
||||
public int $order = -1000;
|
||||
|
||||
public bool $extended = false;
|
||||
|
||||
public function render() : string
|
||||
{
|
||||
return $this->renderSegments([
|
||||
"EXPLAIN", $this->extended ? "EXTENDED" : ""
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
abstract class Fragment {
|
||||
|
||||
public int $order = 0;
|
||||
|
||||
public abstract function render() : string;
|
||||
|
||||
protected function renderSegments(array $segments, string $glue = " ") : string
|
||||
{
|
||||
return implode($glue, array_filter($segments));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
class From extends Fragment {
|
||||
|
||||
public int $order = -80;
|
||||
|
||||
protected $tables = [];
|
||||
|
||||
public function set(array $tables) : self
|
||||
{
|
||||
$this->tables = $tables;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function add($table) : self
|
||||
{
|
||||
foreach((array) $table as $alias => $name) {
|
||||
$this->tables[$alias] = $name;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() : string
|
||||
{
|
||||
return $this->renderSegments([
|
||||
'FROM', $this->renderTables(),
|
||||
]);
|
||||
}
|
||||
|
||||
protected function renderTables() : string
|
||||
{
|
||||
$list = [];
|
||||
|
||||
foreach((array) $this->tables as $alias => $table) {
|
||||
$list[] = ! is_numeric($alias) ? "`$table` $alias" : "`$table`";
|
||||
}
|
||||
|
||||
return implode(", ", $list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
class GroupBy extends Fragment {
|
||||
public int $order = 70;
|
||||
|
||||
public array $groupBy = [];
|
||||
|
||||
public function set(array $order) : self
|
||||
{
|
||||
$this->groupBy = $order;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function add(string $field, ? string $direction = null) : self
|
||||
{
|
||||
$this->groupBy[] = $field;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() : string
|
||||
{
|
||||
return $this->renderSegments([
|
||||
'GROUP BY', implode(", ", $this->groupBy)
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
class Having extends Where {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
class Insert extends Fragment {
|
||||
|
||||
public bool $ignore = false;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
class Join extends Fragment {
|
||||
|
||||
const TYPE_LEFT = "LEFT";
|
||||
const TYPE_RIGHT = "RIGHT";
|
||||
const TYPE_INNER = "INNER";
|
||||
const TYPE_FULL = "FULL";
|
||||
const TYPE_CROSS = "CROSS";
|
||||
const TYPE_NATURAL = "NATURAL";
|
||||
|
||||
public string $type = self::TYPE_INNER;
|
||||
|
||||
public bool $outer = false;
|
||||
|
||||
public function render() : string
|
||||
{
|
||||
return $this->renderSegments([
|
||||
$this->side,
|
||||
'JOIN',
|
||||
/* table here! */,
|
||||
'ON',
|
||||
/* WHERE ! */
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
class Like extends Fragment {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
class Limit extends Fragment {
|
||||
|
||||
public int $order = 80;
|
||||
|
||||
protected int $limit = 0;
|
||||
|
||||
public function set($limit) : self
|
||||
{
|
||||
$this->limit = $limit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() : string
|
||||
{
|
||||
return $this->renderSegments([
|
||||
'LIMIT', $this->limit,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query\MySQL;
|
||||
|
||||
class Replace extends \Ulmus\Query\Fragment {
|
||||
|
||||
public int $order = -1000;
|
||||
|
||||
public bool $extended = false;
|
||||
|
||||
public function render() : string
|
||||
{
|
||||
return $this->renderSegments([
|
||||
"EXPLAIN", $this->extended ? "EXTENDED" : ""
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
class Offset extends Fragment {
|
||||
|
||||
public int $order = 81;
|
||||
|
||||
protected int $offset = 0;
|
||||
|
||||
public function set($offset) : self
|
||||
{
|
||||
$this->offset = $offset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() : string
|
||||
{
|
||||
return $this->renderSegments([
|
||||
'OFFSET', $this->offset,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
class OrderBy extends Fragment {
|
||||
public int $order = 70;
|
||||
|
||||
public array $orderBy = [];
|
||||
|
||||
public function set(array $order) : self
|
||||
{
|
||||
$this->orderBy = $order;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function add(string $field, ? string $direction = null) : self
|
||||
{
|
||||
$this->orderBy[] = [ $field, $direction ];
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() : string
|
||||
{
|
||||
$list = array_map(function($item) {
|
||||
list($field, $direction) = $item;
|
||||
return $field . ( $direction ? " $direction" : "" );
|
||||
}, $this->orderBy);
|
||||
|
||||
return $this->renderSegments([
|
||||
'ORDER BY', implode(", ", $list)
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
class Select extends Fragment {
|
||||
|
||||
public int $order = -100;
|
||||
|
||||
public bool $distinct = false;
|
||||
|
||||
public bool $union = false;
|
||||
|
||||
public bool $top = false;
|
||||
|
||||
protected $fields = [];
|
||||
|
||||
public function set($fields) : self
|
||||
{
|
||||
$this->fields = is_array($fields) ? $fields : [ $fields ];
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function add($fields) : self
|
||||
{
|
||||
if ( is_array($fields) ) {
|
||||
$this->fields = array_merge($this->fields, $fields);
|
||||
}
|
||||
else {
|
||||
$this->fields[] = $fields;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() : string
|
||||
{
|
||||
return $this->renderSegments([
|
||||
( $this->union ? 'UNION' : false ),
|
||||
'SELECT',
|
||||
( $this->top ? 'TOP' : false ),
|
||||
implode(', ', $this->fields)
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace Ulmus\Query;
|
||||
|
||||
use Ulmus\QueryBuilder;
|
||||
|
||||
use Ulmus\Common\EntityField,
|
||||
Ulmus\Common\Sql;
|
||||
|
||||
class Where extends Fragment {
|
||||
const OPERATOR_LIKE = "LIKE";
|
||||
const OPERATOR_EQUAL = "=";
|
||||
const OPERATOR_NOT_EQUAL = "<>";
|
||||
const CONDITION_AND = "AND";
|
||||
const CONDITION_OR = "OR";
|
||||
const CONDITION_NOT = "NOT";
|
||||
const COMPARISON_IN = "IN";
|
||||
const COMPARISON_IS = "IS";
|
||||
const COMPARISON_NULL = "NULL";
|
||||
|
||||
public int $order = 50;
|
||||
|
||||
public array $conditionList;
|
||||
|
||||
public QueryBuilder $queryBuilder;
|
||||
|
||||
public ? Where $parent = null;
|
||||
|
||||
public string $condition = self::CONDITION_AND;
|
||||
|
||||
public function __construct(? QueryBuilder $queryBuilder, $condition = self::CONDITION_AND)
|
||||
{
|
||||
$this->queryBuilder = $queryBuilder;
|
||||
$this->condition = $condition;
|
||||
$this->parent = $queryBuilder->where ?? 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() : string
|
||||
{
|
||||
$stack = [];
|
||||
|
||||
foreach ($this->conditionList ?? [] as $key => $item) {
|
||||
if ( $item instanceof Where ) {
|
||||
if ( $item->conditionList ?? false ) {
|
||||
$stack[] = ( $key !== 0 ? "{$item->condition} " : "" ) . "(" . $item->render() . ")";
|
||||
}
|
||||
}
|
||||
else {
|
||||
list($field, $value, $operator, $condition, $not) = $item;
|
||||
$stack[] = $latest = $this->whereCondition($field, $value, $operator, $key !== 0 ? $condition : "", $not);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->renderSegments([
|
||||
! $this->parent ? "WHERE" : "",
|
||||
implode(" ", $stack)
|
||||
]);
|
||||
}
|
||||
|
||||
protected function whereCondition($field, $value, string $operator = self::OPERATOR_EQUAL, string $condition = self::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($this->value);
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString() : string
|
||||
{
|
||||
return $this->render();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user