rebuilding golden resources with survivorship in partitions (#5957)
* fixing a regression that prevented rebuilding golden resources with survivorship in a partitioned system * spotless * update var usage --------- Co-authored-by: leif stawnyczy <leifstawnyczy@leifs-mbp.home>
This commit is contained in:
parent
f199a3ee4e
commit
357802bfe8
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5956
|
||||||
|
title: "Fixed a regression that prevented rebuilding golden resources with mdm
|
||||||
|
survivorship rules when resources have non-numeric fhir ids in
|
||||||
|
a partitioned system.
|
||||||
|
"
|
|
@ -155,25 +155,26 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
|
||||||
public IResourceLookup<JpaPid> resolveResourceIdentity(
|
public IResourceLookup<JpaPid> resolveResourceIdentity(
|
||||||
@Nonnull RequestPartitionId theRequestPartitionId,
|
@Nonnull RequestPartitionId theRequestPartitionId,
|
||||||
String theResourceType,
|
String theResourceType,
|
||||||
String theResourceId,
|
final String theResourceId,
|
||||||
boolean theExcludeDeleted)
|
boolean theExcludeDeleted)
|
||||||
throws ResourceNotFoundException {
|
throws ResourceNotFoundException {
|
||||||
assert myDontCheckActiveTransactionForUnitTest || TransactionSynchronizationManager.isSynchronizationActive()
|
assert myDontCheckActiveTransactionForUnitTest || TransactionSynchronizationManager.isSynchronizationActive()
|
||||||
: "no transaction active";
|
: "no transaction active";
|
||||||
|
|
||||||
if (theResourceId.contains("/")) {
|
String resourceIdToUse = theResourceId;
|
||||||
theResourceId = theResourceId.substring(theResourceId.indexOf("/") + 1);
|
if (resourceIdToUse.contains("/")) {
|
||||||
|
resourceIdToUse = theResourceId.substring(resourceIdToUse.indexOf("/") + 1);
|
||||||
}
|
}
|
||||||
IdDt id = new IdDt(theResourceType, theResourceId);
|
IdDt id = new IdDt(theResourceType, resourceIdToUse);
|
||||||
Map<String, List<IResourceLookup<JpaPid>>> matches =
|
Map<String, List<IResourceLookup<JpaPid>>> matches =
|
||||||
translateForcedIdToPids(theRequestPartitionId, Collections.singletonList(id), theExcludeDeleted);
|
translateForcedIdToPids(theRequestPartitionId, Collections.singletonList(id), theExcludeDeleted);
|
||||||
|
|
||||||
// We only pass 1 input in so only 0..1 will come back
|
// We only pass 1 input in so only 0..1 will come back
|
||||||
if (matches.isEmpty() || !matches.containsKey(theResourceId)) {
|
if (matches.isEmpty() || !matches.containsKey(resourceIdToUse)) {
|
||||||
throw new ResourceNotFoundException(Msg.code(2001) + "Resource " + id + " is not known");
|
throw new ResourceNotFoundException(Msg.code(2001) + "Resource " + id + " is not known");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matches.size() > 1 || matches.get(theResourceId).size() > 1) {
|
if (matches.size() > 1 || matches.get(resourceIdToUse).size() > 1) {
|
||||||
/*
|
/*
|
||||||
* This means that:
|
* This means that:
|
||||||
* 1. There are two resources with the exact same resource type and forced id
|
* 1. There are two resources with the exact same resource type and forced id
|
||||||
|
@ -183,7 +184,7 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
|
||||||
throw new PreconditionFailedException(Msg.code(1099) + msg);
|
throw new PreconditionFailedException(Msg.code(1099) + msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
return matches.get(theResourceId).get(0);
|
return matches.get(resourceIdToUse).get(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -31,9 +31,11 @@ import java.math.RoundingMode;
|
||||||
|
|
||||||
public class MdmModelConverterSvcImpl implements IMdmModelConverterSvc {
|
public class MdmModelConverterSvcImpl implements IMdmModelConverterSvc {
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
@Autowired
|
@Autowired
|
||||||
IIdHelperService myIdHelperService;
|
IIdHelperService myIdHelperService;
|
||||||
|
|
||||||
|
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||||
@Override
|
@Override
|
||||||
public MdmLinkJson toJson(IMdmLink theLink) {
|
public MdmLinkJson toJson(IMdmLink theLink) {
|
||||||
MdmLinkJson retVal = new MdmLinkJson();
|
MdmLinkJson retVal = new MdmLinkJson();
|
||||||
|
@ -42,11 +44,13 @@ public class MdmModelConverterSvcImpl implements IMdmModelConverterSvc {
|
||||||
.toVersionless()
|
.toVersionless()
|
||||||
.getValue();
|
.getValue();
|
||||||
retVal.setSourceId(sourceId);
|
retVal.setSourceId(sourceId);
|
||||||
|
retVal.setSourcePid(theLink.getSourcePersistenceId());
|
||||||
String goldenResourceId = myIdHelperService
|
String goldenResourceId = myIdHelperService
|
||||||
.resourceIdFromPidOrThrowException(theLink.getGoldenResourcePersistenceId(), theLink.getMdmSourceType())
|
.resourceIdFromPidOrThrowException(theLink.getGoldenResourcePersistenceId(), theLink.getMdmSourceType())
|
||||||
.toVersionless()
|
.toVersionless()
|
||||||
.getValue();
|
.getValue();
|
||||||
retVal.setGoldenResourceId(goldenResourceId);
|
retVal.setGoldenResourceId(goldenResourceId);
|
||||||
|
retVal.setGoldenPid(theLink.getGoldenResourcePersistenceId());
|
||||||
retVal.setCreated(theLink.getCreated());
|
retVal.setCreated(theLink.getCreated());
|
||||||
retVal.setEidMatch(theLink.getEidMatch());
|
retVal.setEidMatch(theLink.getEidMatch());
|
||||||
retVal.setLinkSource(theLink.getLinkSource());
|
retVal.setLinkSource(theLink.getLinkSource());
|
||||||
|
|
|
@ -2,13 +2,14 @@ package ca.uhn.fhir.jpa.mdm.svc;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.entity.MdmLink;
|
import ca.uhn.fhir.jpa.entity.MdmLink;
|
||||||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||||
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.model.entity.EnversRevision;
|
import ca.uhn.fhir.jpa.model.entity.EnversRevision;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmLink;
|
import ca.uhn.fhir.mdm.api.IMdmLink;
|
||||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
|
||||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
|
||||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevision;
|
import ca.uhn.fhir.mdm.api.MdmLinkWithRevision;
|
||||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||||
|
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||||
|
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||||
import org.hibernate.envers.RevisionType;
|
import org.hibernate.envers.RevisionType;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -16,8 +17,6 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
@ -25,6 +24,8 @@ import java.time.Month;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
public class MdmModelConverterSvcImplTest extends BaseMdmR4Test {
|
public class MdmModelConverterSvcImplTest extends BaseMdmR4Test {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(MdmModelConverterSvcImplTest.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(MdmModelConverterSvcImplTest.class);
|
||||||
|
|
||||||
|
@ -49,7 +50,8 @@ public class MdmModelConverterSvcImplTest extends BaseMdmR4Test {
|
||||||
|
|
||||||
ourLog.info("actualMdmLinkJson: {}", actualMdmLinkJson);
|
ourLog.info("actualMdmLinkJson: {}", actualMdmLinkJson);
|
||||||
|
|
||||||
assertEquals(getExepctedMdmLinkJson(mdmLink.getGoldenResourcePersistenceId().getId(), mdmLink.getSourcePersistenceId().getId(), MdmMatchResultEnum.MATCH, MdmLinkSourceEnum.MANUAL, version, createTime, updateTime, isLinkCreatedResource, scoreRounded), actualMdmLinkJson);
|
MdmLinkJson exepctedMdmLinkJson = getExepctedMdmLinkJson(mdmLink.getGoldenResourcePersistenceId().getId(), mdmLink.getSourcePersistenceId().getId(), MdmMatchResultEnum.MATCH, MdmLinkSourceEnum.MANUAL, version, createTime, updateTime, isLinkCreatedResource, scoreRounded);
|
||||||
|
assertEquals(exepctedMdmLinkJson, actualMdmLinkJson);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -99,7 +101,9 @@ public class MdmModelConverterSvcImplTest extends BaseMdmR4Test {
|
||||||
final MdmLinkJson mdmLinkJson = new MdmLinkJson();
|
final MdmLinkJson mdmLinkJson = new MdmLinkJson();
|
||||||
|
|
||||||
mdmLinkJson.setGoldenResourceId("Patient/" + theGoldenPatientId);
|
mdmLinkJson.setGoldenResourceId("Patient/" + theGoldenPatientId);
|
||||||
|
mdmLinkJson.setGoldenPid(JpaPid.fromId(theGoldenPatientId));
|
||||||
mdmLinkJson.setSourceId("Patient/" + theSourceId);
|
mdmLinkJson.setSourceId("Patient/" + theSourceId);
|
||||||
|
mdmLinkJson.setSourcePid(JpaPid.fromId(theSourceId));
|
||||||
mdmLinkJson.setMatchResult(theMdmMatchResultEnum);
|
mdmLinkJson.setMatchResult(theMdmMatchResultEnum);
|
||||||
mdmLinkJson.setLinkSource(theMdmLinkSourceEnum);
|
mdmLinkJson.setLinkSource(theMdmLinkSourceEnum);
|
||||||
mdmLinkJson.setVersion(version);
|
mdmLinkJson.setVersion(version);
|
||||||
|
|
|
@ -1,17 +1,22 @@
|
||||||
package ca.uhn.fhir.jpa.mdm.svc;
|
package ca.uhn.fhir.jpa.mdm.svc;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
|
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
||||||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.StorageSettings;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
|
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
|
||||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||||
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
|
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
|
||||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||||
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.partition.RequestTenantPartitionInterceptor;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
@ -77,4 +82,104 @@ class MdmSurvivorshipSvcImplIT extends BaseMdmR4Test {
|
||||||
|
|
||||||
myMdmSurvivorshipService.rebuildGoldenResourceWithSurvivorshipRules(goldenPatient, new MdmTransactionContext(MdmTransactionContext.OperationType.UPDATE_LINK));
|
myMdmSurvivorshipService.rebuildGoldenResourceWithSurvivorshipRules(goldenPatient, new MdmTransactionContext(MdmTransactionContext.OperationType.UPDATE_LINK));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void rebuildGoldenResourceWithSurvivorshipRules_usingPatchedResourcesAndPartitions_doesNotThrow() {
|
||||||
|
// setup
|
||||||
|
boolean isPartitioningEnabled = myPartitionSettings.isPartitioningEnabled();
|
||||||
|
boolean isUnnamedPartitionMode = myPartitionSettings.isUnnamedPartitionMode();
|
||||||
|
StorageSettings.IndexEnabledEnum indexMissingFields = myStorageSettings.getIndexMissingFields();
|
||||||
|
boolean isSearchAllPartitionForMatch = myMdmSettings.getSearchAllPartitionForMatch();
|
||||||
|
String goldenResourcePartitionName = myMdmSettings.getGoldenResourcePartitionName();
|
||||||
|
|
||||||
|
myPartitionSettings.setPartitioningEnabled(true);
|
||||||
|
myPartitionSettings.setUnnamedPartitionMode(false);
|
||||||
|
myStorageSettings.setIndexMissingFields(StorageSettings.IndexEnabledEnum.ENABLED);
|
||||||
|
myMdmSettings.setSearchAllPartitionForMatch(true);
|
||||||
|
myMdmSettings.setGoldenResourcePartitionName(PARTITION_2);
|
||||||
|
|
||||||
|
MdmTransactionContext transactionContext = new MdmTransactionContext(MdmTransactionContext.OperationType.UPDATE_LINK);
|
||||||
|
|
||||||
|
// register the tenant partition interceptor
|
||||||
|
// req'd so partition values will be filled in
|
||||||
|
RequestTenantPartitionInterceptor tenantPartitionInterceptor = new RequestTenantPartitionInterceptor();
|
||||||
|
myInterceptorRegistry.registerInterceptor(tenantPartitionInterceptor);
|
||||||
|
try {
|
||||||
|
// create the partitions we need
|
||||||
|
PartitionEntity partition1 = new PartitionEntity();
|
||||||
|
partition1.setName(PARTITION_1);
|
||||||
|
partition1.setId(1);
|
||||||
|
partition1.setDescription("first");
|
||||||
|
myPartitionLookupSvc.createPartition(partition1, new SystemRequestDetails());
|
||||||
|
PartitionEntity partition2 = new PartitionEntity();
|
||||||
|
partition2.setName(PARTITION_2);
|
||||||
|
partition2.setId(2);
|
||||||
|
partition2.setDescription("second");
|
||||||
|
myPartitionLookupSvc.createPartition(partition2, new SystemRequestDetails());
|
||||||
|
myPartitionLookupSvc.invalidateCaches();
|
||||||
|
|
||||||
|
// create the patients - 2 in part-a, golden in partition golden
|
||||||
|
SystemRequestDetails partitionARequestDetails = new SystemRequestDetails();
|
||||||
|
partitionARequestDetails.setRequestPartitionId(RequestPartitionId.fromPartitionId(1));
|
||||||
|
Patient patient1 = buildJanePatient();
|
||||||
|
patient1.setId("Patient/pat-a");
|
||||||
|
myPatientDao.update(patient1,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
partitionARequestDetails,
|
||||||
|
new TransactionDetails());
|
||||||
|
|
||||||
|
Patient patient2 = buildJanePatient();
|
||||||
|
patient2.setId("Patient/pat-b");
|
||||||
|
myPatientDao.update(
|
||||||
|
patient2,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
partitionARequestDetails,
|
||||||
|
new TransactionDetails()
|
||||||
|
);
|
||||||
|
|
||||||
|
// manually create our golden resource
|
||||||
|
SystemRequestDetails goldenRequestDetails = new SystemRequestDetails();
|
||||||
|
goldenRequestDetails.setRequestPartitionId(RequestPartitionId.fromPartitionId(2));
|
||||||
|
final Patient goldenPatient = buildJanePatient();
|
||||||
|
goldenPatient.setId("pat-gold");
|
||||||
|
myPatientDao.update(goldenPatient,
|
||||||
|
null,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
goldenRequestDetails,
|
||||||
|
new TransactionDetails());
|
||||||
|
|
||||||
|
// save our links
|
||||||
|
{
|
||||||
|
myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, patient1, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.AUTO, createContextForCreate("Patient"));
|
||||||
|
myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, patient2, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.AUTO, createContextForCreate("Patient"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove link
|
||||||
|
{
|
||||||
|
Patient patb = new Patient();
|
||||||
|
patb.setId(patient2.getId());
|
||||||
|
myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, patb, MdmMatchOutcome.NO_MATCH, MdmLinkSourceEnum.MANUAL, createContextForUpdate("Patient"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// test
|
||||||
|
myMdmSurvivorshipService.rebuildGoldenResourceWithSurvivorshipRules(goldenPatient, transactionContext);
|
||||||
|
|
||||||
|
IBundleProvider provider = myPatientDao.search(new SearchParameterMap().setLoadSynchronous(true),
|
||||||
|
new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.allPartitions()));
|
||||||
|
} finally {
|
||||||
|
// reset
|
||||||
|
myInterceptorRegistry.unregisterInterceptor(tenantPartitionInterceptor);
|
||||||
|
|
||||||
|
myPartitionSettings.setPartitioningEnabled(isPartitioningEnabled);
|
||||||
|
myPartitionSettings.setUnnamedPartitionMode(isUnnamedPartitionMode);
|
||||||
|
myStorageSettings.setIndexMissingFields(indexMissingFields);
|
||||||
|
myMdmSettings.setSearchAllPartitionForMatch(isSearchAllPartitionForMatch);
|
||||||
|
myMdmSettings.setGoldenResourcePartitionName(goldenResourcePartitionName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||||
import ca.uhn.fhir.mdm.model.CanonicalEID;
|
import ca.uhn.fhir.mdm.model.CanonicalEID;
|
||||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkWithRevisionJson;
|
|
||||||
import ca.uhn.fhir.mdm.rules.json.MdmRulesJson;
|
import ca.uhn.fhir.mdm.rules.json.MdmRulesJson;
|
||||||
import ca.uhn.fhir.mdm.svc.MdmSurvivorshipSvcImpl;
|
import ca.uhn.fhir.mdm.svc.MdmSurvivorshipSvcImpl;
|
||||||
import ca.uhn.fhir.mdm.util.EIDHelper;
|
import ca.uhn.fhir.mdm.util.EIDHelper;
|
||||||
|
@ -102,6 +101,7 @@ public class MdmSurvivorshipSvcImplTest {
|
||||||
public void rebuildGoldenResourceCurrentLinksUsingSurvivorshipRules_withManyLinks_rebuildsInUpdateOrder(boolean theIsUseNonNumericId) {
|
public void rebuildGoldenResourceCurrentLinksUsingSurvivorshipRules_withManyLinks_rebuildsInUpdateOrder(boolean theIsUseNonNumericId) {
|
||||||
// setup
|
// setup
|
||||||
// create resources
|
// create resources
|
||||||
|
int goldenId = 777;
|
||||||
Patient goldenPatient = new Patient();
|
Patient goldenPatient = new Patient();
|
||||||
goldenPatient.addAddress()
|
goldenPatient.addAddress()
|
||||||
.setCity("Toronto")
|
.setCity("Toronto")
|
||||||
|
@ -109,13 +109,13 @@ public class MdmSurvivorshipSvcImplTest {
|
||||||
goldenPatient.addName()
|
goldenPatient.addName()
|
||||||
.setFamily("Doe")
|
.setFamily("Doe")
|
||||||
.addGiven("Jane");
|
.addGiven("Jane");
|
||||||
goldenPatient.setId("Patient/777");
|
goldenPatient.setId("Patient/" + goldenId);
|
||||||
MdmResourceUtil.setMdmManaged(goldenPatient);
|
MdmResourceUtil.setMdmManaged(goldenPatient);
|
||||||
MdmResourceUtil.setGoldenResource(goldenPatient);
|
MdmResourceUtil.setGoldenResource(goldenPatient);
|
||||||
|
|
||||||
List<IBaseResource> resources = new ArrayList<>();
|
List<IBaseResource> resources = new ArrayList<>();
|
||||||
List<MdmLinkJson> links = new ArrayList<>();
|
List<MdmLinkJson> links = new ArrayList<>();
|
||||||
List<MdmLinkWithRevisionJson> linksWithRevisions = new ArrayList<>();
|
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
// we want our resources to be slightly different
|
// we want our resources to be slightly different
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
|
@ -128,21 +128,16 @@ public class MdmSurvivorshipSvcImplTest {
|
||||||
patient.addIdentifier()
|
patient.addIdentifier()
|
||||||
.setSystem("http://example.com")
|
.setSystem("http://example.com")
|
||||||
.setValue("Value" + i);
|
.setValue("Value" + i);
|
||||||
patient.setId("Patient/" + (theIsUseNonNumericId ? "pat"+i : Integer.toString(i)));
|
patient.setId("Patient/" + (theIsUseNonNumericId ? "pat" + i : Integer.toString(i)));
|
||||||
resources.add(patient);
|
resources.add(patient);
|
||||||
|
|
||||||
MdmLinkJson link = createLinkJson(
|
MdmLinkJson link = createLinkJson(
|
||||||
patient,
|
patient,
|
||||||
goldenPatient
|
goldenPatient
|
||||||
);
|
);
|
||||||
|
link.setSourcePid(JpaPid.fromId((long)i));
|
||||||
|
link.setGoldenPid(JpaPid.fromId((long)goldenId));
|
||||||
links.add(link);
|
links.add(link);
|
||||||
linksWithRevisions.add(new MdmLinkWithRevisionJson(
|
|
||||||
link,
|
|
||||||
1L,
|
|
||||||
Date.from(
|
|
||||||
Instant.now().minus(i, ChronoUnit.HOURS)
|
|
||||||
)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IFhirResourceDao resourceDao = mock(IFhirResourceDao.class);
|
IFhirResourceDao resourceDao = mock(IFhirResourceDao.class);
|
||||||
|
@ -151,13 +146,8 @@ public class MdmSurvivorshipSvcImplTest {
|
||||||
when(myDaoRegistry.getResourceDao(eq("Patient")))
|
when(myDaoRegistry.getResourceDao(eq("Patient")))
|
||||||
.thenReturn(resourceDao);
|
.thenReturn(resourceDao);
|
||||||
AtomicInteger counter = new AtomicInteger();
|
AtomicInteger counter = new AtomicInteger();
|
||||||
if (theIsUseNonNumericId) {
|
when(resourceDao.readByPid(any()))
|
||||||
when(resourceDao.read(any(), any()))
|
.thenAnswer(params -> resources.get(counter.getAndIncrement()));
|
||||||
.thenAnswer(params -> resources.get(counter.getAndIncrement()));
|
|
||||||
} else {
|
|
||||||
when(resourceDao.readByPid(any()))
|
|
||||||
.thenAnswer(params -> resources.get(counter.getAndIncrement()));
|
|
||||||
}
|
|
||||||
Page<MdmLinkJson> linkPage = mock(Page.class);
|
Page<MdmLinkJson> linkPage = mock(Page.class);
|
||||||
when(myMdmLinkQuerySvc.queryLinks(any(), any()))
|
when(myMdmLinkQuerySvc.queryLinks(any(), any()))
|
||||||
.thenReturn(linkPage);
|
.thenReturn(linkPage);
|
||||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.mdm.model.mdmevents;
|
||||||
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.model.api.IModelJson;
|
import ca.uhn.fhir.model.api.IModelJson;
|
||||||
|
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -29,15 +30,39 @@ import java.util.Objects;
|
||||||
|
|
||||||
public class MdmLinkJson implements IModelJson {
|
public class MdmLinkJson implements IModelJson {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Golden resource FhirId
|
||||||
|
*/
|
||||||
@JsonProperty("goldenResourceId")
|
@JsonProperty("goldenResourceId")
|
||||||
private String myGoldenResourceId;
|
private String myGoldenResourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source resource FhirId
|
||||||
|
*/
|
||||||
@JsonProperty("sourceId")
|
@JsonProperty("sourceId")
|
||||||
private String mySourceId;
|
private String mySourceId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Golden resource PID
|
||||||
|
*/
|
||||||
|
@JsonProperty("goldenPid")
|
||||||
|
private IResourcePersistentId<?> myGoldenPid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Source PID
|
||||||
|
*/
|
||||||
|
@JsonProperty("sourcePid")
|
||||||
|
private IResourcePersistentId<?> mySourcePid;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kind of link (MATCH, etc)
|
||||||
|
*/
|
||||||
@JsonProperty("matchResult")
|
@JsonProperty("matchResult")
|
||||||
private MdmMatchResultEnum myMatchResult;
|
private MdmMatchResultEnum myMatchResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How the link was constructed (AUTO - by the system, MANUAL - by a user)
|
||||||
|
*/
|
||||||
@JsonProperty("linkSource")
|
@JsonProperty("linkSource")
|
||||||
private MdmLinkSourceEnum myLinkSource;
|
private MdmLinkSourceEnum myLinkSource;
|
||||||
|
|
||||||
|
@ -178,6 +203,22 @@ public class MdmLinkJson implements IModelJson {
|
||||||
myRuleCount = theRuleCount;
|
myRuleCount = theRuleCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IResourcePersistentId<?> getGoldenPid() {
|
||||||
|
return myGoldenPid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGoldenPid(IResourcePersistentId<?> theGoldenPid) {
|
||||||
|
myGoldenPid = theGoldenPid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IResourcePersistentId<?> getSourcePid() {
|
||||||
|
return mySourcePid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourcePid(IResourcePersistentId<?> theSourcePid) {
|
||||||
|
mySourcePid = theSourcePid;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object theO) {
|
public boolean equals(Object theO) {
|
||||||
if (this == theO) return true;
|
if (this == theO) return true;
|
||||||
|
@ -185,6 +226,8 @@ public class MdmLinkJson implements IModelJson {
|
||||||
final MdmLinkJson that = (MdmLinkJson) theO;
|
final MdmLinkJson that = (MdmLinkJson) theO;
|
||||||
return Objects.equals(myGoldenResourceId, that.myGoldenResourceId)
|
return Objects.equals(myGoldenResourceId, that.myGoldenResourceId)
|
||||||
&& Objects.equals(mySourceId, that.mySourceId)
|
&& Objects.equals(mySourceId, that.mySourceId)
|
||||||
|
&& mySourcePid.equals(that.mySourcePid)
|
||||||
|
&& myGoldenPid.equals(that.myGoldenPid)
|
||||||
&& myMatchResult == that.myMatchResult
|
&& myMatchResult == that.myMatchResult
|
||||||
&& myLinkSource == that.myLinkSource
|
&& myLinkSource == that.myLinkSource
|
||||||
&& Objects.equals(myCreated, that.myCreated)
|
&& Objects.equals(myCreated, that.myCreated)
|
||||||
|
@ -202,6 +245,8 @@ public class MdmLinkJson implements IModelJson {
|
||||||
return Objects.hash(
|
return Objects.hash(
|
||||||
myGoldenResourceId,
|
myGoldenResourceId,
|
||||||
mySourceId,
|
mySourceId,
|
||||||
|
mySourcePid,
|
||||||
|
myGoldenPid,
|
||||||
myMatchResult,
|
myMatchResult,
|
||||||
myLinkSource,
|
myLinkSource,
|
||||||
myCreated,
|
myCreated,
|
||||||
|
@ -216,18 +261,21 @@ public class MdmLinkJson implements IModelJson {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "MdmLinkJson{" + "myGoldenResourceId='"
|
return "MdmLinkJson{"
|
||||||
+ myGoldenResourceId + '\'' + ", mySourceId='"
|
+ "myGoldenResourceId='" + myGoldenResourceId + '\''
|
||||||
+ mySourceId + '\'' + ", myMatchResult="
|
+ ", myGoldenPid='" + myGoldenPid + '\''
|
||||||
+ myMatchResult + ", myLinkSource="
|
+ ", mySourceId='" + mySourceId + '\''
|
||||||
+ myLinkSource + ", myCreated="
|
+ ", mySourcePid='" + mySourcePid + '\''
|
||||||
+ myCreated + ", myUpdated="
|
+ ", myMatchResult=" + myMatchResult
|
||||||
+ myUpdated + ", myVersion='"
|
+ ", myLinkSource=" + myLinkSource
|
||||||
+ myVersion + '\'' + ", myEidMatch="
|
+ ", myCreated=" + myCreated
|
||||||
+ myEidMatch + ", myLinkCreatedNewResource="
|
+ ", myUpdated=" + myUpdated
|
||||||
+ myLinkCreatedNewResource + ", myVector="
|
+ ", myVersion='" + myVersion + '\''
|
||||||
+ myVector + ", myScore="
|
+ ", myEidMatch=" + myEidMatch
|
||||||
+ myScore + ", myRuleCount="
|
+ ", myLinkCreatedNewResource=" + myLinkCreatedNewResource
|
||||||
+ myRuleCount + '}';
|
+ ", myVector=" + myVector
|
||||||
|
+ ", myScore=" + myScore
|
||||||
|
+ ", myRuleCount=" + myRuleCount
|
||||||
|
+ '}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
package ca.uhn.fhir.mdm.svc;
|
package ca.uhn.fhir.mdm.svc;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
||||||
|
@ -31,7 +32,7 @@ import ca.uhn.fhir.mdm.api.params.MdmQuerySearchParameters;
|
||||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||||
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson;
|
||||||
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
|
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||||
import ca.uhn.fhir.util.TerserUtil;
|
import ca.uhn.fhir.util.TerserUtil;
|
||||||
|
@ -118,7 +119,15 @@ public class MdmSurvivorshipSvcImpl implements IMdmSurvivorshipService {
|
||||||
|
|
||||||
// save it
|
// save it
|
||||||
IFhirResourceDao dao = myDaoRegistry.getResourceDao(goldenResource.fhirType());
|
IFhirResourceDao dao = myDaoRegistry.getResourceDao(goldenResource.fhirType());
|
||||||
dao.update(toSave, new SystemRequestDetails());
|
|
||||||
|
SystemRequestDetails requestDetails = new SystemRequestDetails();
|
||||||
|
// if using partitions, we should save to the correct partition
|
||||||
|
Object resourcePartitionIdObj = toSave.getUserData(Constants.RESOURCE_PARTITION_ID);
|
||||||
|
if (resourcePartitionIdObj instanceof RequestPartitionId) {
|
||||||
|
RequestPartitionId partitionId = (RequestPartitionId) resourcePartitionIdObj;
|
||||||
|
requestDetails.setRequestPartitionId(partitionId);
|
||||||
|
}
|
||||||
|
dao.update(toSave, requestDetails);
|
||||||
|
|
||||||
return (T) toSave;
|
return (T) toSave;
|
||||||
}
|
}
|
||||||
|
@ -135,24 +144,8 @@ public class MdmSurvivorshipSvcImpl implements IMdmSurvivorshipService {
|
||||||
Page<MdmLinkJson> linksQuery = myMdmLinkQuerySvc.queryLinks(searchParameters, theMdmTransactionContext);
|
Page<MdmLinkJson> linksQuery = myMdmLinkQuerySvc.queryLinks(searchParameters, theMdmTransactionContext);
|
||||||
|
|
||||||
return linksQuery.get().map(link -> {
|
return linksQuery.get().map(link -> {
|
||||||
String sourceId = link.getSourceId();
|
IResourcePersistentId<?> pid = link.getSourcePid();
|
||||||
|
return dao.readByPid(pid);
|
||||||
// +1 because of "/" in id: "ResourceType/Id"
|
|
||||||
final String sourceIdUnqualified = sourceId.substring(resourceType.length() + 1);
|
|
||||||
|
|
||||||
// myMdmLinkQuerySvc.queryLinks populates sourceId with the FHIR_ID, not the RES_ID, so if we don't
|
|
||||||
// add this conditional logic, on JPA, myIIdHelperService.newPidFromStringIdAndResourceName will fail with
|
|
||||||
// NumberFormatException
|
|
||||||
if (isNumericOrUuid(sourceIdUnqualified)) {
|
|
||||||
IResourcePersistentId<?> pid = getResourcePID(sourceIdUnqualified, resourceType);
|
|
||||||
|
|
||||||
// this might be a bit unperformant
|
|
||||||
// but it depends how many links there are
|
|
||||||
// per golden resource (unlikely to be thousands)
|
|
||||||
return dao.readByPid(pid);
|
|
||||||
} else {
|
|
||||||
return dao.read(new IdDt(sourceId), new SystemRequestDetails());
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue