79 lines
2.6 KiB
C#
79 lines
2.6 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using StackExchange.Redis;
|
|
|
|
public class QsofaService : IQsofaService
|
|
{
|
|
private readonly AppDbContext _db;
|
|
private readonly IConnectionMultiplexer _redis;
|
|
|
|
public QsofaService(AppDbContext db, IConnectionMultiplexer redis)
|
|
{
|
|
_db = db;
|
|
_redis = redis;
|
|
}
|
|
|
|
public async Task<QsofaCurrentResponse> GetCurrentAsync(Guid encounterId)
|
|
{
|
|
await EnsureEncounterExistsAsync(encounterId);
|
|
|
|
var values = await ReadCriterionValuesAsync(encounterId);
|
|
return BuildResponse(values);
|
|
}
|
|
|
|
public async Task<int> GetActiveCriteriaCountAsync(Guid encounterId)
|
|
{
|
|
var values = await ReadCriterionValuesAsync(encounterId);
|
|
return QsofaCalculator.CountActiveCriteria(values);
|
|
}
|
|
|
|
public async Task<CursorPage<ClinicalAlert>> GetHistoryAsync(
|
|
Guid encounterId, int limit, string? cursor)
|
|
{
|
|
limit = Math.Clamp(limit, 1, 100);
|
|
|
|
var query = _db.ClinicalAlerts
|
|
.AsNoTracking()
|
|
.Where(a => a.EncounterId == encounterId
|
|
#pragma warning disable CS0618 // Include legacy QSOFA_WARNING rows in history
|
|
&& (a.AlertType == AlertType.QsofaScreen || a.AlertType == AlertType.QsofaWarning));
|
|
#pragma warning restore CS0618
|
|
|
|
var items = await query
|
|
.OrderByDescending(a => a.TriggeredAt)
|
|
.ThenByDescending(a => a.Id)
|
|
.Take(limit + 1)
|
|
.ToListAsync();
|
|
|
|
var hasMore = items.Count > limit;
|
|
if (hasMore) items.RemoveAt(limit);
|
|
|
|
return new CursorPage<ClinicalAlert>(items, null, hasMore);
|
|
}
|
|
|
|
private async Task EnsureEncounterExistsAsync(Guid encounterId)
|
|
{
|
|
var exists = await _db.Encounters.AnyAsync(e => e.Id == encounterId);
|
|
if (!exists)
|
|
throw new NotFoundException("Encounter not found.", "ENCOUNTER_NOT_FOUND");
|
|
}
|
|
|
|
private async Task<RedisValue[]> ReadCriterionValuesAsync(Guid encounterId)
|
|
{
|
|
var cache = _redis.GetDatabase();
|
|
return await cache.StringGetAsync(QsofaCalculator.AllCriterionKeys(encounterId));
|
|
}
|
|
|
|
private static QsofaCurrentResponse BuildResponse(RedisValue[] values)
|
|
{
|
|
return new QsofaCurrentResponse(
|
|
QsofaCalculator.CountActiveCriteria(values),
|
|
new QsofaCriteriaState(
|
|
ParseOptionalDecimal(values[0]),
|
|
ParseOptionalDecimal(values[1]),
|
|
ParseOptionalDecimal(values[2])));
|
|
}
|
|
|
|
private static decimal? ParseOptionalDecimal(RedisValue value) =>
|
|
value.HasValue ? decimal.Parse(value.ToString()) : null;
|
|
}
|