feature: FHIR R4 Inbound Facade
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
using Hl7.Fhir.Model;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
public class FhirReferenceResolver
|
||||
{
|
||||
private readonly IExternalIdentifierService _identifiers;
|
||||
private readonly FhirOptions _options;
|
||||
|
||||
public FhirReferenceResolver(
|
||||
IExternalIdentifierService identifiers,
|
||||
IOptions<FhirOptions> options)
|
||||
{
|
||||
_identifiers = identifiers;
|
||||
_options = options.Value;
|
||||
}
|
||||
|
||||
public async Task<Guid> ResolvePatientReferenceAsync(ResourceReference reference)
|
||||
{
|
||||
if (reference.Identifier is not null)
|
||||
return await ResolveByIdentifierAsync(
|
||||
ExternalResourceType.Patient,
|
||||
reference.Identifier.System,
|
||||
reference.Identifier.Value,
|
||||
_options.PatientIdentifierSystems);
|
||||
|
||||
if (FhirMappingHelpers.TryParseResourceReference(reference.Reference, out var type, out var id)
|
||||
&& type == "Patient"
|
||||
&& Guid.TryParse(id, out var guid))
|
||||
{
|
||||
return guid;
|
||||
}
|
||||
|
||||
throw new FhirMappingException(
|
||||
"Patient reference must include a resolvable identifier or UUID.",
|
||||
"required");
|
||||
}
|
||||
|
||||
public async Task<Guid> ResolveEncounterReferenceAsync(ResourceReference reference)
|
||||
{
|
||||
if (reference.Identifier is not null)
|
||||
return await ResolveByIdentifierAsync(
|
||||
ExternalResourceType.Encounter,
|
||||
reference.Identifier.System,
|
||||
reference.Identifier.Value,
|
||||
_options.EncounterIdentifierSystems);
|
||||
|
||||
if (FhirMappingHelpers.TryParseResourceReference(reference.Reference, out var type, out var id)
|
||||
&& type == "Encounter"
|
||||
&& Guid.TryParse(id, out var guid))
|
||||
{
|
||||
return guid;
|
||||
}
|
||||
|
||||
throw new FhirMappingException(
|
||||
"Encounter reference must include a resolvable identifier or UUID.",
|
||||
"required");
|
||||
}
|
||||
|
||||
public (string System, string Value)? ExtractPrimaryIdentifier(
|
||||
IIdentifiable<List<Identifier>> resource, string[] acceptedSystems)
|
||||
{
|
||||
foreach (var system in acceptedSystems)
|
||||
{
|
||||
var match = resource.Identifier?
|
||||
.FirstOrDefault(i => i.System == system && !string.IsNullOrWhiteSpace(i.Value));
|
||||
if (match is not null)
|
||||
return (match.System!, match.Value!);
|
||||
}
|
||||
|
||||
return resource.Identifier?
|
||||
.FirstOrDefault(i => !string.IsNullOrWhiteSpace(i.System) && !string.IsNullOrWhiteSpace(i.Value))
|
||||
is { } fallback
|
||||
? (fallback.System!, fallback.Value!)
|
||||
: null;
|
||||
}
|
||||
|
||||
private async Task<Guid> ResolveByIdentifierAsync(
|
||||
ExternalResourceType type, string? system, string? value, string[] acceptedSystems)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(system) || string.IsNullOrWhiteSpace(value))
|
||||
throw new FhirMappingException("Identifier system and value are required.", "required");
|
||||
|
||||
if (!acceptedSystems.Contains(system))
|
||||
throw new FhirMappingException(
|
||||
$"Identifier system '{system}' is not configured.", "not-supported");
|
||||
|
||||
var internalId = await _identifiers.ResolveInternalIdAsync(type, system, value);
|
||||
if (internalId is null)
|
||||
throw new NotFoundException(
|
||||
$"{type} with identifier {system}|{value} not found.",
|
||||
"FHIR_RESOURCE_NOT_FOUND");
|
||||
|
||||
return internalId.Value;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user