using System.Collections.Generic; using System.Text.RegularExpressions; namespace QuantEngine.Infrastructure.Data { /// /// Orders DbUp migration scripts by their numeric V{n} version instead of plain ordinal /// string order. Without this, "V10__Name.sql" sorts before "V2__Name.sql" (and, as /// happened on 2026-07-24, zero-padded "V003_Name.sql" sorts before unpadded /// "V1__Name.sql") because ordinal comparison looks at characters, not numeric value. /// That mismatch let a migration with an unmet table dependency run first and silently /// no-op, and another one run first and hard-fail, blocking every migration after it on a /// fresh database. This comparer makes the "V{n}" scheme collision-proof regardless of /// digit count or padding, so it can never happen again. /// public class MigrationScriptNameComparer : IComparer { private static readonly Regex VersionPattern = new(@"V(\d+)", RegexOptions.Compiled); public int Compare(string? x, string? y) { if (x == null || y == null) { return string.CompareOrdinal(x, y); } var matchX = VersionPattern.Match(x); var matchY = VersionPattern.Match(y); if (matchX.Success && matchY.Success) { var versionX = long.Parse(matchX.Groups[1].Value); var versionY = long.Parse(matchY.Groups[1].Value); if (versionX != versionY) { return versionX.CompareTo(versionY); } } return string.CompareOrdinal(x, y); } } }