using System.Text.Json; using System.Text.Json.Serialization; using SQLInsight.Core.Instances; namespace SQLInsight.Rules.Lifecycle; public sealed record SupportLifecycle(SqlServerRelease Release, DateOnly? MainstreamEnd, DateOnly? ExtendedEnd); /// /// Microsoft's support dates per SQL Server release. Shipped as data so it can be updated with the rule pack. /// public sealed class SupportLifecycleCatalog { private const string ResourceName = "SQLInsight.Rules.support-lifecycle.json"; private static readonly JsonSerializerOptions JsonOptions = new() { PropertyNameCaseInsensitive = true, Converters = { new JsonStringEnumConverter() }, }; private readonly Dictionary _entries; public SupportLifecycleCatalog(IEnumerable entries) { ArgumentNullException.ThrowIfNull(entries); _entries = entries.ToDictionary(e => e.Release); } public static SupportLifecycleCatalog LoadEmbedded() { using var stream = typeof(SupportLifecycleCatalog).Assembly.GetManifestResourceStream(ResourceName) ?? throw new InvalidOperationException($"Embedded resource '{ResourceName}' is missing."); return From(JsonSerializer.Deserialize(stream, JsonOptions)); } /// Reads the lifecycle section of a rule pack. Throws if it is malformed. public static SupportLifecycleCatalog FromJson(JsonElement element) => From(element.Deserialize(JsonOptions)); private static SupportLifecycleCatalog From(CatalogDocument? document) { if (document?.Releases is not { Count: > 0 } releases) { throw new InvalidDataException("The support lifecycle catalog is empty."); } try { return new SupportLifecycleCatalog(releases); } catch (ArgumentException ex) { throw new InvalidDataException("The support lifecycle catalog is invalid: " + ex.Message, ex); } } public SupportLifecycle? Find(SqlServerRelease release) => _entries.GetValueOrDefault(release); private sealed record CatalogDocument(IReadOnlyList Releases); }