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.Collection;
033import java.util.Date;
034import java.util.List;
035import java.util.Optional;
036
037@Repository
038public interface IMdmLinkJpaRepository
039                extends RevisionRepository<MdmLink, Long, Long>, JpaRepository<MdmLink, Long>, IHapiFhirJpaRepository {
040        @Modifying
041        @Query("DELETE FROM MdmLink f WHERE myGoldenResourcePid = :pid OR mySourcePid = :pid")
042        int deleteWithAnyReferenceToPid(@Param("pid") Long thePid);
043
044        @Modifying
045        @Query(
046                        "DELETE FROM MdmLink f WHERE (myGoldenResourcePid = :pid OR mySourcePid = :pid) AND myMatchResult <> :matchResult")
047        int deleteWithAnyReferenceToPidAndMatchResultNot(
048                        @Param("pid") Long thePid, @Param("matchResult") MdmMatchResultEnum theMatchResult);
049
050        @Modifying
051        @Query("DELETE FROM MdmLink f WHERE myGoldenResourcePid IN (:goldenPids) OR mySourcePid IN (:goldenPids)")
052        void deleteLinksWithAnyReferenceToPids(@Param("goldenPids") List<Long> theResourcePids);
053
054        @Modifying
055        @Query(
056                        value =
057                                        "DELETE FROM MPI_LINK_AUD WHERE GOLDEN_RESOURCE_PID IN (:goldenPids) OR TARGET_PID IN (:goldenPids)",
058                        nativeQuery = true)
059        void deleteLinksHistoryWithAnyReferenceToPids(@Param("goldenPids") List<Long> theResourcePids);
060
061        // TODO:  LD:  the calling code in JpaBulkExportProcessor doesn't yet leverage the partition IDs, but maybe it
062        // should?
063        @Query(
064                        "SELECT lookup_links.myGoldenResourcePid as goldenPid, gld_rt.myPartitionIdValue as goldenPartitionId, lookup_links.mySourcePid as sourcePid, lookup_links.myPartitionIdValue as sourcePartitionId "
065                                        + "FROM MdmLink lookup_links "
066                                        + "INNER JOIN ResourceTable gld_rt "
067                                        + "on lookup_links.myGoldenResourcePid=gld_rt.myId "
068                                        + "WHERE lookup_links.myMatchResult=:matchResult "
069                                        + "AND lookup_links.myGoldenResourcePid IN ("
070                                        + "SELECT inner_mdm_link.myGoldenResourcePid FROM MdmLink inner_mdm_link "
071                                        + "INNER JOIN ResourceLink inner_res_link "
072                                        + "ON inner_res_link.myTargetResourcePid=inner_mdm_link.mySourcePid "
073                                        + "AND inner_res_link.mySourceResourcePid=:groupPid "
074                                        + "AND inner_res_link.mySourcePath='Group.member.entity' "
075                                        + "AND inner_res_link.myTargetResourceType='Patient'"
076                                        + ")")
077        List<MdmPidTuple> expandPidsFromGroupPidGivenMatchResult(
078                        @Param("groupPid") Long theGroupPid, @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnum);
079
080        @Query("SELECT ml FROM MdmLink ml WHERE ml.mySourcePid = :sourcePid AND ml.myMatchResult = :matchResult")
081        Optional<MdmLink> findBySourcePidAndMatchResult(
082                        @Param("sourcePid") Long theSourcePid, @Param("matchResult") MdmMatchResultEnum theMatch);
083
084        interface MdmPidTuple {
085                Long getGoldenPid();
086
087                Integer getGoldenPartitionId();
088
089                Long getSourcePid();
090
091                Integer getSourcePartitionId();
092        }
093
094        @Query(
095                        "SELECT lookup_link.myGoldenResourcePid as goldenPid, gld_rt.myPartitionIdValue as goldenPartitionId, lookup_link.mySourcePid as sourcePid, lookup_link.myPartitionIdValue as sourcePartitionId "
096                                        + "FROM MdmLink lookup_link "
097                                        + "INNER JOIN MdmLink gld_link "
098                                        + "on lookup_link.myGoldenResourcePid=gld_link.myGoldenResourcePid "
099                                        + "INNER JOIN ResourceTable gld_rt "
100                                        + "on gld_link.myGoldenResourcePid=gld_rt.myId "
101                                        + "WHERE gld_link.mySourcePid=:sourcePid "
102                                        + "AND gld_link.myMatchResult=:matchResult "
103                                        + "AND lookup_link.myMatchResult=:matchResult")
104        List<MdmPidTuple> expandPidsBySourcePidAndMatchResult(
105                        @Param("sourcePid") Long theSourcePid, @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnum);
106
107        @Query("SELECT ml " + "FROM MdmLink ml "
108                        + "INNER JOIN MdmLink ml2 "
109                        + "on ml.myGoldenResourcePid=ml2.myGoldenResourcePid "
110                        + "WHERE ml2.mySourcePid=:sourcePid "
111                        + "AND ml2.myMatchResult!=:matchResult")
112        List<MdmLink> findLinksAssociatedWithGoldenResourceOfSourceResourceExcludingMatchResult(
113                        @Param("sourcePid") Long theSourcePid,
114                        @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnumToExclude);
115
116        @Query(
117                        "SELECT lookup_link.myGoldenResourcePid as goldenPid, gld_rt.myPartitionIdValue as goldenPartitionId, lookup_link.mySourcePid as sourcePid, lookup_link.myPartitionIdValue as sourcePartitionId "
118                                        + "FROM MdmLink lookup_link "
119                                        + "INNER JOIN ResourceTable gld_rt "
120                                        + "on lookup_link.myGoldenResourcePid=gld_rt.myId "
121                                        + "WHERE lookup_link.myGoldenResourcePid = :goldenPid "
122                                        + "AND lookup_link.myMatchResult = :matchResult")
123        List<MdmPidTuple> expandPidsByGoldenResourcePidAndMatchResult(
124                        @Param("goldenPid") Long theSourcePid, @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnum);
125
126        @Query(
127                        "SELECT lookup_link.myGoldenResourcePid as goldenPid, gld_rt.myPartitionIdValue as goldenPartitionId, lookup_link.mySourcePid as sourcePid, lookup_link.myPartitionIdValue as sourcePartitionId "
128                                        + "FROM MdmLink lookup_link "
129                                        + "INNER JOIN ResourceTable gld_rt "
130                                        + "on lookup_link.myGoldenResourcePid=gld_rt.myId "
131                                        + "WHERE "
132                                        + "   (lookup_link.myGoldenResourcePid IN (:pids) "
133                                        + "    OR"
134                                        + "    lookup_link.mySourcePid IN (:pids))"
135                                        + "AND lookup_link.myMatchResult = :matchResult")
136        List<MdmPidTuple> expandPidsByGoldenResourcePidsOrSourcePidsAndMatchResult(
137                        @Param("pids") Collection<Long> theSourcePid,
138                        @Param("matchResult") MdmMatchResultEnum theMdmMatchResultEnum);
139
140        @Query(
141                        "SELECT ml.myId FROM MdmLink ml WHERE ml.myMdmSourceType = :resourceName AND ml.myCreated <= :highThreshold ORDER BY ml.myCreated DESC")
142        List<Long> findPidByResourceNameAndThreshold(
143                        @Param("resourceName") String theResourceName,
144                        @Param("highThreshold") Date theHighThreshold,
145                        Pageable thePageable);
146
147        @Query(
148                        "SELECT ml.myId FROM MdmLink ml WHERE ml.myMdmSourceType = :resourceName AND ml.myCreated <= :highThreshold AND ml.myPartitionIdValue IN :partitionId ORDER BY ml.myCreated DESC")
149        List<Long> findPidByResourceNameAndThresholdAndPartitionId(
150                        @Param("resourceName") String theResourceName,
151                        @Param("highThreshold") Date theHighThreshold,
152                        @Param("partitionId") List<Integer> thePartitionIds,
153                        Pageable thePageable);
154}