Fixed code for use case #2 test case

This commit is contained in:
Nick Goupinets 2020-11-09 15:29:50 -05:00
parent ac3b1e3e17
commit 4865e8a410
8 changed files with 159 additions and 81 deletions

View File

@ -29,6 +29,8 @@ import ca.uhn.fhir.empi.model.EmpiTransactionContext;
import ca.uhn.fhir.jpa.dao.data.IEmpiLinkDao; import ca.uhn.fhir.jpa.dao.data.IEmpiLinkDao;
import ca.uhn.fhir.jpa.dao.index.IdHelperService; import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.entity.EmpiLink; import ca.uhn.fhir.jpa.entity.EmpiLink;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -308,6 +310,26 @@ public class EmpiLinkDaoSvc {
return myEmpiLinkDao.findAll(example); return myEmpiLinkDao.findAll(example);
} }
/**
* Finds all {@link EmpiLink} entities in which theSourceResource's PID is the source
* of the relationship.
*
* @param theSourceResource the source resource to find links for.
*
* @return all links for the source.
*/
public List<EmpiLink> findEmpiMatchLinksBySource(IBaseResource theSourceResource) {
Long pid = myIdHelperService.getPidOrNull(theSourceResource);
if (pid == null) {
return Collections.emptyList();
}
EmpiLink exampleLink = myEmpiLinkFactory.newEmpiLink().setSourceResourcePid(pid);
exampleLink.setMatchResult(EmpiMatchResultEnum.MATCH);
Example<EmpiLink> example = Example.of(exampleLink);
return myEmpiLinkDao.findAll(example);
}
/** /**
* Factory delegation method, whenever you need a new EmpiLink, use this factory method. * Factory delegation method, whenever you need a new EmpiLink, use this factory method.
* //TODO Should we make the constructor private for EmpiLink? or work out some way to ensure they can only be instantiated via factory. * //TODO Should we make the constructor private for EmpiLink? or work out some way to ensure they can only be instantiated via factory.

View File

@ -71,14 +71,14 @@ public class EmpiEidUpdateService {
// myPersonHelper.updatePersonFromUpdatedEmpiTarget(updateContext.getMatchedPerson(), theResource, theEmpiTransactionContext); // myPersonHelper.updatePersonFromUpdatedEmpiTarget(updateContext.getMatchedPerson(), theResource, theEmpiTransactionContext);
if (!updateContext.isIncomingResourceHasAnEid() || updateContext.isHasEidsInCommon()) { if (!updateContext.isIncomingResourceHasAnEid() || updateContext.isHasEidsInCommon()) {
//update to patient that uses internal EIDs only. //update to patient that uses internal EIDs only.
myEmpiLinkSvc.updateLink(updateContext.getMatchedPerson(), theResource, theMatchedSourceResourceCandidate.getMatchResult(), EmpiLinkSourceEnum.AUTO, theEmpiTransactionContext); myEmpiLinkSvc.updateLink(updateContext.getMatchedSourceResource(), theResource, theMatchedSourceResourceCandidate.getMatchResult(), EmpiLinkSourceEnum.AUTO, theEmpiTransactionContext);
} else if (!updateContext.isHasEidsInCommon()) { } else if (!updateContext.isHasEidsInCommon()) {
handleNoEidsInCommon(theResource, theMatchedSourceResourceCandidate, theEmpiTransactionContext, updateContext); handleNoEidsInCommon(theResource, theMatchedSourceResourceCandidate, theEmpiTransactionContext, updateContext);
} }
} else { } else {
//This is a new linking scenario. we have to break the existing link and link to the new person. For now, we create duplicate. //This is a new linking scenario. we have to break the existing link and link to the new person. For now, we create duplicate.
//updated patient has an EID that matches to a new candidate. Link them, and set the persons possible duplicates //updated patient has an EID that matches to a new candidate. Link them, and set the persons possible duplicates
linkToNewPersonAndFlagAsDuplicate(theResource, updateContext.getExistingPerson(), updateContext.getMatchedPerson(), theEmpiTransactionContext); linkToNewPersonAndFlagAsDuplicate(theResource, updateContext.getExistingPerson(), updateContext.getMatchedSourceResource(), theEmpiTransactionContext);
} }
} }
@ -86,15 +86,16 @@ public class EmpiEidUpdateService {
// the user is simply updating their EID. We propagate this change to the Person. // the user is simply updating their EID. We propagate this change to the Person.
//overwrite. No EIDS in common, but still same person. //overwrite. No EIDS in common, but still same person.
if (myEmpiSettings.isPreventMultipleEids()) { if (myEmpiSettings.isPreventMultipleEids()) {
if (myPersonHelper.getLinkCount(theUpdateContext.getMatchedPerson()) <= 1) { // If there is only 0/1 link on the person, we can safely overwrite the EID. if (myEmpiLinkDaoSvc.findEmpiMatchLinksBySource(theUpdateContext.getMatchedSourceResource()).size() <= 1) { // If there is only 0/1 link on the person, we can safely overwrite the EID.
handleExternalEidOverwrite(theUpdateContext.getMatchedPerson(), theResource, theEmpiTransactionContext); // if (myPersonHelper.getLinkCount(theUpdateContext.getMatchedSourceResource()) <= 1) { // If there is only 0/1 link on the person, we can safely overwrite the EID.
handleExternalEidOverwrite(theUpdateContext.getMatchedSourceResource(), theResource, theEmpiTransactionContext);
} else { // If the person has multiple patients tied to it, we can't just overwrite the EID, so we split the person. } else { // If the person has multiple patients tied to it, we can't just overwrite the EID, so we split the person.
createNewPersonAndFlagAsDuplicate(theResource, theEmpiTransactionContext, theUpdateContext.getExistingPerson()); createNewPersonAndFlagAsDuplicate(theResource, theEmpiTransactionContext, theUpdateContext.getExistingPerson());
} }
} else { } else {
myPersonHelper.handleExternalEidAddition(theUpdateContext.getMatchedPerson(), theResource, theEmpiTransactionContext); myPersonHelper.handleExternalEidAddition(theUpdateContext.getMatchedSourceResource(), theResource, theEmpiTransactionContext);
} }
myEmpiLinkSvc.updateLink(theUpdateContext.getMatchedPerson(), theResource, theMatchedSourceResourceCandidate.getMatchResult(), EmpiLinkSourceEnum.AUTO, theEmpiTransactionContext); myEmpiLinkSvc.updateLink(theUpdateContext.getMatchedSourceResource(), theResource, theMatchedSourceResourceCandidate.getMatchResult(), EmpiLinkSourceEnum.AUTO, theEmpiTransactionContext);
} }
private void handleExternalEidOverwrite(IAnyResource thePerson, IAnyResource theResource, EmpiTransactionContext theEmpiTransactionContext) { private void handleExternalEidOverwrite(IAnyResource thePerson, IAnyResource theResource, EmpiTransactionContext theEmpiTransactionContext) {
@ -138,17 +139,17 @@ public class EmpiEidUpdateService {
private IAnyResource myExistingPerson; private IAnyResource myExistingPerson;
private boolean myRemainsMatchedToSamePerson; private boolean myRemainsMatchedToSamePerson;
public IAnyResource getMatchedPerson() { public IAnyResource getMatchedSourceResource() {
return myMatchedPerson; return myMatchedSourceResource;
} }
private final IAnyResource myMatchedPerson; private final IAnyResource myMatchedSourceResource;
EmpiUpdateContext(MatchedSourceResourceCandidate theMatchedSourceResourceCandidate, IAnyResource theResource) { EmpiUpdateContext(MatchedSourceResourceCandidate theMatchedSourceResourceCandidate, IAnyResource theResource) {
final String resourceType = theResource.getIdElement().getResourceType(); final String resourceType = theResource.getIdElement().getResourceType();
myMatchedPerson = myEmpiSourceResourceFindingSvc.getSourceResourceFromMatchedSourceResourceCandidate(theMatchedSourceResourceCandidate, resourceType); myMatchedSourceResource = myEmpiSourceResourceFindingSvc.getSourceResourceFromMatchedSourceResourceCandidate(theMatchedSourceResourceCandidate, resourceType);
myHasEidsInCommon = myEIDHelper.hasEidOverlap(myMatchedPerson, theResource); myHasEidsInCommon = myEIDHelper.hasEidOverlap(myMatchedSourceResource, theResource);
myIncomingResourceHasAnEid = !myEIDHelper.getExternalEid(theResource).isEmpty(); myIncomingResourceHasAnEid = !myEIDHelper.getExternalEid(theResource).isEmpty();
Optional<EmpiLink> theExistingMatchLink = myEmpiLinkDaoSvc.getMatchedLinkForTarget(theResource); Optional<EmpiLink> theExistingMatchLink = myEmpiLinkDaoSvc.getMatchedLinkForTarget(theResource);

View File

@ -105,7 +105,8 @@ public class EmpiLinkSvcImpl implements IEmpiLinkSvc {
@Override @Override
@Transactional @Transactional
public void syncEmpiLinksToPersonLinks(IAnyResource thePersonResource, EmpiTransactionContext theEmpiTransactionContext) { public void syncEmpiLinksToPersonLinks(IAnyResource thePersonResource, EmpiTransactionContext theEmpiTransactionContext) {
int origLinkCount = myPersonHelper.getLinkCount(thePersonResource); // int origLinkCount = myPersonHelper.getLinkCount(thePersonResource);
int origLinkCount = myEmpiLinkDaoSvc.findEmpiMatchLinksBySource(thePersonResource).size();
List<EmpiLink> empiLinks = myEmpiLinkDaoSvc.findEmpiLinksByPerson(thePersonResource); List<EmpiLink> empiLinks = myEmpiLinkDaoSvc.findEmpiLinksByPerson(thePersonResource);

View File

@ -73,8 +73,8 @@ public class EmpiResourceDaoSvc {
map.setLoadSynchronous(true); map.setLoadSynchronous(true);
map.add("identifier", new TokenParam(myEmpiConfig.getEmpiRules().getEnterpriseEIDSystem(), theEid)); map.add("identifier", new TokenParam(myEmpiConfig.getEmpiRules().getEnterpriseEIDSystem(), theEid));
// TODO NG - During person dedup do we set this to false? We might be setting a person to inactive... // TODO NG - During person dedup do we set this to false? We might be setting a person to inactive...
// map.add("active", new TokenParam("true")); map.add("active", new TokenParam("true"));
map.add("_tag", new TokenParam(EmpiConstants.SYSTEM_EMPI_MANAGED, EmpiConstants.CODE_HAPI_EMPI_MANAGED)); // map.add("_tag", new TokenParam(EmpiConstants.SYSTEM_EMPI_MANAGED, EmpiConstants.CODE_HAPI_EMPI_MANAGED));
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theResourceType); IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theResourceType);
IBundleProvider search = resourceDao.search(map); IBundleProvider search = resourceDao.search(map);

View File

@ -24,7 +24,7 @@ public class IsSameSourceResourceAs extends BaseSourceResourceMatcher {
sourceResourcePidsToMatch = myBaseResources.stream().map(this::getMatchedResourcePidFromResource).collect(Collectors.toList()); sourceResourcePidsToMatch = myBaseResources.stream().map(this::getMatchedResourcePidFromResource).collect(Collectors.toList());
boolean allToCheckAreSame = sourceResourcePidsToMatch.stream().allMatch(pid -> pid.equals(sourceResourcePidsToMatch.get(0))); boolean allToCheckAreSame = sourceResourcePidsToMatch.stream().allMatch(pid -> pid.equals(sourceResourcePidsToMatch.get(0)));
if (!allToCheckAreSame) { if (!allToCheckAreSame) {
throw new IllegalStateException("You wanted to do a source resource comparison, but the pool of persons you submitted for checking don't match! We won't even check the incoming person against them."); throw new IllegalStateException("You wanted to do a source resource comparison, but the pool of source resources you submitted for checking don't match! We won't even check the incoming source resource against them.");
} }
return sourceResourcePidsToMatch.contains(incomingSourceResourcePid); return sourceResourcePidsToMatch.contains(incomingSourceResourcePid);
} }

View File

@ -41,14 +41,15 @@ import static org.junit.jupiter.api.Assertions.*;
import static org.slf4j.LoggerFactory.getLogger; import static org.slf4j.LoggerFactory.getLogger;
public class EmpiMatchLinkSvcTest extends BaseEmpiR4Test { public class EmpiMatchLinkSvcTest extends BaseEmpiR4Test {
private static final Logger ourLog = getLogger(EmpiMatchLinkSvcTest.class); private static final Logger ourLog = getLogger(EmpiMatchLinkSvcTest.class);
@Autowired @Autowired
IEmpiLinkSvc myEmpiLinkSvc; IEmpiLinkSvc myEmpiLinkSvc;
@Autowired @Autowired
private EIDHelper myEidHelper; private EIDHelper myEidHelper;
@Autowired @Autowired
private PersonHelper myPersonHelper; private PersonHelper myPersonHelper;
@Autowired @Autowired
private EmpiResourceDaoSvc myEmpiResourceDaoSvc; // TODO NG - remove? private EmpiResourceDaoSvc myEmpiResourceDaoSvc; // TODO NG - remove?
@ -117,19 +118,26 @@ public class EmpiMatchLinkSvcTest extends BaseEmpiR4Test {
@Test @Test
public void testWhenPOSSIBLE_MATCHOccursOnPersonThatHasBeenManuallyNOMATCHedThatItIsBlocked() { public void testWhenPOSSIBLE_MATCHOccursOnPersonThatHasBeenManuallyNOMATCHedThatItIsBlocked() {
Patient originalJane = createPatientAndUpdateLinks(buildJanePatient()); Patient originalJane = createPatientAndUpdateLinks(buildJanePatient());
IBundleProvider search = myPersonDao.search(new SearchParameterMap());
IBundleProvider search = myPatientDao.search(new SearchParameterMap());
IAnyResource janePerson = (IAnyResource) search.getResources(0, 1).get(0); IAnyResource janePerson = (IAnyResource) search.getResources(0, 1).get(0);
Patient unmatchedPatient = createPatient(buildJanePatient()); Patient unmatchedPatient = createPatient(buildJanePatient());
//This simulates an admin specifically saying that unmatchedPatient does NOT match janePerson. //This simulates an admin specifically saying that unmatchedPatient does NOT match janePerson.
myEmpiLinkSvc.updateLink(janePerson, unmatchedPatient, EmpiMatchOutcome.NO_MATCH, EmpiLinkSourceEnum.MANUAL, createContextForCreate("Patient")); myEmpiLinkSvc.updateLink(janePerson, unmatchedPatient, EmpiMatchOutcome.NO_MATCH, EmpiLinkSourceEnum.MANUAL, createContextForCreate("Patient"));
//TODO change this so that it will only partially match. // TODO change this so that it will only partially match.
//Now normally, when we run update links, it should link to janePerson. However, this manual NO_MATCH link //Now normally, when we run update links, it should link to janePerson. However, this manual NO_MATCH link
//should cause a whole new Person to be created. //should cause a whole new Person to be created.
myEmpiMatchLinkSvc.updateEmpiLinksForEmpiTarget(unmatchedPatient, createContextForCreate("Patient")); myEmpiMatchLinkSvc.updateEmpiLinksForEmpiTarget(unmatchedPatient, createContextForCreate("Patient"));
System.out.println("Unmatched Patient");
print(unmatchedPatient);
System.out.println("Jane");
print(janePerson);
assertThat(unmatchedPatient, is(not(sameSourceResourceAs(janePerson)))); assertThat(unmatchedPatient, is(not(sameSourceResourceAs(janePerson))));
assertThat(unmatchedPatient, is(not(linkedTo(originalJane)))); assertThat(unmatchedPatient, is(not(linkedTo(originalJane))));
@ -225,35 +233,9 @@ public class EmpiMatchLinkSvcTest extends BaseEmpiR4Test {
Patient patient1 = addExternalEID(buildJanePatient(), "uniqueid"); Patient patient1 = addExternalEID(buildJanePatient(), "uniqueid");
createPatientAndUpdateLinks(patient1); createPatientAndUpdateLinks(patient1);
{
// state is now > Patient/ID.JANE.123[name=jane & EID = uniqueid] <-- EMPI Link -- Patient/[name=jane & EDI = uniqueid & EMPI_MANAGED = true]
IBundleProvider bundle = myPatientDao.search(new SearchParameterMap());
List<IBaseResource> resources = bundle.getResources(0, bundle.size());
resources.forEach(r -> {
print(r);
assertFalse(myEidHelper.getExternalEid(r).isEmpty());
});
assertEquals(2, resources.size());
IBaseResource testPatient1 = resources.get(0);
IBaseResource testPatient2 = resources.get(1);
assertThat((Patient) testPatient1, is(sameSourceResourceAs((Patient) testPatient2)));
Optional<EmpiLink> empiLinkByTarget = myEmpiLinkDaoSvc.findEmpiLinkByTarget(patient1);
assertTrue(empiLinkByTarget.isPresent());
System.out.println(empiLinkByTarget.get());
}
Patient patient2 = buildPaulPatient(); Patient patient2 = buildPaulPatient();
patient2.setActive(true);
patient2 = addExternalEID(patient2, "uniqueid"); patient2 = addExternalEID(patient2, "uniqueid");
createPatientAndUpdateLinks(patient2); createPatientAndUpdateLinks(patient2);
// state should be > Patient/ID.JANE.123[name=jane & EID = uniqueid] <--> Patient/[name=jane & EDI = uniqueid] <--> Patient/[name=paul & EDI = uniqueid]
IBundleProvider search = myPatientDao.search(new SearchParameterMap());
search.getResources(0, search.size()).forEach( r -> {
print(r);
}
);
assertThat(patient1, is(sameSourceResourceAs(patient2))); assertThat(patient1, is(sameSourceResourceAs(patient2)));
} }
@ -552,8 +534,8 @@ public class EmpiMatchLinkSvcTest extends BaseEmpiR4Test {
} }
@Test @Test
//Test Case #2
public void testSinglyLinkedPersonThatGetsAnUpdatedEidSimplyUpdatesEID() { public void testSinglyLinkedPersonThatGetsAnUpdatedEidSimplyUpdatesEID() {
//Use Case # 2
String EID_1 = "123"; String EID_1 = "123";
String EID_2 = "456"; String EID_2 = "456";
@ -568,7 +550,12 @@ public class EmpiMatchLinkSvcTest extends BaseEmpiR4Test {
clearExternalEIDs(paul); clearExternalEIDs(paul);
addExternalEID(paul, EID_2); addExternalEID(paul, EID_2);
System.out.println("Paul Before");
print(paul);
Patient pailTemp = paul;
paul = updatePatientAndUpdateLinks(paul); paul = updatePatientAndUpdateLinks(paul);
System.out.println("Paul After");
print(pailTemp);
assertNoDuplicates(); assertNoDuplicates();

View File

@ -48,5 +48,4 @@ public interface IEmpiLinkSvc {
* @param theResource * @param theResource
*/ */
void deleteLink(IAnyResource theExistingPerson, IAnyResource theResource, EmpiTransactionContext theEmpiTransactionContext); void deleteLink(IAnyResource theExistingPerson, IAnyResource theResource, EmpiTransactionContext theEmpiTransactionContext);
} }

View File

@ -32,6 +32,7 @@ import ca.uhn.fhir.empi.model.CanonicalEID;
import ca.uhn.fhir.empi.model.CanonicalIdentityAssuranceLevel; import ca.uhn.fhir.empi.model.CanonicalIdentityAssuranceLevel;
import ca.uhn.fhir.empi.model.EmpiTransactionContext; import ca.uhn.fhir.empi.model.EmpiTransactionContext;
import ca.uhn.fhir.fhirpath.IFhirPath; import ca.uhn.fhir.fhirpath.IFhirPath;
import ca.uhn.fhir.model.primitive.BooleanDt;
import ca.uhn.fhir.util.FhirTerser; import ca.uhn.fhir.util.FhirTerser;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IAnyResource;
@ -43,6 +44,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; 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.Address; import org.hl7.fhir.r4.model.Address;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.ContactPoint; import org.hl7.fhir.r4.model.ContactPoint;
import org.hl7.fhir.r4.model.HumanName; import org.hl7.fhir.r4.model.HumanName;
import org.hl7.fhir.r4.model.Identifier; import org.hl7.fhir.r4.model.Identifier;
@ -243,9 +245,20 @@ public class PersonHelper {
populateMetaTag(newSourceResource); populateMetaTag(newSourceResource);
setActive(newSourceResource, resourceDefinition);
return (T) newSourceResource; return (T) newSourceResource;
} }
private void setActive(IBaseResource theNewSourceResource, RuntimeResourceDefinition theResourceDefinition) {
BaseRuntimeChildDefinition activeChildDefinition = theResourceDefinition.getChildByName("active");
if (activeChildDefinition == null) {
ourLog.warn(String.format("Unable to set active flag on the provided source resource %s.", theNewSourceResource));
return;
}
activeChildDefinition.getMutator().setValue(theNewSourceResource, toBooleanType(true));
}
/** /**
* If there are no external EIDs on the incoming resource, create a new HAPI EID on the new SourceResource. * If there are no external EIDs on the incoming resource, create a new HAPI EID on the new SourceResource.
*/ */
@ -262,19 +275,19 @@ public class PersonHelper {
/** /**
* Given an Child Definition of `identifier`, a R4/DSTU3 EID Identifier, and a new resource, clone the EID into that resources' identifier list. * Given an Child Definition of `identifier`, a R4/DSTU3 EID Identifier, and a new resource, clone the EID into that resources' identifier list.
*/ */
private void cloneExternalEidIntoNewSourceResource(BaseRuntimeChildDefinition sourceResourceIdentifier, IBase theEid, IBase newSourceResource) { private void cloneExternalEidIntoNewSourceResource(BaseRuntimeChildDefinition theSourceResourceIdentifier, IBase theEid, IBase theNewSourceResource) {
// FHIR choice types - fields within fhir where we have a choice of ids // FHIR choice types - fields within fhir where we have a choice of ids
BaseRuntimeElementCompositeDefinition<?> childIdentifier = (BaseRuntimeElementCompositeDefinition<?>) sourceResourceIdentifier.getChildByName("identifier"); BaseRuntimeElementCompositeDefinition<?> childIdentifier = (BaseRuntimeElementCompositeDefinition<?>) theSourceResourceIdentifier.getChildByName("identifier");
FhirTerser terser = myFhirContext.newTerser(); FhirTerser terser = myFhirContext.newTerser();
IBase sourceResourceNewIdentifier = childIdentifier.newInstance(); IBase sourceResourceNewIdentifier = childIdentifier.newInstance();
terser.cloneInto(theEid, sourceResourceNewIdentifier, true); terser.cloneInto(theEid, sourceResourceNewIdentifier, true);
sourceResourceIdentifier.getMutator().addValue(newSourceResource, sourceResourceNewIdentifier); theSourceResourceIdentifier.getMutator().addValue(theNewSourceResource, sourceResourceNewIdentifier);
} }
private void cloneAllExternalEidsIntoNewSourceResource(BaseRuntimeChildDefinition sourceResourceIdentifier, IBase theSourceResource, IBase newSourceResource) { private void cloneAllExternalEidsIntoNewSourceResource(BaseRuntimeChildDefinition theSourceResourceIdentifier, IBase theSourceResource, IBase theNewSourceResource) {
// FHIR choice types - fields within fhir where we have a choice of ids // FHIR choice types - fields within fhir where we have a choice of ids
IFhirPath fhirPath = myFhirContext.newFhirPath(); IFhirPath fhirPath = myFhirContext.newFhirPath();
List<IBase> sourceResourceIdentifiers = sourceResourceIdentifier.getAccessor().getValues(theSourceResource); List<IBase> sourceResourceIdentifiers = theSourceResourceIdentifier.getAccessor().getValues(theSourceResource);
for (IBase base : sourceResourceIdentifiers) { for (IBase base : sourceResourceIdentifiers) {
Optional<IPrimitiveType> system = fhirPath.evaluateFirst(base, "system", IPrimitiveType.class); Optional<IPrimitiveType> system = fhirPath.evaluateFirst(base, "system", IPrimitiveType.class);
@ -282,8 +295,8 @@ public class PersonHelper {
String empiSystem = myEmpiConfig.getEmpiRules().getEnterpriseEIDSystem(); String empiSystem = myEmpiConfig.getEmpiRules().getEnterpriseEIDSystem();
String baseSystem = system.get().getValueAsString(); String baseSystem = system.get().getValueAsString();
if (Objects.equals(baseSystem, empiSystem)) { if (Objects.equals(baseSystem, empiSystem)) {
cloneExternalEidIntoNewSourceResource(sourceResourceIdentifier, base, newSourceResource); cloneExternalEidIntoNewSourceResource(theSourceResourceIdentifier, base, theNewSourceResource);
} else { } else if (ourLog.isDebugEnabled()) {
ourLog.debug(String.format("System %s differs from system in the EMPI rules %s", baseSystem, empiSystem)); ourLog.debug(String.format("System %s differs from system in the EMPI rules %s", baseSystem, empiSystem));
} }
} else { } else {
@ -336,25 +349,67 @@ public class PersonHelper {
return theSourceResource; return theSourceResource;
} }
public IBaseResource overwriteExternalEids(IBaseResource thePerson, List<CanonicalEID> theNewEid) { public IBaseResource overwriteExternalEids(IBaseResource theSourceResource, List<CanonicalEID> theNewEid) {
clearExternalEids(thePerson); clearExternalEids(theSourceResource);
addCanonicalEidsToSourceResourceIfAbsent(thePerson, theNewEid); addCanonicalEidsToSourceResourceIfAbsent(theSourceResource, theNewEid);
return thePerson; return theSourceResource;
} }
private void clearExternalEids(IBaseResource thePerson) { private void clearExternalEidsFromTheSourceResource(BaseRuntimeChildDefinition theSourceResourceIdentifier, IBase theSourceResource) {
switch (myFhirContext.getVersion().getVersion()) { IFhirPath fhirPath = myFhirContext.newFhirPath();
case R4: List<IBase> sourceResourceIdentifiers = theSourceResourceIdentifier.getAccessor().getValues(theSourceResource);
Person personR4 = (Person) thePerson; List<IBase> clonedIdentifiers = new ArrayList<>();
personR4.getIdentifier().removeIf(theIdentifier -> theIdentifier.getSystem().equalsIgnoreCase(myEmpiConfig.getEmpiRules().getEnterpriseEIDSystem()));
break; for (IBase base : sourceResourceIdentifiers) {
case DSTU3: Optional<IPrimitiveType> system = fhirPath.evaluateFirst(base, "system", IPrimitiveType.class);
org.hl7.fhir.dstu3.model.Person personDstu3 = (org.hl7.fhir.dstu3.model.Person) thePerson; if (system.isPresent()) {
personDstu3.getIdentifier().removeIf(theIdentifier -> theIdentifier.getSystem().equalsIgnoreCase(myEmpiConfig.getEmpiRules().getEnterpriseEIDSystem())); String empiSystem = myEmpiConfig.getEmpiRules().getEnterpriseEIDSystem();
break; String baseSystem = system.get().getValueAsString();
default: if (Objects.equals(baseSystem, empiSystem)) {
throw new UnsupportedOperationException("Version not supported: " + myFhirContext.getVersion().getVersion()); if (ourLog.isDebugEnabled()) {
ourLog.debug(String.format("Found EID confirming to EMPI rules %s. It should not be copied, skipping", baseSystem));
}
continue;
}
}
if (ourLog.isDebugEnabled()) {
ourLog.debug("Copying non-EMPI EID");
}
BaseRuntimeElementCompositeDefinition<?> childIdentifier = (BaseRuntimeElementCompositeDefinition<?>)
theSourceResourceIdentifier.getChildByName("identifier");
FhirTerser terser = myFhirContext.newTerser();
IBase sourceResourceNewIdentifier = childIdentifier.newInstance();
terser.cloneInto(base, sourceResourceNewIdentifier, true);
clonedIdentifiers.add(sourceResourceNewIdentifier);
} }
sourceResourceIdentifiers.clear();
sourceResourceIdentifiers.addAll(clonedIdentifiers);
}
private void clearExternalEids(IBaseResource theSourceResource) {
// validate the system - if it's set to EID system - then clear it - type and STU version
validateContextSupported();
// get a ref to the actual ID Field
RuntimeResourceDefinition resourceDefinition = myFhirContext.getResourceDefinition(theSourceResource);
BaseRuntimeChildDefinition sourceResourceIdentifier = resourceDefinition.getChildByName("identifier");
clearExternalEidsFromTheSourceResource(sourceResourceIdentifier, theSourceResource);
// switch (myFhirContext.getVersion().getVersion()) {
// case R4:
// Person personR4 = (Person) theSourceResource;
// personR4.getIdentifier().removeIf(theIdentifier -> theIdentifier.getSystem().equalsIgnoreCase(myEmpiConfig.getEmpiRules().getEnterpriseEIDSystem()));
// break;
// case DSTU3:
// org.hl7.fhir.dstu3.model.Person personDstu3 = (org.hl7.fhir.dstu3.model.Person) theSourceResource;
// personDstu3.getIdentifier().removeIf(theIdentifier -> theIdentifier.getSystem().equalsIgnoreCase(myEmpiConfig.getEmpiRules().getEnterpriseEIDSystem()));
// break;
// default:
// throw new UnsupportedOperationException("Version not supported: " + myFhirContext.getVersion().getVersion());
// }
} }
/** /**
@ -376,6 +431,8 @@ public class PersonHelper {
} }
} }
private <T> T toId(CanonicalEID eid) { private <T> T toId(CanonicalEID eid) {
switch (myFhirContext.getVersion().getVersion()) { switch (myFhirContext.getVersion().getVersion()) {
case R4: case R4:
@ -386,6 +443,17 @@ public class PersonHelper {
throw new IllegalStateException("Unsupported FHIR version " + myFhirContext.getVersion().getVersion()); throw new IllegalStateException("Unsupported FHIR version " + myFhirContext.getVersion().getVersion());
} }
private <T extends IBase> T toBooleanType(boolean theFlag) {
switch (myFhirContext.getVersion().getVersion()) {
case R4:
return (T) new BooleanType(theFlag);
case DSTU3:
return (T) new org.hl7.fhir.dstu3.model.BooleanType(theFlag);
}
throw new IllegalStateException("Unsupported FHIR version " + myFhirContext.getVersion().getVersion());
}
/** /**
* To avoid adding duplicate * To avoid adding duplicate
* *
@ -534,18 +602,18 @@ public class PersonHelper {
person.setLink(links); person.setLink(links);
} }
public int getLinkCount(IAnyResource thePerson) { // public int getLinkCount(IAnyResource theSourceResource) {
switch (myFhirContext.getVersion().getVersion()) { // switch (myFhirContext.getVersion().getVersion()) {
case R4: // case R4:
Person personR4 = (Person) thePerson; // Person personR4 = (Person) theSourceResource;
return personR4.getLink().size(); // return personR4.getLink().size();
case DSTU3: // case DSTU3:
org.hl7.fhir.dstu3.model.Person personStu3 = (org.hl7.fhir.dstu3.model.Person) thePerson; // org.hl7.fhir.dstu3.model.Person personStu3 = (org.hl7.fhir.dstu3.model.Person) theSourceResource;
return personStu3.getLink().size(); // return personStu3.getLink().size();
default: // default:
throw new UnsupportedOperationException("Version not supported: " + myFhirContext.getVersion().getVersion()); // throw new UnsupportedOperationException("Version not supported: " + myFhirContext.getVersion().getVersion());
} // }
} // }
private void log(EmpiTransactionContext theEmpiTransactionContext, String theMessage) { private void log(EmpiTransactionContext theEmpiTransactionContext, String theMessage) {
theEmpiTransactionContext.addTransactionLogMessage(theMessage); theEmpiTransactionContext.addTransactionLogMessage(theMessage);