fixed mdmjsonlink serialization issues (#5987)
* fixed mdmjsonlink serialization issues * spotless * test fixing * spotless * review fixes * spotless * fixing * spotless --------- Co-authored-by: leif stawnyczy <leifstawnyczy@leifs-mbp.home>
This commit is contained in:
parent
5b75639718
commit
1437c356ae
|
@ -0,0 +1,8 @@
|
||||||
|
---
|
||||||
|
type: fix
|
||||||
|
issue: 5985
|
||||||
|
title: "Fixed an issue where MDM json links were unserializable
|
||||||
|
due to using the IResourcePersistenceId objects.
|
||||||
|
This has been fixed, and IResourcePersistenceId objects
|
||||||
|
will not be serialized or returned to users.
|
||||||
|
"
|
|
@ -125,7 +125,7 @@ public class IdHelperService implements IIdHelperService<JpaPid> {
|
||||||
private boolean myDontCheckActiveTransactionForUnitTest;
|
private boolean myDontCheckActiveTransactionForUnitTest;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void setDontCheckActiveTransactionForUnitTest(boolean theDontCheckActiveTransactionForUnitTest) {
|
protected void setDontCheckActiveTransactionForUnitTest(boolean theDontCheckActiveTransactionForUnitTest) {
|
||||||
myDontCheckActiveTransactionForUnitTest = theDontCheckActiveTransactionForUnitTest;
|
myDontCheckActiveTransactionForUnitTest = theDontCheckActiveTransactionForUnitTest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,11 +20,20 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.ArgumentMatchers;
|
import org.mockito.ArgumentMatchers;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.Spy;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.lenient;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
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;
|
||||||
|
@ -37,7 +46,7 @@ import static org.mockito.Mockito.when;
|
||||||
public class IdHelperServiceTest {
|
public class IdHelperServiceTest {
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private final IdHelperService subject = new IdHelperService();
|
private final IdHelperService myHelperSvc = new IdHelperService();
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
protected IResourceTableDao myResourceTableDao;
|
protected IResourceTableDao myResourceTableDao;
|
||||||
|
@ -45,8 +54,8 @@ public class IdHelperServiceTest {
|
||||||
@Mock
|
@Mock
|
||||||
private JpaStorageSettings myStorageSettings;
|
private JpaStorageSettings myStorageSettings;
|
||||||
|
|
||||||
@Mock
|
@Spy
|
||||||
private FhirContext myFhirCtx;
|
private FhirContext myFhirCtx = FhirContext.forR4Cached();
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private MemoryCacheService myMemoryCacheService;
|
private MemoryCacheService myMemoryCacheService;
|
||||||
|
@ -59,10 +68,11 @@ public class IdHelperServiceTest {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
subject.setDontCheckActiveTransactionForUnitTest(true);
|
myHelperSvc.setDontCheckActiveTransactionForUnitTest(true);
|
||||||
|
|
||||||
when(myStorageSettings.isDeleteEnabled()).thenReturn(true);
|
// lenient because some tests require this setup, and others do not
|
||||||
when(myStorageSettings.getResourceClientIdStrategy()).thenReturn(JpaStorageSettings.ClientIdStrategyEnum.ANY);
|
lenient().doReturn(true).when(myStorageSettings).isDeleteEnabled();
|
||||||
|
lenient().doReturn(JpaStorageSettings.ClientIdStrategyEnum.ANY).when(myStorageSettings).getResourceClientIdStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -81,7 +91,7 @@ public class IdHelperServiceTest {
|
||||||
// configure mock behaviour
|
// configure mock behaviour
|
||||||
when(myStorageSettings.isDeleteEnabled()).thenReturn(true);
|
when(myStorageSettings.isDeleteEnabled()).thenReturn(true);
|
||||||
|
|
||||||
final ResourceNotFoundException resourceNotFoundException = assertThrows(ResourceNotFoundException.class, () -> subject.resolveResourcePersistentIds(requestPartitionId, resourceType, ids, theExcludeDeleted));
|
final ResourceNotFoundException resourceNotFoundException = assertThrows(ResourceNotFoundException.class, () -> myHelperSvc.resolveResourcePersistentIds(requestPartitionId, resourceType, ids, theExcludeDeleted));
|
||||||
assertEquals("HAPI-2001: Resource Patient/123 is not known", resourceNotFoundException.getMessage());
|
assertEquals("HAPI-2001: Resource Patient/123 is not known", resourceNotFoundException.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,13 +112,14 @@ public class IdHelperServiceTest {
|
||||||
// configure mock behaviour
|
// configure mock behaviour
|
||||||
when(myStorageSettings.isDeleteEnabled()).thenReturn(false);
|
when(myStorageSettings.isDeleteEnabled()).thenReturn(false);
|
||||||
|
|
||||||
Map<String, JpaPid> actualIds = subject.resolveResourcePersistentIds(requestPartitionId, resourceType, ids, theExcludeDeleted);
|
Map<String, JpaPid> actualIds = myHelperSvc.resolveResourcePersistentIds(requestPartitionId, resourceType, ids, theExcludeDeleted);
|
||||||
|
|
||||||
//verifyResult
|
//verifyResult
|
||||||
assertFalse(actualIds.isEmpty());
|
assertFalse(actualIds.isEmpty());
|
||||||
assertNull(actualIds.get(ids.get(0)));
|
assertNull(actualIds.get(ids.get(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Root<ResourceTable> getMockedFrom() {
|
private Root<ResourceTable> getMockedFrom() {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Path<Object> path = mock(Path.class);
|
Path<Object> path = mock(Path.class);
|
||||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.mdm.config;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
|
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
|
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
|
||||||
|
@ -57,10 +58,18 @@ public class MdmSurvivorshipConfig {
|
||||||
@Autowired
|
@Autowired
|
||||||
private IIdHelperService<?> myIIdHelperService;
|
private IIdHelperService<?> myIIdHelperService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private HapiTransactionService myTransactionService;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public IMdmSurvivorshipService mdmSurvivorshipService() {
|
public IMdmSurvivorshipService mdmSurvivorshipService() {
|
||||||
return new MdmSurvivorshipSvcImpl(
|
return new MdmSurvivorshipSvcImpl(
|
||||||
myFhirContext, goldenResourceHelper(), myDaoRegistry, myMdmLinkQuerySvc, myIIdHelperService);
|
myFhirContext,
|
||||||
|
goldenResourceHelper(),
|
||||||
|
myDaoRegistry,
|
||||||
|
myMdmLinkQuerySvc,
|
||||||
|
myIIdHelperService,
|
||||||
|
myTransactionService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
@ -44,13 +44,17 @@ public class MdmModelConverterSvcImpl implements IMdmModelConverterSvc {
|
||||||
.toVersionless()
|
.toVersionless()
|
||||||
.getValue();
|
.getValue();
|
||||||
retVal.setSourceId(sourceId);
|
retVal.setSourceId(sourceId);
|
||||||
|
if (theLink.getSourcePersistenceId() != null) {
|
||||||
retVal.setSourcePid(theLink.getSourcePersistenceId());
|
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);
|
||||||
|
if (theLink.getGoldenResourcePersistenceId() != null) {
|
||||||
retVal.setGoldenPid(theLink.getGoldenResourcePersistenceId());
|
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());
|
||||||
|
|
|
@ -50,8 +50,15 @@ public class MdmModelConverterSvcImplTest extends BaseMdmR4Test {
|
||||||
|
|
||||||
ourLog.info("actualMdmLinkJson: {}", actualMdmLinkJson);
|
ourLog.info("actualMdmLinkJson: {}", actualMdmLinkJson);
|
||||||
|
|
||||||
MdmLinkJson exepctedMdmLinkJson = getExepctedMdmLinkJson(mdmLink.getGoldenResourcePersistenceId().getId(), mdmLink.getSourcePersistenceId().getId(), MdmMatchResultEnum.MATCH, MdmLinkSourceEnum.MANUAL, version, createTime, updateTime, isLinkCreatedResource, scoreRounded);
|
MdmLinkJson expectedMdmLinkJson = getExepctedMdmLinkJson(mdmLink.getGoldenResourcePersistenceId().getId(), mdmLink.getSourcePersistenceId().getId(), MdmMatchResultEnum.MATCH, MdmLinkSourceEnum.MANUAL, version, createTime, updateTime, isLinkCreatedResource, scoreRounded);
|
||||||
assertEquals(exepctedMdmLinkJson, actualMdmLinkJson);
|
assertEquals(expectedMdmLinkJson.getSourceId(), actualMdmLinkJson.getSourceId());
|
||||||
|
assertEquals(expectedMdmLinkJson.getGoldenResourceId(), actualMdmLinkJson.getGoldenResourceId());
|
||||||
|
assertEquals(expectedMdmLinkJson.getGoldenPid().getId(), actualMdmLinkJson.getGoldenPid().getId());
|
||||||
|
assertEquals(expectedMdmLinkJson.getSourcePid().getId(), actualMdmLinkJson.getSourcePid().getId());
|
||||||
|
assertEquals(expectedMdmLinkJson.getVector(), actualMdmLinkJson.getVector());
|
||||||
|
assertEquals(expectedMdmLinkJson.getScore(), actualMdmLinkJson.getScore());
|
||||||
|
assertEquals(expectedMdmLinkJson.getMatchResult(), actualMdmLinkJson.getMatchResult());
|
||||||
|
assertEquals(expectedMdmLinkJson.getLinkSource(), actualMdmLinkJson.getLinkSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package ca.uhn.fhir.jpa.mdm.svc;
|
package ca.uhn.fhir.jpa.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.dao.index.IdHelperService;
|
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
||||||
import ca.uhn.fhir.jpa.entity.MdmLink;
|
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
|
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||||
|
@ -21,6 +22,7 @@ import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
|
||||||
import ca.uhn.fhir.mdm.util.MdmPartitionHelper;
|
import ca.uhn.fhir.mdm.util.MdmPartitionHelper;
|
||||||
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
@ -31,20 +33,23 @@ import org.mockito.Mock;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageImpl;
|
||||||
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.time.temporal.ChronoUnit;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.doAnswer;
|
||||||
|
import static org.mockito.Mockito.doReturn;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.spy;
|
import static org.mockito.Mockito.spy;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
|
@ -69,12 +74,15 @@ public class MdmSurvivorshipSvcImplTest {
|
||||||
@Mock
|
@Mock
|
||||||
private MdmPartitionHelper myMdmPartitionHelper;
|
private MdmPartitionHelper myMdmPartitionHelper;
|
||||||
|
|
||||||
@Spy
|
@Mock
|
||||||
private IIdHelperService<?> myIIdHelperService = new IdHelperService();
|
private IdHelperService myIIdHelperService;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private IMdmLinkQuerySvc myMdmLinkQuerySvc;
|
private IMdmLinkQuerySvc myMdmLinkQuerySvc;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private HapiTransactionService myTransactionService;
|
||||||
|
|
||||||
private MdmSurvivorshipSvcImpl mySvc;
|
private MdmSurvivorshipSvcImpl mySvc;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
|
@ -91,7 +99,8 @@ public class MdmSurvivorshipSvcImplTest {
|
||||||
myGoldenResourceHelper,
|
myGoldenResourceHelper,
|
||||||
myDaoRegistry,
|
myDaoRegistry,
|
||||||
myMdmLinkQuerySvc,
|
myMdmLinkQuerySvc,
|
||||||
myIIdHelperService
|
myIIdHelperService,
|
||||||
|
myTransactionService
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +124,7 @@ public class MdmSurvivorshipSvcImplTest {
|
||||||
|
|
||||||
List<IBaseResource> resources = new ArrayList<>();
|
List<IBaseResource> resources = new ArrayList<>();
|
||||||
List<MdmLinkJson> links = new ArrayList<>();
|
List<MdmLinkJson> links = new ArrayList<>();
|
||||||
|
Map<String, IResourcePersistentId> sourceIdToPid = new HashMap<>();
|
||||||
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();
|
||||||
|
@ -137,24 +146,34 @@ public class MdmSurvivorshipSvcImplTest {
|
||||||
);
|
);
|
||||||
link.setSourcePid(JpaPid.fromId((long)i));
|
link.setSourcePid(JpaPid.fromId((long)i));
|
||||||
link.setGoldenPid(JpaPid.fromId((long)goldenId));
|
link.setGoldenPid(JpaPid.fromId((long)goldenId));
|
||||||
|
link.setSourceId(patient.getId());
|
||||||
|
link.setGoldenResourceId(goldenPatient.getId());
|
||||||
links.add(link);
|
links.add(link);
|
||||||
|
sourceIdToPid.put(patient.getId(), link.getSourcePid());
|
||||||
}
|
}
|
||||||
|
|
||||||
IFhirResourceDao resourceDao = mock(IFhirResourceDao.class);
|
IFhirResourceDao resourceDao = mock(IFhirResourceDao.class);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
|
IHapiTransactionService.IExecutionBuilder executionBuilder = mock(IHapiTransactionService.IExecutionBuilder.class);
|
||||||
|
when(myTransactionService.withRequest(any())).thenReturn(executionBuilder);
|
||||||
|
doAnswer(a -> {
|
||||||
|
Runnable callback = a.getArgument(0);
|
||||||
|
callback.run();
|
||||||
|
return 0;
|
||||||
|
}).when(executionBuilder).execute(any(Runnable.class));
|
||||||
when(myDaoRegistry.getResourceDao(eq("Patient")))
|
when(myDaoRegistry.getResourceDao(eq("Patient")))
|
||||||
.thenReturn(resourceDao);
|
.thenReturn(resourceDao);
|
||||||
AtomicInteger counter = new AtomicInteger();
|
AtomicInteger counter = new AtomicInteger();
|
||||||
when(resourceDao.readByPid(any()))
|
when(resourceDao.readByPid(any()))
|
||||||
.thenAnswer(params -> resources.get(counter.getAndIncrement()));
|
.thenAnswer(params -> resources.get(counter.getAndIncrement()));
|
||||||
Page<MdmLinkJson> linkPage = mock(Page.class);
|
Page<MdmLinkJson> linkPage = new PageImpl<>(links);
|
||||||
when(myMdmLinkQuerySvc.queryLinks(any(), any()))
|
when(myMdmLinkQuerySvc.queryLinks(any(), any()))
|
||||||
.thenReturn(linkPage);
|
.thenReturn(linkPage);
|
||||||
when(linkPage.get())
|
|
||||||
.thenReturn(links.stream());
|
|
||||||
when(myMdmSettings.getMdmRules())
|
when(myMdmSettings.getMdmRules())
|
||||||
.thenReturn(new MdmRulesJson());
|
.thenReturn(new MdmRulesJson());
|
||||||
|
doReturn(sourceIdToPid).when(myIIdHelperService)
|
||||||
|
.resolveResourcePersistentIds(any(RequestPartitionId.class), anyString(), any(List.class));
|
||||||
// we will return a non-empty list to reduce mocking
|
// we will return a non-empty list to reduce mocking
|
||||||
when(myEIDHelper.getExternalEid(any()))
|
when(myEIDHelper.getExternalEid(any()))
|
||||||
.thenReturn(Collections.singletonList(new CanonicalEID("example", "value", "use")));
|
.thenReturn(Collections.singletonList(new CanonicalEID("example", "value", "use")));
|
||||||
|
@ -178,19 +197,6 @@ public class MdmSurvivorshipSvcImplTest {
|
||||||
.update(eq(goldenPatientRebuilt), any(RequestDetails.class));
|
.update(eq(goldenPatientRebuilt), any(RequestDetails.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
private MdmLink createLinkWithoutUpdateDate(Patient theSource, Patient theGoldenResource) {
|
|
||||||
MdmLink link = new MdmLink();
|
|
||||||
link.setCreated(Date.from(
|
|
||||||
Instant.now().minus(2, ChronoUnit.DAYS)
|
|
||||||
));
|
|
||||||
link.setLinkSource(MdmLinkSourceEnum.AUTO);
|
|
||||||
link.setMatchResult(MdmMatchResultEnum.MATCH);
|
|
||||||
link.setSourcePersistenceId(JpaPid.fromId(theSource.getIdElement().getIdPartAsLong()));
|
|
||||||
link.setGoldenResourcePersistenceId(JpaPid.fromId(theGoldenResource.getIdElement().getIdPartAsLong()));
|
|
||||||
|
|
||||||
return link;
|
|
||||||
}
|
|
||||||
|
|
||||||
private MdmTransactionContext createTransactionContext() {
|
private MdmTransactionContext createTransactionContext() {
|
||||||
MdmTransactionContext context = new MdmTransactionContext();
|
MdmTransactionContext context = new MdmTransactionContext();
|
||||||
context.setRestOperation(MdmTransactionContext.OperationType.UPDATE_LINK);
|
context.setRestOperation(MdmTransactionContext.OperationType.UPDATE_LINK);
|
||||||
|
|
|
@ -23,6 +23,7 @@ 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 ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
@ -45,13 +46,13 @@ public class MdmLinkJson implements IModelJson {
|
||||||
/**
|
/**
|
||||||
* Golden resource PID
|
* Golden resource PID
|
||||||
*/
|
*/
|
||||||
@JsonProperty("goldenPid")
|
@JsonIgnore
|
||||||
private IResourcePersistentId<?> myGoldenPid;
|
private IResourcePersistentId<?> myGoldenPid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Source PID
|
* Source PID
|
||||||
*/
|
*/
|
||||||
@JsonProperty("sourcePid")
|
@JsonIgnore
|
||||||
private IResourcePersistentId<?> mySourcePid;
|
private IResourcePersistentId<?> mySourcePid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -24,6 +24,7 @@ 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;
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
|
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
|
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
|
||||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||||
|
@ -36,12 +37,15 @@ 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;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -58,17 +62,21 @@ public class MdmSurvivorshipSvcImpl implements IMdmSurvivorshipService {
|
||||||
|
|
||||||
private final IIdHelperService<?> myIIdHelperService;
|
private final IIdHelperService<?> myIIdHelperService;
|
||||||
|
|
||||||
|
private final HapiTransactionService myTransactionService;
|
||||||
|
|
||||||
public MdmSurvivorshipSvcImpl(
|
public MdmSurvivorshipSvcImpl(
|
||||||
FhirContext theFhirContext,
|
FhirContext theFhirContext,
|
||||||
GoldenResourceHelper theResourceHelper,
|
GoldenResourceHelper theResourceHelper,
|
||||||
DaoRegistry theDaoRegistry,
|
DaoRegistry theDaoRegistry,
|
||||||
IMdmLinkQuerySvc theLinkQuerySvc,
|
IMdmLinkQuerySvc theLinkQuerySvc,
|
||||||
IIdHelperService<?> theIIdHelperService) {
|
IIdHelperService<?> theIIdHelperService,
|
||||||
|
HapiTransactionService theHapiTransactionService) {
|
||||||
myFhirContext = theFhirContext;
|
myFhirContext = theFhirContext;
|
||||||
myGoldenResourceHelper = theResourceHelper;
|
myGoldenResourceHelper = theResourceHelper;
|
||||||
myDaoRegistry = theDaoRegistry;
|
myDaoRegistry = theDaoRegistry;
|
||||||
myMdmLinkQuerySvc = theLinkQuerySvc;
|
myMdmLinkQuerySvc = theLinkQuerySvc;
|
||||||
myIIdHelperService = theIIdHelperService;
|
myIIdHelperService = theIIdHelperService;
|
||||||
|
myTransactionService = theHapiTransactionService;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this logic is custom in smile vs hapi
|
// this logic is custom in smile vs hapi
|
||||||
|
@ -132,6 +140,7 @@ public class MdmSurvivorshipSvcImpl implements IMdmSurvivorshipService {
|
||||||
return (T) toSave;
|
return (T) toSave;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
private Stream<IBaseResource> getMatchedSourceIdsByLinkUpdateDate(
|
private Stream<IBaseResource> getMatchedSourceIdsByLinkUpdateDate(
|
||||||
IBaseResource theGoldenResource, MdmTransactionContext theMdmTransactionContext) {
|
IBaseResource theGoldenResource, MdmTransactionContext theMdmTransactionContext) {
|
||||||
String resourceType = theGoldenResource.fhirType();
|
String resourceType = theGoldenResource.fhirType();
|
||||||
|
@ -143,18 +152,27 @@ public class MdmSurvivorshipSvcImpl implements IMdmSurvivorshipService {
|
||||||
searchParameters.setMatchResult(MdmMatchResultEnum.MATCH);
|
searchParameters.setMatchResult(MdmMatchResultEnum.MATCH);
|
||||||
Page<MdmLinkJson> linksQuery = myMdmLinkQuerySvc.queryLinks(searchParameters, theMdmTransactionContext);
|
Page<MdmLinkJson> linksQuery = myMdmLinkQuerySvc.queryLinks(searchParameters, theMdmTransactionContext);
|
||||||
|
|
||||||
return linksQuery.get().map(link -> {
|
// we want it ordered
|
||||||
IResourcePersistentId<?> pid = link.getSourcePid();
|
List<String> sourceIds = new ArrayList<>();
|
||||||
return dao.readByPid(pid);
|
linksQuery.forEach(link -> {
|
||||||
|
sourceIds.add(link.getSourceId());
|
||||||
|
});
|
||||||
|
Map<String, IResourcePersistentId> sourceIdToPid = new HashMap<>();
|
||||||
|
if (!sourceIds.isEmpty()) {
|
||||||
|
// we cannot call resolveResourcePersistentIds if there are no ids to call it with
|
||||||
|
myTransactionService
|
||||||
|
.withRequest(new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.allPartitions()))
|
||||||
|
.execute(() -> {
|
||||||
|
Map<String, ? extends IResourcePersistentId> ids =
|
||||||
|
myIIdHelperService.resolveResourcePersistentIds(
|
||||||
|
RequestPartitionId.allPartitions(), resourceType, sourceIds);
|
||||||
|
sourceIdToPid.putAll(ids);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private IResourcePersistentId<?> getResourcePID(String theId, String theResourceType) {
|
return sourceIds.stream().map(id -> {
|
||||||
return myIIdHelperService.newPidFromStringIdAndResourceName(theId, theResourceType);
|
IResourcePersistentId<?> pid = sourceIdToPid.get(id);
|
||||||
}
|
return dao.readByPid(pid);
|
||||||
|
});
|
||||||
private boolean isNumericOrUuid(String theLongCandidate) {
|
|
||||||
return StringUtils.isNumeric(theLongCandidate)
|
|
||||||
|| IS_UUID.matcher(theLongCandidate).matches();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
package ca.uhn.fhir.mdm.model.mdmevents;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||||
|
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||||
|
import ca.uhn.fhir.rest.api.server.storage.BaseResourcePersistentId;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
|
public class MdmLinkJsonTest {
|
||||||
|
|
||||||
|
private static class TestPID<T> extends BaseResourcePersistentId<T> {
|
||||||
|
|
||||||
|
private final T myId;
|
||||||
|
|
||||||
|
protected TestPID(String theResourceType, T theId) {
|
||||||
|
super(theResourceType);
|
||||||
|
myId = theId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T getId() {
|
||||||
|
return myId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ObjectMapper myObjectMapper = new ObjectMapper();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void serializeDeserialize_longId_works() throws JsonProcessingException {
|
||||||
|
// setup
|
||||||
|
MdmLinkJson json = createLinkJson();
|
||||||
|
TestPID<Long> golden = new TestPID<>("Patient", 1L);
|
||||||
|
golden.setAssociatedResourceId(new IdType("Patient/1"));
|
||||||
|
golden.setVersion(1L);
|
||||||
|
TestPID<Long> source = new TestPID<>("Patient", 2L);
|
||||||
|
source.setAssociatedResourceId(new IdType("Patient/2"));
|
||||||
|
source.setVersion(1L);
|
||||||
|
json.setGoldenPid(golden);
|
||||||
|
json.setSourcePid(source);
|
||||||
|
|
||||||
|
// test
|
||||||
|
String strVal = myObjectMapper.writeValueAsString(json);
|
||||||
|
assertFalse(isBlank(strVal));
|
||||||
|
|
||||||
|
MdmLinkJson deserialized = myObjectMapper.readValue(strVal, MdmLinkJson.class);
|
||||||
|
assertNotNull(deserialized);
|
||||||
|
assertNull(deserialized.getSourcePid());
|
||||||
|
assertNull(deserialized.getGoldenPid());
|
||||||
|
}
|
||||||
|
|
||||||
|
private MdmLinkJson createLinkJson() {
|
||||||
|
MdmLinkJson json = new MdmLinkJson();
|
||||||
|
json.setGoldenResourceId("Patient/1");
|
||||||
|
json.setSourceId("Patient/2");
|
||||||
|
json.setMatchResult(MdmMatchResultEnum.MATCH);
|
||||||
|
json.setLinkSource(MdmLinkSourceEnum.MANUAL);
|
||||||
|
json.setCreated(new Date());
|
||||||
|
json.setUpdated(new Date());
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.rest.api.server.storage;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
||||||
public interface IResourcePersistentId<T> {
|
public interface IResourcePersistentId<T> {
|
||||||
|
|
||||||
IResourcePersistentId NOT_FOUND = new NotFoundPid();
|
IResourcePersistentId NOT_FOUND = new NotFoundPid();
|
||||||
|
|
||||||
IIdType getAssociatedResourceId();
|
IIdType getAssociatedResourceId();
|
||||||
|
@ -31,6 +32,7 @@ public interface IResourcePersistentId<T> {
|
||||||
T getId();
|
T getId();
|
||||||
|
|
||||||
Long getVersion();
|
Long getVersion();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param theVersion This should only be populated if a specific version is needed. If you want the current version,
|
* @param theVersion This should only be populated if a specific version is needed. If you want the current version,
|
||||||
* leave this as <code>null</code>
|
* leave this as <code>null</code>
|
||||||
|
|
Loading…
Reference in New Issue