2878 mdm mongo support (#3748)

* small refactor

* refactored MDM module to use iterface IMDMLink, refactored MDMLink to use ResourcePersistenceId wrapper rather than pid as long

* removing IJpaIdHelperService and refactor IIdHelperService

* fixed bugs for GoldenResourceMergerSvcImpl and FindCandidateByExampleSvc

* changes to IIdHelperService

* move MdmSearchParamSvc and MdmSubmitSvcImpl out of jpaserver-mdm

* moved JpaResourceLoader to hapi-fhir-storage, renamed to ResourceLoaderImpl

* added error Msg code, removed Fixme

* fixed error code, update last used code in Msg.java to 2083

* fixed accidentally throwing unprocessableentityException

* added MdmLinkExpandSvc interface

* build adding license to files

* MdmLinkdao refactor

* fix build

* mdm config refactoring

* MdmStorageInterceptor and IExpungeEverythingService changes

* fix bug where a pid is converted to ResourcePersistenceId twice

* minor refactor to IMdmLink, change id from long to ResourcePersistenceId

* changed PageImpl to Page interface

* refactor MdmSearchExpandingInterceptor to use interface

* fixed missed refactor where the resourcePersistenceId is still assumed to be long

* resolve test failures resulting from merging master

* changed conflicting exception code

* fixed issue with bulk export wrapping resourcePid inside resourcePersistenceId

* added IMdmLinkImpl to MdmSettings

* fixed missing import in IdHelperService from merging master

* fixed MdmLinkDaoSvcTest importing wrong MdmLinkTuple

* restored JpaIdHelperService and added changelog

* modified msg.code to non-duplicate

* code review changes

* refactored some bulk export batch 2 files to accomodate change in beans being exported

* fixed jpa bulk export failing tests

* removed duplicate bean declaration of MdmLinkImplFactory in BaseMdmR4Test

* merged master and bump version to pre25

* extracted expungeEverythingByType to IExpungeEverythingService

* fixed wiring issue

* messed up merging pom with master

* fixed broken changelog

Co-authored-by: Long Ma <long@smilecdr.com>
Co-authored-by: Samuel Lee <samuel.lee@smilecdr.com>
Co-authored-by: Ken Stevens <ken@smilecdr.com>
This commit is contained in:
longma1 2022-07-29 08:58:40 -06:00 committed by GitHub
parent 8346c0263b
commit f933ff3d9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
176 changed files with 1587 additions and 771 deletions

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -25,7 +25,7 @@ public final class Msg {
/**
* IMPORTANT: Please update the following comment after you add a new code
* Last code value: 2106
* Last code value: 2109
*/
private Msg() {}

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -3,14 +3,14 @@
<modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-bom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<packaging>pom</packaging>
<name>HAPI FHIR BOM</name>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-cli</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -0,0 +1,4 @@
---
type: add
issue: 2878
title: "Refactored mdm classes to use ResourcePersistenceId rather than prematurely converting to longs"

View File

@ -11,7 +11,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -4,7 +4,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -29,13 +29,13 @@ import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.api.model.PersistentIdToForcedIdMap;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.bulk.export.api.IBulkExportProcessor;
import ca.uhn.fhir.jpa.bulk.export.model.ExportPIDIteratorParameters;
import ca.uhn.fhir.jpa.dao.IResultIterator;
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkDao;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.dao.mdm.MdmExpansionCacheSvc;
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
@ -43,6 +43,8 @@ import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.util.QueryChunker;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
import ca.uhn.fhir.mdm.model.MdmPidTuple;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.server.bulk.BulkDataExportOptions;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
@ -101,9 +103,6 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor {
@Autowired
private IMdmLinkDao myMdmLinkDao;
@Autowired
private IJpaIdHelperService myJpaIdHelperService;
@Autowired
private MdmExpansionCacheSvc myMdmExpansionCacheSvc;
@ -259,25 +258,23 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor {
private Iterator<ResourcePersistentId> getExpandedPatientIterator(ExportPIDIteratorParameters theParameters) {
List<String> members = getMembers(theParameters.getGroupId());
List<IIdType> ids = members.stream().map(member -> new IdDt("Patient/" + member)).collect(Collectors.toList());
List<Long> pidsOrThrowException = myJpaIdHelperService.getPidsOrThrowException(ids);
Set<Long> patientPidsToExport = new HashSet<>(pidsOrThrowException);
// Are bulk exports partition aware or care about partition at all? This does
List<ResourcePersistentId> pidsOrThrowException = myIdHelperService.getPidsOrThrowException(RequestPartitionId.allPartitions(), ids);
Set<ResourcePersistentId> patientPidsToExport = new HashSet<>(pidsOrThrowException);
if (theParameters.isExpandMdm()) {
SystemRequestDetails srd = SystemRequestDetails.newSystemRequestAllPartitions();
IBaseResource group = myDaoRegistry.getResourceDao("Group").read(new IdDt(theParameters.getGroupId()), srd);
Long pidOrNull = myJpaIdHelperService.getPidOrNull(group);
List<IMdmLinkDao.MdmPidTuple> goldenPidSourcePidTuple = myMdmLinkDao.expandPidsFromGroupPidGivenMatchResult(pidOrNull, MdmMatchResultEnum.MATCH);
ResourcePersistentId pidOrNull = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), group);
List<MdmPidTuple> goldenPidSourcePidTuple = myMdmLinkDao.expandPidsFromGroupPidGivenMatchResult(pidOrNull, MdmMatchResultEnum.MATCH);
goldenPidSourcePidTuple.forEach(tuple -> {
patientPidsToExport.add(tuple.getGoldenPid());
patientPidsToExport.add(tuple.getSourcePid());
});
populateMdmResourceCache(goldenPidSourcePidTuple);
}
List<ResourcePersistentId> resourcePersistentIds = patientPidsToExport
.stream()
.map(ResourcePersistentId::new)
.collect(Collectors.toList());
return resourcePersistentIds.iterator();
return patientPidsToExport.iterator();
}
/**
@ -295,7 +292,7 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor {
/**
* @param thePidTuples
*/
private void populateMdmResourceCache(List<IMdmLinkDao.MdmPidTuple> thePidTuples) {
private void populateMdmResourceCache(List<MdmPidTuple> thePidTuples) {
if (myMdmExpansionCacheSvc.hasBeenPopulated()) {
return;
}
@ -304,7 +301,7 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor {
// patient/gold-1 -> [patient/1, patient/2]
// patient/gold-2 -> [patient/3, patient/4]
//}
Map<Long, Set<Long>> goldenResourceToSourcePidMap = new HashMap<>();
Map<ResourcePersistentId, Set<ResourcePersistentId>> goldenResourceToSourcePidMap = new HashMap<>();
extract(thePidTuples, goldenResourceToSourcePidMap);
//Next, lets convert it to an inverted index for fast lookup
@ -317,11 +314,9 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor {
Map<String, String> sourceResourceIdToGoldenResourceIdMap = new HashMap<>();
goldenResourceToSourcePidMap.forEach((key, value) -> {
String goldenResourceId = myIdHelperService.translatePidIdToForcedIdWithCache(new ResourcePersistentId(key)).orElse(key.toString());
Map<Long, Optional<String>> pidsToForcedIds = myIdHelperService.translatePidsToForcedIds(value);
PersistentIdToForcedIdMap pidsToForcedIds = myIdHelperService.translatePidsToForcedIds(value);
Set<String> sourceResourceIds = pidsToForcedIds.entrySet().stream()
.map(ent -> ent.getValue().isPresent() ? ent.getValue().get() : ent.getKey().toString())
.collect(Collectors.toSet());
Set<String> sourceResourceIds = pidsToForcedIds.getResolvedResourceIds();
sourceResourceIds
.forEach(sourceResourceId -> sourceResourceIdToGoldenResourceIdMap.put(sourceResourceId, goldenResourceId));
@ -331,10 +326,10 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor {
myMdmExpansionCacheSvc.setCacheContents(sourceResourceIdToGoldenResourceIdMap);
}
private void extract(List<IMdmLinkDao.MdmPidTuple> theGoldenPidTargetPidTuples, Map<Long, Set<Long>> theGoldenResourceToSourcePidMap) {
for (IMdmLinkDao.MdmPidTuple goldenPidTargetPidTuple : theGoldenPidTargetPidTuples) {
Long goldenPid = goldenPidTargetPidTuple.getGoldenPid();
Long sourcePid = goldenPidTargetPidTuple.getSourcePid();
private void extract(List<MdmPidTuple> theGoldenPidTargetPidTuples, Map<ResourcePersistentId, Set<ResourcePersistentId>> theGoldenResourceToSourcePidMap) {
for (MdmPidTuple goldenPidTargetPidTuple : theGoldenPidTargetPidTuples) {
ResourcePersistentId goldenPid = goldenPidTargetPidTuple.getGoldenPid();
ResourcePersistentId sourcePid = goldenPidTargetPidTuple.getSourcePid();
theGoldenResourceToSourcePidMap.computeIfAbsent(goldenPid, key -> new HashSet<>()).add(sourcePid);
}
}
@ -416,28 +411,25 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor {
Set<String> expandedIds = new HashSet<>();
SystemRequestDetails requestDetails = SystemRequestDetails.newSystemRequestAllPartitions();
IBaseResource group = myDaoRegistry.getResourceDao("Group").read(new IdDt(theParams.getGroupId()), requestDetails);
Long pidOrNull = myJpaIdHelperService.getPidOrNull(group);
ResourcePersistentId pidOrNull = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), group);
//Attempt to perform MDM Expansion of membership
if (theParams.isExpandMdm()) {
List<IMdmLinkDao.MdmPidTuple> goldenPidTargetPidTuples = myMdmLinkDao.expandPidsFromGroupPidGivenMatchResult(pidOrNull, MdmMatchResultEnum.MATCH);
List<MdmPidTuple> goldenPidTargetPidTuples = myMdmLinkDao.expandPidsFromGroupPidGivenMatchResult(pidOrNull, MdmMatchResultEnum.MATCH);
//Now lets translate these pids into resource IDs
Set<Long> uniquePids = new HashSet<>();
Set<ResourcePersistentId> uniquePids = new HashSet<>();
goldenPidTargetPidTuples.forEach(tuple -> {
uniquePids.add(tuple.getGoldenPid());
uniquePids.add(tuple.getSourcePid());
});
Map<Long, Optional<String>> pidToForcedIdMap = myIdHelperService.translatePidsToForcedIds(uniquePids);
PersistentIdToForcedIdMap pidToForcedIdMap = myIdHelperService.translatePidsToForcedIds(uniquePids);
Map<Long, Set<Long>> goldenResourceToSourcePidMap = new HashMap<>();
Map<ResourcePersistentId, Set<ResourcePersistentId>> goldenResourceToSourcePidMap = new HashMap<>();
extract(goldenPidTargetPidTuples, goldenResourceToSourcePidMap);
populateMdmResourceCache(goldenPidTargetPidTuples);
//If the result of the translation is an empty optional, it means there is no forced id, and we can use the PID as the resource ID.
Set<String> resolvedResourceIds = pidToForcedIdMap.entrySet().stream()
.map(entry -> entry.getValue().isPresent() ? entry.getValue().get() : entry.getKey().toString())
.collect(Collectors.toSet());
Set<String> resolvedResourceIds = pidToForcedIdMap.getResolvedResourceIds();
expandedIds.addAll(resolvedResourceIds);
}

View File

@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.config;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.svc.IBatch2DaoSvc;
import ca.uhn.fhir.jpa.api.svc.IDeleteExpungeSvc;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.dao.data.IResourceLinkDao;
import ca.uhn.fhir.jpa.dao.expunge.ResourceTableFKProvider;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
@ -46,7 +47,7 @@ public class Batch2SupportConfig {
}
@Bean
DeleteExpungeSqlBuilder deleteExpungeSqlBuilder(ResourceTableFKProvider theResourceTableFKProvider, DaoConfig theDaoConfig, IJpaIdHelperService theIdHelper, IResourceLinkDao theResourceLinkDao) {
DeleteExpungeSqlBuilder deleteExpungeSqlBuilder(ResourceTableFKProvider theResourceTableFKProvider, DaoConfig theDaoConfig, IIdHelperService theIdHelper, IResourceLinkDao theResourceLinkDao) {
return new DeleteExpungeSqlBuilder(theResourceTableFKProvider, theDaoConfig, theIdHelper, theResourceLinkDao);
}
}

View File

@ -27,6 +27,7 @@ import ca.uhn.fhir.jpa.config.util.ResourceCountCacheUtil;
import ca.uhn.fhir.jpa.config.util.ValidationSupportConfigUtil;
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
import ca.uhn.fhir.jpa.dao.mdm.MdmLinkDaoJpaImpl;
import ca.uhn.fhir.jpa.dao.search.HSearchSortHelperImpl;
import ca.uhn.fhir.jpa.dao.search.IHSearchSortHelper;
import ca.uhn.fhir.jpa.provider.DaoRegistryResourceSupportedSvc;
@ -35,6 +36,7 @@ import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
import ca.uhn.fhir.jpa.util.ResourceCountCache;
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChain;
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
import ca.uhn.fhir.rest.api.IResourceSupportedSvc;
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
@ -92,4 +94,9 @@ public class HapiJpaConfig {
public ResourceCountCache resourceCountsCache(IFhirSystemDao<?, ?> theSystemDao) {
return ResourceCountCacheUtil.newResourceCountCache(theSystemDao);
}
@Bean
public static IMdmLinkDao mdmLinkDao(){
return new MdmLinkDaoJpaImpl();
}
}

View File

@ -10,6 +10,7 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IDao;
import ca.uhn.fhir.jpa.api.model.ExpungeOptions;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.api.svc.ISearchCoordinatorSvc;
import ca.uhn.fhir.jpa.batch.BatchJobsConfig;
import ca.uhn.fhir.jpa.batch.config.BatchConstants;
@ -39,10 +40,8 @@ import ca.uhn.fhir.jpa.dao.expunge.ResourceExpungeService;
import ca.uhn.fhir.jpa.dao.expunge.ResourceTableFKProvider;
import ca.uhn.fhir.jpa.dao.index.DaoResourceLinkResolver;
import ca.uhn.fhir.jpa.dao.index.DaoSearchParamSynchronizer;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.dao.index.JpaIdHelperService;
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.dao.index.SearchParamWithInlineReferencesExtractor;
import ca.uhn.fhir.jpa.dao.mdm.MdmLinkExpandSvc;
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
import ca.uhn.fhir.jpa.delete.DeleteConflictFinderService;
import ca.uhn.fhir.jpa.delete.DeleteConflictService;
@ -122,8 +121,9 @@ import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc;
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
import ca.uhn.fhir.jpa.term.config.TermCodeSystemConfig;
import ca.uhn.fhir.jpa.util.MemoryCacheService;
import ca.uhn.fhir.jpa.validation.JpaResourceLoader;
import ca.uhn.fhir.jpa.validation.ResourceLoaderImpl;
import ca.uhn.fhir.jpa.validation.ValidationSettings;
import ca.uhn.fhir.mdm.svc.MdmLinkExpandSvc;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.storage.IDeleteExpungeJobSubmitter;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
@ -137,6 +137,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
import org.hl7.fhir.utilities.npm.PackageClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@ -617,7 +618,7 @@ public class JpaConfig {
return new SearchQueryExecutor(theGeneratedSql, theMaxResultsToFetch);
}
@Bean(name = SEARCH_BUILDER)
@Bean(name = ISearchBuilder.SEARCH_BUILDER_BEAN_NAME)
@Scope("prototype")
public ISearchBuilder newSearchBuilder(IDao theDao, String theResourceName, Class<? extends IBaseResource> theResourceType, DaoConfig theDaoConfig) {
return new SearchBuilder(theDao, theResourceName, theResourceType);
@ -636,8 +637,8 @@ public class JpaConfig {
}
@Bean
public IJpaIdHelperService jpaIdHelperService() {
return new JpaIdHelperService();
public IIdHelperService idHelperService () {
return new IdHelperService();
}
@Bean
@ -717,8 +718,8 @@ public class JpaConfig {
}
@Bean
public JpaResourceLoader jpaResourceLoader() {
return new JpaResourceLoader();
public ResourceLoaderImpl jpaResourceLoader() {
return new ResourceLoaderImpl();
}
@Bean

View File

@ -24,9 +24,11 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.model.PersistentIdToForcedIdMap;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimaps;
@ -47,8 +49,9 @@ import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static ca.uhn.fhir.jpa.search.builder.SearchBuilder.toPredicateArray;
@ -121,15 +124,16 @@ public class HistoryBuilder {
List<ResourceHistoryTable> tables = query.getResultList();
if (tables.size() > 0) {
ImmutableListMultimap<Long, ResourceHistoryTable> resourceIdToHistoryEntries = Multimaps.index(tables, ResourceHistoryTable::getResourceId);
Map<Long, Optional<String>> pidToForcedId = myIdHelperService.translatePidsToForcedIds(resourceIdToHistoryEntries.keySet());
ourLog.trace("Translated IDs: {}", pidToForcedId);
Set<ResourcePersistentId> pids = resourceIdToHistoryEntries.keySet().stream().map(t-> new ResourcePersistentId(t)).collect(Collectors.toSet());
PersistentIdToForcedIdMap pidToForcedId = myIdHelperService.translatePidsToForcedIds(pids);
ourLog.trace("Translated IDs: {}", pidToForcedId.getResourcePersistentIdOptionalMap());
for (Long nextResourceId : resourceIdToHistoryEntries.keySet()) {
List<ResourceHistoryTable> historyTables = resourceIdToHistoryEntries.get(nextResourceId);
String resourceId;
Optional<String> forcedId = pidToForcedId.get(nextResourceId);
Optional<String> forcedId = pidToForcedId.get(new ResourcePersistentId(nextResourceId));
if (forcedId.isPresent()) {
resourceId = forcedId.get();
} else {

View File

@ -34,7 +34,7 @@ import java.util.List;
import java.util.Optional;
@Repository
public interface IMdmLinkDao extends JpaRepository<MdmLink, Long>, IHapiFhirJpaRepository {
public interface IMdmLinkJpaRepository extends JpaRepository<MdmLink, Long>, IHapiFhirJpaRepository {
@Modifying
@Query("DELETE FROM MdmLink f WHERE myGoldenResourcePid = :pid OR mySourcePid = :pid")
int deleteWithAnyReferenceToPid(@Param("pid") Long thePid);

View File

@ -51,11 +51,11 @@ public class FhirResourceDaoQuestionnaireResponseDstu3 extends BaseHapiFhirResou
// }
// }
//
// public class JpaResourceLoader implements IResourceLoader {
// public class ResourceLoaderImpl implements IResourceLoader {
//
// private RequestDetails myRequestDetails;
//
// public JpaResourceLoader(RequestDetails theRequestDetails) {
// public ResourceLoaderImpl(RequestDetails theRequestDetails) {
// super();
// myRequestDetails = theRequestDetails;
// }

View File

@ -27,6 +27,7 @@ import ca.uhn.fhir.jpa.entity.Batch2JobInstanceEntity;
import ca.uhn.fhir.jpa.entity.Batch2WorkChunkEntity;
import ca.uhn.fhir.jpa.entity.BulkImportJobEntity;
import ca.uhn.fhir.jpa.entity.BulkImportJobFileEntity;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.entity.PartitionEntity;
import ca.uhn.fhir.jpa.entity.Search;
import ca.uhn.fhir.jpa.entity.SearchInclude;
@ -236,12 +237,18 @@ public class ExpungeEverythingService implements IExpungeEverythingService {
return outcome;
}
@Override
public int expungeEverythingByType(Class<?> theEntityType) {
int result = expungeEverythingByTypeWithoutPurging(theEntityType);
purgeAllCaches();
return result;
}
@Override
public int expungeEverythingMdmLinks() {
return expungeEverythingByType(MdmLink.class);
}
private int doExpungeEverythingQuery(String theQuery) {
StopWatch sw = new StopWatch();
int outcome = myEntityManager.createQuery(theQuery).executeUpdate();

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.dao.index;
*/
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
@ -76,7 +77,7 @@ public interface IJpaIdHelperService extends IIdHelperService {
Long getPidOrThrowException(IIdType theId);
@Nonnull
Long getPidOrThrowException(@Nonnull IAnyResource theResource);
ResourcePersistentId getPidOrThrowException(@Nonnull IAnyResource theResource);
IIdType resourceIdFromPidOrThrowException(Long thePid);
@ -91,6 +92,6 @@ public interface IJpaIdHelperService extends IIdHelperService {
* @param thePids The Set of pids you would like to resolve to external FHIR Resource IDs.
* @return A Set of strings representing the FHIR IDs of the pids.
*/
Set<String> translatePidsToFhirResourceIds(Set<Long> thePids);
Set<String> translatePidsToFhirResourceIds(Set<ResourcePersistentId> thePids);
}

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.model.PersistentIdToForcedIdMap;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
@ -31,6 +32,7 @@ import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
import ca.uhn.fhir.jpa.model.cross.ResourceLookup;
import ca.uhn.fhir.jpa.model.entity.ForcedId;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
import ca.uhn.fhir.jpa.util.MemoryCacheService;
import ca.uhn.fhir.jpa.util.QueryChunker;
@ -44,6 +46,8 @@ import com.google.common.collect.ListMultimap;
import com.google.common.collect.MultimapBuilder;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.IdType;
import org.springframework.beans.factory.annotation.Autowired;
@ -589,9 +593,9 @@ public class IdHelperService implements IIdHelperService {
}
@Override
public Map<Long, Optional<String>> translatePidsToForcedIds(Set<Long> thePids) {
public PersistentIdToForcedIdMap translatePidsToForcedIds(Set<ResourcePersistentId> theResourceIds) {
assert myDontCheckActiveTransactionForUnitTest || TransactionSynchronizationManager.isSynchronizationActive();
Set<Long> thePids = theResourceIds.stream().map(t -> t.getIdAsLong()).collect(Collectors.toSet());
Map<Long, Optional<String>> retVal = new HashMap<>(myMemoryCacheService.getAllPresent(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, thePids));
List<Long> remainingPids = thePids
@ -618,8 +622,13 @@ public class IdHelperService implements IIdHelperService {
retVal.put(nextResourcePid, Optional.empty());
myMemoryCacheService.putAfterCommit(MemoryCacheService.CacheEnum.PID_TO_FORCED_ID, nextResourcePid, Optional.empty());
}
return retVal;
Map<ResourcePersistentId, Optional<String>> convertRetVal = new HashMap<>();
retVal.forEach(
(k, v) -> {
convertRetVal.put(new ResourcePersistentId(k), v);
}
);
return new PersistentIdToForcedIdMap(convertRetVal);
}
/**
@ -664,4 +673,73 @@ public class IdHelperService implements IIdHelperService {
public static boolean isValidPid(String theIdPart) {
return StringUtils.isNumeric(theIdPart);
}
@Override
@Nonnull
public List<ResourcePersistentId> getPidsOrThrowException(@Nonnull RequestPartitionId theRequestPartitionId, List<IIdType> theIds) {
List<ResourcePersistentId> resourcePersistentIds = resolveResourcePersistentIdsWithCache(theRequestPartitionId, theIds);
return resourcePersistentIds;
}
@Override
@Nullable
public ResourcePersistentId getPidOrNull(@Nonnull RequestPartitionId theRequestPartitionId, IBaseResource theResource) {
ResourcePersistentId retVal = new ResourcePersistentId(theResource.getUserData(RESOURCE_PID));
if (retVal.getId() == null) {
IIdType id = theResource.getIdElement();
try {
retVal = resolveResourcePersistentIds(theRequestPartitionId, id.getResourceType(), id.getIdPart());
} catch (ResourceNotFoundException e) {
return null;
}
}
return retVal;
}
@Override
@Nonnull
public ResourcePersistentId getPidOrThrowException(@Nonnull RequestPartitionId theRequestPartitionId, IIdType theId) {
List<IIdType> ids = Collections.singletonList(theId);
List<ResourcePersistentId> resourcePersistentIds = resolveResourcePersistentIdsWithCache(theRequestPartitionId, ids);
return resourcePersistentIds.get(0);
}
@Override
@Nonnull
public ResourcePersistentId getPidOrThrowException(@Nonnull IAnyResource theResource) {
Object theResourcePID = theResource.getUserData(RESOURCE_PID);
if (theResourcePID == null) {
throw new IllegalStateException(Msg.code(2108) + String.format("Unable to find %s in the user data for %s with ID %s", RESOURCE_PID, theResource, theResource.getId()));
}
return new ResourcePersistentId(theResourcePID);
}
@Override
public IIdType resourceIdFromPidOrThrowException(ResourcePersistentId thePid, String theResourceType) {
Optional<ResourceTable> optionalResource = myResourceTableDao.findById(thePid.getIdAsLong());
if (!optionalResource.isPresent()) {
throw new ResourceNotFoundException(Msg.code(2107) + "Requested resource not found");
}
return optionalResource.get().getIdDt().toVersionless();
}
/**
* Given a set of PIDs, return a set of public FHIR Resource IDs.
* This function will resolve a forced ID if it resolves, and if it fails to resolve to a forced it, will just return the pid
* Example:
* Let's say we have Patient/1(pid == 1), Patient/pat1 (pid == 2), Patient/3 (pid == 3), their pids would resolve as follows:
* <p>
* [1,2,3] -> ["1","pat1","3"]
*
* @param thePids The Set of pids you would like to resolve to external FHIR Resource IDs.
* @return A Set of strings representing the FHIR IDs of the pids.
*/
@Override
public Set<String> translatePidsToFhirResourceIds(Set<ResourcePersistentId> thePids) {
assert TransactionSynchronizationManager.isSynchronizationActive();
PersistentIdToForcedIdMap pidToForcedIdMap = translatePidsToForcedIds(thePids);
return pidToForcedIdMap.getResolvedResourceIds();
}
}

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.dao.index;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.model.PersistentIdToForcedIdMap;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
@ -37,13 +38,10 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static ca.uhn.fhir.jpa.dao.index.IdHelperService.RESOURCE_PID;
/**
* See {@link IJpaIdHelperService} for an explanation of this class.
*/
@ -104,13 +102,13 @@ public class JpaIdHelperService extends IdHelperService implements IJpaIdHelperS
@Override
@Nonnull
public Long getPidOrThrowException(@Nonnull IAnyResource theResource) {
public ResourcePersistentId getPidOrThrowException(@Nonnull IAnyResource theResource) {
Long retVal = (Long) theResource.getUserData(RESOURCE_PID);
if (retVal == null) {
throw new IllegalStateException(Msg.code(1102) + String.format("Unable to find %s in the user data for %s with ID %s", RESOURCE_PID, theResource, theResource.getId())
);
}
return retVal;
return new ResourcePersistentId(retVal);
}
@Override
@ -134,18 +132,12 @@ public class JpaIdHelperService extends IdHelperService implements IJpaIdHelperS
* @return A Set of strings representing the FHIR IDs of the pids.
*/
@Override
public Set<String> translatePidsToFhirResourceIds(Set<Long> thePids) {
public Set<String> translatePidsToFhirResourceIds(Set<ResourcePersistentId> thePids) {
assert TransactionSynchronizationManager.isSynchronizationActive();
Map<Long, Optional<String>> pidToForcedIdMap = super.translatePidsToForcedIds(thePids);
//If the result of the translation is an empty optional, it means there is no forced id, and we can use the PID as the resource ID.
Set<String> resolvedResourceIds = pidToForcedIdMap.entrySet().stream()
.map(entry -> entry.getValue().isPresent() ? entry.getValue().get() : entry.getKey().toString())
.collect(Collectors.toSet());
return resolvedResourceIds;
PersistentIdToForcedIdMap pidToForcedIdMap = super.translatePidsToForcedIds(thePids);
return pidToForcedIdMap.getResolvedResourceIds();
}
}

View File

@ -0,0 +1,243 @@
package ca.uhn.fhir.jpa.dao.mdm;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2022 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%
*/
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkJpaRepository;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
import ca.uhn.fhir.mdm.model.MdmPidTuple;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.hl7.fhir.instance.model.api.IIdType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class MdmLinkDaoJpaImpl implements IMdmLinkDao<MdmLink> {
@Autowired
IMdmLinkJpaRepository myMdmLinkDao;
@Autowired
protected EntityManager myEntityManager;
@Autowired
private IIdHelperService myIdHelperService;
@Override
public int deleteWithAnyReferenceToPid(ResourcePersistentId thePid) {
return myMdmLinkDao.deleteWithAnyReferenceToPid(thePid.getIdAsLong());
}
@Override
public int deleteWithAnyReferenceToPidAndMatchResultNot(ResourcePersistentId thePid, MdmMatchResultEnum theMatchResult) {
return myMdmLinkDao.deleteWithAnyReferenceToPidAndMatchResultNot(thePid.getIdAsLong(), theMatchResult);
}
@Override
public List<MdmPidTuple> expandPidsFromGroupPidGivenMatchResult(ResourcePersistentId theGroupPid, MdmMatchResultEnum theMdmMatchResultEnum) {
return myMdmLinkDao.expandPidsFromGroupPidGivenMatchResult(theGroupPid.getIdAsLong(), theMdmMatchResultEnum)
.stream()
.map( theMdmPidTuple -> new MdmPidTuple()
.setSourcePid(new ResourcePersistentId(theMdmPidTuple.getSourcePid()))
.setGoldenPid(new ResourcePersistentId(theMdmPidTuple.getGoldenPid())))
.collect(Collectors.toList());
}
@Override
public List<MdmPidTuple> expandPidsBySourcePidAndMatchResult(ResourcePersistentId theSourcePid, MdmMatchResultEnum theMdmMatchResultEnum) {
return myMdmLinkDao.expandPidsBySourcePidAndMatchResult(theSourcePid.getIdAsLong(), theMdmMatchResultEnum)
.stream()
.map( theMdmPidTuple -> new MdmPidTuple()
.setSourcePid(new ResourcePersistentId(theMdmPidTuple.getSourcePid()))
.setGoldenPid(new ResourcePersistentId(theMdmPidTuple.getGoldenPid())))
.collect(Collectors.toList());
}
@Override
public List<MdmPidTuple> expandPidsByGoldenResourcePidAndMatchResult(ResourcePersistentId theSourcePid, MdmMatchResultEnum theMdmMatchResultEnum) {
return myMdmLinkDao.expandPidsByGoldenResourcePidAndMatchResult(theSourcePid.getIdAsLong(), theMdmMatchResultEnum)
.stream()
.map( theMdmPidTuple -> new MdmPidTuple()
.setSourcePid(new ResourcePersistentId(theMdmPidTuple.getSourcePid()))
.setGoldenPid(new ResourcePersistentId(theMdmPidTuple.getGoldenPid())))
.collect(Collectors.toList());
}
@Override
public List<ResourcePersistentId> findPidByResourceNameAndThreshold(String theResourceName, Date theHighThreshold, Pageable thePageable) {
return myMdmLinkDao.findPidByResourceNameAndThreshold(theResourceName,theHighThreshold, thePageable)
.stream()
.map( theResourcePids -> new ResourcePersistentId(theResourcePids))
.collect(Collectors.toList());
}
@Override
public List<ResourcePersistentId> findPidByResourceNameAndThresholdAndPartitionId(String theResourceName, Date theHighThreshold, List<Integer> thePartitionIds, Pageable thePageable) {
return myMdmLinkDao.findPidByResourceNameAndThresholdAndPartitionId(theResourceName,theHighThreshold, thePartitionIds, thePageable)
.stream()
.map( theResourcePids -> new ResourcePersistentId(theResourcePids))
.collect(Collectors.toList());
}
@Override
public List<MdmLink> findAllById(List<ResourcePersistentId> thePids) {
List<Long> theLongPids = thePids.stream().map(theResourcePersistentId -> theResourcePersistentId.getIdAsLong()).collect(Collectors.toList());
return myMdmLinkDao.findAllById(theLongPids);
}
@Override
public Optional<MdmLink> findById(ResourcePersistentId thePid) {
return myMdmLinkDao.findById(thePid.getIdAsLong());
}
public void deleteAll(List<MdmLink> theLinks) {
myMdmLinkDao.deleteAll(theLinks);
}
@Override
public List<MdmLink> findAll(Example<MdmLink> theExample) {
return myMdmLinkDao.findAll(theExample);
}
@Override
public List<MdmLink> findAll() {
return myMdmLinkDao.findAll();
}
@Override
public Long count() {
return myMdmLinkDao.count();
}
@Override
public void deleteAll() {
myMdmLinkDao.deleteAll();
}
@Override
public MdmLink save(MdmLink theMdmLink) {
return myMdmLinkDao.save(theMdmLink);
}
@Override
public Optional<MdmLink> findOne(Example<MdmLink> theExample) {
return myMdmLinkDao.findOne(theExample);
}
@Override
public void delete(MdmLink theMdmLink) {
myMdmLinkDao.delete(theMdmLink);
}
@Override
public MdmLink validateMdmLink(IMdmLink theMdmLink) throws UnprocessableEntityException {
if (theMdmLink instanceof MdmLink){
return (MdmLink) theMdmLink;
}
else {
throw new UnprocessableEntityException(Msg.code(2109) + "Unprocessable MdmLink implementation");
}
}
@Override
public Page<MdmLink> search(IIdType theGoldenResourceId, IIdType theSourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmPageRequest thePageRequest, List<Integer> thePartitionId) {
CriteriaBuilder criteriaBuilder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<MdmLink> criteriaQuery = criteriaBuilder.createQuery(MdmLink.class);
Root<MdmLink> from = criteriaQuery.from(MdmLink.class);
List<Predicate> andPredicates = new ArrayList<>();
if (theGoldenResourceId != null) {
Predicate goldenResourcePredicate = criteriaBuilder.equal(from.get("myGoldenResourcePid").as(Long.class), myIdHelperService.getPidOrThrowException(RequestPartitionId.allPartitions(), theGoldenResourceId).getIdAsLong());
andPredicates.add(goldenResourcePredicate);
}
if (theSourceId != null) {
Predicate sourceIdPredicate = criteriaBuilder.equal(from.get("mySourcePid").as(Long.class), myIdHelperService.getPidOrThrowException(RequestPartitionId.allPartitions(), theSourceId).getIdAsLong());
andPredicates.add(sourceIdPredicate);
}
if (theMatchResult != null) {
Predicate matchResultPredicate = criteriaBuilder.equal(from.get("myMatchResult").as(MdmMatchResultEnum.class), theMatchResult);
andPredicates.add(matchResultPredicate);
}
if (theLinkSource != null) {
Predicate linkSourcePredicate = criteriaBuilder.equal(from.get("myLinkSource").as(MdmLinkSourceEnum.class), theLinkSource);
andPredicates.add(linkSourcePredicate);
}
if (!CollectionUtils.isEmpty(thePartitionId)) {
Expression<Integer> exp = from.get("myPartitionId").get("myPartitionId").as(Integer.class);
Predicate linkSourcePredicate = exp.in(thePartitionId);
andPredicates.add(linkSourcePredicate);
}
Predicate finalQuery = criteriaBuilder.and(andPredicates.toArray(new Predicate[0]));
TypedQuery<MdmLink> typedQuery = myEntityManager.createQuery(criteriaQuery.where(finalQuery));
CriteriaQuery<Long> countQuery = criteriaBuilder.createQuery(Long.class);
countQuery.select(criteriaBuilder.count(countQuery.from(MdmLink.class)))
.where(finalQuery);
Long totalResults = myEntityManager.createQuery(countQuery).getSingleResult();
return new PageImpl<>(typedQuery.setFirstResult(thePageRequest.getOffset()).setMaxResults(thePageRequest.getCount()).getResultList(),
PageRequest.of(thePageRequest.getPage(), thePageRequest.getCount()),
totalResults);
}
@Override
public Optional<? extends IMdmLink> findBySourcePidAndMatchResult(ResourcePersistentId theSourcePid, MdmMatchResultEnum theMatch) {
return myMdmLinkDao.findBySourcePidAndMatchResult(theSourcePid.getIdAsLong(), theMatch);
}
@Override
public void deleteLinksWithAnyReferenceToPids(List<ResourcePersistentId> theResourcePersistentIds) {
List<Long> goldenResourcePids = theResourcePersistentIds.stream().map(ResourcePersistentId::getIdAsLong).collect(Collectors.toList());
// Split into chunks of 500 so older versions of Oracle don't run into issues (500 = 1000 / 2 since the dao
// method uses the list twice in the sql predicate)
List<List<Long>> chunks = ListUtils.partition(goldenResourcePids, 500);
for (List<Long> chunk : chunks) {
myMdmLinkDao.deleteLinksWithAnyReferenceToPids(chunk);
}
}
}

View File

@ -51,11 +51,11 @@ public class FhirResourceDaoQuestionnaireResponseR4 extends BaseHapiFhirResource
// }
// }
//
// public class JpaResourceLoader implements IResourceLoader {
// public class ResourceLoaderImpl implements IResourceLoader {
//
// private RequestDetails myRequestDetails;
//
// public JpaResourceLoader(RequestDetails theRequestDetails) {
// public ResourceLoaderImpl(RequestDetails theRequestDetails) {
// super();
// myRequestDetails = theRequestDetails;
// }

View File

@ -51,11 +51,11 @@ public class FhirResourceDaoQuestionnaireResponseR5 extends BaseHapiFhirResource
// }
// }
//
// public class JpaResourceLoader implements IResourceLoader {
// public class ResourceLoaderImpl implements IResourceLoader {
//
// private RequestDetails myRequestDetails;
//
// public JpaResourceLoader(RequestDetails theRequestDetails) {
// public ResourceLoaderImpl(RequestDetails theRequestDetails) {
// super();
// myRequestDetails = theRequestDetails;
// }

View File

@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.delete.batch2;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.dao.data.IResourceLinkDao;
import ca.uhn.fhir.jpa.dao.expunge.ResourceForeignKey;
import ca.uhn.fhir.jpa.dao.expunge.ResourceTableFKProvider;
@ -45,10 +46,10 @@ public class DeleteExpungeSqlBuilder {
private final ResourceTableFKProvider myResourceTableFKProvider;
private final DaoConfig myDaoConfig;
private final IJpaIdHelperService myIdHelper;
private final IIdHelperService myIdHelper;
private final IResourceLinkDao myResourceLinkDao;
public DeleteExpungeSqlBuilder(ResourceTableFKProvider theResourceTableFKProvider, DaoConfig theDaoConfig, IJpaIdHelperService theIdHelper, IResourceLinkDao theResourceLinkDao) {
public DeleteExpungeSqlBuilder(ResourceTableFKProvider theResourceTableFKProvider, DaoConfig theDaoConfig, IIdHelperService theIdHelper, IResourceLinkDao theResourceLinkDao) {
myResourceTableFKProvider = theResourceTableFKProvider;
myDaoConfig = theDaoConfig;
myIdHelper = theIdHelper;
@ -96,8 +97,8 @@ public class DeleteExpungeSqlBuilder {
//NB-GGG: We previously instantiated these ID values from firstConflict.getSourceResource().getIdDt(), but in a situation where we
//actually had to run delete conflict checks in multiple partitions, the executor service starts its own sessions on a per thread basis, and by the time
//we arrive here, those sessions are closed. So instead, we resolve them from PIDs, which are eagerly loaded.
String sourceResourceId = myIdHelper.resourceIdFromPidOrThrowException(firstConflict.getSourceResourcePid()).toVersionless().getValue();
String targetResourceId = myIdHelper.resourceIdFromPidOrThrowException(firstConflict.getTargetResourcePid()).toVersionless().getValue();
String sourceResourceId = myIdHelper.resourceIdFromPidOrThrowException(new ResourcePersistentId(firstConflict.getSourceResourcePid()), firstConflict.getSourceResourceType()).toVersionless().getValue();
String targetResourceId = myIdHelper.resourceIdFromPidOrThrowException(new ResourcePersistentId(firstConflict.getTargetResourcePid()), firstConflict.getTargetResourceType()).toVersionless().getValue();
throw new InvalidRequestException(Msg.code(822) + "DELETE with _expunge=true failed. Unable to delete " +
targetResourceId + " because " + sourceResourceId + " refers to it via the path " + firstConflict.getSourcePath());

View File

@ -25,6 +25,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.apache.commons.lang3.builder.ToStringBuilder;
import javax.persistence.Column;
@ -137,12 +138,38 @@ public class MdmLink extends BasePartitionable implements IMdmLink {
@Column(name = "TARGET_TYPE", nullable = true, length = SOURCE_TYPE_LENGTH)
private String myMdmSourceType;
public Long getId() {
return myId;
@Override
public ResourcePersistentId getId() {
return new ResourcePersistentId(myId);
}
public MdmLink setId(Long theId) {
myId = theId;
@Override
public MdmLink setId(ResourcePersistentId theId) {
myId = theId.getIdAsLong();
return this;
}
@Override
public ResourcePersistentId getGoldenResourcePersistenceId() {
return new ResourcePersistentId(myGoldenResourcePid);
}
@Override
public IMdmLink setGoldenResourcePersistenceId(ResourcePersistentId theGoldenResourcePid) {
setPersonPid(theGoldenResourcePid.getIdAsLong());
myGoldenResourcePid = theGoldenResourcePid.getIdAsLong();
return this;
}
@Override
public ResourcePersistentId getSourcePersistenceId() {
return new ResourcePersistentId(mySourcePid);
}
@Override
public IMdmLink setSourcePersistenceId(ResourcePersistentId theSourcePid) {
mySourcePid = theSourcePid.getIdAsLong();
return this;
}
@ -160,6 +187,7 @@ public class MdmLink extends BasePartitionable implements IMdmLink {
return this;
}
@Deprecated
public Long getGoldenResourcePid() {
return myGoldenResourcePid;
}
@ -173,6 +201,10 @@ public class MdmLink extends BasePartitionable implements IMdmLink {
return this;
}
/**
* @deprecated Use {@link #setGoldenResourcePersistenceId(ResourcePersistentId)} instead
*/
@Deprecated
public MdmLink setGoldenResourcePid(Long theGoldenResourcePid) {
setPersonPid(theGoldenResourcePid);
@ -190,101 +222,92 @@ public class MdmLink extends BasePartitionable implements IMdmLink {
return this;
}
@Deprecated
public Long getSourcePid() {
return mySourcePid;
}
/**
* @deprecated Use {@link #setSourcePersistenceId(ResourcePersistentId)} instead
*/
@Deprecated
public MdmLink setSourcePid(Long theSourcePid) {
mySourcePid = theSourcePid;
return this;
}
@Override
public MdmMatchResultEnum getMatchResult() {
return myMatchResult;
}
@Override
public MdmLink setMatchResult(MdmMatchResultEnum theMatchResult) {
myMatchResult = theMatchResult;
return this;
}
public boolean isNoMatch() {
return myMatchResult == MdmMatchResultEnum.NO_MATCH;
}
public boolean isMatch() {
return myMatchResult == MdmMatchResultEnum.MATCH;
}
public boolean isPossibleMatch() {
return myMatchResult == MdmMatchResultEnum.POSSIBLE_MATCH;
}
public boolean isRedirect() {
return myMatchResult == MdmMatchResultEnum.REDIRECT;
}
public boolean isPossibleDuplicate() {
return myMatchResult == MdmMatchResultEnum.POSSIBLE_DUPLICATE;
}
@Override
public MdmLinkSourceEnum getLinkSource() {
return myLinkSource;
}
@Override
public MdmLink setLinkSource(MdmLinkSourceEnum theLinkSource) {
myLinkSource = theLinkSource;
return this;
}
public boolean isAuto() {
return myLinkSource == MdmLinkSourceEnum.AUTO;
}
public boolean isManual() {
return myLinkSource == MdmLinkSourceEnum.MANUAL;
}
@Override
public Date getCreated() {
return myCreated;
}
@Override
public MdmLink setCreated(Date theCreated) {
myCreated = theCreated;
return this;
}
@Override
public Date getUpdated() {
return myUpdated;
}
@Override
public MdmLink setUpdated(Date theUpdated) {
myUpdated = theUpdated;
return this;
}
@Override
public String getVersion() {
return myVersion;
}
@Override
public MdmLink setVersion(String theVersion) {
myVersion = theVersion;
return this;
}
@Override
public Long getVector() {
return myVector;
}
@Override
public MdmLink setVector(Long theVector) {
myVector = theVector;
return this;
}
@Override
public Double getScore() {
return myScore;
}
@Override
public MdmLink setScore(Double theScore) {
myScore = theScore;
return this;
@ -299,19 +322,23 @@ public class MdmLink extends BasePartitionable implements IMdmLink {
* <code>isEidMatch</code> because Hibernate Search complains about having
* 2 accessors for this property
*/
public boolean isEidMatchPresent() {
@Override
public Boolean isEidMatchPresent() {
return myEidMatch != null && myEidMatch;
}
@Override
public MdmLink setEidMatch(Boolean theEidMatch) {
myEidMatch = theEidMatch;
return this;
}
public boolean getHadToCreateNewGoldenResource() {
@Override
public Boolean getHadToCreateNewGoldenResource() {
return myHadToCreateNewGoldenResource != null && myHadToCreateNewGoldenResource;
}
@Override
public MdmLink setHadToCreateNewGoldenResource(Boolean theHadToCreateNewResource) {
myHadToCreateNewGoldenResource = theHadToCreateNewResource;
return this;
@ -347,8 +374,9 @@ public class MdmLink extends BasePartitionable implements IMdmLink {
return myRuleCount;
}
public void setRuleCount(Long theRuleCount) {
public MdmLink setRuleCount(Long theRuleCount) {
myRuleCount = theRuleCount;
return this;
}
}

View File

@ -21,7 +21,6 @@ package ca.uhn.fhir.jpa.term;
*/
import ca.uhn.fhir.context.support.ConceptValidationOptions;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValueSetExpansionOptions;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
@ -35,7 +34,6 @@ import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ValueSet;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.Nullable;
import java.util.ArrayList;

View File

@ -7,18 +7,20 @@ import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.api.model.PersistentIdToForcedIdMap;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.bulk.export.model.ExportPIDIteratorParameters;
import ca.uhn.fhir.jpa.dao.IResultIterator;
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkDao;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.dao.mdm.MdmExpansionCacheSvc;
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
import ca.uhn.fhir.mdm.model.MdmPidTuple;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.server.bulk.BulkDataExportOptions;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
@ -126,9 +128,6 @@ public class JpaBulkExportProcessorTest {
@Mock
private IMdmLinkDao myMdmLinkDao;
@Mock
private IJpaIdHelperService myJpaIdHelperService;
@Mock
private MdmExpansionCacheSvc myMdmExpansionCacheSvc;
@ -159,16 +158,16 @@ public class JpaBulkExportProcessorTest {
return patientTypes;
}
private IMdmLinkDao.MdmPidTuple createTuple(long theGroupId, long theGoldenId) {
return new IMdmLinkDao.MdmPidTuple() {
private MdmPidTuple createTuple(long theGroupId, long theGoldenId) {
return new MdmPidTuple() {
@Override
public Long getGoldenPid() {
return theGoldenId;
public ResourcePersistentId getGoldenPid() {
return new ResourcePersistentId(theGoldenId);
}
@Override
public Long getSourcePid() {
return theGroupId;
public ResourcePersistentId getSourcePid() {
return new ResourcePersistentId(theGroupId);
}
};
}
@ -251,19 +250,19 @@ public class JpaBulkExportProcessorTest {
ExportPIDIteratorParameters parameters = createExportParameters(BulkDataExportOptions.ExportStyle.GROUP);
parameters.setResourceType("Patient");
long groupId = Long.parseLong(parameters.getGroupId());
ResourcePersistentId groupId = new ResourcePersistentId(Long.parseLong(parameters.getGroupId()));
long groupGoldenPid = 4567l;
Group groupResource = new Group();
groupResource.setId(parameters.getGroupId());
List<IPrimitiveType> patientTypes = createPatientTypes();
List<Long> pids = new ArrayList<>();
List<ResourcePersistentId> pids = new ArrayList<>();
for (IPrimitiveType type : patientTypes) {
pids.add(((IdDt) type).getIdPartAsLong());
pids.add(new ResourcePersistentId(((IdDt) type).getIdPartAsLong()));
}
IMdmLinkDao.MdmPidTuple tuple = createTuple(groupId, groupGoldenPid);
MdmPidTuple tuple = createTuple(groupId.getIdAsLong(), groupGoldenPid);
IFhirResourceDao<Group> groupDao = mock(IFhirResourceDao.class);
IFhirPath path = mock(IFhirPath.class);
@ -279,13 +278,22 @@ public class JpaBulkExportProcessorTest {
.thenReturn(path);
when(path.evaluate(eq(groupResource), anyString(), any(Class.class)))
.thenReturn(patientTypes);
when(myJpaIdHelperService.getPidsOrThrowException(anyList()))
when(myIdHelperService.getPidsOrThrowException(any(), anyList()))
.thenReturn(pids);
// mdm expansion stuff
if (theMdm) {
when(myJpaIdHelperService.getPidOrNull(any(Group.class)))
when(myIdHelperService.translatePidsToForcedIds(any(Set.class)))
.thenAnswer(params -> {
Set<ResourcePersistentId> uniqPids = params.getArgument(0);
HashMap<ResourcePersistentId, Optional<String>> answer = new HashMap<>();
for (ResourcePersistentId l : uniqPids) {
answer.put(l, Optional.empty());
}
return new PersistentIdToForcedIdMap(answer);
});
when(myIdHelperService.getPidOrNull(any(), any(Group.class)))
.thenReturn(groupId);
when(myMdmLinkDao.expandPidsFromGroupPidGivenMatchResult(anyLong(), eq(MdmMatchResultEnum.MATCH)))
when(myMdmLinkDao.expandPidsFromGroupPidGivenMatchResult(any(ResourcePersistentId.class), eq(MdmMatchResultEnum.MATCH)))
.thenReturn(Collections.singletonList(tuple));
when(myMdmExpansionCacheSvc.hasBeenPopulated())
.thenReturn(false); // does not matter, since if false, it then goes and populates
@ -301,7 +309,7 @@ public class JpaBulkExportProcessorTest {
while (pidIterator.hasNext()) {
ResourcePersistentId pid = pidIterator.next();
long idAsLong = pid.getIdAsLong();
boolean existing = pids.contains(idAsLong);
boolean existing = pids.contains(new ResourcePersistentId(idAsLong));
if (!existing) {
assertTrue(theMdm);
assertEquals(groupGoldenPid, idAsLong);
@ -320,7 +328,7 @@ public class JpaBulkExportProcessorTest {
ExportPIDIteratorParameters parameters = createExportParameters(BulkDataExportOptions.ExportStyle.GROUP);
parameters.setResourceType("Observation");
long groupId = Long.parseLong(parameters.getGroupId());
ResourcePersistentId groupId = new ResourcePersistentId(Long.parseLong(parameters.getGroupId()));
Group groupResource = new Group();
groupResource.setId(parameters.getGroupId());
long groupGoldenPid = 4567l;
@ -331,7 +339,7 @@ public class JpaBulkExportProcessorTest {
Arrays.asList(pid, pid2)
);
IMdmLinkDao.MdmPidTuple tuple = createTuple(groupId, groupGoldenPid);
MdmPidTuple tuple = createTuple(groupId.getIdAsLong(), groupGoldenPid);
List<IPrimitiveType> patientTypes = createPatientTypes();
IFhirResourceDao<Group> groupDao = mock(IFhirResourceDao.class);
@ -346,20 +354,20 @@ public class JpaBulkExportProcessorTest {
.thenReturn(groupDao);
when(groupDao.read(any(IIdType.class), any(SystemRequestDetails.class)))
.thenReturn(groupResource);
when(myJpaIdHelperService.getPidOrNull(eq(groupResource)))
when(myIdHelperService.getPidOrNull(any(), eq(groupResource)))
.thenReturn(groupId);
if (theMdm) {
when(myMdmLinkDao.expandPidsFromGroupPidGivenMatchResult(anyLong(), eq(MdmMatchResultEnum.MATCH)))
when(myMdmLinkDao.expandPidsFromGroupPidGivenMatchResult(any(ResourcePersistentId.class), eq(MdmMatchResultEnum.MATCH)))
.thenReturn(Collections.singletonList(tuple));
when(myIdHelperService.translatePidsToForcedIds(any(Set.class)))
.thenAnswer(params -> {
Set<Long> uniqPids = params.getArgument(0);
HashMap<Long, Optional<String>> answer = new HashMap<>();
for (long l : uniqPids) {
Set<ResourcePersistentId> uniqPids = params.getArgument(0);
HashMap<ResourcePersistentId, Optional<String>> answer = new HashMap<>();
for (ResourcePersistentId l : uniqPids) {
answer.put(l, Optional.empty());
}
return answer;
return new PersistentIdToForcedIdMap(answer);
});
}
when(myFhirContext.newFhirPath())

View File

@ -7,7 +7,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -6,7 +6,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

View File

@ -20,13 +20,11 @@ package ca.uhn.fhir.jpa.mdm.broker;
* #L%
*/
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.jpa.mdm.svc.IMdmModelConverterSvc;
import ca.uhn.fhir.jpa.mdm.svc.MdmMatchLinkSvc;
import ca.uhn.fhir.jpa.mdm.svc.MdmResourceFilteringSvc;
@ -55,8 +53,6 @@ public class MdmMessageHandler implements MessageHandler {
private static final Logger ourLog = Logs.getMdmTroubleshootingLog();
@Autowired
private MdmLinkDaoSvc myMdmLinkDaoSvc;
@Autowired
private MdmMatchLinkSvc myMdmMatchLinkSvc;
@Autowired
@ -181,7 +177,7 @@ public class MdmMessageHandler implements MessageHandler {
theMdmContext.getMdmLinks()
.stream()
.forEach(l -> {
linkChangeEvent.addMdmLink(myModelConverter.toJson((MdmLink) l));
linkChangeEvent.addMdmLink(myModelConverter.toJson(l));
});
return linkChangeEvent;

View File

@ -21,9 +21,9 @@ package ca.uhn.fhir.jpa.mdm.config;
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.mdm.MdmLinkDeleteSvc;
import ca.uhn.fhir.jpa.interceptor.MdmSearchExpandingInterceptor;
import ca.uhn.fhir.mdm.interceptor.MdmSearchExpandingInterceptor;
import ca.uhn.fhir.mdm.rules.config.MdmRuleValidator;
import ca.uhn.fhir.mdm.svc.MdmLinkDeleteSvc;
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -41,7 +41,6 @@ public class MdmCommonConfig {
return new MdmSearchExpandingInterceptor();
}
@Bean
MdmLinkDeleteSvc mdmLinkDeleteSvc() {
return new MdmLinkDeleteSvc();

View File

@ -27,9 +27,7 @@ import ca.uhn.fhir.jpa.mdm.broker.MdmMessageHandler;
import ca.uhn.fhir.jpa.mdm.broker.MdmMessageKeySvc;
import ca.uhn.fhir.jpa.mdm.broker.MdmQueueConsumerLoader;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkFactory;
import ca.uhn.fhir.jpa.mdm.interceptor.IMdmStorageInterceptor;
import ca.uhn.fhir.jpa.mdm.interceptor.MdmStorageInterceptor;
import ca.uhn.fhir.mdm.dao.MdmLinkFactory;
import ca.uhn.fhir.jpa.mdm.svc.GoldenResourceMergerSvcImpl;
import ca.uhn.fhir.jpa.mdm.svc.GoldenResourceSearchSvcImpl;
import ca.uhn.fhir.jpa.mdm.svc.IMdmModelConverterSvc;
@ -44,7 +42,6 @@ import ca.uhn.fhir.jpa.mdm.svc.MdmMatchLinkSvc;
import ca.uhn.fhir.jpa.mdm.svc.MdmModelConverterSvcImpl;
import ca.uhn.fhir.jpa.mdm.svc.MdmResourceDaoSvc;
import ca.uhn.fhir.jpa.mdm.svc.MdmResourceFilteringSvc;
import ca.uhn.fhir.jpa.mdm.svc.MdmSearchParamSvc;
import ca.uhn.fhir.jpa.mdm.svc.MdmSurvivorshipSvcImpl;
import ca.uhn.fhir.jpa.mdm.svc.candidate.CandidateSearcher;
import ca.uhn.fhir.jpa.mdm.svc.candidate.FindCandidateByEidSvc;
@ -65,10 +62,14 @@ import ca.uhn.fhir.mdm.api.IMdmMatchFinderSvc;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
import ca.uhn.fhir.mdm.batch2.MdmBatch2Config;
import ca.uhn.fhir.mdm.dao.IMdmLinkImplFactory;
import ca.uhn.fhir.mdm.interceptor.IMdmStorageInterceptor;
import ca.uhn.fhir.mdm.interceptor.MdmStorageInterceptor;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.provider.MdmControllerHelper;
import ca.uhn.fhir.mdm.provider.MdmProviderLoader;
import ca.uhn.fhir.mdm.rules.svc.MdmResourceMatcherSvc;
import ca.uhn.fhir.mdm.svc.MdmSearchParamSvc;
import ca.uhn.fhir.mdm.util.EIDHelper;
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
import ca.uhn.fhir.mdm.util.MessageHelper;
@ -219,8 +220,8 @@ public class MdmConsumerConfig {
}
@Bean
MdmLinkFactory mdmLinkFactory(IMdmSettings theMdmSettings) {
return new MdmLinkFactory(theMdmSettings);
MdmLinkFactory mdmLinkFactory(IMdmSettings theMdmSettings, IMdmLinkImplFactory theMdmLinkImplFactory) {
return new MdmLinkFactory(theMdmSettings, theMdmLinkImplFactory);
}
@Bean

View File

@ -21,16 +21,17 @@ package ca.uhn.fhir.jpa.mdm.config;
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.mdm.MdmLinkDeleteSvc;
import ca.uhn.fhir.jpa.dao.mdm.MdmLinkDaoJpaImpl;
import ca.uhn.fhir.jpa.mdm.dao.JpaMdmLinkImplFactory;
import ca.uhn.fhir.jpa.mdm.interceptor.MdmSubmitterInterceptorLoader;
import ca.uhn.fhir.jpa.mdm.svc.MdmChannelSubmitterSvcImpl;
import ca.uhn.fhir.jpa.mdm.svc.MdmSearchParamSvc;
import ca.uhn.fhir.jpa.mdm.svc.MdmSubmitSvcImpl;
import ca.uhn.fhir.mdm.dao.IMdmLinkImplFactory;
import ca.uhn.fhir.mdm.svc.MdmChannelSubmitterSvcImpl;
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
import ca.uhn.fhir.mdm.svc.MdmSearchParamSvc;
import ca.uhn.fhir.mdm.svc.MdmSubmitSvcImpl;
import ca.uhn.fhir.jpa.subscription.channel.api.IChannelFactory;
import ca.uhn.fhir.mdm.api.IMdmChannelSubmitterSvc;
import ca.uhn.fhir.mdm.api.IMdmSubmitSvc;
import ca.uhn.fhir.mdm.rules.config.MdmRuleValidator;
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@ -60,4 +61,12 @@ public class MdmSubmitterConfig {
IMdmSubmitSvc mdmSubmitService() {
return new MdmSubmitSvcImpl();
}
@Bean
IMdmLinkDao mdmLinkDao(){
return new MdmLinkDaoJpaImpl();
}
@Bean
IMdmLinkImplFactory mdmLinkImplFactory() {return new JpaMdmLinkImplFactory();}
}

View File

@ -26,7 +26,6 @@ import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.subscription.channel.api.ChannelProducerSettings;
import ca.uhn.fhir.jpa.subscription.channel.subscription.IChannelNamer;
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionLoader;
@ -56,8 +55,6 @@ public class MdmSubscriptionLoader {
@Autowired
public DaoRegistry myDaoRegistry;
@Autowired
public IJpaIdHelperService myIdHelperService;
@Autowired
IChannelNamer myChannelNamer;
@Autowired
private SubscriptionLoader mySubscriptionLoader;

View File

@ -0,0 +1,32 @@
package ca.uhn.fhir.jpa.mdm.dao;
/*-
* #%L
* HAPI FHIR JPA Server - Master Data Management
* %%
* Copyright (C) 2014 - 2022 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%
*/
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.dao.IMdmLinkImplFactory;
public class JpaMdmLinkImplFactory implements IMdmLinkImplFactory {
@Override
public IMdmLink newMdmLinkImpl() {
return new MdmLink();
}
}

View File

@ -22,40 +22,31 @@ package ca.uhn.fhir.jpa.mdm.dao;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkDao;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
import ca.uhn.fhir.mdm.dao.MdmLinkFactory;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.rest.api.Constants;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Page;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@ -70,18 +61,13 @@ public class MdmLinkDaoSvc {
@Autowired
private MdmLinkFactory myMdmLinkFactory;
@Autowired
private IJpaIdHelperService myJpaIdHelperService;
private IIdHelperService myIdHelperService;
@Autowired
private FhirContext myFhirContext;
@Autowired
protected EntityManager myEntityManager;
@Transactional
public MdmLink createOrUpdateLinkEntity(IBaseResource theGoldenResource, IBaseResource theSourceResource, MdmMatchOutcome theMatchOutcome, MdmLinkSourceEnum theLinkSource, @Nullable MdmTransactionContext theMdmTransactionContext) {
Long goldenResourcePid = myJpaIdHelperService.getPidOrNull(theGoldenResource);
Long sourceResourcePid = myJpaIdHelperService.getPidOrNull(theSourceResource);
MdmLink mdmLink = getOrCreateMdmLinkByGoldenResourcePidAndSourceResourcePid(goldenResourcePid, sourceResourcePid);
public IMdmLink createOrUpdateLinkEntity(IAnyResource theGoldenResource, IAnyResource theSourceResource, MdmMatchOutcome theMatchOutcome, MdmLinkSourceEnum theLinkSource, @Nullable MdmTransactionContext theMdmTransactionContext) {
IMdmLink mdmLink = getOrCreateMdmLinkByGoldenResourceAndSourceResource(theGoldenResource, theSourceResource);
mdmLink.setLinkSource(theLinkSource);
mdmLink.setMatchResult(theMatchOutcome.getMatchResultEnum());
// Preserve these flags for link updates
@ -107,26 +93,46 @@ public class MdmLinkDaoSvc {
}
@Nonnull
public MdmLink getOrCreateMdmLinkByGoldenResourcePidAndSourceResourcePid(Long theGoldenResourcePid, Long theSourceResourcePid) {
Optional<MdmLink> oExisting = getLinkByGoldenResourcePidAndSourceResourcePid(theGoldenResourcePid, theSourceResourcePid);
public IMdmLink getOrCreateMdmLinkByGoldenResourceAndSourceResource(IAnyResource theGoldenResource, IAnyResource theSourceResource) {
ResourcePersistentId goldenResourcePid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theGoldenResource);
ResourcePersistentId sourceResourcePid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theSourceResource);
Optional<? extends IMdmLink> oExisting = getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourcePid, sourceResourcePid);
if (oExisting.isPresent()) {
return oExisting.get();
} else {
MdmLink newLink = myMdmLinkFactory.newMdmLink();
newLink.setGoldenResourcePid(theGoldenResourcePid);
newLink.setSourcePid(theSourceResourcePid);
IMdmLink newLink = myMdmLinkFactory.newMdmLink();
newLink.setGoldenResourcePersistenceId(goldenResourcePid);
newLink.setSourcePersistenceId(sourceResourcePid);
return newLink;
}
}
public Optional<MdmLink> getLinkByGoldenResourcePidAndSourceResourcePid(Long theGoldenResourcePid, Long theSourceResourcePid) {
/**
* Given a golden resource Pid and source Pid, return the mdm link that matches these criterias if exists
* @deprecated This was deprecated in favour of using ResourcePersistenceId rather than longs
* @param theGoldenResourcePid
* @param theSourceResourcePid
* @return
*/
@Deprecated
public Optional<? extends IMdmLink> getLinkByGoldenResourcePidAndSourceResourcePid(Long theGoldenResourcePid, Long theSourceResourcePid) {
return getLinkByGoldenResourcePidAndSourceResourcePid(new ResourcePersistentId(theGoldenResourcePid), new ResourcePersistentId(theSourceResourcePid));
}
/**
* Given a golden resource Pid and source Pid, return the mdm link that matches these criterias if exists
* @param theGoldenResourcePid The ResourcePersistenceId of the golden resource
* @param theSourceResourcePid The ResourcepersistenceId of the Source resource
* @return The {@link IMdmLink} entity that matches these criteria if exists
*/
public Optional<? extends IMdmLink> getLinkByGoldenResourcePidAndSourceResourcePid(ResourcePersistentId theGoldenResourcePid, ResourcePersistentId theSourceResourcePid) {
if (theSourceResourcePid == null || theGoldenResourcePid == null) {
return Optional.empty();
}
MdmLink link = myMdmLinkFactory.newMdmLink();
link.setSourcePid(theSourceResourcePid);
link.setGoldenResourcePid(theGoldenResourcePid);
Example<MdmLink> example = Example.of(link);
IMdmLink link = myMdmLinkFactory.newMdmLink();
link.setSourcePersistenceId(theSourceResourcePid);
link.setGoldenResourcePersistenceId(theGoldenResourcePid);
Example<? extends IMdmLink> example = Example.of(link);
return myMdmLinkDao.findOne(example);
}
@ -135,123 +141,132 @@ public class MdmLinkDaoSvc {
*
* @param theSourcePid the source of the relationship.
* @param theMatchResult the Match Result of the relationship
* @return a list of {@link MdmLink} entities matching these criteria.
* @return a list of {@link IMdmLink} entities matching these criteria.
*/
public List<MdmLink> getMdmLinksBySourcePidAndMatchResult(Long theSourcePid, MdmMatchResultEnum theMatchResult) {
MdmLink exampleLink = myMdmLinkFactory.newMdmLink();
exampleLink.setSourcePid(theSourcePid);
public List<? extends IMdmLink> getMdmLinksBySourcePidAndMatchResult(ResourcePersistentId theSourcePid, MdmMatchResultEnum theMatchResult) {
IMdmLink exampleLink = myMdmLinkFactory.newMdmLink();
exampleLink.setSourcePersistenceId(theSourcePid);
exampleLink.setMatchResult(theMatchResult);
Example<MdmLink> example = Example.of(exampleLink);
Example<? extends IMdmLink> example = Example.of(exampleLink);
return myMdmLinkDao.findAll(example);
}
/**
* Given a source Pid, return its Matched {@link MdmLink}. There can only ever be at most one of these, but its possible
* Given a source Pid, return its Matched {@link IMdmLink}. There can only ever be at most one of these, but its possible
* the source has no matches, and may return an empty optional.
*
* @param theSourcePid The Pid of the source you wish to find the matching link for.
* @return the {@link MdmLink} that contains the Match information for the source.
* @return the {@link IMdmLink} that contains the Match information for the source.
*/
@Deprecated
@Transactional
public Optional<MdmLink> getMatchedLinkForSourcePid(Long theSourcePid) {
public Optional<? extends IMdmLink> getMatchedLinkForSourcePid(ResourcePersistentId theSourcePid) {
return myMdmLinkDao.findBySourcePidAndMatchResult(theSourcePid, MdmMatchResultEnum.MATCH);
}
/**
* Given an IBaseResource, return its Matched {@link MdmLink}. There can only ever be at most one of these, but its possible
* Given an IBaseResource, return its Matched {@link IMdmLink}. There can only ever be at most one of these, but its possible
* the source has no matches, and may return an empty optional.
*
* @param theSourceResource The IBaseResource representing the source you wish to find the matching link for.
* @return the {@link MdmLink} that contains the Match information for the source.
* @return the {@link IMdmLink} that contains the Match information for the source.
*/
public Optional<MdmLink> getMatchedLinkForSource(IBaseResource theSourceResource) {
public Optional<? extends IMdmLink> getMatchedLinkForSource(IBaseResource theSourceResource) {
return getMdmLinkWithMatchResult(theSourceResource, MdmMatchResultEnum.MATCH);
}
public Optional<MdmLink> getPossibleMatchedLinkForSource(IBaseResource theSourceResource) {
public Optional<? extends IMdmLink> getPossibleMatchedLinkForSource(IBaseResource theSourceResource) {
return getMdmLinkWithMatchResult(theSourceResource, MdmMatchResultEnum.POSSIBLE_MATCH);
}
@Nonnull
private Optional<MdmLink> getMdmLinkWithMatchResult(IBaseResource theSourceResource, MdmMatchResultEnum theMatchResult) {
Long pid = myJpaIdHelperService.getPidOrNull(theSourceResource);
private Optional<? extends IMdmLink> getMdmLinkWithMatchResult(IBaseResource theSourceResource, MdmMatchResultEnum theMatchResult) {
ResourcePersistentId pid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theSourceResource);
if (pid == null) {
return Optional.empty();
}
MdmLink exampleLink = myMdmLinkFactory.newMdmLink();
exampleLink.setSourcePid(pid);
IMdmLink exampleLink = myMdmLinkFactory.newMdmLink();
exampleLink.setSourcePersistenceId(pid);
exampleLink.setMatchResult(theMatchResult);
Example<MdmLink> example = Example.of(exampleLink);
Example<? extends IMdmLink> example = Example.of(exampleLink);
return myMdmLinkDao.findOne(example);
}
/**
* Given a golden resource a source and a match result, return the matching {@link MdmLink}, if it exists.
* Given a golden resource a source and a match result, return the matching {@link IMdmLink}, if it exists.
*
* @param theGoldenResourcePid The Pid of the Golden Resource in the relationship
* @param theSourcePid The Pid of the source in the relationship
* @param theMatchResult The MatchResult you are looking for.
* @return an Optional {@link MdmLink} containing the matched link if it exists.
* @return an Optional {@link IMdmLink} containing the matched link if it exists.
*/
public Optional<MdmLink> getMdmLinksByGoldenResourcePidSourcePidAndMatchResult(Long theGoldenResourcePid,
Long theSourcePid, MdmMatchResultEnum theMatchResult) {
MdmLink exampleLink = myMdmLinkFactory.newMdmLink();
exampleLink.setGoldenResourcePid(theGoldenResourcePid);
exampleLink.setSourcePid(theSourcePid);
public Optional<? extends IMdmLink> getMdmLinksByGoldenResourcePidSourcePidAndMatchResult(Long theGoldenResourcePid,
Long theSourcePid, MdmMatchResultEnum theMatchResult) {
return getMdmLinksByGoldenResourcePidSourcePidAndMatchResult(new ResourcePersistentId(theGoldenResourcePid), new ResourcePersistentId(theSourcePid), theMatchResult);
}
public Optional<? extends IMdmLink> getMdmLinksByGoldenResourcePidSourcePidAndMatchResult(ResourcePersistentId theGoldenResourcePid,
ResourcePersistentId theSourcePid, MdmMatchResultEnum theMatchResult) {
IMdmLink exampleLink = myMdmLinkFactory.newMdmLink();
exampleLink.setGoldenResourcePersistenceId(theGoldenResourcePid);
exampleLink.setSourcePersistenceId(theSourcePid);
exampleLink.setMatchResult(theMatchResult);
Example<MdmLink> example = Example.of(exampleLink);
Example<? extends IMdmLink> example = Example.of(exampleLink);
return myMdmLinkDao.findOne(example);
}
/**
* Get all {@link MdmLink} which have {@link MdmMatchResultEnum#POSSIBLE_DUPLICATE} as their match result.
* Get all {@link IMdmLink} which have {@link MdmMatchResultEnum#POSSIBLE_DUPLICATE} as their match result.
*
* @return A list of {@link MdmLink} that hold potential duplicate golden resources.
* @return A list of {@link IMdmLink} that hold potential duplicate golden resources.
*/
public List<MdmLink> getPossibleDuplicates() {
MdmLink exampleLink = myMdmLinkFactory.newMdmLink();
public List<? extends IMdmLink> getPossibleDuplicates() {
IMdmLink exampleLink = myMdmLinkFactory.newMdmLink();
exampleLink.setMatchResult(MdmMatchResultEnum.POSSIBLE_DUPLICATE);
Example<MdmLink> example = Example.of(exampleLink);
Example<? extends IMdmLink> example = Example.of(exampleLink);
return myMdmLinkDao.findAll(example);
}
@Transactional
public Optional<MdmLink> findMdmLinkBySource(IBaseResource theSourceResource) {
@Nullable Long pid = myJpaIdHelperService.getPidOrNull(theSourceResource);
public Optional<? extends IMdmLink> findMdmLinkBySource(IBaseResource theSourceResource) {
@Nullable ResourcePersistentId pid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theSourceResource);
if (pid == null) {
return Optional.empty();
}
MdmLink exampleLink = myMdmLinkFactory.newMdmLink().setSourcePid(pid);
Example<MdmLink> example = Example.of(exampleLink);
IMdmLink exampleLink = myMdmLinkFactory.newMdmLink();
exampleLink.setSourcePersistenceId(pid);
Example<? extends IMdmLink> example = Example.of(exampleLink);
return myMdmLinkDao.findOne(example);
}
}
/**
* Delete a given {@link MdmLink}. Note that this does not clear out the Golden resource.
* Delete a given {@link IMdmLink}. Note that this does not clear out the Golden resource.
* It is a simple entity delete.
*
* @param theMdmLink the {@link MdmLink} to delete.
* @param theMdmLink the {@link IMdmLink} to delete.
*/
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void deleteLink(MdmLink theMdmLink) {
public void deleteLink(IMdmLink theMdmLink) {
myMdmLinkDao.validateMdmLink(theMdmLink);
myMdmLinkDao.delete(theMdmLink);
}
/**
* Given a Golden Resource, return all links in which they are the source Golden Resource of the {@link MdmLink}
* Given a Golden Resource, return all links in which they are the source Golden Resource of the {@link IMdmLink}
*
* @param theGoldenResource The {@link IBaseResource} Golden Resource who's links you would like to retrieve.
* @return A list of all {@link MdmLink} entities in which theGoldenResource is the source Golden Resource
* @return A list of all {@link IMdmLink} entities in which theGoldenResource is the source Golden Resource
*/
@Transactional
public List<MdmLink> findMdmLinksByGoldenResource(IBaseResource theGoldenResource) {
Long pid = myJpaIdHelperService.getPidOrNull(theGoldenResource);
public List<? extends IMdmLink> findMdmLinksByGoldenResource(IBaseResource theGoldenResource) {
ResourcePersistentId pid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theGoldenResource);
if (pid == null) {
return Collections.emptyList();
}
MdmLink exampleLink = myMdmLinkFactory.newMdmLink().setGoldenResourcePid(pid);
Example<MdmLink> example = Example.of(exampleLink);
IMdmLink exampleLink = myMdmLinkFactory.newMdmLink();
exampleLink.setGoldenResourcePersistenceId(pid);
Example<? extends IMdmLink> example = Example.of(exampleLink);
return myMdmLinkDao.findAll(example);
}
@ -259,14 +274,15 @@ public class MdmLinkDaoSvc {
* Persist an MDM link to the database.
*
* @param theMdmLink the link to save.
* @return the persisted {@link MdmLink} entity.
* @return the persisted {@link IMdmLink} entity.
*/
public MdmLink save(MdmLink theMdmLink) {
if (theMdmLink.getCreated() == null) {
theMdmLink.setCreated(new Date());
public IMdmLink save(IMdmLink theMdmLink) {
IMdmLink mdmLink = myMdmLinkDao.validateMdmLink(theMdmLink);
if (mdmLink.getCreated() == null) {
mdmLink.setCreated(new Date());
}
theMdmLink.setUpdated(new Date());
return myMdmLinkDao.save(theMdmLink);
mdmLink.setUpdated(new Date());
return myMdmLinkDao.save(mdmLink);
}
@ -279,84 +295,47 @@ public class MdmLinkDaoSvc {
* @param theLinkSource the {@link MdmLinkSourceEnum} being searched.
* @param thePageRequest the {@link MdmPageRequest} paging information
* @param thePartitionId List of partitions ID being searched, where the link's partition must be in the list.
* @return a list of {@link MdmLink} entities which match the example.
* @return a list of {@link IMdmLink} entities which match the example.
*/
public PageImpl<MdmLink> executeTypedQuery(IIdType theGoldenResourceId, IIdType theSourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmPageRequest thePageRequest, List<Integer> thePartitionId) {
CriteriaBuilder criteriaBuilder = myEntityManager.getCriteriaBuilder();
CriteriaQuery<MdmLink> criteriaQuery = criteriaBuilder.createQuery(MdmLink.class);
Root<MdmLink> from = criteriaQuery.from(MdmLink.class);
List<Predicate> andPredicates = new ArrayList<>();
if (theGoldenResourceId != null) {
Predicate goldenResourcePredicate = criteriaBuilder.equal(from.get("myGoldenResourcePid").as(Long.class), myJpaIdHelperService.getPidOrThrowException(theGoldenResourceId));
andPredicates.add(goldenResourcePredicate);
}
if (theSourceId != null) {
Predicate sourceIdPredicate = criteriaBuilder.equal(from.get("mySourcePid").as(Long.class), myJpaIdHelperService.getPidOrThrowException(theSourceId));
andPredicates.add(sourceIdPredicate);
}
if (theMatchResult != null) {
Predicate matchResultPredicate = criteriaBuilder.equal(from.get("myMatchResult").as(MdmMatchResultEnum.class), theMatchResult);
andPredicates.add(matchResultPredicate);
}
if (theLinkSource != null) {
Predicate linkSourcePredicate = criteriaBuilder.equal(from.get("myLinkSource").as(MdmLinkSourceEnum.class), theLinkSource);
andPredicates.add(linkSourcePredicate);
}
if (!CollectionUtils.isEmpty(thePartitionId)) {
Expression<Integer> exp = from.get("myPartitionId").get("myPartitionId").as(Integer.class);
Predicate linkSourcePredicate = exp.in(thePartitionId);
andPredicates.add(linkSourcePredicate);
}
Predicate finalQuery = criteriaBuilder.and(andPredicates.toArray(new Predicate[0]));
TypedQuery<MdmLink> typedQuery = myEntityManager.createQuery(criteriaQuery.where(finalQuery));
CriteriaQuery<Long> countQuery = criteriaBuilder.createQuery(Long.class);
countQuery.select(criteriaBuilder.count(countQuery.from(MdmLink.class)))
.where(finalQuery);
Long totalResults = myEntityManager.createQuery(countQuery).getSingleResult();
return new PageImpl<>(typedQuery.setFirstResult(thePageRequest.getOffset()).setMaxResults(thePageRequest.getCount()).getResultList(),
PageRequest.of(thePageRequest.getPage(), thePageRequest.getCount()),
totalResults);
public Page<? extends IMdmLink> executeTypedQuery(IIdType theGoldenResourceId, IIdType theSourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmPageRequest thePageRequest, List<Integer> thePartitionId) {
return myMdmLinkDao.search(theGoldenResourceId, theSourceId, theMatchResult, theLinkSource, thePageRequest, thePartitionId);
}
/**
* Given a source {@link IBaseResource}, return all {@link MdmLink} entities in which this source is the source
* Given a source {@link IBaseResource}, return all {@link IMdmLink} entities in which this source is the source
* of the relationship. This will show you all links for a given Patient/Practitioner.
*
* @param theSourceResource the source resource to find links for.
* @return all links for the source.
*/
@Transactional
public List<MdmLink> findMdmLinksBySourceResource(IBaseResource theSourceResource) {
Long pid = myJpaIdHelperService.getPidOrNull(theSourceResource);
public List<? extends IMdmLink> findMdmLinksBySourceResource(IBaseResource theSourceResource) {
ResourcePersistentId pid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theSourceResource);
if (pid == null) {
return Collections.emptyList();
}
MdmLink exampleLink = myMdmLinkFactory.newMdmLink().setSourcePid(pid);
Example<MdmLink> example = Example.of(exampleLink);
IMdmLink exampleLink = myMdmLinkFactory.newMdmLink();
exampleLink.setSourcePersistenceId(pid);
Example<? extends IMdmLink> example = Example.of(exampleLink);
return myMdmLinkDao.findAll(example);
}
/**
* Finds all {@link MdmLink} entities in which theGoldenResource's PID is the source
* Finds all {@link IMdmLink} entities in which theGoldenResource's PID is the source
* of the relationship.
*
* @param theGoldenResource the source resource to find links for.
* @return all links for the source.
*/
public List<MdmLink> findMdmMatchLinksByGoldenResource(IBaseResource theGoldenResource) {
Long pid = myJpaIdHelperService.getPidOrNull(theGoldenResource);
public List<? extends IMdmLink> findMdmMatchLinksByGoldenResource(IBaseResource theGoldenResource) {
ResourcePersistentId pid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theGoldenResource);
if (pid == null) {
return Collections.emptyList();
}
MdmLink exampleLink = myMdmLinkFactory.newMdmLink().setGoldenResourcePid(pid);
IMdmLink exampleLink = myMdmLinkFactory.newMdmLink();
exampleLink.setGoldenResourcePersistenceId(pid);
exampleLink.setMatchResult(MdmMatchResultEnum.MATCH);
Example<MdmLink> example = Example.of(exampleLink);
Example<? extends IMdmLink> example = Example.of(exampleLink);
return myMdmLinkDao.findAll(example);
}
@ -364,37 +343,32 @@ public class MdmLinkDaoSvc {
* Factory delegation method, whenever you need a new MdmLink, use this factory method.
* //TODO Should we make the constructor private for MdmLink? or work out some way to ensure they can only be instantiated via factory.
*
* @return A new {@link MdmLink}.
* @return A new {@link IMdmLink}.
*/
public MdmLink newMdmLink() {
public IMdmLink newMdmLink() {
return myMdmLinkFactory.newMdmLink();
}
public Optional<MdmLink> getMatchedOrPossibleMatchedLinkForSource(IAnyResource theResource) {
public Optional<? extends IMdmLink> getMatchedOrPossibleMatchedLinkForSource(IAnyResource theResource) {
// TODO KHS instead of two queries, just do one query with an OR
Optional<MdmLink> retval = getMatchedLinkForSource(theResource);
Optional<? extends IMdmLink> retval = getMatchedLinkForSource(theResource);
if (!retval.isPresent()) {
retval = getPossibleMatchedLinkForSource(theResource);
}
return retval;
}
public Optional<MdmLink> getLinkByGoldenResourceAndSourceResource(@Nullable IAnyResource theGoldenResource, @Nullable IAnyResource theSourceResource) {
public Optional<? extends IMdmLink> getLinkByGoldenResourceAndSourceResource(@Nullable IAnyResource theGoldenResource, @Nullable IAnyResource theSourceResource) {
if (theGoldenResource == null || theSourceResource == null) {
return Optional.empty();
}
return getLinkByGoldenResourcePidAndSourceResourcePid(
myJpaIdHelperService.getPidOrNull(theGoldenResource),
myJpaIdHelperService.getPidOrNull(theSourceResource));
myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theGoldenResource),
myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theSourceResource));
}
@Transactional(propagation = Propagation.MANDATORY)
public void deleteLinksWithAnyReferenceToPids(List<Long> theGoldenResourcePids) {
// Split into chunks of 500 so older versions of Oracle don't run into issues (500 = 1000 / 2 since the dao
// method uses the list twice in the sql predicate)
List<List<Long>> chunks = ListUtils.partition(theGoldenResourcePids, 500);
for (List<Long> chunk : chunks) {
myMdmLinkDao.deleteLinksWithAnyReferenceToPids(chunk);
}
public void deleteLinksWithAnyReferenceToPids(List<ResourcePersistentId> theGoldenResourcePids) {
myMdmLinkDao.deleteLinksWithAnyReferenceToPids(theGoldenResourcePids);
}
}

View File

@ -22,7 +22,8 @@ package ca.uhn.fhir.jpa.mdm.interceptor;
import ca.uhn.fhir.interceptor.api.IInterceptorService;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.interceptor.MdmSearchExpandingInterceptor;
import ca.uhn.fhir.mdm.interceptor.IMdmStorageInterceptor;
import ca.uhn.fhir.mdm.interceptor.MdmSearchExpandingInterceptor;
import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionSubmitInterceptorLoader;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.log.Logs;

View File

@ -21,11 +21,13 @@ package ca.uhn.fhir.jpa.mdm.svc;
*/
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.jpa.mdm.util.MdmPartitionHelper;
import ca.uhn.fhir.mdm.api.IGoldenResourceMergerSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
@ -33,9 +35,11 @@ import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.mdm.util.MessageHelper;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -57,19 +61,15 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc {
@Autowired
IMdmLinkSvc myMdmLinkSvc;
@Autowired
IJpaIdHelperService myIdHelperService;
IIdHelperService myIdHelperService;
@Autowired
MdmResourceDaoSvc myMdmResourceDaoSvc;
@Autowired
MessageHelper myMessageHelper;
@Autowired
MdmPartitionHelper myMdmPartitionHelper;
@Override
@Transactional
public IAnyResource mergeGoldenResources(IAnyResource theFromGoldenResource, IAnyResource theMergedResource, IAnyResource theToGoldenResource, MdmTransactionContext theMdmTransactionContext) {
Long fromGoldenResourcePid = myIdHelperService.getPidOrThrowException(theFromGoldenResource);
Long toGoldenResourcePid = myIdHelperService.getPidOrThrowException(theToGoldenResource);
String resourceType = theMdmTransactionContext.getResourceType();
if (theMergedResource != null) {
@ -92,10 +92,10 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc {
myMdmPartitionHelper.validateResourcesInSamePartition(theFromGoldenResource, theToGoldenResource);
//Merge the links from the FROM to the TO resource. Clean up dangling links.
mergeGoldenResourceLinks(theFromGoldenResource, theToGoldenResource, toGoldenResourcePid, theMdmTransactionContext);
mergeGoldenResourceLinks(theFromGoldenResource, theToGoldenResource, theFromGoldenResource.getIdElement(), theMdmTransactionContext);
//Create the new REDIRECT link
addMergeLink(toGoldenResourcePid, fromGoldenResourcePid, resourceType);
addMergeLink(theToGoldenResource, theFromGoldenResource, resourceType);
//Strip the golden resource tag from the now-deprecated resource.
myMdmResourceDaoSvc.removeGoldenResourceTag(theFromGoldenResource, resourceType);
@ -111,9 +111,9 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc {
return theToGoldenResource;
}
private void addMergeLink(Long theGoldenResourcePidAkaActive, Long theTargetResourcePidAkaDeactivated, String theResourceType) {
MdmLink mdmLink = myMdmLinkDaoSvc
.getOrCreateMdmLinkByGoldenResourcePidAndSourceResourcePid(theGoldenResourcePidAkaActive, theTargetResourcePidAkaDeactivated);
private void addMergeLink(IAnyResource theGoldenResource, IAnyResource theTargetResource, String theResourceType) {
IMdmLink mdmLink = myMdmLinkDaoSvc
.getOrCreateMdmLinkByGoldenResourceAndSourceResource(theGoldenResource, theTargetResource);
mdmLink
.setMdmSourceType(theResourceType)
@ -137,17 +137,18 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc {
* @param theToResourcePid
* @param theMdmTransactionContext
*/
private void mergeGoldenResourceLinks(IAnyResource theFromResource, IAnyResource theToResource, Long theToResourcePid, MdmTransactionContext theMdmTransactionContext) {
List<MdmLink> fromLinks = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(theFromResource); // fromLinks - links going to theFromResource
List<MdmLink> toLinks = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(theToResource); // toLinks - links going to theToResource
List<MdmLink> toDelete = new ArrayList<>();
private void mergeGoldenResourceLinks(IAnyResource theFromResource, IAnyResource theToResource, IIdType theToResourcePid, MdmTransactionContext theMdmTransactionContext) {
List<? extends IMdmLink> fromLinks = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(theFromResource); // fromLinks - links going to theFromResource
List<? extends IMdmLink> toLinks = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(theToResource); // toLinks - links going to theToResource
List<IMdmLink> toDelete = new ArrayList<>();
ResourcePersistentId goldenResourcePid = myIdHelperService.resolveResourcePersistentIds((RequestPartitionId) theToResource.getUserData(Constants.RESOURCE_PARTITION_ID), theToResource.getIdElement().getResourceType(), theToResource.getIdElement().getIdPart());
for (MdmLink fromLink : fromLinks) {
Optional<MdmLink> optionalToLink = findFirstLinkWithMatchingSource(toLinks, fromLink);
for (IMdmLink fromLink : fromLinks) {
Optional<? extends IMdmLink> optionalToLink = findFirstLinkWithMatchingSource(toLinks, fromLink);
if (optionalToLink.isPresent()) {
// The original links already contain this target, so move it over to the toResource
MdmLink toLink = optionalToLink.get();
IMdmLink toLink = optionalToLink.get();
if (fromLink.isManual()) {
switch (toLink.getLinkSource()) {
case AUTO:
@ -167,7 +168,7 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc {
}
}
//2 The original TO links didn't contain this target, so move it over to the toGoldenResource
fromLink.setGoldenResourcePid(theToResourcePid);
fromLink.setGoldenResourcePersistenceId(goldenResourcePid);
ourLog.trace("Saving link {}", fromLink);
myMdmLinkDaoSvc.save(fromLink);
}
@ -175,9 +176,9 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc {
toDelete.forEach(link -> myMdmLinkDaoSvc.deleteLink(link));
}
private Optional<MdmLink> findFirstLinkWithMatchingSource(List<MdmLink> theMdmLinks, MdmLink theLinkWithSourceToMatch) {
private Optional<? extends IMdmLink> findFirstLinkWithMatchingSource(List<? extends IMdmLink> theMdmLinks, IMdmLink theLinkWithSourceToMatch) {
return theMdmLinks.stream()
.filter(mdmLink -> mdmLink.getSourcePid().equals(theLinkWithSourceToMatch.getSourcePid()))
.filter(mdmLink -> mdmLink.getSourcePersistenceId().equals(theLinkWithSourceToMatch.getSourcePersistenceId()))
.findFirst();
}

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.mdm.svc;
*/
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkJson;
/**
@ -34,6 +35,6 @@ public interface IMdmModelConverterSvc {
* @param theLink Link to convert
* @return Returns the converted link
*/
public MdmLinkJson toJson(MdmLink theLink);
public MdmLinkJson toJson(IMdmLink theLink);
}

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.jpa.mdm.svc.candidate.MatchedGoldenResourceCandidate;
import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmGoldenResourceFindingSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
@ -110,8 +111,8 @@ public class MdmEidUpdateService {
}
}
private boolean candidateIsSameAsMdmLinkGoldenResource(MdmLink theExistingMatchLink, MatchedGoldenResourceCandidate theGoldenResourceCandidate) {
return theExistingMatchLink.getGoldenResourcePid().equals(theGoldenResourceCandidate.getCandidateGoldenResourcePid().getIdAsLong());
private boolean candidateIsSameAsMdmLinkGoldenResource(IMdmLink theExistingMatchLink, MatchedGoldenResourceCandidate theGoldenResourceCandidate) {
return theExistingMatchLink.getGoldenResourcePersistenceId().equals(theGoldenResourceCandidate.getCandidateGoldenResourcePid());
}
private void createNewGoldenResourceAndFlagAsDuplicate(IAnyResource theResource, MdmTransactionContext theMdmTransactionContext, IAnyResource theOldGoldenResource) {
@ -162,13 +163,13 @@ public class MdmEidUpdateService {
myHasEidsInCommon = myEIDHelper.hasEidOverlap(myMatchedGoldenResource, theResource);
myIncomingResourceHasAnEid = !myEIDHelper.getExternalEid(theResource).isEmpty();
Optional<MdmLink> theExistingMatchOrPossibleMatchLink = myMdmLinkDaoSvc.getMatchedOrPossibleMatchedLinkForSource(theResource);
Optional<? extends IMdmLink> theExistingMatchOrPossibleMatchLink = myMdmLinkDaoSvc.getMatchedOrPossibleMatchedLinkForSource(theResource);
myExistingGoldenResource = null;
if (theExistingMatchOrPossibleMatchLink.isPresent()) {
MdmLink mdmLink = theExistingMatchOrPossibleMatchLink.get();
Long existingGoldenResourcePid = mdmLink.getGoldenResourcePid();
myExistingGoldenResource = myMdmResourceDaoSvc.readGoldenResourceByPid(new ResourcePersistentId(existingGoldenResourcePid), resourceType);
IMdmLink mdmLink = theExistingMatchOrPossibleMatchLink.get();
ResourcePersistentId existingGoldenResourcePid = mdmLink.getGoldenResourcePersistenceId();
myExistingGoldenResource = myMdmResourceDaoSvc.readGoldenResourceByPid(existingGoldenResourcePid, resourceType);
myRemainsMatchedToSameGoldenResource = candidateIsSameAsMdmLinkGoldenResource(mdmLink, theMatchedGoldenResourceCandidate);
} else {
myRemainsMatchedToSameGoldenResource = false;

View File

@ -21,14 +21,13 @@ package ca.uhn.fhir.jpa.mdm.svc;
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.jpa.mdm.util.MdmPartitionHelper;
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmLinkCreateSvc;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
@ -38,6 +37,7 @@ import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.mdm.util.MessageHelper;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.slf4j.Logger;
@ -54,7 +54,7 @@ public class MdmLinkCreateSvcImpl implements IMdmLinkCreateSvc {
@Autowired
FhirContext myFhirContext;
@Autowired
IJpaIdHelperService myIdHelperService;
IIdHelperService myIdHelperService;
@Autowired
MdmLinkDaoSvc myMdmLinkDaoSvc;
@Autowired
@ -71,23 +71,23 @@ public class MdmLinkCreateSvcImpl implements IMdmLinkCreateSvc {
validateCreateLinkRequest(theGoldenResource, theSourceResource, sourceType);
Long goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
Long targetId = myIdHelperService.getPidOrThrowException(theSourceResource);
ResourcePersistentId goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
ResourcePersistentId targetId = myIdHelperService.getPidOrThrowException(theSourceResource);
// check if the golden resource and the source resource are in the same partition, throw error if not
myMdmPartitionHelper.validateResourcesInSamePartition(theGoldenResource, theSourceResource);
Optional<MdmLink> optionalMdmLink = myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
Optional<? extends IMdmLink> optionalMdmLink = myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
if (optionalMdmLink.isPresent()) {
throw new InvalidRequestException(Msg.code(753) + myMessageHelper.getMessageForPresentLink(theGoldenResource, theSourceResource));
}
List<MdmLink> mdmLinks = myMdmLinkDaoSvc.getMdmLinksBySourcePidAndMatchResult(targetId, MdmMatchResultEnum.MATCH);
List<? extends IMdmLink> mdmLinks = myMdmLinkDaoSvc.getMdmLinksBySourcePidAndMatchResult(targetId, MdmMatchResultEnum.MATCH);
if (mdmLinks.size() > 0 && theMatchResult == MdmMatchResultEnum.MATCH) {
throw new InvalidRequestException(Msg.code(754) + myMessageHelper.getMessageForMultipleGoldenRecords(theSourceResource));
}
MdmLink mdmLink = myMdmLinkDaoSvc.getOrCreateMdmLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
IMdmLink mdmLink = myMdmLinkDaoSvc.getOrCreateMdmLinkByGoldenResourceAndSourceResource(theGoldenResource, theSourceResource);
mdmLink.setLinkSource(MdmLinkSourceEnum.MANUAL);
if (theMatchResult == null) {
mdmLink.setMatchResult(MdmMatchResultEnum.MATCH);

View File

@ -20,8 +20,8 @@ package ca.uhn.fhir.jpa.mdm.svc;
* #L%
*/
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
import ca.uhn.fhir.mdm.api.MdmLinkJson;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
@ -57,7 +57,7 @@ public class MdmLinkQuerySvcImplSvc implements IMdmLinkQuerySvc {
@Override
@Transactional
public Page<MdmLinkJson> queryLinks(IIdType theGoldenResourceId, IIdType theSourceResourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest, List<Integer> thePartitionId) {
Page<MdmLink> mdmLinks = myMdmLinkDaoSvc.executeTypedQuery(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource, thePageRequest, thePartitionId);
Page<? extends IMdmLink> mdmLinks = myMdmLinkDaoSvc.executeTypedQuery(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource, thePageRequest, thePartitionId);
return mdmLinks.map(myMdmModelConverterSvc::toJson);
}
@ -70,7 +70,7 @@ public class MdmLinkQuerySvcImplSvc implements IMdmLinkQuerySvc {
@Override
@Transactional
public Page<MdmLinkJson> getDuplicateGoldenResources(MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest, List<Integer> thePartitionId) {
Page<MdmLink> mdmLinkPage = myMdmLinkDaoSvc.executeTypedQuery(null, null, MdmMatchResultEnum.POSSIBLE_DUPLICATE, null, thePageRequest, thePartitionId);
Page<? extends IMdmLink> mdmLinkPage = myMdmLinkDaoSvc.executeTypedQuery(null, null, MdmMatchResultEnum.POSSIBLE_DUPLICATE, null, thePageRequest, thePartitionId);
return mdmLinkPage.map(myMdmModelConverterSvc::toJson);
}
}

View File

@ -21,9 +21,10 @@ package ca.uhn.fhir.jpa.mdm.svc;
*/
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
@ -33,7 +34,6 @@ import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@ -57,7 +57,7 @@ public class MdmLinkSvcImpl implements IMdmLinkSvc {
@Autowired
private MdmLinkDaoSvc myMdmLinkDaoSvc;
@Autowired
private IJpaIdHelperService myIdHelperService;
private IIdHelperService myIdHelperService;
@Override
@Transactional
@ -74,13 +74,13 @@ public class MdmLinkSvcImpl implements IMdmLinkSvc {
validateRequestIsLegal(theGoldenResource, theSourceResource, matchResultEnum, theLinkSource);
myMdmResourceDaoSvc.upsertGoldenResource(theGoldenResource, theMdmTransactionContext.getResourceType());
MdmLink link = createOrUpdateLinkEntity(theGoldenResource, theSourceResource, theMatchOutcome, theLinkSource, theMdmTransactionContext);
IMdmLink link = createOrUpdateLinkEntity(theGoldenResource, theSourceResource, theMatchOutcome, theLinkSource, theMdmTransactionContext);
theMdmTransactionContext.addMdmLink(link);
}
private boolean goldenResourceLinkedAsNoMatch(IAnyResource theGoldenResource, IAnyResource theSourceResource) {
Long goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
Long sourceId = myIdHelperService.getPidOrThrowException(theSourceResource);
ResourcePersistentId goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
ResourcePersistentId sourceId = myIdHelperService.getPidOrThrowException(theSourceResource);
// TODO perf collapse into one query
return myMdmLinkDaoSvc.getMdmLinksByGoldenResourcePidSourcePidAndMatchResult(goldenResourceId, sourceId, MdmMatchResultEnum.NO_MATCH).isPresent() ||
myMdmLinkDaoSvc.getMdmLinksByGoldenResourcePidSourcePidAndMatchResult(sourceId, goldenResourceId, MdmMatchResultEnum.NO_MATCH).isPresent();
@ -91,9 +91,9 @@ public class MdmLinkSvcImpl implements IMdmLinkSvc {
if (theGoldenResource == null) {
return;
}
Optional<MdmLink> optionalMdmLink = getMdmLinkForGoldenResourceSourceResourcePair(theGoldenResource, theSourceResource);
Optional<? extends IMdmLink> optionalMdmLink = getMdmLinkForGoldenResourceSourceResourcePair(theGoldenResource, theSourceResource);
if (optionalMdmLink.isPresent()) {
MdmLink mdmLink = optionalMdmLink.get();
IMdmLink mdmLink = optionalMdmLink.get();
log(theMdmTransactionContext, "Deleting MdmLink [" + theGoldenResource.getIdElement().toVersionless() + " -> " + theSourceResource.getIdElement().toVersionless() + "] with result: " + mdmLink.getMatchResult());
myMdmLinkDaoSvc.deleteLink(mdmLink);
theMdmTransactionContext.addMdmLink(mdmLink);
@ -103,15 +103,14 @@ public class MdmLinkSvcImpl implements IMdmLinkSvc {
@Override
@Transactional
public void deleteLinksWithAnyReferenceTo(List<ResourcePersistentId> theGoldenResourceIds) {
List<Long> goldenResourcePids = theGoldenResourceIds.stream().map(ResourcePersistentId::getIdAsLong).collect(Collectors.toList());
myMdmLinkDaoSvc.deleteLinksWithAnyReferenceToPids(goldenResourcePids);
myMdmLinkDaoSvc.deleteLinksWithAnyReferenceToPids(theGoldenResourceIds);
}
/**
* Helper function which runs various business rules about what types of requests are allowed.
*/
private void validateRequestIsLegal(IAnyResource theGoldenResource, IAnyResource theResource, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource) {
Optional<MdmLink> oExistingLink = getMdmLinkForGoldenResourceSourceResourcePair(theGoldenResource, theResource);
Optional<? extends IMdmLink> oExistingLink = getMdmLinkForGoldenResourceSourceResourcePair(theGoldenResource, theResource);
if (oExistingLink.isPresent() && systemIsAttemptingToModifyManualLink(theLinkSource, oExistingLink.get())) {
throw new InternalErrorException(Msg.code(760) + "MDM system is not allowed to modify links on manually created links");
}
@ -131,19 +130,22 @@ public class MdmLinkSvcImpl implements IMdmLinkSvc {
/**
* Helper function to let us catch when System MDM rules are attempting to override a manually defined link.
*/
private boolean systemIsAttemptingToModifyManualLink(MdmLinkSourceEnum theIncomingSource, MdmLink theExistingSource) {
private boolean systemIsAttemptingToModifyManualLink(MdmLinkSourceEnum theIncomingSource, IMdmLink theExistingSource) {
return theIncomingSource == MdmLinkSourceEnum.AUTO && theExistingSource.isManual();
}
private Optional<MdmLink> getMdmLinkForGoldenResourceSourceResourcePair(@Nonnull IAnyResource theGoldenResource, @Nonnull IAnyResource theCandidate) {
private Optional<? extends IMdmLink> getMdmLinkForGoldenResourceSourceResourcePair(@Nonnull IAnyResource theGoldenResource, @Nonnull IAnyResource theCandidate) {
if (theGoldenResource.getIdElement().getIdPart() == null || theCandidate.getIdElement().getIdPart() == null) {
return Optional.empty();
} else {
return myMdmLinkDaoSvc.getLinkByGoldenResourceAndSourceResource(theGoldenResource, theCandidate);
return myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(
myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theGoldenResource),
myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theCandidate)
);
}
}
private MdmLink createOrUpdateLinkEntity(IBaseResource theGoldenResource, IBaseResource theSourceResource, MdmMatchOutcome theMatchOutcome, MdmLinkSourceEnum theLinkSource, MdmTransactionContext theMdmTransactionContext) {
private IMdmLink createOrUpdateLinkEntity(IAnyResource theGoldenResource, IAnyResource theSourceResource, MdmMatchOutcome theMatchOutcome, MdmLinkSourceEnum theLinkSource, MdmTransactionContext theMdmTransactionContext) {
return myMdmLinkDaoSvc.createOrUpdateLinkEntity(theGoldenResource, theSourceResource, theMatchOutcome, theLinkSource, theMdmTransactionContext);
}

View File

@ -22,15 +22,12 @@ package ca.uhn.fhir.jpa.mdm.svc;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.jpa.mdm.util.MdmPartitionHelper;
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
import ca.uhn.fhir.mdm.api.IMdmSettings;
@ -42,6 +39,7 @@ import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.mdm.util.MessageHelper;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
import org.hl7.fhir.instance.model.api.IAnyResource;
@ -59,7 +57,7 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
@Autowired
FhirContext myFhirContext;
@Autowired
IJpaIdHelperService myIdHelperService;
IIdHelperService myIdHelperService;
@Autowired
MdmLinkDaoSvc myMdmLinkDaoSvc;
@Autowired
@ -84,18 +82,18 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
validateUpdateLinkRequest(theGoldenResource, theSourceResource, theMatchResult, sourceType);
Long goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
Long targetId = myIdHelperService.getPidOrThrowException(theSourceResource);
ResourcePersistentId goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
ResourcePersistentId targetId = myIdHelperService.getPidOrThrowException(theSourceResource);
// check if the golden resource and the source resource are in the same partition, throw error if not
myMdmPartitionHelper.validateResourcesInSamePartition(theGoldenResource, theSourceResource);
Optional<MdmLink> optionalMdmLink = myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
Optional<? extends IMdmLink> optionalMdmLink = myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
if (!optionalMdmLink.isPresent()) {
throw new InvalidRequestException(Msg.code(738) + myMessageHelper.getMessageForNoLink(theGoldenResource, theSourceResource));
}
MdmLink mdmLink = optionalMdmLink.get();
IMdmLink mdmLink = optionalMdmLink.get();
if (mdmLink.getMatchResult() == theMatchResult) {
ourLog.warn("MDM Link for " + theGoldenResource.getIdElement().toVersionless() + ", " + theSourceResource.getIdElement().toVersionless() + " already has value " + theMatchResult + ". Nothing to do.");
return theGoldenResource;
@ -160,15 +158,15 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
public void notDuplicateGoldenResource(IAnyResource theGoldenResource, IAnyResource theTargetGoldenResource, MdmTransactionContext theMdmContext) {
validateNotDuplicateGoldenResourceRequest(theGoldenResource, theTargetGoldenResource);
Long goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
Long targetId = myIdHelperService.getPidOrThrowException(theTargetGoldenResource);
ResourcePersistentId goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
ResourcePersistentId targetId = myIdHelperService.getPidOrThrowException(theTargetGoldenResource);
Optional<MdmLink> oMdmLink = myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
Optional<? extends IMdmLink> oMdmLink = myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
if (!oMdmLink.isPresent()) {
throw new InvalidRequestException(Msg.code(745) + "No link exists between " + theGoldenResource.getIdElement().toVersionless() + " and " + theTargetGoldenResource.getIdElement().toVersionless());
}
MdmLink mdmLink = oMdmLink.get();
IMdmLink mdmLink = oMdmLink.get();
if (!mdmLink.isPossibleDuplicate()) {
throw new InvalidRequestException(Msg.code(746) + theGoldenResource.getIdElement().toVersionless() + " and " + theTargetGoldenResource.getIdElement().toVersionless() + " are not linked as POSSIBLE_DUPLICATE.");
}

View File

@ -30,6 +30,7 @@ import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.TransactionLogMessages;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.slf4j.Logger;
@ -92,9 +93,9 @@ public class MdmMatchLinkSvc {
private void handleMdmWithMultipleCandidates(IAnyResource theResource, CandidateList theCandidateList, MdmTransactionContext theMdmTransactionContext) {
MatchedGoldenResourceCandidate firstMatch = theCandidateList.getFirstMatch();
Long sampleGoldenResourcePid = firstMatch.getCandidateGoldenResourcePid().getIdAsLong();
ResourcePersistentId sampleGoldenResourcePid = firstMatch.getCandidateGoldenResourcePid();
boolean allSameGoldenResource = theCandidateList.stream()
.allMatch(candidate -> candidate.getCandidateGoldenResourcePid().getIdAsLong().equals(sampleGoldenResourcePid));
.allMatch(candidate -> candidate.getCandidateGoldenResourcePid().equals(sampleGoldenResourcePid));
if (allSameGoldenResource) {
log(theMdmTransactionContext, "MDM received multiple match candidates, but they are all linked to the same Golden Resource.");

View File

@ -20,22 +20,22 @@ package ca.uhn.fhir.jpa.mdm.svc;
* #L%
*/
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkJson;
import org.springframework.beans.factory.annotation.Autowired;
public class MdmModelConverterSvcImpl implements IMdmModelConverterSvc {
@Autowired
IJpaIdHelperService myIdHelperService;
IIdHelperService myIdHelperService;
@Override
public MdmLinkJson toJson(MdmLink theLink) {
public MdmLinkJson toJson(IMdmLink theLink) {
MdmLinkJson retVal = new MdmLinkJson();
String sourceId = myIdHelperService.resourceIdFromPidOrThrowException(theLink.getSourcePid()).toVersionless().getValue();
String sourceId = myIdHelperService.resourceIdFromPidOrThrowException(theLink.getSourcePersistenceId(), theLink.getMdmSourceType()).toVersionless().getValue();
retVal.setSourceId(sourceId);
String goldenResourceId = myIdHelperService.resourceIdFromPidOrThrowException(theLink.getGoldenResourcePid()).toVersionless().getValue();
String goldenResourceId = myIdHelperService.resourceIdFromPidOrThrowException(theLink.getGoldenResourcePersistenceId(), theLink.getMdmSourceType()).toVersionless().getValue();
retVal.setGoldenResourceId(goldenResourceId);
retVal.setCreated(theLink.getCreated());
retVal.setEidMatch(theLink.getEidMatch());

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.rules.json.MdmResourceSearchParamJson;
import ca.uhn.fhir.mdm.svc.MdmSearchParamSvc;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.slf4j.Logger;

View File

@ -20,7 +20,7 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
* #L%
*/
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.springframework.beans.factory.annotation.Autowired;
@ -29,7 +29,7 @@ import java.util.List;
public abstract class BaseCandidateFinder {
@Autowired
IJpaIdHelperService myIdHelperService;
IIdHelperService myIdHelperService;
@Autowired
MdmLinkDaoSvc myMdmLinkDaoSvc;

View File

@ -23,7 +23,7 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.mdm.svc.MdmSearchParamSvc;
import ca.uhn.fhir.mdm.svc.MdmSearchParamSvc;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.mdm.api.IMdmSettings;

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.jpa.mdm.svc.MdmResourceDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.CanonicalEID;
@ -65,9 +66,10 @@ public class FindCandidateByEidSvc extends BaseCandidateFinder {
if (isNoMatch(foundGoldenResource, theIncomingResource)) {
continue;
}
Long pidOrNull = myIdHelperService.getPidOrNull(foundGoldenResource);
MatchedGoldenResourceCandidate mpc = new MatchedGoldenResourceCandidate(new ResourcePersistentId(pidOrNull), MdmMatchOutcome.EID_MATCH);
ResourcePersistentId pidOrNull = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), foundGoldenResource);
MatchedGoldenResourceCandidate mpc = new MatchedGoldenResourceCandidate(pidOrNull, MdmMatchOutcome.EID_MATCH);
ourLog.debug("Incoming Resource {} matched Golden Resource {} by EID {}", theIncomingResource.getIdElement().toUnqualifiedVersionless(), foundGoldenResource.getIdElement().toUnqualifiedVersionless(), eid);
retval.add(mpc);
}
}
@ -76,11 +78,11 @@ public class FindCandidateByEidSvc extends BaseCandidateFinder {
}
private boolean isNoMatch(IAnyResource theGoldenResource, IAnyResource theSourceResource) {
Optional<MdmLink> oLink = myMdmLinkDaoSvc.getLinkByGoldenResourceAndSourceResource(theGoldenResource, theSourceResource);
Optional<? extends IMdmLink> oLink = myMdmLinkDaoSvc.getLinkByGoldenResourceAndSourceResource(theGoldenResource, theSourceResource);
if (oLink.isEmpty()) {
return false;
}
MdmLink link = oLink.get();
MdmLink link = (MdmLink) oLink.get();
return link.isNoMatch();
}

View File

@ -22,9 +22,9 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmMatchFinderSvc;
import ca.uhn.fhir.mdm.api.MatchedTarget;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
@ -46,7 +46,7 @@ import java.util.stream.Collectors;
public class FindCandidateByExampleSvc extends BaseCandidateFinder {
private static final Logger ourLog = Logs.getMdmTroubleshootingLog();
@Autowired
IJpaIdHelperService myIdHelperService;
IIdHelperService myIdHelperService;
@Autowired
private FhirContext myFhirContext;
@Autowired
@ -66,7 +66,7 @@ public class FindCandidateByExampleSvc extends BaseCandidateFinder {
protected List<MatchedGoldenResourceCandidate> findMatchGoldenResourceCandidates(IAnyResource theTarget) {
List<MatchedGoldenResourceCandidate> retval = new ArrayList<>();
List<Long> goldenResourcePidsToExclude = getNoMatchGoldenResourcePids(theTarget);
List<ResourcePersistentId> goldenResourcePidsToExclude = getNoMatchGoldenResourcePids(theTarget);
List<MatchedTarget> matchedCandidates = myMdmMatchFinderSvc.getMatchedTargets(myFhirContext.getResourceType(theTarget), theTarget, (RequestPartitionId) theTarget.getUserData(Constants.RESOURCE_PARTITION_ID));
@ -78,8 +78,7 @@ public class FindCandidateByExampleSvc extends BaseCandidateFinder {
List<String> skippedLogMessages = new ArrayList<>();
List<String> matchedLogMessages = new ArrayList<>();
for (MatchedTarget match : matchedCandidates) {
Optional<MdmLink> optionalMdmLink = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(myIdHelperService.getPidOrNull(match.getTarget()));
Optional<? extends IMdmLink> optionalMdmLink = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), match.getTarget()));
if (!optionalMdmLink.isPresent()) {
if (ourLog.isDebugEnabled()) {
skippedLogMessages.add(String.format("%s does not link to a Golden Resource (it may be a Golden Resource itself). Removing candidate.", match.getTarget().getIdElement().toUnqualifiedVersionless()));
@ -87,16 +86,19 @@ public class FindCandidateByExampleSvc extends BaseCandidateFinder {
continue;
}
MdmLink matchMdmLink = optionalMdmLink.get();
if (goldenResourcePidsToExclude.contains(matchMdmLink.getGoldenResourcePid())) {
skippedLogMessages.add(String.format("Skipping MDM on candidate Golden Resource with PID %s due to manual NO_MATCH", matchMdmLink.getGoldenResourcePid()));
IMdmLink matchMdmLink = optionalMdmLink.get();
if (goldenResourcePidsToExclude.contains(matchMdmLink.getGoldenResourcePersistenceId())) {
skippedLogMessages.add(String.format("Skipping MDM on candidate Golden Resource with PID %s due to manual NO_MATCH", matchMdmLink.getGoldenResourcePersistenceId().toString()));
continue;
}
MatchedGoldenResourceCandidate candidate = new MatchedGoldenResourceCandidate(getResourcePersistentId(matchMdmLink.getGoldenResourcePid()), match.getMatchResult());
MatchedGoldenResourceCandidate candidate = new MatchedGoldenResourceCandidate(matchMdmLink.getGoldenResourcePersistenceId(), match.getMatchResult());
if (ourLog.isDebugEnabled()) {
matchedLogMessages.add(String.format("Navigating from matched resource %s to its Golden Resource %s", match.getTarget().getIdElement().toUnqualifiedVersionless(), matchMdmLink.getGoldenResource().getIdDt().toUnqualifiedVersionless()));
matchedLogMessages.add(String.format("Navigating from matched resource %s to its Golden Resource %s", match.getTarget().getIdElement().toUnqualifiedVersionless(), matchMdmLink.getGoldenResourcePersistenceId().toString()));
}
retval.add(candidate);
}
@ -111,18 +113,14 @@ public class FindCandidateByExampleSvc extends BaseCandidateFinder {
return retval;
}
private List<Long> getNoMatchGoldenResourcePids(IBaseResource theBaseResource) {
Long targetPid = myIdHelperService.getPidOrNull(theBaseResource);
private List<ResourcePersistentId> getNoMatchGoldenResourcePids(IBaseResource theBaseResource) {
ResourcePersistentId targetPid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theBaseResource);
return myMdmLinkDaoSvc.getMdmLinksBySourcePidAndMatchResult(targetPid, MdmMatchResultEnum.NO_MATCH)
.stream()
.map(MdmLink::getGoldenResourcePid)
.map(IMdmLink::getGoldenResourcePersistenceId)
.collect(Collectors.toList());
}
private ResourcePersistentId getResourcePersistentId(Long theGoldenResourcePid) {
return new ResourcePersistentId(theGoldenResourcePid);
}
@Override
protected CandidateStrategyEnum getStrategy() {
return CandidateStrategyEnum.SCORE;

View File

@ -20,7 +20,9 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
* #L%
*/
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hl7.fhir.instance.model.api.IAnyResource;
@ -45,11 +47,11 @@ public class FindCandidateByLinkSvc extends BaseCandidateFinder {
protected List<MatchedGoldenResourceCandidate> findMatchGoldenResourceCandidates(IAnyResource theTarget) {
List<MatchedGoldenResourceCandidate> retval = new ArrayList<>();
Long targetPid = myIdHelperService.getPidOrNull(theTarget);
ResourcePersistentId targetPid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theTarget);
if (targetPid != null) {
Optional<MdmLink> oLink = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(targetPid);
Optional<? extends IMdmLink> oLink = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(targetPid);
if (oLink.isPresent()) {
ResourcePersistentId goldenResourcePid = new ResourcePersistentId(oLink.get().getGoldenResourcePid());
ResourcePersistentId goldenResourcePid = new ResourcePersistentId(oLink.get().getGoldenResourcePersistenceId().getIdAsLong());
ourLog.debug("Resource previously linked. Using existing link.");
retval.add(new MatchedGoldenResourceCandidate(goldenResourcePid, oLink.get()));
}

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
* #L%
*/
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
@ -34,7 +35,7 @@ public class MatchedGoldenResourceCandidate {
myMdmMatchOutcome = theMdmMatchOutcome;
}
public MatchedGoldenResourceCandidate(ResourcePersistentId theGoldenResourcePid, MdmLink theMdmLink) {
public MatchedGoldenResourceCandidate(ResourcePersistentId theGoldenResourcePid, IMdmLink theMdmLink) {
myCandidateGoldenResourcePid = theGoldenResourcePid;
myMdmMatchOutcome = new MdmMatchOutcome(theMdmLink.getVector(), theMdmLink.getScore()).setMatchResultEnum(theMdmLink.getMatchResult());
}

View File

@ -21,7 +21,7 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
*/
import ca.uhn.fhir.mdm.rules.json.MdmResourceSearchParamJson;
import ca.uhn.fhir.jpa.mdm.svc.MdmSearchParamSvc;
import ca.uhn.fhir.mdm.svc.MdmSearchParamSvc;
import ca.uhn.fhir.util.UrlUtil;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.springframework.beans.factory.annotation.Autowired;

View File

@ -20,14 +20,15 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
* #L%
*/
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.rules.json.MdmFilterSearchParamJson;
import ca.uhn.fhir.mdm.rules.json.MdmResourceSearchParamJson;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger;
@ -54,7 +55,7 @@ public class MdmCandidateSearchSvc {
@Autowired
private IMdmSettings myMdmSettings;
@Autowired
private IJpaIdHelperService myJpaIdHelperService;
private IIdHelperService myIdHelperService;
@Autowired
private MdmCandidateSearchCriteriaBuilderSvc myMdmCandidateSearchCriteriaBuilderSvc;
@Autowired
@ -74,7 +75,7 @@ public class MdmCandidateSearchSvc {
*/
@Transactional
public Collection<IAnyResource> findCandidates(String theResourceType, IAnyResource theResource, RequestPartitionId theRequestPartitionId) {
Map<Long, IAnyResource> matchedPidsToResources = new HashMap<>();
Map<ResourcePersistentId, IAnyResource> matchedPidsToResources = new HashMap<>();
List<MdmFilterSearchParamJson> filterSearchParams = myMdmSettings.getMdmRules().getCandidateFilterSearchParams();
List<String> filterCriteria = buildFilterQuery(filterSearchParams, theResourceType);
List<MdmResourceSearchParamJson> candidateSearchParams = myMdmSettings.getMdmRules().getCandidateSearchParams();
@ -97,7 +98,7 @@ public class MdmCandidateSearchSvc {
// Sometimes, we are running this function on a resource that has not yet been persisted,
// so it may not have an ID yet, precluding the need to remove it.
if (theResource.getIdElement().getIdPart() != null) {
if (matchedPidsToResources.remove(myJpaIdHelperService.getPidOrNull(theResource)) != null) {
if (matchedPidsToResources.remove(myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theResource)) != null) {
ourLog.debug("Removing incoming resource {} from list of candidates.", theResource.getIdElement().toUnqualifiedVersionless());
}
}
@ -119,7 +120,7 @@ public class MdmCandidateSearchSvc {
* 4. Store all results in `theMatchedPidsToResources`
*/
@SuppressWarnings("rawtypes")
private void searchForIdsAndAddToMap(String theResourceType, IAnyResource theResource, Map<Long, IAnyResource> theMatchedPidsToResources, List<String> theFilterCriteria, MdmResourceSearchParamJson resourceSearchParam, RequestPartitionId theRequestPartitionId) {
private void searchForIdsAndAddToMap(String theResourceType, IAnyResource theResource, Map<ResourcePersistentId, IAnyResource> theMatchedPidsToResources, List<String> theFilterCriteria, MdmResourceSearchParamJson resourceSearchParam, RequestPartitionId theRequestPartitionId) {
//1.
Optional<String> oResourceCriteria = myMdmCandidateSearchCriteriaBuilderSvc.buildResourceQueryString(theResourceType, theResource, theFilterCriteria, resourceSearchParam);
if (!oResourceCriteria.isPresent()) {
@ -138,7 +139,7 @@ public class MdmCandidateSearchSvc {
int initialSize = theMatchedPidsToResources.size();
//4.
resources.forEach(resource -> theMatchedPidsToResources.put(myJpaIdHelperService.getPidOrNull(resource), (IAnyResource) resource));
resources.forEach(resource -> theMatchedPidsToResources.put(myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), resource), (IAnyResource) resource));
int newSize = theMatchedPidsToResources.size();

View File

@ -5,8 +5,7 @@ import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkDao;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.config.MdmConsumerConfig;
import ca.uhn.fhir.jpa.mdm.config.MdmSubmitterConfig;
@ -26,10 +25,12 @@ import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryImpl;
import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig;
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.MdmConstants;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.rules.svc.MdmResourceMatcherSvc;
import ca.uhn.fhir.mdm.util.EIDHelper;
@ -116,7 +117,7 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
@Autowired
protected MdmLinkDaoSvc myMdmLinkDaoSvc;
@Autowired
protected IJpaIdHelperService myIdHelperService;
protected IIdHelperService myIdHelperService;
@Autowired
protected IMdmSettings myMdmSettings;
@Autowired
@ -365,18 +366,18 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
String resourceType = theBaseResource.getIdElement().getResourceType();
IFhirResourceDao relevantDao = myDaoRegistry.getResourceDao(resourceType);
Optional<MdmLink> matchedLinkForTargetPid = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(runInTransaction(() -> myIdHelperService.getPidOrNull(theBaseResource)));
Optional<? extends IMdmLink> matchedLinkForTargetPid = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(runInTransaction(() -> myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theBaseResource)));
if (matchedLinkForTargetPid.isPresent()) {
Long goldenResourcePid = matchedLinkForTargetPid.get().getGoldenResourcePid();
Long goldenResourcePid = matchedLinkForTargetPid.get().getGoldenResourcePersistenceId().getIdAsLong();
return (T) relevantDao.readByPid(new ResourcePersistentId(goldenResourcePid));
} else {
return null;
}
}
protected <T extends IBaseResource> T getTargetResourceFromMdmLink(MdmLink theMdmLink, String theResourceType) {
protected <T extends IBaseResource> T getTargetResourceFromMdmLink(IMdmLink theMdmLink, String theResourceType) {
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theResourceType);
return (T) resourceDao.readByPid(new ResourcePersistentId(theMdmLink.getGoldenResourcePid()));
return (T) resourceDao.readByPid(new ResourcePersistentId(theMdmLink.getGoldenResourcePersistenceId().getIdAsLong()));
}
protected Patient addExternalEID(Patient thePatient, String theEID) {
@ -545,11 +546,11 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
Patient sourcePatient = createGoldenPatient();
Patient patient = createPatient();
MdmLink mdmLink = myMdmLinkDaoSvc.newMdmLink();
MdmLink mdmLink = (MdmLink) myMdmLinkDaoSvc.newMdmLink();
mdmLink.setLinkSource(MdmLinkSourceEnum.MANUAL);
mdmLink.setMatchResult(MdmMatchResultEnum.MATCH);
mdmLink.setGoldenResourcePid(runInTransaction(() -> myIdHelperService.getPidOrNull(sourcePatient)));
mdmLink.setSourcePid(runInTransaction(() -> myIdHelperService.getPidOrNull(patient)));
mdmLink.setGoldenResourcePersistenceId(runInTransaction(() -> myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), sourcePatient)));
mdmLink.setSourcePersistenceId(runInTransaction(() -> myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), patient)));
return mdmLink;
}

View File

@ -1,5 +1,7 @@
package ca.uhn.fhir.jpa.mdm.config;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.dao.JpaMdmLinkImplFactory;
import ca.uhn.fhir.jpa.mdm.helper.MdmLinkHelper;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.rules.config.MdmRuleValidator;

View File

@ -1,8 +1,10 @@
package ca.uhn.fhir.jpa.mdm.config;
import ca.uhn.fhir.jpa.mdm.dao.JpaMdmLinkImplFactory;
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperR4;
import ca.uhn.fhir.jpa.subscription.channel.config.SubscriptionChannelConfig;
import ca.uhn.fhir.jpa.subscription.submit.config.SubscriptionSubmitterConfig;
import ca.uhn.fhir.mdm.dao.IMdmLinkImplFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;

View File

@ -1,16 +1,18 @@
package ca.uhn.fhir.jpa.mdm.dao;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkDao;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.rules.json.MdmRulesJson;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkJpaRepository;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.jpa.util.TestUtil;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.model.MdmPidTuple;
import ca.uhn.fhir.mdm.rules.json.MdmRulesJson;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.ArrayList;
import java.util.Date;
@ -22,7 +24,6 @@ import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.in;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isIn;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -44,17 +45,17 @@ public class MdmLinkDaoSvcTest extends BaseMdmR4Test {
@Test
public void testUpdate() {
MdmLink createdLink = myMdmLinkDaoSvc.save(createResourcesAndBuildTestMDMLink());
IMdmLink createdLink = myMdmLinkDaoSvc.save(createResourcesAndBuildTestMDMLink());
assertThat(createdLink.getLinkSource(), is(MdmLinkSourceEnum.MANUAL));
TestUtil.sleepOneClick();
createdLink.setLinkSource(MdmLinkSourceEnum.AUTO);
MdmLink updatedLink = myMdmLinkDaoSvc.save(createdLink);
IMdmLink updatedLink = myMdmLinkDaoSvc.save(createdLink);
assertNotEquals(updatedLink.getCreated(), updatedLink.getUpdated());
}
@Test
public void testNew() {
MdmLink newLink = myMdmLinkDaoSvc.newMdmLink();
IMdmLink newLink = myMdmLinkDaoSvc.newMdmLink();
MdmRulesJson rules = myMdmSettings.getMdmRules();
assertEquals("1", rules.getVersion());
assertEquals(rules.getVersion(), newLink.getVersion());
@ -79,28 +80,28 @@ public class MdmLinkDaoSvcTest extends BaseMdmR4Test {
List<Long> expectedExpandedPids = mdmLinks.stream().map(MdmLink::getSourcePid).collect(Collectors.toList());
//SUT
List<IMdmLinkDao.MdmPidTuple> lists = myMdmLinkDao.expandPidsBySourcePidAndMatchResult(mdmLinks.get(0).getSourcePid(), MdmMatchResultEnum.MATCH);
List<MdmPidTuple> lists = myMdmLinkDao.expandPidsBySourcePidAndMatchResult(new ResourcePersistentId(mdmLinks.get(0).getSourcePid()), MdmMatchResultEnum.MATCH);
assertThat(lists, hasSize(10));
lists.stream()
.forEach(tuple -> {
assertThat(tuple.getGoldenPid(), is(equalTo(golden.getIdElement().getIdPartAsLong())));
assertThat(tuple.getSourcePid(), is(in(expectedExpandedPids)));
assertThat(tuple.getGoldenPid().getIdAsLong(), is(equalTo(golden.getIdElement().getIdPartAsLong())));
assertThat(tuple.getSourcePid().getIdAsLong(), is(in(expectedExpandedPids)));
});
}
private MdmLink createPatientAndLinkTo(Long thePatientPid, MdmMatchResultEnum theMdmMatchResultEnum) {
Patient patient = createPatient();
MdmLink mdmLink = myMdmLinkDaoSvc.newMdmLink();
MdmLink mdmLink = (MdmLink) myMdmLinkDaoSvc.newMdmLink();
mdmLink.setLinkSource(MdmLinkSourceEnum.MANUAL);
mdmLink.setMatchResult(theMdmMatchResultEnum);
mdmLink.setCreated(new Date());
mdmLink.setUpdated(new Date());
mdmLink.setGoldenResourcePid(thePatientPid);
mdmLink.setSourcePid(runInTransaction(()->myIdHelperService.getPidOrNull(patient)));
MdmLink saved= myMdmLinkDao.save(mdmLink);
mdmLink.setGoldenResourcePersistenceId(new ResourcePersistentId(thePatientPid));
mdmLink.setSourcePersistenceId(runInTransaction(()->myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), patient)));
MdmLink saved= (MdmLink) myMdmLinkDao.save(mdmLink);
return saved;
}
}

View File

@ -1,6 +1,6 @@
package ca.uhn.fhir.jpa.mdm.helper;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkDao;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkJpaRepository;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.model.primitive.IdDt;
import org.slf4j.Logger;
@ -16,7 +16,7 @@ public class MdmLinkHelper {
private static final Logger ourLog = LoggerFactory.getLogger(MdmLinkHelper.class);
@Autowired
IMdmLinkDao myMdmLinkDao;
IMdmLinkJpaRepository myMdmLinkDao;
@Transactional
public void logMdmLinks() {

View File

@ -104,7 +104,7 @@ public class MdmEventIT extends BaseMdmR4Test {
private MdmLink getLinkByTargetId(IBaseResource theResource) {
MdmLink example = new MdmLink();
example.setSourcePid(theResource.getIdElement().getIdPartAsLong());
return myMdmLinkDao.findAll(Example.of(example)).get(0);
return (MdmLink) myMdmLinkDao.findAll(Example.of(example)).get(0);
}
@Test

View File

@ -8,6 +8,7 @@ import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.interceptor.IMdmStorageInterceptor;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.hl7.fhir.r4.model.Patient;
@ -16,8 +17,6 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -28,7 +27,7 @@ public class MdmExpungeTest extends BaseMdmR4Test {
@Autowired
IInterceptorService myInterceptorService;
@Autowired
IMdmStorageInterceptor myMdmStorageInterceptor;
IMdmStorageInterceptor myMdmStorageInterceptor;
@Autowired
DaoConfig myDaoConfig;
private ResourceTable myTargetEntity;
@ -43,7 +42,7 @@ public class MdmExpungeTest extends BaseMdmR4Test {
myTargetId = myTargetEntity.getIdDt().toVersionless();
mySourceEntity = (ResourceTable) myPatientDao.create(new Patient()).getEntity();
MdmLink mdmLink = myMdmLinkDaoSvc.newMdmLink();
MdmLink mdmLink = (MdmLink) myMdmLinkDaoSvc.newMdmLink();
mdmLink.setLinkSource(MdmLinkSourceEnum.MANUAL);
mdmLink.setMatchResult(MdmMatchResultEnum.MATCH);
mdmLink.setGoldenResourcePid(mySourceEntity.getId());

View File

@ -1,12 +1,14 @@
package ca.uhn.fhir.jpa.mdm.interceptor;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperConfig;
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperR4;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.model.CanonicalEID;
import ca.uhn.fhir.mdm.rules.config.MdmSettings;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
@ -57,7 +59,7 @@ public class MdmStorageInterceptorIT extends BaseMdmR4Test {
@Autowired
public MdmHelperR4 myMdmHelper;
@Autowired
private IJpaIdHelperService myIdHelperService;
private IIdHelperService myIdHelperService;
@Override
@ -74,7 +76,7 @@ public class MdmStorageInterceptorIT extends BaseMdmR4Test {
private MdmLink getLinkByTargetId(IBaseResource theResource) {
MdmLink example = new MdmLink();
example.setSourcePid(theResource.getIdElement().getIdPartAsLong());
return myMdmLinkDao.findAll(Example.of(example)).get(0);
return (MdmLink) myMdmLinkDao.findAll(Example.of(example)).get(0);
}
@Test
@ -210,8 +212,8 @@ public class MdmStorageInterceptorIT extends BaseMdmR4Test {
patient.setId(patientId);
// Updating a Golden Resource Patient who was created via MDM should fail.
MdmLink mdmLink = runInTransaction(() -> myMdmLinkDaoSvc.getMatchedLinkForSourcePid(myIdHelperService.getPidOrNull(patient)).orElseThrow(() -> new IllegalStateException()));
Long sourcePatientPid = mdmLink.getGoldenResourcePid();
IMdmLink mdmLink = runInTransaction(() -> myMdmLinkDaoSvc.getMatchedLinkForSourcePid(myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), patient)).orElseThrow(() -> new IllegalStateException()));
Long sourcePatientPid = mdmLink.getGoldenResourcePersistenceId().getIdAsLong();
Patient goldenResourcePatient = myPatientDao.readByPid(new ResourcePersistentId(sourcePatientPid));
goldenResourcePatient.setGender(Enumerations.AdministrativeGender.MALE);
try {

View File

@ -1,10 +1,12 @@
package ca.uhn.fhir.jpa.mdm.matcher;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hamcrest.TypeSafeMatcher;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.slf4j.Logger;
@ -21,42 +23,44 @@ public abstract class BaseGoldenResourceMatcher extends TypeSafeMatcher<IAnyReso
private static final Logger ourLog = LoggerFactory.getLogger(BaseGoldenResourceMatcher.class);
protected IJpaIdHelperService myIdHelperService;
protected IIdHelperService myIdHelperService;
protected MdmLinkDaoSvc myMdmLinkDaoSvc;
protected Collection<IAnyResource> myBaseResources;
protected String myTargetType;
protected BaseGoldenResourceMatcher(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
protected BaseGoldenResourceMatcher(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
myIdHelperService = theIdHelperService;
myMdmLinkDaoSvc = theMdmLinkDaoSvc;
myBaseResources = Arrays.stream(theBaseResource).collect(Collectors.toList());
}
@Nullable
protected Long getMatchedResourcePidFromResource(IAnyResource theResource) {
Long retval;
protected ResourcePersistentId getMatchedResourcePidFromResource(IAnyResource theResource) {
ResourcePersistentId retval;
boolean isGoldenRecord = MdmResourceUtil.isMdmManaged(theResource);
if (isGoldenRecord) {
return myIdHelperService.getPidOrNull(theResource);
return myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theResource);
}
MdmLink matchLink = getMatchedMdmLink(theResource);
IMdmLink matchLink = getMatchedMdmLink(theResource);
if (matchLink == null) {
return null;
} else {
retval = matchLink.getGoldenResourcePid();
retval = matchLink.getGoldenResourcePersistenceId();
myTargetType = matchLink.getMdmSourceType();
}
return retval;
}
protected List<Long> getPossibleMatchedGoldenResourcePidsFromTarget(IAnyResource theBaseResource) {
return getMdmLinksForTarget(theBaseResource, MdmMatchResultEnum.POSSIBLE_MATCH).stream().map(MdmLink::getGoldenResourcePid).collect(Collectors.toList());
protected List<ResourcePersistentId> getPossibleMatchedGoldenResourcePidsFromTarget(IAnyResource theBaseResource) {
return getMdmLinksForTarget(theBaseResource, MdmMatchResultEnum.POSSIBLE_MATCH)
.stream()
.map(IMdmLink::getGoldenResourcePersistenceId).collect(Collectors.toList());
}
protected MdmLink getMatchedMdmLink(IAnyResource thePatientOrPractitionerResource) {
List<MdmLink> mdmLinks = getMdmLinksForTarget(thePatientOrPractitionerResource, MdmMatchResultEnum.MATCH);
protected IMdmLink getMatchedMdmLink(IAnyResource thePatientOrPractitionerResource) {
List<? extends IMdmLink> mdmLinks = getMdmLinksForTarget(thePatientOrPractitionerResource, MdmMatchResultEnum.MATCH);
if (mdmLinks.size() == 0) {
return null;
} else if (mdmLinks.size() == 1) {
@ -66,9 +70,9 @@ public abstract class BaseGoldenResourceMatcher extends TypeSafeMatcher<IAnyReso
}
}
protected List<MdmLink> getMdmLinksForTarget(IAnyResource theTargetResource, MdmMatchResultEnum theMatchResult) {
Long pidOrNull = myIdHelperService.getPidOrNull(theTargetResource);
List<MdmLink> matchLinkForTarget = myMdmLinkDaoSvc.getMdmLinksBySourcePidAndMatchResult(pidOrNull, theMatchResult);
protected List<? extends IMdmLink> getMdmLinksForTarget(IAnyResource theTargetResource, MdmMatchResultEnum theMatchResult) {
ResourcePersistentId pidOrNull = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theTargetResource);
List<? extends IMdmLink> matchLinkForTarget = myMdmLinkDaoSvc.getMdmLinksBySourcePidAndMatchResult(pidOrNull, theMatchResult);
if (!matchLinkForTarget.isEmpty()) {
return matchLinkForTarget;
} else {

View File

@ -1,7 +1,8 @@
package ca.uhn.fhir.jpa.mdm.matcher;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hl7.fhir.instance.model.api.IAnyResource;
@ -15,10 +16,10 @@ import java.util.stream.Collectors;
*/
public class IsLinkedTo extends BaseGoldenResourceMatcher {
private List<Long> baseResourceGoldenResourcePids;
private Long incomingResourceGoldenResourcePid;
private List<ResourcePersistentId> baseResourceGoldenResourcePids;
private ResourcePersistentId incomingResourceGoldenResourcePid;
protected IsLinkedTo(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
protected IsLinkedTo(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
super(theIdHelperService, theMdmLinkDaoSvc, theBaseResource);
}
@ -41,7 +42,7 @@ public class IsLinkedTo extends BaseGoldenResourceMatcher {
public void describeTo(Description theDescription) {
}
public static Matcher<IAnyResource> linkedTo(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
public static Matcher<IAnyResource> linkedTo(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
return new IsLinkedTo(theIdHelperService, theMdmLinkDaoSvc, theBaseResource);
}
}

View File

@ -1,8 +1,9 @@
package ca.uhn.fhir.jpa.mdm.matcher;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
@ -12,17 +13,17 @@ import java.util.Optional;
public class IsMatchedToAGoldenResource extends TypeSafeMatcher<IAnyResource> {
private final IJpaIdHelperService myIdHelperService;
private final IIdHelperService myIdHelperService;
private final MdmLinkDaoSvc myMdmLinkDaoSvc;
public IsMatchedToAGoldenResource(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc) {
public IsMatchedToAGoldenResource(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc) {
myIdHelperService = theIdHelperService;
myMdmLinkDaoSvc = theMdmLinkDaoSvc;
}
@Override
protected boolean matchesSafely(IAnyResource theIncomingResource) {
Optional<MdmLink> matchedLinkForTargetPid = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(myIdHelperService.getPidOrNull(theIncomingResource));
Optional<? extends IMdmLink> matchedLinkForTargetPid = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theIncomingResource));
return matchedLinkForTargetPid.isPresent();
}
@ -31,7 +32,7 @@ public class IsMatchedToAGoldenResource extends TypeSafeMatcher<IAnyResource> {
theDescription.appendText("target was not linked to a Golden Resource.");
}
public static Matcher<IAnyResource> matchedToAGoldenResource(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc) {
public static Matcher<IAnyResource> matchedToAGoldenResource(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc) {
return new IsMatchedToAGoldenResource(theIdHelperService, theMdmLinkDaoSvc);
}
}

View File

@ -1,9 +1,10 @@
package ca.uhn.fhir.jpa.mdm.matcher;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hl7.fhir.instance.model.api.IAnyResource;
@ -18,9 +19,9 @@ public class IsPossibleDuplicateOf extends BaseGoldenResourceMatcher {
* Matcher with tells us if there is an MdmLink with between these two resources that are considered POSSIBLE DUPLICATE.
* For use only on GoldenResource.
*/
private Long incomingGoldenResourcePid;
private ResourcePersistentId incomingGoldenResourcePid;
protected IsPossibleDuplicateOf(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
protected IsPossibleDuplicateOf(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
super(theIdHelperService, theMdmLinkDaoSvc, theBaseResource);
}
@ -28,7 +29,7 @@ public class IsPossibleDuplicateOf extends BaseGoldenResourceMatcher {
protected boolean matchesSafely(IAnyResource theIncomingResource) {
incomingGoldenResourcePid = getMatchedResourcePidFromResource(theIncomingResource);
List<Long> goldenResourcePidsToMatch = myBaseResources.stream()
List<ResourcePersistentId> goldenResourcePidsToMatch = myBaseResources.stream()
.map(this::getMatchedResourcePidFromResource)
.collect(Collectors.toList());
@ -36,7 +37,7 @@ public class IsPossibleDuplicateOf extends BaseGoldenResourceMatcher {
//Returns true if there is a POSSIBLE_DUPLICATE between the incoming resource, and all of the resources passed in via the constructor.
return goldenResourcePidsToMatch.stream()
.map(baseResourcePid -> {
Optional<MdmLink> duplicateLink = myMdmLinkDaoSvc.getMdmLinksByGoldenResourcePidSourcePidAndMatchResult(baseResourcePid, incomingGoldenResourcePid, MdmMatchResultEnum.POSSIBLE_DUPLICATE);
Optional<? extends IMdmLink> duplicateLink = myMdmLinkDaoSvc.getMdmLinksByGoldenResourcePidSourcePidAndMatchResult(baseResourcePid, incomingGoldenResourcePid, MdmMatchResultEnum.POSSIBLE_DUPLICATE);
if (!duplicateLink.isPresent()) {
duplicateLink = myMdmLinkDaoSvc.getMdmLinksByGoldenResourcePidSourcePidAndMatchResult(incomingGoldenResourcePid, baseResourcePid, MdmMatchResultEnum.POSSIBLE_DUPLICATE);
}
@ -55,7 +56,7 @@ public class IsPossibleDuplicateOf extends BaseGoldenResourceMatcher {
mismatchDescription.appendText("No MdmLink With POSSIBLE_DUPLICATE was found");
}
public static Matcher<IAnyResource> possibleDuplicateOf(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
public static Matcher<IAnyResource> possibleDuplicateOf(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
return new IsPossibleDuplicateOf(theIdHelperService, theMdmLinkDaoSvc, theBaseResource);
}
}

View File

@ -1,7 +1,9 @@
package ca.uhn.fhir.jpa.mdm.matcher;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hl7.fhir.instance.model.api.IAnyResource;
@ -15,16 +17,16 @@ import java.util.stream.Collectors;
*/
public class IsPossibleLinkedTo extends BaseGoldenResourceMatcher {
private List<Long> baseResourceGoldenResourcePids;
private Long incomingResourceGoldenResourcePid;
private List<ResourcePersistentId> baseResourceGoldenResourcePids;
private ResourcePersistentId incomingResourceGoldenResourcePid;
protected IsPossibleLinkedTo(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theTargetResources) {
protected IsPossibleLinkedTo(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theTargetResources) {
super(theIdHelperService, theMdmLinkDaoSvc, theTargetResources);
}
@Override
protected boolean matchesSafely(IAnyResource theGoldenResource) {
incomingResourceGoldenResourcePid = myIdHelperService.getPidOrNull(theGoldenResource);
incomingResourceGoldenResourcePid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theGoldenResource);
//OK, lets grab all the golden resource pids of the resources passed in via the constructor.
baseResourceGoldenResourcePids = myBaseResources.stream()
@ -40,7 +42,7 @@ public class IsPossibleLinkedTo extends BaseGoldenResourceMatcher {
public void describeTo(Description theDescription) {
}
public static Matcher<IAnyResource> possibleLinkedTo(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
public static Matcher<IAnyResource> possibleLinkedTo(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
return new IsPossibleLinkedTo(theIdHelperService, theMdmLinkDaoSvc, theBaseResource);
}
}

View File

@ -1,9 +1,10 @@
package ca.uhn.fhir.jpa.mdm.matcher;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hl7.fhir.instance.model.api.IAnyResource;
@ -17,15 +18,15 @@ import java.util.stream.Collectors;
*/
public class IsPossibleMatchWith extends BaseGoldenResourceMatcher {
protected IsPossibleMatchWith(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
protected IsPossibleMatchWith(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
super(theIdHelperService, theMdmLinkDaoSvc, theBaseResource);
}
@Override
protected boolean matchesSafely(IAnyResource theIncomingResource) {
List<MdmLink> mdmLinks = getMdmLinksForTarget(theIncomingResource, MdmMatchResultEnum.POSSIBLE_MATCH);
List<? extends IMdmLink> mdmLinks = getMdmLinksForTarget(theIncomingResource, MdmMatchResultEnum.POSSIBLE_MATCH);
List<Long> goldenResourcePidsToMatch = myBaseResources.stream()
List<ResourcePersistentId> goldenResourcePidsToMatch = myBaseResources.stream()
.map(this::getMatchedResourcePidFromResource)
.filter(Objects::nonNull)
.collect(Collectors.toList());
@ -36,8 +37,8 @@ public class IsPossibleMatchWith extends BaseGoldenResourceMatcher {
.collect(Collectors.toList());
}
List<Long> mdmLinkGoldenResourcePids = mdmLinks
.stream().map(MdmLink::getGoldenResourcePid)
List<ResourcePersistentId> mdmLinkGoldenResourcePids = mdmLinks
.stream().map(IMdmLink::getGoldenResourcePersistenceId)
.collect(Collectors.toList());
return mdmLinkGoldenResourcePids.containsAll(goldenResourcePidsToMatch);
@ -54,7 +55,7 @@ public class IsPossibleMatchWith extends BaseGoldenResourceMatcher {
mismatchDescription.appendText("No MDM Link With POSSIBLE_MATCH was found");
}
public static Matcher<IAnyResource> possibleMatchWith(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
public static Matcher<IAnyResource> possibleMatchWith(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
return new IsPossibleMatchWith(theIdHelperService, theMdmLinkDaoSvc, theBaseResource);
}
}

View File

@ -1,7 +1,8 @@
package ca.uhn.fhir.jpa.mdm.matcher;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hl7.fhir.instance.model.api.IAnyResource;
@ -11,10 +12,10 @@ import java.util.stream.Collectors;
public class IsSameGoldenResourceAs extends BaseGoldenResourceMatcher {
private List<Long> goldenResourcePidsToMatch;
private Long incomingGoldenResourcePid;
private List<ResourcePersistentId> goldenResourcePidsToMatch;
private ResourcePersistentId incomingGoldenResourcePid;
public IsSameGoldenResourceAs(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
public IsSameGoldenResourceAs(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
super(theIdHelperService, theMdmLinkDaoSvc, theBaseResource);
}
@ -40,7 +41,7 @@ public class IsSameGoldenResourceAs extends BaseGoldenResourceMatcher {
mismatchDescription.appendText(String.format(" was actually linked to %s/%s", myTargetType, incomingGoldenResourcePid));
}
public static Matcher<IAnyResource> sameGoldenResourceAs(IJpaIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
public static Matcher<IAnyResource> sameGoldenResourceAs(IIdHelperService theIdHelperService, MdmLinkDaoSvc theMdmLinkDaoSvc, IAnyResource... theBaseResource) {
return new IsSameGoldenResourceAs(theIdHelperService, theMdmLinkDaoSvc, theBaseResource);
}
}

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.mdm.provider;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import org.hl7.fhir.instance.model.api.IAnyResource;
@ -46,7 +47,7 @@ public abstract class BaseLinkR4Test extends BaseProviderR4Test {
mySourcePatientId = new StringType(mySourcePatient.getIdElement().getValue());
myVersionlessGodlenResourceId = new StringType(mySourcePatient.getIdElement().toVersionless().getValue());
myLink = getOnlyPatientLink();
myLink = (MdmLink) getOnlyPatientLink();
// Tests require our initial link to be a POSSIBLE_MATCH
myLink.setMatchResult(MdmMatchResultEnum.POSSIBLE_MATCH);
saveLink(myLink);
@ -65,12 +66,12 @@ public abstract class BaseLinkR4Test extends BaseProviderR4Test {
}
@Nonnull
protected MdmLink getOnlyPatientLink() {
protected IMdmLink getOnlyPatientLink() {
return myMdmLinkDaoSvc.findMdmLinkBySource(myPatient).get();
}
@Nonnull
protected List<MdmLink> getPatientLinks() {
protected List<? extends IMdmLink> getPatientLinks() {
return myMdmLinkDaoSvc.findMdmLinksBySourceResource(myPatient);
}
}

View File

@ -196,6 +196,6 @@ public class MdmProviderClearLinkR4Test extends BaseLinkR4Test {
@Nonnull
protected List<MdmLink> getPractitionerLinks() {
return myMdmLinkDaoSvc.findMdmLinksBySourceResource(myPractitioner);
return (List<MdmLink>) myMdmLinkDaoSvc.findMdmLinksBySourceResource(myPractitioner);
}
}

View File

@ -41,7 +41,7 @@ public class MdmProviderCreateLinkR4Test extends BaseLinkR4Test {
myMdmProvider.createLink(sourcePatientId, patientId, MATCH_RESULT, myRequestDetails);
assertLinkCount(2);
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
List<MdmLink> links = (List<MdmLink>) myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
assertEquals(MdmMatchResultEnum.MATCH, links.get(0).getMatchResult());
}
@ -62,7 +62,7 @@ public class MdmProviderCreateLinkR4Test extends BaseLinkR4Test {
myMdmProvider.createLink(sourcePatientId, patientId, MATCH_RESULT, myRequestDetails);
assertLinkCount(2);
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
List<MdmLink> links = (List<MdmLink>) myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
assertEquals(links.size(), 1);
assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
assertEquals(MdmMatchResultEnum.MATCH, links.get(0).getMatchResult());
@ -106,7 +106,7 @@ public class MdmProviderCreateLinkR4Test extends BaseLinkR4Test {
myMdmProvider.createLink(sourcePatientId, patientId, null, myRequestDetails);
assertLinkCount(2);
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
List<MdmLink> links = (List<MdmLink>) myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
assertEquals(MdmMatchResultEnum.MATCH, links.get(0).getMatchResult());
}
@ -152,7 +152,7 @@ public class MdmProviderCreateLinkR4Test extends BaseLinkR4Test {
myMdmProvider.createLink(sourcePatientId2, patientId, NO_MATCH_RESULT, myRequestDetails);
assertLinkCount(3);
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
List<MdmLink> links = (List<MdmLink>) myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
assertEquals(MdmLinkSourceEnum.MANUAL, links.get(1).getLinkSource());
assertEquals(MdmMatchResultEnum.NO_MATCH, links.get(1).getMatchResult());
}

View File

@ -97,7 +97,7 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
// Optional<Identifier> redirect = fromSourcePatient.getIdentifier().stream().filter(theIdentifier -> theIdentifier.getSystem().equals("REDIRECT")).findFirst();
// assertThat(redirect.get().getValue(), is(equalTo(myToSourcePatient.getIdElement().toUnqualified().getValue())));
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(myFromGoldenPatient);
List<MdmLink> links = (List<MdmLink>) myMdmLinkDaoSvc.findMdmLinksBySourceResource(myFromGoldenPatient);
assertThat(links, hasSize(1));
MdmLink link = links.get(0);
@ -129,7 +129,7 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
// 2 from the set-up and only one from this test should be golden resource
assertEquals(3, getAllGoldenPatients().size());
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(fromGoldenPatient);
List<MdmLink> links = (List<MdmLink>) myMdmLinkDaoSvc.findMdmLinksBySourceResource(fromGoldenPatient);
assertThat(links, hasSize(1));
MdmLink link = links.get(0);
@ -176,7 +176,7 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
assertFalse(MdmResourceUtil.isGoldenRecord(fromSourcePatient));
assertTrue(MdmResourceUtil.isGoldenRecordRedirected(fromSourcePatient));
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(myFromGoldenPatient);
List<MdmLink> links = (List<MdmLink>) myMdmLinkDaoSvc.findMdmLinksBySourceResource(myFromGoldenPatient);
assertThat(links, hasSize(1));
MdmLink link = links.get(0);

View File

@ -56,7 +56,7 @@ public class MdmProviderNotDuplicateGoldenResourceR4Test extends BaseProviderR4T
myMdmProvider.notDuplicate(myGoldenPatientId, myTargetPatientId, myRequestDetails);
assertLinkCount(1);
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(myTargetPatient);
List<MdmLink> links = (List<MdmLink>) myMdmLinkDaoSvc.findMdmLinksBySourceResource(myTargetPatient);
assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
assertEquals(MdmMatchResultEnum.NO_MATCH, links.get(0).getMatchResult());
}
@ -98,7 +98,7 @@ public class MdmProviderNotDuplicateGoldenResourceR4Test extends BaseProviderR4T
myMdmProvider.notDuplicate(goldenPatientId, targetPatientId, myRequestDetails);
assertLinkCount(1);
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(targetPatient);
List<MdmLink> links = (List<MdmLink>) myMdmLinkDaoSvc.findMdmLinksBySourceResource(targetPatient);
assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
assertEquals(MdmMatchResultEnum.NO_MATCH, links.get(0).getMatchResult());
}

View File

@ -1,11 +1,13 @@
package ca.uhn.fhir.jpa.mdm.provider;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.util.CircularQueueCaptureQueriesListener;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.util.StopWatch;
@ -56,12 +58,15 @@ public class MdmProviderQueryLinkR4Test extends BaseLinkR4Test {
myLinkSource = new StringType(MdmLinkSourceEnum.AUTO.name());
Patient sourcePatient1 = createGoldenPatient();
myGoldenResource1Id = new StringType(sourcePatient1.getIdElement().toVersionless().getValue());
Long sourcePatient1Pid = runInTransaction(()->myIdHelperService.getPidOrNull(sourcePatient1));
ResourcePersistentId sourcePatient1Pid = runInTransaction(()->myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), sourcePatient1));
Patient sourcePatient2 = createGoldenPatient();
myGoldenResource2Id = new StringType(sourcePatient2.getIdElement().toVersionless().getValue());
Long sourcePatient2Pid = runInTransaction(()->myIdHelperService.getPidOrNull(sourcePatient2));
ResourcePersistentId sourcePatient2Pid = runInTransaction(()->myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), sourcePatient2));
MdmLink possibleDuplicateMdmLink = myMdmLinkDaoSvc.newMdmLink().setGoldenResourcePid(sourcePatient1Pid).setSourcePid(sourcePatient2Pid).setMatchResult(MdmMatchResultEnum.POSSIBLE_DUPLICATE).setLinkSource(MdmLinkSourceEnum.AUTO);
MdmLink possibleDuplicateMdmLink = (MdmLink) myMdmLinkDaoSvc.newMdmLink();
possibleDuplicateMdmLink.setGoldenResourcePersistenceId(sourcePatient1Pid);
possibleDuplicateMdmLink.setSourcePersistenceId(sourcePatient2Pid);
possibleDuplicateMdmLink.setMatchResult(MdmMatchResultEnum.POSSIBLE_DUPLICATE).setLinkSource(MdmLinkSourceEnum.AUTO);
saveLink(possibleDuplicateMdmLink);
}

View File

@ -37,7 +37,7 @@ public class MdmProviderUpdateLinkR4Test extends BaseLinkR4Test {
myMdmProvider.updateLink(mySourcePatientId, myPatientId, NO_MATCH_RESULT, myRequestDetails);
assertLinkCount(2);
List<MdmLink> links = getPatientLinks();
List<MdmLink> links = (List<MdmLink>) getPatientLinks();
assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
assertEquals(MdmMatchResultEnum.NO_MATCH, links.get(0).getMatchResult());
assertEquals(MdmLinkSourceEnum.AUTO, links.get(1).getLinkSource());
@ -51,7 +51,7 @@ public class MdmProviderUpdateLinkR4Test extends BaseLinkR4Test {
myMdmProvider.updateLink(mySourcePatientId, myPatientId, MATCH_RESULT, myRequestDetails);
assertLinkCount(1);
List<MdmLink> links = getPatientLinks();
List<MdmLink> links = (List<MdmLink>) getPatientLinks();
assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
assertEquals(MdmMatchResultEnum.MATCH, links.get(0).getMatchResult());
}
@ -66,7 +66,7 @@ public class MdmProviderUpdateLinkR4Test extends BaseLinkR4Test {
Patient sourcePatient = getGoldenResourceFromTargetResource(patient);
StringType sourcePatientId = new StringType(sourcePatient.getIdElement().getValue());
MdmLink link = myMdmLinkDaoSvc.findMdmLinkBySource(patient).get();
MdmLink link = (MdmLink) myMdmLinkDaoSvc.findMdmLinkBySource(patient).get();
link.setMatchResult(MdmMatchResultEnum.POSSIBLE_MATCH);
saveLink(link);
assertEquals(MdmLinkSourceEnum.AUTO, link.getLinkSource());
@ -74,7 +74,7 @@ public class MdmProviderUpdateLinkR4Test extends BaseLinkR4Test {
myMdmProvider.updateLink(sourcePatientId, patientId, MATCH_RESULT, myRequestDetails);
assertLinkCount(2);
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
List<MdmLink> links = (List<MdmLink>) myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
assertEquals(MdmMatchResultEnum.MATCH, links.get(0).getMatchResult());
assertNotNull(links.get(0).getPartitionId());

View File

@ -5,6 +5,7 @@ import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.mdm.api.IMdmSubmitSvc;
import ca.uhn.fhir.mdm.svc.MdmSubmitSvcImpl;
import ca.uhn.test.concurrency.PointcutLatch;
import org.apache.commons.lang3.time.DateUtils;
import org.junit.jupiter.api.AfterEach;

View File

@ -85,7 +85,7 @@ public class MdmControllerSvcImplTest extends BaseLinkR4Test {
getGoldenResourceFromTargetResource(patient);
MdmLink link = myMdmLinkDaoSvc.findMdmLinkBySource(patient).get();
MdmLink link = (MdmLink) myMdmLinkDaoSvc.findMdmLinkBySource(patient).get();
link.setMatchResult(MdmMatchResultEnum.POSSIBLE_MATCH);
saveLink(link);
assertEquals(MdmLinkSourceEnum.AUTO, link.getLinkSource());
@ -113,7 +113,7 @@ public class MdmControllerSvcImplTest extends BaseLinkR4Test {
getGoldenResourceFromTargetResource(patient);
MdmLink link = myMdmLinkDaoSvc.findMdmLinkBySource(patient).get();
MdmLink link = (MdmLink) myMdmLinkDaoSvc.findMdmLinkBySource(patient).get();
link.setMatchResult(MdmMatchResultEnum.POSSIBLE_DUPLICATE);
saveLink(link);
assertEquals(MdmLinkSourceEnum.AUTO, link.getLinkSource());

View File

@ -1,6 +1,8 @@
package ca.uhn.fhir.jpa.mdm.svc;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
@ -9,8 +11,9 @@ import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.interceptor.api.IInterceptorService;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.jpa.mdm.helper.MdmLinkHelper;
import ca.uhn.fhir.jpa.mdm.interceptor.IMdmStorageInterceptor;
import ca.uhn.fhir.mdm.interceptor.IMdmStorageInterceptor;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.TransactionLogMessages;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -67,10 +70,10 @@ public class MdmGoldenResourceMergerSvcTest extends BaseMdmR4Test {
public void before() {
myFromGoldenPatient = createGoldenPatient();
IdType fromSourcePatientId = myFromGoldenPatient.getIdElement().toUnqualifiedVersionless();
myFromGoldenPatientPid = runInTransaction(()->myIdHelperService.getPidOrThrowException(fromSourcePatientId));
myFromGoldenPatientPid = runInTransaction(()->myIdHelperService.getPidOrThrowException(RequestPartitionId.allPartitions(), fromSourcePatientId)).getIdAsLong();
myToGoldenPatient = createGoldenPatient();
IdType toGoldenPatientId = myToGoldenPatient.getIdElement().toUnqualifiedVersionless();
myToGoldenPatientPid = runInTransaction(()->myIdHelperService.getPidOrThrowException(toGoldenPatientId));
myToGoldenPatientPid = runInTransaction(()->myIdHelperService.getPidOrThrowException(RequestPartitionId.allPartitions(), toGoldenPatientId)).getIdAsLong();
myTargetPatient1 = createPatient();
myTargetPatient2 = createPatient();
@ -121,9 +124,9 @@ public class MdmGoldenResourceMergerSvcTest extends BaseMdmR4Test {
@Test
public void mergeRemovesPossibleDuplicatesLink() {
MdmLink mdmLink = myMdmLinkDaoSvc.newMdmLink()
.setGoldenResourcePid(myToGoldenPatientPid)
.setSourcePid(myFromGoldenPatientPid)
MdmLink mdmLink = (MdmLink) myMdmLinkDaoSvc.newMdmLink()
.setGoldenResourcePersistenceId(new ResourcePersistentId(myToGoldenPatientPid))
.setSourcePersistenceId(new ResourcePersistentId(myFromGoldenPatientPid))
.setMdmSourceType("Patient")
.setMatchResult(MdmMatchResultEnum.POSSIBLE_DUPLICATE)
.setLinkSource(MdmLinkSourceEnum.AUTO);
@ -228,6 +231,7 @@ public class MdmGoldenResourceMergerSvcTest extends BaseMdmR4Test {
private List<MdmLink> getNonRedirectLinksByGoldenResource(Patient theGoldenPatient) {
return myMdmLinkDaoSvc.findMdmLinksByGoldenResource(theGoldenPatient).stream()
.filter(link -> !link.isRedirect())
.map( link -> (MdmLink) link)
.collect(Collectors.toList());
}
@ -340,7 +344,7 @@ public class MdmGoldenResourceMergerSvcTest extends BaseMdmR4Test {
private void assertResourceHasLinkCount(IBaseResource theResource, int theCount) {
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(theResource);
List<? extends IMdmLink> links = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(theResource);
assertEquals(theCount, links.size());
}
@ -359,8 +363,8 @@ public class MdmGoldenResourceMergerSvcTest extends BaseMdmR4Test {
}
private void assertResourceHasAutoLinkCount(Patient myToGoldenPatient, int theCount) {
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(myToGoldenPatient);
assertEquals(theCount, links.stream().filter(MdmLink::isAuto).count());
List<? extends IMdmLink> links = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(myToGoldenPatient);
assertEquals(theCount, links.stream().filter(IMdmLink::isAuto).count());
}
@Test
@ -456,7 +460,7 @@ public class MdmGoldenResourceMergerSvcTest extends BaseMdmR4Test {
}
private MdmLink createMdmLink(Patient theSourcePatient, Patient theTargetPatient) {
return myMdmLinkDaoSvc.createOrUpdateLinkEntity(theSourcePatient, theTargetPatient, POSSIBLE_MATCH, MdmLinkSourceEnum.AUTO, createContextForCreate("Patient"));
return (MdmLink) myMdmLinkDaoSvc.createOrUpdateLinkEntity(theSourcePatient, theTargetPatient, POSSIBLE_MATCH, MdmLinkSourceEnum.AUTO, createContextForCreate("Patient"));
}
private void populatePatient(Patient theSourcePatient) {

View File

@ -6,11 +6,13 @@ import ca.uhn.fhir.jpa.dao.expunge.ExpungeEverythingService;
import ca.uhn.fhir.jpa.dao.expunge.IExpungeEverythingService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.hamcrest.Matchers;
import org.hl7.fhir.r4.model.IdType;
@ -88,10 +90,10 @@ public class MdmLinkSvcTest extends BaseMdmR4Test {
Patient goldenPatient1 = createGoldenPatient();
Patient goldenPatient2 = createGoldenPatient();
Long goldenPatient1Pid = runInTransaction(()->myIdHelperService.getPidOrNull(goldenPatient1));
Long goldenPatient2Pid = runInTransaction(()->myIdHelperService.getPidOrNull(goldenPatient2));
assertFalse(myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenPatient1Pid, goldenPatient2Pid).isPresent());
assertFalse(myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenPatient2Pid, goldenPatient1Pid).isPresent());
ResourcePersistentId goldenPatient1Pid = runInTransaction(()->myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), goldenPatient1));
ResourcePersistentId goldenPatient2Pid = runInTransaction(()->myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), goldenPatient2));
assertFalse(myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenPatient1Pid.getIdAsLong(), goldenPatient2Pid.getIdAsLong()).isPresent());
assertFalse(myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenPatient2Pid.getIdAsLong(), goldenPatient1Pid.getIdAsLong()).isPresent());
saveNoMatchLink(goldenPatient1Pid, goldenPatient2Pid);
@ -106,10 +108,10 @@ public class MdmLinkSvcTest extends BaseMdmR4Test {
Patient goldenPatient1 = createGoldenPatient();
Patient goldenPatient2 = createGoldenPatient();
Long goldenPatient1Pid = runInTransaction(()->myIdHelperService.getPidOrNull(goldenPatient1));
Long goldenPatient2Pid = runInTransaction(()->myIdHelperService.getPidOrNull(goldenPatient2));
assertFalse(myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenPatient1Pid, goldenPatient2Pid).isPresent());
assertFalse(myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenPatient2Pid, goldenPatient1Pid).isPresent());
ResourcePersistentId goldenPatient1Pid = runInTransaction(()->myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), goldenPatient1));
ResourcePersistentId goldenPatient2Pid = runInTransaction(()->myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), goldenPatient2));
assertFalse(myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenPatient1Pid.getIdAsLong(), goldenPatient2Pid.getIdAsLong()).isPresent());
assertFalse(myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenPatient2Pid.getIdAsLong(), goldenPatient1Pid.getIdAsLong()).isPresent());
saveNoMatchLink(goldenPatient2Pid, goldenPatient1Pid);
@ -118,12 +120,11 @@ public class MdmLinkSvcTest extends BaseMdmR4Test {
assertLinkCount(1);
}
private void saveNoMatchLink(Long theGoldenResourcePid, Long theTargetPid) {
MdmLink noMatchLink = myMdmLinkDaoSvc.newMdmLink()
.setGoldenResourcePid(theGoldenResourcePid)
.setSourcePid(theTargetPid)
.setLinkSource(MdmLinkSourceEnum.MANUAL)
.setMatchResult(MdmMatchResultEnum.NO_MATCH);
private void saveNoMatchLink(ResourcePersistentId theGoldenResourcePid, ResourcePersistentId theTargetPid) {
MdmLink noMatchLink = (MdmLink) myMdmLinkDaoSvc.newMdmLink();
noMatchLink.setGoldenResourcePersistenceId(theGoldenResourcePid);
noMatchLink.setSourcePersistenceId(theTargetPid);
noMatchLink.setLinkSource(MdmLinkSourceEnum.MANUAL).setMatchResult(MdmMatchResultEnum.NO_MATCH);
saveLink(noMatchLink);
}
@ -165,7 +166,7 @@ public class MdmLinkSvcTest extends BaseMdmR4Test {
myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, patient1, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.MANUAL, createContextForCreate("Patient"));
myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, patient2, MdmMatchOutcome.NO_MATCH, MdmLinkSourceEnum.MANUAL, createContextForCreate("Patient"));
List<MdmLink> targets = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(goldenPatient);
List<? extends IMdmLink> targets = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(goldenPatient);
assertFalse(targets.isEmpty());
assertEquals(2, targets.size());
@ -173,7 +174,7 @@ public class MdmLinkSvcTest extends BaseMdmR4Test {
//assertEquals(patient1.getIdElement().toVersionless().getValue(), sourcePatient.getLinkFirstRep().getTarget().getReference());
List<String> actual = targets
.stream()
.map(link -> link.getSourcePid().toString())
.map(link -> link.getSourcePersistenceId().getId().toString())
.collect(Collectors.toList());
List<String> expected = Arrays.asList(patient1, patient2)
@ -195,7 +196,7 @@ public class MdmLinkSvcTest extends BaseMdmR4Test {
assertEquals(0, myMdmLinkDao.count());
myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, patient1, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.MANUAL, createContextForCreate("Patient"));
List<MdmLink> targets = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(goldenPatient);
List<? extends IMdmLink> targets = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(goldenPatient);
assertFalse(targets.isEmpty());
assertEquals(1, targets.size());
assertEquals(requestPartitionId.getFirstPartitionIdOrNull(), targets.get(0).getPartitionId().getPartitionId());

View File

@ -1,10 +1,12 @@
package ca.uhn.fhir.jpa.mdm.svc;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.mdm.api.MdmConstants;
import ca.uhn.fhir.mdm.model.CanonicalEID;
import ca.uhn.fhir.mdm.util.EIDHelper;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Patient;
@ -140,20 +142,19 @@ public class MdmMatchLinkSvcMultipleEidModeTest extends BaseMdmR4Test {
assertLinksCreatedNewResource(true, true, false);
assertLinksMatchedByEid(false, false, true);
List<MdmLink> possibleDuplicates = myMdmLinkDaoSvc.getPossibleDuplicates();
List<MdmLink> possibleDuplicates = (List<MdmLink>) myMdmLinkDaoSvc.getPossibleDuplicates();
assertThat(possibleDuplicates, hasSize(1));
Patient finalPatient1 = patient1;
Patient finalPatient2 = patient2;
List<Long> duplicatePids = runInTransaction(()->Stream.of(finalPatient1, finalPatient2)
.map(this::getGoldenResourceFromTargetResource)
.map(myIdHelperService::getPidOrNull)
List<ResourcePersistentId> duplicatePids = runInTransaction(()->Stream.of(finalPatient1, finalPatient2)
.map(t -> myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), getGoldenResourceFromTargetResource(t)))
.collect(Collectors.toList()));
//The two GoldenResources related to the patients should both show up in the only existing POSSIBLE_DUPLICATE MdmLink.
MdmLink mdmLink = possibleDuplicates.get(0);
assertThat(mdmLink.getGoldenResourcePid(), is(in(duplicatePids)));
assertThat(mdmLink.getSourcePid(), is(in(duplicatePids)));
assertThat(mdmLink.getGoldenResourcePersistenceId(), is(in(duplicatePids)));
assertThat(mdmLink.getSourcePersistenceId(), is(in(duplicatePids)));
}
@Test
@ -201,7 +202,7 @@ public class MdmMatchLinkSvcMultipleEidModeTest extends BaseMdmR4Test {
assertThat(patient2, is(possibleMatchWith(patient1)));
assertThat(patient2, is(possibleMatchWith(patient3)));
List<MdmLink> possibleDuplicates = myMdmLinkDaoSvc.getPossibleDuplicates();
List<MdmLink> possibleDuplicates = (List<MdmLink>) myMdmLinkDaoSvc.getPossibleDuplicates();
assertThat(possibleDuplicates, hasSize(1));
assertThat(patient3, is(possibleDuplicateOf(patient1)));
}

View File

@ -1,8 +1,10 @@
package ca.uhn.fhir.jpa.mdm.svc;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
import ca.uhn.fhir.mdm.api.MdmConstants;
@ -14,6 +16,7 @@ import ca.uhn.fhir.mdm.util.EIDHelper;
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.param.TokenParam;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.r4.model.HumanName;
@ -154,7 +157,7 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
Patient janePatient = addExternalEID(buildJanePatient(), sampleEID);
janePatient = createPatientAndUpdateLinks(janePatient);
Optional<MdmLink> mdmLink = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(janePatient.getIdElement().getIdPartAsLong());
Optional<? extends IMdmLink> mdmLink = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(new ResourcePersistentId(janePatient.getIdElement().getIdPartAsLong()));
assertThat(mdmLink.isPresent(), is(true));
Patient patient = getTargetResourceFromMdmLink(mdmLink.get(), "Patient");
@ -167,7 +170,7 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
@Test
public void testWhenPatientIsCreatedWithoutAnEIDTheGoldenResourceGetsAutomaticallyAssignedOne() {
Patient patient = createPatientAndUpdateLinks(buildJanePatient());
MdmLink mdmLink = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(patient.getIdElement().getIdPartAsLong()).get();
IMdmLink mdmLink = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(new ResourcePersistentId(patient.getIdElement().getIdPartAsLong())).get();
Patient targetPatient = getTargetResourceFromMdmLink(mdmLink, "Patient");
Identifier identifierFirstRep = targetPatient.getIdentifierFirstRep();
@ -179,7 +182,7 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
public void testPatientAttributesAreCopiedOverWhenGoldenResourceIsCreatedFromPatient() {
Patient patient = createPatientAndUpdateLinks(buildPatientWithNameIdAndBirthday("Gary", "GARY_ID", new Date()));
Optional<MdmLink> mdmLink = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(patient.getIdElement().getIdPartAsLong());
Optional<? extends IMdmLink> mdmLink = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(new ResourcePersistentId(patient.getIdElement().getIdPartAsLong()));
Patient read = getTargetResourceFromMdmLink(mdmLink.get(), "Patient");
assertThat(read.getNameFirstRep().getFamily(), is(equalTo(patient.getNameFirstRep().getFamily())));
@ -268,20 +271,19 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
Patient patient2 = addExternalEID(buildJanePatient(), "eid-2");
patient2 = createPatientAndUpdateLinks(patient2);
List<MdmLink> possibleDuplicates = myMdmLinkDaoSvc.getPossibleDuplicates();
List<MdmLink> possibleDuplicates = (List<MdmLink>) myMdmLinkDaoSvc.getPossibleDuplicates();
assertThat(possibleDuplicates, hasSize(1));
Patient finalPatient1 = patient1;
Patient finalPatient2 = patient2;
List<Long> duplicatePids = runInTransaction(()->Stream.of(finalPatient1, finalPatient2)
.map(this::getGoldenResourceFromTargetResource)
.map(myIdHelperService::getPidOrNull)
List<ResourcePersistentId> duplicatePids = runInTransaction(()->Stream.of(finalPatient1, finalPatient2)
.map(t -> myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), getGoldenResourceFromTargetResource(t)))
.collect(Collectors.toList()));
//The two GoldenResources related to the patients should both show up in the only existing POSSIBLE_DUPLICATE MdmLink.
MdmLink mdmLink = possibleDuplicates.get(0);
assertThat(mdmLink.getGoldenResourcePid(), is(in(duplicatePids)));
assertThat(mdmLink.getSourcePid(), is(in(duplicatePids)));
assertThat(mdmLink.getGoldenResourcePersistenceId(), is(in(duplicatePids)));
assertThat(mdmLink.getSourcePersistenceId(), is(in(duplicatePids)));
}
@Test
@ -366,7 +368,7 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
assertThat(incomingJanePatient, is(possibleMatchWith(janePatient, janePatient2)));
//Ensure there is no successful MATCH links for incomingJanePatient
Optional<MdmLink> matchedLinkForTargetPid = runInTransaction(()->myMdmLinkDaoSvc.getMatchedLinkForSourcePid(myIdHelperService.getPidOrNull(incomingJanePatient)));
Optional<? extends IMdmLink> matchedLinkForTargetPid = runInTransaction(()->myMdmLinkDaoSvc.getMatchedLinkForSourcePid(myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), incomingJanePatient)));
assertThat(matchedLinkForTargetPid.isPresent(), is(false));
logAllLinks();
@ -589,7 +591,7 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
}
private void assertNoDuplicates() {
List<MdmLink> possibleDuplicates = myMdmLinkDaoSvc.getPossibleDuplicates();
List<MdmLink> possibleDuplicates = (List<MdmLink>) myMdmLinkDaoSvc.getPossibleDuplicates();
assertThat(possibleDuplicates, hasSize(0));
}
@ -624,7 +626,7 @@ public class MdmMatchLinkSvcTest extends BaseMdmR4Test {
assertThat(patient2, is(sameGoldenResourceAs(patient1)));
List<MdmLink> possibleDuplicates = myMdmLinkDaoSvc.getPossibleDuplicates();
List<MdmLink> possibleDuplicates = (List<MdmLink>) myMdmLinkDaoSvc.getPossibleDuplicates();
assertThat(possibleDuplicates, hasSize(1));
assertThat(patient3, is(possibleDuplicateOf(patient1)));
}

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.mdm.svc;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.rules.json.MdmRulesJson;
import ca.uhn.fhir.mdm.svc.MdmSearchParamSvc;
import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;

View File

@ -2,7 +2,7 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.mdm.svc.MdmSearchParamSvc;
import ca.uhn.fhir.mdm.svc.MdmSearchParamSvc;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.mdm.api.IMdmRuleValidator;
import ca.uhn.fhir.mdm.rules.config.MdmSettings;

View File

@ -31,7 +31,7 @@ class MdmGoldenResourceFindingSvcTest extends BaseMdmR4Test {
Patient jane = createPatientAndUpdateLinks(addExternalEID(buildJanePatient(), EID_1));
// hack the link into a NO_MATCH
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(jane);
List<MdmLink> links = (List<MdmLink>) myMdmLinkDaoSvc.findMdmLinksBySourceResource(jane);
assertThat(links, hasSize(1));
MdmLink link = links.get(0);
link.setMatchResult(MdmMatchResultEnum.NO_MATCH);

View File

@ -53,8 +53,8 @@ class MdmClearStepTest extends BaseMdmR4Test {
goldenPatient.setId(myGoldenId);
myPatientDao.update(goldenPatient);
mySourcePid = myIdHelperService.getPidOrThrowException(sourcePatient);
myGoldenPid = myIdHelperService.getPidOrThrowException(goldenPatient);
mySourcePid = myIdHelperService.getPidOrThrowException(sourcePatient).getIdAsLong();
myGoldenPid = myIdHelperService.getPidOrThrowException(goldenPatient).getIdAsLong();
myLink = buildMdmLink(mySourcePid, myGoldenPid);
myMdmLinkDaoSvc.save(myLink);

View File

@ -5,7 +5,7 @@
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>6.1.0-PRE24-SNAPSHOT</version>
<version>6.1.0-PRE25-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>

Some files were not shown because too many files have changed in this diff Show More