WP-Database-Helper/Query.php

143 lines
4.3 KiB
PHP
Raw Normal View History

2025-02-12 14:03:39 +00:00
<?php
namespace DatabaseHelper;
2025-02-21 18:06:16 +00:00
use DatabaseHelper\beans\Schema;
2025-02-12 14:55:28 +00:00
use DatabaseHelper\enums\Aggregation;
2025-02-12 14:03:39 +00:00
use DatabaseHelper\enums\Join;
use DatabaseHelper\enums\Order;
use http\Exception\InvalidArgumentException;
class Query
{
use Conditionable;
protected Schema $schema;
protected array $columns = ['*'];
2025-02-12 14:55:28 +00:00
protected array $aggregations = [];
2025-02-12 14:03:39 +00:00
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;
}
2025-02-12 14:55:28 +00:00
public function join(Join $join, Schema $other): Query {
2025-02-12 14:03:39 +00:00
$foreignKey = null;
if($this->schema->existsReference($other))
2025-02-21 18:06:16 +00:00
$foreignKey = $this->schema->references[$other->name];
2025-02-12 14:03:39 +00:00
if ($other->existsReference($this->schema))
2025-02-21 18:06:16 +00:00
$foreignKey = $other->references[$this->schema->name];
2025-02-12 14:03:39 +00:00
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 {
2025-02-12 14:55:28 +00:00
// Merge any aggregations with the standard columns.
$selectColumns = $this->columns;
if ($this->hasAggregations())
$selectColumns = array_merge($selectColumns, $this->aggregations);
2025-02-12 14:03:39 +00:00
// Build the SELECT clause.
2025-02-12 14:55:28 +00:00
$columns = implode(", ", $selectColumns);
2025-02-12 14:03:39 +00:00
$primaryTable = $this->schema->name;
2025-02-12 15:55:03 +00:00
$query = "SELECT $columns FROM $primaryTable";
2025-02-12 14:03:39 +00:00
// Append join clauses, if any.
2025-02-12 14:55:28 +00:00
if ($this->isJoined())
foreach ($this->joins as $join)
2025-02-12 15:55:03 +00:00
$query .= " " . $join['type']->toString() . " NATURAL JOIN " . $join['table'];
2025-02-12 14:03:39 +00:00
// Append the WHERE clause if conditions exist.
if ($this->isConditioned()) {
$whereClause = $this->combineConditions();
2025-02-12 15:55:03 +00:00
$query .= " WHERE $whereClause";
2025-02-12 14:03:39 +00:00
}
// Append the ORDER BY clause if ordering is set.
if ($this->isOrdered()) {
$orderClause = $this->orderBy['name'] . ' ' . $this->orderBy['order'];
2025-02-12 15:55:03 +00:00
$query .= " ORDER BY $orderClause";
2025-02-12 14:03:39 +00:00
}
2025-02-12 15:55:03 +00:00
return $query;
2025-02-12 14:03:39 +00:00
}
2025-02-12 14:55:28 +00:00
public function aggregate(string $col, string $alias, Aggregation $func): Query {
if ($col != '*')
$this->schema->requireColumn($col);
$this->aggregations[] = strtoupper($func->toString()) . "($col) AS $alias";
return $this;
}
public function hasAggregations(): bool {
return !empty($this->aggregations);
}
public function query(): mixed {
2025-02-12 14:03:39 +00:00
global $wpdb;
$query = $this->toSql();
$results = $wpdb->get_results($query, ARRAY_A);
2025-02-12 14:55:28 +00:00
return $this->formatResults($results);
2025-02-12 14:03:39 +00:00
}
2025-02-12 14:55:28 +00:00
protected function formatResults(array $results) {
$formatted = [];
foreach ($results as $row) {
// Apply type casting to each column in each row.
2025-02-12 14:03:39 +00:00
foreach ($row as $column => &$value)
if (isset($this->columnTypes[$column]))
$value = $this->columnTypes[$column]->valCast($value);
2025-02-12 14:55:28 +00:00
// Use the primary key for row indexing
$primaryKey = $this->schema->primaryKey();
$formatted[$row[$primaryKey]] = $row;
}
if (count($formatted) === 1) {
// Unpack single row results
$row = array_shift($formatted);
if (count($row) === 1)
// Unpack single column results
return array_shift($row);
return $row;
}
return $formatted;
2025-02-12 14:03:39 +00:00
}
}