feat(db): add macro_assignments, service macro override tables, and guarded legacy data wipe
This commit is contained in:
parent
09ab4821fc
commit
a65bf3d595
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class () extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('macro_assignments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->enum('part_type', ['information', 'moderation', 'sermon', 'song', 'agenda_item']);
|
||||
$table->foreignId('macro_id')->constrained('macros')->restrictOnDelete();
|
||||
$table->enum('position', ['all_slides', 'first_slide', 'last_slide', 'by_label']);
|
||||
$table->foreignId('label_id')->nullable()->constrained('labels')->restrictOnDelete();
|
||||
$table->unsignedInteger('order')->default(0);
|
||||
$table->timestamps();
|
||||
$table->index(['part_type', 'order']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('macro_assignments');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class () extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('service_macro_overrides', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('service_id')->constrained('services')->cascadeOnDelete();
|
||||
$table->enum('part_type', ['information', 'moderation', 'sermon', 'song', 'agenda_item']);
|
||||
$table->timestamps();
|
||||
$table->unique(['service_id', 'part_type']);
|
||||
});
|
||||
|
||||
Schema::create('service_macro_assignments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('service_id')->constrained('services')->cascadeOnDelete();
|
||||
$table->enum('part_type', ['information', 'moderation', 'sermon', 'song', 'agenda_item']);
|
||||
$table->foreignId('macro_id')->constrained('macros')->restrictOnDelete();
|
||||
$table->enum('position', ['all_slides', 'first_slide', 'last_slide', 'by_label']);
|
||||
$table->foreignId('label_id')->nullable()->constrained('labels')->restrictOnDelete();
|
||||
$table->unsignedInteger('order')->default(0);
|
||||
$table->timestamps();
|
||||
$table->index(['service_id', 'part_type', 'order']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('service_macro_assignments');
|
||||
Schema::dropIfExists('service_macro_overrides');
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class () extends Migration {
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('song_groups')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DB::table('song_groups')->count() === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
DB::statement('PRAGMA foreign_keys = OFF');
|
||||
|
||||
try {
|
||||
DB::table('song_arrangement_groups')->delete();
|
||||
DB::table('song_arrangements')->delete();
|
||||
DB::table('song_slides')->delete();
|
||||
DB::table('song_groups')->delete();
|
||||
DB::table('service_songs')->delete();
|
||||
DB::table('songs')->delete();
|
||||
} finally {
|
||||
DB::statement('PRAGMA foreign_keys = ON');
|
||||
}
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Data is unrecoverable — intentional no-op
|
||||
}
|
||||
};
|
||||
25
tests/Feature/Migrations/MacroAssignmentsTableTest.php
Normal file
25
tests/Feature/Migrations/MacroAssignmentsTableTest.php
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
test('macro_assignments table has expected columns', function () {
|
||||
expect(Schema::hasTable('macro_assignments'))->toBeTrue();
|
||||
expect(Schema::hasColumns('macro_assignments', ['id', 'part_type', 'macro_id', 'position', 'label_id', 'order', 'created_at', 'updated_at']))->toBeTrue();
|
||||
});
|
||||
|
||||
test('macro_assignments restrictOnDelete prevents deleting referenced macro', function () {
|
||||
$macroId = DB::table('macros')->insertGetId(['uuid' => 'AABB-1111-2222-3333-FFFFFFFFFFFF', 'name' => 'Test', 'created_at' => now(), 'updated_at' => now()]);
|
||||
$labelId = DB::table('labels')->insertGetId(['name' => 'Copyright', 'created_at' => now(), 'updated_at' => now()]);
|
||||
DB::table('macro_assignments')->insert(['part_type' => 'song', 'macro_id' => $macroId, 'position' => 'by_label', 'label_id' => $labelId, 'order' => 0, 'created_at' => now(), 'updated_at' => now()]);
|
||||
|
||||
expect(fn () => DB::table('macros')->where('id', $macroId)->delete())
|
||||
->toThrow(\Exception::class);
|
||||
});
|
||||
|
||||
test('macro_assignments allows nullable label_id', function () {
|
||||
$macroId = DB::table('macros')->insertGetId(['uuid' => 'CCBB-1111-2222-3333-FFFFFFFFFFFF', 'name' => 'Test2', 'created_at' => now(), 'updated_at' => now()]);
|
||||
DB::table('macro_assignments')->insert(['part_type' => 'sermon', 'macro_id' => $macroId, 'position' => 'all_slides', 'label_id' => null, 'order' => 0, 'created_at' => now(), 'updated_at' => now()]);
|
||||
|
||||
expect(DB::table('macro_assignments')->where('macro_id', $macroId)->value('label_id'))->toBeNull();
|
||||
});
|
||||
35
tests/Feature/Migrations/ServiceMacroOverrideTablesTest.php
Normal file
35
tests/Feature/Migrations/ServiceMacroOverrideTablesTest.php
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
|
||||
use App\Models\Service;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
test('service_macro_overrides table has expected columns', function () {
|
||||
expect(Schema::hasTable('service_macro_overrides'))->toBeTrue();
|
||||
expect(Schema::hasColumns('service_macro_overrides', ['id', 'service_id', 'part_type', 'created_at', 'updated_at']))->toBeTrue();
|
||||
});
|
||||
|
||||
test('service_macro_assignments table has expected columns', function () {
|
||||
expect(Schema::hasTable('service_macro_assignments'))->toBeTrue();
|
||||
expect(Schema::hasColumns('service_macro_assignments', ['id', 'service_id', 'part_type', 'macro_id', 'position', 'label_id', 'order', 'created_at', 'updated_at']))->toBeTrue();
|
||||
});
|
||||
|
||||
test('service_macro_overrides unique constraint on service_id and part_type', function () {
|
||||
$service = Service::factory()->create();
|
||||
DB::table('service_macro_overrides')->insert(['service_id' => $service->id, 'part_type' => 'song', 'created_at' => now(), 'updated_at' => now()]);
|
||||
|
||||
expect(fn () => DB::table('service_macro_overrides')->insert(['service_id' => $service->id, 'part_type' => 'song', 'created_at' => now(), 'updated_at' => now()]))
|
||||
->toThrow(\Exception::class);
|
||||
});
|
||||
|
||||
test('service delete cascades to overrides and assignments', function () {
|
||||
$service = Service::factory()->create();
|
||||
$macroId = DB::table('macros')->insertGetId(['uuid' => 'CCDD-1111-2222-3333-FFFFFFFFFFFF', 'name' => 'Test', 'created_at' => now(), 'updated_at' => now()]);
|
||||
DB::table('service_macro_overrides')->insert(['service_id' => $service->id, 'part_type' => 'sermon', 'created_at' => now(), 'updated_at' => now()]);
|
||||
DB::table('service_macro_assignments')->insert(['service_id' => $service->id, 'part_type' => 'sermon', 'macro_id' => $macroId, 'position' => 'all_slides', 'order' => 0, 'created_at' => now(), 'updated_at' => now()]);
|
||||
|
||||
$service->delete();
|
||||
|
||||
expect(DB::table('service_macro_overrides')->where('service_id', $service->id)->count())->toBe(0);
|
||||
expect(DB::table('service_macro_assignments')->where('service_id', $service->id)->count())->toBe(0);
|
||||
});
|
||||
16
tests/Feature/Migrations/WipeLegacySongDataTest.php
Normal file
16
tests/Feature/Migrations/WipeLegacySongDataTest.php
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
test('wipe migration is no-op on fresh database', function () {
|
||||
expect(DB::table('songs')->count())->toBe(0);
|
||||
expect(Schema::hasTable('songs'))->toBeTrue();
|
||||
expect(Schema::hasTable('song_groups'))->toBeTrue();
|
||||
expect(DB::table('song_groups')->count())->toBe(0);
|
||||
});
|
||||
|
||||
test('wipe migration guard: song_groups exists but is empty after fresh install', function () {
|
||||
expect(Schema::hasTable('song_groups'))->toBeTrue();
|
||||
expect(DB::table('song_groups')->count())->toBe(0);
|
||||
});
|
||||
Loading…
Reference in a new issue