diff --git a/database/migrations/2026_02_25_000001_add_node_fields_to_v2_stat_user_table.php b/database/migrations/2026_02_25_000001_add_node_fields_to_v2_stat_user_table.php index 9051523..06782de 100644 --- a/database/migrations/2026_02_25_000001_add_node_fields_to_v2_stat_user_table.php +++ b/database/migrations/2026_02_25_000001_add_node_fields_to_v2_stat_user_table.php @@ -2,6 +2,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Schema; return new class extends Migration { @@ -27,45 +28,20 @@ return new class extends Migration { } }); - Schema::table(self::TABLE, function (Blueprint $table) { - try { - $table->dropUnique(self::OLD_UNIQUE_INDEX); - } catch (\Throwable) { - } + $this->dropUniqueIfExists(self::TABLE, self::OLD_UNIQUE_INDEX); + $this->dropIndexIfExists(self::TABLE, self::OLD_COMPOSITE_INDEX); - try { - $table->dropIndex(self::OLD_COMPOSITE_INDEX); - } catch (\Throwable) { - } - - try { - $table->dropIndex(['user_id', 'server_rate', 'record_at']); - } catch (\Throwable) { - } - }); - - Schema::table(self::TABLE, function (Blueprint $table) { - try { - $table->unique( - ['user_id', 'server_rate', 'server_id', 'server_type', 'record_at'], - self::NEW_UNIQUE_INDEX - ); - } catch (\Throwable) { - } - - try { - $table->index( - ['user_id', 'server_id', 'server_type', 'record_at'], - self::NEW_COMPOSITE_INDEX - ); - } catch (\Throwable) { - } - - try { - $table->index('server_id', self::NEW_SERVER_ID_INDEX); - } catch (\Throwable) { - } - }); + $this->addUniqueIfNotExists( + self::TABLE, + ['user_id', 'server_rate', 'server_id', 'server_type', 'record_at'], + self::NEW_UNIQUE_INDEX + ); + $this->addIndexIfNotExists( + self::TABLE, + ['user_id', 'server_id', 'server_type', 'record_at'], + self::NEW_COMPOSITE_INDEX + ); + $this->addIndexIfNotExists(self::TABLE, ['server_id'], self::NEW_SERVER_ID_INDEX); } /** @@ -73,34 +49,12 @@ return new class extends Migration { */ public function down(): void { - Schema::table(self::TABLE, function (Blueprint $table) { - try { - $table->dropUnique(self::NEW_UNIQUE_INDEX); - } catch (\Throwable) { - } + $this->dropUniqueIfExists(self::TABLE, self::NEW_UNIQUE_INDEX); + $this->dropIndexIfExists(self::TABLE, self::NEW_COMPOSITE_INDEX); + $this->dropIndexIfExists(self::TABLE, self::NEW_SERVER_ID_INDEX); - try { - $table->dropIndex(self::NEW_COMPOSITE_INDEX); - } catch (\Throwable) { - } - - try { - $table->dropIndex(self::NEW_SERVER_ID_INDEX); - } catch (\Throwable) { - } - }); - - Schema::table(self::TABLE, function (Blueprint $table) { - try { - $table->unique(['server_rate', 'user_id', 'record_at'], self::OLD_UNIQUE_INDEX); - } catch (\Throwable) { - } - - try { - $table->index(['user_id', 'server_rate', 'record_at']); - } catch (\Throwable) { - } - }); + $this->addUniqueIfNotExists(self::TABLE, ['server_rate', 'user_id', 'record_at'], self::OLD_UNIQUE_INDEX); + $this->addIndexIfNotExists(self::TABLE, ['user_id', 'server_rate', 'record_at'], self::OLD_COMPOSITE_INDEX); Schema::table(self::TABLE, function (Blueprint $table) { if (Schema::hasColumn(self::TABLE, 'server_type')) { @@ -112,4 +66,70 @@ return new class extends Migration { } }); } + + private function addUniqueIfNotExists(string $table, array $columns, string $indexName): void + { + if ($this->indexExists($table, $indexName)) { + return; + } + + Schema::table($table, function (Blueprint $blueprint) use ($columns, $indexName) { + $blueprint->unique($columns, $indexName); + }); + } + + private function addIndexIfNotExists(string $table, array $columns, string $indexName): void + { + if ($this->indexExists($table, $indexName)) { + return; + } + + Schema::table($table, function (Blueprint $blueprint) use ($columns, $indexName) { + $blueprint->index($columns, $indexName); + }); + } + + private function dropUniqueIfExists(string $table, string $indexName): void + { + if (!$this->indexExists($table, $indexName)) { + return; + } + + Schema::table($table, function (Blueprint $blueprint) use ($indexName) { + $blueprint->dropUnique($indexName); + }); + } + + private function dropIndexIfExists(string $table, string $indexName): void + { + if (!$this->indexExists($table, $indexName)) { + return; + } + + Schema::table($table, function (Blueprint $blueprint) use ($indexName) { + $blueprint->dropIndex($indexName); + }); + } + + private function indexExists(string $table, string $indexName): bool + { + $connection = Schema::getConnection(); + $driver = $connection->getDriverName(); + + return match ($driver) { + 'mysql' => DB::table('information_schema.statistics') + ->where('table_schema', $connection->getDatabaseName()) + ->where('table_name', $table) + ->where('index_name', $indexName) + ->exists(), + 'pgsql' => DB::table('pg_indexes') + ->whereRaw('schemaname = current_schema()') + ->where('tablename', $table) + ->where('indexname', $indexName) + ->exists(), + 'sqlite' => collect(DB::select("PRAGMA index_list('{$table}')")) + ->contains(fn($index) => isset($index->name) && $index->name === $indexName), + default => false, + }; + } };