Cleanup
This commit is contained in:
parent
1c13ccd2d5
commit
034d9a9b48
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
type: add
|
||||
issue: 6464
|
||||
title: "A new experimental interceptor called the MdmReadVirtualizationInterceptor
|
||||
has been added. This interceptor rewrites results when querying an MDM-enabled
|
||||
JPA server in order to always include linked resources and rerwrites query results
|
||||
to link to the MDM golden resource. This interceptor is still being developed
|
||||
and should be used with caution."
|
|
@ -134,7 +134,8 @@ public interface IMdmLinkJpaRepository
|
|||
+ " lookup_link.mySourcePid IN (:pids))"
|
||||
+ "AND lookup_link.myMatchResult = :matchResult")
|
||||
List<MdmPidTuple> expandPidsByGoldenResourcePidsOrSourcePidsAndMatchResult(
|
||||
@Param("pids") Collection<Long> theSourcePid, @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnum);
|
||||
@Param("pids") Collection<Long> theSourcePid,
|
||||
@Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnum);
|
||||
|
||||
@Query(
|
||||
"SELECT ml.myId FROM MdmLink ml WHERE ml.myMdmSourceType = :resourceName AND ml.myCreated <= :highThreshold ORDER BY ml.myCreated DESC")
|
||||
|
|
|
@ -37,7 +37,6 @@ import ca.uhn.fhir.mdm.api.params.MdmQuerySearchParameters;
|
|||
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
|
||||
import ca.uhn.fhir.mdm.model.MdmPidTuple;
|
||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.persistence.EntityManager;
|
||||
|
@ -155,11 +154,12 @@ public class MdmLinkDaoJpaImpl implements IMdmLinkDao<JpaPid, MdmLink> {
|
|||
@Override
|
||||
public Collection<MdmPidTuple<JpaPid>> resolveGoldenResources(List<JpaPid> theSourcePids) {
|
||||
return myMdmLinkDao
|
||||
.expandPidsByGoldenResourcePidsOrSourcePidsAndMatchResult(JpaPid.toLongList(theSourcePids), MdmMatchResultEnum.MATCH)
|
||||
.stream()
|
||||
.map(this::daoTupleToMdmTuple)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
.expandPidsByGoldenResourcePidsOrSourcePidsAndMatchResult(
|
||||
JpaPid.toLongList(theSourcePids), MdmMatchResultEnum.MATCH)
|
||||
.stream()
|
||||
.map(this::daoTupleToMdmTuple)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,8 +22,8 @@ package ca.uhn.fhir.jpa.mdm.config;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.nickname.INicknameSvc;
|
||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||
import ca.uhn.fhir.mdm.interceptor.MdmSearchExpandingInterceptor;
|
||||
import ca.uhn.fhir.mdm.interceptor.MdmReadVirtualizationInterceptor;
|
||||
import ca.uhn.fhir.mdm.interceptor.MdmSearchExpandingInterceptor;
|
||||
import ca.uhn.fhir.mdm.rules.config.MdmRuleValidator;
|
||||
import ca.uhn.fhir.mdm.rules.matcher.IMatcherFactory;
|
||||
import ca.uhn.fhir.mdm.rules.matcher.MdmMatcherFactory;
|
||||
|
|
|
@ -20,7 +20,6 @@
|
|||
package ca.uhn.fhir.mdm.dao;
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||
import ca.uhn.fhir.mdm.api.IMdmLink;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkWithRevision;
|
||||
|
|
|
@ -31,27 +31,54 @@ import java.util.List;
|
|||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* <b>This class is experimental and subject to change. Use with caution.</b>
|
||||
* <p>
|
||||
* This interceptor provided an "MDM Virtualized" endpoint, meaning that
|
||||
* searches are expanded to include MDM-linked resources (including any
|
||||
* linked golden resource, and also including any other resources linked
|
||||
* to that golden resource). Searches for non-MDM resources which have
|
||||
* a reference to an MDM resource will have their reference parameter
|
||||
* expanded to include the golden and linked resources.
|
||||
* </p>
|
||||
* <p>
|
||||
* In addition, responses are cleaned up so that only the golden resource
|
||||
* is included in responses, and references to non-golden resources
|
||||
* are rewritten.
|
||||
* </p>
|
||||
* <p>
|
||||
* This interceptor does not modify data that is being stored/written
|
||||
* in any way, it only modifies data that is being returned by the
|
||||
* server.
|
||||
* </p>
|
||||
*
|
||||
* @since 8.0.0
|
||||
*/
|
||||
public class MdmReadVirtualizationInterceptor<P extends IResourcePersistentId<?>> {
|
||||
|
||||
@Autowired
|
||||
private FhirContext myFhirContext;
|
||||
|
||||
@Autowired
|
||||
private IMdmLinkDao<P, ?> myMdmLinkDao;
|
||||
|
||||
@Autowired
|
||||
private IIdHelperService<P> myIdHelperService;
|
||||
|
||||
@Autowired
|
||||
private DaoRegistry myDaoRegistry;
|
||||
|
||||
@Autowired
|
||||
private MdmSettings myMdmSettings;
|
||||
|
||||
@Autowired
|
||||
private MdmSearchExpansionSvc myMdmSearchExpansionSvc;
|
||||
|
||||
@Hook(Pointcut.STORAGE_PRESEARCH_REGISTERED)
|
||||
public void hook(RequestDetails theRequestDetails, SearchParameterMap theSearchParameterMap) {
|
||||
myMdmSearchExpansionSvc.expandSearch(theRequestDetails, theSearchParameterMap, t->true);
|
||||
myMdmSearchExpansionSvc.expandSearch(theRequestDetails, theSearchParameterMap, t -> true);
|
||||
}
|
||||
|
||||
|
||||
@Hook(Pointcut.STORAGE_PRESHOW_RESOURCES)
|
||||
public void preShowResources(RequestDetails theRequestDetails, IPreResourceShowDetails theDetails) {
|
||||
|
||||
|
@ -65,14 +92,16 @@ public class MdmReadVirtualizationInterceptor<P extends IResourcePersistentId<?>
|
|||
Set<IIdType> allIds = new HashSet<>();
|
||||
candidateResourceIds.keySet().forEach(t -> allIds.add(newIdType(t)));
|
||||
candidateReferences.keySet().forEach(t -> allIds.add(newIdType(t)));
|
||||
List<P> sourcePids = myIdHelperService.getPidsOrThrowException(RequestPartitionId.allPartitions(), List.copyOf(allIds));
|
||||
List<P> sourcePids =
|
||||
myIdHelperService.getPidsOrThrowException(RequestPartitionId.allPartitions(), List.copyOf(allIds));
|
||||
Collection<MdmPidTuple<P>> tuples = myMdmLinkDao.resolveGoldenResources(sourcePids);
|
||||
|
||||
// Resolve the link PIDs into FHIR IDs
|
||||
Set<P> allPersistentIds = new HashSet<>();
|
||||
tuples.forEach(t -> allPersistentIds.add(t.getGoldenPid()));
|
||||
tuples.forEach(t -> allPersistentIds.add(t.getSourcePid()));
|
||||
PersistentIdToForcedIdMap<P> persistentIdToFhirIdMap = myIdHelperService.translatePidsToForcedIds(allPersistentIds);
|
||||
PersistentIdToForcedIdMap<P> persistentIdToFhirIdMap =
|
||||
myIdHelperService.translatePidsToForcedIds(allPersistentIds);
|
||||
|
||||
// Loop through each link and figure out whether we need to remap anything
|
||||
for (MdmPidTuple<P> tuple : tuples) {
|
||||
|
@ -84,13 +113,13 @@ public class MdmReadVirtualizationInterceptor<P extends IResourcePersistentId<?>
|
|||
List<ResourceReferenceInfo> referencesToRemap = candidateReferences.get(sourceId);
|
||||
if (!referencesToRemap.isEmpty()) {
|
||||
P associatedGoldenResourcePid = tuple.getGoldenPid();
|
||||
Optional<String> associatedGoldenResourceId = persistentIdToFhirIdMap.get(associatedGoldenResourcePid);
|
||||
Optional<String> associatedGoldenResourceId =
|
||||
persistentIdToFhirIdMap.get(associatedGoldenResourcePid);
|
||||
if (associatedGoldenResourceId.isPresent()) {
|
||||
for (ResourceReferenceInfo referenceInfoToRemap : referencesToRemap) {
|
||||
IBaseReference referenceToRemap = referenceInfoToRemap.getResourceReference();
|
||||
referenceToRemap.setReference(associatedGoldenResourceId.get());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -122,7 +151,6 @@ public class MdmReadVirtualizationInterceptor<P extends IResourcePersistentId<?>
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,7 +158,8 @@ public class MdmReadVirtualizationInterceptor<P extends IResourcePersistentId<?>
|
|||
* that resource within the {@link IPreResourceShowDetails}
|
||||
*/
|
||||
private ListMultimap<String, Integer> extractRemapCandidateResources(IPreResourceShowDetails theDetails) {
|
||||
ListMultimap<String, Integer> retVal = MultimapBuilder.hashKeys().arrayListValues().build();
|
||||
ListMultimap<String, Integer> retVal =
|
||||
MultimapBuilder.hashKeys().arrayListValues().build();
|
||||
for (int resourceIdx = 0; resourceIdx < theDetails.size(); resourceIdx++) {
|
||||
IBaseResource resource = theDetails.getResource(resourceIdx);
|
||||
|
||||
|
@ -149,8 +178,10 @@ public class MdmReadVirtualizationInterceptor<P extends IResourcePersistentId<?>
|
|||
* @return Returns a map where the keys are a typed ID (Patient/ABC) and the values are references
|
||||
* found in any of the resources that are referring to that ID.
|
||||
*/
|
||||
private ListMultimap<String, ResourceReferenceInfo> extractRemapCandidateReferences(IPreResourceShowDetails theDetails) {
|
||||
ListMultimap<String, ResourceReferenceInfo> retVal = MultimapBuilder.hashKeys().arrayListValues().build();
|
||||
private ListMultimap<String, ResourceReferenceInfo> extractRemapCandidateReferences(
|
||||
IPreResourceShowDetails theDetails) {
|
||||
ListMultimap<String, ResourceReferenceInfo> retVal =
|
||||
MultimapBuilder.hashKeys().arrayListValues().build();
|
||||
FhirTerser terser = myFhirContext.newTerser();
|
||||
|
||||
for (int resourceIdx = 0; resourceIdx < theDetails.size(); resourceIdx++) {
|
||||
|
@ -182,6 +213,4 @@ public class MdmReadVirtualizationInterceptor<P extends IResourcePersistentId<?>
|
|||
private boolean isRemapCandidate(String theResourceType) {
|
||||
return myMdmSettings.isSupportedMdmType(theResourceType);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -49,5 +49,4 @@ public class MdmSearchExpandingInterceptor {
|
|||
myMdmSearchExpansionSvc.expandSearch(theRequestDetails, theSearchParameterMap, ReferenceParam::isMdmExpand);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -51,12 +51,15 @@ public class MdmSearchExpansionSvc {
|
|||
* by this function to determine whether it should be expanded.
|
||||
* @since 8.0.0
|
||||
*/
|
||||
public void expandSearch(RequestDetails theRequestDetails, SearchParameterMap theSearchParameterMap, Function<ReferenceParam, Boolean> theExpansionCandidateTester) {
|
||||
public void expandSearch(
|
||||
RequestDetails theRequestDetails,
|
||||
SearchParameterMap theSearchParameterMap,
|
||||
Function<ReferenceParam, Boolean> theExpansionCandidateTester) {
|
||||
final RequestDetails requestDetailsToUse =
|
||||
theRequestDetails == null ? new SystemRequestDetails() : theRequestDetails;
|
||||
theRequestDetails == null ? new SystemRequestDetails() : theRequestDetails;
|
||||
final RequestPartitionId requestPartitionId =
|
||||
myRequestPartitionHelperSvc.determineReadPartitionForRequestForSearchType(
|
||||
requestDetailsToUse, requestDetailsToUse.getResourceName(), theSearchParameterMap);
|
||||
myRequestPartitionHelperSvc.determineReadPartitionForRequestForSearchType(
|
||||
requestDetailsToUse, requestDetailsToUse.getResourceName(), theSearchParameterMap);
|
||||
for (Map.Entry<String, List<List<IQueryParameterType>>> set : theSearchParameterMap.entrySet()) {
|
||||
String paramName = set.getKey();
|
||||
List<List<IQueryParameterType>> andList = set.getValue();
|
||||
|
@ -69,7 +72,10 @@ public class MdmSearchExpansionSvc {
|
|||
}
|
||||
|
||||
private void expandAnyReferenceParameters(
|
||||
RequestPartitionId theRequestPartitionId, String theParamName, List<IQueryParameterType> orList, Function<ReferenceParam, Boolean> theExpansionCandidateTester) {
|
||||
RequestPartitionId theRequestPartitionId,
|
||||
String theParamName,
|
||||
List<IQueryParameterType> orList,
|
||||
Function<ReferenceParam, Boolean> theExpansionCandidateTester) {
|
||||
List<IQueryParameterType> toRemove = new ArrayList<>();
|
||||
List<IQueryParameterType> toAdd = new ArrayList<>();
|
||||
for (IQueryParameterType iQueryParameterType : orList) {
|
||||
|
@ -79,12 +85,12 @@ public class MdmSearchExpansionSvc {
|
|||
ourLog.debug("Found a reference parameter to expand: {}", refParam);
|
||||
// First, attempt to expand as a source resource.
|
||||
Set<String> expandedResourceIds = myMdmLinkExpandSvc.expandMdmBySourceResourceId(
|
||||
theRequestPartitionId, new IdDt(refParam.getValue()));
|
||||
theRequestPartitionId, new IdDt(refParam.getValue()));
|
||||
|
||||
// If we failed, attempt to expand as a golden resource
|
||||
if (expandedResourceIds.isEmpty()) {
|
||||
expandedResourceIds = myMdmLinkExpandSvc.expandMdmByGoldenResourceId(
|
||||
theRequestPartitionId, new IdDt(refParam.getValue()));
|
||||
theRequestPartitionId, new IdDt(refParam.getValue()));
|
||||
}
|
||||
|
||||
// Rebuild the search param list.
|
||||
|
@ -92,9 +98,9 @@ public class MdmSearchExpansionSvc {
|
|||
ourLog.debug("Parameter has been expanded to: {}", String.join(", ", expandedResourceIds));
|
||||
toRemove.add(refParam);
|
||||
expandedResourceIds.stream()
|
||||
.map(resourceId -> addResourceTypeIfNecessary(refParam.getResourceType(), resourceId))
|
||||
.map(ReferenceParam::new)
|
||||
.forEach(toAdd::add);
|
||||
.map(resourceId -> addResourceTypeIfNecessary(refParam.getResourceType(), resourceId))
|
||||
.map(ReferenceParam::new)
|
||||
.forEach(toAdd::add);
|
||||
}
|
||||
}
|
||||
} else if (theParamName.equalsIgnoreCase("_id")) {
|
||||
|
@ -124,10 +130,10 @@ public class MdmSearchExpansionSvc {
|
|||
* @param theRemoveList
|
||||
*/
|
||||
private void expandIdParameter(
|
||||
RequestPartitionId theRequestPartitionId,
|
||||
IQueryParameterType theIdParameter,
|
||||
List<IQueryParameterType> theAddList,
|
||||
List<IQueryParameterType> theRemoveList) {
|
||||
RequestPartitionId theRequestPartitionId,
|
||||
IQueryParameterType theIdParameter,
|
||||
List<IQueryParameterType> theAddList,
|
||||
List<IQueryParameterType> theRemoveList) {
|
||||
// id parameters can either be StringParam (for $everything operation)
|
||||
// or TokenParam (for searches)
|
||||
// either case, we want to expand it out and grab all related resources
|
||||
|
@ -147,8 +153,8 @@ public class MdmSearchExpansionSvc {
|
|||
if (id == null) {
|
||||
// in case the _id parameter type is different from the above
|
||||
ourLog.warn(
|
||||
"_id parameter of incorrect type. Expected StringParam or TokenParam, but got {}. No expansion will be done!",
|
||||
theIdParameter.getClass().getSimpleName());
|
||||
"_id parameter of incorrect type. Expected StringParam or TokenParam, but got {}. No expansion will be done!",
|
||||
theIdParameter.getClass().getSimpleName());
|
||||
} else if (mdmExpand) {
|
||||
ourLog.debug("_id parameter must be expanded out from: {}", id.getValue());
|
||||
|
||||
|
@ -171,5 +177,4 @@ public class MdmSearchExpansionSvc {
|
|||
}
|
||||
// else - no expansion required
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue