Seperate table and schema

This commit is contained in:
Jan-Niclas Loosen 2025-02-05 15:40:52 +01:00
parent ed099a8bcb
commit 817513095e
9 changed files with 89 additions and 59 deletions

View File

@ -1,52 +1,72 @@
<?php
namespace DatabaseHelper;
namespace DatabaseHelper;
use DatabaseHelper\enums\ColumnTypes;
use InvalidArgumentException;
use wpdb;
global $wpdb;
class Insertion
{
private Table $table;
private array $currentRow = [];
private array $batchRows = [];
private bool $isReady = false;
public function __construct(Table $table) {
$this->table = $table;
}
/**
* Adds a single column-value pair to the row.
* @param string $col Column name.
* @param mixed $val Value to insert.
* @return Insertion Current instance for method chaining.
* @throws InvalidArgumentException
*/
public function data(string $col, mixed $val): Insertion {
if (!isset($this->table->columns[$col]))
throw new InvalidArgumentException("Column '$col' does not exist.");
$columnType = $this->table->columns[$col]['colType'];
$this->currentRow[$col] = $columnType->valCast($val);
$this->currentRow[$col] = $columnType->dbCast($val);
return $this;
}
public function done(): Insertion {
if (!empty($this->currentRow)) {
$this->batchRows[] = $this->currentRow;
$this->currentRow = [];
}
$this->isReady = true;
/**
* Adds multiple column-value pairs to the row.
* @param array $data Associative array of column-value pairs.
* @return Insertion Current instance for method chaining.
* @throws InvalidArgumentException
*/
public function batchData(array $data): Insertion {
foreach ($data as $key => $value)
$this->data($key, $value);
return $this;
}
/**
* Finalizes the current row and stacks it for insertion.
* @return Insertion Current instance for method chaining.
*/
public function stack(): Insertion {
if (!empty($this->currentRow))
$this->stackForInsertion();
return $this;
}
private function stackForInsertion(): void {
$this->batchRows[] = $this->currentRow;
$this->currentRow = [];
}
/**
* Executes the insertion of all batched rows into the database.
* @throws InvalidArgumentException
*/
public function insert(): void {
global $wpdb;
// Convert single to batch queries.
if (!$this->isReady and !empty($this->currentRow)) {
$this->batchRows[] = $this->currentRow;
$this->currentRow = [];
$this->isReady = true;
}
if (!empty($this->currentRow))
$this->stackForInsertion();
if (empty($this->batchRows))
throw new InvalidArgumentException("No data set for insertion.");

23
Schema.php Normal file
View File

@ -0,0 +1,23 @@
<?php
namespace DatabaseHelper;
use DatabaseHelper\enums\CharsetTypes;
use DatabaseHelper\enums\CollationTypes;
use DatabaseHelper\enums\EngineTypes;
class Schema
{
public string $name = '';
public array $columns = [];
public array $primaryKey = [];
public array $foreignKeys = [];
public EngineTypes $engine = EngineTypes::INNODB;
public CharsetTypes $charset = CharsetTypes::UTF8;
public CollationTypes $collation = CollationTypes::UTF8_GENERAL_CI;
public function __construct(string $tableName) {
$this->name = $tableName;
}
}

View File

@ -10,29 +10,18 @@ use InvalidArgumentException;
class Table
{
public string $tableName;
public array $columns = [];
public array $primaryKey;
public array $foreignKeys = [];
// Table settings
protected EngineTypes $engine = EngineTypes::INNODB;
protected CharsetTypes $charset = CharsetTypes::UTF8;
protected CollationTypes $collation = CollationTypes::UTF8_GENERAL_CI;
public Schema $table;
public function __construct(string $tableName) {
Database::standardizeTableNames($tableName);
$this->tableName = $tableName;
$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]))
throw new InvalidArgumentException('Column name already exists.');
$this->columns[$colName] = [
$this->table->columns[$colName] = [
'colName' => $colName,
'defaultVal' => $default,
'colType' => $colType,
@ -47,7 +36,7 @@ class Table
if(isset($this->primaryKey))
throw new InvalidArgumentException('Primary column already exists.');
$this->primaryKey = [
$this->table->primaryKey = [
'colName' => $colName,
'colType' => $colType,
'autoincrement' => $autoInc
@ -56,46 +45,46 @@ class Table
return $this->column($colName, $colType);
}
public function referenceColumn(Table $foreignTable, CascadeTypes $onDelete = CascadeTypes::CASCADE, CascadeTypes $onUpdate = CascadeTypes::CASCADE): Table {
public function reference(Schema $foreignTable, CascadeTypes $onDelete = CascadeTypes::CASCADE, CascadeTypes $onUpdate = CascadeTypes::CASCADE): Table {
$colName = $foreignTable->primaryKey['colName'];
if(isset($this->columns[$colName]))
throw new InvalidArgumentException('Column name already exists.');
$this->foreignKeys[] = [
$this->table->foreignKeys[] = [
'colName' => $colName,
'tableName' => $foreignTable->tableName,
'tableName' => $foreignTable->name,
'onDelete' => $onDelete,
'onUpdate' => $onUpdate
];
$this->columns[$colName] = $foreignTable->columns[$colName];
$this->table->columns[$colName] = $foreignTable->columns[$colName];
return $this;
}
public function engine(EngineTypes $engine): Table {
$this->engine = $engine;
$this->table->engine = $engine;
return $this;
}
public function charset(CharsetTypes $charset): Table {
$this->charset = $charset;
$this->table->charset = $charset;
return $this;
}
public function collation(CollationTypes $collation): Table {
$this->collation = $collation;
$this->table->collation = $collation;
return $this;
}
public function toSql(): string {
$sql = "CREATE TABLE `{$this->tableName}` (\n";
$sql = "CREATE TABLE `{$this->table->name}` (\n";
// Add primary key constraint if present
if (!empty($this->primaryKey))
$sql .= " PRIMARY KEY (`{$this->primaryKey['colName']}`),\n";
foreach ($this->columns as $column) {
if ($column['colName'] !== $this->primaryKey['colName']) {
foreach ($this->table->columns as $column) {
if ($column['colName'] !== $this->table->primaryKey['colName']) {
$sql .= " `{$column['colName']}` {$column['colType']->value}";
// Handle nulls, uniqueness, and defaults
@ -113,30 +102,30 @@ class Table
}
// Add secondary constraints if present
foreach ($this->foreignKeys as $foreignKey) {
foreach ($this->table->foreignKeys as $foreignKey) {
$sql .= " FOREIGN KEY (`{$foreignKey['colName']}`) REFERENCES `{$foreignKey['tableName']}` (`{$foreignKey['colName']}`)";
$sql .= " ON DELETE {$foreignKey['onDelete']->type()} ON UPDATE {$foreignKey['onUpdate']->type()},\n";
$sql .= " ON DELETE {$foreignKey['onDelete']->toString()} ON UPDATE {$foreignKey['onUpdate']->toString()},\n";
}
// Close the SQL string and add constraints
$sql = rtrim($sql, ",\n") . "\n";
$sql .= ") ENGINE={$this->engine->type()} CHARSET={$this->charset->type()} COLLATE={$this->collation->type()};";
$sql .= ") ENGINE={$this->table->engine->toString()} CHARSET={$this->table->charset->toString()} COLLATE={$this->table->collation->toString()};";
return esc_sql($sql);
}
public function create(): Table {
public function create(): Schema {
global $wpdb;
if (empty($this->primaryKey))
throw new InvalidArgumentException('A primary key must be defined.');
$table_name = $wpdb->prefix . $this->tableName;
$table_name = $wpdb->prefix . $this->table->name;
if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") !== $table_name) {
$sql = $this->toSql();
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
}
return $this;
return $this->table;
}
}

View File

@ -9,7 +9,7 @@ enum CascadeTypes
case RESTRICT;
case SET_DEFAULT;
public function type(): string {
public function toString(): string {
return match ($this) {
self::CASCADE => 'CASCADE',
self::SET_NULL => 'SET NULL',

View File

@ -18,7 +18,7 @@ enum CharsetTypes
case HEBREW;
case BINARY;
public function type(): string {
public function toString(): string {
return match ($this) {
self::UTF8 => 'utf8',
self::UTF8MB4 => 'utf8mb4',

View File

@ -14,7 +14,7 @@ enum CollationTypes
case UTF8_BIN;
case LATIN1_BIN;
public function type(): string {
public function toString(): string {
return match ($this) {
self::UTF8_GENERAL_CI => 'utf8_general_ci',
self::UTF8_UNICODE_CI => 'utf8_unicode_ci',

View File

@ -26,14 +26,14 @@ enum ColumnTypes
return match ($this) {
self::INT => intval($value),
self::FLOAT => floatval($value),
self::STRING => esc_sql($value),
self::BOOL => filter_var($value, FILTER_VALIDATE_BOOLEAN) ? "TRUE" : "FALSE",
self::ARRAY => json_encode($value),
self::DATE => $value instanceof DateTime ? $value->format('Y-m-d H:i:s') : json_encode($value),
default => is_object($value) ? json_encode($value) : $value,
self::DATE => $value instanceof DateTime ? $value->format('Y-m-d H:i:s') : json_encode($value)
};
}
public function type(): string {
public function toString(): string {
return match ($this) {
self::INT => 'INTEGER',
self::FLOAT => 'FLOAT',

View File

@ -6,7 +6,7 @@ enum EngineTypes
case INNODB;
case MYISAM;
public function type(): string {
public function toString(): string {
return match ($this) {
self::INNODB => 'InnoDB',
self::MYISAM => 'MyISAM',

View File

@ -32,9 +32,7 @@ try {
$batchInsert = Database::makeInsertion($table);
foreach($batches as $batch) {
foreach($batch as $col => $value)
$batchInsert->data($col, $value);
$batchInsert->done();
$batchInsert->batchData($batch)->stack();
}
$batchInsert->insert();