feature:
Full SOFA Score: Data Layer + Scoring Engine Glasgow Coma Scale: Data Layer + Scoring Engine
This commit is contained in:
@@ -16,6 +16,8 @@ public class AppDbContext : DbContext
|
||||
public DbSet<SepsisBundle> SepsisBundles => Set<SepsisBundle>();
|
||||
public DbSet<SepsisBundleElement> SepsisBundleElements => Set<SepsisBundleElement>();
|
||||
public DbSet<MedicationAdministration> MedicationAdministrations => Set<MedicationAdministration>();
|
||||
public DbSet<GcsScore> GcsScores => Set<GcsScore>();
|
||||
public DbSet<SofaScore> SofaScores => Set<SofaScore>();
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
|
||||
@@ -12,8 +12,19 @@ public class ClinicalAlertConfiguration : IEntityTypeConfiguration<ClinicalAlert
|
||||
t.HasCheckConstraint("chk_clinical_alerts_status",
|
||||
"status IN ('OPEN', 'ACKNOWLEDGED', 'RESOLVED', 'ESCALATED')");
|
||||
t.HasCheckConstraint("chk_clinical_alerts_alert_type",
|
||||
"alert_type IN ('SEPSIS_WARNING', 'CRITICAL_HEART_RATE', 'CRITICAL_TEMP_C', " +
|
||||
"'CRITICAL_POTASSIUM_MEQ_L', 'CRITICAL_SPO2', 'CRITICAL_RESP_RATE', 'CRITICAL_WBC_K_UL')");
|
||||
"alert_type IN (" +
|
||||
"'SEPSIS_WARNING', " +
|
||||
"'CRITICAL_HEART_RATE', 'CRITICAL_TEMP_C', 'CRITICAL_POTASSIUM_MEQ_L', " +
|
||||
"'CRITICAL_SPO2', 'CRITICAL_RESP_RATE', 'CRITICAL_WBC_K_UL', " +
|
||||
"'CRITICAL_SYSTOLIC_BP', 'CRITICAL_DIASTOLIC_BP', 'CRITICAL_LACTATE_MMOL_L', " +
|
||||
"'CRITICAL_AVPU', 'CRITICAL_GLUCOSE_MG_DL', " +
|
||||
"'WARNING_HEART_RATE', 'WARNING_TEMP_C', 'WARNING_POTASSIUM_MEQ_L', " +
|
||||
"'WARNING_SPO2', 'WARNING_RESP_RATE', 'WARNING_WBC_K_UL', " +
|
||||
"'WARNING_SYSTOLIC_BP', 'WARNING_DIASTOLIC_BP', 'WARNING_LACTATE_MMOL_L', " +
|
||||
"'WARNING_GLUCOSE_MG_DL', " +
|
||||
"'NEWS2_WARNING', 'NEWS2_EMERGENCY', " +
|
||||
"'RAPID_DETERIORATION', 'QSOFA_WARNING', " +
|
||||
"'GCS_CRITICAL', 'GCS_WARNING')");
|
||||
});
|
||||
builder.HasKey(a => a.Id);
|
||||
builder.Property(a => a.Id).HasColumnName("id").HasDefaultValueSql("gen_random_uuid()");
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
public class GcsScoreConfiguration : IEntityTypeConfiguration<GcsScore>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<GcsScore> builder)
|
||||
{
|
||||
builder.ToTable("gcs_scores", t =>
|
||||
{
|
||||
t.HasCheckConstraint("chk_gcs_scores_classification",
|
||||
"classification IN ('MILD', 'MODERATE', 'SEVERE')");
|
||||
});
|
||||
builder.HasKey(g => g.Id);
|
||||
builder.Property(g => g.Id).HasColumnName("id").HasDefaultValueSql("gen_random_uuid()");
|
||||
builder.Property(g => g.EncounterId).HasColumnName("encounter_id").IsRequired();
|
||||
builder.Property(g => g.PatientId).HasColumnName("patient_id").IsRequired();
|
||||
builder.Property(g => g.EyeScore).HasColumnName("eye_score").IsRequired();
|
||||
builder.Property(g => g.VerbalScore).HasColumnName("verbal_score").IsRequired();
|
||||
builder.Property(g => g.MotorScore).HasColumnName("motor_score").IsRequired();
|
||||
builder.Property(g => g.TotalScore).HasColumnName("total_score").IsRequired();
|
||||
builder.Property(g => g.Classification).HasColumnName("classification").HasMaxLength(16).IsRequired();
|
||||
builder.Property(g => g.CalculatedAt).HasColumnName("calculated_at").IsRequired();
|
||||
builder.Property(g => g.CreatedAt).HasColumnName("created_at").IsRequired();
|
||||
|
||||
builder.HasOne(g => g.Encounter)
|
||||
.WithMany()
|
||||
.HasForeignKey(g => g.EncounterId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasIndex(g => new { g.EncounterId, g.CalculatedAt });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
public class SofaScoreConfiguration : IEntityTypeConfiguration<SofaScore>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<SofaScore> builder)
|
||||
{
|
||||
builder.ToTable("sofa_scores");
|
||||
builder.HasKey(s => s.Id);
|
||||
builder.Property(s => s.Id).HasColumnName("id").HasDefaultValueSql("gen_random_uuid()");
|
||||
builder.Property(s => s.EncounterId).HasColumnName("encounter_id").IsRequired();
|
||||
builder.Property(s => s.PatientId).HasColumnName("patient_id").IsRequired();
|
||||
builder.Property(s => s.TotalScore).HasColumnName("total_score").IsRequired();
|
||||
builder.Property(s => s.RespiratoryScore).HasColumnName("respiratory_score").IsRequired();
|
||||
builder.Property(s => s.CoagulationScore).HasColumnName("coagulation_score").IsRequired();
|
||||
builder.Property(s => s.LiverScore).HasColumnName("liver_score").IsRequired();
|
||||
builder.Property(s => s.CardiovascularScore).HasColumnName("cardiovascular_score").IsRequired();
|
||||
builder.Property(s => s.CnsScore).HasColumnName("cns_score").IsRequired();
|
||||
builder.Property(s => s.RenalScore).HasColumnName("renal_score").IsRequired();
|
||||
builder.Property(s => s.IsBaseline).HasColumnName("is_baseline").IsRequired();
|
||||
builder.Property(s => s.DeltaFromBaseline).HasColumnName("delta_from_baseline");
|
||||
builder.Property(s => s.StalenessFlags).HasColumnName("staleness_flags").HasColumnType("jsonb");
|
||||
builder.Property(s => s.CalculatedAt).HasColumnName("calculated_at").IsRequired();
|
||||
builder.Property(s => s.CreatedAt).HasColumnName("created_at").IsRequired();
|
||||
|
||||
builder.HasOne(s => s.Encounter)
|
||||
.WithMany()
|
||||
.HasForeignKey(s => s.EncounterId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
builder.HasIndex(s => new { s.EncounterId, s.CalculatedAt });
|
||||
builder.HasIndex(s => s.EncounterId)
|
||||
.HasFilter("is_baseline = true")
|
||||
.HasDatabaseName("idx_sofa_scores_baseline");
|
||||
}
|
||||
}
|
||||
@@ -127,6 +127,70 @@ public static class DataSeeder
|
||||
CriticalLow = 40m, WarningLow = 70m, WarningHigh = 180m, CriticalHigh = 400m,
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
},
|
||||
// GCS components — registered for ingestion; thresholds are null (alerting is on computed total in GcsDetector)
|
||||
new AlertThreshold
|
||||
{
|
||||
Id = Guid.NewGuid(), ObservationCode = "GCS_EYE",
|
||||
DisplayName = "GCS Eye Response", Unit = "score",
|
||||
CriticalLow = null, WarningLow = null, WarningHigh = null, CriticalHigh = null,
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
},
|
||||
new AlertThreshold
|
||||
{
|
||||
Id = Guid.NewGuid(), ObservationCode = "GCS_VERBAL",
|
||||
DisplayName = "GCS Verbal Response", Unit = "score",
|
||||
CriticalLow = null, WarningLow = null, WarningHigh = null, CriticalHigh = null,
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
},
|
||||
new AlertThreshold
|
||||
{
|
||||
Id = Guid.NewGuid(), ObservationCode = "GCS_MOTOR",
|
||||
DisplayName = "GCS Motor Response", Unit = "score",
|
||||
CriticalLow = null, WarningLow = null, WarningHigh = null, CriticalHigh = null,
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
},
|
||||
new AlertThreshold
|
||||
{
|
||||
Id = Guid.NewGuid(), ObservationCode = "PAO2_MMHG",
|
||||
DisplayName = "Partial Pressure O2 (Arterial)", Unit = "mmHg",
|
||||
CriticalLow = 60m, WarningLow = 80m, WarningHigh = null, CriticalHigh = null,
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
},
|
||||
new AlertThreshold
|
||||
{
|
||||
Id = Guid.NewGuid(), ObservationCode = "FIO2_PCT",
|
||||
DisplayName = "Fraction of Inspired O2", Unit = "%",
|
||||
CriticalLow = null, WarningLow = null, WarningHigh = null, CriticalHigh = null,
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
},
|
||||
new AlertThreshold
|
||||
{
|
||||
Id = Guid.NewGuid(), ObservationCode = "PLATELET_K_UL",
|
||||
DisplayName = "Platelet Count", Unit = "k/µL",
|
||||
CriticalLow = 20m, WarningLow = 50m, WarningHigh = null, CriticalHigh = null,
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
},
|
||||
new AlertThreshold
|
||||
{
|
||||
Id = Guid.NewGuid(), ObservationCode = "BILIRUBIN_MG_DL",
|
||||
DisplayName = "Total Bilirubin", Unit = "mg/dL",
|
||||
CriticalLow = null, WarningLow = null, WarningHigh = 2.0m, CriticalHigh = 6.0m,
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
},
|
||||
new AlertThreshold
|
||||
{
|
||||
Id = Guid.NewGuid(), ObservationCode = "CREATININE_MG_DL",
|
||||
DisplayName = "Serum Creatinine", Unit = "mg/dL",
|
||||
CriticalLow = null, WarningLow = null, WarningHigh = 2.0m, CriticalHigh = 3.5m,
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
},
|
||||
new AlertThreshold
|
||||
{
|
||||
Id = Guid.NewGuid(), ObservationCode = "URINE_OUTPUT_ML_H",
|
||||
DisplayName = "Urine Output", Unit = "mL/h",
|
||||
CriticalLow = null, WarningLow = null, WarningHigh = null, CriticalHigh = null,
|
||||
CreatedAt = DateTimeOffset.UtcNow
|
||||
},
|
||||
};
|
||||
db.AlertThresholds.AddRange(thresholds);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user