Commit 889d6e89 authored by Mahmoud Aglan's avatar Mahmoud Aglan

fix(migrations): make performance indexes migration idempotent

Use IF NOT EXISTS checks to avoid duplicate index errors when
original table migrations already define the same indexes.
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent 3df8faf6
...@@ -2,105 +2,82 @@ ...@@ -2,105 +2,82 @@
use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema; use Illuminate\Support\Facades\Schema;
return new class extends Migration return new class extends Migration
{ {
public function up(): void public function up(): void
{ {
if (Schema::hasTable('users')) { $this->addIndexIfNotExists('users', 'users_role_index', 'role');
Schema::table('users', function (Blueprint $table) { $this->addIndexIfNotExists('users', 'users_status_index', 'status');
$table->index('role'); $this->addCompositeIndexIfNotExists('users', 'users_role_status_index', ['role', 'status']);
$table->index('status'); $this->addIndexIfNotExists('users', 'users_email_verified_at_index', 'email_verified_at');
$table->index(['role', 'status']); $this->addIndexIfNotExists('users', 'users_last_login_at_index', 'last_login_at');
$table->index('email_verified_at');
$table->index('last_login_at');
});
}
if (Schema::hasTable('campaigns')) { $this->addIndexIfNotExists('campaigns', 'campaigns_status_index', 'status');
Schema::table('campaigns', function (Blueprint $table) { $this->addIndexIfNotExists('campaigns', 'campaigns_deadline_index', 'deadline');
$table->index('status'); $this->addCompositeIndexIfNotExists('campaigns', 'campaigns_status_deadline_index', ['status', 'deadline']);
$table->index('deadline'); $this->addIndexIfNotExists('campaigns', 'campaigns_is_featured_index', 'is_featured');
$table->index(['status', 'deadline']); $this->addIndexIfNotExists('campaigns', 'campaigns_created_at_index', 'created_at');
$table->index('is_featured');
$table->index('created_at');
});
}
if (Schema::hasTable('applications')) { $this->addIndexIfNotExists('applications', 'applications_status_index', 'status');
Schema::table('applications', function (Blueprint $table) { $this->addCompositeIndexIfNotExists('applications', 'applications_campaign_id_status_index', ['campaign_id', 'status']);
$table->index('status'); $this->addCompositeIndexIfNotExists('applications', 'applications_creator_profile_id_status_index', ['creator_profile_id', 'status']);
$table->index(['campaign_id', 'status']);
$table->index(['creator_profile_id', 'status']);
});
}
if (Schema::hasTable('projects')) { $this->addIndexIfNotExists('projects', 'projects_status_perf_index', 'status');
Schema::table('projects', function (Blueprint $table) { $this->addIndexIfNotExists('projects', 'projects_deadline_perf_index', 'deadline');
$table->index('status'); $this->addCompositeIndexIfNotExists('projects', 'projects_status_deadline_index', ['status', 'deadline']);
$table->index('deadline'); $this->addCompositeIndexIfNotExists('projects', 'projects_company_id_status_index', ['company_id', 'status']);
$table->index(['status', 'deadline']); $this->addCompositeIndexIfNotExists('projects', 'projects_creator_id_status_index', ['creator_id', 'status']);
$table->index(['company_id', 'status']);
$table->index(['creator_profile_id', 'status']);
});
}
if (Schema::hasTable('deliverables')) { $this->addIndexIfNotExists('deliverables', 'deliverables_status_index', 'status');
Schema::table('deliverables', function (Blueprint $table) { $this->addCompositeIndexIfNotExists('deliverables', 'deliverables_project_id_status_index', ['project_id', 'status']);
$table->index('status'); $this->addIndexIfNotExists('deliverables', 'deliverables_due_date_index', 'due_date');
$table->index(['project_id', 'status']);
$table->index('due_date');
});
}
if (Schema::hasTable('notifications')) { $this->addCompositeIndexIfNotExists('notifications', 'notifications_user_id_is_read_created_at_index', ['user_id', 'is_read', 'created_at']);
Schema::table('notifications', function (Blueprint $table) { $this->addCompositeIndexIfNotExists('notifications', 'notifications_user_id_type_created_at_index', ['user_id', 'type', 'created_at']);
$table->index(['user_id', 'is_read', 'created_at']);
$table->index(['user_id', 'type', 'created_at']);
});
}
if (Schema::hasTable('messages')) { $this->addCompositeIndexIfNotExists('messages', 'messages_conversation_id_created_at_index', ['conversation_id', 'created_at']);
Schema::table('messages', function (Blueprint $table) {
$table->index(['conversation_id', 'created_at']);
});
}
if (Schema::hasTable('reviews')) { $this->addCompositeIndexIfNotExists('reviews', 'reviews_reviewee_id_is_visible_index', ['reviewee_id', 'is_visible']);
Schema::table('reviews', function (Blueprint $table) { $this->addIndexIfNotExists('reviews', 'reviews_is_visible_index', 'is_visible');
$table->index(['reviewee_id', 'is_visible']);
$table->index('is_visible');
});
}
if (Schema::hasTable('creator_profiles')) { $this->addIndexIfNotExists('creator_profiles', 'creator_profiles_availability_status_perf_index', 'availability_status');
Schema::table('creator_profiles', function (Blueprint $table) { $this->addIndexIfNotExists('creator_profiles', 'creator_profiles_is_verified_index', 'is_verified');
$table->index('availability_status'); $this->addIndexIfNotExists('creator_profiles', 'creator_profiles_is_featured_index', 'is_featured');
$table->index('is_verified'); $this->addIndexIfNotExists('creator_profiles', 'creator_profiles_reputation_score_perf_index', 'reputation_score');
$table->index('is_featured');
$table->index('reputation_score'); $this->addIndexIfNotExists('company_profiles', 'company_profiles_approval_status_index', 'approval_status');
}); $this->addIndexIfNotExists('company_profiles', 'company_profiles_reputation_score_index', 'reputation_score');
}
public function down(): void
{
}
private function addIndexIfNotExists(string $table, string $indexName, string $column): void
{
if (!Schema::hasTable($table)) {
return;
} }
if (Schema::hasTable('company_profiles')) { $exists = DB::select("SELECT 1 FROM pg_indexes WHERE tablename = ? AND indexname = ?", [$table, $indexName]);
Schema::table('company_profiles', function (Blueprint $table) { if (empty($exists)) {
$table->index('approval_status'); DB::statement("CREATE INDEX \"{$indexName}\" ON \"{$table}\" (\"{$column}\")");
$table->index('reputation_score');
});
} }
} }
public function down(): void private function addCompositeIndexIfNotExists(string $table, string $indexName, array $columns): void
{ {
if (Schema::hasTable('users')) { if (!Schema::hasTable($table)) {
Schema::table('users', function (Blueprint $table) { return;
$table->dropIndex(['role']); }
$table->dropIndex(['status']);
$table->dropIndex(['role', 'status']); $exists = DB::select("SELECT 1 FROM pg_indexes WHERE tablename = ? AND indexname = ?", [$table, $indexName]);
$table->dropIndex(['email_verified_at']); if (empty($exists)) {
$table->dropIndex(['last_login_at']); $cols = implode('", "', $columns);
}); DB::statement("CREATE INDEX \"{$indexName}\" ON \"{$table}\" (\"{$cols}\")");
} }
} }
}; };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment