Updated link processing for MDM events

This commit is contained in:
Nick Goupinets 2021-09-03 16:29:26 -04:00
parent 1bd1b36668
commit c63a503841
11 changed files with 106 additions and 284 deletions

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.entity;
* #L% * #L%
*/ */
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum; import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum; import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.ResourceTable;
@ -47,7 +48,7 @@ import java.util.Date;
@Table(name = "MPI_LINK", uniqueConstraints = { @Table(name = "MPI_LINK", uniqueConstraints = {
@UniqueConstraint(name = "IDX_EMPI_PERSON_TGT", columnNames = {"PERSON_PID", "TARGET_PID"}), @UniqueConstraint(name = "IDX_EMPI_PERSON_TGT", columnNames = {"PERSON_PID", "TARGET_PID"}),
}) })
public class MdmLink { public class MdmLink implements IMdmLink {
public static final int VERSION_LENGTH = 16; public static final int VERSION_LENGTH = 16;
private static final int MATCH_RESULT_LENGTH = 16; private static final int MATCH_RESULT_LENGTH = 16;
private static final int LINK_SOURCE_LENGTH = 16; private static final int LINK_SOURCE_LENGTH = 16;

View File

@ -119,17 +119,17 @@ public class MdmMessageHandler implements MessageHandler {
ResourceOperationMessage outgoingMsg = new ResourceOperationMessage(myFhirContext, targetResource, theMsg.getOperationType()); ResourceOperationMessage outgoingMsg = new ResourceOperationMessage(myFhirContext, targetResource, theMsg.getOperationType());
outgoingMsg.setTransactionId(theMsg.getTransactionId()); outgoingMsg.setTransactionId(theMsg.getTransactionId());
MdmLinkEvent linkChangeEvent = mdmContext.getMdmLinkEvent(); MdmLinkEvent linkChangeEvent = new MdmLinkEvent();
Optional<MdmLink> mdmLinkBySource = myMdmLinkDaoSvc.findMdmLinkBySource(targetResource); mdmContext.getMdmLinks()
if (!mdmLinkBySource.isPresent()) { .stream()
ourLog.warn("Unable to find link by source for {}", targetResource.getIdElement()); .forEach(l -> {
} linkChangeEvent.addMdmLink(myModelConverter.toJson((MdmLink) l));
});
mdmLinkBySource.ifPresent(link -> linkChangeEvent.setFromLink(myModelConverter.toJson(link)));
HookParams params = new HookParams() HookParams params = new HookParams()
.add(ResourceOperationMessage.class, outgoingMsg) .add(ResourceOperationMessage.class, outgoingMsg)
.add(TransactionLogMessages.class, mdmContext.getTransactionLogMessages()) .add(TransactionLogMessages.class, mdmContext.getTransactionLogMessages())
.add(MdmLinkEvent.class, mdmContext.getMdmLinkEvent()); .add(MdmLinkEvent.class, linkChangeEvent);
myInterceptorBroadcaster.callHooks(Pointcut.MDM_AFTER_PERSISTED_RESOURCE_CHECKED, params); myInterceptorBroadcaster.callHooks(Pointcut.MDM_AFTER_PERSISTED_RESOURCE_CHECKED, params);
} }

View File

@ -85,8 +85,6 @@ public class MdmEidUpdateService {
myMdmSurvivorshipService.applySurvivorshipRulesToGoldenResource(theTargetResource, updateContext.getMatchedGoldenResource(), theMdmTransactionContext); myMdmSurvivorshipService.applySurvivorshipRulesToGoldenResource(theTargetResource, updateContext.getMatchedGoldenResource(), theMdmTransactionContext);
myMdmResourceDaoSvc.upsertGoldenResource(updateContext.getMatchedGoldenResource(), theMdmTransactionContext.getResourceType()); myMdmResourceDaoSvc.upsertGoldenResource(updateContext.getMatchedGoldenResource(), theMdmTransactionContext.getResourceType());
} }
theMdmTransactionContext.getMdmLinkEvent().setGoldenResourceId(updateContext.getExistingGoldenResource());
} }
private void handleNoEidsInCommon(IAnyResource theResource, MatchedGoldenResourceCandidate theMatchedGoldenResourceCandidate, MdmTransactionContext theMdmTransactionContext, MdmUpdateContext theUpdateContext) { private void handleNoEidsInCommon(IAnyResource theResource, MatchedGoldenResourceCandidate theMatchedGoldenResourceCandidate, MdmTransactionContext theMdmTransactionContext, MdmUpdateContext theUpdateContext) {

View File

@ -53,6 +53,8 @@ public class MdmLinkSvcImpl implements IMdmLinkSvc {
private MdmLinkDaoSvc myMdmLinkDaoSvc; private MdmLinkDaoSvc myMdmLinkDaoSvc;
@Autowired @Autowired
private IdHelperService myIdHelperService; private IdHelperService myIdHelperService;
@Autowired
private IMdmModelConverterSvc myMdmModelConverterSvc;
@Override @Override
@Transactional @Transactional
@ -69,7 +71,8 @@ public class MdmLinkSvcImpl implements IMdmLinkSvc {
validateRequestIsLegal(theGoldenResource, theSourceResource, matchResultEnum, theLinkSource); validateRequestIsLegal(theGoldenResource, theSourceResource, matchResultEnum, theLinkSource);
myMdmResourceDaoSvc.upsertGoldenResource(theGoldenResource, theMdmTransactionContext.getResourceType()); myMdmResourceDaoSvc.upsertGoldenResource(theGoldenResource, theMdmTransactionContext.getResourceType());
createOrUpdateLinkEntity(theGoldenResource, theSourceResource, theMatchOutcome, theLinkSource, theMdmTransactionContext); MdmLink link = createOrUpdateLinkEntity(theGoldenResource, theSourceResource, theMatchOutcome, theLinkSource, theMdmTransactionContext);
theMdmTransactionContext.addMdmLink(link);
} }
private boolean goldenResourceLinkedAsNoMatch(IAnyResource theGoldenResource, IAnyResource theSourceResource) { private boolean goldenResourceLinkedAsNoMatch(IAnyResource theGoldenResource, IAnyResource theSourceResource) {
@ -87,6 +90,7 @@ public class MdmLinkSvcImpl implements IMdmLinkSvc {
MdmLink mdmLink = optionalMdmLink.get(); MdmLink mdmLink = optionalMdmLink.get();
log(theMdmTransactionContext, "Deleting MdmLink [" + theGoldenResource.getIdElement().toVersionless() + " -> " + theSourceResource.getIdElement().toVersionless() + "] with result: " + mdmLink.getMatchResult()); log(theMdmTransactionContext, "Deleting MdmLink [" + theGoldenResource.getIdElement().toVersionless() + " -> " + theSourceResource.getIdElement().toVersionless() + "] with result: " + mdmLink.getMatchResult());
myMdmLinkDaoSvc.deleteLink(mdmLink); myMdmLinkDaoSvc.deleteLink(mdmLink);
theMdmTransactionContext.addMdmLink(mdmLink);
} }
} }
@ -129,8 +133,8 @@ public class MdmLinkSvcImpl implements IMdmLinkSvc {
} }
} }
private void createOrUpdateLinkEntity(IBaseResource theGoldenResource, IBaseResource theSourceResource, MdmMatchOutcome theMatchOutcome, MdmLinkSourceEnum theLinkSource, MdmTransactionContext theMdmTransactionContext) { private MdmLink createOrUpdateLinkEntity(IBaseResource theGoldenResource, IBaseResource theSourceResource, MdmMatchOutcome theMatchOutcome, MdmLinkSourceEnum theLinkSource, MdmTransactionContext theMdmTransactionContext) {
myMdmLinkDaoSvc.createOrUpdateLinkEntity(theGoldenResource, theSourceResource, theMatchOutcome, theLinkSource, theMdmTransactionContext); return myMdmLinkDaoSvc.createOrUpdateLinkEntity(theGoldenResource, theSourceResource, theMatchOutcome, theLinkSource, theMdmTransactionContext);
} }
private void log(MdmTransactionContext theMdmTransactionContext, String theMessage) { private void log(MdmTransactionContext theMdmTransactionContext, String theMessage) {

View File

@ -78,8 +78,6 @@ public class MdmMatchLinkSvc {
private MdmTransactionContext doMdmUpdate(IAnyResource theResource, MdmTransactionContext theMdmTransactionContext) { private MdmTransactionContext doMdmUpdate(IAnyResource theResource, MdmTransactionContext theMdmTransactionContext) {
CandidateList candidateList = myMdmGoldenResourceFindingSvc.findGoldenResourceCandidates(theResource); CandidateList candidateList = myMdmGoldenResourceFindingSvc.findGoldenResourceCandidates(theResource);
theMdmTransactionContext.getMdmLinkEvent().setTargetResourceId(theResource);
if (candidateList.isEmpty()) { if (candidateList.isEmpty()) {
handleMdmWithNoCandidates(theResource, theMdmTransactionContext); handleMdmWithNoCandidates(theResource, theMdmTransactionContext);
} else if (candidateList.exactlyOneMatch()) { } else if (candidateList.exactlyOneMatch()) {
@ -115,14 +113,12 @@ public class MdmMatchLinkSvc {
//Set all GoldenResources as POSSIBLE_DUPLICATE of the last GoldenResource. //Set all GoldenResources as POSSIBLE_DUPLICATE of the last GoldenResource.
IAnyResource firstGoldenResource = goldenResources.get(0); IAnyResource firstGoldenResource = goldenResources.get(0);
theMdmTransactionContext.getMdmLinkEvent().setGoldenResourceId(firstGoldenResource);
goldenResources.subList(1, goldenResources.size()) goldenResources.subList(1, goldenResources.size())
.forEach(possibleDuplicateGoldenResource -> { .forEach(possibleDuplicateGoldenResource -> {
MdmMatchOutcome outcome = MdmMatchOutcome.POSSIBLE_DUPLICATE; MdmMatchOutcome outcome = MdmMatchOutcome.POSSIBLE_DUPLICATE;
outcome.setEidMatch(theCandidateList.isEidMatch()); outcome.setEidMatch(theCandidateList.isEidMatch());
myMdmLinkSvc.updateLink(firstGoldenResource, possibleDuplicateGoldenResource, outcome, MdmLinkSourceEnum.AUTO, theMdmTransactionContext); myMdmLinkSvc.updateLink(firstGoldenResource, possibleDuplicateGoldenResource, outcome, MdmLinkSourceEnum.AUTO, theMdmTransactionContext);
theMdmTransactionContext.getMdmLinkEvent().addDuplicateGoldenResourceId(possibleDuplicateGoldenResource);
}); });
} }
} }
@ -135,8 +131,6 @@ public class MdmMatchLinkSvc {
// 2. Create source resource for the MDM source // 2. Create source resource for the MDM source
// 3. UPDATE MDM LINK TABLE // 3. UPDATE MDM LINK TABLE
myMdmLinkSvc.updateLink(newGoldenResource, theResource, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.AUTO, theMdmTransactionContext); myMdmLinkSvc.updateLink(newGoldenResource, theResource, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.AUTO, theMdmTransactionContext);
theMdmTransactionContext.getMdmLinkEvent().setGoldenResourceId(newGoldenResource);
} }
private void handleMdmCreate(IAnyResource theTargetResource, MatchedGoldenResourceCandidate theGoldenResourceCandidate, MdmTransactionContext theMdmTransactionContext) { private void handleMdmCreate(IAnyResource theTargetResource, MatchedGoldenResourceCandidate theGoldenResourceCandidate, MdmTransactionContext theMdmTransactionContext) {
@ -146,7 +140,6 @@ public class MdmMatchLinkSvc {
if (myGoldenResourceHelper.isPotentialDuplicate(goldenResource, theTargetResource)) { if (myGoldenResourceHelper.isPotentialDuplicate(goldenResource, theTargetResource)) {
log(theMdmTransactionContext, "Duplicate detected based on the fact that both resources have different external EIDs."); log(theMdmTransactionContext, "Duplicate detected based on the fact that both resources have different external EIDs.");
IAnyResource newGoldenResource = myGoldenResourceHelper.createGoldenResourceFromMdmSourceResource(theTargetResource, theMdmTransactionContext); IAnyResource newGoldenResource = myGoldenResourceHelper.createGoldenResourceFromMdmSourceResource(theTargetResource, theMdmTransactionContext);
theMdmTransactionContext.getMdmLinkEvent().setGoldenResourceId(newGoldenResource);
myMdmLinkSvc.updateLink(newGoldenResource, theTargetResource, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.AUTO, theMdmTransactionContext); myMdmLinkSvc.updateLink(newGoldenResource, theTargetResource, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.AUTO, theMdmTransactionContext);
myMdmLinkSvc.updateLink(newGoldenResource, goldenResource, MdmMatchOutcome.POSSIBLE_DUPLICATE, MdmLinkSourceEnum.AUTO, theMdmTransactionContext); myMdmLinkSvc.updateLink(newGoldenResource, goldenResource, MdmMatchOutcome.POSSIBLE_DUPLICATE, MdmLinkSourceEnum.AUTO, theMdmTransactionContext);
@ -156,7 +149,6 @@ public class MdmMatchLinkSvc {
myEidUpdateService.applySurvivorshipRulesAndSaveGoldenResource(theTargetResource, goldenResource, theMdmTransactionContext); myEidUpdateService.applySurvivorshipRulesAndSaveGoldenResource(theTargetResource, goldenResource, theMdmTransactionContext);
} }
theMdmTransactionContext.getMdmLinkEvent().setGoldenResourceId(goldenResource);
myMdmLinkSvc.updateLink(goldenResource, theTargetResource, theGoldenResourceCandidate.getMatchResult(), MdmLinkSourceEnum.AUTO, theMdmTransactionContext); myMdmLinkSvc.updateLink(goldenResource, theTargetResource, theGoldenResourceCandidate.getMatchResult(), MdmLinkSourceEnum.AUTO, theMdmTransactionContext);
} }
} }

View File

@ -31,22 +31,22 @@ public class MdmModelConverterSvcImpl implements IMdmModelConverterSvc {
IdHelperService myIdHelperService; IdHelperService myIdHelperService;
public MdmLinkJson toJson(MdmLink theLink) { public MdmLinkJson toJson(MdmLink theLink) {
MdmLinkJson retval = new MdmLinkJson(); MdmLinkJson retVal = new MdmLinkJson();
String sourceId = myIdHelperService.resourceIdFromPidOrThrowException(theLink.getSourcePid()).toVersionless().getValue(); String sourceId = myIdHelperService.resourceIdFromPidOrThrowException(theLink.getSourcePid()).toVersionless().getValue();
retval.setSourceId(sourceId); retVal.setSourceId(sourceId);
String goldenResourceId = myIdHelperService.resourceIdFromPidOrThrowException(theLink.getGoldenResourcePid()).toVersionless().getValue(); String goldenResourceId = myIdHelperService.resourceIdFromPidOrThrowException(theLink.getGoldenResourcePid()).toVersionless().getValue();
retval.setGoldenResourceId(goldenResourceId); retVal.setGoldenResourceId(goldenResourceId);
retval.setCreated(theLink.getCreated()); retVal.setCreated(theLink.getCreated());
retval.setEidMatch(theLink.getEidMatch()); retVal.setEidMatch(theLink.getEidMatch());
retval.setLinkSource(theLink.getLinkSource()); retVal.setLinkSource(theLink.getLinkSource());
retval.setMatchResult(theLink.getMatchResult()); retVal.setMatchResult(theLink.getMatchResult());
retval.setLinkCreatedNewResource(theLink.getHadToCreateNewGoldenResource()); retVal.setLinkCreatedNewResource(theLink.getHadToCreateNewGoldenResource());
retval.setScore(theLink.getScore()); retVal.setScore(theLink.getScore());
retval.setUpdated(theLink.getUpdated()); retVal.setUpdated(theLink.getUpdated());
retval.setVector(theLink.getVector()); retVal.setVector(theLink.getVector());
retval.setVersion(theLink.getVersion()); retVal.setVersion(theLink.getVersion());
retval.setRuleCount(theLink.getRuleCount()); retVal.setRuleCount(theLink.getRuleCount());
return retval; return retVal;
} }
} }

View File

@ -6,7 +6,10 @@ import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperConfig; import ca.uhn.fhir.jpa.mdm.helper.MdmHelperConfig;
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperR4; import ca.uhn.fhir.jpa.mdm.helper.MdmHelperR4;
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer; import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkEvent; import ca.uhn.fhir.mdm.api.MdmLinkEvent;
import ca.uhn.fhir.mdm.api.MdmLinkJson;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.model.MdmTransactionContext; import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage; import ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage;
@ -29,6 +32,7 @@ import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.TestPropertySource;
import java.util.List;
import java.util.Properties; import java.util.Properties;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -51,53 +55,38 @@ public class MdmEventIT extends BaseMdmR4Test {
@Autowired @Autowired
private IdHelperService myIdHelperService; private IdHelperService myIdHelperService;
@Bean
@Primary
public Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.format_sql", "true");
extraProperties.put("hibernate.show_sql", "true");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.dialect", H2Dialect.class.getName());
extraProperties.put(BackendSettings.backendKey(BackendSettings.TYPE), "lucene");
extraProperties.put(BackendSettings.backendKey(LuceneBackendSettings.ANALYSIS_CONFIGURER), HapiLuceneAnalysisConfigurer.class.getName());
extraProperties.put(BackendSettings.backendKey(LuceneIndexSettings.DIRECTORY_TYPE), "local-heap");
extraProperties.put(BackendSettings.backendKey(LuceneBackendSettings.LUCENE_VERSION), "LUCENE_CURRENT");
extraProperties.put(HibernateOrmMapperSettings.ENABLED, "true");
return extraProperties;
}
@Test @Test
public void testDuplicateLinkChangeEvent() throws InterruptedException { public void testDuplicateLinkChangeEvent() throws InterruptedException {
Patient patient1 = buildJanePatient(); Patient patient1 = buildJanePatient();
addExternalEID(patient1, "eid-1"); addExternalEID(patient1, "eid-1");
addExternalEID(patient1, "eid-11"); addExternalEID(patient1, "eid-11");
patient1 = createPatientAndUpdateLinks(patient1); myMdmHelper.createWithLatch(patient1);
Patient patient2 = buildPaulPatient(); Patient patient2 = buildPaulPatient();
addExternalEID(patient2, "eid-2"); addExternalEID(patient2, "eid-2");
addExternalEID(patient2, "eid-22"); addExternalEID(patient2, "eid-22");
patient2 = createPatientAndUpdateLinks(patient2); myMdmHelper.createWithLatch(patient2);
Patient patient3 = buildPaulPatient(); Patient patient3 = buildPaulPatient();
addExternalEID(patient3, "eid-22"); addExternalEID(patient3, "eid-22");
patient3 = createPatientAndUpdateLinks(patient3); myMdmHelper.createWithLatch(patient3);
patient2.getIdentifier().clear(); patient2.getIdentifier().clear();
addExternalEID(patient2, "eid-11"); addExternalEID(patient2, "eid-11");
addExternalEID(patient2, "eid-22"); addExternalEID(patient2, "eid-22");
patient2 = (Patient) myPatientDao.update(patient2).getResource(); myMdmHelper.updateWithLatch(patient2);
MdmTransactionContext ctx = myMdmMatchLinkSvc.updateMdmLinksForMdmSource(patient2, createContextForUpdate(patient2.getIdElement().getResourceType()));
MdmLinkEvent mdmLinkEvent = ctx.getMdmLinkEvent(); MdmLinkEvent linkChangeEvent = myMdmHelper.getAfterMdmLatch().getLatchInvocationParameterOfType(MdmLinkEvent.class);
assertFalse(mdmLinkEvent.getDuplicateGoldenResourceIds().isEmpty()); assertNotNull(linkChangeEvent);
// MdmTransactionContext ctx = myMdmMatchLinkSvc.updateMdmLinksForMdmSource(patient2, createContextForUpdate(patient2.getIdElement().getResourceType()));
List<MdmLinkJson> mdmLinkEvent = linkChangeEvent.getMdmLinks();
assertEquals(3, mdmLinkEvent.size());
} }
// @Test @Test
public void testCreateLinkChangeEvent() throws InterruptedException { public void testCreateLinkChangeEvent() throws InterruptedException {
Practitioner pr = buildPractitionerWithNameAndId("Young", "AC-DC"); Practitioner pr = buildPractitionerWithNameAndId("Young", "AC-DC");
myMdmHelper.createWithLatch(pr); myMdmHelper.createWithLatch(pr);
@ -110,56 +99,13 @@ public class MdmEventIT extends BaseMdmR4Test {
MdmLinkEvent linkChangeEvent = myMdmHelper.getAfterMdmLatch().getLatchInvocationParameterOfType(MdmLinkEvent.class); MdmLinkEvent linkChangeEvent = myMdmHelper.getAfterMdmLatch().getLatchInvocationParameterOfType(MdmLinkEvent.class);
assertNotNull(linkChangeEvent); assertNotNull(linkChangeEvent);
assertEquals(link.getGoldenResourcePid(), new IdDt(linkChangeEvent.getGoldenResourceId()).getIdPartAsLong());
assertEquals(link.getSourcePid(), new IdDt(linkChangeEvent.getTargetResourceId()).getIdPartAsLong()); assertEquals(1, linkChangeEvent.getMdmLinks().size());
MdmLinkJson l = linkChangeEvent.getMdmLinks().get(0);
assertEquals(link.getGoldenResourcePid(), new IdDt(l.getGoldenResourceId()).getIdPartAsLong());
assertEquals(link.getSourcePid(), new IdDt(l.getSourceId()).getIdPartAsLong());
} }
/*
@Test
public void testDuplicateLinkChangeEvent() throws InterruptedException {
logAllLinks();
for (IBaseResource r : myPatientDao.search(new SearchParameterMap()).getAllResources()) {
ourLog.info("Found {}", r);
}
Patient myPatient = createPatientAndUpdateLinks(buildPaulPatient());
StringType myPatientId = new StringType(myPatient.getIdElement().getValue());
Patient mySourcePatient = getGoldenResourceFromTargetResource(myPatient);
StringType mySourcePatientId = new StringType(mySourcePatient.getIdElement().getValue());
StringType myVersionlessGodlenResourceId = new StringType(mySourcePatient.getIdElement().toVersionless().getValue());
MdmLink myLink = myMdmLinkDaoSvc.findMdmLinkBySource(myPatient).get();
// Tests require our initial link to be a POSSIBLE_MATCH
myLink.setMatchResult(MdmMatchResultEnum.POSSIBLE_MATCH);
saveLink(myLink);
assertEquals(MdmLinkSourceEnum.AUTO, myLink.getLinkSource());
// myDaoConfig.setExpungeEnabled(true);
// Add a second patient
createPatientAndUpdateLinks(buildJanePatient());
// Add a possible duplicate
StringType myLinkSource = new StringType(MdmLinkSourceEnum.AUTO.name());
Patient sourcePatient1 = createGoldenPatient();
StringType myGoldenResource1Id = new StringType(sourcePatient1.getIdElement().toVersionless().getValue());
Long sourcePatient1Pid = myIdHelperService.getPidOrNull(sourcePatient1);
Patient sourcePatient2 = createGoldenPatient();
StringType myGoldenResource2Id = new StringType(sourcePatient2.getIdElement().toVersionless().getValue());
Long sourcePatient2Pid = myIdHelperService.getPidOrNull(sourcePatient2);
MdmLink possibleDuplicateMdmLink = myMdmLinkDaoSvc.newMdmLink().setGoldenResourcePid(sourcePatient1Pid).setSourcePid(sourcePatient2Pid).setMatchResult(MdmMatchResultEnum.POSSIBLE_DUPLICATE).setLinkSource(MdmLinkSourceEnum.AUTO);
saveLink(possibleDuplicateMdmLink);
logAllLinks();
ResourceOperationMessage resourceOperationMessage = myMdmHelper.getAfterMdmLatch().getLatchInvocationParameterOfType(ResourceOperationMessage.class);
assertNotNull(resourceOperationMessage);
assertEquals(sourcePatient2.getId(), resourceOperationMessage.getId());
}
*/
private MdmLink getLinkByTargetId(IBaseResource theResource) { private MdmLink getLinkByTargetId(IBaseResource theResource) {
MdmLink example = new MdmLink(); MdmLink example = new MdmLink();
example.setSourcePid(theResource.getIdElement().getIdPartAsLong()); example.setSourcePid(theResource.getIdElement().getIdPartAsLong());
@ -171,19 +117,14 @@ public class MdmEventIT extends BaseMdmR4Test {
Patient patient1 = addExternalEID(buildJanePatient(), "eid-1"); Patient patient1 = addExternalEID(buildJanePatient(), "eid-1");
myMdmHelper.createWithLatch(patient1); myMdmHelper.createWithLatch(patient1);
MdmTransactionContext ctx = createContextForCreate("Patient"); MdmLinkEvent linkChangeEvent = myMdmHelper.getAfterMdmLatch().getLatchInvocationParameterOfType(MdmLinkEvent.class);
myMdmMatchLinkSvc.updateMdmLinksForMdmSource(patient1, ctx); assertNotNull(linkChangeEvent);
ourLog.info(ctx.getMdmLinkEvent().toString()); assertEquals(1, linkChangeEvent.getMdmLinks().size());
assertEquals(patient1.getIdElement().getValue(), ctx.getMdmLinkEvent().getTargetResourceId());
assertEquals(getLinkByTargetId(patient1).getGoldenResourcePid(), new IdDt(ctx.getMdmLinkEvent().getGoldenResourceId()).getIdPartAsLong());
Patient patient2 = addExternalEID(buildJanePatient(), "eid-2"); MdmLinkJson link = linkChangeEvent.getMdmLinks().get(0);
myMdmHelper.createWithLatch(patient2); assertEquals(patient1.getResourceType() + "/" + patient1.getIdElement().getIdPart(), link.getSourceId());
ctx = createContextForCreate("Patient"); assertEquals(getLinkByTargetId(patient1).getGoldenResourcePid(), new IdDt(link.getGoldenResourceId()).getIdPartAsLong());
myMdmMatchLinkSvc.updateMdmLinksForMdmSource(patient2, ctx); assertEquals(MdmMatchResultEnum.MATCH, link.getMatchResult());
ourLog.info(ctx.getMdmLinkEvent().toString());
assertEquals(patient2.getIdElement().getValue(), ctx.getMdmLinkEvent().getTargetResourceId());
assertEquals(getLinkByTargetId(patient2).getGoldenResourcePid(), new IdDt(ctx.getMdmLinkEvent().getGoldenResourceId()).getIdPartAsLong());
} }

View File

@ -76,26 +76,6 @@ public class MdmStorageInterceptorIT extends BaseMdmR4Test {
return myMdmLinkDao.findAll(Example.of(example)).get(0); return myMdmLinkDao.findAll(Example.of(example)).get(0);
} }
@Test
public void testUpdateLinkChangeEvent() throws InterruptedException {
Patient patient1 = addExternalEID(buildJanePatient(), "eid-1");
myMdmHelper.createWithLatch(patient1);
MdmTransactionContext ctx = createContextForCreate("Patient");
myMdmMatchLinkSvc.updateMdmLinksForMdmSource(patient1, ctx);
ourLog.info(ctx.getMdmLinkEvent().toString());
assertEquals(patient1.getIdElement().getValue(), ctx.getMdmLinkEvent().getTargetResourceId());
assertEquals(getLinkByTargetId(patient1).getGoldenResourcePid(), new IdDt(ctx.getMdmLinkEvent().getGoldenResourceId()).getIdPartAsLong());
Patient patient2 = addExternalEID(buildJanePatient(), "eid-2");
myMdmHelper.createWithLatch(patient2);
ctx = createContextForCreate("Patient");
myMdmMatchLinkSvc.updateMdmLinksForMdmSource(patient2, ctx);
ourLog.info(ctx.getMdmLinkEvent().toString());
assertEquals(patient2.getIdElement().getValue(), ctx.getMdmLinkEvent().getTargetResourceId());
assertEquals(getLinkByTargetId(patient2).getGoldenResourcePid(), new IdDt(ctx.getMdmLinkEvent().getGoldenResourceId()).getIdPartAsLong());
}
@Test @Test
public void testSearchExpandingInterceptorWorks() { public void testSearchExpandingInterceptorWorks() {
SearchParameterMap subject = new SearchParameterMap("subject", new ReferenceParam("Patient/123").setMdmExpand(true)).setLoadSynchronous(true); SearchParameterMap subject = new SearchParameterMap("subject", new ReferenceParam("Patient/123").setMdmExpand(true)).setLoadSynchronous(true);

View File

@ -0,0 +1,24 @@
package ca.uhn.fhir.mdm.api;
/*-
* #%L
* HAPI FHIR - Master Data Management
* %%
* Copyright (C) 2014 - 2021 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
public interface IMdmLink {
}

View File

@ -25,158 +25,32 @@ import com.fasterxml.jackson.annotation.JsonProperty;
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.IIdType;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
import java.util.Set; import java.util.Set;
public class MdmLinkEvent implements IModelJson { public class MdmLinkEvent implements IModelJson {
@JsonProperty(value = "matchResult") private List<MdmLinkJson> myMdmLinks = new ArrayList<>();
private MdmMatchResultEnum myMdmMatchResult;
@JsonProperty(value = "linkSource")
private MdmLinkSourceEnum myMdmLinkSource;
@JsonProperty(value = "eidMatch")
private Boolean myEidMatch;
@JsonProperty(value = "newGoldenResource")
private Boolean myNewGoldenResource;
@JsonProperty(value = "score")
private Double myScore;
@JsonProperty(value = "ruleCount")
private Long myRuleCount;
@JsonProperty(value = "targetResourceId", required = true)
private String myTargetResourceId;
@JsonProperty(value = "goldenResourceId", required = true)
private String myGoldenResourceId;
@JsonProperty(value = "duplicateResourceIds")
private Set<String> myDuplicateGoldenResourceIds = new HashSet<>();
public String getGoldenResourceId() { public List<MdmLinkJson> getMdmLinks() {
return myGoldenResourceId; return myMdmLinks;
} }
public void setGoldenResourceId(IBaseResource theGoldenResourceId) { public void setMdmLinks(List<MdmLinkJson> theMdmLinks) {
setGoldenResourceId(getIdAsString(theGoldenResourceId)); myMdmLinks = theMdmLinks;
} }
public void setGoldenResourceId(String theGoldenResourceId) { public MdmLinkEvent addMdmLink(MdmLinkJson theMdmLink) {
myGoldenResourceId = theGoldenResourceId; getMdmLinks().add(theMdmLink);
}
private String getIdAsString(IBaseResource theResource) {
if (theResource == null) {
return null;
}
IIdType idElement = theResource.getIdElement();
if (idElement == null) {
return null;
}
return idElement.getValueAsString();
}
public String getTargetResourceId() {
return myTargetResourceId;
}
public void setTargetResourceId(IBaseResource theTargetResource) {
setTargetResourceId(getIdAsString(theTargetResource));
}
public void setTargetResourceId(String theTargetResourceId) {
myTargetResourceId = theTargetResourceId;
}
public Set<String> getDuplicateGoldenResourceIds() {
return myDuplicateGoldenResourceIds;
}
public void setDuplicateGoldenResourceIds(Set<String> theDuplicateGoldenResourceIds) {
myDuplicateGoldenResourceIds = theDuplicateGoldenResourceIds;
}
public MdmLinkEvent addDuplicateGoldenResourceId(IBaseResource theDuplicateGoldenResourceId) {
String id = getIdAsString(theDuplicateGoldenResourceId);
if (id != null) {
getDuplicateGoldenResourceIds().add(id);
}
return this; return this;
} }
public MdmMatchResultEnum getMdmMatchResult() {
return myMdmMatchResult;
}
public void setMdmMatchResult(MdmMatchResultEnum theMdmMatchResult) {
myMdmMatchResult = theMdmMatchResult;
}
public MdmLinkSourceEnum getMdmLinkSource() {
return myMdmLinkSource;
}
public void setMdmLinkSource(MdmLinkSourceEnum theMdmLinkSource) {
myMdmLinkSource = theMdmLinkSource;
}
public Boolean getEidMatch() {
return myEidMatch;
}
public void setEidMatch(Boolean theEidMatch) {
if (theEidMatch == null) {
myEidMatch = Boolean.FALSE;
return;
}
myEidMatch = theEidMatch;
}
public Boolean getNewGoldenResource() {
return myNewGoldenResource;
}
public void setNewGoldenResource(Boolean theNewGoldenResource) {
if (theNewGoldenResource == null) {
myNewGoldenResource = Boolean.FALSE;
return;
}
myNewGoldenResource = theNewGoldenResource;
}
public Double getScore() {
return myScore;
}
public void setScore(Double theScore) {
myScore = theScore;
}
public Long getRuleCount() {
return myRuleCount;
}
public void setRuleCount(Long theRuleCount) {
myRuleCount = theRuleCount;
}
public void setFromLink(MdmLinkJson theMdmLinkJson) {
setMdmMatchResult(theMdmLinkJson.getMatchResult());
setMdmLinkSource(theMdmLinkJson.getLinkSource());
setEidMatch(theMdmLinkJson.getEidMatch());
setNewGoldenResource(theMdmLinkJson.getLinkCreatedNewResource());
setScore(theMdmLinkJson.getScore());
setRuleCount(theMdmLinkJson.getRuleCount());
}
@Override @Override
public String toString() { public String toString() {
return "MdmLinkChangeEvent{" + return "MdmLinkEvent{" +
"myMdmMatchResult=" + myMdmMatchResult + "myMdmLinks=" + myMdmLinks +
", myMdmLinkSource=" + myMdmLinkSource +
", myEidMatch=" + myEidMatch +
", myNewGoldenResource=" + myNewGoldenResource +
", myScore=" + myScore +
", myRuleCount=" + myRuleCount +
", myTargetResourceId='" + myTargetResourceId + '\'' +
", myGoldenResourceId='" + myGoldenResourceId + '\'' +
", myDuplicateGoldenResourceIds=" + myDuplicateGoldenResourceIds +
'}'; '}';
} }
} }

View File

@ -20,9 +20,13 @@ package ca.uhn.fhir.mdm.model;
* #L% * #L%
*/ */
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkEvent; import ca.uhn.fhir.mdm.api.MdmLinkEvent;
import ca.uhn.fhir.rest.server.TransactionLogMessages; import ca.uhn.fhir.rest.server.TransactionLogMessages;
import java.util.ArrayList;
import java.util.List;
public class MdmTransactionContext { public class MdmTransactionContext {
public enum OperationType { public enum OperationType {
@ -46,7 +50,7 @@ public class MdmTransactionContext {
private String myResourceType; private String myResourceType;
private MdmLinkEvent myMdmLinkEvent = new MdmLinkEvent(); private List<IMdmLink> myMdmLinkEvents = new ArrayList<>();
public TransactionLogMessages getTransactionLogMessages() { public TransactionLogMessages getTransactionLogMessages() {
return myTransactionLogMessages; return myTransactionLogMessages;
@ -96,12 +100,16 @@ public class MdmTransactionContext {
this.myResourceType = myResourceType; this.myResourceType = myResourceType;
} }
public MdmLinkEvent getMdmLinkEvent() { public List<IMdmLink> getMdmLinks() {
return myMdmLinkEvent; return myMdmLinkEvents;
} }
public void setMdmLinkChangeEvent(MdmLinkEvent theMdmLinkEvent) { public MdmTransactionContext addMdmLink(IMdmLink theMdmLinkEvent) {
myMdmLinkEvent = theMdmLinkEvent; getMdmLinks().add(theMdmLinkEvent);
return this;
} }
public void setMdmLinks(List<IMdmLink> theMdmLinkEvents) {
myMdmLinkEvents = theMdmLinkEvents;
}
} }