Tweaks to contained searches (#2461)

* Tweaks to contained searches

* Add changelog

* Build fix
This commit is contained in:
James Agnew 2021-03-09 11:51:30 -05:00 committed by GitHub
parent bf8e890a0c
commit be50a46d76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 448 additions and 481 deletions

View File

@ -267,6 +267,7 @@ public class Constants {
*/
public static final String RESOURCE_PARTITION_ID = Constants.class.getName() + "_RESOURCE_PARTITION_ID";
public static final String CT_APPLICATION_GZIP = "application/gzip";
public static final String[] EMPTY_STRING_ARRAY = new String[0];
static {
CHARSET_UTF8 = StandardCharsets.UTF_8;

View File

@ -0,0 +1,76 @@
package ca.uhn.fhir.rest.api;
/*
* #%L
* HAPI FHIR Search Parameters
* %%
* Copyright (C) 2014 - 2021 Smile CDR, Inc.
* %%
* 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 ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.UrlUtil;
import java.util.HashMap;
import java.util.Map;
public enum SearchContainedModeEnum {
/**
* default, search on the non-contained (normal) resources
*/
FALSE("false"),
/**
* search on the contained resources only
*/
TRUE("true"),
/**
* Search on the normal resources and contained resources.
* This option is not supported yet.
*/
BOTH("both");
private static volatile Map<String, SearchContainedModeEnum> ourCodeToEnum;
private final String myCode;
SearchContainedModeEnum(String theCode) {
myCode = theCode;
}
private String getCode() {
return myCode;
}
public static SearchContainedModeEnum fromCode(String theCode) {
Map<String, SearchContainedModeEnum> codeToEnum = ourCodeToEnum;
if (codeToEnum == null) {
codeToEnum = new HashMap<>();
for (SearchContainedModeEnum next : values()) {
codeToEnum.put(next.getCode(), next);
}
ourCodeToEnum = codeToEnum;
}
SearchContainedModeEnum retVal = codeToEnum.get(theCode);
if (retVal == null) {
throw new InvalidRequestException("Invalid contained mode: " + UrlUtil.sanitizeUrlPart(theCode));
}
return retVal;
}
}

View File

@ -25,7 +25,6 @@ import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.search.HapiLuceneAnalysisConfigurer;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.search.backend.lucene.cfg.LuceneBackendSettings;
import org.hibernate.search.backend.lucene.cfg.LuceneIndexSettings;
@ -49,9 +48,6 @@ public class CommonConfig {
@Bean
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();
retVal.setSubscriptionEnabled(true);
retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowMultipleDelete(true);
return retVal;
}

View File

@ -59,9 +59,6 @@ public class FhirServerConfig extends BaseJavaConfigDstu2 {
@Bean
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();
retVal.setSubscriptionEnabled(true);
retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowMultipleDelete(true);
return retVal;
}
@ -79,7 +76,6 @@ public class FhirServerConfig extends BaseJavaConfigDstu2 {
/**
* Do some fancy logging to create a nice access log that has details about each incoming request.
* @return
*/
public LoggingInterceptor loggingInterceptor() {
LoggingInterceptor retVal = new LoggingInterceptor();

View File

@ -0,0 +1,6 @@
---
type: add
issue: 2441
title: "Support has been added to the JPA server for indexing and searching using the `_contained` parameter, which
allows searching using chained parameters that chain into contained resources. This feature is disabled by default
but can be enabled via a setting on the ModelConfig object."

View File

@ -118,11 +118,6 @@ public class DaoConfig {
* update setter javadoc if default changes
*/
private Integer myFetchSizeDefaultMaximum = null;
private int myHardTagListLimit = 1000;
/**
* update setter javadoc if default changes
*/
private boolean myIndexContainedResources = true;
private int myMaximumExpansionSize = DEFAULT_MAX_EXPANSION_SIZE;
private Integer myMaximumSearchResultCountInTransaction = DEFAULT_MAXIMUM_SEARCH_RESULT_COUNT_IN_TRANSACTION;
@ -209,9 +204,6 @@ public class DaoConfig {
* Constructor
*/
public DaoConfig() {
setSubscriptionEnabled(true);
setSubscriptionPollDelay(0);
setSubscriptionPurgeInactiveAfterMillis(Long.MAX_VALUE);
setMarkResourcesForReindexingUponSearchParameterChange(true);
setReindexThreadCount(Runtime.getRuntime().availableProcessors());
setExpungeThreadCount(Runtime.getRuntime().availableProcessors());
@ -580,20 +572,6 @@ public class DaoConfig {
myFetchSizeDefaultMaximum = theFetchSizeDefaultMaximum;
}
/**
* Gets the maximum number of results to return in a GetTags query (DSTU1 only)
*/
public int getHardTagListLimit() {
return myHardTagListLimit;
}
/**
* Gets the maximum number of results to return in a GetTags query (DSTU1 only)
*/
public void setHardTagListLimit(int theHardTagListLimit) {
myHardTagListLimit = theHardTagListLimit;
}
/**
* If set to {@link IndexEnabledEnum#DISABLED} (default is {@link IndexEnabledEnum#DISABLED})
* the server will not create search indexes for search parameters with no values in resources.
@ -1442,22 +1420,6 @@ public class DaoConfig {
myExpungeBatchSize = theExpungeBatchSize;
}
/**
* Should contained IDs be indexed the same way that non-contained IDs are (default is
* <code>true</code>)
*/
public boolean isIndexContainedResources() {
return myIndexContainedResources;
}
/**
* Should contained IDs be indexed the same way that non-contained IDs are (default is
* <code>true</code>)
*/
public void setIndexContainedResources(boolean theIndexContainedResources) {
myIndexContainedResources = theIndexContainedResources;
}
/**
* Should resources be marked as needing reindexing when a
* SearchParameter resource is added or changed. This should generally
@ -1591,62 +1553,6 @@ public class DaoConfig {
myValidateSearchParameterExpressionsOnSave = theValidateSearchParameterExpressionsOnSave;
}
/**
* Do not call this method, it exists only for legacy reasons. It
* will be removed in a future version. Configure the page size on your
* paging provider instead.
*
* @deprecated This method does not do anything. Configure the page size on your
* paging provider instead. Deprecated in HAPI FHIR 2.3 (Jan 2017)
*/
@Deprecated
public void setHardSearchLimit(int theHardSearchLimit) {
// this method does nothing
}
/**
* This is the maximum number of resources that will be added to a single page of returned resources. Because of
* includes with wildcards and other possibilities it is possible for a client to make requests that include very
* large amounts of data, so this hard limit can be imposed to prevent runaway requests.
*
* @deprecated Deprecated in HAPI FHIR 3.2.0 as this method doesn't actually do anything
*/
@Deprecated
public void setIncludeLimit(@SuppressWarnings("unused") int theIncludeLimit) {
// nothing
}
/**
* @deprecated As of HAPI FHIR 3.0.0, subscriptions no longer use polling for
* detecting changes, so this setting has no effect
*/
@Deprecated
public void setSubscriptionEnabled(boolean theSubscriptionEnabled) {
// nothing
}
/**
* @deprecated As of HAPI FHIR 3.0.0, subscriptions no longer use polling for
* detecting changes, so this setting has no effect
*/
@Deprecated
public void setSubscriptionPollDelay(long theSubscriptionPollDelay) {
// ignore
}
/**
* @deprecated As of HAPI FHIR 3.0.0, subscriptions no longer use polling for
* detecting changes, so this setting has no effect
*/
@Deprecated
public void setSubscriptionPurgeInactiveAfterMillis(Long theMillis) {
// ignore
}
public void setSubscriptionPurgeInactiveAfterSeconds(int theSeconds) {
setSubscriptionPurgeInactiveAfterMillis(theSeconds * DateUtils.MILLIS_PER_SECOND);
}
/**
* This setting sets the number of search results to prefetch. For example, if this list
* is set to [100, 1000, -1] then the server will initially load 100 results and not

View File

@ -54,7 +54,7 @@ import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
import ca.uhn.fhir.jpa.search.cache.SearchCacheStatusEnum;
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
import ca.uhn.fhir.jpa.searchparam.SearchContainedEnum;
import ca.uhn.fhir.rest.api.SearchContainedModeEnum;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.util.JpaInterceptorBroadcaster;
import ca.uhn.fhir.model.api.IQueryParameterType;
@ -1292,16 +1292,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override
public IBundleProvider search(final SearchParameterMap theParams, RequestDetails theRequest, HttpServletResponse theServletResponse) {
if (theRequest != null) {
String[] contained = theRequest.getParameters().get(Constants.PARAM_CONTAINED);
if (contained != null && contained.length > 0) {
if (contained[0].equals("true")) {
theParams.setSearchContainedMode(SearchContainedEnum.TRUE);
ourLog.info("Search on contained resources only");
} else if (contained[0].equals("both")) {
ourLog.warn("Search on both normal resources and contained resources are not support. set to default search on normal resources");
}
}
if (theParams.getSearchContainedMode() == SearchContainedModeEnum.BOTH) {
throw new MethodNotAllowedException("Contained mode 'both' is not currently supported");
}
if (theParams.getSearchContainedMode() != SearchContainedModeEnum.FALSE && !myModelConfig.isIndexOnContainedResources()) {
throw new MethodNotAllowedException("Searching with _contained mode enabled is not enabled on this server");
}
if (myDaoConfig.getIndexMissingFields() == DaoConfig.IndexEnabledEnum.DISABLED) {

View File

@ -52,7 +52,7 @@ import ca.uhn.fhir.jpa.search.builder.predicate.TokenPredicateBuilder;
import ca.uhn.fhir.jpa.search.builder.predicate.UriPredicateBuilder;
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.SearchContainedEnum;
import ca.uhn.fhir.rest.api.SearchContainedModeEnum;
import ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.jpa.searchparam.util.SourceParam;
@ -561,7 +561,7 @@ public class QueryStack {
List<String> paths = join.createResourceLinkPaths(targetResourceType, paramReference);
Condition typePredicate = BinaryCondition.equalTo(join.getColumnTargetResourceType(), mySqlBuilder.generatePlaceholder(theResourceType));
Condition pathPredicate = toEqualToOrInPredicate(join.getColumnSourcePath(), mySqlBuilder.generatePlaceholders(paths));
Condition linkedPredicate = searchForIdsWithAndOr(join.getColumnSrcResourceId(), targetResourceType, parameterName, Collections.singletonList(orValues), theRequest, theRequestPartitionId, SearchContainedEnum.FALSE);
Condition linkedPredicate = searchForIdsWithAndOr(join.getColumnSrcResourceId(), targetResourceType, parameterName, Collections.singletonList(orValues), theRequest, theRequestPartitionId, SearchContainedModeEnum.FALSE);
andPredicates.add(toAndPredicate(partitionPredicate, pathPredicate, typePredicate, linkedPredicate));
}
@ -1046,7 +1046,7 @@ public class QueryStack {
}
@Nullable
public Condition searchForIdsWithAndOr(@Nullable DbColumn theSourceJoinColumn, String theResourceName, String theParamName, List<List<IQueryParameterType>> theAndOrParams, RequestDetails theRequest, RequestPartitionId theRequestPartitionId, SearchContainedEnum theSearchContainedMode) {
public Condition searchForIdsWithAndOr(@Nullable DbColumn theSourceJoinColumn, String theResourceName, String theParamName, List<List<IQueryParameterType>> theAndOrParams, RequestDetails theRequest, RequestPartitionId theRequestPartitionId, SearchContainedModeEnum theSearchContainedMode) {
if (theAndOrParams.isEmpty()) {
return null;
@ -1108,7 +1108,7 @@ public class QueryStack {
break;
case REFERENCE:
for (List<? extends IQueryParameterType> nextAnd : theAndOrParams) {
if (theSearchContainedMode.equals(SearchContainedEnum.TRUE))
if (theSearchContainedMode.equals(SearchContainedModeEnum.TRUE))
andPredicates.add(createPredicateReferenceForContainedResource(theSourceJoinColumn, theResourceName, theParamName, nextParamDef, nextAnd, null, theRequest, theRequestPartitionId));
else
andPredicates.add(createPredicateReference(theSourceJoinColumn, theResourceName, theParamName, nextAnd, null, theRequest, theRequestPartitionId));

View File

@ -60,7 +60,7 @@ import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.jpa.searchparam.util.Dstu3DistanceHelper;
import ca.uhn.fhir.jpa.searchparam.util.LastNParameterHelper;
import ca.uhn.fhir.jpa.searchparam.SearchContainedEnum;
import ca.uhn.fhir.rest.api.SearchContainedModeEnum;
import ca.uhn.fhir.jpa.util.BaseIterator;
import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
import ca.uhn.fhir.jpa.util.JpaInterceptorBroadcaster;
@ -216,7 +216,7 @@ public class SearchBuilder implements ISearchBuilder {
attemptCompositeUniqueSpProcessing(theQueryStack, theParams, theRequest);
}
SearchContainedEnum searchContainedMode = theParams.getSearchContainedMode();
SearchContainedModeEnum searchContainedMode = theParams.getSearchContainedMode();
// Handle each parameter
List<String> paramNames = new ArrayList<>(myParams.keySet());

View File

@ -43,7 +43,7 @@ import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
import ca.uhn.fhir.jpa.searchparam.ResourceMetaParams;
import ca.uhn.fhir.jpa.searchparam.SearchContainedEnum;
import ca.uhn.fhir.rest.api.SearchContainedModeEnum;
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
import ca.uhn.fhir.jpa.util.JpaInterceptorBroadcaster;
import ca.uhn.fhir.model.api.IQueryParameterType;
@ -395,7 +395,7 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder {
List<Condition> andPredicates = new ArrayList<>();
List<List<IQueryParameterType>> chainParamValues = Collections.singletonList(orValues);
andPredicates.add(childQueryFactory.searchForIdsWithAndOr(myColumnTargetResourceId, subResourceName, chain, chainParamValues, theRequest, theRequestPartitionId, SearchContainedEnum.FALSE));
andPredicates.add(childQueryFactory.searchForIdsWithAndOr(myColumnTargetResourceId, subResourceName, chain, chainParamValues, theRequest, theRequestPartitionId, SearchContainedModeEnum.FALSE));
orPredicates.add(toAndPredicate(andPredicates));

View File

@ -244,9 +244,6 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
@BeforeEach
public void beforeResetConfig() {
myDaoConfig.setHardSearchLimit(1000);
myDaoConfig.setHardTagListLimit(1000);
myDaoConfig.setIncludeLimit(2000);
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
}

View File

@ -396,9 +396,6 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
@BeforeEach
public void beforeResetConfig() {
myDaoConfig.setHardSearchLimit(1000);
myDaoConfig.setHardTagListLimit(1000);
myDaoConfig.setIncludeLimit(2000);
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
}

View File

@ -3,12 +3,10 @@ package ca.uhn.fhir.jpa.dao.dstu3;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.TokenParamModifier;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -18,23 +16,17 @@ public class FhirResourceDaoDstu3ContainedTest extends BaseJpaDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3ContainedTest.class);
@Test
public void before() {
myDaoConfig.setIndexContainedResources(true);
}
@Test
public void testIndexContained() {
Patient p = new Patient();
p.setId("#some_patient");
p.addName().setFamily("MYFAMILY").addGiven("MYGIVEN");
Observation o1 = new Observation();
o1.getCode().setText("Some Observation");
o1.setSubject(new Reference(p));
IIdType oid1 = myObservationDao.create(o1, mySrd).getId().toUnqualifiedVersionless();
Observation o2 = new Observation();
o2.getCode().setText("Some Observation");
o2.setSubject(new Reference(p));
@ -43,16 +35,16 @@ public class FhirResourceDaoDstu3ContainedTest extends BaseJpaDstu3Test {
Patient p2 = new Patient();
p2.addName().setFamily("MYFAMILY").addGiven("MYGIVEN");
IIdType pid2 = myPatientDao.create(p2, mySrd).getId().toUnqualifiedVersionless();
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(o2));
SearchParameterMap map = new SearchParameterMap();
map.add(Observation.SP_CODE, new TokenParam(null, "some observation").setModifier(TokenParamModifier.TEXT));
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(oid1, oid2)));
}
// TODO: make sure match URLs don't delete
}

View File

@ -476,7 +476,6 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
@Autowired
private IValidationSupport myJpaValidationSupportChainR4;
private PerformanceTracingLoggingInterceptor myPerformanceTracingLoggingInterceptor;
private List<Object> mySystemInterceptors;
@Autowired
private IBulkDataExportSvc myBulkDataExportSvc;
@Autowired
@ -524,8 +523,6 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
@BeforeEach
public void beforeCreateInterceptor() {
mySystemInterceptors = myInterceptorRegistry.getAllRegisteredInterceptors();
myInterceptor = mock(IServerInterceptor.class);
myPerformanceTracingLoggingInterceptor = new PerformanceTracingLoggingInterceptor();
@ -558,9 +555,6 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
@BeforeEach
public void beforeResetConfig() {
myDaoConfig.setHardSearchLimit(1000);
myDaoConfig.setHardTagListLimit(1000);
myDaoConfig.setIncludeLimit(2000);
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
myValidationSettings.setLocalReferenceValidationDefaultPolicy(new ValidationSettings().getLocalReferenceValidationDefaultPolicy());
}

View File

@ -5,7 +5,6 @@ import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Address;
import org.hl7.fhir.r4.model.Address.AddressUse;
@ -27,7 +26,7 @@ import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import ca.uhn.fhir.jpa.searchparam.SearchContainedEnum;
import ca.uhn.fhir.rest.api.SearchContainedModeEnum;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.ReferenceParam;
@ -75,7 +74,7 @@ public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
map = new SearchParameterMap();
map.add("subject", new ReferenceParam("name", "Smith"));
map.setSearchContainedMode(SearchContainedEnum.TRUE);
map.setSearchContainedMode(SearchContainedModeEnum.TRUE);
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id)));
}
@ -111,7 +110,7 @@ public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
map = new SearchParameterMap();
map.add("subject", new ReferenceParam("name", "Smith"));
map.setSearchContainedMode(SearchContainedEnum.TRUE);
map.setSearchContainedMode(SearchContainedModeEnum.TRUE);
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id)));
}
@ -180,7 +179,7 @@ public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
map = new SearchParameterMap();
map.add("general-practitioner", new ReferenceParam("family", "Smith"));
map.setSearchContainedMode(SearchContainedEnum.TRUE);
map.setSearchContainedMode(SearchContainedModeEnum.TRUE);
assertThat(toUnqualifiedVersionlessIdValues(myPatientDao.search(map)), containsInAnyOrder(toValues(id)));
}
@ -265,7 +264,7 @@ public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
map = new SearchParameterMap();
map.add("based-on", new ReferenceParam("authored", "2021-02-23"));
map.setSearchContainedMode(SearchContainedEnum.TRUE);
map.setSearchContainedMode(SearchContainedModeEnum.TRUE);
assertThat(toUnqualifiedVersionlessIdValues(myEncounterDao.search(map)), containsInAnyOrder(toValues(id)));
}
@ -277,7 +276,7 @@ public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
map = new SearchParameterMap();
map.add("subject", new ReferenceParam("near", "toronto"));
map.setSearchContainedMode(SearchContainedEnum.TRUE);
map.setSearchContainedMode(SearchContainedModeEnum.TRUE);
try {
IBundleProvider outcome = myObservationDao.search(map);
@ -296,7 +295,7 @@ public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
map = new SearchParameterMap();
map.add("subject", new ReferenceParam("marital-status", "M"));
map.setSearchContainedMode(SearchContainedEnum.TRUE);
map.setSearchContainedMode(SearchContainedModeEnum.TRUE);
try {
IBundleProvider outcome = myObservationDao.search(map);
@ -307,4 +306,4 @@ public class FhirResourceDaoR4ContainedTest extends BaseJpaR4Test {
}
}
}
}

View File

@ -148,13 +148,6 @@ public class FhirResourceDaoR4SearchWithLuceneDisabledTest extends BaseJpaTest {
purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegistry, myBulkDataExportSvc);
}
@BeforeEach
public void beforeResetConfig() {
myDaoConfig.setHardSearchLimit(1000);
myDaoConfig.setHardTagListLimit(1000);
myDaoConfig.setIncludeLimit(2000);
}
@Override
protected PlatformTransactionManager getTxManager() {
return myTxManager;
@ -171,7 +164,7 @@ public class FhirResourceDaoR4SearchWithLuceneDisabledTest extends BaseJpaTest {
Organization org = new Organization();
org.setName(methodName);
IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap map = new SearchParameterMap();
map.add(ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT, new StringParam(methodName));
@ -189,7 +182,7 @@ public class FhirResourceDaoR4SearchWithLuceneDisabledTest extends BaseJpaTest {
Organization org = new Organization();
org.setName(methodName);
IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
SearchParameterMap map = new SearchParameterMap();
map.add(Organization.SP_NAME, new StringParam(methodName));

View File

@ -480,7 +480,6 @@ public abstract class BaseJpaR5Test extends BaseJpaTest {
@BeforeEach
public void beforeResetConfig() {
myDaoConfig.setHardTagListLimit(1000);
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
}

View File

@ -309,9 +309,6 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
@Test
public void testCountParam() {
// NB this does not get used- The paging provider has its own limits built in
myDaoConfig.setHardSearchLimit(100);
List<IBaseResource> resources = new ArrayList<IBaseResource>();
for (int i = 0; i < 100; i++) {
Organization org = new Organization();

View File

@ -7,7 +7,12 @@ import ca.uhn.fhir.jpa.subscription.SubscriptionTestUtil;
import ca.uhn.fhir.rest.api.MethodOutcome;
import com.google.common.collect.Lists;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.EventDefinition;
import org.hl7.fhir.r4.model.Expression;
import org.hl7.fhir.r4.model.Observation;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Subscription;
import org.hl7.fhir.r4.model.TriggerDefinition;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
@ -36,6 +41,7 @@ import java.util.List;
* 6. Execute the 'sendObservation' test
* 7. Look in the 'attachWebSocket' terminal execution and wait for your ping with the subscription id
*/
/**
* Ignored because this feature isn't implemented yet
*/
@ -77,15 +83,6 @@ public class RestHookWithEventDefinitionR4Test extends BaseResourceProviderR4Tes
mySubscriptionTestUtil.unregisterSubscriptionInterceptor();
}
@Override
@BeforeEach
public void before() throws Exception {
super.before();
myDaoConfig.setSubscriptionEnabled(true);
}
@Test
public void testSubscriptionAddedTrigger() {
/*

View File

@ -9,7 +9,12 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.Observation;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.Subscription;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -20,8 +25,8 @@ import java.net.URI;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
/**
* Adds a FHIR subscription with criteria through the rest interface. Then creates a websocket with the id of the
@ -71,9 +76,6 @@ public class WebsocketWithSubscriptionIdDstu3Test extends BaseResourceProviderDs
public void before() throws Exception {
super.before();
myDaoConfig.setSubscriptionEnabled(true);
myDaoConfig.setSubscriptionPollDelay(0L);
mySubscriptionTestUtil.registerWebSocketInterceptor();
/*

View File

@ -734,8 +734,8 @@ public class ModelConfig {
/**
* Should indexed on the contained resources, it could be searched by <code>_contained=true</code>
* This may have performance impacts
* Should indexing and searching on contained resources be enabled on this server.
* This may have performance impacts, and should be enabled only if it is needed. Default is <code>false</code>.
*
* @since 5.4.0
*/
@ -744,9 +744,9 @@ public class ModelConfig {
}
/**
* Should indexed on the contained resources, it could be searched by <code>_contained=true</code>
* This may have performance impacts
*
* Should indexing and searching on contained resources be enabled on this server.
* This may have performance impacts, and should be enabled only if it is needed. Default is <code>false</code>.
*
* @since 5.4.0
*/
public void setIndexOnContainedResources(boolean theIndexOnContainedResources) {

View File

@ -1,40 +0,0 @@
package ca.uhn.fhir.jpa.searchparam;
/*
* #%L
* HAPI FHIR Search Parameters
* %%
* Copyright (C) 2014 - 2021 Smile CDR, Inc.
* %%
* 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%
*/
public enum SearchContainedEnum {
/**
* default, search on the non-contained (normal) resources
*/
FALSE,
/**
* search on the contained resources only
*/
TRUE,
/**
* Search on the normal resources and contained resources.
* This option is not supported yet.
*/
BOTH,
}

View File

@ -6,6 +6,7 @@ import ca.uhn.fhir.model.api.IQueryParameterOr;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.SearchContainedModeEnum;
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec;
@ -79,7 +80,7 @@ public class SearchParameterMap implements Serializable {
private boolean myLastN;
private Integer myLastNMax;
private boolean myDeleteExpunge;
private SearchContainedEnum mySearchContainedMode = SearchContainedEnum.FALSE;
private SearchContainedModeEnum mySearchContainedMode = SearchContainedModeEnum.FALSE;
/**
* Constructor
@ -735,12 +736,16 @@ public class SearchParameterMap implements Serializable {
return retVal;
}
public SearchContainedEnum getSearchContainedMode() {
public SearchContainedModeEnum getSearchContainedMode() {
return mySearchContainedMode;
}
public void setSearchContainedMode(SearchContainedEnum theSearchContainedMode) {
this.mySearchContainedMode = theSearchContainedMode;
public void setSearchContainedMode(SearchContainedModeEnum theSearchContainedMode) {
if (theSearchContainedMode == null) {
mySearchContainedMode = SearchContainedModeEnum.FALSE;
} else {
this.mySearchContainedMode = theSearchContainedMode;
}
}

View File

@ -79,6 +79,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
retVal.setWebsocketContextPath("/");
retVal.setFilterParameterEnabled(true);
retVal.setDefaultSearchParamsCanBeOverridden(false);
retVal.getModelConfig().setIndexOnContainedResources(true);
return retVal;
}

View File

@ -77,6 +77,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
retVal.setExpungeEnabled(true);
retVal.setFilterParameterEnabled(true);
retVal.setDefaultSearchParamsCanBeOverridden(false);
retVal.getModelConfig().setIndexOnContainedResources(true);
return retVal;
}

View File

@ -78,6 +78,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
retVal.setExpungeEnabled(true);
retVal.setFilterParameterEnabled(true);
retVal.setDefaultSearchParamsCanBeOverridden(false);
retVal.getModelConfig().setIndexOnContainedResources(true);
return retVal;
}

View File

@ -77,6 +77,7 @@ public class TestR5Config extends BaseJavaConfigR5 {
retVal.setExpungeEnabled(true);
retVal.setFilterParameterEnabled(true);
retVal.setDefaultSearchParamsCanBeOverridden(false);
retVal.getModelConfig().setIndexOnContainedResources(true);
return retVal;
}

View File

@ -44,7 +44,6 @@ import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
public class RuleBuilder implements IAuthRuleBuilder {
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private static final ConcurrentHashMap<Class<? extends IBaseResource>, String> ourTypeToName = new ConcurrentHashMap<>();
private ArrayList<IAuthRule> myRules;
private IAuthRuleBuilderRule myAllow;
@ -144,7 +143,7 @@ public class RuleBuilder implements IAuthRuleBuilder {
@Override
public IAuthRuleBuilderRuleOpClassifierFinishedWithTenantId forTenantIds(String... theTenantIds) {
return forTenantIds(Arrays.asList(defaultIfNull(theTenantIds, EMPTY_STRING_ARRAY)));
return forTenantIds(Arrays.asList(defaultIfNull(theTenantIds, Constants.EMPTY_STRING_ARRAY)));
}
@Override
@ -162,7 +161,7 @@ public class RuleBuilder implements IAuthRuleBuilder {
@Override
public IAuthRuleBuilderRuleOpClassifierFinishedWithTenantId notForTenantIds(String... theTenantIds) {
return notForTenantIds(Arrays.asList(defaultIfNull(theTenantIds, EMPTY_STRING_ARRAY)));
return notForTenantIds(Arrays.asList(defaultIfNull(theTenantIds, Constants.EMPTY_STRING_ARRAY)));
}
@Override

View File

@ -131,6 +131,8 @@ public class MethodUtil {
param = new SummaryEnumParameter();
} else if (parameterType.equals(PatchTypeEnum.class)) {
param = new PatchTypeParameter();
} else if (parameterType.equals(SearchContainedModeEnum.class)) {
param = new SearchContainedModeParameter();
} else if (parameterType.equals(SearchTotalModeEnum.class)) {
param = new SearchTotalModeParameter();
} else {

View File

@ -0,0 +1,34 @@
package ca.uhn.fhir.rest.server.method;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.SearchContainedModeEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import java.lang.reflect.Method;
import java.util.Collection;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
class SearchContainedModeParameter implements IParameter {
@Override
public Object translateQueryParametersIntoServerArgument(RequestDetails theRequest, BaseMethodBinding<?> theMethodBinding) throws InternalErrorException, InvalidRequestException {
return getTypeForRequestOrThrowInvalidRequestException(theRequest);
}
@Override
public void initializeTypes(Method theMethod, Class<? extends Collection<?>> theOuterCollectionType, Class<? extends Collection<?>> theInnerCollectionType, Class<?> theParameterType) {
// ignore
}
public static SearchContainedModeEnum getTypeForRequestOrThrowInvalidRequestException(RequestDetails theRequest) {
String[] paramValues = theRequest.getParameters().getOrDefault(Constants.PARAM_CONTAINED, Constants.EMPTY_STRING_ARRAY);
if (paramValues.length > 0 && isNotBlank(paramValues[0])) {
return SearchContainedModeEnum.fromCode(paramValues[0]);
}
return null;
}
}

View File

@ -20,6 +20,7 @@ import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
import ca.uhn.fhir.rest.api.SearchContainedModeEnum;
public class ${className}ResourceProvider extends
## We have specialized base classes for RPs that handle certain resource types. These
@ -138,7 +139,9 @@ public class ${className}ResourceProvider extends
SummaryEnum theSummaryMode,
SearchTotalModeEnum theSearchTotalMode
SearchTotalModeEnum theSearchTotalMode,
SearchContainedModeEnum theSearchContainedMode
) {
startRequest(theServletRequest);
@ -165,6 +168,7 @@ public class ${className}ResourceProvider extends
paramMap.setOffset(theOffset);
paramMap.setSummaryMode(theSummaryMode);
paramMap.setSearchTotalMode(theSearchTotalMode);
paramMap.setSearchContainedMode(theSearchContainedMode);
getDao().translateRawParameters(theAdditionalRawParams, paramMap);