001/*-
002 * #%L
003 * HAPI FHIR JPA Server
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.sp;
021
022import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
023import ca.uhn.fhir.jpa.dao.data.ISearchParamPresentDao;
024import ca.uhn.fhir.jpa.model.entity.ResourceTable;
025import ca.uhn.fhir.jpa.model.entity.SearchParamPresentEntity;
026import ca.uhn.fhir.jpa.util.AddRemoveCount;
027import com.google.common.annotations.VisibleForTesting;
028import org.springframework.beans.factory.annotation.Autowired;
029import org.springframework.stereotype.Service;
030
031import java.util.ArrayList;
032import java.util.Collection;
033import java.util.HashMap;
034import java.util.List;
035import java.util.Map;
036import java.util.Map.Entry;
037
038@Service
039public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc {
040
041        @Autowired
042        private ISearchParamPresentDao mySearchParamPresentDao;
043
044        @Autowired
045        private JpaStorageSettings myStorageSettings;
046
047        @VisibleForTesting
048        public void setStorageSettings(JpaStorageSettings theStorageSettings) {
049                myStorageSettings = theStorageSettings;
050        }
051
052        @Override
053        public AddRemoveCount updatePresence(
054                        ResourceTable theResource, Collection<SearchParamPresentEntity> thePresenceEntities) {
055                AddRemoveCount retVal = new AddRemoveCount();
056                if (myStorageSettings.getIndexMissingFields() == JpaStorageSettings.IndexEnabledEnum.DISABLED) {
057                        return retVal;
058                }
059
060                // Find existing entries
061                Collection<SearchParamPresentEntity> existing = theResource.getSearchParamPresents();
062                Map<Long, SearchParamPresentEntity> existingHashToPresence = new HashMap<>();
063                for (SearchParamPresentEntity nextExistingEntity : existing) {
064                        existingHashToPresence.put(nextExistingEntity.getHashPresence(), nextExistingEntity);
065                }
066
067                // Find newly wanted set of entries
068                Map<Long, SearchParamPresentEntity> newHashToPresence = new HashMap<>();
069                for (SearchParamPresentEntity next : thePresenceEntities) {
070                        newHashToPresence.put(next.getHashPresence(), next);
071                }
072
073                // Delete any that should be deleted
074                List<SearchParamPresentEntity> toDelete = new ArrayList<>();
075                for (Entry<Long, SearchParamPresentEntity> nextEntry : existingHashToPresence.entrySet()) {
076                        if (newHashToPresence.containsKey(nextEntry.getKey()) == false) {
077                                toDelete.add(nextEntry.getValue());
078                        }
079                }
080                // Add any that should be added
081                List<SearchParamPresentEntity> toAdd = new ArrayList<>();
082                for (Entry<Long, SearchParamPresentEntity> nextEntry : newHashToPresence.entrySet()) {
083                        if (existingHashToPresence.containsKey(nextEntry.getKey()) == false) {
084                                toAdd.add(nextEntry.getValue());
085                        }
086                }
087
088                // Try to reuse any entities we can
089                while (toDelete.size() > 0 && toAdd.size() > 0) {
090                        SearchParamPresentEntity nextToDelete = toDelete.remove(toDelete.size() - 1);
091                        SearchParamPresentEntity nextToAdd = toAdd.remove(toAdd.size() - 1);
092                        nextToDelete.updateValues(nextToAdd);
093                        mySearchParamPresentDao.save(nextToDelete);
094                        retVal.addToAddCount(1);
095                        retVal.addToRemoveCount(1);
096                }
097
098                mySearchParamPresentDao.deleteAll(toDelete);
099                retVal.addToRemoveCount(toDelete.size());
100
101                mySearchParamPresentDao.saveAll(toAdd);
102                retVal.addToRemoveCount(toAdd.size());
103
104                return retVal;
105        }
106}