Files

131 lines
4.6 KiB
C#

using Hl7.Fhir.Model;
using Microsoft.EntityFrameworkCore;
public class FhirBundleProcessor
{
private readonly AppDbContext _db;
private readonly IPatientService _patients;
private readonly IEncounterService _encounters;
private readonly IObservationService _observations;
private readonly IMedicationService _medications;
private readonly PatientFhirMapper _patientMapper;
private readonly EncounterFhirMapper _encounterMapper;
private readonly ObservationFhirMapper _observationMapper;
private readonly MedicationAdministrationFhirMapper _medMapper;
public FhirBundleProcessor(
AppDbContext db,
IPatientService patients,
IEncounterService encounters,
IObservationService observations,
IMedicationService medications,
PatientFhirMapper patientMapper,
EncounterFhirMapper encounterMapper,
ObservationFhirMapper observationMapper,
MedicationAdministrationFhirMapper medMapper)
{
_db = db;
_patients = patients;
_encounters = encounters;
_observations = observations;
_medications = medications;
_patientMapper = patientMapper;
_encounterMapper = encounterMapper;
_observationMapper = observationMapper;
_medMapper = medMapper;
}
public async Task<Bundle> ProcessTransactionAsync(Bundle transaction)
{
var response = new Bundle { Type = Bundle.BundleType.TransactionResponse };
var entries = transaction.Entry
.OrderBy(e => Priority(e.Resource))
.ToList();
await using var tx = await _db.Database.BeginTransactionAsync();
foreach (var entry in entries)
{
var resource = entry.Resource;
try
{
var location = resource switch
{
Hl7.Fhir.Model.Patient p => await ProcessPatientAsync(p),
Hl7.Fhir.Model.Encounter e => await ProcessEncounterAsync(e),
Hl7.Fhir.Model.Observation o => await ProcessObservationAsync(o),
Hl7.Fhir.Model.MedicationAdministration m => await ProcessMedAsync(m),
_ => throw new FhirMappingException(
$"Unsupported resource type in bundle: {resource.TypeName}", "not-supported")
};
response.Entry.Add(new Bundle.EntryComponent
{
Response = new Bundle.ResponseComponent
{
Status = "201 Created",
Location = location
}
});
}
catch (Exception ex)
{
await tx.RollbackAsync();
response.Entry.Add(new Bundle.EntryComponent
{
Response = new Bundle.ResponseComponent
{
Status = "422 Unprocessable Entity",
Outcome = FhirOperationOutcomeBuilder.FromException(ex)
}
});
return response;
}
}
await tx.CommitAsync();
return response;
}
private static int Priority(Resource? r) => r switch
{
Hl7.Fhir.Model.Patient => 0,
Hl7.Fhir.Model.Encounter => 1,
_ => 2
};
private async Task<string> ProcessPatientAsync(Hl7.Fhir.Model.Patient fhir)
{
var req = _patientMapper.ToUpsertRequest(fhir);
var patient = await _patients.RegisterOrUpdateByIdentifierAsync(req);
return $"Patient/{patient.Id}";
}
private async Task<string> ProcessEncounterAsync(Hl7.Fhir.Model.Encounter fhir)
{
var req = await _encounterMapper.ToUpsertRequestAsync(fhir);
var encounter = await _encounters.OpenOrUpdateByIdentifierAsync(req);
return $"Encounter/{encounter.Id}";
}
private async Task<string> ProcessObservationAsync(Hl7.Fhir.Model.Observation fhir)
{
var mapped = await _observationMapper.ToIngestRequestsAsync(fhir);
Guid? lastId = null;
foreach (var item in mapped)
{
var result = await _observations.IngestAsync(item.EncounterId, item.Request);
lastId = result.Observation.Id;
}
return $"Observation/{lastId}";
}
private async Task<string> ProcessMedAsync(Hl7.Fhir.Model.MedicationAdministration fhir)
{
var (req, encounterId) = await _medMapper.ToCreateRequestAsync(fhir);
var med = await _medications.CreateAsync(encounterId, req);
return $"MedicationAdministration/{med.Id}";
}
}