diff --git a/database/migrations/2025_09_14_000000_create_component_checks_table.php b/database/migrations/2025_09_14_000000_create_component_checks_table.php index 4f3d92d4..2462090b 100644 --- a/database/migrations/2025_09_14_000000_create_component_checks_table.php +++ b/database/migrations/2025_09_14_000000_create_component_checks_table.php @@ -13,7 +13,13 @@ public function up(): void { Schema::create('component_checks', function (Blueprint $table) { $table->id(); - $table->unsignedInteger('component_id'); + + if ($this->componentsTableUsesBigIntegerIds()) { + $table->unsignedBigInteger('component_id'); + } else { + $table->unsignedInteger('component_id'); + } + $table->unsignedTinyInteger('status'); $table->boolean('successful')->default(false); $table->unsignedSmallInteger('response_code')->nullable(); @@ -32,4 +38,17 @@ public function down(): void { Schema::dropIfExists('component_checks'); } + + /** + * Whether the components table keys its rows by big integers. + * + * components.id is an unsigned integer on fresh installations and on + * upgrades from 2.x, but a big integer on databases created by early 3.x + * builds. MySQL refuses a foreign key whose column type does not match + * the column it references, so component_id must mirror the parent. + */ + private function componentsTableUsesBigIntegerIds(): bool + { + return in_array(Schema::getColumnType('components', 'id'), ['bigint', 'int8'], true); + } }; diff --git a/database/migrations/2026_07_25_000001_create_component_status_changes_table.php b/database/migrations/2026_07_25_000001_create_component_status_changes_table.php index 1c805758..7d24fdc5 100644 --- a/database/migrations/2026_07_25_000001_create_component_status_changes_table.php +++ b/database/migrations/2026_07_25_000001_create_component_status_changes_table.php @@ -13,7 +13,13 @@ public function up(): void { Schema::create('component_status_changes', function (Blueprint $table) { $table->id(); - $table->unsignedInteger('component_id'); + + if ($this->componentsTableUsesBigIntegerIds()) { + $table->unsignedBigInteger('component_id'); + } else { + $table->unsignedInteger('component_id'); + } + $table->unsignedTinyInteger('old_status')->nullable(); $table->unsignedTinyInteger('new_status'); $table->string('source'); @@ -33,4 +39,17 @@ public function down(): void { Schema::dropIfExists('component_status_changes'); } + + /** + * Whether the components table keys its rows by big integers. + * + * components.id is an unsigned integer on fresh installations and on + * upgrades from 2.x, but a big integer on databases created by early 3.x + * builds. MySQL refuses a foreign key whose column type does not match + * the column it references, so component_id must mirror the parent. + */ + private function componentsTableUsesBigIntegerIds(): bool + { + return in_array(Schema::getColumnType('components', 'id'), ['bigint', 'int8'], true); + } }; diff --git a/tests/Unit/Database/ComponentStatusChangesTableTest.php b/tests/Unit/Database/ComponentStatusChangesTableTest.php new file mode 100644 index 00000000..e551c6f8 --- /dev/null +++ b/tests/Unit/Database/ComponentStatusChangesTableTest.php @@ -0,0 +1,20 @@ +firstWhere('name', 'id'); + $componentId = collect(Schema::getColumns('component_status_changes'))->firstWhere('name', 'component_id'); + + expect($componentId['type'])->toBe($componentsId['type']); +}); + +it('constrains component_id to components.id with cascading deletes', function () { + $foreignKey = collect(Schema::getForeignKeys('component_status_changes')) + ->first(fn (array $key) => $key['columns'] === ['component_id']); + + expect($foreignKey)->not->toBeNull() + ->and($foreignKey['foreign_table'])->toBe('components') + ->and($foreignKey['foreign_columns'])->toBe(['id']) + ->and(strtolower($foreignKey['on_delete']))->toBe('cascade'); +});