packages/ztd-query-mysql/src/Shadow/Mutation/Table/Alter/OperationApplier.php

1<?php
2
3declare(strict_types=1);
4
5namespace ZtdQuery\Platform\MySql\Shadow\Mutation\Table\Alter;
6
7use PhpMyAdmin\SqlParser\Components\AlterOperation;
8use PhpMyAdmin\SqlParser\Statements\AlterStatement;
9use PhpMyAdmin\SqlParser\Statements\CreateStatement;
10use ZtdQuery\Exception\UnsupportedSqlException;
11use ZtdQuery\Schema\TableDefinition;
12use ZtdQuery\Schema\TableDefinitionRegistry;
13use ZtdQuery\Shadow\ShadowStore;
14
15/**
16 * Operation Applier.
17 *
18 * @visibility ZtdQuery\Platform\MySql
19 */
20final class OperationApplier
21{
22    /**
23     * Configure the dependencies used by this operation.
24     */
25    public function __construct(private AlterStatement $alterStatement, private TableDefinitionRegistry $registry, private string $tableName)
26    {
27    }
28    /**
29     * Apply a single ALTER operation to the CREATE statement.
30     * @throws UnsupportedSqlException
31     */
32    public function applyOperation(CreateStatement $createStmt, AlterOperation $op, ShadowStore $store, TableDefinition $definition): string
33    {
34        $options = $op->options;
35        if ($options->isEmpty()) {
36            return $this->tableName;
37        }
38
39        $columnAction = (new ColumnAction())->detect($op);
40        if ($columnAction !== null) {
41            $columns = new ColumnAlteration($this->alterStatement, $this->tableName);
42            match ($columnAction) {
43                'add' => $columns->applyAddColumn($createStmt, $op, $definition),
44                'drop' => $columns->applyDropColumn($createStmt, $op, $store, $definition),
45                'modify' => $columns->applyModifyColumn($createStmt, $op, $definition),
46                'change' => $columns->applyChangeColumn($createStmt, $op, $store, $definition),
47            };
48            return $this->tableName;
49        }
50        if (($options->has('RENAME') !== false) && ($options->has('TO') !== false) && !\ZtdQuery\Platform\MySql\Sql\Alter\OptionList::hasAny($options, ['INDEX', 'KEY', 'COLUMN'])) {
51            $this->applyRenameTable($op, $store);
52        } elseif (($options->has('ADD') !== false) && ($options->has('PRIMARY KEY') !== false)) {
53            (new PrimaryKeyAlteration())->applyAddPrimaryKey($createStmt, $op);
54        } elseif (($options->has('DROP') !== false) && ($options->has('PRIMARY KEY') !== false)) {
55            (new PrimaryKeyAlteration())->applyDropPrimaryKey($createStmt);
56        } elseif (($options->has('FOREIGN') !== false) && \ZtdQuery\Platform\MySql\Sql\Alter\OptionList::hasAny($options, ['ADD', 'DROP'])) {
57            return $this->tableName;
58        } elseif (($options->has('RENAME') !== false) && ($options->has('COLUMN') !== false)) {
59            (new ColumnAlteration($this->alterStatement, $this->tableName))->applyRenameColumn($createStmt, $op, $store, $definition);
60        } elseif (($options->has('ALTER') !== false) && (\ZtdQuery\Platform\MySql\Sql\Alter\OptionList::hasAny($options, ['SET DEFAULT', 'DROP DEFAULT']))) {
61            return $this->tableName;
62        } else {
63            throw new UnsupportedSqlException(AlterOperation::build($op), 'ALTER TABLE');
64        }
65        return $this->tableName;
66    }
67
68    /**
69     * Apply Rename Table for the supplied MySQL input.
70     */
71    public function applyRenameTable(AlterOperation $op, ShadowStore $store): void
72    {
73        $toValue = $op->options !== null ? $op->options->has('TO') : false;
74        if (!is_string($toValue) || $toValue === '') {
75            return;
76        }
77
78        $newName = (str_replace('`', '', $toValue));
79
80        $data = $store->get($this->tableName);
81        $store->set($newName, $data);
82        $store->set($this->tableName, []);
83
84        $existingDef = $this->registry->get($this->tableName);
85        if ($existingDef !== null) {
86            $this->registry->unregister($this->tableName);
87            $this->registry->register($newName, $existingDef);
88        }
89
90        $this->tableName = $newName;
91    }
92}
93