001/*-
002 * #%L
003 * HAPI FHIR JPA Server
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.jpa.dao.data;
021
022import ca.uhn.fhir.jpa.entity.MdmLink;
023import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
024import org.springframework.data.domain.Pageable;
025import org.springframework.data.jpa.repository.JpaRepository;
026import org.springframework.data.jpa.repository.Modifying;
027import org.springframework.data.jpa.repository.Query;
028import org.springframework.data.repository.history.RevisionRepository;
029import org.springframework.data.repository.query.Param;
030import org.springframework.stereotype.Repository;
031
032import java.util.Date;
033import java.util.List;
034import java.util.Optional;
035
036@Repository
037public interface IMdmLinkJpaRepository
038                extends RevisionRepository<MdmLink, Long, Long>, JpaRepository<MdmLink, Long>, IHapiFhirJpaRepository {
039        @Modifying
040        @Query("DELETE FROM MdmLink f WHERE myGoldenResourcePid = :pid OR mySourcePid = :pid")
041        int deleteWithAnyReferenceToPid(@Param("pid") Long thePid);
042
043        @Modifying
044        @Query(
045                        "DELETE FROM MdmLink f WHERE (myGoldenResourcePid = :pid OR mySourcePid = :pid) AND myMatchResult <> :matchResult")
046        int deleteWithAnyReferenceToPidAndMatchResultNot(
047                        @Param("pid") Long thePid, @Param("matchResult") MdmMatchResultEnum theMatchResult);
048
049        @Modifying
050        @Query("DELETE FROM MdmLink f WHERE myGoldenResourcePid IN (:goldenPids) OR mySourcePid IN (:goldenPids)")
051        void deleteLinksWithAnyReferenceToPids(@Param("goldenPids") List<Long> theResourcePids);
052
053        @Modifying
054        @Query(
055                        value =
056                                        "DELETE FROM MPI_LINK_AUD WHERE GOLDEN_RESOURCE_PID IN (:goldenPids) OR TARGET_PID IN (:goldenPids)",
057                        nativeQuery = true)
058        void deleteLinksHistoryWithAnyReferenceToPids(@Param("goldenPids") List<Long> theResourcePids);
059
060        // TODO:  LD:  the calling code in JpaBulkExportProcessor doesn't yet leverage the partition IDs, but maybe it
061        // should?
062        @Query(
063                        "SELECT lookup_links.myGoldenResourcePid as goldenPid, gld_rt.myPartitionIdValue as goldenPartitionId, lookup_links.mySourcePid as sourcePid, lookup_links.myPartitionIdValue as sourcePartitionId "
064                                        + "FROM MdmLink lookup_links "
065                                        + "INNER JOIN ResourceTable gld_rt "
066                                        + "on lookup_links.myGoldenResourcePid=gld_rt.myId "
067                                        + "WHERE lookup_links.myMatchResult=:matchResult "
068                                        + "AND lookup_links.myGoldenResourcePid IN ("
069                                        + "SELECT inner_mdm_link.myGoldenResourcePid FROM MdmLink inner_mdm_link "
070                                        + "INNER JOIN ResourceLink inner_res_link "
071                                        + "ON inner_res_link.myTargetResourcePid=inner_mdm_link.mySourcePid "
072                                        + "AND inner_res_link.mySourceResourcePid=:groupPid "
073                                        + "AND inner_res_link.mySourcePath='Group.member.entity' "
074                                        + "AND inner_res_link.myTargetResourceType='Patient'"
075                                        + ")")
076        List<MdmPidTuple> expandPidsFromGroupPidGivenMatchResult(
077                        @Param("groupPid") Long theGroupPid, @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnum);
078
079        @Query("SELECT ml FROM MdmLink ml WHERE ml.mySourcePid = :sourcePid AND ml.myMatchResult = :matchResult")
080        Optional<MdmLink> findBySourcePidAndMatchResult(
081                        @Param("sourcePid") Long theSourcePid, @Param("matchResult") MdmMatchResultEnum theMatch);
082
083        interface MdmPidTuple {
084                Long getGoldenPid();
085
086                Integer getGoldenPartitionId();
087
088                Long getSourcePid();
089
090                Integer getSourcePartitionId();
091        }
092
093        @Query(
094                        "SELECT lookup_link.myGoldenResourcePid as goldenPid, gld_rt.myPartitionIdValue as goldenPartitionId, lookup_link.mySourcePid as sourcePid, lookup_link.myPartitionIdValue as sourcePartitionId "
095                                        + "FROM MdmLink lookup_link "
096                                        + "INNER JOIN MdmLink gld_link "
097                                        + "on lookup_link.myGoldenResourcePid=gld_link.myGoldenResourcePid "
098                                        + "INNER JOIN ResourceTable gld_rt "
099                                        + "on gld_link.myGoldenResourcePid=gld_rt.myId "
100                                        + "WHERE gld_link.mySourcePid=:sourcePid "
101                                        + "AND gld_link.myMatchResult=:matchResult "
102                                        + "AND lookup_link.myMatchResult=:matchResult")
103        List<MdmPidTuple> expandPidsBySourcePidAndMatchResult(
104                        @Param("sourcePid") Long theSourcePid, @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnum);
105
106        @Query("SELECT ml " + "FROM MdmLink ml "
107                        + "INNER JOIN MdmLink ml2 "
108                        + "on ml.myGoldenResourcePid=ml2.myGoldenResourcePid "
109                        + "WHERE ml2.mySourcePid=:sourcePid "
110                        + "AND ml2.myMatchResult!=:matchResult")
111        List<MdmLink> findLinksAssociatedWithGoldenResourceOfSourceResourceExcludingMatchResult(
112                        @Param("sourcePid") Long theSourcePid,
113                        @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnumToExclude);
114
115        @Query(
116                        "SELECT lookup_link.myGoldenResourcePid as goldenPid, gld_rt.myPartitionIdValue as goldenPartitionId, lookup_link.mySourcePid as sourcePid, lookup_link.myPartitionIdValue as sourcePartitionId "
117                                        + "FROM MdmLink lookup_link "
118                                        + "INNER JOIN ResourceTable gld_rt "
119                                        + "on lookup_link.myGoldenResourcePid=gld_rt.myId "
120                                        + "WHERE lookup_link.myGoldenResourcePid = :goldenPid "
121                                        + "AND lookup_link.myMatchResult = :matchResult")
122        List<MdmPidTuple> expandPidsByGoldenResourcePidAndMatchResult(
123                        @Param("goldenPid") Long theSourcePid, @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnum);
124
125        @Query(
126                        "SELECT ml.myId FROM MdmLink ml WHERE ml.myMdmSourceType = :resourceName AND ml.myCreated <= :highThreshold ORDER BY ml.myCreated DESC")
127        List<Long> findPidByResourceNameAndThreshold(
128                        @Param("resourceName") String theResourceName,
129                        @Param("highThreshold") Date theHighThreshold,
130                        Pageable thePageable);
131
132        @Query(
133                        "SELECT ml.myId FROM MdmLink ml WHERE ml.myMdmSourceType = :resourceName AND ml.myCreated <= :highThreshold AND ml.myPartitionIdValue IN :partitionId ORDER BY ml.myCreated DESC")
134        List<Long> findPidByResourceNameAndThresholdAndPartitionId(
135                        @Param("resourceName") String theResourceName,
136                        @Param("highThreshold") Date theHighThreshold,
137                        @Param("partitionId") List<Integer> thePartitionIds,
138                        Pageable thePageable);
139}