Work on presence API

This commit is contained in:
James Agnew 2018-06-29 14:32:08 -04:00
parent 03fc593cb9
commit bb637c5433
8 changed files with 91 additions and 190 deletions

View File

@ -326,7 +326,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
});
txTemplate.execute(t -> {
doExpungeEverythingQuery("DELETE from " + SearchParamPresent.class.getSimpleName() + " d");
doExpungeEverythingQuery("DELETE from " + SearchParam.class.getSimpleName() + " d");
doExpungeEverythingQuery("DELETE from " + ForcedId.class.getSimpleName() + " d");
doExpungeEverythingQuery("DELETE from " + ResourceIndexedSearchParamDate.class.getSimpleName() + " d");
doExpungeEverythingQuery("DELETE from " + ResourceIndexedSearchParamNumber.class.getSimpleName() + " d");

View File

@ -297,11 +297,10 @@ public class SearchBuilder implements ISearchBuilder {
private void addPredicateParamMissing(String theResourceName, String theParamName, boolean theMissing) {
Join<ResourceTable, SearchParamPresent> paramPresentJoin = myResourceTableRoot.join("mySearchParamPresents", JoinType.LEFT);
Join<SearchParamPresent, SearchParam> paramJoin = paramPresentJoin.join("mySearchParam", JoinType.LEFT);
myPredicates.add(myBuilder.equal(paramJoin.get("myResourceName"), theResourceName));
myPredicates.add(myBuilder.equal(paramJoin.get("myParamName"), theParamName));
myPredicates.add(myBuilder.equal(paramPresentJoin.get("myPresent"), !theMissing));
Expression<Long> hashPresence = paramPresentJoin.get("myHashPresence").as(Long.class);
Long hash = SearchParamPresent.calculateHashPresence(theResourceName, theParamName, !theMissing);
myPredicates.add(myBuilder.equal(hashPresence, hash));
}
private void addPredicateParamMissing(String theResourceName, String theParamName, boolean theMissing, Join<ResourceTable, ? extends BaseResourceIndexedSearchParam> theJoin) {

View File

@ -1,34 +0,0 @@
package ca.uhn.fhir.jpa.dao.data;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ca.uhn.fhir.jpa.entity.SearchParam;
public interface ISearchParamDao extends JpaRepository<SearchParam, Long> {
@Query("SELECT s FROM SearchParam s WHERE s.myResourceName = :resname AND s.myParamName = :parmname")
public SearchParam findForResource(@Param("resname") String theResourceType, @Param("parmname") String theParamName);
}

View File

@ -1,59 +0,0 @@
package ca.uhn.fhir.jpa.entity;
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2018 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import javax.persistence.*;
@Entity
@Table(name = "HFJ_SEARCH_PARM", uniqueConstraints= {
@UniqueConstraint(name="IDX_SEARCHPARM_RESTYPE_SPNAME", columnNames= {"RES_TYPE", "PARAM_NAME"})
})
public class SearchParam {
@Id
@SequenceGenerator(name = "SEQ_SEARCHPARM_ID", sequenceName = "SEQ_SEARCHPARM_ID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SEARCHPARM_ID")
@Column(name = "PID")
private Long myId;
@Column(name="PARAM_NAME", length=BaseResourceIndexedSearchParam.MAX_SP_NAME, nullable=false, updatable=false)
private String myParamName;
@Column(name="RES_TYPE", length=ResourceTable.RESTYPE_LEN, nullable=false, updatable=false)
private String myResourceName;
public String getParamName() {
return myParamName;
}
public void setParamName(String theParamName) {
myParamName = theParamName;
}
public void setResourceName(String theResourceName) {
myResourceName = theResourceName;
}
public Long getId() {
return myId;
}
}

View File

@ -20,18 +20,16 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
import java.io.Serializable;
import javax.persistence.*;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.persistence.*;
import java.io.Serializable;
@Entity
@Table(name = "HFJ_RES_PARAM_PRESENT", indexes = {
@Index(name = "IDX_RESPARMPRESENT_RESID", columnList = "RES_ID")
}, uniqueConstraints = {
@UniqueConstraint(name = "IDX_RESPARMPRESENT_SPID_RESID", columnNames = { "SP_ID", "RES_ID" })
@Index(name = "IDX_RESPARMPRESENT_RESID", columnList = "RES_ID"),
@Index(name = "IDX_RESPARMPRESENT_HASHPRES", columnList = "HASH_PRESENCE")
})
public class SearchParamPresent implements Serializable {
@ -42,17 +40,15 @@ public class SearchParamPresent implements Serializable {
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESPARMPRESENT_ID")
@Column(name = "PID")
private Long myId;
@Column(name = "SP_PRESENT", nullable = false)
private boolean myPresent;
@ManyToOne()
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, foreignKey = @ForeignKey(name = "FK_RESPARMPRES_RESID"))
private ResourceTable myResource;
@ManyToOne()
@JoinColumn(name = "SP_ID", referencedColumnName = "PID", nullable = false, foreignKey = @ForeignKey(name = "FK_RESPARMPRES_SPID"))
private SearchParam mySearchParam;
@Transient
private transient String myParamName;
@Column(name = "HASH_PRESENCE")
private Long myHashPresence;
/**
* Constructor
@ -61,12 +57,39 @@ public class SearchParamPresent implements Serializable {
super();
}
@SuppressWarnings("unused")
@PrePersist
public void calculateHashes() {
if (myHashPresence == null) {
String resourceType = getResource().getResourceType();
String paramName = getParamName();
boolean present = myPresent;
setHashPresence(calculateHashPresence(resourceType, paramName, present));
}
}
public Long getHashPresence() {
return myHashPresence;
}
public void setHashPresence(Long theHashPresence) {
myHashPresence = theHashPresence;
}
public String getParamName() {
return myParamName;
}
public void setParamName(String theParamName) {
myParamName = theParamName;
}
public ResourceTable getResource() {
return myResource;
}
public SearchParam getSearchParam() {
return mySearchParam;
public void setResource(ResourceTable theResourceTable) {
myResource = theResourceTable;
}
public boolean isPresent() {
@ -77,22 +100,18 @@ public class SearchParamPresent implements Serializable {
myPresent = thePresent;
}
public void setResource(ResourceTable theResourceTable) {
myResource = theResourceTable;
}
public void setSearchParam(SearchParam theSearchParam) {
mySearchParam = theSearchParam;
}
@Override
public String toString() {
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
b.append("res_pid", myResource.getIdDt().toUnqualifiedVersionless().getValue());
b.append("param", mySearchParam.getParamName());
b.append("resPid", myResource.getIdDt().toUnqualifiedVersionless().getValue());
b.append("paramName", myParamName);
b.append("present", myPresent);
return b.build();
}
public static long calculateHashPresence(String theResourceType, String theParamName, boolean thePresent) {
return BaseResourceIndexedSearchParam.hash(theResourceType, theParamName, Boolean.toString(thePresent));
}
}

View File

@ -20,14 +20,12 @@ package ca.uhn.fhir.jpa.sp;
* #L%
*/
import java.util.Map;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import java.util.Map;
public interface ISearchParamPresenceSvc {
void updatePresence(ResourceTable theResource, Map<String, Boolean> theParamNameToPresence);
void flushCachesForUnitTest();
}

View File

@ -20,29 +20,17 @@ package ca.uhn.fhir.jpa.sp;
* #L%
*/
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.jpa.dao.data.ISearchParamDao;
import ca.uhn.fhir.jpa.dao.data.ISearchParamPresentDao;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.SearchParam;
import ca.uhn.fhir.jpa.entity.SearchParamPresent;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.*;
import java.util.Map.Entry;
public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamPresenceSvcImpl.class);
private Map<Pair<String, String>, SearchParam> myResourceTypeToSearchParamToEntity = new ConcurrentHashMap<Pair<String, String>, SearchParam>();
@Autowired
private ISearchParamDao mySearchParamDao;
@Autowired
private ISearchParamPresentDao mySearchParamPresentDao;
@ -55,62 +43,48 @@ public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc {
return;
}
Map<String, Boolean> presenceMap = new HashMap<String, Boolean>(theParamNameToPresence);
List<SearchParamPresent> entitiesToSave = new ArrayList<SearchParamPresent>();
List<SearchParamPresent> entitiesToDelete = new ArrayList<SearchParamPresent>();
Map<String, Boolean> presenceMap = new HashMap<>(theParamNameToPresence);
// Find existing entries
Collection<SearchParamPresent> existing;
existing = mySearchParamPresentDao.findAllForResource(theResource);
Map<Long, SearchParamPresent> existingHashToPresence = new HashMap<>();
for (SearchParamPresent nextExistingEntity : existing) {
String nextSearchParamName = nextExistingEntity.getSearchParam().getParamName();
Boolean existingValue = presenceMap.remove(nextSearchParamName);
if (existingValue == null) {
entitiesToDelete.add(nextExistingEntity);
} else if (existingValue.booleanValue() == nextExistingEntity.isPresent()) {
ourLog.trace("No change for search param {}", nextSearchParamName);
} else {
nextExistingEntity.setPresent(existingValue);
entitiesToSave.add(nextExistingEntity);
}
existingHashToPresence.put(nextExistingEntity.getHashPresence(), nextExistingEntity);
}
// Find newly wanted set of entries
Map<Long, SearchParamPresent> newHashToPresence = new HashMap<>();
for (Entry<String, Boolean> next : presenceMap.entrySet()) {
String resourceType = theResource.getResourceType();
String paramName = next.getKey();
Pair<String, String> key = Pair.of(resourceType, paramName);
SearchParam searchParam = myResourceTypeToSearchParamToEntity.get(key);
if (searchParam == null) {
searchParam = mySearchParamDao.findForResource(resourceType, paramName);
if (searchParam != null) {
myResourceTypeToSearchParamToEntity.put(key, searchParam);
} else {
searchParam = new SearchParam();
searchParam.setResourceName(resourceType);
searchParam.setParamName(paramName);
searchParam = mySearchParamDao.save(searchParam);
ourLog.info("Added search param {} with pid {}", paramName, searchParam.getId());
// Don't add the newly saved entity to the map in case the save fails
}
}
SearchParamPresent present = new SearchParamPresent();
present.setResource(theResource);
present.setSearchParam(searchParam);
present.setParamName(paramName);
present.setPresent(next.getValue());
entitiesToSave.add(present);
present.calculateHashes();
newHashToPresence.put(present.getHashPresence(), present);
}
// Delete any that should be deleted
List<SearchParamPresent> toDelete = new ArrayList<>();
for (Entry<Long, SearchParamPresent> nextEntry : existingHashToPresence.entrySet()) {
if (newHashToPresence.containsKey(nextEntry.getKey()) == false) {
toDelete.add(nextEntry.getValue());
}
}
mySearchParamPresentDao.deleteInBatch(toDelete);
// Add any that should be added
List<SearchParamPresent> toAdd = new ArrayList<>();
for (Entry<Long, SearchParamPresent> nextEntry : newHashToPresence.entrySet()) {
if (existingHashToPresence.containsKey(nextEntry.getKey()) == false) {
toAdd.add(nextEntry.getValue());
}
}
mySearchParamPresentDao.saveAll(toAdd);
}
mySearchParamPresentDao.deleteInBatch(entitiesToDelete);
mySearchParamPresentDao.saveAll(entitiesToSave);
}
@Override
public void flushCachesForUnitTest() {
myResourceTypeToSearchParamToEntity.clear();
}
}

View File

@ -156,3 +156,8 @@ drop index IDX_FORCEDID_TYPE_FORCEDID;
create index IDX_FORCEDID_TYPE_FID;
drop index IDX_SP_NUMBER;
create index IDX_SP_NUMBER_HASH_VAL;
drop column SP_ID from table HFJ_RES_PARAM_PRESENT;
drop index IDX_SEARCHPARM_RESTYPE_SPNAME;
drop index IDX_RESPARMPRESENT_SPID_RESID;
drop table HFJ_SEARCH_PARM;