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.expunge;
021
022import ca.uhn.fhir.mdm.api.IMdmSettings;
023import jakarta.annotation.Nonnull;
024import org.springframework.beans.factory.annotation.Autowired;
025import org.springframework.stereotype.Service;
026
027import java.util.ArrayList;
028import java.util.List;
029
030import static ca.uhn.fhir.jpa.entity.MdmLink.GOLDEN_RESOURCE_PARTITION_ID;
031import static ca.uhn.fhir.jpa.entity.MdmLink.GOLDEN_RESOURCE_PID;
032import static ca.uhn.fhir.jpa.entity.MdmLink.PERSON_PARTITION_ID;
033import static ca.uhn.fhir.jpa.entity.MdmLink.PERSON_PID;
034import static ca.uhn.fhir.jpa.entity.MdmLink.TARGET_PARTITION_ID;
035import static ca.uhn.fhir.jpa.entity.MdmLink.TARGET_PID;
036import static ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId.PARTITION_ID;
037import static ca.uhn.fhir.jpa.model.entity.ResourceLink.TARGET_RESOURCE_ID;
038import static ca.uhn.fhir.jpa.model.entity.ResourceLink.TARGET_RES_PARTITION_ID;
039
040@Service
041public class ResourceTableFKProvider {
042        @Autowired(required = false)
043        IMdmSettings myMdmSettings;
044
045        @Nonnull
046        public List<ResourceForeignKey> getResourceForeignKeys() {
047                List<ResourceForeignKey> retval = new ArrayList<>();
048
049                // To find all the FKs that need to be included here, run the following SQL in the INFORMATION_SCHEMA:
050                // SELECT FKTABLE_NAME, FKCOLUMN_NAME FROM CROSS_REFERENCES WHERE PKTABLE_NAME = 'HFJ_RESOURCE'
051
052                // Add some secondary related records that don't have foreign keys
053                retval.add(new ResourceForeignKey("HFJ_HISTORY_TAG", PARTITION_ID, "RES_ID")); // NOT covered by index.
054                retval.add(new ResourceForeignKey("HFJ_RES_VER_PROV", PARTITION_ID, "RES_PID"));
055
056                // These have the possibility of touching all resource types.
057                retval.add(new ResourceForeignKey("HFJ_IDX_CMP_STRING_UNIQ", PARTITION_ID, "RES_ID"));
058                retval.add(new ResourceForeignKey("HFJ_IDX_CMB_TOK_NU", PARTITION_ID, "RES_ID"));
059                retval.add(new ResourceForeignKey("HFJ_RES_LINK", PARTITION_ID, "SRC_RESOURCE_ID"));
060                retval.add(new ResourceForeignKey("HFJ_RES_LINK", TARGET_RES_PARTITION_ID, TARGET_RESOURCE_ID));
061                retval.add(new ResourceForeignKey("HFJ_RES_PARAM_PRESENT", PARTITION_ID, "RES_ID"));
062                retval.add(new ResourceForeignKey("HFJ_RES_TAG", PARTITION_ID, "RES_ID"));
063                retval.add(new ResourceForeignKey("HFJ_RES_VER", PARTITION_ID, "RES_ID"));
064                retval.add(new ResourceForeignKey("HFJ_SPIDX_COORDS", PARTITION_ID, "RES_ID"));
065                retval.add(new ResourceForeignKey("HFJ_SPIDX_DATE", PARTITION_ID, "RES_ID"));
066                retval.add(new ResourceForeignKey("HFJ_SPIDX_NUMBER", PARTITION_ID, "RES_ID"));
067                retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY", PARTITION_ID, "RES_ID"));
068                retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY_NRML", PARTITION_ID, "RES_ID"));
069                retval.add(new ResourceForeignKey("HFJ_SPIDX_STRING", PARTITION_ID, "RES_ID"));
070                retval.add(new ResourceForeignKey("HFJ_SPIDX_TOKEN", PARTITION_ID, "RES_ID"));
071                retval.add(new ResourceForeignKey("HFJ_SPIDX_URI", PARTITION_ID, "RES_ID"));
072                retval.add(new ResourceForeignKey("MPI_LINK", GOLDEN_RESOURCE_PARTITION_ID, GOLDEN_RESOURCE_PID));
073                retval.add(new ResourceForeignKey("MPI_LINK", TARGET_PARTITION_ID, TARGET_PID));
074                retval.add(new ResourceForeignKey("MPI_LINK", PERSON_PARTITION_ID, PERSON_PID));
075
076                // These only touch certain resource types.
077                retval.add(new ResourceForeignKey("TRM_CODESYSTEM_VER", PARTITION_ID, "RES_ID"));
078                retval.add(new ResourceForeignKey("TRM_CODESYSTEM", PARTITION_ID, "RES_ID"));
079                retval.add(new ResourceForeignKey("TRM_VALUESET", PARTITION_ID, "RES_ID"));
080                retval.add(new ResourceForeignKey("TRM_CONCEPT_MAP", PARTITION_ID, "RES_ID"));
081                retval.add(new ResourceForeignKey("NPM_PACKAGE_VER", PARTITION_ID, "BINARY_RES_ID"));
082                retval.add(new ResourceForeignKey("NPM_PACKAGE_VER_RES", PARTITION_ID, "BINARY_RES_ID"));
083
084                retval.add(new ResourceForeignKey("HFJ_RES_SEARCH_URL", PARTITION_ID, "RES_ID"));
085
086                return retval;
087        }
088
089        @Nonnull
090        public List<ResourceForeignKey> getResourceForeignKeysByResourceType(String theResourceType) {
091                List<ResourceForeignKey> retval = new ArrayList<>();
092                // These have the possibility of touching all resource types.
093                retval.add(new ResourceForeignKey("HFJ_HISTORY_TAG", PARTITION_ID, "RES_ID"));
094                retval.add(new ResourceForeignKey("HFJ_RES_VER_PROV", PARTITION_ID, "RES_PID"));
095                retval.add(new ResourceForeignKey("HFJ_IDX_CMP_STRING_UNIQ", PARTITION_ID, "RES_ID"));
096                retval.add(new ResourceForeignKey("HFJ_IDX_CMB_TOK_NU", PARTITION_ID, "RES_ID"));
097                retval.add(new ResourceForeignKey("HFJ_RES_LINK", PARTITION_ID, "SRC_RESOURCE_ID"));
098                retval.add(new ResourceForeignKey("HFJ_RES_LINK", TARGET_PARTITION_ID, TARGET_RESOURCE_ID));
099                retval.add(new ResourceForeignKey("HFJ_RES_PARAM_PRESENT", PARTITION_ID, "RES_ID"));
100                retval.add(new ResourceForeignKey(
101                                "HFJ_RES_TAG", PARTITION_ID, "RES_ID")); // TODO GGG: Res_ID + TAG_ID? is that enough?
102                retval.add(new ResourceForeignKey(
103                                "HFJ_RES_VER", PARTITION_ID, "RES_ID")); // TODO GGG: RES_ID + updated? is that enough?
104                retval.add(new ResourceForeignKey("HFJ_SPIDX_COORDS", PARTITION_ID, "RES_ID"));
105                retval.add(new ResourceForeignKey("HFJ_SPIDX_DATE", PARTITION_ID, "RES_ID"));
106                retval.add(new ResourceForeignKey("HFJ_SPIDX_NUMBER", PARTITION_ID, "RES_ID"));
107                retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY", PARTITION_ID, "RES_ID"));
108                retval.add(new ResourceForeignKey("HFJ_SPIDX_QUANTITY_NRML", PARTITION_ID, "RES_ID"));
109                retval.add(new ResourceForeignKey("HFJ_SPIDX_STRING", PARTITION_ID, "RES_ID"));
110                retval.add(new ResourceForeignKey("HFJ_SPIDX_TOKEN", PARTITION_ID, "RES_ID"));
111                retval.add(new ResourceForeignKey("HFJ_SPIDX_URI", PARTITION_ID, "RES_ID"));
112
113                if (myMdmSettings != null && myMdmSettings.isEnabled()) {
114                        retval.add(new ResourceForeignKey(
115                                        "MPI_LINK", GOLDEN_RESOURCE_PARTITION_ID, GOLDEN_RESOURCE_PID)); // NOT covered by index.
116                        retval.add(new ResourceForeignKey(
117                                        "MPI_LINK", TARGET_PARTITION_ID, TARGET_PID)); // Possibly covered, partial index
118                        retval.add(new ResourceForeignKey(
119                                        "MPI_LINK",
120                                        PERSON_PARTITION_ID,
121                                        PERSON_PID)); // TODO GGG: I don't even think we need this... this field is deprecated, and the
122                        // deletion is covered by GOLDEN_RESOURCE_PID
123                }
124
125                switch (theResourceType.toLowerCase()) {
126                        case "binary":
127                                retval.add(new ResourceForeignKey("NPM_PACKAGE_VER", PARTITION_ID, "BINARY_RES_ID")); // Not covered
128                                retval.add(new ResourceForeignKey("NPM_PACKAGE_VER_RES", PARTITION_ID, "BINARY_RES_ID")); // Not covered
129                                break;
130                        case "subscription":
131                                retval.add(
132                                                new ResourceForeignKey("HFJ_SUBSCRIPTION_STATS", PARTITION_ID, "RES_ID")); // Covered by index.
133                                break;
134                        case "codesystem":
135                                retval.add(new ResourceForeignKey("TRM_CODESYSTEM_VER", PARTITION_ID, "RES_ID")); // Not covered
136                                retval.add(new ResourceForeignKey("TRM_CODESYSTEM", PARTITION_ID, "RES_ID")); // Not covered
137                                break;
138                        case "valueset":
139                                retval.add(new ResourceForeignKey("TRM_VALUESET", PARTITION_ID, "RES_ID")); // Not covered
140                                break;
141                        case "conceptmap":
142                                retval.add(new ResourceForeignKey("TRM_CONCEPT_MAP", PARTITION_ID, "RES_ID")); // Not covered
143                                break;
144                        default:
145                }
146                return retval;
147        }
148}