71 lines
2.9 KiB
C#
71 lines
2.9 KiB
C#
using System.Text.Json;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
public static class ClinicalAlertFactory
|
|
{
|
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
|
{
|
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
|
};
|
|
|
|
public static string SerializeOutboxPayload(object payload) =>
|
|
JsonSerializer.Serialize(payload, JsonOptions);
|
|
|
|
/// <summary>
|
|
/// Idempotent INSERT. Returns true when a new row was created.
|
|
/// When <paramref name="observationCode"/> is null, dedupes on encounter + alert type only
|
|
/// (NEWS2, SOFA, GCS). When set, dedupes on encounter + alert type + observation code (trend).
|
|
/// </summary>
|
|
public static async Task<bool> TryInsertAsync(
|
|
AppDbContext db,
|
|
Guid alertId,
|
|
Guid encounterId,
|
|
Guid patientId,
|
|
AlertType alertType,
|
|
AlertSeverity severity,
|
|
string details,
|
|
AlertExplanation? explanation,
|
|
string? observationCode,
|
|
DateTimeOffset triggeredAt,
|
|
CancellationToken ct)
|
|
{
|
|
var explanationJson = explanation is null
|
|
? null
|
|
: JsonSerializer.Serialize(explanation, JsonOptions);
|
|
|
|
var affected = observationCode is null
|
|
? await db.Database.ExecuteSqlInterpolatedAsync($"""
|
|
INSERT INTO clinical_alerts
|
|
(id, encounter_id, patient_id, alert_type, severity,
|
|
details, explanation, status, triggered_at)
|
|
SELECT {alertId}, {encounterId}, {patientId},
|
|
{alertType.ToDbString()}, {severity.ToDbString()},
|
|
{details}, {explanationJson}::jsonb, 'OPEN', {triggeredAt}
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM clinical_alerts
|
|
WHERE encounter_id = {encounterId}
|
|
AND alert_type = {alertType.ToDbString()}
|
|
AND status IN ('OPEN', 'ESCALATED')
|
|
)
|
|
""", ct)
|
|
: await db.Database.ExecuteSqlInterpolatedAsync($"""
|
|
INSERT INTO clinical_alerts
|
|
(id, encounter_id, patient_id, alert_type, severity,
|
|
details, explanation, observation_code, status, triggered_at)
|
|
SELECT {alertId}, {encounterId}, {patientId},
|
|
{alertType.ToDbString()}, {severity.ToDbString()},
|
|
{details}, {explanationJson}::jsonb,
|
|
{observationCode}, 'OPEN', {triggeredAt}
|
|
WHERE NOT EXISTS (
|
|
SELECT 1 FROM clinical_alerts
|
|
WHERE encounter_id = {encounterId}
|
|
AND alert_type = {alertType.ToDbString()}
|
|
AND observation_code = {observationCode}
|
|
AND status IN ('OPEN', 'ESCALATED')
|
|
)
|
|
""", ct);
|
|
|
|
return affected > 0;
|
|
}
|
|
}
|