All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc Maven / Gradle / Ivy

The newest version!
/*-
 * #%L
 * HAPI FHIR JPA Server - Master Data Management
 * %%
 * Copyright (C) 2014 - 2024 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%
 */
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.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.MdmLinkWithRevision;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.api.params.MdmHistorySearchParameters;
import ca.uhn.fhir.mdm.api.params.MdmQuerySearchParameters;
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 ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
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.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.history.Revisions;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;

public class MdmLinkDaoSvc

> { private static final Logger ourLog = Logs.getMdmTroubleshootingLog(); @Autowired private IMdmLinkDao myMdmLinkDao; @Autowired private MdmLinkFactory myMdmLinkFactory; @Autowired private IIdHelperService

myIdHelperService; @Autowired private FhirContext myFhirContext; @Transactional public M createOrUpdateLinkEntity( IAnyResource theGoldenResource, IAnyResource theSourceResource, MdmMatchOutcome theMatchOutcome, MdmLinkSourceEnum theLinkSource, @Nullable MdmTransactionContext theMdmTransactionContext) { M mdmLink = getOrCreateMdmLinkByGoldenResourceAndSourceResource(theGoldenResource, theSourceResource); mdmLink.setLinkSource(theLinkSource); mdmLink.setMatchResult(theMatchOutcome.getMatchResultEnum()); // Preserve these flags for link updates mdmLink.setEidMatch(theMatchOutcome.isEidMatch() | mdmLink.isEidMatchPresent()); mdmLink.setHadToCreateNewGoldenResource( theMatchOutcome.isCreatedNewResource() | mdmLink.getHadToCreateNewGoldenResource()); mdmLink.setMdmSourceType(myFhirContext.getResourceType(theSourceResource)); setScoreProperties(theMatchOutcome, mdmLink); // Add partition for the mdm link if it's available in the source resource RequestPartitionId partitionId = (RequestPartitionId) theSourceResource.getUserData(Constants.RESOURCE_PARTITION_ID); if (partitionId != null && partitionId.getFirstPartitionIdOrNull() != null) { mdmLink.setPartitionId(new PartitionablePartitionId( partitionId.getFirstPartitionIdOrNull(), partitionId.getPartitionDate())); } String message = String.format( "Creating %s link from %s to Golden Resource %s.", mdmLink.getMatchResult(), theSourceResource.getIdElement().toUnqualifiedVersionless(), theGoldenResource.getIdElement().toUnqualifiedVersionless()); theMdmTransactionContext.addTransactionLogMessage(message); ourLog.debug(message); save(mdmLink); return mdmLink; } private void setScoreProperties(MdmMatchOutcome theMatchOutcome, M mdmLink) { if (theMatchOutcome.getScore() != null) { mdmLink.setScore( mdmLink.getScore() != null ? Math.max(theMatchOutcome.getNormalizedScore(), mdmLink.getScore()) : theMatchOutcome.getNormalizedScore()); } if (theMatchOutcome.getVector() != null) { mdmLink.setVector( mdmLink.getVector() != null ? Math.max(theMatchOutcome.getVector(), mdmLink.getVector()) : theMatchOutcome.getVector()); } mdmLink.setRuleCount( mdmLink.getRuleCount() != null ? Math.max(theMatchOutcome.getMdmRuleCount(), mdmLink.getRuleCount()) : theMatchOutcome.getMdmRuleCount()); } @Nonnull public M getOrCreateMdmLinkByGoldenResourceAndSourceResource( IAnyResource theGoldenResource, IAnyResource theSourceResource) { P goldenResourcePid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theGoldenResource); P sourceResourcePid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theSourceResource); Optional oExisting = getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourcePid, sourceResourcePid); if (oExisting.isPresent()) { return oExisting.get(); } else { M newLink = myMdmLinkFactory.newMdmLink(); newLink.setGoldenResourcePersistenceId(goldenResourcePid); newLink.setSourcePersistenceId(sourceResourcePid); return newLink; } } /** * Given a golden resource Pid and source Pid, return the mdm link that matches these criterias if exists * * @param theGoldenResourcePid * @param theSourceResourcePid * @return * @deprecated This was deprecated in favour of using ResourcePersistenceId rather than longs */ @Deprecated public Optional getLinkByGoldenResourcePidAndSourceResourcePid( Long theGoldenResourcePid, Long theSourceResourcePid) { return getLinkByGoldenResourcePidAndSourceResourcePid( myIdHelperService.newPid(theGoldenResourcePid), myIdHelperService.newPid(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 getLinkByGoldenResourcePidAndSourceResourcePid(P theGoldenResourcePid, P theSourceResourcePid) { if (theSourceResourcePid == null || theGoldenResourcePid == null) { return Optional.empty(); } M link = myMdmLinkFactory.newMdmLinkVersionless(); link.setSourcePersistenceId(theSourceResourcePid); link.setGoldenResourcePersistenceId(theGoldenResourcePid); // TODO - replace the use of example search Example example = Example.of(link); return myMdmLinkDao.findOne(example); } /** * Given a source resource Pid, and a match result, return all links that match these criteria. * * @param theSourcePid the source of the relationship. * @param theMatchResult the Match Result of the relationship * @return a list of {@link IMdmLink} entities matching these criteria. */ public List getMdmLinksBySourcePidAndMatchResult(P theSourcePid, MdmMatchResultEnum theMatchResult) { M exampleLink = myMdmLinkFactory.newMdmLinkVersionless(); exampleLink.setSourcePersistenceId(theSourcePid); exampleLink.setMatchResult(theMatchResult); Example example = Example.of(exampleLink); return myMdmLinkDao.findAll(example); } /** * 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 IMdmLink} that contains the Match information for the source. */ @Deprecated @Transactional public Optional getMatchedLinkForSourcePid(P theSourcePid) { return myMdmLinkDao.findBySourcePidAndMatchResult(theSourcePid, MdmMatchResultEnum.MATCH); } /** * 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 IMdmLink} that contains the Match information for the source. */ public Optional getMatchedLinkForSource(IBaseResource theSourceResource) { return getMdmLinkWithMatchResult(theSourceResource, MdmMatchResultEnum.MATCH); } public Optional getPossibleMatchedLinkForSource(IBaseResource theSourceResource) { return getMdmLinkWithMatchResult(theSourceResource, MdmMatchResultEnum.POSSIBLE_MATCH); } @Nonnull private Optional getMdmLinkWithMatchResult(IBaseResource theSourceResource, MdmMatchResultEnum theMatchResult) { P pid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theSourceResource); if (pid == null) { return Optional.empty(); } M exampleLink = myMdmLinkFactory.newMdmLinkVersionless(); exampleLink.setSourcePersistenceId(pid); exampleLink.setMatchResult(theMatchResult); Example example = Example.of(exampleLink); return myMdmLinkDao.findOne(example); } /** * 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 IMdmLink} containing the matched link if it exists. */ public Optional getMdmLinksByGoldenResourcePidSourcePidAndMatchResult( Long theGoldenResourcePid, Long theSourcePid, MdmMatchResultEnum theMatchResult) { return getMdmLinksByGoldenResourcePidSourcePidAndMatchResult( myIdHelperService.newPid(theGoldenResourcePid), myIdHelperService.newPid(theSourcePid), theMatchResult); } public Optional getMdmLinksByGoldenResourcePidSourcePidAndMatchResult( P theGoldenResourcePid, P theSourcePid, MdmMatchResultEnum theMatchResult) { M exampleLink = myMdmLinkFactory.newMdmLinkVersionless(); exampleLink.setGoldenResourcePersistenceId(theGoldenResourcePid); exampleLink.setSourcePersistenceId(theSourcePid); exampleLink.setMatchResult(theMatchResult); Example example = Example.of(exampleLink); return myMdmLinkDao.findOne(example); } /** * Get all {@link IMdmLink} which have {@link MdmMatchResultEnum#POSSIBLE_DUPLICATE} as their match result. * * @return A list of {@link IMdmLink} that hold potential duplicate golden resources. */ public List getPossibleDuplicates() { M exampleLink = myMdmLinkFactory.newMdmLinkVersionless(); exampleLink.setMatchResult(MdmMatchResultEnum.POSSIBLE_DUPLICATE); Example example = Example.of(exampleLink); return myMdmLinkDao.findAll(example); } @Transactional public Optional findMdmLinkBySource(IBaseResource theSourceResource) { @Nullable P pid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theSourceResource); if (pid == null) { return Optional.empty(); } M exampleLink = myMdmLinkFactory.newMdmLinkVersionless(); exampleLink.setSourcePersistenceId(pid); Example example = Example.of(exampleLink); return myMdmLinkDao.findOne(example); } /** * 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 IMdmLink} to delete. */ @Transactional(propagation = Propagation.REQUIRES_NEW) public void deleteLink(M 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 IMdmLink} * * @param theGoldenResource The {@link IBaseResource} Golden Resource who's links you would like to retrieve. * @return A list of all {@link IMdmLink} entities in which theGoldenResource is the source Golden Resource */ @Transactional public List findMdmLinksByGoldenResource(IBaseResource theGoldenResource) { P pid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theGoldenResource); if (pid == null) { return Collections.emptyList(); } M exampleLink = myMdmLinkFactory.newMdmLinkVersionless(); exampleLink.setGoldenResourcePersistenceId(pid); Example example = Example.of(exampleLink); return myMdmLinkDao.findAll(example); } /** * Persist an MDM link to the database. * * @param theMdmLink the link to save. * @return the persisted {@link IMdmLink} entity. */ public M save(M theMdmLink) { M mdmLink = myMdmLinkDao.validateMdmLink(theMdmLink); if (mdmLink.getCreated() == null) { mdmLink.setCreated(new Date()); } mdmLink.setUpdated(new Date()); return myMdmLinkDao.save(mdmLink); } /** * Given a list of criteria, return all links from the database which fits the criteria provided * * @param theMdmQuerySearchParameters The {@link MdmQuerySearchParameters} being searched. * @return a list of {@link IMdmLink} entities which match the example. */ public Page executeTypedQuery(MdmQuerySearchParameters theMdmQuerySearchParameters) { return myMdmLinkDao.search(theMdmQuerySearchParameters); } /** * 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 findMdmLinksBySourceResource(IBaseResource theSourceResource) { P pid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theSourceResource); if (pid == null) { return Collections.emptyList(); } M exampleLink = myMdmLinkFactory.newMdmLinkVersionless(); exampleLink.setSourcePersistenceId(pid); Example example = Example.of(exampleLink); return myMdmLinkDao.findAll(example); } /** * 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 findMdmMatchLinksByGoldenResource(IBaseResource theGoldenResource) { P pid = myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theGoldenResource); if (pid == null) { return Collections.emptyList(); } M exampleLink = myMdmLinkFactory.newMdmLinkVersionless(); exampleLink.setGoldenResourcePersistenceId(pid); exampleLink.setMatchResult(MdmMatchResultEnum.MATCH); Example example = Example.of(exampleLink); return myMdmLinkDao.findAll(example); } /** * 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 IMdmLink}. */ public IMdmLink newMdmLink() { return myMdmLinkFactory.newMdmLink(); } public Optional getMatchedOrPossibleMatchedLinkForSource(IAnyResource theResource) { // TODO KHS instead of two queries, just do one query with an OR Optional retval = getMatchedLinkForSource(theResource); if (!retval.isPresent()) { retval = getPossibleMatchedLinkForSource(theResource); } return retval; } public Optional getLinkByGoldenResourceAndSourceResource( @Nullable IAnyResource theGoldenResource, @Nullable IAnyResource theSourceResource) { if (theGoldenResource == null || theSourceResource == null) { return Optional.empty(); } return getLinkByGoldenResourcePidAndSourceResourcePid( myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theGoldenResource), myIdHelperService.getPidOrNull(RequestPartitionId.allPartitions(), theSourceResource)); } @Transactional(propagation = Propagation.MANDATORY) public void deleteLinksWithAnyReferenceToPids(List

theGoldenResourcePids) { myMdmLinkDao.deleteLinksWithAnyReferenceToPids(theGoldenResourcePids); } // TODO: LD: delete for good on the next bump @Deprecated(since = "6.5.7", forRemoval = true) public Revisions findMdmLinkHistory(M mdmLink) { return myMdmLinkDao.findHistory(mdmLink.getId()); } @Transactional public List> findMdmLinkHistory(MdmHistorySearchParameters theMdmHistorySearchParameters) { return myMdmLinkDao.getHistoryForIds(theMdmHistorySearchParameters); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy