Prototype for Schema

This commit is contained in:
Jan-Niclas Loosen 2025-02-05 16:10:30 +01:00
parent 817513095e
commit 39bd110344
4 changed files with 65 additions and 55 deletions

View File

@ -5,11 +5,11 @@ use InvalidArgumentException;
class Insertion
{
private Table $table;
private Schema $table;
private array $currentRow = [];
private array $batchRows = [];
public function __construct(Table $table) {
public function __construct(Schema $table) {
$this->table = $table;
}
@ -73,6 +73,6 @@ class Insertion
foreach ($this->batchRows as $row)
if (!empty($row))
$wpdb->insert($this->table->tableName, $row);
$wpdb->insert($this->table->name, $row);
}
}

View File

@ -6,23 +6,23 @@ use InvalidArgumentException;
class Query
{
private Table $table;
private Schema $table;
private array $columns = ['*'];
private array $conditions = [];
/**
* @var ColumnTypes[]
*/
private array $columnTypes = [];
public function __construct(Table $table) {
$this->columnTypes = array_map(fn($col) => $col['colType'], $table->columns);
public function __construct(Schema $table) {
$this->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;
}
@ -38,23 +38,23 @@ class Query
return $this->addCondition($col, $operator, $val, "OR");
}
private function addCondition(string $colName, string $operator, mixed $val, string $prefix): Query {
if (!isset($this->columnTypes[$colName]))
throw new InvalidArgumentException("Unknown column: $colName");
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->columnTypes[$colName];
$columnType = $this->table->columnType($col);
$castedValue = $columnType->dbCast($val);
if (!empty($this->conditions))
$this->conditions[] = $prefix;
$this->conditions[] = "$colName $operator $castedValue";
$this->conditions[] = "$col $operator $castedValue";
return $this;
}
public function toSql(): string {
$columns = implode(", ", $this->columns);
$table = $this->table->tableName;
$table = $this->table->name;
$whereClause = !empty($this->conditions) ? " WHERE " . implode(" ", $this->conditions) : "";
return esc_sql("SELECT $columns FROM $table$whereClause");
}

View File

@ -17,7 +17,19 @@ class Schema
public CharsetTypes $charset = CharsetTypes::UTF8;
public CollationTypes $collation = CollationTypes::UTF8_GENERAL_CI;
public function __construct(string $tableName) {
$this->name = $tableName;
public function __construct(string $name) {
$this->name = $name;
}
public function existsColumn(string $col): bool {
return isset($this->columns[$col]);
}
public function columnType(string $col) {
return $this->columns[$col]['type'];
}
public function primaryKey() {
return $this->columns['primary']['name'];
}
}

View File

@ -17,47 +17,46 @@ class Table
$this->table = new Schema($tableName);
}
public function column(string $colName, ColumnTypes $colType, mixed $default = null, bool $nullable = false, bool $unique = false): Table {
if(isset($this->columns[$colName]))
public function column(string $name, ColumnTypes $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Table {
if(isset($this->columns[$name]))
throw new InvalidArgumentException('Column name already exists.');
$this->table->columns[$colName] = [
'colName' => $colName,
'defaultVal' => $default,
'colType' => $colType,
'nullable' => $nullable,
'unique' => $unique
$this->table->columns[$name] = [
'name' => $name,
'default' => $default,
'type' => $type,
'isNullable' => $isNullable,
'isUnique' => $isUnique
];
return $this;
}
public function primary(string $colName, ColumnTypes $colType, bool $autoInc = false): Table {
public function primary(string $name, ColumnTypes $type, bool $autoInc = false): Table {
if(isset($this->primaryKey))
throw new InvalidArgumentException('Primary column already exists.');
$this->table->primaryKey = [
'colName' => $colName,
'colType' => $colType,
'autoincrement' => $autoInc
'name' => $name,
'autoInc' => $autoInc
];
return $this->column($colName, $colType);
return $this->column($name, $type);
}
public function reference(Schema $foreignTable, CascadeTypes $onDelete = CascadeTypes::CASCADE, CascadeTypes $onUpdate = CascadeTypes::CASCADE): Table {
$colName = $foreignTable->primaryKey['colName'];
if(isset($this->columns[$colName]))
$name = $foreignTable->primaryKey();
if(isset($this->columns[$name]))
throw new InvalidArgumentException('Column name already exists.');
$this->table->foreignKeys[] = [
'colName' => $colName,
'tableName' => $foreignTable->name,
'name' => $name,
'table' => $foreignTable->name,
'onDelete' => $onDelete,
'onUpdate' => $onUpdate
];
$this->table->columns[$colName] = $foreignTable->columns[$colName];
$this->table->columns[$name] = $foreignTable->columns[$name];
return $this;
}
@ -77,23 +76,21 @@ class Table
}
public function toSql(): string {
$primaryKey = $this->table->primaryKey();
$sql = "CREATE TABLE `{$this->table->name}` (\n";
$sql .= " PRIMARY KEY (`$primaryKey`),\n";
// Add primary key constraint if present
if (!empty($this->primaryKey))
$sql .= " PRIMARY KEY (`{$this->primaryKey['colName']}`),\n";
foreach ($this->table->columns as $column) {
if ($column['colName'] !== $this->table->primaryKey['colName']) {
$sql .= " `{$column['colName']}` {$column['colType']->value}";
foreach ($this->table->columns as $col) {
if ($col['name'] !== $primaryKey) {
$sql .= " `{$col['name']}` {$col['type']->toString()}";
// Handle nulls, uniqueness, and defaults
if (!$column['nullable'])
if (!$col['isNullable'])
$sql .= " NOT NULL";
if ($column['unique'])
if ($col['isUnique'])
$sql .= " UNIQUE";
if ($column['defaultVal'] !== null) {
$default = is_string($column['defaultVal']) ? "'{$column['defaultVal']}'" : $column['defaultVal'];
if ($col['default'] !== null) {
$default = is_string($col['default']) ? "'{$col['default']}'" : $col['default'];
$sql .= " DEFAULT $default";
}
@ -102,15 +99,16 @@ class Table
}
// Add secondary constraints if present
foreach ($this->table->foreignKeys as $foreignKey) {
$sql .= " FOREIGN KEY (`{$foreignKey['colName']}`) REFERENCES `{$foreignKey['tableName']}` (`{$foreignKey['colName']}`)";
$sql .= " ON DELETE {$foreignKey['onDelete']->toString()} ON UPDATE {$foreignKey['onUpdate']->toString()},\n";
foreach ($this->table->foreignKeys as $key) {
$sql .= " FOREIGN KEY (`{$key['name']}`) REFERENCES `{$key['table']}` (`{$key['name']}`)";
$sql .= " ON DELETE {$key['onDelete']->toString()} ON UPDATE {$key['onUpdate']->toString()},\n";
}
// Close the SQL string and add constraints
$sql = rtrim($sql, ",\n") . "\n";
$sql .= ") ENGINE={$this->table->engine->toString()} CHARSET={$this->table->charset->toString()} COLLATE={$this->table->collation->toString()};";
$sql = rtrim($sql, ",\n") . "\n) ";
$sql .= "ENGINE={$this->table->engine->toString()} ";
$sql .= "CHARSET={$this->table->charset->toString()} ";
$sql -= "COLLATE={$this->table->collation->toString()};";
return esc_sql($sql);
}