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