110 lines
3.2 KiB
PHP
110 lines
3.2 KiB
PHP
|
<?php
|
||
|
namespace DatabaseHelper;
|
||
|
|
||
|
use DatabaseHelper\enums\Join;
|
||
|
use DatabaseHelper\enums\Order;
|
||
|
use http\Exception\InvalidArgumentException;
|
||
|
use SimplePie\Exception;
|
||
|
|
||
|
class Query
|
||
|
{
|
||
|
use Conditionable;
|
||
|
|
||
|
protected Schema $schema;
|
||
|
protected array $columns = ['*'];
|
||
|
protected array $joins = [];
|
||
|
public array $orderBy;
|
||
|
|
||
|
public function __construct(Schema $table) {
|
||
|
$this->schema = $table;
|
||
|
}
|
||
|
|
||
|
public function select(string ...$cols): Query {
|
||
|
if (!empty($cols))
|
||
|
$this->columns = $cols;
|
||
|
foreach ($cols as $col)
|
||
|
$this->schema->requireColumn($col);
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
public function orderBy(string $col, Order $order): Query {
|
||
|
$this->schema->requireColumn($col);
|
||
|
$this->orderBy = [
|
||
|
'name' => $col,
|
||
|
'order' => $order
|
||
|
];
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
public function join(Schema $other, Join $join): Query {
|
||
|
$foreignKey = null;
|
||
|
if($this->schema->existsReference($other))
|
||
|
$foreignKey = $this->schema->foreignKeys[$other->name];
|
||
|
if ($other->existsReference($this->schema))
|
||
|
$foreignKey = $other->foreignKeys[$this->schema->name];
|
||
|
|
||
|
if (is_null($foreignKey))
|
||
|
throw new InvalidArgumentException('Joins can only applied to referencing columns.');
|
||
|
|
||
|
// TODO: Implement include instead of merge
|
||
|
$this->schema->include($other);
|
||
|
$this->joins[] = [
|
||
|
'table' => $other->name,
|
||
|
'type' => $join
|
||
|
];
|
||
|
|
||
|
return $this;
|
||
|
}
|
||
|
|
||
|
protected function isOrdered(): bool {
|
||
|
return !empty($this->orderBy);
|
||
|
}
|
||
|
|
||
|
protected function isJoined(): bool {
|
||
|
return !empty($this->joins);
|
||
|
}
|
||
|
|
||
|
public function toSql(): string {
|
||
|
// Build the SELECT clause.
|
||
|
$columns = implode(", ", $this->columns);
|
||
|
$primaryTable = $this->schema->name;
|
||
|
$sqlStatement = "SELECT $columns FROM $primaryTable";
|
||
|
|
||
|
// Append join clauses, if any.
|
||
|
if ($this->isJoined()) {
|
||
|
foreach ($this->joins as $join) {
|
||
|
$sqlStatement .= " " . $join['type']->toString() . " NATURAL JOIN " . $join['table'];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Append the WHERE clause if conditions exist.
|
||
|
if ($this->isConditioned()) {
|
||
|
$whereClause = $this->combineConditions();
|
||
|
$sqlStatement .= " WHERE $whereClause";
|
||
|
}
|
||
|
|
||
|
// Append the ORDER BY clause if ordering is set.
|
||
|
if ($this->isOrdered()) {
|
||
|
$orderClause = $this->orderBy['name'] . ' ' . $this->orderBy['order'];
|
||
|
$sqlStatement .= " ORDER BY $orderClause";
|
||
|
}
|
||
|
|
||
|
return esc_sql($sqlStatement);
|
||
|
}
|
||
|
|
||
|
public function query(): array {
|
||
|
global $wpdb;
|
||
|
$query = $this->toSql();
|
||
|
$results = $wpdb->get_results($query, ARRAY_A);
|
||
|
return $this->castResults($results);
|
||
|
}
|
||
|
|
||
|
protected function castResults(array $results): array {
|
||
|
foreach ($results as &$row)
|
||
|
foreach ($row as $column => &$value)
|
||
|
if (isset($this->columnTypes[$column]))
|
||
|
$value = $this->columnTypes[$column]->valCast($value);
|
||
|
return $results;
|
||
|
}
|
||
|
}
|