improve migration class
This commit is contained in:
		@@ -7,7 +7,7 @@ use InvalidArgumentException;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class Migration
 | 
					class Migration
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    protected Schema $table;
 | 
					    protected Schema $schema;
 | 
				
			||||||
    protected array $columnsToAdd = [];
 | 
					    protected array $columnsToAdd = [];
 | 
				
			||||||
    protected array $columnsToModify = [];
 | 
					    protected array $columnsToModify = [];
 | 
				
			||||||
    protected array $columnsToDrop = [];
 | 
					    protected array $columnsToDrop = [];
 | 
				
			||||||
@@ -16,11 +16,13 @@ class Migration
 | 
				
			|||||||
    protected array $foreignKeysToDrop = [];
 | 
					    protected array $foreignKeysToDrop = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function __construct(Schema $table) {
 | 
					    public function __construct(Schema $table) {
 | 
				
			||||||
        $this->table = $table->copy();
 | 
					        $this->schema = $table->copy();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function addColumn(string $name, Type $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Migration {
 | 
					    public function add(string $name, Type $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Migration {
 | 
				
			||||||
        $this->table->columns[$name] = [
 | 
					        if ($this->schema->existsColumn($name))
 | 
				
			||||||
 | 
					            throw new InvalidArgumentException("Column '$name' already exists.");
 | 
				
			||||||
 | 
					        $this->schema->columns[$name] = [
 | 
				
			||||||
            'name' => $name,
 | 
					            'name' => $name,
 | 
				
			||||||
            'type' => $type,
 | 
					            'type' => $type,
 | 
				
			||||||
            'default' => $default,
 | 
					            'default' => $default,
 | 
				
			||||||
@@ -31,11 +33,9 @@ class Migration
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function modifyColumn(string $name, Type $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Migration {
 | 
					    public function modify(string $name, Type $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Migration {
 | 
				
			||||||
        if (!isset($this->table->columns[$name])) {
 | 
					        $this->schema->requireColumn($name);
 | 
				
			||||||
            throw new InvalidArgumentException("Column $name does not exist.");
 | 
					        $this->schema->columns[$name] = [
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        $this->table->columns[$name] = [
 | 
					 | 
				
			||||||
            'name' => $name,
 | 
					            'name' => $name,
 | 
				
			||||||
            'type' => $type,
 | 
					            'type' => $type,
 | 
				
			||||||
            'default' => $default,
 | 
					            'default' => $default,
 | 
				
			||||||
@@ -46,87 +46,27 @@ class Migration
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function dropColumn(string $name): Migration {
 | 
					    public function delete(string $name): Migration {
 | 
				
			||||||
        if (!isset($this->table->columns[$name])) {
 | 
					        $this->schema->requireColumn($name);
 | 
				
			||||||
            throw new InvalidArgumentException("Column $name does not exist.");
 | 
					        unset($this->schema->columns[$name]);
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        unset($this->table->columns[$name]);
 | 
					 | 
				
			||||||
        $this->columnsToDrop[] = $name;
 | 
					        $this->columnsToDrop[] = $name;
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function changePrimaryKey(string $name, bool $autoInc = false): Migration {
 | 
					    public function reference(Schema $foreignTable, Propagation $onDelete = Propagation::CASCADE, Propagation $onUpdate = Propagation::CASCADE): Migration {
 | 
				
			||||||
        if (!isset($this->table->columns[$name])) {
 | 
					
 | 
				
			||||||
            throw new InvalidArgumentException("Column $name does not exist.");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        $this->table->primaryKey = [
 | 
					 | 
				
			||||||
            'name' => $name,
 | 
					 | 
				
			||||||
            'autoInc' => $autoInc
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
        $this->primaryKey = $name;
 | 
					 | 
				
			||||||
        return $this;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function addForeignKey(string $column, string $referencedTable, string $referencedColumn, Propagation $onDelete, Propagation $onUpdate): Migration {
 | 
					    public function dereference(Schema $foreignTable): Migration {
 | 
				
			||||||
        if (!isset($this->table->columns[$column])) {
 | 
					 | 
				
			||||||
            throw new InvalidArgumentException("Column $column does not exist.");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        $this->table->foreignKeys[$column] = [
 | 
					 | 
				
			||||||
            'referencedTable' => $referencedTable,
 | 
					 | 
				
			||||||
            'referencedColumn' => $referencedColumn,
 | 
					 | 
				
			||||||
            'onDelete' => $onDelete,
 | 
					 | 
				
			||||||
            'onUpdate' => $onUpdate
 | 
					 | 
				
			||||||
        ];
 | 
					 | 
				
			||||||
        $this->foreignKeysToAdd[] = $column;
 | 
					 | 
				
			||||||
        return $this;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function dropForeignKey(string $name): Migration {
 | 
					 | 
				
			||||||
        if (!isset($this->table->foreignKeys[$name])) {
 | 
					 | 
				
			||||||
            throw new InvalidArgumentException("Foreign key $name does not exist.");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        unset($this->table->foreignKeys[$name]);
 | 
					 | 
				
			||||||
        $this->foreignKeysToDrop[] = $name;
 | 
					 | 
				
			||||||
        return $this;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function toSql(): string {
 | 
					    public function toSql(): string {
 | 
				
			||||||
        $sql = "ALTER TABLE `{$this->table->name}` ";
 | 
					 | 
				
			||||||
        $statements = [];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        foreach ($this->columnsToAdd as $name) {
 | 
					 | 
				
			||||||
            $col = $this->table->columns[$name];
 | 
					 | 
				
			||||||
            $statements[] = "ADD COLUMN `{$col['name']}` {$col['type']->toString()}" .
 | 
					 | 
				
			||||||
                ($col['isNullable'] ? "" : " NOT NULL") .
 | 
					 | 
				
			||||||
                ($col['isUnique'] ? " UNIQUE" : "") .
 | 
					 | 
				
			||||||
                ($col['default'] !== null ? " DEFAULT " . (is_string($col['default']) ? "'{$col['default']}'" : $col['default']) : "");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        foreach ($this->columnsToModify as $name) {
 | 
					 | 
				
			||||||
            $col = $this->table->columns[$name];
 | 
					 | 
				
			||||||
            $statements[] = "MODIFY COLUMN `{$col['name']}` {$col['type']->toString()}" .
 | 
					 | 
				
			||||||
                ($col['isNullable'] ? "" : " NOT NULL") .
 | 
					 | 
				
			||||||
                ($col['isUnique'] ? " UNIQUE" : "") .
 | 
					 | 
				
			||||||
                ($col['default'] !== null ? " DEFAULT " . (is_string($col['default']) ? "'{$col['default']}'" : $col['default']) : "");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        foreach ($this->columnsToDrop as $name) {
 | 
					 | 
				
			||||||
            $statements[] = "DROP COLUMN `$name`";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        foreach ($this->foreignKeysToDrop as $name) {
 | 
					 | 
				
			||||||
            $statements[] = "DROP FOREIGN KEY `$name`";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        foreach ($this->foreignKeysToAdd as $column) {
 | 
					 | 
				
			||||||
            $fk = $this->table->foreignKeys[$column];
 | 
					 | 
				
			||||||
            $statements[] = "ADD CONSTRAINT `fk_{$column}` FOREIGN KEY (`$column`) REFERENCES `{$fk['referencedTable']}` (`{$fk['referencedColumn']}`) ON DELETE {$fk['onDelete']->toString()} ON UPDATE {$fk['onUpdate']->toString()}";
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return $sql . implode(", ", $statements) . ";";
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function drop(): null {
 | 
					    public function drop(): null {
 | 
				
			||||||
 | 
					        global $wpdb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -134,6 +74,6 @@ class Migration
 | 
				
			|||||||
        global $wpdb;
 | 
					        global $wpdb;
 | 
				
			||||||
        $sql = $this->toSql();
 | 
					        $sql = $this->toSql();
 | 
				
			||||||
        $wpdb->query($sql);
 | 
					        $wpdb->query($sql);
 | 
				
			||||||
        return $this->table;
 | 
					        return $this->schema;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										55
									
								
								Query.php
									
									
									
									
									
								
							
							
						
						
									
										55
									
								
								Query.php
									
									
									
									
									
								
							@@ -1,6 +1,7 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
namespace DatabaseHelper;
 | 
					namespace DatabaseHelper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use DatabaseHelper\enums\Aggregation;
 | 
				
			||||||
use DatabaseHelper\enums\Join;
 | 
					use DatabaseHelper\enums\Join;
 | 
				
			||||||
use DatabaseHelper\enums\Order;
 | 
					use DatabaseHelper\enums\Order;
 | 
				
			||||||
use http\Exception\InvalidArgumentException;
 | 
					use http\Exception\InvalidArgumentException;
 | 
				
			||||||
@@ -12,6 +13,7 @@ class Query
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    protected Schema $schema;
 | 
					    protected Schema $schema;
 | 
				
			||||||
    protected array $columns = ['*'];
 | 
					    protected array $columns = ['*'];
 | 
				
			||||||
 | 
					    protected array $aggregations = [];
 | 
				
			||||||
    protected array $joins = [];
 | 
					    protected array $joins = [];
 | 
				
			||||||
    public array $orderBy;
 | 
					    public array $orderBy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -36,7 +38,7 @@ class Query
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function join(Schema $other, Join $join): Query {
 | 
					    public function join(Join $join, Schema $other): Query {
 | 
				
			||||||
        $foreignKey = null;
 | 
					        $foreignKey = null;
 | 
				
			||||||
        if($this->schema->existsReference($other))
 | 
					        if($this->schema->existsReference($other))
 | 
				
			||||||
            $foreignKey = $this->schema->foreignKeys[$other->name];
 | 
					            $foreignKey = $this->schema->foreignKeys[$other->name];
 | 
				
			||||||
@@ -65,17 +67,20 @@ class Query
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function toSql(): string {
 | 
					    public function toSql(): string {
 | 
				
			||||||
 | 
					        // Merge any aggregations with the standard columns.
 | 
				
			||||||
 | 
					        $selectColumns = $this->columns;
 | 
				
			||||||
 | 
					        if ($this->hasAggregations())
 | 
				
			||||||
 | 
					            $selectColumns = array_merge($selectColumns, $this->aggregations);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Build the SELECT clause.
 | 
					        // Build the SELECT clause.
 | 
				
			||||||
        $columns = implode(", ", $this->columns);
 | 
					        $columns = implode(", ", $selectColumns);
 | 
				
			||||||
        $primaryTable = $this->schema->name;
 | 
					        $primaryTable = $this->schema->name;
 | 
				
			||||||
        $sqlStatement = "SELECT $columns FROM $primaryTable";
 | 
					        $sqlStatement = "SELECT $columns FROM $primaryTable";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Append join clauses, if any.
 | 
					        // Append join clauses, if any.
 | 
				
			||||||
        if ($this->isJoined()) {
 | 
					        if ($this->isJoined())
 | 
				
			||||||
            foreach ($this->joins as $join) {
 | 
					            foreach ($this->joins as $join)
 | 
				
			||||||
                $sqlStatement .= " " . $join['type']->toString() . " NATURAL JOIN " . $join['table'];
 | 
					                $sqlStatement .= " " . $join['type']->toString() . " NATURAL JOIN " . $join['table'];
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Append the WHERE clause if conditions exist.
 | 
					        // Append the WHERE clause if conditions exist.
 | 
				
			||||||
        if ($this->isConditioned()) {
 | 
					        if ($this->isConditioned()) {
 | 
				
			||||||
@@ -92,18 +97,46 @@ class Query
 | 
				
			|||||||
        return esc_sql($sqlStatement);
 | 
					        return esc_sql($sqlStatement);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function query(): array {
 | 
					    public function aggregate(string $col, string $alias, Aggregation $func): Query {
 | 
				
			||||||
 | 
					        if ($col != '*')
 | 
				
			||||||
 | 
					            $this->schema->requireColumn($col);
 | 
				
			||||||
 | 
					        $this->aggregations[] = strtoupper($func->toString()) . "($col) AS $alias";
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function hasAggregations(): bool {
 | 
				
			||||||
 | 
					        return !empty($this->aggregations);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function query(): mixed {
 | 
				
			||||||
        global $wpdb;
 | 
					        global $wpdb;
 | 
				
			||||||
        $query = $this->toSql();
 | 
					        $query = $this->toSql();
 | 
				
			||||||
        $results = $wpdb->get_results($query, ARRAY_A);
 | 
					        $results = $wpdb->get_results($query, ARRAY_A);
 | 
				
			||||||
        return $this->castResults($results);
 | 
					        return $this->formatResults($results);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected function castResults(array $results): array {
 | 
					    protected function formatResults(array $results) {
 | 
				
			||||||
        foreach ($results as &$row)
 | 
					        $formatted = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($results as $row) {
 | 
				
			||||||
 | 
					            // Apply type casting to each column in each row.
 | 
				
			||||||
            foreach ($row as $column => &$value)
 | 
					            foreach ($row as $column => &$value)
 | 
				
			||||||
                if (isset($this->columnTypes[$column]))
 | 
					                if (isset($this->columnTypes[$column]))
 | 
				
			||||||
                    $value = $this->columnTypes[$column]->valCast($value);
 | 
					                    $value = $this->columnTypes[$column]->valCast($value);
 | 
				
			||||||
        return $results;
 | 
					            // Use the primary key for row indexing
 | 
				
			||||||
 | 
					            $primaryKey = $this->schema->primaryKey();
 | 
				
			||||||
 | 
					            $formatted[$row[$primaryKey]] = $row;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (count($formatted) === 1) {
 | 
				
			||||||
 | 
					            // Unpack single row results
 | 
				
			||||||
 | 
					            $row = array_shift($formatted);
 | 
				
			||||||
 | 
					            if (count($row) === 1)
 | 
				
			||||||
 | 
					                // Unpack single column results
 | 
				
			||||||
 | 
					                return array_shift($row);
 | 
				
			||||||
 | 
					            return $row;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $formatted;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										11
									
								
								Schema.php
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								Schema.php
									
									
									
									
									
								
							@@ -1,6 +1,7 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
namespace DatabaseHelper;
 | 
					namespace DatabaseHelper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use DatabaseHelper\enums\Aggregation;
 | 
				
			||||||
use DatabaseHelper\enums\Charset;
 | 
					use DatabaseHelper\enums\Charset;
 | 
				
			||||||
use DatabaseHelper\enums\Collation;
 | 
					use DatabaseHelper\enums\Collation;
 | 
				
			||||||
use DatabaseHelper\enums\Engine;
 | 
					use DatabaseHelper\enums\Engine;
 | 
				
			||||||
@@ -38,6 +39,12 @@ class Schema
 | 
				
			|||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function countEntries(): int {
 | 
				
			||||||
 | 
					        return Database::makeQuery($this)
 | 
				
			||||||
 | 
					            ->aggregate('*', 'count', Aggregation::COUNT)
 | 
				
			||||||
 | 
					            ->query();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function columnType(string $col) {
 | 
					    public function columnType(string $col) {
 | 
				
			||||||
        return $this->columns[$col]['type'];
 | 
					        return $this->columns[$col]['type'];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -46,10 +53,6 @@ class Schema
 | 
				
			|||||||
        return $this->columns['primary']['name'];
 | 
					        return $this->columns['primary']['name'];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Creates a deep copy of this instance.
 | 
					 | 
				
			||||||
     * @return Schema
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public function copy(): Schema {
 | 
					    public function copy(): Schema {
 | 
				
			||||||
        $copy = new Schema($this->name);
 | 
					        $copy = new Schema($this->name);
 | 
				
			||||||
        $copy->columns = genericDeepCopy($this->columns);
 | 
					        $copy->columns = genericDeepCopy($this->columns);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										211
									
								
								Table.php
									
									
									
									
									
								
							
							
						
						
									
										211
									
								
								Table.php
									
									
									
									
									
								
							@@ -2,130 +2,165 @@
 | 
				
			|||||||
namespace DatabaseHelper;
 | 
					namespace DatabaseHelper;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use DatabaseHelper\enums\Propagation;
 | 
					use DatabaseHelper\enums\Propagation;
 | 
				
			||||||
use DatabaseHelper\enums\Charset;
 | 
					 | 
				
			||||||
use DatabaseHelper\enums\Collation;
 | 
					 | 
				
			||||||
use DatabaseHelper\enums\Type;
 | 
					use DatabaseHelper\enums\Type;
 | 
				
			||||||
use DatabaseHelper\enums\Engine;
 | 
					 | 
				
			||||||
use InvalidArgumentException;
 | 
					use InvalidArgumentException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Table
 | 
					class Migration
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    protected Schema $table;
 | 
					    protected Schema $schema;
 | 
				
			||||||
 | 
					    protected array $columnsToAdd = [];
 | 
				
			||||||
 | 
					    protected array $columnsToModify = [];
 | 
				
			||||||
 | 
					    protected array $columnsToDrop = [];
 | 
				
			||||||
 | 
					    protected ?array $primaryKey = null;
 | 
				
			||||||
 | 
					    protected array $foreignKeysToAdd = [];
 | 
				
			||||||
 | 
					    protected array $foreignKeysToDrop = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function __construct(string $tableName) {
 | 
					    public function __construct(Schema $table) {
 | 
				
			||||||
        Database::standardizeTableNames($tableName);
 | 
					        $this->schema = $table->copy();
 | 
				
			||||||
        $this->table = new Schema($tableName);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function column(string $name, Type $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Table {
 | 
					    public function column(string $name, Type $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Migration {
 | 
				
			||||||
        $this->table->columns[$name] = [
 | 
					        if ($this->schema->existsColumn($name))
 | 
				
			||||||
            'name' => $name,
 | 
					            throw new InvalidArgumentException("Column '$name' already exists.");
 | 
				
			||||||
            'default' => $default,
 | 
					        $this->schema->columns[$name] = [
 | 
				
			||||||
            'type' => $type,
 | 
					            'name'       => $name,
 | 
				
			||||||
 | 
					            'type'       => $type,
 | 
				
			||||||
 | 
					            'default'    => $default,
 | 
				
			||||||
            'isNullable' => $isNullable,
 | 
					            'isNullable' => $isNullable,
 | 
				
			||||||
            'isUnique' => $isUnique
 | 
					            'isUnique'   => $isUnique
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					        $this->columnsToAdd[] = $name;
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function primary(string $name, Type $type, bool $autoInc = false): Table {
 | 
					    public function modify(string $name, Type $type, mixed $default = null, bool $isNullable = false, bool $isUnique = false): Migration {
 | 
				
			||||||
        if(isset($this->primaryKey))
 | 
					        $this->schema->requireColumn($name);
 | 
				
			||||||
            throw new InvalidArgumentException('Primary column already exists.');
 | 
					        $this->schema->columns[$name] = [
 | 
				
			||||||
 | 
					            'name'       => $name,
 | 
				
			||||||
        $this->table->primaryKey = [
 | 
					            'type'       => $type,
 | 
				
			||||||
            'name' => $name,
 | 
					            'default'    => $default,
 | 
				
			||||||
            'autoInc' => $autoInc
 | 
					            'isNullable' => $isNullable,
 | 
				
			||||||
 | 
					            'isUnique'   => $isUnique
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					        $this->columnsToModify[] = $name;
 | 
				
			||||||
        return $this->column($name, $type);
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function reference(Schema $foreignTable, Propagation $onDelete = Propagation::CASCADE, Propagation $onUpdate = Propagation::CASCADE): Table {
 | 
					    public function delete(string $name): Migration {
 | 
				
			||||||
        $name = $foreignTable->primaryKey();
 | 
					        $this->schema->requireColumn($name);
 | 
				
			||||||
        if(isset($this->columns[$name]))
 | 
					        unset($this->schema->columns[$name]);
 | 
				
			||||||
            throw new InvalidArgumentException('Column name already exists.');
 | 
					        $this->columnsToDrop[] = $name;
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->table->foreignKeys[$name] = [
 | 
					    public function reference(Schema $foreignTable, Propagation $onDelete = Propagation::CASCADE, Propagation $onUpdate = Propagation::CASCADE): Migration {
 | 
				
			||||||
            'name' => $name,
 | 
					        $name = $foreignTable->primaryKey();
 | 
				
			||||||
            'table' => $foreignTable->name,
 | 
					        if ($this->schema->existsColumn($name))
 | 
				
			||||||
 | 
					            throw new InvalidArgumentException("Column '$name' already exists.");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->schema->foreignKeys[$name] = [
 | 
				
			||||||
 | 
					            'name'     => $name,
 | 
				
			||||||
 | 
					            'table'    => $foreignTable->name,
 | 
				
			||||||
            'onDelete' => $onDelete,
 | 
					            'onDelete' => $onDelete,
 | 
				
			||||||
            'onUpdate' => $onUpdate
 | 
					            'onUpdate' => $onUpdate
 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->table->columns[$name] = $foreignTable->columns[$name];
 | 
					        $this->schema->columns[$name] = $foreignTable->columns[$name];
 | 
				
			||||||
 | 
					        $this->foreignKeysToAdd[] = $name;
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function engine(Engine $engine): Table {
 | 
					    public function dereference(Schema $foreignTable): Migration {
 | 
				
			||||||
        $this->table->engine = $engine;
 | 
					        $name = $foreignTable->primaryKey();
 | 
				
			||||||
 | 
					        if ($this->schema->existsReference($foreignTable))
 | 
				
			||||||
 | 
					            throw new InvalidArgumentException('Foreign table is not referenced.');
 | 
				
			||||||
 | 
					        unset($this->schema->foreignKeys[$name]);
 | 
				
			||||||
 | 
					        // Also remove the column and mark it for dropping.
 | 
				
			||||||
 | 
					        if (isset($this->schema->columns[$name]))
 | 
				
			||||||
 | 
					            $this->delete($name);
 | 
				
			||||||
 | 
					        $this->foreignKeysToDrop[] = $name;
 | 
				
			||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function charset(Charset $charset): Table {
 | 
					 | 
				
			||||||
        $this->table->charset = $charset;
 | 
					 | 
				
			||||||
        return $this;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    public function collation(Collation $collation): Table {
 | 
					 | 
				
			||||||
        $this->table->collation = $collation;
 | 
					 | 
				
			||||||
        return $this;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Generates the SQL statement.
 | 
					 | 
				
			||||||
     * @return string SQL query.
 | 
					 | 
				
			||||||
     * @throws InvalidArgumentException
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public function toSql(): string {
 | 
					    public function toSql(): string {
 | 
				
			||||||
        $primaryKey = $this->table->primaryKey();
 | 
					        global $wpdb;
 | 
				
			||||||
 | 
					        // We assume that the table name in the schema is not prefixed; add the prefix here.
 | 
				
			||||||
 | 
					        $tableName = $wpdb->prefix . $this->schema->name;
 | 
				
			||||||
 | 
					        $clauses = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $sql = "CREATE TABLE `{$this->table->name}` (\n";
 | 
					        // Process new columns.
 | 
				
			||||||
        $sql .= "  PRIMARY KEY (`$primaryKey`),\n";
 | 
					        foreach ($this->columnsToAdd as $columnName) {
 | 
				
			||||||
 | 
					            $col = $this->schema->columns[$columnName];
 | 
				
			||||||
        foreach ($this->table->columns as $col) {
 | 
					            $clause = "ADD COLUMN `{$col['name']}` " . $col['type']->toString();
 | 
				
			||||||
            if ($col['name'] !== $primaryKey) {
 | 
					            if (!$col['isNullable']) {
 | 
				
			||||||
                $sql .= "  `{$col['name']}` {$col['type']->toString()}";
 | 
					                $clause .= " NOT NULL";
 | 
				
			||||||
                // Handle nulls, uniqueness, and defaults
 | 
					 | 
				
			||||||
                if (!$col['isNullable'])
 | 
					 | 
				
			||||||
                    $sql .= " NOT NULL";
 | 
					 | 
				
			||||||
                if ($col['isUnique'])
 | 
					 | 
				
			||||||
                    $sql .= " UNIQUE";
 | 
					 | 
				
			||||||
                if ($col['default'] !== null) {
 | 
					 | 
				
			||||||
                    $default = is_string($col['default']) ? "'{$col['default']}'" : $col['default'];
 | 
					 | 
				
			||||||
                    $sql .= " DEFAULT $default";
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                $sql .= ",\n";
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            if ($col['isUnique']) {
 | 
				
			||||||
 | 
					                $clause .= " UNIQUE";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if ($col['default'] !== null) {
 | 
				
			||||||
 | 
					                $default = is_string($col['default']) ? "'{$col['default']}'" : $col['default'];
 | 
				
			||||||
 | 
					                $clause .= " DEFAULT $default";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $clauses[] = $clause;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Add secondary constraints if present
 | 
					        // Process modified columns.
 | 
				
			||||||
        foreach ($this->table->foreignKeys as $key) {
 | 
					        foreach ($this->columnsToModify as $columnName) {
 | 
				
			||||||
            $sql .= "  FOREIGN KEY (`{$key['name']}`) REFERENCES `{$key['table']}` (`{$key['name']}`)";
 | 
					            $col = $this->schema->columns[$columnName];
 | 
				
			||||||
            $sql .= " ON DELETE {$key['onDelete']->toString()} ON UPDATE {$key['onUpdate']->toString()},\n";
 | 
					            $clause = "MODIFY COLUMN `{$col['name']}` " . $col['type']->toString();
 | 
				
			||||||
 | 
					            if (!$col['isNullable']) {
 | 
				
			||||||
 | 
					                $clause .= " NOT NULL";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if ($col['isUnique']) {
 | 
				
			||||||
 | 
					                $clause .= " UNIQUE";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if ($col['default'] !== null) {
 | 
				
			||||||
 | 
					                $default = is_string($col['default']) ? "'{$col['default']}'" : $col['default'];
 | 
				
			||||||
 | 
					                $clause .= " DEFAULT $default";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $clauses[] = $clause;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Close the SQL string and add constraints
 | 
					        // Process dropped columns.
 | 
				
			||||||
        $sql = rtrim($sql, ",\n") . "\n) ";
 | 
					        foreach ($this->columnsToDrop as $columnName) {
 | 
				
			||||||
        $sql .= "ENGINE={$this->table->engine->toString()} ";
 | 
					            $clauses[] = "DROP COLUMN `{$columnName}`";
 | 
				
			||||||
        $sql .= "CHARSET={$this->table->charset->toString()} ";
 | 
					        }
 | 
				
			||||||
        $sql -= "COLLATE={$this->table->collation->toString()};";
 | 
					
 | 
				
			||||||
 | 
					        // Process foreign keys to add.
 | 
				
			||||||
 | 
					        foreach ($this->foreignKeysToAdd as $fkName) {
 | 
				
			||||||
 | 
					            $fk = $this->schema->foreignKeys[$fkName];
 | 
				
			||||||
 | 
					            // Here we name the constraint “fk_{$name}”. (There are other acceptable naming schemes.)
 | 
				
			||||||
 | 
					            $clause = "ADD CONSTRAINT `fk_{$fk['name']}` FOREIGN KEY (`{$fk['name']}`) REFERENCES `{$fk['table']}` (`{$fk['name']}`) ON DELETE " . $fk['onDelete']->toString() . " ON UPDATE " . $fk['onUpdate']->toString();
 | 
				
			||||||
 | 
					            $clauses[] = $clause;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Process foreign keys to drop.
 | 
				
			||||||
 | 
					        foreach ($this->foreignKeysToDrop as $fkName) {
 | 
				
			||||||
 | 
					            // Again, we assume the constraint was named “fk_{$name}”
 | 
				
			||||||
 | 
					            $clauses[] = "DROP FOREIGN KEY `fk_{$fkName}`";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (empty($clauses)) {
 | 
				
			||||||
 | 
					            throw new InvalidArgumentException("No migration operations to perform.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $sql = "ALTER TABLE `{$tableName}`\n" . implode(",\n", $clauses) . ";";
 | 
				
			||||||
        return esc_sql($sql);
 | 
					        return esc_sql($sql);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
    public function create(): Schema {
 | 
					    public function drop(): null {
 | 
				
			||||||
        global $wpdb;
 | 
					        global $wpdb;
 | 
				
			||||||
 | 
					        $tableName = $wpdb->prefix . $this->schema->name;
 | 
				
			||||||
 | 
					        $sql = "DROP TABLE IF EXISTS `{$tableName}`;";
 | 
				
			||||||
 | 
					        $wpdb->query(esc_sql($sql));
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (empty($this->primaryKey))
 | 
					    public function migrate(): Schema {
 | 
				
			||||||
            throw new InvalidArgumentException('A primary key must be defined.');
 | 
					        global $wpdb;
 | 
				
			||||||
        $table_name = $wpdb->prefix . $this->table->name;
 | 
					        $sql = $this->toSql();
 | 
				
			||||||
 | 
					        $wpdb->query($sql);
 | 
				
			||||||
        if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") !== $table_name) {
 | 
					        return $this->schema;
 | 
				
			||||||
            $sql = $this->toSql();
 | 
					 | 
				
			||||||
            require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
 | 
					 | 
				
			||||||
            dbDelta($sql);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return $this->table;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										21
									
								
								enums/Aggregation.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								enums/Aggregation.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					namespace DatabaseHelper\enums;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum Aggregation
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    case COUNT;
 | 
				
			||||||
 | 
					    case SUM;
 | 
				
			||||||
 | 
					    case AVG;
 | 
				
			||||||
 | 
					    case MIN;
 | 
				
			||||||
 | 
					    case MAX;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function toString(): string {
 | 
				
			||||||
 | 
					        return match ($this) {
 | 
				
			||||||
 | 
					            self::COUNT => 'COUNT',
 | 
				
			||||||
 | 
					            self::SUM => 'SUM',
 | 
				
			||||||
 | 
					            self::AVG => 'AVG',
 | 
				
			||||||
 | 
					            self::MIN => 'MIN',
 | 
				
			||||||
 | 
					            self::MAX => 'MAX',
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user