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.term.api;
021
022import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
023import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao;
024import ca.uhn.fhir.jpa.dao.data.ITermConceptDao;
025import ca.uhn.fhir.jpa.dao.data.ITermConceptDesignationDao;
026import ca.uhn.fhir.jpa.dao.data.ITermConceptParentChildLinkDao;
027import ca.uhn.fhir.jpa.dao.data.ITermConceptPropertyDao;
028import ca.uhn.fhir.jpa.entity.TermCodeSystem;
029import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
030import ca.uhn.fhir.jpa.model.entity.IdAndPartitionId;
031import ca.uhn.fhir.jpa.term.models.CodeSystemConceptsDeleteResult;
032import org.slf4j.Logger;
033import org.slf4j.LoggerFactory;
034import org.springframework.beans.factory.annotation.Autowired;
035import org.springframework.transaction.annotation.Transactional;
036
037import java.text.DecimalFormat;
038import java.util.Collections;
039import java.util.Iterator;
040import java.util.List;
041import java.util.Optional;
042import java.util.stream.Collectors;
043
044@Transactional
045public class TermCodeSystemDeleteJobSvc implements ITermCodeSystemDeleteJobSvc {
046        private static final Logger ourLog = LoggerFactory.getLogger(TermCodeSystemDeleteJobSvc.class);
047
048        private static final DecimalFormat ourDecimalFormat = new DecimalFormat("#,###");
049
050        @Autowired
051        private ITermConceptDao myConceptDao;
052
053        @Autowired
054        private ITermCodeSystemDao myCodeSystemDao;
055
056        @Autowired
057        private ITermCodeSystemVersionDao myTermCodeSystemVersionDao;
058
059        @Autowired
060        private ITermConceptParentChildLinkDao myConceptParentChildLinkDao;
061
062        @Autowired
063        private ITermConceptPropertyDao myConceptPropertyDao;
064
065        @Autowired
066        private ITermConceptDesignationDao myConceptDesignationDao;
067
068        @Autowired
069        private ITermCodeSystemDao myTermCodeSystemDao;
070
071        @Autowired
072        private ITermDeferredStorageSvc myDeferredStorageSvc;
073
074        @Override
075        public Iterator<IdAndPartitionId> getAllCodeSystemVersionForCodeSystemPid(long thePid) {
076                // TODO - make this a pageable iterator
077                List<Object[]> pids = myTermCodeSystemVersionDao.findSortedPidsByCodeSystemPid(thePid);
078
079                if (pids == null) {
080                        return Collections.emptyIterator();
081                }
082
083                return pids.stream()
084                                .map(t -> new IdAndPartitionId((Long) t[1], (Integer) t[0]))
085                                .collect(Collectors.toList())
086                                .iterator();
087        }
088
089        @Override
090        public CodeSystemConceptsDeleteResult deleteCodeSystemConceptsByCodeSystemVersionPid(long theCodeSystemVersionPid) {
091                CodeSystemConceptsDeleteResult result = new CodeSystemConceptsDeleteResult();
092
093                // code system links delete
094                ourLog.info("Deleting term code links");
095                int deletedLinks = myConceptParentChildLinkDao.deleteByCodeSystemVersion(theCodeSystemVersionPid);
096                ourLog.info("Deleted {} term code links", ourDecimalFormat.format(deletedLinks));
097                result.setDeletedLinks(deletedLinks);
098
099                // code system concept properties
100                ourLog.info("Deleting term code properties");
101                int deletedProperties = myConceptPropertyDao.deleteByCodeSystemVersion(theCodeSystemVersionPid);
102                ourLog.info("Deleted {} term code properties", ourDecimalFormat.format(deletedProperties));
103                result.setDeletedProperties(deletedProperties);
104
105                // code system concept designations
106                ourLog.info("Deleting concept designations");
107                int deletedDesignations = myConceptDesignationDao.deleteByCodeSystemVersion(theCodeSystemVersionPid);
108                ourLog.info("Deleted {} concept designations", ourDecimalFormat.format(deletedDesignations));
109                result.setDeletedDesignations(deletedDesignations);
110
111                // code system concept
112                ourLog.info("Deleting concepts");
113                int deletedConcepts = myConceptDao.deleteByCodeSystemVersion(theCodeSystemVersionPid);
114                ourLog.info("Deleted {} concepts", ourDecimalFormat.format(deletedConcepts));
115                result.setCodeSystemConceptDelete(deletedConcepts);
116
117                return result;
118        }
119
120        @Override
121        public void deleteCodeSystemVersion(long theVersionPid) {
122                ourLog.debug("Executing for codeSystemVersionId: {}", theVersionPid);
123
124                // if TermCodeSystemVersion being deleted is current, disconnect it form TermCodeSystem
125                Optional<TermCodeSystem> codeSystemOpt =
126                                myCodeSystemDao.findWithCodeSystemVersionAsCurrentVersion(theVersionPid);
127                if (codeSystemOpt.isPresent()) {
128                        TermCodeSystem codeSystem = codeSystemOpt.get();
129                        ourLog.info(
130                                        "Removing code system version: {} as current version of code system: {}",
131                                        theVersionPid,
132                                        codeSystem.getPid());
133                        codeSystem.setCurrentVersion(null);
134                        myCodeSystemDao.save(codeSystem);
135                }
136
137                ourLog.info("Deleting code system version: {}", theVersionPid);
138                Optional<TermCodeSystemVersion> csv = myTermCodeSystemVersionDao.findByPid(theVersionPid);
139                csv.ifPresent(theTermCodeSystemVersion -> {
140                        myTermCodeSystemVersionDao.delete(theTermCodeSystemVersion);
141                        ourLog.info("Code system version: {} deleted", theVersionPid);
142                });
143        }
144
145        @Override
146        public void deleteCodeSystem(long thePid) {
147                ourLog.info("Deleting code system by id : {}", thePid);
148
149                Optional<TermCodeSystem> csop = myTermCodeSystemDao.findByPid(thePid);
150                if (csop.isPresent()) {
151                        TermCodeSystem cs = csop.get();
152
153                        ourLog.info("Deleting code system {} / {}", thePid, cs.getCodeSystemUri());
154
155                        myTermCodeSystemDao.deleteById(cs.getPartitionedId());
156
157                        ourLog.info("Code system {} deleted", thePid);
158                }
159        }
160
161        @Override
162        public void notifyJobComplete(String theJobId) {
163                myDeferredStorageSvc.notifyJobEnded(theJobId);
164        }
165}