docs: add XML doc comments across src + Sister Projects section in CLAUDE.md
Bulk CommentChecker pass: fills in <param>/<inheritdoc> tags on public APIs across all 23 src/ projects so the doc-coverage gate is green. Also adds a Sister Projects section to CLAUDE.md pointing at the MxAccess Gateway and OtOpcUa sibling repos, and gitignores local credential captures (*login*.txt) and the wonder-app-vd03 deploy/ artifacts.
This commit is contained in:
@@ -42,20 +42,18 @@ public class SiteCallAuditRepository : ISiteCallAuditRepository
|
||||
private readonly ScadaLinkDbContext _context;
|
||||
private readonly ILogger<SiteCallAuditRepository> _logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SiteCallAuditRepository"/> class.
|
||||
/// </summary>
|
||||
/// <param name="context">The EF Core database context.</param>
|
||||
/// <param name="logger">Optional logger for diagnostic information.</param>
|
||||
public SiteCallAuditRepository(ScadaLinkDbContext context, ILogger<SiteCallAuditRepository>? logger = null)
|
||||
{
|
||||
_context = context ?? throw new ArgumentNullException(nameof(context));
|
||||
_logger = logger ?? NullLogger<SiteCallAuditRepository>.Instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Two-step: <c>IF NOT EXISTS INSERT</c> then conditional <c>UPDATE</c> with
|
||||
/// an inline <c>CASE</c> rank comparison. Both go through
|
||||
/// <see cref="Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.ExecuteSqlInterpolatedAsync"/>
|
||||
/// so the change tracker is bypassed and the value-converted PK column is
|
||||
/// written as the canonical "D"-format GUID string. Duplicate-key violations
|
||||
/// from the insert race are swallowed.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public async Task UpsertAsync(SiteCall siteCall, CancellationToken ct = default)
|
||||
{
|
||||
if (siteCall is null)
|
||||
@@ -141,25 +139,13 @@ WHERE TrackedOperationId = {idText}
|
||||
ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Single <c>FindAsync</c> against the PK. Returns <c>null</c> for unknown ids.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public async Task<SiteCall?> GetAsync(TrackedOperationId id, CancellationToken ct = default)
|
||||
{
|
||||
return await _context.Set<SiteCall>().FindAsync(new object?[] { id }, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds a parameterised SQL query against <c>dbo.SiteCalls</c> ordered by
|
||||
/// <c>(CreatedAtUtc DESC, TrackedOperationId DESC)</c>, with keyset paging.
|
||||
/// Raw SQL is used here (rather than LINQ) because EF Core 10 cannot
|
||||
/// translate the lexicographic string comparison against the value-converted
|
||||
/// <see cref="TrackedOperationId"/> column inside an expression tree — the
|
||||
/// converter is applied to equality but not to inequality comparisons
|
||||
/// against the underlying Guid. The keyset tiebreaker is varchar lex order,
|
||||
/// which is deterministic and gives "no overlap, every row exactly once"
|
||||
/// paging without depending on Guid byte ordering.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<SiteCall>> QueryAsync(
|
||||
SiteCallQueryFilter filter, SiteCallPaging paging, CancellationToken ct = default)
|
||||
{
|
||||
@@ -223,11 +209,7 @@ ORDER BY CreatedAtUtc DESC, TrackedOperationId DESC;";
|
||||
return rows;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes rows whose <see cref="SiteCall.TerminalAtUtc"/> is non-null AND
|
||||
/// strictly less than <paramref name="olderThanUtc"/>. Non-terminal rows are
|
||||
/// never touched. Returns the number of rows removed.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public async Task<int> PurgeTerminalAsync(DateTime olderThanUtc, CancellationToken ct = default)
|
||||
{
|
||||
return await _context.Database.ExecuteSqlInterpolatedAsync(
|
||||
@@ -252,16 +234,7 @@ ORDER BY CreatedAtUtc DESC, TrackedOperationId DESC;";
|
||||
private const string StatusDelivered = "Delivered";
|
||||
private const string StatusFailed = "Failed";
|
||||
|
||||
/// <summary>
|
||||
/// Computes the global KPI snapshot with five server-side aggregate queries
|
||||
/// against <c>dbo.SiteCalls</c>. No rows are materialised — every count is a
|
||||
/// translated <c>COUNT</c> and the oldest-pending age is a translated
|
||||
/// <c>MIN(CreatedAtUtc)</c>. The <c>Status</c> and <c>CreatedAtUtc</c>/<c>TerminalAtUtc</c>
|
||||
/// columns have no value converter, so the aggregates translate cleanly to
|
||||
/// SQL Server (unlike the NotificationOutbox's <c>DateTimeOffset</c>-converted
|
||||
/// column, which forces an order-and-take). "Buffered" / "stuck" key off
|
||||
/// <c>TerminalAtUtc IS NULL</c> — see the field comments above.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public async Task<SiteCallKpiSnapshot> ComputeKpisAsync(
|
||||
DateTime stuckCutoff, DateTime intervalSince, CancellationToken ct = default)
|
||||
{
|
||||
@@ -304,14 +277,7 @@ ORDER BY CreatedAtUtc DESC, TrackedOperationId DESC;";
|
||||
StuckCount: stuckCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the per-source-site KPI breakdown. The five counts are
|
||||
/// <c>GROUP BY SourceSite</c> aggregates; the oldest-pending age is a
|
||||
/// per-site <c>MIN(CreatedAtUtc)</c> over the (bounded) non-terminal set —
|
||||
/// all run server-side. A site appears in the result only if it has at
|
||||
/// least one row matched by one of the count queries. "Buffered" / "stuck"
|
||||
/// key off <c>TerminalAtUtc IS NULL</c> — see <see cref="ComputeKpisAsync"/>.
|
||||
/// </summary>
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<SiteCallSiteKpiSnapshot>> ComputePerSiteKpisAsync(
|
||||
DateTime stuckCutoff, DateTime intervalSince, CancellationToken ct = default)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user