001/*-
002 * #%L
003 * HAPI FHIR Storage api
004 * %%
005 * Copyright (C) 2014 - 2023 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 org.hl7.fhir.instance.model.api.IAnyResource;
030import org.hl7.fhir.instance.model.api.IBaseResource;
031import org.hl7.fhir.instance.model.api.IIdType;
032
033import javax.annotation.Nonnull;
034import javax.annotation.Nullable;
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(@Nonnull RequestPartitionId theRequestPartitionId, List<IIdType> theIds, boolean theOnlyForcedIds);
057
058        /**
059         * Given a resource type and ID, determines the internal persistent ID for the resource.
060         *
061         * @throws ResourceNotFoundException If the ID can not be found
062         */
063        @Nonnull
064        T resolveResourcePersistentIds(@Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, String theId);
065
066        /**
067         * Given a resource type and ID, determines the internal persistent ID for a resource.
068         * Optionally filters out deleted resources.
069         *
070         * @throws ResourceNotFoundException If the ID can not be found
071         */
072        @Nonnull
073        T resolveResourcePersistentIds(@Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, String theId, boolean theExcludeDeleted);
074
075        /**
076         * Returns a mapping of Id -> IResourcePersistentId.
077         * If any resource is not found, it will throw ResourceNotFound exception
078         * (and no map will be returned)
079         */
080        @Nonnull
081        Map<String, T> resolveResourcePersistentIds(@Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, List<String> theIds);
082
083        /**
084         * Returns a mapping of Id -> IResourcePersistentId.
085         * If any resource is not found, it will throw ResourceNotFound exception (and no map will be returned)
086         * Optionally filters out deleted resources.
087         */
088        @Nonnull
089        Map<String, T> resolveResourcePersistentIds(@Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, List<String> theIds, boolean theExcludeDeleted);
090
091        /**
092         * Given a persistent ID, returns the associated resource ID
093         */
094        @Nonnull
095        IIdType translatePidIdToForcedId(FhirContext theCtx, String theResourceType, T theId);
096
097        /**
098         * Given a forced ID, convert it to it's Long value. Since you are allowed to use string IDs for resources, we need to
099         * convert those to the underlying Long values that are stored, for lookup and comparison purposes.
100         *
101         * @throws ResourceNotFoundException If the ID can not be found
102         */
103        @Nonnull
104        IResourceLookup resolveResourceIdentity(@Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, String theResourceId) throws ResourceNotFoundException;
105
106        /**
107         * Given a forced ID, convert it to it's Long value. Since you are allowed to use string IDs for resources, we need to
108         * convert those to the underlying Long values that are stored, for lookup and comparison purposes.
109         * Optionally filters out deleted resources.
110         *
111         * @throws ResourceNotFoundException If the ID can not be found
112         */
113        @Nonnull
114        IResourceLookup resolveResourceIdentity(@Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, String theResourceId, boolean theExcludeDeleted) throws ResourceNotFoundException;
115
116        /**
117         * Returns true if the given resource ID should be stored in a forced ID. Under default config
118         * (meaning client ID strategy is {@link JpaStorageSettings.ClientIdStrategyEnum#ALPHANUMERIC})
119         * this will return true if the ID has any non-digit characters.
120         * <p>
121         * In {@link JpaStorageSettings.ClientIdStrategyEnum#ANY} mode it will always return true.
122         */
123        boolean idRequiresForcedId(String theId);
124
125        /**
126         * Given a collection of resource IDs (resource type + id), resolves the internal persistent IDs.
127         * <p>
128         * This implementation will always try to use a cache for performance, meaning that it can resolve resources that
129         * are deleted (but note that forced IDs can't change, so the cache can't return incorrect results)
130         */
131        @Nonnull
132        List<T> resolveResourcePersistentIdsWithCache(RequestPartitionId theRequestPartitionId, List<IIdType> theIds);
133
134        Optional<String> translatePidIdToForcedIdWithCache(T theResourcePersistentId);
135
136        PersistentIdToForcedIdMap<T> translatePidsToForcedIds(Set<T> theResourceIds);
137
138        /**
139         * Pre-cache a PID-to-Resource-ID mapping for later retrieval by {@link #translatePidsToForcedIds(Set)} and related methods
140         */
141        void addResolvedPidToForcedId(T theResourcePersistentId, @Nonnull RequestPartitionId theRequestPartitionId, String theResourceType, @Nullable String theForcedId, @Nullable Date theDeletedAt);
142
143        @Nonnull
144        List<T> getPidsOrThrowException(RequestPartitionId theRequestPartitionId, List<IIdType> theIds);
145
146        @Nullable
147        T getPidOrNull(RequestPartitionId theRequestPartitionId, IBaseResource theResource);
148
149        @Nonnull
150        T getPidOrThrowException(RequestPartitionId theRequestPartitionId, IIdType theId);
151
152        @Nonnull
153        T getPidOrThrowException(@Nonnull IAnyResource theResource);
154
155        IIdType resourceIdFromPidOrThrowException(T thePid, String theResourceType);
156
157        /**
158         * Given a set of PIDs, return a set of public FHIR Resource IDs.
159         * 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
160         * Example:
161         * Let's say we have Patient/1(pid == 1), Patient/pat1 (pid == 2), Patient/3 (pid == 3), their pids would resolve as follows:
162         * <p>
163         * [1,2,3] -> ["1","pat1","3"]
164         *
165         * @param thePids The Set of pids you would like to resolve to external FHIR Resource IDs.
166         * @return A Set of strings representing the FHIR IDs of the pids.
167         */
168        Set<String> translatePidsToFhirResourceIds(Set<T> thePids);
169
170        T newPid(Object thePid);
171
172        T newPidFromStringIdAndResourceName(String thePid, String theResourceType);
173}