using SPTarkov.Server.Core.Migration;
namespace SPTarkov.Server.Core.Extensions;
public static class ProfileMigratorExtensions
{
///
/// Sorts the profile migrations in dependency order, ensuring that each migration appears
/// after all of its prerequisite migrations.
///
/// The collection of profile migrations to sort.
/// A topologically sorted list of migrations.
public static IEnumerable Sort(this IEnumerable profileMigrations)
{
var sortedMigrations = new List();
var visitedMigrations = new Dictionary();
var migrationDict = profileMigrations.ToDictionary(m => m.GetType());
foreach (var migration in profileMigrations)
{
VisitMigrationForSort(migration, migrationDict, visitedMigrations, sortedMigrations);
}
return sortedMigrations;
}
internal static void VisitMigrationForSort(
IProfileMigration migration,
Dictionary migrationTypeDictionary,
Dictionary visitedTypeDictionary,
List sortedMigrations
)
{
var migrationType = migration.GetType();
if (visitedTypeDictionary.TryGetValue(migrationType, out var isVisited))
{
if (isVisited)
{
return;
}
// Big error, two migrations should never depend on one another
throw new InvalidOperationException($"Cycle detected in migration prerequisites involving: {migrationType.Name}");
}
// Mark the current migration type for visiting
visitedTypeDictionary[migrationType] = false;
foreach (var prerequisiteType in migration.PrerequisiteMigrations)
{
if (!migrationTypeDictionary.TryGetValue(prerequisiteType, out var prereqMigration))
{
continue;
}
// Visit the next prerequisite
VisitMigrationForSort(prereqMigration, migrationTypeDictionary, visitedTypeDictionary, sortedMigrations);
}
// Done visiting, mark it as fully visited and add it to the sorted migrations
visitedTypeDictionary[migrationType] = true;
sortedMigrations.Add(migration);
}
}