|
4 | 4 |
|
5 | 5 | use Illuminate\Database\Migrations\Migration; |
6 | 6 | use Illuminate\Database\Schema\Blueprint; |
7 | | -use Illuminate\Support\Facades\DB; |
8 | 7 | use Illuminate\Support\Facades\Schema; |
9 | 8 |
|
10 | 9 | return new class() extends Migration { |
|
28 | 27 |
|
29 | 28 | public function up(): void |
30 | 29 | { |
31 | | - if (Schema::hasTable(self::TABLE)) { |
32 | | - if (Schema::hasColumns(self::TABLE, [ |
33 | | - 'id', |
34 | | - 'workflow_schedule_id', |
35 | | - 'schedule_id', |
36 | | - 'sequence', |
37 | | - 'event_type', |
38 | | - 'payload', |
39 | | - 'recorded_at', |
40 | | - ])) { |
41 | | - $this->ensureExpectedIndexes(); |
42 | | - |
43 | | - return; |
44 | | - } |
45 | | - |
46 | | - throw new RuntimeException( |
47 | | - self::TABLE . ' already exists but is missing expected schedule-history columns.' |
48 | | - ); |
49 | | - } |
50 | | - |
51 | 30 | Schema::create(self::TABLE, static function (Blueprint $table): void { |
52 | 31 | $table->string('id', 26) |
53 | 32 | ->primary(); |
@@ -82,193 +61,4 @@ public function down(): void |
82 | 61 | { |
83 | 62 | Schema::dropIfExists(self::TABLE); |
84 | 63 | } |
85 | | - |
86 | | - private function ensureExpectedIndexes(): void |
87 | | - { |
88 | | - $this->ensureIndex(['workflow_schedule_id'], self::WORKFLOW_SCHEDULE_INDEX); |
89 | | - $this->ensureIndex(['schedule_id'], self::SCHEDULE_INDEX); |
90 | | - $this->ensureIndex(['namespace'], self::NAMESPACE_INDEX); |
91 | | - $this->ensureIndex(['workflow_instance_id'], self::WORKFLOW_INSTANCE_INDEX); |
92 | | - $this->ensureIndex(['workflow_run_id'], self::WORKFLOW_RUN_INDEX); |
93 | | - $this->ensureIndex(['workflow_schedule_id', 'sequence'], self::SCHEDULE_SEQUENCE_UNIQUE, unique: true); |
94 | | - $this->ensureIndex(['namespace', 'schedule_id'], self::NAMESPACE_SCHEDULE_INDEX); |
95 | | - $this->ensureIndex(['event_type', 'recorded_at'], self::EVENT_RECORDED_INDEX); |
96 | | - } |
97 | | - |
98 | | - /** |
99 | | - * @param array<int, string> $columns |
100 | | - */ |
101 | | - private function ensureIndex(array $columns, string $name, bool $unique = false): void |
102 | | - { |
103 | | - if ($this->hasExpectedIndex($columns, $unique)) { |
104 | | - return; |
105 | | - } |
106 | | - |
107 | | - Schema::table(self::TABLE, static function (Blueprint $table) use ($columns, $name, $unique): void { |
108 | | - if ($unique) { |
109 | | - $table->unique($columns, $name); |
110 | | - |
111 | | - return; |
112 | | - } |
113 | | - |
114 | | - $table->index($columns, $name); |
115 | | - }); |
116 | | - } |
117 | | - |
118 | | - /** |
119 | | - * @param array<int, string> $columns |
120 | | - */ |
121 | | - private function hasExpectedIndex(array $columns, bool $unique): bool |
122 | | - { |
123 | | - $schema = Schema::getFacadeRoot(); |
124 | | - |
125 | | - if (is_object($schema) && method_exists($schema, 'hasIndex')) { |
126 | | - return Schema::hasIndex(self::TABLE, $columns, $unique ? 'unique' : null); |
127 | | - } |
128 | | - |
129 | | - return match (DB::connection()->getDriverName()) { |
130 | | - 'mysql', 'mariadb' => $this->hasMysqlIndex($columns, $unique), |
131 | | - 'pgsql' => $this->hasPostgresIndex($columns, $unique), |
132 | | - 'sqlite' => $this->hasSqliteIndex($columns, $unique), |
133 | | - 'sqlsrv' => $this->hasSqlServerIndex($columns, $unique), |
134 | | - default => false, |
135 | | - }; |
136 | | - } |
137 | | - |
138 | | - /** |
139 | | - * @param array<int, string> $columns |
140 | | - */ |
141 | | - private function hasMysqlIndex(array $columns, bool $unique): bool |
142 | | - { |
143 | | - return $this->indexRowsMatch( |
144 | | - DB::select( |
145 | | - <<<'SQL' |
146 | | - select index_name, (non_unique = 0) as is_unique, column_name |
147 | | - from information_schema.statistics |
148 | | - where table_schema = ? and table_name = ? |
149 | | - order by index_name, seq_in_index |
150 | | - SQL |
151 | | - , |
152 | | - [DB::connection()->getDatabaseName(), self::TABLE] |
153 | | - ), |
154 | | - $columns, |
155 | | - $unique |
156 | | - ); |
157 | | - } |
158 | | - |
159 | | - /** |
160 | | - * @param array<int, string> $columns |
161 | | - */ |
162 | | - private function hasPostgresIndex(array $columns, bool $unique): bool |
163 | | - { |
164 | | - return $this->indexRowsMatch( |
165 | | - DB::select( |
166 | | - <<<'SQL' |
167 | | - select i.relname as index_name, ix.indisunique as is_unique, a.attname as column_name |
168 | | - from pg_class t |
169 | | - join pg_index ix on t.oid = ix.indrelid |
170 | | - join pg_class i on i.oid = ix.indexrelid |
171 | | - join unnest(ix.indkey) with ordinality as ord(attnum, ordinality) on true |
172 | | - join pg_attribute a on a.attrelid = t.oid and a.attnum = ord.attnum |
173 | | - where t.relname = ? |
174 | | - order by i.relname, ord.ordinality |
175 | | - SQL |
176 | | - , |
177 | | - [self::TABLE] |
178 | | - ), |
179 | | - $columns, |
180 | | - $unique |
181 | | - ); |
182 | | - } |
183 | | - |
184 | | - /** |
185 | | - * @param array<int, string> $columns |
186 | | - */ |
187 | | - private function hasSqliteIndex(array $columns, bool $unique): bool |
188 | | - { |
189 | | - $indexes = []; |
190 | | - |
191 | | - foreach (DB::select('pragma index_list(' . $this->sqliteIdentifier(self::TABLE) . ')') as $index) { |
192 | | - $indexName = (string) $index->name; |
193 | | - |
194 | | - $indexes[] = [ |
195 | | - 'unique' => $this->truthy($index->unique ?? false), |
196 | | - 'columns' => array_map( |
197 | | - static fn (object $column): string => (string) $column->name, |
198 | | - DB::select('pragma index_info(' . $this->sqliteIdentifier($indexName) . ')') |
199 | | - ), |
200 | | - ]; |
201 | | - } |
202 | | - |
203 | | - return $this->indexesMatch($indexes, $columns, $unique); |
204 | | - } |
205 | | - |
206 | | - /** |
207 | | - * @param array<int, string> $columns |
208 | | - */ |
209 | | - private function hasSqlServerIndex(array $columns, bool $unique): bool |
210 | | - { |
211 | | - return $this->indexRowsMatch( |
212 | | - DB::select( |
213 | | - <<<'SQL' |
214 | | - select i.name as index_name, i.is_unique as is_unique, c.name as column_name |
215 | | - from sys.indexes i |
216 | | - join sys.index_columns ic on i.object_id = ic.object_id and i.index_id = ic.index_id |
217 | | - join sys.columns c on ic.object_id = c.object_id and ic.column_id = c.column_id |
218 | | - where i.object_id = object_id(?) |
219 | | - order by i.name, ic.key_ordinal |
220 | | - SQL |
221 | | - , |
222 | | - [self::TABLE] |
223 | | - ), |
224 | | - $columns, |
225 | | - $unique |
226 | | - ); |
227 | | - } |
228 | | - |
229 | | - /** |
230 | | - * @param array<int, object> $rows |
231 | | - * @param array<int, string> $columns |
232 | | - */ |
233 | | - private function indexRowsMatch(array $rows, array $columns, bool $unique): bool |
234 | | - { |
235 | | - $indexes = []; |
236 | | - |
237 | | - foreach ($rows as $row) { |
238 | | - $indexName = (string) $row->index_name; |
239 | | - $indexes[$indexName]['unique'] ??= $this->truthy($row->is_unique ?? false); |
240 | | - $indexes[$indexName]['columns'][] = (string) $row->column_name; |
241 | | - } |
242 | | - |
243 | | - return $this->indexesMatch(array_values($indexes), $columns, $unique); |
244 | | - } |
245 | | - |
246 | | - /** |
247 | | - * @param array<int, array{unique: bool, columns: array<int, string>}> $indexes |
248 | | - * @param array<int, string> $columns |
249 | | - */ |
250 | | - private function indexesMatch(array $indexes, array $columns, bool $unique): bool |
251 | | - { |
252 | | - foreach ($indexes as $index) { |
253 | | - if ($index['columns'] === $columns && (! $unique || $index['unique'])) { |
254 | | - return true; |
255 | | - } |
256 | | - } |
257 | | - |
258 | | - return false; |
259 | | - } |
260 | | - |
261 | | - private function sqliteIdentifier(string $identifier): string |
262 | | - { |
263 | | - return '"' . str_replace('"', '""', $identifier) . '"'; |
264 | | - } |
265 | | - |
266 | | - private function truthy(mixed $value): bool |
267 | | - { |
268 | | - return $value === true |
269 | | - || $value === 1 |
270 | | - || $value === '1' |
271 | | - || $value === 't' |
272 | | - || $value === 'true'; |
273 | | - } |
274 | 64 | }; |
0 commit comments