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; } }