Refactor Common SearchParameter Functionality (#4321)
* refactor checkpoint * clean up * add method to find runtime search param by id * new search param cache tests * extract SearchParameter validation functionality * create common interface for combo searchparameters * Remove ResourceTable from extractor interface * clean up * move SearchParameterDaoValidator * resolve code review comments * remove reflection * change log * bump version to 6.3.4-SNAPSHOT Co-authored-by: nathaniel.doef <nathaniel.doef@smilecdr.com>
This commit is contained in:
parent
29ebb950e8
commit
7b86eda8a9
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-bom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>HAPI FHIR BOM</name>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-cli</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../../hapi-deployable-pom</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
type: change
|
||||
issue: 4363
|
||||
title: "Common `SearchParameter` functionality has been refactored. In particular,
|
||||
1) Validation logic performed inside `JpaResourceDaoSearchParameter` has been moved into a new class called
|
||||
`SearchParameterDaoValidator` 2) Logic for extracting combo unique and combo non-unique search parameters
|
||||
that was inside `SearchParamWithInlineReferencesExtractor` has been moved into `BaseSearchParamExtractor`
|
||||
and 3) a new interface called `IResourceIndexComboSearchParameter` has been added which provides a common interface
|
||||
for combo unique and combo non-unique search parameters."
|
|
@ -11,7 +11,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -134,6 +134,7 @@ import ca.uhn.fhir.jpa.term.api.ITermReindexingSvc;
|
|||
import ca.uhn.fhir.jpa.term.config.TermCodeSystemConfig;
|
||||
import ca.uhn.fhir.jpa.util.MemoryCacheService;
|
||||
import ca.uhn.fhir.jpa.validation.ResourceLoaderImpl;
|
||||
import ca.uhn.fhir.jpa.dao.validation.SearchParameterDaoValidator;
|
||||
import ca.uhn.fhir.jpa.validation.ValidationSettings;
|
||||
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
|
||||
import ca.uhn.fhir.mdm.dao.IMdmLinkImplFactory;
|
||||
|
@ -145,6 +146,7 @@ import ca.uhn.fhir.rest.server.interceptor.ResponseTerminologyTranslationInterce
|
|||
import ca.uhn.fhir.rest.server.interceptor.ResponseTerminologyTranslationSvc;
|
||||
import ca.uhn.fhir.rest.server.interceptor.consent.IConsentContextServices;
|
||||
import ca.uhn.fhir.rest.server.interceptor.partition.RequestTenantPartitionInterceptor;
|
||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||
import ca.uhn.hapi.converters.canonical.VersionCanonicalizer;
|
||||
import org.hl7.fhir.common.hapi.validation.support.UnknownCodeSystemWarningValidationSupport;
|
||||
import org.hl7.fhir.r4.model.Consent;
|
||||
|
@ -775,6 +777,11 @@ public class JpaConfig {
|
|||
return new VersionCanonicalizer(theFhirContext);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SearchParameterDaoValidator searchParameterDaoValidator(FhirContext theFhirContext, DaoConfig theDaoConfig, ISearchParamRegistry theSearchParamRegistry) {
|
||||
return new SearchParameterDaoValidator(theFhirContext, theDaoConfig, theSearchParamRegistry);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ITermReadSvc terminologyService() {
|
||||
return new TermReadSvcImpl();
|
||||
|
|
|
@ -1,31 +1,18 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoSearchParameter;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.dao.validation.SearchParameterDaoValidator;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import ca.uhn.hapi.converters.canonical.VersionCanonicalizer;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r5.model.CodeType;
|
||||
import org.hl7.fhir.r5.model.Enumerations;
|
||||
import org.hl7.fhir.r5.model.SearchParameter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -48,10 +35,12 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
|||
|
||||
public class JpaResourceDaoSearchParameter<T extends IBaseResource> extends BaseHapiFhirResourceDao<T> implements IFhirResourceDaoSearchParameter<T> {
|
||||
|
||||
private static final Pattern REGEX_SP_EXPRESSION_HAS_PATH = Pattern.compile("[( ]*([A-Z][a-zA-Z]+\\.)?[a-z].*");
|
||||
@Autowired
|
||||
private VersionCanonicalizer myVersionCanonicalizer;
|
||||
|
||||
@Autowired
|
||||
private SearchParameterDaoValidator mySearchParameterDaoValidator;
|
||||
|
||||
protected void reindexAffectedResources(T theResource, RequestDetails theRequestDetails) {
|
||||
// N.B. Don't do this on the canonicalized version
|
||||
Boolean reindex = theResource != null ? CURRENTLY_REINDEXING.get(theResource) : null;
|
||||
|
@ -84,88 +73,12 @@ public class JpaResourceDaoSearchParameter<T extends IBaseResource> extends Base
|
|||
protected void validateResourceForStorage(T theResource, ResourceTable theEntityToSave) {
|
||||
super.validateResourceForStorage(theResource, theEntityToSave);
|
||||
|
||||
validateSearchParam(theResource, getContext(), getConfig());
|
||||
validateSearchParam(theResource);
|
||||
}
|
||||
|
||||
public void validateSearchParam(IBaseResource theResource, FhirContext theContext, DaoConfig theDaoConfig) {
|
||||
public void validateSearchParam(IBaseResource theResource) {
|
||||
org.hl7.fhir.r5.model.SearchParameter searchParameter = myVersionCanonicalizer.searchParameterToCanonical(theResource);
|
||||
|
||||
/*
|
||||
* If overriding built-in SPs is disabled on this server, make sure we aren't
|
||||
* doing that
|
||||
*/
|
||||
if (theDaoConfig.getModelConfig().isDefaultSearchParamsCanBeOverridden() == false) {
|
||||
for (IPrimitiveType<?> nextBaseType : searchParameter.getBase()) {
|
||||
String nextBase = nextBaseType.getValueAsString();
|
||||
RuntimeSearchParam existingSearchParam = mySearchParamRegistry.getActiveSearchParam(nextBase, searchParameter.getCode());
|
||||
if (existingSearchParam != null) {
|
||||
boolean isBuiltIn = existingSearchParam.getId() == null;
|
||||
isBuiltIn |= existingSearchParam.getUri().startsWith("http://hl7.org/fhir/SearchParameter/");
|
||||
if (isBuiltIn) {
|
||||
throw new UnprocessableEntityException(Msg.code(1111) + "Can not override built-in search parameter " + nextBase + ":" + searchParameter.getCode() + " because overriding is disabled on this server");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Everything below is validating that the SP is actually valid. We'll only do that if the
|
||||
* SPO is active, so that we don't block people from uploading works-in-progress
|
||||
*/
|
||||
if (searchParameter.getStatus() == null) {
|
||||
throw new UnprocessableEntityException(Msg.code(1112) + "SearchParameter.status is missing or invalid");
|
||||
}
|
||||
if (!searchParameter.getStatus().name().equals("ACTIVE")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ElementUtil.isEmpty(searchParameter.getBase()) && (searchParameter.getType() == null || !Enumerations.SearchParamType.COMPOSITE.name().equals(searchParameter.getType().name()))) {
|
||||
throw new UnprocessableEntityException(Msg.code(1113) + "SearchParameter.base is missing");
|
||||
}
|
||||
|
||||
boolean isUnique = hasAnyExtensionUniqueSetTo(searchParameter, true);
|
||||
|
||||
if (searchParameter.getType() != null && searchParameter.getType().name().equals(Enumerations.SearchParamType.COMPOSITE.name()) && isBlank(searchParameter.getExpression())) {
|
||||
|
||||
// this is ok
|
||||
|
||||
} else if (isBlank(searchParameter.getExpression())) {
|
||||
|
||||
throw new UnprocessableEntityException(Msg.code(1114) + "SearchParameter.expression is missing");
|
||||
|
||||
} else {
|
||||
|
||||
if (isUnique) {
|
||||
if (searchParameter.getComponent().size() == 0) {
|
||||
throw new UnprocessableEntityException(Msg.code(1115) + "SearchParameter is marked as unique but has no components");
|
||||
}
|
||||
for (SearchParameter.SearchParameterComponentComponent next : searchParameter.getComponent()) {
|
||||
if (isBlank(next.getDefinition())) {
|
||||
throw new UnprocessableEntityException(Msg.code(1116) + "SearchParameter is marked as unique but is missing component.definition");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FhirVersionEnum fhirVersion = theContext.getVersion().getVersion();
|
||||
if (fhirVersion.isOlderThan(FhirVersionEnum.DSTU3)) {
|
||||
// omitting validation for DSTU2_HL7ORG, DSTU2_1 and DSTU2
|
||||
} else {
|
||||
|
||||
if (theDaoConfig.isValidateSearchParameterExpressionsOnSave()) {
|
||||
|
||||
validateExpressionPath(searchParameter);
|
||||
|
||||
String expression = getExpression(searchParameter);
|
||||
|
||||
try {
|
||||
theContext.newFhirPath().parse(expression);
|
||||
} catch (Exception exception) {
|
||||
throw new UnprocessableEntityException(Msg.code(1121) + "Invalid FHIRPath format for SearchParameter.expression \"" + expression + "\": " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mySearchParameterDaoValidator.validate(searchParameter);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
@ -173,32 +86,8 @@ public class JpaResourceDaoSearchParameter<T extends IBaseResource> extends Base
|
|||
myVersionCanonicalizer = theVersionCanonicalizer;
|
||||
}
|
||||
|
||||
private static void validateExpressionPath(SearchParameter theSearchParameter) {
|
||||
String expression = getExpression(theSearchParameter);
|
||||
|
||||
boolean isResourceOfTypeComposite = theSearchParameter.getType() == Enumerations.SearchParamType.COMPOSITE;
|
||||
boolean isResourceOfTypeSpecial = theSearchParameter.getType() == Enumerations.SearchParamType.SPECIAL;
|
||||
boolean expressionHasPath = REGEX_SP_EXPRESSION_HAS_PATH.matcher(expression).matches();
|
||||
|
||||
boolean isUnique = hasAnyExtensionUniqueSetTo(theSearchParameter, true);
|
||||
|
||||
if (!isUnique && !isResourceOfTypeComposite && !isResourceOfTypeSpecial && !expressionHasPath) {
|
||||
throw new UnprocessableEntityException(Msg.code(1120) + "SearchParameter.expression value \"" + expression + "\" is invalid due to missing/incorrect path");
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setSearchParameterDaoValidatorForUnitTest(SearchParameterDaoValidator theSearchParameterDaoValidator){
|
||||
mySearchParameterDaoValidator = theSearchParameterDaoValidator;
|
||||
}
|
||||
|
||||
private static String getExpression(SearchParameter theSearchParameter) {
|
||||
return theSearchParameter.getExpression().trim();
|
||||
}
|
||||
|
||||
private static boolean hasAnyExtensionUniqueSetTo(SearchParameter theSearchParameter, boolean theValue) {
|
||||
String theValueAsString = Boolean.toString(theValue);
|
||||
|
||||
return theSearchParameter
|
||||
.getExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||
.stream()
|
||||
.anyMatch(t -> theValueAsString.equals(t.getValueAsPrimitive().getValueAsString()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ package ca.uhn.fhir.jpa.dao.index;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
|
@ -37,15 +36,11 @@ import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource;
|
|||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorService;
|
||||
import ca.uhn.fhir.jpa.searchparam.util.JpaParamUtil;
|
||||
import ca.uhn.fhir.jpa.util.MemoryCacheService;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
|
@ -54,8 +49,6 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
|||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.rest.server.util.ResourceSearchParams;
|
||||
import ca.uhn.fhir.util.FhirTerser;
|
||||
import ca.uhn.fhir.util.StringUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.hl7.fhir.instance.model.api.IBaseReference;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -64,23 +57,17 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.PersistenceContextType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
@Service
|
||||
@Lazy
|
||||
public class SearchParamWithInlineReferencesExtractor {
|
||||
|
@ -146,124 +133,12 @@ public class SearchParamWithInlineReferencesExtractor {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle combo parameters
|
||||
*/
|
||||
extractCompositeStringUniques(theEntity, theParams);
|
||||
extractComboParameters(theEntity, theParams);
|
||||
}
|
||||
|
||||
private void extractCompositeStringUniques(ResourceTable theEntity, ResourceIndexedSearchParams theParams) {
|
||||
|
||||
final String resourceType = theEntity.getResourceType();
|
||||
List<RuntimeSearchParam> comboSearchParams = mySearchParamRegistry.getActiveComboSearchParams(resourceType);
|
||||
|
||||
for (RuntimeSearchParam next : comboSearchParams) {
|
||||
switch (Objects.requireNonNull(next.getComboSearchParamType())) {
|
||||
case UNIQUE:
|
||||
extractComboUniqueParam(theEntity, theParams, resourceType, next);
|
||||
break;
|
||||
case NON_UNIQUE:
|
||||
extractComboNonUniqueParam(theEntity, theParams, resourceType, next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void extractComboNonUniqueParam(ResourceTable theEntity, ResourceIndexedSearchParams theParams, String theResourceType, RuntimeSearchParam theParam) {
|
||||
Set<String> queryStringsToPopulate = extractParameterCombinationsForComboParam(theParams, theResourceType, theParam);
|
||||
|
||||
for (String nextQueryString : queryStringsToPopulate) {
|
||||
ourLog.trace("Adding composite unique SP: {}", nextQueryString);
|
||||
theParams.myComboTokenNonUnique.add(new ResourceIndexedComboTokenNonUnique(myPartitionSettings, theEntity, nextQueryString));
|
||||
}
|
||||
}
|
||||
|
||||
private void extractComboUniqueParam(ResourceTable theEntity, ResourceIndexedSearchParams theParams, String theResourceType, RuntimeSearchParam theParam) {
|
||||
Set<String> queryStringsToPopulate = extractParameterCombinationsForComboParam(theParams, theResourceType, theParam);
|
||||
|
||||
for (String nextQueryString : queryStringsToPopulate) {
|
||||
ourLog.trace("Adding composite unique SP: {}", nextQueryString);
|
||||
theParams.myComboStringUniques.add(new ResourceIndexedComboStringUnique(theEntity, nextQueryString, theParam.getId()));
|
||||
}
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private Set<String> extractParameterCombinationsForComboParam(ResourceIndexedSearchParams theParams, String theResourceType, RuntimeSearchParam theParam) {
|
||||
List<List<String>> partsChoices = new ArrayList<>();
|
||||
|
||||
List<RuntimeSearchParam> compositeComponents = JpaParamUtil.resolveComponentParameters(mySearchParamRegistry, theParam);
|
||||
for (RuntimeSearchParam nextCompositeOf : compositeComponents) {
|
||||
Collection<? extends BaseResourceIndexedSearchParam> paramsListForCompositePart = findParameterIndexes(theParams, nextCompositeOf);
|
||||
|
||||
Collection<ResourceLink> linksForCompositePart = null;
|
||||
switch (nextCompositeOf.getParamType()) {
|
||||
case REFERENCE:
|
||||
linksForCompositePart = theParams.myLinks;
|
||||
break;
|
||||
case NUMBER:
|
||||
case DATE:
|
||||
case STRING:
|
||||
case TOKEN:
|
||||
case QUANTITY:
|
||||
case URI:
|
||||
case SPECIAL:
|
||||
case COMPOSITE:
|
||||
case HAS:
|
||||
break;
|
||||
}
|
||||
|
||||
Collection<String> linksForCompositePartWantPaths = null;
|
||||
switch (nextCompositeOf.getParamType()) {
|
||||
case REFERENCE:
|
||||
linksForCompositePartWantPaths = new HashSet<>(nextCompositeOf.getPathsSplit());
|
||||
break;
|
||||
case NUMBER:
|
||||
case DATE:
|
||||
case STRING:
|
||||
case TOKEN:
|
||||
case QUANTITY:
|
||||
case URI:
|
||||
case SPECIAL:
|
||||
case COMPOSITE:
|
||||
case HAS:
|
||||
break;
|
||||
}
|
||||
|
||||
ArrayList<String> nextChoicesList = new ArrayList<>();
|
||||
partsChoices.add(nextChoicesList);
|
||||
|
||||
String key = UrlUtil.escapeUrlParam(nextCompositeOf.getName());
|
||||
if (paramsListForCompositePart != null) {
|
||||
for (BaseResourceIndexedSearchParam nextParam : paramsListForCompositePart) {
|
||||
IQueryParameterType nextParamAsClientParam = nextParam.toQueryParameterType();
|
||||
String value = nextParamAsClientParam.getValueAsQueryToken(myContext);
|
||||
|
||||
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(theResourceType, key);
|
||||
if (theParam.getComboSearchParamType() == ComboSearchParamType.NON_UNIQUE && param != null && param.getParamType() == RestSearchParameterTypeEnum.STRING) {
|
||||
value = StringUtil.normalizeStringForSearchIndexing(value);
|
||||
}
|
||||
|
||||
if (isNotBlank(value)) {
|
||||
value = UrlUtil.escapeUrlParam(value);
|
||||
nextChoicesList.add(key + "=" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (linksForCompositePart != null) {
|
||||
for (ResourceLink nextLink : linksForCompositePart) {
|
||||
if (linksForCompositePartWantPaths.contains(nextLink.getSourcePath())) {
|
||||
assert isNotBlank(nextLink.getTargetResourceType());
|
||||
assert isNotBlank(nextLink.getTargetResourceId());
|
||||
String value = nextLink.getTargetResourceType() + "/" + nextLink.getTargetResourceId();
|
||||
if (isNotBlank(value)) {
|
||||
value = UrlUtil.escapeUrlParam(value);
|
||||
nextChoicesList.add(key + "=" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ResourceIndexedSearchParams.extractCompositeStringUniquesValueChains(theResourceType, partsChoices);
|
||||
private void extractComboParameters(ResourceTable theEntity, ResourceIndexedSearchParams theParams) {
|
||||
mySearchParamExtractorService.extractSearchParamComboUnique(theEntity, theParams);
|
||||
mySearchParamExtractorService.extractSearchParamComboNonUnique(theEntity, theParams);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package ca.uhn.fhir.jpa.model.entity;
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
|
||||
/**
|
||||
* Provides a common interface used to extract Combo Unique ({@link ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique})
|
||||
* and Combo Non-Unique ({@link ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique}) SearchParameters
|
||||
*/
|
||||
public interface IResourceIndexComboSearchParameter {
|
||||
|
||||
IIdType getSearchParameterId();
|
||||
|
||||
void setSearchParameterId(IIdType theSearchParameterId);
|
||||
|
||||
String getIndexString();
|
||||
|
||||
ResourceTable getResource();
|
||||
|
||||
void setResource(ResourceTable theResourceTable);
|
||||
}
|
|
@ -35,7 +35,7 @@ import javax.persistence.*;
|
|||
@Index(name = ResourceIndexedComboStringUnique.IDX_IDXCMPSTRUNIQ_STRING, columnList = "IDX_STRING", unique = true),
|
||||
@Index(name = ResourceIndexedComboStringUnique.IDX_IDXCMPSTRUNIQ_RESOURCE, columnList = "RES_ID", unique = false)
|
||||
})
|
||||
public class ResourceIndexedComboStringUnique extends BasePartitionable implements Comparable<ResourceIndexedComboStringUnique> {
|
||||
public class ResourceIndexedComboStringUnique extends BasePartitionable implements Comparable<ResourceIndexedComboStringUnique>, IResourceIndexComboSearchParameter {
|
||||
|
||||
public static final int MAX_STRING_LENGTH = 500;
|
||||
public static final String IDX_IDXCMPSTRUNIQ_STRING = "IDX_IDXCMPSTRUNIQ_STRING";
|
||||
|
@ -102,6 +102,7 @@ public class ResourceIndexedComboStringUnique extends BasePartitionable implemen
|
|||
.isEquals();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexString() {
|
||||
return myIndexString;
|
||||
}
|
||||
|
@ -139,6 +140,7 @@ public class ResourceIndexedComboStringUnique extends BasePartitionable implemen
|
|||
/**
|
||||
* Note: This field is not persisted, so it will only be populated for new indexes
|
||||
*/
|
||||
@Override
|
||||
public void setSearchParameterId(IIdType theSearchParameterId) {
|
||||
mySearchParameterId = theSearchParameterId;
|
||||
}
|
||||
|
@ -146,6 +148,7 @@ public class ResourceIndexedComboStringUnique extends BasePartitionable implemen
|
|||
/**
|
||||
* Note: This field is not persisted, so it will only be populated for new indexes
|
||||
*/
|
||||
@Override
|
||||
public IIdType getSearchParameterId() {
|
||||
return mySearchParameterId;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.apache.commons.lang3.builder.CompareToBuilder;
|
|||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
|
@ -48,7 +49,7 @@ import static ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam.hash;
|
|||
@Index(name = "IDX_IDXCMBTOKNU_STR", columnList = "IDX_STRING", unique = false),
|
||||
@Index(name = "IDX_IDXCMBTOKNU_RES", columnList = "RES_ID", unique = false)
|
||||
})
|
||||
public class ResourceIndexedComboTokenNonUnique extends BaseResourceIndex implements Comparable<ResourceIndexedComboTokenNonUnique> {
|
||||
public class ResourceIndexedComboTokenNonUnique extends BaseResourceIndex implements Comparable<ResourceIndexedComboTokenNonUnique>, IResourceIndexComboSearchParameter {
|
||||
|
||||
@SequenceGenerator(name = "SEQ_IDXCMBTOKNU_ID", sequenceName = "SEQ_IDXCMBTOKNU_ID")
|
||||
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_IDXCMBTOKNU_ID")
|
||||
|
@ -72,6 +73,9 @@ public class ResourceIndexedComboTokenNonUnique extends BaseResourceIndex implem
|
|||
@Transient
|
||||
private transient PartitionSettings myPartitionSettings;
|
||||
|
||||
@Transient
|
||||
private IIdType mySearchParameterId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
@ -86,6 +90,7 @@ public class ResourceIndexedComboTokenNonUnique extends BaseResourceIndex implem
|
|||
calculateHashes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIndexString() {
|
||||
return myIndexString;
|
||||
}
|
||||
|
@ -156,10 +161,15 @@ public class ResourceIndexedComboTokenNonUnique extends BaseResourceIndex implem
|
|||
return myPartitionSettings;
|
||||
}
|
||||
|
||||
public void setPartitionSettings(PartitionSettings thePartitionSettings) {
|
||||
myPartitionSettings = thePartitionSettings;
|
||||
}
|
||||
|
||||
public ResourceTable getResource() {
|
||||
return myResource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResource(ResourceTable theResource) {
|
||||
myResource = theResource;
|
||||
}
|
||||
|
@ -198,4 +208,19 @@ public class ResourceIndexedComboTokenNonUnique extends BaseResourceIndex implem
|
|||
return hash(partitionSettings, partitionId, queryString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This field is not persisted, so it will only be populated for new indexes
|
||||
*/
|
||||
@Override
|
||||
public void setSearchParameterId(IIdType theSearchParameterId) {
|
||||
mySearchParameterId = theSearchParameterId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This field is not persisted, so it will only be populated for new indexes
|
||||
*/
|
||||
@Override
|
||||
public IIdType getSearchParameterId() {
|
||||
return mySearchParameterId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.searchparam.extractor;
|
|||
import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
|
||||
import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
|
||||
import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
|
||||
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
|
@ -32,6 +33,8 @@ import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
|||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParamQuantity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
|
@ -40,8 +43,11 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantityNormalized
|
|||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.util.JpaParamUtil;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.model.primitive.BoundCodeDt;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
|
@ -50,6 +56,7 @@ import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
|||
import ca.uhn.fhir.util.FhirTerser;
|
||||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import ca.uhn.fhir.util.StringUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
@ -69,6 +76,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.context.ApplicationContext;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.measure.quantity.Quantity;
|
||||
import javax.measure.unit.NonSI;
|
||||
|
@ -386,6 +394,176 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchParamSet<ResourceIndexedComboStringUnique> extractSearchParamComboUnique(String theResourceType, ResourceIndexedSearchParams theParams){
|
||||
SearchParamSet<ResourceIndexedComboStringUnique> retVal = new SearchParamSet<>();
|
||||
List<RuntimeSearchParam> runtimeComboUniqueParams = mySearchParamRegistry.getActiveComboSearchParams(theResourceType, ComboSearchParamType.UNIQUE);
|
||||
|
||||
for (RuntimeSearchParam runtimeParam : runtimeComboUniqueParams) {
|
||||
Set<ResourceIndexedComboStringUnique> comboUniqueParams = createComboUniqueParam(theResourceType, theParams, runtimeParam);
|
||||
retVal.addAll(comboUniqueParams);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private SearchParamSet<ResourceIndexedComboStringUnique> createComboUniqueParam(String theResourceType, ResourceIndexedSearchParams theParams, RuntimeSearchParam theRuntimeParam) {
|
||||
SearchParamSet<ResourceIndexedComboStringUnique> retVal = new SearchParamSet<>();
|
||||
Set<String> queryStringsToPopulate = extractParameterCombinationsForComboParam(theParams, theResourceType, theRuntimeParam);
|
||||
|
||||
for (String nextQueryString : queryStringsToPopulate) {
|
||||
ourLog.trace("Adding composite unique SP: {}", nextQueryString);
|
||||
ResourceIndexedComboStringUnique uniqueParam = new ResourceIndexedComboStringUnique();
|
||||
uniqueParam.setIndexString(nextQueryString);
|
||||
uniqueParam.setSearchParameterId(theRuntimeParam.getId());
|
||||
retVal.add(uniqueParam);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchParamSet<ResourceIndexedComboTokenNonUnique> extractSearchParamComboNonUnique(String theResourceType, ResourceIndexedSearchParams theParams){
|
||||
SearchParamSet<ResourceIndexedComboTokenNonUnique> retVal = new SearchParamSet<>();
|
||||
List<RuntimeSearchParam> runtimeComboNonUniqueParams = mySearchParamRegistry.getActiveComboSearchParams(theResourceType, ComboSearchParamType.NON_UNIQUE);
|
||||
|
||||
for (RuntimeSearchParam runtimeParam : runtimeComboNonUniqueParams) {
|
||||
Set<ResourceIndexedComboTokenNonUnique> comboNonUniqueParams = createComboNonUniqueParam(theResourceType, theParams, runtimeParam);
|
||||
retVal.addAll(comboNonUniqueParams);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private SearchParamSet<ResourceIndexedComboTokenNonUnique> createComboNonUniqueParam(String theResourceType, ResourceIndexedSearchParams theParams, RuntimeSearchParam theRuntimeParam) {
|
||||
SearchParamSet<ResourceIndexedComboTokenNonUnique> retVal = new SearchParamSet<>();
|
||||
Set<String> queryStringsToPopulate = extractParameterCombinationsForComboParam(theParams, theResourceType, theRuntimeParam);
|
||||
|
||||
for (String nextQueryString : queryStringsToPopulate) {
|
||||
ourLog.trace("Adding composite unique SP: {}", nextQueryString);
|
||||
ResourceIndexedComboTokenNonUnique nonUniqueParam = new ResourceIndexedComboTokenNonUnique();
|
||||
nonUniqueParam.setPartitionSettings(myPartitionSettings);
|
||||
nonUniqueParam.setIndexString(nextQueryString);
|
||||
nonUniqueParam.setSearchParameterId(theRuntimeParam.getId());
|
||||
retVal.add(nonUniqueParam);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
private Set<String> extractParameterCombinationsForComboParam(ResourceIndexedSearchParams theParams, String theResourceType, RuntimeSearchParam theParam) {
|
||||
List<List<String>> partsChoices = new ArrayList<>();
|
||||
|
||||
List<RuntimeSearchParam> compositeComponents = JpaParamUtil.resolveComponentParameters(mySearchParamRegistry, theParam);
|
||||
for (RuntimeSearchParam nextCompositeOf : compositeComponents) {
|
||||
Collection<? extends BaseResourceIndexedSearchParam> paramsListForCompositePart = findParameterIndexes(theParams, nextCompositeOf);
|
||||
|
||||
Collection<ResourceLink> linksForCompositePart = null;
|
||||
switch (nextCompositeOf.getParamType()) {
|
||||
case REFERENCE:
|
||||
linksForCompositePart = theParams.myLinks;
|
||||
break;
|
||||
case NUMBER:
|
||||
case DATE:
|
||||
case STRING:
|
||||
case TOKEN:
|
||||
case QUANTITY:
|
||||
case URI:
|
||||
case SPECIAL:
|
||||
case COMPOSITE:
|
||||
case HAS:
|
||||
break;
|
||||
}
|
||||
|
||||
Collection<String> linksForCompositePartWantPaths = null;
|
||||
switch (nextCompositeOf.getParamType()) {
|
||||
case REFERENCE:
|
||||
linksForCompositePartWantPaths = new HashSet<>(nextCompositeOf.getPathsSplit());
|
||||
break;
|
||||
case NUMBER:
|
||||
case DATE:
|
||||
case STRING:
|
||||
case TOKEN:
|
||||
case QUANTITY:
|
||||
case URI:
|
||||
case SPECIAL:
|
||||
case COMPOSITE:
|
||||
case HAS:
|
||||
break;
|
||||
}
|
||||
|
||||
ArrayList<String> nextChoicesList = new ArrayList<>();
|
||||
partsChoices.add(nextChoicesList);
|
||||
|
||||
String key = UrlUtil.escapeUrlParam(nextCompositeOf.getName());
|
||||
if (paramsListForCompositePart != null) {
|
||||
for (BaseResourceIndexedSearchParam nextParam : paramsListForCompositePart) {
|
||||
IQueryParameterType nextParamAsClientParam = nextParam.toQueryParameterType();
|
||||
String value = nextParamAsClientParam.getValueAsQueryToken(myContext);
|
||||
|
||||
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(theResourceType, key);
|
||||
if (theParam.getComboSearchParamType() == ComboSearchParamType.NON_UNIQUE && param != null && param.getParamType() == RestSearchParameterTypeEnum.STRING) {
|
||||
value = StringUtil.normalizeStringForSearchIndexing(value);
|
||||
}
|
||||
|
||||
if (isNotBlank(value)) {
|
||||
value = UrlUtil.escapeUrlParam(value);
|
||||
nextChoicesList.add(key + "=" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (linksForCompositePart != null) {
|
||||
for (ResourceLink nextLink : linksForCompositePart) {
|
||||
if (linksForCompositePartWantPaths.contains(nextLink.getSourcePath())) {
|
||||
assert isNotBlank(nextLink.getTargetResourceType());
|
||||
assert isNotBlank(nextLink.getTargetResourceId());
|
||||
String value = nextLink.getTargetResourceType() + "/" + nextLink.getTargetResourceId();
|
||||
if (isNotBlank(value)) {
|
||||
value = UrlUtil.escapeUrlParam(value);
|
||||
nextChoicesList.add(key + "=" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ResourceIndexedSearchParams.extractCompositeStringUniquesValueChains(theResourceType, partsChoices);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Collection<? extends BaseResourceIndexedSearchParam> findParameterIndexes(ResourceIndexedSearchParams theParams, RuntimeSearchParam nextCompositeOf) {
|
||||
Collection<? extends BaseResourceIndexedSearchParam> paramsListForCompositePart = null;
|
||||
switch (nextCompositeOf.getParamType()) {
|
||||
case NUMBER:
|
||||
paramsListForCompositePart = theParams.myNumberParams;
|
||||
break;
|
||||
case DATE:
|
||||
paramsListForCompositePart = theParams.myDateParams;
|
||||
break;
|
||||
case STRING:
|
||||
paramsListForCompositePart = theParams.myStringParams;
|
||||
break;
|
||||
case TOKEN:
|
||||
paramsListForCompositePart = theParams.myTokenParams;
|
||||
break;
|
||||
case QUANTITY:
|
||||
paramsListForCompositePart = theParams.myQuantityParams;
|
||||
break;
|
||||
case URI:
|
||||
paramsListForCompositePart = theParams.myUriParams;
|
||||
break;
|
||||
case REFERENCE:
|
||||
case SPECIAL:
|
||||
case COMPOSITE:
|
||||
case HAS:
|
||||
break;
|
||||
}
|
||||
if (paramsListForCompositePart != null) {
|
||||
paramsListForCompositePart = paramsListForCompositePart
|
||||
.stream()
|
||||
.filter(t -> t.getParamName().equals(nextCompositeOf.getName()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
return paramsListForCompositePart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchParamSet<BaseResourceIndexedSearchParam> extractSearchParamTokens(IBaseResource theResource) {
|
||||
IExtractor<BaseResourceIndexedSearchParam> extractor = createTokenExtractor(theResource);
|
||||
|
|
|
@ -23,6 +23,8 @@ package ca.uhn.fhir.jpa.searchparam.extractor;
|
|||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity;
|
||||
|
@ -38,6 +40,7 @@ import java.util.Collections;
|
|||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public interface ISearchParamExtractor {
|
||||
|
||||
|
@ -61,6 +64,10 @@ public interface ISearchParamExtractor {
|
|||
|
||||
SearchParamSet<BaseResourceIndexedSearchParam> extractSearchParamSpecial(IBaseResource theResource);
|
||||
|
||||
SearchParamSet<ResourceIndexedComboStringUnique> extractSearchParamComboUnique(String theResourceType, ResourceIndexedSearchParams theParams);
|
||||
|
||||
SearchParamSet<ResourceIndexedComboTokenNonUnique> extractSearchParamComboNonUnique(String theResourceType, ResourceIndexedSearchParams theParams);
|
||||
|
||||
SearchParamSet<ResourceIndexedSearchParamUri> extractSearchParamUri(IBaseResource theResource);
|
||||
|
||||
SearchParamSet<PathAndRef> extractResourceLinks(IBaseResource theResource, boolean theWantLocalReferences);
|
||||
|
|
|
@ -31,10 +31,14 @@ import ca.uhn.fhir.interceptor.api.Pointcut;
|
|||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
|
||||
import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
|
||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.IResourceIndexComboSearchParameter;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||
|
@ -67,6 +71,7 @@ import java.util.Collection;
|
|||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
@ -587,6 +592,17 @@ public class SearchParamExtractorService {
|
|||
}
|
||||
}
|
||||
|
||||
private void populateResourceTableForComboParams(Collection<? extends IResourceIndexComboSearchParameter> theParams, ResourceTable theResourceTable) {
|
||||
for (IResourceIndexComboSearchParameter next : theParams) {
|
||||
if (next.getResource() == null) {
|
||||
next.setResource(theResourceTable);
|
||||
if (next instanceof BasePartitionable){
|
||||
((BasePartitionable)next).setPartitionId(theResourceTable.getPartitionId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamDate> extractSearchParamDates(IBaseResource theResource) {
|
||||
return mySearchParamExtractor.extractSearchParamDates(theResource);
|
||||
}
|
||||
|
@ -634,6 +650,20 @@ public class SearchParamExtractorService {
|
|||
return mySearchParamExtractor.extractParamValuesAsStrings(theActiveSearchParam, theResource);
|
||||
}
|
||||
|
||||
public void extractSearchParamComboUnique(ResourceTable theEntity, ResourceIndexedSearchParams theParams) {
|
||||
String resourceType = theEntity.getResourceType();
|
||||
Set<ResourceIndexedComboStringUnique> comboUniques = mySearchParamExtractor.extractSearchParamComboUnique(resourceType, theParams);
|
||||
theParams.myComboStringUniques.addAll(comboUniques);
|
||||
populateResourceTableForComboParams(theParams.myComboStringUniques, theEntity);
|
||||
}
|
||||
|
||||
public void extractSearchParamComboNonUnique(ResourceTable theEntity, ResourceIndexedSearchParams theParams) {
|
||||
String resourceType = theEntity.getResourceType();
|
||||
Set<ResourceIndexedComboTokenNonUnique> comboNonUniques = mySearchParamExtractor.extractSearchParamComboNonUnique(resourceType, theParams);
|
||||
theParams.myComboTokenNonUnique.addAll(comboNonUniques);
|
||||
populateResourceTableForComboParams(theParams.myComboTokenNonUnique, theEntity);
|
||||
}
|
||||
|
||||
static void handleWarnings(RequestDetails theRequestDetails, IInterceptorBroadcaster theInterceptorBroadcaster, ISearchParamExtractor.SearchParamSet<?> theSearchParamSet) {
|
||||
if (theSearchParamSet.getWarnings().isEmpty()) {
|
||||
return;
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.searchparam.registry;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
|
@ -29,6 +30,7 @@ import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
|||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.rest.server.util.ResourceSearchParams;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -39,16 +41,19 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class JpaSearchParamCache {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(JpaSearchParamCache.class);
|
||||
|
||||
private volatile Map<String, List<RuntimeSearchParam>> myActiveComboSearchParams = Collections.emptyMap();
|
||||
private volatile Map<String, Map<Set<String>, List<RuntimeSearchParam>>> myActiveParamNamesToComboSearchParams = Collections.emptyMap();
|
||||
volatile Map<String, List<RuntimeSearchParam>> myActiveComboSearchParams = Collections.emptyMap();
|
||||
volatile Map<String, Map<Set<String>, List<RuntimeSearchParam>>> myActiveParamNamesToComboSearchParams = Collections.emptyMap();
|
||||
|
||||
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
|
||||
List<RuntimeSearchParam> retval = myActiveComboSearchParams.get(theResourceName);
|
||||
|
@ -58,6 +63,20 @@ public class JpaSearchParamCache {
|
|||
return retval;
|
||||
}
|
||||
|
||||
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, ComboSearchParamType theParamType) {
|
||||
return getActiveComboSearchParams(theResourceName)
|
||||
.stream()
|
||||
.filter(param -> Objects.equals(theParamType, param.getComboSearchParamType()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public Optional<RuntimeSearchParam> getActiveComboSearchParamById(String theResourceName, IIdType theId) {
|
||||
return getActiveComboSearchParams(theResourceName)
|
||||
.stream()
|
||||
.filter((param) -> Objects.equals(theId, param.getId()))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
|
||||
Map<Set<String>, List<RuntimeSearchParam>> paramNamesToParams = myActiveParamNamesToComboSearchParams.get(theResourceName);
|
||||
if (paramNamesToParams == null) {
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.searchparam.registry;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
|
@ -57,6 +58,7 @@ import java.util.Collection;
|
|||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
@ -129,6 +131,11 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry, IResourceC
|
|||
return myJpaSearchParamCache.getActiveComboSearchParams(theResourceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, ComboSearchParamType theParamType) {
|
||||
return myJpaSearchParamCache.getActiveComboSearchParams(theResourceName, theParamType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
|
||||
return myJpaSearchParamCache.getActiveComboSearchParams(theResourceName, theParamNames);
|
||||
|
@ -144,6 +151,12 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry, IResourceC
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Optional<RuntimeSearchParam> getActiveComboSearchParamById(String theResourceName, IIdType theId) {
|
||||
return myJpaSearchParamCache.getActiveComboSearchParamById(theResourceName, theId);
|
||||
}
|
||||
|
||||
private void rebuildActiveSearchParams() {
|
||||
ourLog.info("Rebuilding SearchParamRegistry");
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package ca.uhn.fhir.jpa.searchparam.extractor;
|
||||
|
||||
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.cache.ResourceChangeResult;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
|
@ -32,6 +34,7 @@ import org.hl7.fhir.dstu3.model.Location;
|
|||
import org.hl7.fhir.dstu3.model.Observation;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.Questionnaire;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -39,6 +42,7 @@ import javax.annotation.Nullable;
|
|||
import java.text.Normalizer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
@ -305,6 +309,16 @@ public class SearchParamExtractorDstu3Test {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, ComboSearchParamType theParamType) {
|
||||
throw new UnsupportedOperationException(Msg.code(2210));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<RuntimeSearchParam> getActiveComboSearchParamById(String theResourceName, IIdType theId) {
|
||||
throw new UnsupportedOperationException(Msg.code(2212));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestRefresh() {
|
||||
// nothing
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
package ca.uhn.fhir.jpa.searchparam.registry;
|
||||
|
||||
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class JpaSearchParamCacheTest {
|
||||
|
||||
private static final String RESOURCE_TYPE = "Patient";
|
||||
private TestableJpaSearchParamCache myJpaSearchParamCache;
|
||||
|
||||
@BeforeEach
|
||||
public void beforeEach(){
|
||||
myJpaSearchParamCache = new TestableJpaSearchParamCache();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAllActiveComboParams(){
|
||||
RuntimeSearchParam unique1 = createSearchParam(ComboSearchParamType.UNIQUE);
|
||||
RuntimeSearchParam unique2 = createSearchParam(ComboSearchParamType.UNIQUE);
|
||||
RuntimeSearchParam nonUnique1 = createSearchParam(ComboSearchParamType.NON_UNIQUE);
|
||||
RuntimeSearchParam nonUnique2 = createSearchParam(ComboSearchParamType.NON_UNIQUE);
|
||||
setActiveComboSearchParams(RESOURCE_TYPE, List.of(unique1, unique2, nonUnique1, nonUnique2));
|
||||
|
||||
List<RuntimeSearchParam> result = myJpaSearchParamCache.getActiveComboSearchParams(RESOURCE_TYPE);
|
||||
assertEquals(4, result.size());
|
||||
assertTrue(result.containsAll(List.of(unique1, unique2, nonUnique1, nonUnique2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetUniqueActiveComboParams(){
|
||||
RuntimeSearchParam unique1 = createSearchParam(ComboSearchParamType.UNIQUE);
|
||||
RuntimeSearchParam unique2 = createSearchParam(ComboSearchParamType.UNIQUE);
|
||||
RuntimeSearchParam nonUnique = createSearchParam(ComboSearchParamType.NON_UNIQUE);
|
||||
setActiveComboSearchParams(RESOURCE_TYPE, List.of(unique1, unique2, nonUnique));
|
||||
|
||||
List<RuntimeSearchParam> result = myJpaSearchParamCache.getActiveComboSearchParams(RESOURCE_TYPE, ComboSearchParamType.UNIQUE);
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.containsAll(List.of(unique1, unique2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNonUniqueActiveComboParams(){
|
||||
RuntimeSearchParam nonUnique1 = createSearchParam(ComboSearchParamType.NON_UNIQUE);
|
||||
RuntimeSearchParam nonUnique2 = createSearchParam(ComboSearchParamType.NON_UNIQUE);
|
||||
RuntimeSearchParam unique = createSearchParam(ComboSearchParamType.UNIQUE);
|
||||
setActiveComboSearchParams(RESOURCE_TYPE, List.of(nonUnique1, nonUnique2, unique));
|
||||
|
||||
List<RuntimeSearchParam> result = myJpaSearchParamCache.getActiveComboSearchParams(RESOURCE_TYPE, ComboSearchParamType.NON_UNIQUE);
|
||||
assertEquals(2, result.size());
|
||||
assertTrue(result.containsAll(List.of(nonUnique1, nonUnique2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetActiveComboParamByIdPresent(){
|
||||
IIdType id1 = new IdType(1);
|
||||
RuntimeSearchParam sp1 = createSearchParam(id1, ComboSearchParamType.NON_UNIQUE);
|
||||
|
||||
IIdType id2 = new IdType(2);
|
||||
RuntimeSearchParam sp2 = createSearchParam(id2, ComboSearchParamType.NON_UNIQUE);
|
||||
|
||||
setActiveComboSearchParams(RESOURCE_TYPE, List.of(sp1, sp2));
|
||||
|
||||
Optional<RuntimeSearchParam> found = myJpaSearchParamCache.getActiveComboSearchParamById(RESOURCE_TYPE, id1);
|
||||
assertTrue(found.isPresent());
|
||||
assertEquals(id1, found.get().getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetActiveComboParamByIdAbsent(){
|
||||
IIdType id1 = new IdType(1);
|
||||
RuntimeSearchParam sp1 = createSearchParam(id1, ComboSearchParamType.NON_UNIQUE);
|
||||
|
||||
IIdType id2 = new IdType(2);
|
||||
|
||||
setActiveComboSearchParams(RESOURCE_TYPE, List.of(sp1));
|
||||
|
||||
Optional<RuntimeSearchParam> found = myJpaSearchParamCache.getActiveComboSearchParamById(RESOURCE_TYPE, id2);
|
||||
assertTrue(found.isEmpty());
|
||||
}
|
||||
|
||||
private RuntimeSearchParam createSearchParam(ComboSearchParamType theType){
|
||||
return createSearchParam(null, theType);
|
||||
}
|
||||
|
||||
private RuntimeSearchParam createSearchParam(IIdType theId, ComboSearchParamType theType){
|
||||
RuntimeSearchParam sp = mock(RuntimeSearchParam.class);
|
||||
when(sp.getId()).thenReturn(theId);
|
||||
when(sp.getComboSearchParamType()).thenReturn(theType);
|
||||
return sp;
|
||||
}
|
||||
|
||||
private void setActiveComboSearchParams(String theResourceType, List<RuntimeSearchParam> theRuntimeSearchParams) {
|
||||
Map<String, List<RuntimeSearchParam>> activeComboParams = new HashMap<>();
|
||||
activeComboParams.put(theResourceType, theRuntimeSearchParams);
|
||||
myJpaSearchParamCache.setActiveComboSearchParams(activeComboParams);
|
||||
}
|
||||
|
||||
private class TestableJpaSearchParamCache extends JpaSearchParamCache {
|
||||
public void setActiveComboSearchParams(Map<String, List<RuntimeSearchParam>> theActiveComboSearchParams){
|
||||
myActiveComboSearchParams = theActiveComboSearchParams;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,9 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
|||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.validation.SearchParameterDaoValidator;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||
import ca.uhn.hapi.converters.canonical.VersionCanonicalizer;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.SearchParameter;
|
||||
|
@ -30,6 +32,8 @@ public class JpaResourceDaoSearchParameterTest {
|
|||
private JpaResourceDaoSearchParameter<SearchParameter> myDao;
|
||||
@Mock
|
||||
private ApplicationContext myApplicationContext;
|
||||
@Mock
|
||||
private ISearchParamRegistry mySearchParamRegistry;
|
||||
|
||||
@BeforeEach
|
||||
public void before() {
|
||||
|
@ -39,10 +43,13 @@ public class JpaResourceDaoSearchParameterTest {
|
|||
|
||||
myDao = new JpaResourceDaoSearchParameter<>();
|
||||
myDao.setContext(myCtx);
|
||||
DaoConfig defaultConfig = new DaoConfig();
|
||||
myDao.setDaoConfigForUnitTest(defaultConfig);
|
||||
myDao.setResourceType(SearchParameter.class);
|
||||
myDao.setDaoConfigForUnitTest(new DaoConfig());
|
||||
myDao.setApplicationContext(myApplicationContext);
|
||||
myDao.setVersionCanonicalizerForUnitTest(versionCanonicalizer);
|
||||
SearchParameterDaoValidator validator = new SearchParameterDaoValidator(myCtx, defaultConfig, mySearchParamRegistry);
|
||||
myDao.setSearchParameterDaoValidatorForUnitTest(validator);
|
||||
myDao.start();
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -20,17 +20,20 @@ package ca.uhn.fhir.rest.server.util;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
public class FhirContextSearchParamRegistry implements ISearchParamRegistry {
|
||||
|
@ -97,6 +100,16 @@ public class FhirContextSearchParamRegistry implements ISearchParamRegistry {
|
|||
throw new UnsupportedOperationException(Msg.code(2068));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, ComboSearchParamType theParamType) {
|
||||
throw new UnsupportedOperationException(Msg.code(2209));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<RuntimeSearchParam> getActiveComboSearchParamById(String theResourceName, IIdType theId) {
|
||||
throw new UnsupportedOperationException(Msg.code(2211));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestRefresh() {
|
||||
// nothing
|
||||
|
|
|
@ -20,17 +20,20 @@ package ca.uhn.fhir.rest.server.util;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
|
@ -73,6 +76,17 @@ public interface ISearchParamRegistry {
|
|||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
// TODO ND remove default implementation
|
||||
default List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, ComboSearchParamType theParamType) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// TODO ND remove default implementation
|
||||
default Optional<RuntimeSearchParam> getActiveComboSearchParamById(String theResourceName, IIdType theId) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
default List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
|||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-caching-api</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-okhttp</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-server-jersey</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
package ca.uhn.fhir.jpa.dao.validation;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r5.model.Enumerations;
|
||||
import org.hl7.fhir.r5.model.SearchParameter;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
public class SearchParameterDaoValidator {
|
||||
|
||||
private static final Pattern REGEX_SP_EXPRESSION_HAS_PATH = Pattern.compile("[( ]*([A-Z][a-zA-Z]+\\.)?[a-z].*");
|
||||
|
||||
private final FhirContext myFhirContext;
|
||||
private final DaoConfig myDaoConfig;
|
||||
private final ISearchParamRegistry mySearchParamRegistry;
|
||||
|
||||
public SearchParameterDaoValidator(FhirContext theContext, DaoConfig theDaoConfig, ISearchParamRegistry theSearchParamRegistry) {
|
||||
myFhirContext = theContext;
|
||||
myDaoConfig = theDaoConfig;
|
||||
mySearchParamRegistry = theSearchParamRegistry;
|
||||
}
|
||||
|
||||
public void validate(SearchParameter searchParameter) {
|
||||
/*
|
||||
* If overriding built-in SPs is disabled on this server, make sure we aren't
|
||||
* doing that
|
||||
*/
|
||||
if (myDaoConfig.getModelConfig().isDefaultSearchParamsCanBeOverridden() == false) {
|
||||
for (IPrimitiveType<?> nextBaseType : searchParameter.getBase()) {
|
||||
String nextBase = nextBaseType.getValueAsString();
|
||||
RuntimeSearchParam existingSearchParam = mySearchParamRegistry.getActiveSearchParam(nextBase, searchParameter.getCode());
|
||||
if (existingSearchParam != null) {
|
||||
boolean isBuiltIn = existingSearchParam.getId() == null;
|
||||
isBuiltIn |= existingSearchParam.getUri().startsWith("http://hl7.org/fhir/SearchParameter/");
|
||||
if (isBuiltIn) {
|
||||
throw new UnprocessableEntityException(Msg.code(1111) + "Can not override built-in search parameter " + nextBase + ":" + searchParameter.getCode() + " because overriding is disabled on this server");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Everything below is validating that the SP is actually valid. We'll only do that if the
|
||||
* SPO is active, so that we don't block people from uploading works-in-progress
|
||||
*/
|
||||
if (searchParameter.getStatus() == null) {
|
||||
throw new UnprocessableEntityException(Msg.code(1112) + "SearchParameter.status is missing or invalid");
|
||||
}
|
||||
if (!searchParameter.getStatus().name().equals("ACTIVE")) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCompositeWithoutBase(searchParameter)) {
|
||||
throw new UnprocessableEntityException(Msg.code(1113) + "SearchParameter.base is missing");
|
||||
}
|
||||
|
||||
boolean isUnique = hasAnyExtensionUniqueSetTo(searchParameter, true);
|
||||
|
||||
if (isCompositeWithoutExpression(searchParameter)) {
|
||||
|
||||
// this is ok
|
||||
|
||||
} else if (isBlank(searchParameter.getExpression())) {
|
||||
|
||||
throw new UnprocessableEntityException(Msg.code(1114) + "SearchParameter.expression is missing");
|
||||
|
||||
} else {
|
||||
|
||||
if (isUnique) {
|
||||
if (searchParameter.getComponent().size() == 0) {
|
||||
throw new UnprocessableEntityException(Msg.code(1115) + "SearchParameter is marked as unique but has no components");
|
||||
}
|
||||
for (SearchParameter.SearchParameterComponentComponent next : searchParameter.getComponent()) {
|
||||
if (isBlank(next.getDefinition())) {
|
||||
throw new UnprocessableEntityException(Msg.code(1116) + "SearchParameter is marked as unique but is missing component.definition");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FhirVersionEnum fhirVersion = myFhirContext.getVersion().getVersion();
|
||||
if (fhirVersion.isOlderThan(FhirVersionEnum.DSTU3)) {
|
||||
// omitting validation for DSTU2_HL7ORG, DSTU2_1 and DSTU2
|
||||
} else {
|
||||
|
||||
if (myDaoConfig.isValidateSearchParameterExpressionsOnSave()) {
|
||||
|
||||
validateExpressionPath(searchParameter);
|
||||
|
||||
String expression = getExpression(searchParameter);
|
||||
|
||||
try {
|
||||
myFhirContext.newFhirPath().parse(expression);
|
||||
} catch (Exception exception) {
|
||||
throw new UnprocessableEntityException(Msg.code(1121) + "Invalid FHIRPath format for SearchParameter.expression \"" + expression + "\": " + exception.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isCompositeWithoutBase(SearchParameter searchParameter) {
|
||||
return ElementUtil.isEmpty(searchParameter.getBase()) && (searchParameter.getType() == null || !Enumerations.SearchParamType.COMPOSITE.name().equals(searchParameter.getType().name()));
|
||||
}
|
||||
|
||||
private boolean isCompositeWithoutExpression(SearchParameter searchParameter) {
|
||||
return searchParameter.getType() != null && searchParameter.getType().name().equals(Enumerations.SearchParamType.COMPOSITE.name()) && isBlank(searchParameter.getExpression());
|
||||
}
|
||||
|
||||
private void validateExpressionPath(SearchParameter theSearchParameter) {
|
||||
String expression = getExpression(theSearchParameter);
|
||||
|
||||
boolean isResourceOfTypeComposite = theSearchParameter.getType() == Enumerations.SearchParamType.COMPOSITE;
|
||||
boolean isResourceOfTypeSpecial = theSearchParameter.getType() == Enumerations.SearchParamType.SPECIAL;
|
||||
boolean expressionHasPath = REGEX_SP_EXPRESSION_HAS_PATH.matcher(expression).matches();
|
||||
|
||||
boolean isUnique = hasAnyExtensionUniqueSetTo(theSearchParameter, true);
|
||||
|
||||
if (!isUnique && !isResourceOfTypeComposite && !isResourceOfTypeSpecial && !expressionHasPath) {
|
||||
throw new UnprocessableEntityException(Msg.code(1120) + "SearchParameter.expression value \"" + expression + "\" is invalid due to missing/incorrect path");
|
||||
}
|
||||
}
|
||||
|
||||
private String getExpression(SearchParameter theSearchParameter) {
|
||||
return theSearchParameter.getExpression().trim();
|
||||
}
|
||||
|
||||
private boolean hasAnyExtensionUniqueSetTo(SearchParameter theSearchParameter, boolean theValue) {
|
||||
String theValueAsString = Boolean.toString(theValue);
|
||||
|
||||
return theSearchParameter
|
||||
.getExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||
.stream()
|
||||
.anyMatch(t -> theValueAsString.equals(t.getValueAsPrimitive().getValueAsString()));
|
||||
}
|
||||
}
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
4
pom.xml
4
pom.xml
|
@ -6,7 +6,7 @@
|
|||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<name>HAPI-FHIR</name>
|
||||
<description>An open-source implementation of the FHIR specification in Java.</description>
|
||||
<url>https://hapifhir.io</url>
|
||||
|
@ -2110,7 +2110,7 @@
|
|||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-checkstyle</artifactId>
|
||||
<!-- Remember to bump this when you upgrade the version -->
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.3-SNAPSHOT</version>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
Loading…
Reference in New Issue