Extended Select functionality with handling of derived tables

This commit is contained in:
Balázs Vigh 2021-05-05 19:18:07 +02:00
parent 807b4d024f
commit 66c871fbc2

View File

@ -12,6 +12,8 @@ class Select
const CONDITION_HAVING = 1; const CONDITION_HAVING = 1;
const DERIVED_TABLE_KEY = 'DERIVED';
private IConnection $connection; private IConnection $connection;
private string $table; private string $table;
@ -55,6 +57,11 @@ class Select
return $this; return $this;
} }
public function setDerivedTableAlias(string $tableAlias): Select
{
return $this->setTableAliases([Select::DERIVED_TABLE_KEY => $tableAlias]);
}
public function from(string $table): Select public function from(string $table): Select
{ {
$this->table = $table; $this->table = $table;
@ -194,6 +201,11 @@ class Select
} }
} }
private function isDerivedTable(): bool
{
return array_key_exists(Select::DERIVED_TABLE_KEY, $this->tableAliases);
}
private function addJoin(string $type, $table, $column1, string $relation, $column2): void private function addJoin(string $type, $table, $column1, string $relation, $column2): void
{ {
$this->joins[] = [$type, $table, $column1, $relation, $column2]; $this->joins[] = [$type, $table, $column1, $relation, $column2];
@ -211,10 +223,14 @@ class Select
private function generateQuery(): array private function generateQuery(): array
{ {
$queryString = 'SELECT ' . $this->generateColumns() . ' FROM ' . $this->generateTable($this->table, true); list($innerQuery, $innerParams) = $this->generateTable($this->table, true);
$queryString = 'SELECT ' . $this->generateColumns() . ' FROM ' . $innerQuery;
if (count($this->joins) > 0) { if (count($this->joins) > 0) {
$queryString .= ' ' . $this->generateJoins(); list($joinQuery, $joinParams) = $this->generateJoins();
$queryString .= ' ' . $joinQuery;
} else {
$joinParams = [];
} }
if (count($this->conditions[self::CONDITION_WHERE]) > 0) { if (count($this->conditions[self::CONDITION_WHERE]) > 0) {
@ -245,20 +261,32 @@ class Select
$queryString .= ' LIMIT ' . $this->limit[1] . ', ' . $this->limit[0]; $queryString .= ' LIMIT ' . $this->limit[1] . ', ' . $this->limit[0];
} }
return [$queryString, array_merge($whereParams, $havingParams)]; if($this->isDerivedTable()) {
$queryString = '(' . $queryString . ') AS ' . $this->tableAliases[Select::DERIVED_TABLE_KEY];
}
return [$queryString, array_merge($innerParams, $joinParams, $whereParams, $havingParams)];
} }
private function generateTable($table, bool $defineAlias = false): string private function generateTable($table, bool $defineAlias = false): array
{ {
$params = [];
if ($table instanceof RawExpression) { if ($table instanceof RawExpression) {
return (string) $table; return [(string) $table, $params];
}
if($table instanceof Select)
{
return $table->generateQuery();
} }
if (isset($this->tableAliases[$table])) { if (isset($this->tableAliases[$table])) {
return ($defineAlias ? Utils::backtick($this->tableAliases[$table]) . ' ' . Utils::backtick($table) : Utils::backtick($table)); $queryString = ($defineAlias ? Utils::backtick($this->tableAliases[$table]) . ' ' . Utils::backtick($table) : Utils::backtick($table));
return [$queryString, $params];
} }
return Utils::backtick($table); return [Utils::backtick($table), $params];
} }
private function generateColumn($column): string private function generateColumn($column): string
@ -271,7 +299,8 @@ class Select
$out = ''; $out = '';
if ($column[0]) { if ($column[0]) {
$out .= $this->generateTable($column[0]) . '.'; list($tableName, $params) = $this->generateTable($column[0]);
$out .= $tableName . '.';
} }
$out .= Utils::backtick($column[1]); $out .= Utils::backtick($column[1]);
@ -297,15 +326,20 @@ class Select
return implode(',', $columns); return implode(',', $columns);
} }
private function generateJoins(): string private function generateJoins(): array
{ {
$joins = $this->joins; $joins = $this->joins;
array_walk($joins, function (&$value, $key) { $joinQueries = [];
$value = $value[0] . ' JOIN ' . $this->generateTable($value[1], true) . ' ON ' . $this->generateColumn($value[2]) . ' ' . $value[3] . ' ' . $this->generateColumn($value[4]); $params = [];
});
return implode(' ', $joins); foreach($joins as $value) {
list($joinQueryFragment, $paramsFragment) = $this->generateTable($value[1], true);
array_push($joinQueries, $value[0] . ' JOIN ' . $joinQueryFragment . ' ON ' . $this->generateColumn($value[2]) . ' ' . $value[3] . ' ' . $this->generateColumn($value[4]));
$params = array_merge($params, $paramsFragment);
}
return [implode(' ', $joinQueries), $params];
} }
private function generateConditions(int $type): array private function generateConditions(int $type): array