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}