table = $table; } public function select(string ...$cols): Query { if (!empty($cols)) $this->columns = $cols; // Validate colum existence foreach ($cols as $col) if (!$this->table->existsColumn($col)) throw new InvalidArgumentException("Unknown column: $col"); return $this; } public function where(string $col, string $operator, mixed $val): Query { return $this->addCondition($col, $operator, $val, "AND"); } public function andWhere(string $col, string $operator, mixed $val): Query { return $this->addCondition($col, $operator, $val, "AND"); } public function orWhere(string $col, string $operator, mixed $val): Query { return $this->addCondition($col, $operator, $val, "OR"); } private function addCondition(string $col, string $operator, mixed $val, string $prefix): Query { if ($this->table->existsColumn($col)) throw new InvalidArgumentException("Unknown column: $col"); $columnType = $this->table->columnType($col); $castedValue = $columnType->dbCast($val); if (!empty($this->conditions)) $this->conditions[] = $prefix; $this->conditions[] = "$col $operator $castedValue"; return $this; } public function toSql(): string { $columns = implode(", ", $this->columns); $table = $this->table->name; $whereClause = !empty($this->conditions) ? " WHERE " . implode(" ", $this->conditions) : ""; return esc_sql("SELECT $columns FROM $table$whereClause"); } public function query(): array { global $wpdb; $query = $this->toSql(); $results = $wpdb->get_results($wpdb->prepare($query), ARRAY_A); return $this->castResults($results); } private 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; } }