using SQLInsight.Core.Collection;
using SQLInsight.Core.CustomRules;
using SQLInsight.Core.Findings;
using SQLInsight.Core.Instances;
using SQLInsight.Rules.Engine;
namespace SQLInsight.Rules.Custom;
/// A rule defined as data (): every row its query returns is a finding.
public sealed class DeclarativeRule(CustomRuleDefinition definition) : IRule
{
public CustomRuleDefinition Definition { get; } = definition ?? throw new ArgumentNullException(nameof(definition));
public string Id => Definition.Id;
public string Title => Definition.Title;
public IReadOnlyCollection RequiredCapabilities => [];
public RuleEvaluation Evaluate(RuleContext context)
{
ArgumentNullException.ThrowIfNull(context);
if (context.Instance.Version < Definition.MinimumSqlVersion)
{
return RuleEvaluation.NotApplicable($"Ikke relevant for {context.Instance.Release.DisplayName()}: reglen kræver SQL Server {Definition.MinimumVersion} eller nyere.");
}
var results = context.Data.Get();
if (!results.Results.TryGetValue(Definition.Id, out var result))
{
throw new DataUnavailableException("Reglens forespørgsel er ikke kørt endnu.");
}
if (result.NotRelevant is { } notRelevant)
{
return RuleEvaluation.NotApplicable(notRelevant);
}
if (result.Error is { } error)
{
if (result.PermissionDenied)
{
return RuleEvaluation.NotMeasurable("Agentens login mangler rettigheder til reglens forespørgsel: " + error);
}
throw new InvalidOperationException("Reglens forespørgsel fejlede: " + error);
}
if (result.Rows.Count == 0)
{
return RuleEvaluation.Passed();
}
var references = Definition.References.Select(r => new Reference(r.Title, r.Url)).ToArray();
var findings = result.Rows.Select(row => new Finding
{
RuleId = Definition.Id,
Severity = Definition.Severity,
Title = CustomRuleDefinition.Fill(Definition.FindingTitle, row),
Subject = Definition.Subject is { } subject ? CustomRuleDefinition.Fill(subject, row) : row.Values.FirstOrDefault(),
Explanation = CustomRuleDefinition.Fill(Definition.Explanation, row)
+ (Definition.Origin == "community" ? " (Community-regel" + (Definition.Author is { } a ? $" af {a}" : "") + ".)" : " (Lokal regel.)"),
Recommendation = CustomRuleDefinition.Fill(Definition.Recommendation, row),
Evidence = row
.Where(c => Definition.Evidence is null || Definition.Evidence.Contains(c.Key, StringComparer.OrdinalIgnoreCase))
.Select(c => new Evidence(c.Key, c.Value ?? "(null)", Definition.SensitiveColumns.Contains(c.Key, StringComparer.OrdinalIgnoreCase)))
.Concat(result.Truncated ? [new Evidence("Bemærk", $"Kun de første {CustomRuleDefinition.MaxRowsPerRule} rækker er medtaget.")] : [])
.ToList(),
References = references,
}).ToArray();
return RuleEvaluation.Found(findings);
}
}