add exclusions to terser reference method (#5343)

This commit is contained in:
JasonRoberts-smile 2023-10-02 09:23:42 -04:00 committed by GitHub
parent 7e0fa9833c
commit 5411622dee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 91 additions and 0 deletions

View File

@ -287,9 +287,33 @@ public class FhirTerser {
return retVal; return retVal;
} }
/**
* Extracts all outbound references from a resource
*
* @param theResource the resource to be analyzed
* @return a list of references to other resources
*/
public List<ResourceReferenceInfo> getAllResourceReferences(final IBaseResource theResource) { public List<ResourceReferenceInfo> getAllResourceReferences(final IBaseResource theResource) {
return getAllResourceReferencesExcluding(theResource, Lists.newArrayList());
}
/**
* Extracts all outbound references from a resource, excluding any that are located on black-listed parts of the
* resource
*
* @param theResource the resource to be analyzed
* @param thePathsToExclude a list of dot-delimited paths not to include in the result
* @return a list of references to other resources
*/
public List<ResourceReferenceInfo> getAllResourceReferencesExcluding(
final IBaseResource theResource, List<String> thePathsToExclude) {
final ArrayList<ResourceReferenceInfo> retVal = new ArrayList<>(); final ArrayList<ResourceReferenceInfo> retVal = new ArrayList<>();
BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource); BaseRuntimeElementCompositeDefinition<?> def = myContext.getResourceDefinition(theResource);
List<List<String>> tokenizedPathsToExclude = thePathsToExclude.stream()
.map(path -> StringUtils.split(path, "."))
.map(Lists::newArrayList)
.collect(Collectors.toList());
visit(newMap(), theResource, theResource, null, null, def, new IModelVisitor() { visit(newMap(), theResource, theResource, null, null, def, new IModelVisitor() {
@Override @Override
public void acceptElement( public void acceptElement(
@ -301,6 +325,10 @@ public class FhirTerser {
if (theElement == null || theElement.isEmpty()) { if (theElement == null || theElement.isEmpty()) {
return; return;
} }
if (thePathToElement != null && pathShouldBeExcluded(tokenizedPathsToExclude, thePathToElement)) {
return;
}
if (IBaseReference.class.isAssignableFrom(theElement.getClass())) { if (IBaseReference.class.isAssignableFrom(theElement.getClass())) {
retVal.add(new ResourceReferenceInfo( retVal.add(new ResourceReferenceInfo(
myContext, theOuterResource, thePathToElement, (IBaseReference) theElement)); myContext, theOuterResource, thePathToElement, (IBaseReference) theElement));
@ -310,6 +338,19 @@ public class FhirTerser {
return retVal; return retVal;
} }
private boolean pathShouldBeExcluded(List<List<String>> theTokenizedPathsToExclude, List<String> thePathToElement) {
return theTokenizedPathsToExclude.stream().anyMatch(p -> {
// Check whether the path to the element starts with the path to be excluded
if (p.size() > thePathToElement.size()) {
return false;
}
List<String> prefix = thePathToElement.subList(0, p.size());
return Objects.equals(p, prefix);
});
}
private BaseRuntimeChildDefinition getDefinition( private BaseRuntimeChildDefinition getDefinition(
BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) { BaseRuntimeElementCompositeDefinition<?> theCurrentDef, List<String> theSubList) {
BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0)); BaseRuntimeChildDefinition nextDef = theCurrentDef.getChildByNameOrThrowDataFormatException(theSubList.get(0));

View File

@ -12,6 +12,7 @@ import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseExtension; import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseReference; import org.hl7.fhir.instance.model.api.IBaseReference;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle;
@ -32,6 +33,7 @@ import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Patient.LinkType; import org.hl7.fhir.r4.model.Patient.LinkType;
import org.hl7.fhir.r4.model.Practitioner; import org.hl7.fhir.r4.model.Practitioner;
import org.hl7.fhir.r4.model.PrimitiveType; import org.hl7.fhir.r4.model.PrimitiveType;
import org.hl7.fhir.r4.model.Provenance;
import org.hl7.fhir.r4.model.Quantity; import org.hl7.fhir.r4.model.Quantity;
import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.ResourceType; import org.hl7.fhir.r4.model.ResourceType;
@ -511,6 +513,54 @@ public class FhirTerserR4Test {
} }
@Test
public void testGetAllResourceReferences() {
// setup
Provenance p = new Provenance();
p.addTarget(new Reference("Observation/1"));
p.addTarget(new Reference("Observation/2"));
p.setLocation(new Reference("Location/3"));
p.getAgentFirstRep().setWho(new Reference("Practitioner/4"));
p.getAgentFirstRep().setOnBehalfOf(new Reference("Organization/5"));
p.getEntityFirstRep().setWhat(new Reference("DocumentReference/6"));
// execute
FhirTerser t = myCtx.newTerser();
List<ResourceReferenceInfo> references = t.getAllResourceReferences(p);
// validate
assertEquals(6, references.size());
assertThat(toResourceIds(references), containsInAnyOrder("Observation/1", "Observation/2", "Location/3", "Practitioner/4", "Organization/5", "DocumentReference/6"));
}
@Test
public void testGetAllResourceReferencesExcluding() {
// setup
Provenance p = new Provenance();
p.addTarget(new Reference("Observation/1"));
p.addTarget(new Reference("Observation/2"));
p.setLocation(new Reference("Location/3"));
p.getAgentFirstRep().setWho(new Reference("Practitioner/4"));
p.getAgentFirstRep().setOnBehalfOf(new Reference("Organization/5"));
p.getEntityFirstRep().setWhat(new Reference("DocumentReference/6"));
// execute
FhirTerser t = myCtx.newTerser();
List<ResourceReferenceInfo> references = t.getAllResourceReferencesExcluding(p, List.of("target"));
// validate
assertEquals(4, references.size());
assertThat(toResourceIds(references), containsInAnyOrder("Location/3", "Practitioner/4", "Organization/5", "DocumentReference/6"));
}
private List<String> toResourceIds(List<ResourceReferenceInfo> references) {
return references.stream()
.map(ResourceReferenceInfo::getResourceReference)
.map(IBaseReference::getReferenceElement)
.map(IIdType::getValue)
.collect(Collectors.toList());
}
@Test @Test
public void testGetResourceReferenceInExtension() { public void testGetResourceReferenceInExtension() {
Patient p = new Patient(); Patient p = new Patient();