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.dao.data.custom.IForcedIdQueries; 023import ca.uhn.fhir.jpa.model.entity.ResourceTable; 024import org.springframework.data.domain.Pageable; 025import org.springframework.data.domain.Slice; 026import org.springframework.data.jpa.repository.JpaRepository; 027import org.springframework.data.jpa.repository.Modifying; 028import org.springframework.data.jpa.repository.Query; 029import org.springframework.data.repository.query.Param; 030import org.springframework.transaction.annotation.Propagation; 031import org.springframework.transaction.annotation.Transactional; 032 033import java.util.Collection; 034import java.util.Date; 035import java.util.List; 036import java.util.Map; 037import java.util.Optional; 038import java.util.stream.Stream; 039 040@Transactional(propagation = Propagation.MANDATORY) 041public interface IResourceTableDao 042 extends JpaRepository<ResourceTable, Long>, IHapiFhirJpaRepository, IForcedIdQueries { 043 044 @Query("SELECT t.myId FROM ResourceTable t WHERE t.myDeleted IS NOT NULL") 045 Slice<Long> findIdsOfDeletedResources(Pageable thePageable); 046 047 @Query("SELECT t.myId FROM ResourceTable t WHERE t.myResourceType = :restype AND t.myDeleted IS NOT NULL") 048 Slice<Long> findIdsOfDeletedResourcesOfType(Pageable thePageable, @Param("restype") String theResourceName); 049 050 @Query( 051 "SELECT t.myId FROM ResourceTable t WHERE t.myId = :resid AND t.myResourceType = :restype AND t.myDeleted IS NOT NULL") 052 Slice<Long> findIdsOfDeletedResourcesOfType( 053 Pageable thePageable, @Param("resid") Long theResourceId, @Param("restype") String theResourceName); 054 055 @Query( 056 "SELECT t.myResourceType as type, COUNT(t.myResourceType) as count FROM ResourceTable t GROUP BY t.myResourceType") 057 List<Map<?, ?>> getResourceCounts(); 058 059 @Query( 060 "SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated DESC") 061 Slice<Long> findIdsOfResourcesWithinUpdatedRangeOrderedFromNewest( 062 Pageable thePage, @Param("low") Date theLow, @Param("high") Date theHigh); 063 064 @Query( 065 "SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC") 066 Slice<Long> findIdsOfResourcesWithinUpdatedRangeOrderedFromOldest( 067 Pageable thePage, @Param("low") Date theLow, @Param("high") Date theHigh); 068 069 @Query( 070 "SELECT t.myId, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC") 071 Stream<Object[]> streamIdsTypesAndUpdateTimesOfResourcesWithinUpdatedRangeOrderedFromOldest( 072 @Param("low") Date theLow, @Param("high") Date theHigh); 073 074 /** 075 * @return List of arrays containing [PID, resourceType, lastUpdated] 076 */ 077 @Query( 078 "SELECT t.myId, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high AND t.myPartitionIdValue IN (:partition_ids) ORDER BY t.myUpdated ASC") 079 Slice<Object[]> findIdsTypesAndUpdateTimesOfResourcesWithinUpdatedRangeOrderedFromOldestForPartitionIds( 080 Pageable thePage, 081 @Param("low") Date theLow, 082 @Param("high") Date theHigh, 083 @Param("partition_ids") List<Integer> theRequestPartitionIds); 084 085 @Query( 086 "SELECT t.myId, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high AND t.myPartitionIdValue IN (:partition_ids) ORDER BY t.myUpdated ASC") 087 Stream<Object[]> streamIdsTypesAndUpdateTimesOfResourcesWithinUpdatedRangeOrderedFromOldestForPartitionIds( 088 @Param("low") Date theLow, 089 @Param("high") Date theHigh, 090 @Param("partition_ids") List<Integer> theRequestPartitionIds); 091 092 /** 093 * @return List of arrays containing [PID, resourceType, lastUpdated] 094 */ 095 @Query( 096 "SELECT t.myId, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC") 097 Slice<Object[]> findIdsTypesAndUpdateTimesOfResourcesWithinUpdatedRangeOrderedFromOldestForDefaultPartition( 098 Pageable thePage, @Param("low") Date theLow, @Param("high") Date theHigh); 099 100 @Query( 101 "SELECT t.myId, t.myResourceType, t.myUpdated FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high ORDER BY t.myUpdated ASC") 102 Stream<Object[]> streamIdsTypesAndUpdateTimesOfResourcesWithinUpdatedRangeOrderedFromOldestForDefaultPartition( 103 @Param("low") Date theLow, @Param("high") Date theHigh); 104 105 // TODO in the future, consider sorting by pid as well so batch jobs process in the same order across restarts 106 @Query( 107 "SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high AND t.myPartitionIdValue = :partition_id ORDER BY t.myUpdated ASC") 108 Slice<Long> findIdsOfPartitionedResourcesWithinUpdatedRangeOrderedFromOldest( 109 Pageable thePage, 110 @Param("low") Date theLow, 111 @Param("high") Date theHigh, 112 @Param("partition_id") Integer theRequestPartitionId); 113 114 @Query( 115 "SELECT t.myId FROM ResourceTable t WHERE t.myUpdated >= :low AND t.myUpdated <= :high AND t.myResourceType = :restype ORDER BY t.myUpdated ASC") 116 Slice<Long> findIdsOfResourcesWithinUpdatedRangeOrderedFromOldest( 117 Pageable thePage, 118 @Param("restype") String theResourceType, 119 @Param("low") Date theLow, 120 @Param("high") Date theHigh); 121 122 @Modifying 123 @Query("UPDATE ResourceTable t SET t.myIndexStatus = :status WHERE t.myId = :id") 124 void updateIndexStatus(@Param("id") Long theId, @Param("status") Long theIndexStatus); 125 126 @Modifying 127 @Query("UPDATE ResourceTable t SET t.myUpdated = :updated WHERE t.myId = :id") 128 void updateLastUpdated(@Param("id") Long theId, @Param("updated") Date theUpdated); 129 130 @Modifying 131 @Query("DELETE FROM ResourceTable t WHERE t.myId = :pid") 132 void deleteByPid(@Param("pid") Long theId); 133 134 /** 135 * This method returns a Collection where each row is an element in the collection. Each element in the collection 136 * is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way. 137 */ 138 @Query( 139 "SELECT t.myResourceType, t.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myId IN (:pid)") 140 Collection<Object[]> findLookupFieldsByResourcePid(@Param("pid") List<Long> thePids); 141 142 /** 143 * This method returns a Collection where each row is an element in the collection. Each element in the collection 144 * is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way. 145 */ 146 @Query( 147 "SELECT t.myResourceType, t.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myId IN (:pid) AND t.myPartitionIdValue IN :partition_id") 148 Collection<Object[]> findLookupFieldsByResourcePidInPartitionIds( 149 @Param("pid") List<Long> thePids, @Param("partition_id") Collection<Integer> thePartitionId); 150 151 /** 152 * This method returns a Collection where each row is an element in the collection. Each element in the collection 153 * is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way. 154 */ 155 @Query( 156 "SELECT t.myResourceType, t.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myId IN (:pid) AND (t.myPartitionIdValue IS NULL OR t.myPartitionIdValue IN :partition_id)") 157 Collection<Object[]> findLookupFieldsByResourcePidInPartitionIdsOrNullPartition( 158 @Param("pid") List<Long> thePids, @Param("partition_id") Collection<Integer> thePartitionId); 159 160 /** 161 * This method returns a Collection where each row is an element in the collection. Each element in the collection 162 * is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way. 163 */ 164 @Query( 165 "SELECT t.myResourceType, t.myId, t.myDeleted, t.myPartitionIdValue, t.myPartitionDateValue FROM ResourceTable t WHERE t.myId IN (:pid) AND t.myPartitionIdValue IS NULL") 166 Collection<Object[]> findLookupFieldsByResourcePidInPartitionNull(@Param("pid") List<Long> thePids); 167 168 @Query("SELECT t.myVersion FROM ResourceTable t WHERE t.myId = :pid") 169 Long findCurrentVersionByPid(@Param("pid") Long thePid); 170 171 /** 172 * This query will return rows with the following values: 173 * Id (resource pid - long), ResourceType (Patient, etc), version (long) 174 * Order matters! 175 * @param pid - list of pids to get versions for 176 * @return 177 */ 178 @Query("SELECT t.myId, t.myResourceType, t.myVersion FROM ResourceTable t WHERE t.myId IN ( :pid )") 179 Collection<Object[]> getResourceVersionsForPid(@Param("pid") List<Long> pid); 180 181 @Query("SELECT t FROM ResourceTable t WHERE t.myPartitionId.myPartitionId IS NULL AND t.myId = :pid") 182 Optional<ResourceTable> readByPartitionIdNull(@Param("pid") Long theResourceId); 183 184 @Query("SELECT t FROM ResourceTable t WHERE t.myPartitionId.myPartitionId = :partitionId AND t.myId = :pid") 185 Optional<ResourceTable> readByPartitionId( 186 @Param("partitionId") int thePartitionId, @Param("pid") Long theResourceId); 187 188 @Query( 189 "SELECT t FROM ResourceTable t WHERE (t.myPartitionId.myPartitionId IS NULL OR t.myPartitionId.myPartitionId IN (:partitionIds)) AND t.myId = :pid") 190 Optional<ResourceTable> readByPartitionIdsOrNull( 191 @Param("partitionIds") Collection<Integer> thrValues, @Param("pid") Long theResourceId); 192 193 @Query("SELECT t FROM ResourceTable t WHERE t.myPartitionId.myPartitionId IN (:partitionIds) AND t.myId = :pid") 194 Optional<ResourceTable> readByPartitionIds( 195 @Param("partitionIds") Collection<Integer> thrValues, @Param("pid") Long theResourceId); 196 197 @Query("SELECT t FROM ResourceTable t WHERE t.myId IN :pids") 198 List<ResourceTable> findAllByIdAndLoadForcedIds(@Param("pids") List<Long> thePids); 199 200 @Query("SELECT t FROM ResourceTable t where t.myResourceType = :restype and t.myFhirId = :fhirId") 201 Optional<ResourceTable> findByTypeAndFhirId( 202 @Param("restype") String theResourceName, @Param("fhirId") String theFhirId); 203}