From 817513095ed4f19408eb81af7f68f7935318d4fd Mon Sep 17 00:00:00 2001 From: Jan-Niclas Loosen Date: Wed, 5 Feb 2025 15:40:52 +0100 Subject: [PATCH] Seperate table and schema --- Insertion.php | 56 +++++++++++++++++++++++++++------------- Schema.php | 23 +++++++++++++++++ Table.php | 51 ++++++++++++++---------------------- enums/CascadeTypes.php | 2 +- enums/CharsetTypes.php | 2 +- enums/CollationTypes.php | 2 +- enums/ColumnTypes.php | 6 ++--- enums/EngineTypes.php | 2 +- index.php | 4 +-- 9 files changed, 89 insertions(+), 59 deletions(-) create mode 100644 Schema.php diff --git a/Insertion.php b/Insertion.php index 6b4b119..18ab6de 100644 --- a/Insertion.php +++ b/Insertion.php @@ -1,52 +1,72 @@ 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."); diff --git a/Schema.php b/Schema.php new file mode 100644 index 0000000..b22d265 --- /dev/null +++ b/Schema.php @@ -0,0 +1,23 @@ +name = $tableName; + } +} \ No newline at end of file diff --git a/Table.php b/Table.php index 7455760..f299572 100644 --- a/Table.php +++ b/Table.php @@ -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; } } diff --git a/enums/CascadeTypes.php b/enums/CascadeTypes.php index f8f50f0..ad5c313 100644 --- a/enums/CascadeTypes.php +++ b/enums/CascadeTypes.php @@ -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', diff --git a/enums/CharsetTypes.php b/enums/CharsetTypes.php index 204330b..a200d6b 100644 --- a/enums/CharsetTypes.php +++ b/enums/CharsetTypes.php @@ -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', diff --git a/enums/CollationTypes.php b/enums/CollationTypes.php index 446d223..a6fed07 100644 --- a/enums/CollationTypes.php +++ b/enums/CollationTypes.php @@ -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', diff --git a/enums/ColumnTypes.php b/enums/ColumnTypes.php index 5c49822..f312b08 100644 --- a/enums/ColumnTypes.php +++ b/enums/ColumnTypes.php @@ -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', diff --git a/enums/EngineTypes.php b/enums/EngineTypes.php index 1f6293b..e1c7b08 100644 --- a/enums/EngineTypes.php +++ b/enums/EngineTypes.php @@ -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', diff --git a/index.php b/index.php index 1e31f13..9cbac24 100644 --- a/index.php +++ b/index.php @@ -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();