001/*- 002 * #%L 003 * HAPI FHIR Storage api 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.api.svc; 021 022import ca.uhn.fhir.context.FhirContext; 023import ca.uhn.fhir.interceptor.model.RequestPartitionId; 024import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; 025import ca.uhn.fhir.jpa.api.model.PersistentIdToForcedIdMap; 026import ca.uhn.fhir.jpa.model.cross.IResourceLookup; 027import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId; 028import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; 029import jakarta.annotation.Nonnull; 030import jakarta.annotation.Nullable; 031import org.hl7.fhir.instance.model.api.IAnyResource; 032import org.hl7.fhir.instance.model.api.IBaseResource; 033import org.hl7.fhir.instance.model.api.IIdType; 034 035import java.util.Date; 036import java.util.List; 037import java.util.Map; 038import java.util.Optional; 039import java.util.Set; 040 041/** 042 * This interface is used to translate between {@link IResourcePersistentId} 043 * and actual resource IDs. 044 */ 045public interface IIdHelperService<T extends IResourcePersistentId> { 046 047 /** 048 * Given a collection of resource IDs (resource type + id), resolves the internal persistent IDs. 049 * <p> 050 * This implementation will always try to use a cache for performance, meaning that it can resolve resources that 051 * are deleted (but note that forced IDs can't change, so the cache can't return incorrect results) 052 * 053 * @param theOnlyForcedIds If <code>true</code>, resources which are not existing forced IDs will not be resolved 054 */ 055 @Nonnull 056 List<T> resolveResourcePersistentIdsWithCache( 057 @Nonnull RequestPartitionId theRequestPartitionId, List<IIdType> theIds, boolean theOnlyForcedIds); 058 059 /** 060 * Given a resource type and ID, determines the internal persistent ID for the resource. 061 * 062 * @throws ResourceNotFoundException If the ID can not be found 063 */ 064 @Nonnull 065 T resolveResourcePersistentIds( 066 @Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, String theId); 067 068 /** 069 * Given a resource type and ID, determines the internal persistent ID for a resource. 070 * Optionally filters out deleted resources. 071 * 072 * @throws ResourceNotFoundException If the ID can not be found 073 */ 074 @Nonnull 075 T resolveResourcePersistentIds( 076 @Nonnull RequestPartitionId theRequestPartitionId, 077 String theResourceType, 078 String theId, 079 boolean theExcludeDeleted); 080 081 /** 082 * Returns a mapping of Id -> IResourcePersistentId. 083 * If any resource is not found, it will throw ResourceNotFound exception 084 * (and no map will be returned) 085 */ 086 @Nonnull 087 Map<String, T> resolveResourcePersistentIds( 088 @Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, List<String> theIds); 089 090 /** 091 * Returns a mapping of Id -> IResourcePersistentId. 092 * If any resource is not found, it will throw ResourceNotFound exception (and no map will be returned) 093 * Optionally filters out deleted resources. 094 */ 095 @Nonnull 096 Map<String, T> resolveResourcePersistentIds( 097 @Nonnull RequestPartitionId theRequestPartitionId, 098 String theResourceType, 099 List<String> theIds, 100 boolean theExcludeDeleted); 101 102 /** 103 * Given a persistent ID, returns the associated resource ID 104 */ 105 @Nonnull 106 IIdType translatePidIdToForcedId(FhirContext theCtx, String theResourceType, T theId); 107 108 /** 109 * Given a forced ID, convert it to it's Long value. Since you are allowed to use string IDs for resources, we need to 110 * convert those to the underlying Long values that are stored, for lookup and comparison purposes. 111 * 112 * @throws ResourceNotFoundException If the ID can not be found 113 */ 114 @Nonnull 115 IResourceLookup resolveResourceIdentity( 116 @Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, String theResourceId) 117 throws ResourceNotFoundException; 118 119 /** 120 * Given a forced ID, convert it to it's Long value. Since you are allowed to use string IDs for resources, we need to 121 * convert those to the underlying Long values that are stored, for lookup and comparison purposes. 122 * Optionally filters out deleted resources. 123 * 124 * @throws ResourceNotFoundException If the ID can not be found 125 */ 126 @Nonnull 127 IResourceLookup resolveResourceIdentity( 128 @Nonnull RequestPartitionId theRequestPartitionId, 129 String theResourceType, 130 String theResourceId, 131 boolean theExcludeDeleted) 132 throws ResourceNotFoundException; 133 134 /** 135 * Returns true if the given resource ID should be stored in a forced ID. Under default config 136 * (meaning client ID strategy is {@link JpaStorageSettings.ClientIdStrategyEnum#ALPHANUMERIC}) 137 * this will return true if the ID has any non-digit characters. 138 * <p> 139 * In {@link JpaStorageSettings.ClientIdStrategyEnum#ANY} mode it will always return true. 140 */ 141 boolean idRequiresForcedId(String theId); 142 143 /** 144 * Given a collection of resource IDs (resource type + id), resolves the internal persistent IDs. 145 * <p> 146 * This implementation will always try to use a cache for performance, meaning that it can resolve resources that 147 * are deleted (but note that forced IDs can't change, so the cache can't return incorrect results) 148 */ 149 @Nonnull 150 List<T> resolveResourcePersistentIdsWithCache(RequestPartitionId theRequestPartitionId, List<IIdType> theIds); 151 152 Optional<String> translatePidIdToForcedIdWithCache(T theResourcePersistentId); 153 154 PersistentIdToForcedIdMap<T> translatePidsToForcedIds(Set<T> theResourceIds); 155 156 /** 157 * Pre-cache a PID-to-Resource-ID mapping for later retrieval by {@link #translatePidsToForcedIds(Set)} and related methods 158 */ 159 void addResolvedPidToForcedId( 160 T theResourcePersistentId, 161 @Nonnull RequestPartitionId theRequestPartitionId, 162 String theResourceType, 163 @Nullable String theForcedId, 164 @Nullable Date theDeletedAt); 165 166 @Nonnull 167 List<T> getPidsOrThrowException(RequestPartitionId theRequestPartitionId, List<IIdType> theIds); 168 169 @Nullable 170 T getPidOrNull(RequestPartitionId theRequestPartitionId, IBaseResource theResource); 171 172 @Nonnull 173 T getPidOrThrowException(RequestPartitionId theRequestPartitionId, IIdType theId); 174 175 @Nonnull 176 T getPidOrThrowException(@Nonnull IAnyResource theResource); 177 178 IIdType resourceIdFromPidOrThrowException(T thePid, String theResourceType); 179 180 /** 181 * Given a set of PIDs, return a set of public FHIR Resource IDs. 182 * This function will resolve a forced ID if it resolves, and if it fails to resolve to a forced it, will just return the pid 183 * Example: 184 * Let's say we have Patient/1(pid == 1), Patient/pat1 (pid == 2), Patient/3 (pid == 3), their pids would resolve as follows: 185 * <p> 186 * [1,2,3] -> ["1","pat1","3"] 187 * 188 * @param thePids The Set of pids you would like to resolve to external FHIR Resource IDs. 189 * @return A Set of strings representing the FHIR IDs of the pids. 190 */ 191 Set<String> translatePidsToFhirResourceIds(Set<T> thePids); 192 193 T newPid(Object thePid); 194 195 T newPidFromStringIdAndResourceName(String thePid, String theResourceType); 196}