Page JPA search results to the database
This commit is contained in:
parent
8de41ca8b4
commit
3bfcb57783
|
@ -38,6 +38,8 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
|||
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvc;
|
||||
import ca.uhn.fhir.jpa.term.ITerminologySvc;
|
||||
import ca.uhn.fhir.jpa.term.TerminologySvcImpl;
|
||||
|
||||
|
@ -62,6 +64,11 @@ public class BaseConfig implements SchedulingConfigurer {
|
|||
theTaskRegistrar.setTaskScheduler(taskScheduler());
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
|
||||
return new DatabaseBackedPagingProvider(10);
|
||||
}
|
||||
|
||||
@Bean(name = "myFhirContextDstu1")
|
||||
@Lazy
|
||||
public FhirContext fhirContextDstu1() {
|
||||
|
@ -99,10 +106,10 @@ public class BaseConfig implements SchedulingConfigurer {
|
|||
}
|
||||
|
||||
@Bean(autowire=Autowire.BY_TYPE)
|
||||
public ITerminologySvc terminologyService() {
|
||||
return new TerminologySvcImpl();
|
||||
public StaleSearchDeletingSvc staleSearchDeletingSvc() {
|
||||
return new StaleSearchDeletingSvc();
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public TaskScheduler taskScheduler() {
|
||||
ThreadPoolTaskScheduler retVal = new ThreadPoolTaskScheduler();
|
||||
|
@ -110,14 +117,11 @@ public class BaseConfig implements SchedulingConfigurer {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* This lets the "@Value" fields reference properties from the properties file
|
||||
*/
|
||||
@Bean
|
||||
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public ITerminologySvc terminologyService() {
|
||||
return new TerminologySvcImpl();
|
||||
}
|
||||
|
||||
|
||||
// @PostConstruct
|
||||
// public void wireResourceDaos() {
|
||||
// Map<String, IDao> daoBeans = myAppCtx.getBeansOfType(IDao.class);
|
||||
|
@ -127,4 +131,12 @@ public class BaseConfig implements SchedulingConfigurer {
|
|||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* This lets the "@Value" fields reference properties from the properties file
|
||||
*/
|
||||
@Bean
|
||||
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@ import org.springframework.context.annotation.Primary;
|
|||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.FhirSearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
|
||||
@Configuration
|
||||
|
@ -42,6 +42,18 @@ public class BaseDstu2Config extends BaseConfig {
|
|||
return fhirContextDstu2();
|
||||
}
|
||||
|
||||
@Bean(name = "myJpaValidationSupportDstu2", autowire = Autowire.BY_NAME)
|
||||
public ca.uhn.fhir.jpa.dao.IJpaValidationSupportDstu2 jpaValidationSupportDstu2() {
|
||||
ca.uhn.fhir.jpa.dao.JpaValidationSupportDstu2 retVal = new ca.uhn.fhir.jpa.dao.JpaValidationSupportDstu2();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IFulltextSearchSvc searchDao() {
|
||||
FulltextSearchSvcImpl searchDao = new FulltextSearchSvcImpl();
|
||||
return searchDao;
|
||||
}
|
||||
|
||||
@Bean(name = "mySystemDaoDstu2", autowire = Autowire.BY_NAME)
|
||||
public IFhirSystemDao<ca.uhn.fhir.model.dstu2.resource.Bundle, MetaDt> systemDaoDstu2() {
|
||||
ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu2 retVal = new ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu2();
|
||||
|
@ -54,17 +66,4 @@ public class BaseDstu2Config extends BaseConfig {
|
|||
retVal.setDao(systemDaoDstu2());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(name = "myJpaValidationSupportDstu2", autowire = Autowire.BY_NAME)
|
||||
public ca.uhn.fhir.jpa.dao.IJpaValidationSupportDstu2 jpaValidationSupportDstu2() {
|
||||
ca.uhn.fhir.jpa.dao.JpaValidationSupportDstu2 retVal = new ca.uhn.fhir.jpa.dao.JpaValidationSupportDstu2();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public ISearchDao searchDao() {
|
||||
FhirSearchDao searchDao = new FhirSearchDao();
|
||||
return searchDao;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,9 +34,9 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.config.BaseConfig;
|
||||
import ca.uhn.fhir.jpa.dao.FhirSearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
|
||||
|
@ -50,6 +50,35 @@ public class BaseDstu3Config extends BaseConfig {
|
|||
return fhirContextDstu3();
|
||||
}
|
||||
|
||||
@Bean(name="myInstanceValidatorDstu3")
|
||||
@Lazy
|
||||
public IValidatorModule instanceValidatorDstu3() {
|
||||
FhirInstanceValidator val = new FhirInstanceValidator();
|
||||
val.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning);
|
||||
val.setValidationSupport(validationSupportChainDstu3());
|
||||
return val;
|
||||
}
|
||||
|
||||
@Bean(name = "myJpaValidationSupportDstu3", autowire = Autowire.BY_NAME)
|
||||
public ca.uhn.fhir.jpa.dao.dstu3.IJpaValidationSupportDstu3 jpaValidationSupportDstu3() {
|
||||
ca.uhn.fhir.jpa.dao.dstu3.JpaValidationSupportDstu3 retVal = new ca.uhn.fhir.jpa.dao.dstu3.JpaValidationSupportDstu3();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(name="myQuestionnaireResponseValidatorDstu3")
|
||||
@Lazy
|
||||
public IValidatorModule questionnaireResponseValidatorDstu3() {
|
||||
FhirQuestionnaireResponseValidator module = new FhirQuestionnaireResponseValidator();
|
||||
module.setValidationSupport(validationSupportChainDstu3());
|
||||
return module;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IFulltextSearchSvc searchDaoDstu3() {
|
||||
FulltextSearchSvcImpl searchDao = new FulltextSearchSvcImpl();
|
||||
return searchDao;
|
||||
}
|
||||
|
||||
@Bean(name = "mySystemDaoDstu3", autowire = Autowire.BY_NAME)
|
||||
public IFhirSystemDao<org.hl7.fhir.dstu3.model.Bundle, org.hl7.fhir.dstu3.model.Meta> systemDaoDstu3() {
|
||||
ca.uhn.fhir.jpa.dao.dstu3.FhirSystemDaoDstu3 retVal = new ca.uhn.fhir.jpa.dao.dstu3.FhirSystemDaoDstu3();
|
||||
|
@ -63,35 +92,6 @@ public class BaseDstu3Config extends BaseConfig {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(name = "myJpaValidationSupportDstu3", autowire = Autowire.BY_NAME)
|
||||
public ca.uhn.fhir.jpa.dao.dstu3.IJpaValidationSupportDstu3 jpaValidationSupportDstu3() {
|
||||
ca.uhn.fhir.jpa.dao.dstu3.JpaValidationSupportDstu3 retVal = new ca.uhn.fhir.jpa.dao.dstu3.JpaValidationSupportDstu3();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public ISearchDao searchDaoDstu3() {
|
||||
FhirSearchDao searchDao = new FhirSearchDao();
|
||||
return searchDao;
|
||||
}
|
||||
|
||||
@Bean(name="myInstanceValidatorDstu3")
|
||||
@Lazy
|
||||
public IValidatorModule instanceValidatorDstu3() {
|
||||
FhirInstanceValidator val = new FhirInstanceValidator();
|
||||
val.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning);
|
||||
val.setValidationSupport(validationSupportChainDstu3());
|
||||
return val;
|
||||
}
|
||||
|
||||
@Bean(name="myQuestionnaireResponseValidatorDstu3")
|
||||
@Lazy
|
||||
public IValidatorModule questionnaireResponseValidatorDstu3() {
|
||||
FhirQuestionnaireResponseValidator module = new FhirQuestionnaireResponseValidator();
|
||||
module.setValidationSupport(validationSupportChainDstu3());
|
||||
return module;
|
||||
}
|
||||
|
||||
@Bean(autowire=Autowire.BY_NAME, name="myJpaValidationSupportChainDstu3")
|
||||
public IValidationSupport validationSupportChainDstu3() {
|
||||
return new JpaValidationSupportChainDstu3();
|
||||
|
|
|
@ -518,7 +518,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <R extends IBaseResource> IFhirResourceDao<R> getDao(Class<R> theType) {
|
||||
public <R extends IBaseResource> IFhirResourceDao<R> getDao(Class<R> theType) {
|
||||
if (myResourceTypeToDao == null) {
|
||||
myResourceTypeToDao = new HashMap<Class<? extends IBaseResource>, IFhirResourceDao<?>>();
|
||||
for (IFhirResourceDao<?> next : myResourceDaos) {
|
||||
|
@ -959,6 +959,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(theResourceType);
|
||||
|
||||
SearchParameterMap paramMap = translateMatchUrl(theMatchUrl, resourceDef);
|
||||
paramMap.setPersistResults(false);
|
||||
|
||||
if (paramMap.isEmpty()) {
|
||||
throw new InvalidRequestException("Invalid match URL[" + theMatchUrl + "] - URL has no search parameters");
|
||||
|
|
|
@ -105,7 +105,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
private Class<T> myResourceType;
|
||||
@Autowired(required = false)
|
||||
protected ISearchDao mySearchDao;
|
||||
protected IFulltextSearchSvc mySearchDao;
|
||||
@Autowired()
|
||||
protected ISearchResultDao mySearchResultDao;
|
||||
@Autowired()
|
||||
|
|
|
@ -40,21 +40,37 @@ public class DaoConfig {
|
|||
private boolean myAllowInlineMatchUrlReferences = false;
|
||||
|
||||
private boolean myAllowMultipleDelete;
|
||||
private int myHardSearchLimit = 1000;
|
||||
private int myHardTagListLimit = 1000;
|
||||
private int myIncludeLimit = 2000;
|
||||
|
||||
// ***
|
||||
// update setter javadoc if default changes
|
||||
// ***
|
||||
private long myExpireSearchResultsAfterMillis = DateUtils.MILLIS_PER_HOUR;
|
||||
private int myHardSearchLimit = 1000;
|
||||
private int myHardTagListLimit = 1000;
|
||||
private int myIncludeLimit = 2000;
|
||||
|
||||
// ***
|
||||
// update setter javadoc if default changes
|
||||
// ***
|
||||
private boolean myIndexContainedResources = true;
|
||||
|
||||
|
||||
private List<IServerInterceptor> myInterceptors;
|
||||
|
||||
private ResourceEncodingEnum myResourceEncoding = ResourceEncodingEnum.JSONC;
|
||||
|
||||
private boolean mySchedulingDisabled;
|
||||
private boolean mySubscriptionEnabled;
|
||||
private long mySubscriptionPollDelay = 1000;
|
||||
private Long mySubscriptionPurgeInactiveAfterMillis;
|
||||
/**
|
||||
* Search results are stored in the database so that they can be paged through. After this
|
||||
* number of milliseconds, they will be deleted from the database. Defaults to 1 hour.
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public long getExpireSearchResultsAfterMillis() {
|
||||
return myExpireSearchResultsAfterMillis;
|
||||
}
|
||||
/**
|
||||
* See {@link #setIncludeLimit(int)}
|
||||
*/
|
||||
|
@ -78,7 +94,6 @@ public class DaoConfig {
|
|||
}
|
||||
return myInterceptors;
|
||||
}
|
||||
|
||||
public ResourceEncodingEnum getResourceEncoding() {
|
||||
return myResourceEncoding;
|
||||
}
|
||||
|
@ -139,6 +154,16 @@ public class DaoConfig {
|
|||
myAllowMultipleDelete = theAllowMultipleDelete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search results are stored in the database so that they can be paged through. After this
|
||||
* number of milliseconds, they will be deleted from the database. Defaults to 1 hour.
|
||||
*
|
||||
* @since 1.5
|
||||
*/
|
||||
public void setExpireSearchResultsAfterMillis(long theExpireSearchResultsAfterMillis) {
|
||||
myExpireSearchResultsAfterMillis = theExpireSearchResultsAfterMillis;
|
||||
}
|
||||
|
||||
public void setHardSearchLimit(int theHardSearchLimit) {
|
||||
myHardSearchLimit = theHardSearchLimit;
|
||||
}
|
||||
|
|
|
@ -61,8 +61,8 @@ import ca.uhn.fhir.rest.server.Constants;
|
|||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
||||
public class FhirSearchDao extends BaseHapiFhirDao<IBaseResource> implements ISearchDao {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSearchDao.class);
|
||||
public class FulltextSearchSvcImpl extends BaseHapiFhirDao<IBaseResource> implements IFulltextSearchSvc {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FulltextSearchSvcImpl.class);
|
||||
|
||||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||
private EntityManager myEntityManager;
|
|
@ -23,6 +23,8 @@ package ca.uhn.fhir.jpa.dao;
|
|||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.rest.method.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
|
@ -41,6 +43,8 @@ public interface IFhirSystemDao<T, MT> extends IDao {
|
|||
|
||||
TagList getAllTags(RequestDetails theRequestDetails);
|
||||
|
||||
public <R extends IBaseResource> IFhirResourceDao<R> getDao(Class<R> theType);
|
||||
|
||||
Map<String, Long> getResourceCounts();
|
||||
|
||||
IBundleProvider history(Date theDate, RequestDetails theRequestDetails);
|
||||
|
|
|
@ -22,9 +22,9 @@ package ca.uhn.fhir.jpa.dao;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.FhirSearchDao.Suggestion;
|
||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl.Suggestion;
|
||||
|
||||
public interface ISearchDao {
|
||||
public interface IFulltextSearchSvc {
|
||||
|
||||
List<Suggestion> suggestKeywords(String theContext, String theSearchParam, String theText);
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -46,6 +46,7 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
|
|||
private EverythingModeEnum myEverythingMode = null;
|
||||
private Set<Include> myIncludes;
|
||||
private DateRangeParam myLastUpdated;
|
||||
private boolean myPersistResults = true;
|
||||
private RequestDetails myRequestDetails;
|
||||
private Set<Include> myRevIncludes;
|
||||
private SortSpec mySort;
|
||||
|
@ -133,6 +134,10 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
|
|||
return mySort;
|
||||
}
|
||||
|
||||
public boolean isPersistResults() {
|
||||
return myPersistResults;
|
||||
}
|
||||
|
||||
public void setCount(Integer theCount) {
|
||||
myCount = theCount;
|
||||
}
|
||||
|
@ -149,6 +154,13 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
|
|||
myLastUpdated = theLastUpdated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should results be persisted into a table for paging
|
||||
*/
|
||||
public void setPersistResults(boolean thePersistResults) {
|
||||
myPersistResults = thePersistResults;
|
||||
}
|
||||
|
||||
public void setRequestDetails(RequestDetails theRequestDetails) {
|
||||
myRequestDetails = theRequestDetails;
|
||||
}
|
||||
|
@ -174,12 +186,13 @@ public class SearchParameterMap extends LinkedHashMap<String, List<List<? extend
|
|||
}
|
||||
|
||||
public enum EverythingModeEnum {
|
||||
/*
|
||||
* Don't reorder! We rely on the ordinals
|
||||
*/
|
||||
ENCOUNTER_INSTANCE(false, true, true),
|
||||
ENCOUNTER_TYPE(false, true, false),
|
||||
PATIENT_INSTANCE(true, false, true),
|
||||
//@formatter:off
|
||||
PATIENT_TYPE(true, false, false);
|
||||
//@formatter:on
|
||||
|
||||
private final boolean myEncounter;
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package ca.uhn.fhir.jpa.dao.data;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 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.Search;
|
||||
|
||||
public interface ISearchDao extends JpaRepository<Search, Long> {
|
||||
|
||||
@Query("SELECT s FROM Search s WHERE s.myCreated < :cutoff")
|
||||
public Collection<Search> findWhereCreatedBefore(@Param("cutoff") Date theCutoff);
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package ca.uhn.fhir.jpa.dao.data;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 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.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import ca.uhn.fhir.jpa.entity.SearchInclude;
|
||||
|
||||
public interface ISearchIncludeDao extends JpaRepository<SearchInclude, Long> {
|
||||
|
||||
@Modifying
|
||||
@Query(value="DELETE FROM SearchInclude r WHERE r.mySearchPid = :search")
|
||||
void deleteForSearch(@Param("search") Long theSearchPid);
|
||||
}
|
|
@ -1,5 +1,10 @@
|
|||
package ca.uhn.fhir.jpa.dao.data;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -21,9 +26,22 @@ package ca.uhn.fhir.jpa.dao.data;
|
|||
*/
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import ca.uhn.fhir.jpa.entity.Search;
|
||||
import ca.uhn.fhir.jpa.entity.SearchResult;
|
||||
|
||||
public interface ISearchResultDao extends JpaRepository<SearchResult, Long> {
|
||||
// nothing
|
||||
|
||||
@Query(value="SELECT r FROM SearchResult r WHERE r.mySearch = :search")
|
||||
Collection<SearchResult> findWithSearchUuid(@Param("search") Search theSearch);
|
||||
|
||||
@Query(value="SELECT r FROM SearchResult r WHERE r.mySearch = :search ORDER BY r.myOrder ASC")
|
||||
Page<SearchResult> findWithSearchUuid(@Param("search") Search theSearch, Pageable thePage);
|
||||
|
||||
@Modifying
|
||||
@Query(value="DELETE FROM SearchResult r WHERE r.mySearchPid = :search")
|
||||
void deleteForSearch(@Param("search") Long theSearchPid);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,9 @@ import javax.persistence.FetchType;
|
|||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
@ -66,6 +68,13 @@ public class ResourceHistoryTable extends BaseHasResource implements Serializabl
|
|||
@OneToMany(mappedBy = "myResourceHistory", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
|
||||
private Collection<ResourceHistoryTag> myTags;
|
||||
|
||||
/**
|
||||
* This field is only populated if this specific histor entry corresponds to
|
||||
* the most recent version of a resource
|
||||
*/
|
||||
@OneToOne(fetch=FetchType.LAZY, optional=true, mappedBy="myHistory")
|
||||
private ResourceTable myCorrespondsToVersion;
|
||||
|
||||
public void addTag(ResourceHistoryTag theTag) {
|
||||
for (ResourceHistoryTag next : getTags()) {
|
||||
if (next.getTag().equals(theTag)) {
|
||||
|
|
|
@ -35,7 +35,9 @@ import javax.persistence.GeneratedValue;
|
|||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
|
@ -150,6 +152,10 @@ public class ResourceTable extends BaseHasResource implements Serializable {
|
|||
@Column(name = "SP_HAS_LINKS")
|
||||
private boolean myHasLinks;
|
||||
|
||||
@OneToOne(fetch=FetchType.LAZY, optional=true)
|
||||
@JoinColumn(name="HISTORY_VERSION_PID", referencedColumnName="PID", nullable=true)
|
||||
private ResourceHistoryTable myHistory;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
@Column(name = "RES_ID")
|
||||
|
|
|
@ -21,20 +21,32 @@ package ca.uhn.fhir.jpa.entity;
|
|||
*/
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EnumType;
|
||||
import javax.persistence.Enumerated;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Temporal;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap.EverythingModeEnum;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
|
||||
//@formatter:off
|
||||
@Entity
|
||||
@Table(name = "HFJ_SEARCH", uniqueConstraints= {
|
||||
|
@ -48,25 +60,73 @@ public class Search implements Serializable {
|
|||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name="CREATED", nullable=false)
|
||||
@Column(name="CREATED", nullable=false, updatable=false)
|
||||
private Date myCreated;
|
||||
|
||||
@Enumerated(EnumType.ORDINAL)
|
||||
@Column(name="EVERYTHING_MODE", nullable=true)
|
||||
private EverythingModeEnum myEverythingMode;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO, generator="SEQ_SEARCH")
|
||||
@SequenceGenerator(name="SEQ_SEARCH", sequenceName="SEQ_SEARCH")
|
||||
@Column(name = "PID")
|
||||
private Long myId;
|
||||
|
||||
@OneToMany(mappedBy="mySearch")
|
||||
private Collection<SearchInclude> myIncludes;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name="LAST_UPDATED_HIGH", nullable=true, insertable=true, updatable=false)
|
||||
private Date myLastUpdatedHigh;
|
||||
|
||||
@Temporal(TemporalType.TIMESTAMP)
|
||||
@Column(name="LAST_UPDATED_LOW", nullable=true, insertable=true, updatable=false)
|
||||
private Date myLastUpdatedLow;
|
||||
|
||||
@Column(name="PREFERRED_PAGE_SIZE", nullable=true)
|
||||
private Integer myPreferredPageSize;
|
||||
|
||||
@OneToMany(mappedBy="mySearch")
|
||||
private Collection<SearchResult> myResults;
|
||||
|
||||
@Column(name="TOTAL_COUNT")
|
||||
private int myTotalCount;
|
||||
|
||||
@Id
|
||||
@Column(name="SEARCH_UUID", length=40, nullable=false)
|
||||
private String myUuid;
|
||||
|
||||
@Column(name="SEARCH_UUID", length=40, nullable=false, updatable=false)
|
||||
private String myUuid;
|
||||
|
||||
public Date getCreated() {
|
||||
return myCreated;
|
||||
}
|
||||
|
||||
public EverythingModeEnum getEverythingMode() {
|
||||
return myEverythingMode;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return myId;
|
||||
}
|
||||
|
||||
public Collection<SearchInclude> getIncludes() {
|
||||
if (myIncludes == null) {
|
||||
myIncludes = new ArrayList<SearchInclude>();
|
||||
}
|
||||
return myIncludes;
|
||||
}
|
||||
|
||||
public DateRangeParam getLastUpdated() {
|
||||
if (myLastUpdatedLow == null && myLastUpdatedHigh == null) {
|
||||
return null;
|
||||
} else {
|
||||
return new DateRangeParam(myLastUpdatedLow, myLastUpdatedHigh);
|
||||
}
|
||||
}
|
||||
|
||||
public Integer getPreferredPageSize() {
|
||||
return myPreferredPageSize;
|
||||
}
|
||||
|
||||
public int getTotalCount() {
|
||||
return myTotalCount;
|
||||
}
|
||||
|
@ -74,17 +134,53 @@ public class Search implements Serializable {
|
|||
public String getUuid() {
|
||||
return myUuid;
|
||||
}
|
||||
|
||||
|
||||
public void setCreated(Date theCreated) {
|
||||
myCreated = theCreated;
|
||||
}
|
||||
|
||||
public void setEverythingMode(EverythingModeEnum theEverythingMode) {
|
||||
myEverythingMode = theEverythingMode;
|
||||
}
|
||||
|
||||
public void setLastUpdated(DateRangeParam theLastUpdated) {
|
||||
if (theLastUpdated == null) {
|
||||
myLastUpdatedLow = null;
|
||||
myLastUpdatedHigh = null;
|
||||
} else {
|
||||
myLastUpdatedLow = theLastUpdated.getLowerBoundAsInstant();
|
||||
myLastUpdatedHigh = theLastUpdated.getUpperBoundAsInstant();
|
||||
}
|
||||
}
|
||||
|
||||
public void setPreferredPageSize(Integer thePreferredPageSize) {
|
||||
myPreferredPageSize = thePreferredPageSize;
|
||||
}
|
||||
|
||||
public void setTotalCount(int theTotalCount) {
|
||||
myTotalCount = theTotalCount;
|
||||
}
|
||||
|
||||
|
||||
public void setUuid(String theUuid) {
|
||||
myUuid = theUuid;
|
||||
}
|
||||
|
||||
private Set<Include> toIncList(boolean theWantReverse) {
|
||||
HashSet<Include> retVal = new HashSet<Include>();
|
||||
for (SearchInclude next : getIncludes()) {
|
||||
if (theWantReverse == next.isReverse()) {
|
||||
retVal.add(new Include(next.getInclude(), next.isRecurse()));
|
||||
}
|
||||
}
|
||||
return Collections.unmodifiableSet(retVal);
|
||||
}
|
||||
|
||||
public Set<Include> toIncludesList() {
|
||||
return toIncList(false);
|
||||
}
|
||||
|
||||
public Set<Include> toRevIncludesList() {
|
||||
return toIncList(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
package ca.uhn.fhir.jpa.entity;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2016 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 java.io.Serializable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.ForeignKey;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
|
||||
//@formatter:off
|
||||
@Entity
|
||||
@Table(name = "HFJ_SEARCH_INCLUDE")
|
||||
//@formatter:on
|
||||
public class SearchInclude implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SEARCH_INC")
|
||||
@SequenceGenerator(name = "SEQ_SEARCH_INC", sequenceName = "SEQ_SEARCH_INC")
|
||||
@Id
|
||||
@Column(name = "PID")
|
||||
private Long myId;
|
||||
|
||||
@Column(name = "REVINCLUDE", insertable = true, updatable = false, nullable = false)
|
||||
private boolean myReverse;
|
||||
|
||||
public boolean isReverse() {
|
||||
return myReverse;
|
||||
}
|
||||
|
||||
@Column(name = "SEARCH_INCLUDE", length = 200, insertable = true, updatable = false, nullable = false)
|
||||
private String myInclude;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "SEARCH_PID", referencedColumnName = "PID", foreignKey = @ForeignKey(name = "FK_SEARCHINC_SEARCH"), insertable = true, updatable = false, nullable = false)
|
||||
private Search mySearch;
|
||||
|
||||
@Column(name="SEARCH_PID", insertable=false, updatable=false, nullable=false)
|
||||
private Long mySearchPid;
|
||||
|
||||
@Column(name = "INC_RECURSE", insertable = true, updatable = false, nullable = false)
|
||||
private boolean myRecurse;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public SearchInclude() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public SearchInclude(Search theSearch, String theInclude, boolean theReverse, boolean theRecurse) {
|
||||
mySearch = theSearch;
|
||||
myInclude = theInclude;
|
||||
myReverse = theReverse;
|
||||
myRecurse = theRecurse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object theObj) {
|
||||
if (!(theObj instanceof SearchInclude)) {
|
||||
return false;
|
||||
}
|
||||
if (myId == null) {
|
||||
return false;
|
||||
}
|
||||
return myId.equals(((SearchInclude) theObj).myId);
|
||||
}
|
||||
|
||||
public String getInclude() {
|
||||
return myInclude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myId == null ? 0 : myId.hashCode();
|
||||
}
|
||||
|
||||
public boolean isRecurse() {
|
||||
return myRecurse;
|
||||
}
|
||||
|
||||
}
|
|
@ -32,22 +32,27 @@ import javax.persistence.JoinColumn;
|
|||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
//@formatter:off
|
||||
@Entity
|
||||
@Table(name = "HFJ_SEARCH_RESULT", uniqueConstraints= {
|
||||
@UniqueConstraint(name="IDX_SEARCHRES_ORDER", columnNames= {"SEARCH_PID", "SEARCH_ORDER"})
|
||||
})
|
||||
//@formatter:on
|
||||
public class SearchResult implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
@GeneratedValue(strategy = GenerationType.AUTO, generator="SEQ_SEARCH_RES")
|
||||
@SequenceGenerator(name="SEQ_SEARCH_RES", sequenceName="SEQ_SEARCH_RES")
|
||||
@Id
|
||||
@Column(name = "PID")
|
||||
private Long myId;
|
||||
|
||||
@Column(name="SEARCH_ORDER", nullable=false)
|
||||
private int myOrder;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name="RESOURCE_PID", referencedColumnName="RES_ID", foreignKey=@ForeignKey(name="FK_SEARCHRES_RES"), insertable=false, updatable=false, nullable=false)
|
||||
private ResourceTable myResource;
|
||||
|
@ -58,14 +63,17 @@ public class SearchResult implements Serializable {
|
|||
@ManyToOne
|
||||
@JoinColumn(name="SEARCH_PID", referencedColumnName="PID", foreignKey=@ForeignKey(name="FK_SEARCHRES_SEARCH"))
|
||||
private Search mySearch;
|
||||
|
||||
|
||||
@Column(name="SEARCH_PID", insertable=false, updatable=false, nullable=false)
|
||||
private Long mySearchPid;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public SearchResult() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
@ -73,6 +81,31 @@ public class SearchResult implements Serializable {
|
|||
mySearch = theSearch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object theObj) {
|
||||
if (!(theObj instanceof SearchResult)) {
|
||||
return false;
|
||||
}
|
||||
return myResourcePid.equals(((SearchResult)theObj).myResourcePid);
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return myOrder;
|
||||
}
|
||||
|
||||
public Long getResourcePid() {
|
||||
return myResourcePid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return myResourcePid.hashCode();
|
||||
}
|
||||
|
||||
public void setOrder(int theOrder) {
|
||||
myOrder = theOrder;
|
||||
}
|
||||
|
||||
public void setResourcePid(Long theResourcePid) {
|
||||
myResourcePid = theResourcePid;
|
||||
}
|
||||
|
|
|
@ -31,9 +31,9 @@ import java.util.TreeMap;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.FhirSearchDao.Suggestion;
|
||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl.Suggestion;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
|
@ -57,7 +57,7 @@ public class JpaSystemProviderDstu2 extends BaseJpaSystemProvider<Bundle, MetaDt
|
|||
private IFhirSystemDao<Bundle, MetaDt> mySystemDao;
|
||||
|
||||
@Autowired
|
||||
private ISearchDao mySearchDao;
|
||||
private IFulltextSearchSvc mySearchDao;
|
||||
|
||||
//@formatter:off
|
||||
// This is generated by hand:
|
||||
|
|
|
@ -38,10 +38,10 @@ import org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.FhirSearchDao.Suggestion;
|
||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl.Suggestion;
|
||||
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProvider;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.primitive.IntegerDt;
|
||||
import ca.uhn.fhir.rest.annotation.Operation;
|
||||
|
@ -59,7 +59,7 @@ public class JpaSystemProviderDstu3 extends BaseJpaSystemProvider<Bundle, Meta>
|
|||
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
||||
|
||||
@Autowired
|
||||
private ISearchDao mySearchDao;
|
||||
private IFulltextSearchSvc mySearchDao;
|
||||
|
||||
//@formatter:off
|
||||
// This is generated by hand:
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package ca.uhn.fhir.jpa.search;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder.BundleProviderPersisted;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
|
||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||
|
||||
public class DatabaseBackedPagingProvider extends FifoMemoryPagingProvider {
|
||||
|
||||
@Autowired
|
||||
private PlatformTransactionManager thePlatformTransactionManager;
|
||||
@Autowired
|
||||
private ISearchResultDao theSearchResultDao;
|
||||
@Autowired
|
||||
private EntityManager theEntityManager;
|
||||
@Autowired
|
||||
private FhirContext theContext;
|
||||
@Autowired
|
||||
private IFhirSystemDao<?, ?> theDao;
|
||||
|
||||
public DatabaseBackedPagingProvider(int theSize) {
|
||||
super(theSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized IBundleProvider retrieveResultList(String theId) {
|
||||
IBundleProvider retVal = super.retrieveResultList(theId);
|
||||
if (retVal == null) {
|
||||
BundleProviderPersisted provider = new SearchBuilder.BundleProviderPersisted(theId, thePlatformTransactionManager, theSearchResultDao, theEntityManager,
|
||||
theContext, theDao);
|
||||
if (!provider.ensureSearchEntityLoaded()) {
|
||||
return null;
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String storeResultList(IBundleProvider theList) {
|
||||
if (theList instanceof SearchBuilder.BundleProviderPersisted) {
|
||||
return ((BundleProviderPersisted)theList).getSearchUuid();
|
||||
}
|
||||
return super.storeResultList(theList);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package ca.uhn.fhir.jpa.search;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchIncludeDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||
import ca.uhn.fhir.jpa.entity.Search;
|
||||
|
||||
/**
|
||||
* Deletes old searches
|
||||
*/
|
||||
public class StaleSearchDeletingSvc {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(StaleSearchDeletingSvc.class);
|
||||
|
||||
@Autowired
|
||||
private ISearchDao mySearchDao;
|
||||
|
||||
@Autowired
|
||||
private DaoConfig myDaoConfig;
|
||||
|
||||
@Autowired
|
||||
private ISearchResultDao mySearchResultDao;
|
||||
|
||||
@Autowired
|
||||
private ISearchIncludeDao mySearchIncludeDao;
|
||||
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTransactionManager;
|
||||
|
||||
@Scheduled(fixedDelay = 10 * DateUtils.MILLIS_PER_SECOND)
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
public synchronized void pollForStaleSearches() {
|
||||
Date cutoff = new Date(System.currentTimeMillis() - myDaoConfig.getExpireSearchResultsAfterMillis());
|
||||
ourLog.debug("Searching for searches which are before {}", cutoff);
|
||||
|
||||
Collection<Search> toDelete = mySearchDao.findWhereCreatedBefore(cutoff);
|
||||
if (toDelete.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TransactionTemplate tt = new TransactionTemplate(myTransactionManager);
|
||||
for (final Search next : toDelete) {
|
||||
tt.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
Search searchToDelete = mySearchDao.findOne(next.getId());
|
||||
ourLog.info("Expiring stale search {} / {}", searchToDelete.getId(), searchToDelete.getUuid());
|
||||
mySearchIncludeDao.deleteForSearch(searchToDelete.getId());
|
||||
mySearchResultDao.deleteForSearch(searchToDelete.getId());
|
||||
mySearchDao.delete(searchToDelete);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -8,14 +8,42 @@ import java.sql.SQLException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hibernate.internal.SessionFactoryRegistry;
|
||||
import org.hibernate.search.jpa.Search;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import ca.uhn.fhir.jpa.entity.ForcedId;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceHistoryTag;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTag;
|
||||
import ca.uhn.fhir.jpa.entity.SearchInclude;
|
||||
import ca.uhn.fhir.jpa.entity.SearchResult;
|
||||
import ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource;
|
||||
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
|
||||
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
|
||||
|
@ -114,4 +142,59 @@ public class BaseJpaTest {
|
|||
return bundleStr;
|
||||
}
|
||||
|
||||
public static void purgeDatabase(final EntityManager entityManager, PlatformTransactionManager theTxManager) {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(theTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
|
||||
txTemplate.execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInTransaction(TransactionStatus theStatus) {
|
||||
entityManager.createQuery("UPDATE " + ResourceHistoryTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate();
|
||||
entityManager.createQuery("UPDATE " + ResourceTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
txTemplate.execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInTransaction(TransactionStatus theStatus) {
|
||||
entityManager.createQuery("DELETE from " + SubscriptionFlaggedResource.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ForcedId.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamDate.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamNumber.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamQuantity.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamString.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamToken.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamUri.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamCoords.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceLink.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + SearchResult.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + SearchInclude.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + TermConceptParentChildLink.class.getSimpleName() + " d").executeUpdate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
txTemplate.execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInTransaction(TransactionStatus theStatus) {
|
||||
entityManager.createQuery("DELETE from " + TermConcept.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + TermCodeSystemVersion.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + TermCodeSystem.class.getSimpleName() + " d").executeUpdate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
txTemplate.execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInTransaction(TransactionStatus theStatus) {
|
||||
entityManager.createQuery("DELETE from " + SubscriptionTable.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceHistoryTag.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceTag.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + TagDefinition.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceHistoryTable.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceTable.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + Search.class.getSimpleName() + " d").executeUpdate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -20,9 +20,7 @@ import org.springframework.context.ApplicationContext;
|
|||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
|
@ -34,23 +32,9 @@ import ca.uhn.fhir.jpa.dao.IFhirResourceDaoPatient;
|
|||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSubscription;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.entity.ForcedId;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceHistoryTag;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTag;
|
||||
import ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource;
|
||||
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
|
||||
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
||||
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
|
||||
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||
|
@ -89,7 +73,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
|||
@Autowired
|
||||
protected ApplicationContext myAppCtx;
|
||||
@Autowired
|
||||
protected ISearchDao mySearchDao;
|
||||
protected IFulltextSearchSvc mySearchDao;
|
||||
@Autowired
|
||||
@Qualifier("myConceptMapDaoDstu2")
|
||||
protected IFhirResourceDao<ConceptMap> myConceptMapDao;
|
||||
|
@ -221,45 +205,4 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
public static void purgeDatabase(final EntityManager entityManager, PlatformTransactionManager theTxManager) {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(theTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
|
||||
txTemplate.execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInTransaction(TransactionStatus theStatus) {
|
||||
entityManager.createQuery("UPDATE " + ResourceHistoryTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate();
|
||||
entityManager.createQuery("UPDATE " + ResourceTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
txTemplate.execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInTransaction(TransactionStatus theStatus) {
|
||||
entityManager.createQuery("DELETE from " + SubscriptionFlaggedResource.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ForcedId.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamDate.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamNumber.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamQuantity.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamString.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamToken.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamUri.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamCoords.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceLink.class.getSimpleName() + " d").executeUpdate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
txTemplate.execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInTransaction(TransactionStatus theStatus) {
|
||||
entityManager.createQuery("DELETE from " + SubscriptionTable.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceHistoryTag.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceTag.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + TagDefinition.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceHistoryTable.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceTable.class.getSimpleName() + " d").executeUpdate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.FhirSearchDao.Suggestion;
|
||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl.Suggestion;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Device;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Media;
|
||||
|
|
|
@ -9,7 +9,7 @@ import java.util.List;
|
|||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Organization;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
|
@ -22,7 +22,7 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
|||
public class FhirSearchDaoDstu2Test extends BaseJpaDstu2Test {
|
||||
|
||||
@Autowired
|
||||
private ISearchDao mySearchDao;
|
||||
private IFulltextSearchSvc mySearchDao;
|
||||
|
||||
@Test
|
||||
public void testContentSearch() {
|
||||
|
|
|
@ -48,9 +48,7 @@ import org.springframework.test.context.ContextConfiguration;
|
|||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionCallback;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
|
@ -62,30 +60,13 @@ import ca.uhn.fhir.jpa.dao.IFhirResourceDaoPatient;
|
|||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSubscription;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||
import ca.uhn.fhir.jpa.dao.dstu2.FhirResourceDaoDstu2SearchNoFtTest;
|
||||
import ca.uhn.fhir.jpa.entity.ForcedId;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceHistoryTag;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTag;
|
||||
import ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource;
|
||||
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
|
||||
import ca.uhn.fhir.jpa.entity.TagDefinition;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvc;
|
||||
import ca.uhn.fhir.jpa.term.ITerminologySvc;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.method.MethodUtil;
|
||||
|
@ -96,29 +77,14 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
|||
@ContextConfiguration(classes= {TestDstu3Config.class})
|
||||
//@formatter:on
|
||||
public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
||||
@Autowired
|
||||
protected IResourceTableDao myResourceTableDao;
|
||||
@Autowired
|
||||
protected ITerminologySvc myTermSvc;
|
||||
@Autowired
|
||||
@Qualifier("myJpaValidationSupportChainDstu3")
|
||||
protected IValidationSupport myValidationSupport;
|
||||
@Autowired
|
||||
protected ApplicationContext myAppCtx;
|
||||
@Autowired
|
||||
protected ISearchDao mySearchDao;
|
||||
@Autowired
|
||||
@Qualifier("myConceptMapDaoDstu3")
|
||||
protected IFhirResourceDao<ConceptMap> myConceptMapDao;
|
||||
@Autowired
|
||||
@Qualifier("myCodeSystemDaoDstu3")
|
||||
protected IFhirResourceDao<CodeSystem> myCodeSystemDao;
|
||||
@Autowired
|
||||
@Qualifier("myMedicationDaoDstu3")
|
||||
protected IFhirResourceDao<Medication> myMedicationDao;
|
||||
@Autowired
|
||||
@Qualifier("myMedicationOrderDaoDstu3")
|
||||
protected IFhirResourceDao<MedicationOrder> myMedicationOrderDao;
|
||||
@Qualifier("myConceptMapDaoDstu3")
|
||||
protected IFhirResourceDao<ConceptMap> myConceptMapDao;
|
||||
@Autowired
|
||||
protected DaoConfig myDaoConfig;
|
||||
@Autowired
|
||||
|
@ -133,11 +99,9 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
@Autowired
|
||||
@Qualifier("myEncounterDaoDstu3")
|
||||
protected IFhirResourceDao<Encounter> myEncounterDao;
|
||||
|
||||
// @PersistenceContext()
|
||||
// @PersistenceContext()
|
||||
@Autowired
|
||||
protected EntityManager myEntityManager;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myFhirContextDstu3")
|
||||
protected FhirContext myFhirCtx;
|
||||
|
@ -149,6 +113,20 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
@Qualifier("myLocationDaoDstu3")
|
||||
protected IFhirResourceDao<Location> myLocationDao;
|
||||
@Autowired
|
||||
@Qualifier("myMediaDaoDstu3")
|
||||
protected IFhirResourceDao<Media> myMediaDao;
|
||||
@Autowired
|
||||
@Qualifier("myMedicationDaoDstu3")
|
||||
protected IFhirResourceDao<Medication> myMedicationDao;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myMedicationOrderDaoDstu3")
|
||||
protected IFhirResourceDao<MedicationOrder> myMedicationOrderDao;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myNamingSystemDaoDstu3")
|
||||
protected IFhirResourceDao<NamingSystem> myNamingSystemDao;
|
||||
@Autowired
|
||||
@Qualifier("myObservationDaoDstu3")
|
||||
protected IFhirResourceDao<Observation> myObservationDao;
|
||||
@Autowired
|
||||
|
@ -158,12 +136,6 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
@Qualifier("myPatientDaoDstu3")
|
||||
protected IFhirResourceDaoPatient<Patient> myPatientDao;
|
||||
@Autowired
|
||||
@Qualifier("myNamingSystemDaoDstu3")
|
||||
protected IFhirResourceDao<NamingSystem> myNamingSystemDao;
|
||||
@Autowired
|
||||
@Qualifier("myMediaDaoDstu3")
|
||||
protected IFhirResourceDao<Media> myMediaDao;
|
||||
@Autowired
|
||||
@Qualifier("myPractitionerDaoDstu3")
|
||||
protected IFhirResourceDao<Practitioner> myPractitionerDao;
|
||||
@Autowired
|
||||
|
@ -176,6 +148,12 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
@Qualifier("myResourceProvidersDstu3")
|
||||
protected Object myResourceProviders;
|
||||
@Autowired
|
||||
protected IResourceTableDao myResourceTableDao;
|
||||
@Autowired
|
||||
protected IFulltextSearchSvc mySearchDao;
|
||||
@Autowired
|
||||
protected StaleSearchDeletingSvc myStaleSearchDeletingSvc;
|
||||
@Autowired
|
||||
@Qualifier("myStructureDefinitionDaoDstu3")
|
||||
protected IFhirResourceDao<StructureDefinition> myStructureDefinitionDao;
|
||||
@Autowired
|
||||
|
@ -191,8 +169,13 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
@Qualifier("mySystemProviderDstu3")
|
||||
protected JpaSystemProviderDstu3 mySystemProvider;
|
||||
@Autowired
|
||||
protected ITerminologySvc myTermSvc;
|
||||
@Autowired
|
||||
protected PlatformTransactionManager myTxManager;
|
||||
@Autowired
|
||||
@Qualifier("myJpaValidationSupportChainDstu3")
|
||||
protected IValidationSupport myValidationSupport;
|
||||
@Autowired
|
||||
@Qualifier("myValueSetDaoDstu3")
|
||||
protected IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> myValueSetDao;
|
||||
|
||||
|
@ -213,14 +196,6 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
myDaoConfig.setSchedulingDisabled(true);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeResetConfig() {
|
||||
myDaoConfig.setHardSearchLimit(1000);
|
||||
myDaoConfig.setHardTagListLimit(1000);
|
||||
myDaoConfig.setIncludeLimit(2000);
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
@Transactional()
|
||||
public void beforePurgeDatabase() {
|
||||
|
@ -228,6 +203,14 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
purgeDatabase(entityManager, myTxManager);
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void beforeResetConfig() {
|
||||
myDaoConfig.setHardSearchLimit(1000);
|
||||
myDaoConfig.setHardTagListLimit(1000);
|
||||
myDaoConfig.setIncludeLimit(2000);
|
||||
}
|
||||
|
||||
protected <T extends IBaseResource> T loadResourceFromClasspath(Class<T> type, String resourceName) throws IOException {
|
||||
InputStream stream = FhirResourceDaoDstu2SearchNoFtTest.class.getResourceAsStream(resourceName);
|
||||
if (stream == null) {
|
||||
|
@ -245,55 +228,4 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
public static void purgeDatabase(final EntityManager entityManager, PlatformTransactionManager theTxManager) {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(theTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
txTemplate.execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInTransaction(TransactionStatus theStatus) {
|
||||
entityManager.createQuery("UPDATE " + ResourceHistoryTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate();
|
||||
entityManager.createQuery("UPDATE " + ResourceTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
txTemplate.execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInTransaction(TransactionStatus theStatus) {
|
||||
entityManager.createQuery("DELETE from " + TermConceptParentChildLink.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + TermConcept.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + TermCodeSystemVersion.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + TermCodeSystem.class.getSimpleName() + " d").executeUpdate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
txTemplate.execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInTransaction(TransactionStatus theStatus) {
|
||||
entityManager.createQuery("DELETE from " + SubscriptionFlaggedResource.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ForcedId.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamDate.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamNumber.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamQuantity.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamString.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamToken.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamUri.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamCoords.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceLink.class.getSimpleName() + " d").executeUpdate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
txTemplate.execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInTransaction(TransactionStatus theStatus) {
|
||||
entityManager.createQuery("DELETE from " + SubscriptionTable.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceHistoryTag.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceTag.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + TagDefinition.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceHistoryTable.class.getSimpleName() + " d").executeUpdate();
|
||||
entityManager.createQuery("DELETE from " + ResourceTable.class.getSimpleName() + " d").executeUpdate();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
|||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.FhirSearchDao.Suggestion;
|
||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl.Suggestion;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||
import ca.uhn.fhir.rest.param.StringOrListParam;
|
||||
|
|
|
@ -11,7 +11,7 @@ import org.hl7.fhir.dstu3.model.Patient;
|
|||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||
import ca.uhn.fhir.rest.param.StringOrListParam;
|
||||
|
@ -22,7 +22,7 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
|||
public class FhirSearchDaoDstu3Test extends BaseJpaDstu3Test {
|
||||
|
||||
@Autowired
|
||||
private ISearchDao mySearchDao;
|
||||
private IFulltextSearchSvc mySearchDao;
|
||||
|
||||
@Test
|
||||
public void testContentSearch() {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package ca.uhn.fhir.jpa.provider;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap.EverythingModeEnum;
|
||||
|
||||
public class SearchParameterMapTest {
|
||||
|
||||
/**
|
||||
* {@link Search} uses these ordinals so they shouldn't get out of order
|
||||
*/
|
||||
@Test
|
||||
public void testEverythingOrdinals() {
|
||||
assertEquals(0, EverythingModeEnum.ENCOUNTER_INSTANCE.ordinal());
|
||||
assertEquals(1, EverythingModeEnum.ENCOUNTER_TYPE.ordinal());
|
||||
assertEquals(2, EverythingModeEnum.PATIENT_INSTANCE.ordinal());
|
||||
assertEquals(3, EverythingModeEnum.PATIENT_TYPE.ordinal());
|
||||
}
|
||||
|
||||
}
|
|
@ -29,6 +29,7 @@ import org.springframework.web.servlet.DispatcherServlet;
|
|||
|
||||
import ca.uhn.fhir.jpa.config.dstu3.WebsocketDstu3Config;
|
||||
import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
|
||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
|
@ -78,7 +79,7 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
public void after() throws Exception {
|
||||
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
|
||||
}
|
||||
|
||||
|
@ -105,7 +106,7 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
confProvider.setImplementationDescription("THIS IS THE DESC");
|
||||
ourRestServer.setServerConformanceProvider(confProvider);
|
||||
|
||||
ourRestServer.setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||
ourRestServer.setPagingProvider(myAppCtx.getBean(DatabaseBackedPagingProvider.class));
|
||||
|
||||
Server server = new Server(ourPort);
|
||||
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package ca.uhn.fhir.jpa.provider.dstu3;
|
||||
|
||||
import static org.hamcrest.Matchers.blankOrNullString;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleLinkComponent;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.rest.gclient.IQuery;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
|
||||
public class StaleSearchDeletingSvcDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(StaleSearchDeletingSvcDstu3Test.class);
|
||||
|
||||
@Override
|
||||
public void after() throws Exception {
|
||||
super.after();
|
||||
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(DateUtils.MILLIS_PER_HOUR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEverythingInstanceWithContentFilter() throws Exception {
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
Patient pt1 = new Patient();
|
||||
pt1.addName().addFamily("Everything").addGiven("Arthur");
|
||||
myPatientDao.create(pt1, new ServletRequestDetails()).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
//@formatter:off
|
||||
IQuery<Bundle> search = ourClient
|
||||
.search()
|
||||
.forResource(Patient.class)
|
||||
.where(Patient.NAME.matches().value("Everything"))
|
||||
.returnBundle(Bundle.class);
|
||||
//@formatter:on
|
||||
|
||||
Bundle resp1 = search.execute();
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
search.execute();
|
||||
}
|
||||
|
||||
BundleLinkComponent nextLink = resp1.getLink("next");
|
||||
assertNotNull(nextLink);
|
||||
String nextLinkUrl = nextLink.getUrl();
|
||||
assertThat(nextLinkUrl, not(blankOrNullString()));
|
||||
|
||||
Bundle resp2 = ourClient.search().byUrl(nextLinkUrl).returnBundle(Bundle.class).execute();
|
||||
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp2));
|
||||
|
||||
myStaleSearchDeletingSvc.pollForStaleSearches();
|
||||
|
||||
ourClient.search().byUrl(nextLinkUrl).returnBundle(Bundle.class).execute();
|
||||
|
||||
Thread.sleep(20);
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(10);
|
||||
myStaleSearchDeletingSvc.pollForStaleSearches();
|
||||
|
||||
try {
|
||||
ourClient.search().byUrl(nextLinkUrl).returnBundle(Bundle.class).execute();
|
||||
fail();
|
||||
} catch (ResourceGoneException e) {
|
||||
assertThat(e.getMessage(), containsString("does not exist and may have expired"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -19,6 +19,7 @@ import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu1;
|
|||
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
|
@ -127,15 +128,17 @@ public class JpaServerDemo extends RestfulServer {
|
|||
ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
/*
|
||||
* Default to XML and pretty printing
|
||||
* Default to JSON and pretty printing
|
||||
*/
|
||||
setDefaultPrettyPrint(true);
|
||||
setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
|
||||
/*
|
||||
* This is a simple paging strategy that keeps the last 10 searches in memory
|
||||
* -- New in HAPI FHIR 1.5 --
|
||||
* This configures the server to page search results to and from
|
||||
* the database
|
||||
*/
|
||||
setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||
setPagingProvider(myAppCtx.getBean(DatabaseBackedPagingProvider.class));
|
||||
|
||||
/*
|
||||
* Load interceptors for the server from Spring (these are defined in FhirServerConfig.java)
|
||||
|
|
|
@ -183,6 +183,14 @@
|
|||
longer includes _revinclude matches in the Bundle.total count, or the
|
||||
page size limit.
|
||||
</action>
|
||||
<action type="add">
|
||||
JPA server now persists search results to the database in a new table where they
|
||||
can be temporaily preserved. This makes the JPA server much more scalable, since it
|
||||
no longer needs to store large lists of pages in memory between search invocations.
|
||||
<![CDATA[<br/><br/>]]>
|
||||
Old searches are deleted after an hour by default, but this can be changed
|
||||
via a setting in the DaoConfig.
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.4" date="2016-02-04">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue