packages/ztd-query-sqlite/src/Shadow/Resolution/TableMutationResolver.php
1<?php
2
3declare(strict_types=1);
4
5namespace ZtdQuery\Platform\Sqlite\Shadow\Resolution;
6
7use ZtdQuery\Exception\UnknownSchemaException;
8use ZtdQuery\Exception\UnsupportedSqlException;
9use ZtdQuery\Platform\SchemaParser;
10use ZtdQuery\Platform\Sqlite\Sql\SqliteParser;
11use ZtdQuery\Schema\TableDefinitionRegistry;
12use ZtdQuery\Shadow\Mutation\ShadowMutation;
13use ZtdQuery\Shadow\Mutation\Table\CreateTableMutation;
14use ZtdQuery\Shadow\Mutation\Table\DropTableMutation;
15
16/**
17 * Resolves table lifecycle and ALTER operations.
18 *
19 * @visibility ZtdQuery\Platform\Sqlite
20 */
21final class TableMutationResolver
22{
23 /**
24 * Binds the collaborators used by this operation.
25 */
26 public function __construct(
27 private SqliteParser $parser,
28 private TableDefinitionRegistry $registry,
29 private SchemaParser $schemaParser
30 ) {
31 }
32
33 /**
34 * Resolves table lifecycle and ALTER operations.
35 * @throws UnsupportedSqlException
36 */
37 public function resolveCreateTable(string $sql): ShadowMutation
38 {
39 $tableName = $this->parser->extractTargetTable($sql);
40 if ($tableName === null) {
41 throw new UnsupportedSqlException($sql, 'Cannot resolve table name');
42 }
43
44 $ifNotExists = (bool) preg_match('/\bIF\s+NOT\s+EXISTS\b/i', $sql);
45
46 if (!$ifNotExists && $this->registry->has($tableName)) {
47 throw new UnsupportedSqlException($sql, 'Table already exists');
48 }
49
50 $definition = $this->schemaParser->parse($sql);
51
52 return new CreateTableMutation($tableName, $definition, $this->registry, $sql, $ifNotExists);
53 }
54
55 /**
56 * Resolves table lifecycle and ALTER operations.
57 * @throws UnknownSchemaException
58 * @throws UnsupportedSqlException
59 */
60 public function resolveDropTable(string $sql): ShadowMutation
61 {
62 $tableName = $this->parser->extractTargetTable($sql);
63 if ($tableName === null) {
64 throw new UnsupportedSqlException($sql, 'Cannot resolve table name');
65 }
66
67 $ifExists = (bool) preg_match('/\bIF\s+EXISTS\b/i', $sql);
68
69 if ($this->registry->isRemoved($tableName)) {
70 if ($ifExists) {
71 return new DropTableMutation($tableName, $this->registry, $sql, true);
72 }
73 throw new UnsupportedSqlException($sql, 'Table was removed from the virtual schema');
74 }
75
76 if (!$ifExists && !$this->registry->has($tableName)) {
77 throw new UnknownSchemaException($sql, $tableName, 'table');
78 }
79
80 return new DropTableMutation($tableName, $this->registry, $sql, $ifExists);
81 }
82
83 /**
84 * @throws UnsupportedSqlException
85 * @throws UnknownSchemaException
86 */
87 public function resolveAlterTable(string $sql): ShadowMutation
88 {
89 $tableName = $this->parser->extractTargetTable($sql);
90 if ($tableName === null) {
91 throw new UnsupportedSqlException($sql, 'Cannot resolve table name');
92 }
93
94 (new MutationTableLookup($this->registry))->assertTableWasNotRemoved($sql, $tableName);
95
96 if (!$this->registry->has($tableName)) {
97 throw new UnknownSchemaException($sql, $tableName, 'table');
98 }
99
100 $operation = (new \ZtdQuery\Platform\Sqlite\Sql\Alter\AlterOperationParser())->alterOperation($sql);
101 if ($operation === null) {
102 throw new UnsupportedSqlException($sql, 'Unsupported ALTER TABLE operation');
103 }
104
105 return match ($operation['kind']) {
106 'add' => (new \ZtdQuery\Platform\Sqlite\Shadow\Mutation\Table\Alter\AddColumnResolver($this->registry, $this->schemaParser))->resolveAlterAddColumn($sql, $tableName, $operation['clause']),
107 'drop' => (new \ZtdQuery\Platform\Sqlite\Shadow\Mutation\Table\Alter\DropColumnResolver($this->registry))->resolveAlterDropColumn($sql, $tableName, $operation['clause']),
108 'rename_table' => (new \ZtdQuery\Platform\Sqlite\Shadow\Mutation\Table\Alter\RenameResolver($this->registry))->resolveAlterRenameTable($sql, $tableName, $operation['clause']),
109 'rename_column' => (new \ZtdQuery\Platform\Sqlite\Shadow\Mutation\Table\Alter\RenameResolver($this->registry))->resolveAlterRenameColumn($sql, $tableName, $operation['clause']),
110 };
111 }
112}
113