namespace SQLInsight.Core.Configuration;
///
/// Which databases on an instance are monitored, as chosen in SQLInsight Web (Opsætning → Overvågede servere). The
/// system databases (master, model, msdb, tempdb) are always monitored: backups of master and msdb and the state of
/// tempdb concern the whole instance. A database nobody has decided on yet (new since the last discovery) follows
/// .
///
public sealed class DatabaseSelection
{
private static readonly HashSet SystemDatabases = new(["master", "model", "msdb", "tempdb"], StringComparer.OrdinalIgnoreCase);
private readonly HashSet _monitored;
private readonly HashSet _notMonitored;
private readonly HashSet _dynamicsAxToHub;
/// Every database, and no Dynamics AX findings to the hub: what 1.2 and earlier did.
public static readonly DatabaseSelection All = new(true, [], [], []);
public DatabaseSelection(bool monitorNew, IEnumerable monitored, IEnumerable notMonitored, IEnumerable dynamicsAxToHub)
{
ArgumentNullException.ThrowIfNull(monitored);
ArgumentNullException.ThrowIfNull(notMonitored);
ArgumentNullException.ThrowIfNull(dynamicsAxToHub);
MonitorNew = monitorNew;
_monitored = new HashSet(monitored, StringComparer.OrdinalIgnoreCase);
_notMonitored = new HashSet(notMonitored, StringComparer.OrdinalIgnoreCase);
_notMonitored.ExceptWith(_monitored);
_dynamicsAxToHub = new HashSet(dynamicsAxToHub, StringComparer.OrdinalIgnoreCase);
}
/// Databases not yet decided on (new on the instance) are monitored.
public bool MonitorNew { get; }
/// Nothing is left out: every database is monitored.
public bool IsEverything => MonitorNew && _notMonitored.Count == 0;
public static bool IsSystemDatabase(string database) => SystemDatabases.Contains(database);
/// Whether the database-specific checks run in .
public bool Includes(string database)
{
ArgumentNullException.ThrowIfNull(database);
if (IsSystemDatabase(database) || _monitored.Contains(database))
{
return true;
}
return !_notMonitored.Contains(database) && MonitorNew;
}
///
/// Whether findings about Dynamics AX in may be sent to SQLInsight Hub. Off unless the
/// customer turned it on for that database.
///
public bool SendsDynamicsAxToHub(string? database) => database is not null && _dynamicsAxToHub.Contains(database) && Includes(database);
/// At least one database sends Dynamics AX findings to the hub.
public bool AnyDynamicsAxToHub => _dynamicsAxToHub.Any(Includes);
/// Keeps the databases in that are monitored.
public List Filter(IEnumerable names) => names.Where(Includes).ToList();
}
///
/// Dynamics AX findings and SQLInsight Hub: they stay in the customer's network unless sending is turned on for the
/// database (default off).
///
public static class DynamicsAxFindings
{
/// The community AX rules (rules/community/dynamics-ax.json).
public const string RulePrefix = "COM-AX-";
/// The built-in AX rules (1.4: batch jobs, number sequences, RecId, AX users behind blocking).
public const string BuiltInRulePrefix = "SQLI-AX-";
private const string DatabaseSubject = "database: ";
/// Separates the database from the rest of an AX finding's subject: database: AX30 · batch: 4711.
public const string SubjectSeparator = " · ";
public static bool IsDynamicsAxRule(string ruleId) =>
ruleId?.StartsWith(RulePrefix, StringComparison.OrdinalIgnoreCase) == true || ruleId?.StartsWith(BuiltInRulePrefix, StringComparison.OrdinalIgnoreCase) == true;
/// The subject of an AX finding about in .
public static string Subject(string database, string? detail = null) =>
detail is null ? DatabaseSubject + database : DatabaseSubject + database + SubjectSeparator + detail;
/// The database a finding is about, from its subject (database: AX30 or database: AX30 · …), or null.
public static string? DatabaseOf(string? subject)
{
if (subject is null || !subject.StartsWith(DatabaseSubject, StringComparison.OrdinalIgnoreCase) || subject.Length <= DatabaseSubject.Length)
{
return null;
}
var rest = subject[DatabaseSubject.Length..];
var separator = rest.IndexOf(SubjectSeparator, StringComparison.Ordinal);
return separator > 0 ? rest[..separator] : rest;
}
}