Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix fhirpath resolve reference #567

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/Spark.Engine.Test/Service/IndexServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,18 +54,19 @@ public void TestInitialize()
};
var searchParameters = new List<SearchParamDefinition> { spPatientName, spMiddleName };
var resources = new Dictionary<Type, string> { { typeof(Patient), "Patient" }, { typeof(HumanName), "HumanName" } };

// For this test setup we want a limited available types and search parameters.
IFhirModel limitedFhirModel = new FhirModel(resources, searchParameters);
ElementIndexer limitedElementIndexer = new ElementIndexer(limitedFhirModel);
_limitedIndexService = new IndexService(limitedFhirModel, indexStoreMock.Object, limitedElementIndexer);
IReferenceToElementResolver referenceToElementResolver = new LightweightReferenceToElementResolver(limitedFhirModel);
_limitedIndexService = new IndexService(limitedFhirModel, indexStoreMock.Object, limitedElementIndexer, referenceToElementResolver);

// For this test setup we want all available types and search parameters.
IFhirModel fullFhirModel = new FhirModel();
ElementIndexer fullElementIndexer = new ElementIndexer(fullFhirModel);
_fullIndexService = new IndexService(fullFhirModel, indexStoreMock.Object, fullElementIndexer);
_fullIndexService = new IndexService(fullFhirModel, indexStoreMock.Object, fullElementIndexer, referenceToElementResolver);
}

[TestMethod]
public async Task TestIndexCustomSearchParameter()
{
Expand Down Expand Up @@ -127,6 +128,9 @@ public async Task TestIndexResourceAppointmentComplete()
IndexValue result = await _fullIndexService.IndexResourceAsync(appResource, appKey);

Assert.IsNotNull(result);
var patientIndexValue = result.IndexValues().FirstOrDefault(v => v.Name == "patient");
Assert.IsNotNull(patientIndexValue);
Assert.AreEqual(1, patientIndexValue.Values.Count);
}

[TestMethod]
Expand Down
15 changes: 15 additions & 0 deletions src/Spark.Engine/Core/FhirModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
using Spark.Engine.Extensions;
using Hl7.Fhir.Utility;
using Spark.Engine.Model;
using Hl7.Fhir.ElementModel;
using Hl7.Fhir.FhirPath;
using Hl7.Fhir.Specification;
using Hl7.FhirPath;

namespace Spark.Engine.Core
{
Expand Down Expand Up @@ -306,5 +310,16 @@ public CompartmentInfo FindCompartmentInfo(string resourceType)
{
return FindCompartmentInfo(GetResourceTypeForResourceName(resourceType));
}
public IStructureDefinitionSummaryProvider StructureDefinitionSummaryProvider => new PocoStructureDefinitionSummaryProvider();

public List<string> SupportedResources => ModelInfo.SupportedResources;

public EvaluationContext GetEvaluationContext(Func<string, ITypedElement> elementResolver = null)
{
return new FhirEvaluationContext
{
ElementResolver = elementResolver,
};
}
}
}
11 changes: 10 additions & 1 deletion src/Spark.Engine/Core/IFhirModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Hl7.Fhir.Model;
using Hl7.Fhir.ElementModel;
using Hl7.Fhir.Model;
using Hl7.Fhir.Specification;
using Hl7.FhirPath;
using Spark.Engine.Model;
using System;
using System.Collections.Generic;
Expand Down Expand Up @@ -59,5 +62,11 @@ public interface IFhirModel

CompartmentInfo FindCompartmentInfo(ResourceType resourceType);
CompartmentInfo FindCompartmentInfo(string resourceType);

IStructureDefinitionSummaryProvider StructureDefinitionSummaryProvider { get; }

List<string> SupportedResources { get; }

EvaluationContext GetEvaluationContext(Func<string, ITypedElement> elementResolver);
}
}
12 changes: 12 additions & 0 deletions src/Spark.Engine/Core/IReferenceToElementResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Hl7.Fhir.ElementModel;
using System;
using System.Collections.Generic;
using System.Text;

namespace Spark.Engine.Core
{
public interface IReferenceToElementResolver
{
ITypedElement Resolve(string reference);
}
}
55 changes: 55 additions & 0 deletions src/Spark.Engine/Core/LightweightReferenceToElementResolver.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using Hl7.Fhir.ElementModel;
using Hl7.Fhir.Serialization;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace Spark.Engine.Core
{
public class LightweightReferenceToElementResolver : IReferenceToElementResolver
{
private readonly IFhirModel _fhirModel;
private readonly string _resourceTypeCapture = "resourceType";
private readonly string _resourceIdCapture = "resourceId";
private readonly Regex _referenceRegex = null;

public LightweightReferenceToElementResolver(IFhirModel fhirModel)
{
_fhirModel = fhirModel;

var resourceTypesPattern = string.Join("|", _fhirModel.SupportedResources);
var referenceCaptureRegexPattern = $@"(?<{_resourceTypeCapture}>{resourceTypesPattern})\/(?<{_resourceIdCapture}>[A-Za-z0-9\-\.]{{1,64}})(\/_history\/[A-Za-z0-9\-\.]{{1,64}})?";
_referenceRegex = new Regex(
referenceCaptureRegexPattern,
RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.ExplicitCapture);
}

public ITypedElement Resolve(string reference)
{
if (string.IsNullOrWhiteSpace(reference))
{
return null;
}

var match = _referenceRegex.Match(reference);
if (!match.Success)
{
return null;
}

string resourceTypeInString = match.Groups[_resourceTypeCapture].Value;
string resourceId = match.Groups[_resourceIdCapture].Value;
ISourceNode node = FhirJsonNode.Create(
JObject.FromObject(
new
{
resourceType = resourceTypeInString,
id = resourceId,
}));

return node.ToTypedElement(_fhirModel.StructureDefinitionSummaryProvider);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,10 +141,10 @@ public static IMvcCoreBuilder AddFhir(this IServiceCollection services, SparkSet
services.TryAddTransient<ElementIndexer>();

services.TryAddTransient<IReferenceNormalizationService, ReferenceNormalizationService>();

services.TryAddSingleton<IReferenceToElementResolver,LightweightReferenceToElementResolver>();
services.TryAddTransient<IIndexService, IndexService>();
services.TryAddTransient<ILocalhost>((provider) => new Localhost(settings.Endpoint));
services.TryAddTransient<IFhirModel>((provider) => new FhirModel(ModelInfo.SearchParameters));
services.TryAddSingleton<IFhirModel>((provider) => new FhirModel(ModelInfo.SearchParameters));
services.TryAddTransient((provider) => new FhirPropertyIndex(provider.GetRequiredService<IFhirModel>()));
services.TryAddTransient<ITransfer, Transfer>();
services.TryAddTransient<ConditionalHeaderFhirResponseInterceptor>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ internal static class ElementNavFhirExtensionsNew
public static IEnumerable<Base> SelectNew(
this Base input,
string expression,
FhirEvaluationContext ctx = null)
EvaluationContext ctx = null)
{
var inputNav = input.ToTypedElement();
var result = inputNav.Select(expression, ctx ?? FhirEvaluationContext.CreateDefault());
var result = inputNav.Select(expression, ctx);
return result.ToFhirValues();
}

Expand Down
11 changes: 7 additions & 4 deletions src/Spark.Engine/Service/FhirServiceExtensions/IndexService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,14 @@ public class IndexService : IIndexService
private readonly IFhirModel _fhirModel;
private readonly IIndexStore _indexStore;
private readonly ElementIndexer _elementIndexer;
private readonly IReferenceToElementResolver _referenceToElementResolver;

public IndexService(IFhirModel fhirModel, IIndexStore indexStore, ElementIndexer elementIndexer)
public IndexService(IFhirModel fhirModel, IIndexStore indexStore, ElementIndexer elementIndexer, IReferenceToElementResolver referenceToElementResolver)
{
_fhirModel = fhirModel;
_indexStore = indexStore;
_elementIndexer = elementIndexer;
_referenceToElementResolver = referenceToElementResolver;
}

public void Process(Entry entry)
Expand All @@ -46,7 +48,7 @@ public void Process(Entry entry)
{
if (entry.IsDeleted())
{
_indexStore.Delete(entry);
_indexStore.Delete(entry);
}
else throw new Exception("Entry is neither resource nor deleted");
}
Expand Down Expand Up @@ -108,7 +110,7 @@ private IndexValue IndexResourceRecursively(Resource resource, IKey key, string
// HACK: Ignoring search parameter expressions which the FhirPath engine does not yet have support for
try
{
resolvedValues = resource.SelectNew(searchParameter.Expression);
resolvedValues = resource.SelectNew(searchParameter.Expression, _fhirModel.GetEvaluationContext(_referenceToElementResolver.Resolve));
}
catch (Exception)
{
Expand Down Expand Up @@ -163,7 +165,8 @@ private Resource MakeContainedReferencesUnique(Resource resource)
// Replace references to these contained resources with the newly created id's.
Auxiliary.ResourceVisitor.VisitByType(
domainResource,
(el, path) => {
(el, path) =>
{
ResourceReference currentRefence = (el as ResourceReference);
if (!string.IsNullOrEmpty(currentRefence.Reference))
{
Expand Down
Loading