Compare commits

...

18 Commits

Author SHA1 Message Date
James Agnew 4a6b4fafac
Merge 123867e86e into 3f6d1eb29b 2024-09-26 02:08:10 +00:00
James Agnew 123867e86e Add changelog 2024-08-27 08:51:05 -04:00
James Agnew 2a3dacc1e5 Cleanup 2024-08-27 08:49:16 -04:00
James Agnew b094163e53 Merge branch 'master' into ja_20240604_allow_disable_param 2024-08-27 08:42:37 -04:00
James Agnew 1468bc1b49 CLeanup 2024-07-12 17:26:36 -04:00
James Agnew c948ef4707 Merge branch 'master' into ja_20240604_allow_disable_param 2024-07-12 17:01:59 -04:00
James Agnew bea1fbbb1a Cleanup 2024-07-12 16:57:53 -04:00
James Agnew 4e0ce372f7 Work on disable code 2024-07-05 09:59:33 -04:00
James Agnew 9b730f509f Spotles 2024-07-04 11:02:32 -04:00
James Agnew 96b496e967 Add tests 2024-07-04 10:52:20 -04:00
James Agnew 3ee3932f68 Drop label 2024-07-04 10:48:14 -04:00
James Agnew 9564541e5e Test fix 2024-07-04 10:47:51 -04:00
James Agnew e844819114 Spotless 2024-07-03 17:27:21 -04:00
James Agnew 94ebe4413f Add changelog 2024-07-03 17:08:08 -04:00
James Agnew 8a5e2679d5 Add tests 2024-07-03 16:57:22 -04:00
James Agnew 6ed919de22 Merge branch 'master' into ja_20240628_combo_permutations 2024-07-03 15:53:48 -04:00
James Agnew c2ed5f8419 Work on combo 2024-07-03 13:40:18 -04:00
James Agnew 9143f5995b Combo permutations 2024-06-28 14:43:33 -04:00
70 changed files with 957 additions and 327 deletions

View File

@ -60,6 +60,7 @@ public class RuntimeSearchParam {
private final List<Component> myComponents;
private final IIdType myIdUnqualifiedVersionless;
private IPhoneticEncoder myPhoneticEncoder;
private boolean myEnabledForSearching = true;
/**
* Constructor
@ -166,6 +167,24 @@ public class RuntimeSearchParam {
}
}
/**
* Is this search parameter actually enabled for being used in searches (as opposed to only being used for
* generating indexes, which might be desired while the search parameter is still being indexed). This
* setting defaults to {@literal true} if it isn't set otherwise.
*/
public boolean isEnabledForSearching() {
return myEnabledForSearching;
}
/**
* Is this search parameter actually enabled for being used in searches (as opposed to only being used for
* generating indexes, which might be desired while the search parameter is still being indexed). This
* setting defaults to {@literal true} if it isn't set otherwise.
*/
public void setEnabledForSearching(boolean theEnabledForSearching) {
myEnabledForSearching = theEnabledForSearching;
}
public List<Component> getComponents() {
return myComponents;
}
@ -361,13 +380,6 @@ public class RuntimeSearchParam {
return !myUpliftRefchains.isEmpty();
}
public enum RuntimeSearchParamStatusEnum {
ACTIVE,
DRAFT,
RETIRED,
UNKNOWN
}
/**
* This method tests whether a given FHIRPath expression <i>could</i>
* possibly apply to the given resource type.
@ -413,6 +425,13 @@ public class RuntimeSearchParam {
return false;
}
public enum RuntimeSearchParamStatusEnum {
ACTIVE,
DRAFT,
RETIRED,
UNKNOWN
}
public static class Component {
private final String myExpression;
private final String myReference;

View File

@ -110,6 +110,12 @@ public class HapiExtensions {
public static final String EXT_SP_UNIQUE = "http://hapifhir.io/fhir/StructureDefinition/sp-unique";
/**
* URL for extension on a Search Parameter which determines whether it should be enabled for searching for resources
*/
public static final String EXT_SEARCHPARAM_ENABLED_FOR_SEARCHING =
"http://hapifhir.io/fhir/StructureDefinition/searchparameter-enabled-for-searching";
/**
* URL for extension on a Phonetic String SearchParameter indicating that text values should be phonetically indexed with the named encoder
*/

View File

@ -133,6 +133,7 @@ ca.uhn.fhir.jpa.dao.BaseStorageDao.successfulTimingSuffix=Took {0}ms.
ca.uhn.fhir.jpa.dao.BaseStorageDao.deleteResourceNotExisting=Not deleted, resource {0} does not exist.
ca.uhn.fhir.jpa.dao.BaseStorageDao.deleteResourceAlreadyDeleted=Not deleted, resource {0} was already deleted.
ca.uhn.fhir.jpa.dao.BaseStorageDao.invalidSearchParameter=Unknown search parameter "{0}" for resource type "{1}". Valid search parameters for this search are: {2}
ca.uhn.fhir.jpa.dao.BaseStorageDao.invalidSearchParameterNotEnabledForSearch=Search parameter "{0}" for resource type "{1}" is not active for searching. Valid search parameters for this search are: {2}
ca.uhn.fhir.jpa.dao.BaseStorageDao.invalidSortParameter=Unknown _sort parameter value "{0}" for resource type "{1}" (Note: sort parameters values must use a valid Search Parameter). Valid values for this search are: {2}
ca.uhn.fhir.jpa.dao.BaseStorageDao.invalidSortParameterTooManyChains=Invalid _sort expression, can not chain more than once in a sort expression: {0}

View File

@ -0,0 +1,6 @@
---
type: add
issue: 6107
title: "A new extension has been created for use on SearchParameter resources in the JPA server. This extension causes
a SearchParameter to be indexed, but to not be available for use in searches. This can be set when a new SP is created
in order to prevent it from being used before an index has been completed."

View File

@ -625,7 +625,8 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor<JpaPid> {
resourceToCheck = "Patient";
activeSearchParamName = "organization";
}
return mySearchParamRegistry.getActiveSearchParam(resourceToCheck, activeSearchParamName);
return mySearchParamRegistry.getActiveSearchParam(
resourceToCheck, activeSearchParamName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
}
/**

View File

@ -137,7 +137,8 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
public ExtendedHSearchIndexData extractLuceneIndexData(
IBaseResource theResource, ResourceIndexedSearchParams theNewParams) {
String resourceType = myFhirContext.getResourceType(theResource);
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams(resourceType);
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams(
resourceType, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
ExtendedHSearchIndexExtractor extractor = new ExtendedHSearchIndexExtractor(
myStorageSettings, myFhirContext, activeSearchParams, mySearchParamExtractor);
return extractor.extract(theResource, theNewParams);

View File

@ -92,7 +92,8 @@ public class ExtendedHSearchSearchBuilder {
String theResourceType, SearchParameterMap myParams, ISearchParamRegistry theSearchParamRegistry) {
boolean canUseHibernate = false;
ResourceSearchParams resourceActiveSearchParams = theSearchParamRegistry.getActiveSearchParams(theResourceType);
ResourceSearchParams resourceActiveSearchParams = theSearchParamRegistry.getActiveSearchParams(
theResourceType, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
for (String paramName : myParams.keySet()) {
// is this parameter supported?
if (illegalForHibernateSearch(paramName, resourceActiveSearchParams)) {
@ -218,7 +219,8 @@ public class ExtendedHSearchSearchBuilder {
// copy the keys to avoid concurrent modification error
ArrayList<String> paramNames = compileParamNames(searchParameterMap);
ResourceSearchParams activeSearchParams = searchParamRegistry.getActiveSearchParams(resourceType);
ResourceSearchParams activeSearchParams = searchParamRegistry.getActiveSearchParams(
resourceType, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
for (String nextParam : paramNames) {
if (illegalForHibernateSearch(nextParam, activeSearchParams)) {
// ignore magic params handled in JPA

View File

@ -151,7 +151,8 @@ public class HSearchSortHelperImpl implements IHSearchSortHelper {
*/
@VisibleForTesting
Optional<RestSearchParameterTypeEnum> getParamType(String theResourceTypeName, String theParamName) {
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams(theResourceTypeName);
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams(
theResourceTypeName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
RuntimeSearchParam searchParam = activeSearchParams.get(theParamName);
if (searchParam == null) {
return Optional.empty();

View File

@ -181,7 +181,8 @@ public class GraphQLProviderWithIntrospection extends GraphQLProvider {
for (String nextResourceType : theResourceTypes) {
StructureDefinition sd = fetchStructureDefinition(nextResourceType);
List<SearchParameter> parameters = toR5SearchParams(mySearchParamRegistry
.getActiveSearchParams(nextResourceType)
.getActiveSearchParams(
nextResourceType, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH)
.values());
myGenerator.generateResource(writer, sd, parameters, theOperations);
}
@ -198,7 +199,8 @@ public class GraphQLProviderWithIntrospection extends GraphQLProvider {
}
if (theOperations.contains(GraphQLSchemaGenerator.FHIROperationType.SEARCH)) {
List<SearchParameter> parameters = toR5SearchParams(mySearchParamRegistry
.getActiveSearchParams(nextResourceType)
.getActiveSearchParams(
nextResourceType, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH)
.values());
myGenerator.generateListAccessQuery(writer, parameters, nextResourceType);
myGenerator.generateConnectionAccessQuery(writer, parameters, nextResourceType);

View File

@ -190,11 +190,12 @@ public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.se
* global params like _lastUpdated
*/
ResourceSearchParams searchParams;
ResourceSearchParams serverConfigurationActiveSearchParams =
myServerConfiguration.getActiveSearchParams(theResourceName);
ResourceSearchParams serverConfigurationActiveSearchParams = myServerConfiguration.getActiveSearchParams(
theResourceName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (mySearchParamRegistry != null) {
searchParams =
mySearchParamRegistry.getActiveSearchParams(theResourceName).makeCopy();
searchParams = mySearchParamRegistry
.getActiveSearchParams(theResourceName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH)
.makeCopy();
if (searchParams == null) {
return ResourceSearchParams.empty(theResourceName);
}
@ -229,8 +230,8 @@ public class JpaConformanceProviderDstu3 extends org.hl7.fhir.dstu3.hapi.rest.se
if (isBlank(otherResourceType)) {
continue;
}
ResourceSearchParams activeSearchParams =
mySearchParamRegistry.getActiveSearchParams(otherResourceType);
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams(
otherResourceType, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
activeSearchParams.values().stream()
.filter(t -> isNotBlank(t.getName()))
.filter(t -> t.getTargets().contains(resourcename))

View File

@ -489,8 +489,13 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
}
if (!Constants.INCLUDE_STAR.equals(paramName)
&& mySearchParamRegistry.getActiveSearchParam(paramType, paramName) == null) {
List<String> validNames = mySearchParamRegistry.getActiveSearchParams(paramType).values().stream()
&& mySearchParamRegistry.getActiveSearchParam(
paramType, paramName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH)
== null) {
List<String> validNames = mySearchParamRegistry
.getActiveSearchParams(paramType, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH)
.values()
.stream()
.filter(t -> t.getParamType() == RestSearchParameterTypeEnum.REFERENCE)
.map(t -> UrlUtil.sanitizeUrlPart(t.getName()))
.sorted()

View File

@ -315,7 +315,8 @@ public class QueryStack {
}
String targetType = null;
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(theResourceName, theParamName);
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(
theResourceName, theParamName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (theReferenceTargetType != null) {
targetType = theReferenceTargetType;
} else if (param.getTargets().size() > 1) {
@ -331,10 +332,13 @@ public class QueryStack {
+ "' as this parameter as this parameter does not define a target type. Please specify the target type.");
}
RuntimeSearchParam targetSearchParameter = mySearchParamRegistry.getActiveSearchParam(targetType, theChain);
RuntimeSearchParam targetSearchParameter = mySearchParamRegistry.getActiveSearchParam(
targetType, theChain, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (targetSearchParameter == null) {
Collection<String> validSearchParameterNames =
mySearchParamRegistry.getActiveSearchParams(targetType).values().stream()
Collection<String> validSearchParameterNames = mySearchParamRegistry
.getActiveSearchParams(targetType, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH)
.values()
.stream()
.filter(t -> t.getParamType() == RestSearchParameterTypeEnum.STRING
|| t.getParamType() == RestSearchParameterTypeEnum.TOKEN
|| t.getParamType() == RestSearchParameterTypeEnum.DATE)
@ -418,6 +422,7 @@ public class QueryStack {
return;
}
}
//noinspection fallthrough
case NUMBER:
case REFERENCE:
case COMPOSITE:
@ -1003,10 +1008,11 @@ public class QueryStack {
return createPredicateSource(null, Collections.singletonList(param));
}
default:
RuntimeSearchParam searchParam = mySearchParamRegistry.getActiveSearchParam(theResourceName, paramName);
RuntimeSearchParam searchParam = mySearchParamRegistry.getActiveSearchParam(
theResourceName, paramName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (searchParam == null) {
Collection<String> validNames =
mySearchParamRegistry.getValidSearchParameterNamesIncludingMeta(theResourceName);
Collection<String> validNames = mySearchParamRegistry.getValidSearchParameterNamesIncludingMeta(
theResourceName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
String msg = myFhirContext
.getLocalizer()
.getMessageSanitized(
@ -1164,13 +1170,14 @@ public class QueryStack {
// Ensure that the name of the search param
// (e.g. the `code` in Patient?_has:Observation:subject:code=sys|val)
// exists on the target resource type.
RuntimeSearchParam owningParameterDef =
mySearchParamRegistry.getRuntimeSearchParam(targetResourceType, paramName);
RuntimeSearchParam owningParameterDef = mySearchParamRegistry.getRuntimeSearchParam(
targetResourceType, paramName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
// Ensure that the name of the back-referenced search param on the target (e.g. the `subject` in
// Patient?_has:Observation:subject:code=sys|val)
// exists on the target resource, or in the top-level Resource resource.
mySearchParamRegistry.getRuntimeSearchParam(targetResourceType, paramReference);
mySearchParamRegistry.getRuntimeSearchParam(
targetResourceType, paramReference, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
IQueryParameterAnd<?> parsedParam = JpaParamUtil.parseQueryParams(
mySearchParamRegistry, myFhirContext, owningParameterDef, paramName, parameters);
@ -1360,7 +1367,7 @@ public class QueryStack {
theRequestPartitionId));
} else {
List<QuantityParam> quantityParams =
theList.stream().map(t -> QuantityParam.toQuantityParam(t)).collect(Collectors.toList());
theList.stream().map(QuantityParam::toQuantityParam).collect(Collectors.toList());
BaseQuantityPredicateBuilder join = null;
boolean normalizedSearchEnabled = myStorageSettings
@ -1368,8 +1375,8 @@ public class QueryStack {
.equals(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_SUPPORTED);
if (normalizedSearchEnabled) {
List<QuantityParam> normalizedQuantityParams = quantityParams.stream()
.map(t -> UcumServiceUtil.toCanonicalQuantityOrNull(t))
.filter(t -> t != null)
.map(UcumServiceUtil::toCanonicalQuantityOrNull)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (normalizedQuantityParams.size() == quantityParams.size()) {
@ -2455,7 +2462,8 @@ public class QueryStack {
RequestDetails theRequest,
RequestPartitionId theRequestPartitionId) {
List<Condition> andPredicates = new ArrayList<>();
RuntimeSearchParam nextParamDef = mySearchParamRegistry.getActiveSearchParam(theResourceName, theParamName);
RuntimeSearchParam nextParamDef = mySearchParamRegistry.getActiveSearchParam(
theResourceName, theParamName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (nextParamDef != null) {
if (myPartitionSettings.isPartitioningEnabled() && myPartitionSettings.isIncludePartitionInSearchHashes()) {
@ -2662,6 +2670,9 @@ public class QueryStack {
}
} else {
RuntimeSearchParam notEnabledForSearchParam =
mySearchParamRegistry.getActiveSearchParam(theResourceName, theParamName, null);
if (notEnabledForSearchParam == null) {
String msg = myFhirContext
.getLocalizer()
.getMessageSanitized(
@ -2669,8 +2680,23 @@ public class QueryStack {
"invalidSearchParameter",
theParamName,
theResourceName,
mySearchParamRegistry.getValidSearchParameterNamesIncludingMeta(theResourceName));
mySearchParamRegistry.getValidSearchParameterNamesIncludingMeta(
theResourceName,
ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH));
throw new InvalidRequestException(Msg.code(1223) + msg);
} else {
String msg = myFhirContext
.getLocalizer()
.getMessageSanitized(
BaseStorageDao.class,
"invalidSearchParameterNotEnabledForSearch",
theParamName,
theResourceName,
mySearchParamRegistry.getValidSearchParameterNamesIncludingMeta(
theResourceName,
ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH));
throw new InvalidRequestException(Msg.code(2540) + msg);
}
}
}
}
@ -2701,8 +2727,8 @@ public class QueryStack {
ReferenceParam param = (ReferenceParam) nextAnd.get(0);
if (isNotBlank(param.getChain())) {
String fullName = theParamName + "." + param.getChain();
RuntimeSearchParam fullChainParam =
mySearchParamRegistry.getActiveSearchParam(theResourceName, fullName);
RuntimeSearchParam fullChainParam = mySearchParamRegistry.getActiveSearchParam(
theResourceName, fullName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (fullChainParam != null) {
List<IQueryParameterType> swappedParamTypes = nextAnd.stream()
.map(t -> newParameterInstance(fullChainParam, null, t.getValueAsQueryToken(myFhirContext)))
@ -2769,8 +2795,10 @@ public class QueryStack {
if (indexOnContainedResources) {
return true;
}
RuntimeSearchParam param =
mySearchParamRegistry.getActiveSearchParam(theResourceType, theParameterName);
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(
theResourceType,
theParameterName,
ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
return param != null && param.hasUpliftRefchain(t);
});
@ -3010,7 +3038,8 @@ public class QueryStack {
for (String nextTarget : thePreviousSearchParam.getTargets()) {
RuntimeSearchParam nextSearchParam = null;
if (isBlank(theResourceType) || theResourceType.equals(nextTarget)) {
nextSearchParam = mySearchParamRegistry.getActiveSearchParam(nextTarget, nextParamName);
nextSearchParam = mySearchParamRegistry.getActiveSearchParam(
nextTarget, nextParamName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
}
if (nextSearchParam != null) {
searchParamFound = true;

View File

@ -651,8 +651,8 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|| theParams.getSort() != null
|| theParams.keySet().contains(Constants.PARAM_HAS)
|| isPotentiallyContainedReferenceParameterExistsAtRoot(theParams)) {
List<RuntimeSearchParam> activeComboParams =
mySearchParamRegistry.getActiveComboSearchParams(myResourceName, theParams.keySet());
List<RuntimeSearchParam> activeComboParams = mySearchParamRegistry.getActiveComboSearchParams(
myResourceName, theParams.keySet(), ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (activeComboParams.isEmpty()) {
sqlBuilder.setNeedResourceTableRoot(true);
}
@ -915,8 +915,8 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
theQueryStack.addSortOnLastUpdated(ascending);
} else {
RuntimeSearchParam param =
mySearchParamRegistry.getActiveSearchParam(myResourceName, theSort.getParamName());
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(
myResourceName, theSort.getParamName(), ISearchParamRegistry.SearchParamLookupContextEnum.SORT);
/*
* If we have a sort like _sort=subject.name and we have an
@ -940,8 +940,8 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
referenceParamTargetType = referenceParam.substring(0, colonIdx);
referenceParam = referenceParam.substring(colonIdx + 1);
}
RuntimeSearchParam outerParam =
mySearchParamRegistry.getActiveSearchParam(myResourceName, referenceParam);
RuntimeSearchParam outerParam = mySearchParamRegistry.getActiveSearchParam(
myResourceName, referenceParam, ISearchParamRegistry.SearchParamLookupContextEnum.SORT);
if (outerParam == null) {
throwInvalidRequestExceptionForUnknownSortParameter(myResourceName, referenceParam);
} else if (outerParam.hasUpliftRefchain(targetParam)) {
@ -949,8 +949,10 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
if (referenceParamTargetType != null && !referenceParamTargetType.equals(nextTargetType)) {
continue;
}
RuntimeSearchParam innerParam =
mySearchParamRegistry.getActiveSearchParam(nextTargetType, targetParam);
RuntimeSearchParam innerParam = mySearchParamRegistry.getActiveSearchParam(
nextTargetType,
targetParam,
ISearchParamRegistry.SearchParamLookupContextEnum.SORT);
if (innerParam != null) {
param = innerParam;
break;
@ -984,7 +986,8 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
}
if (param == null) {
param = mySearchParamRegistry.getActiveSearchParam(myResourceName, paramName);
param = mySearchParamRegistry.getActiveSearchParam(
myResourceName, paramName, ISearchParamRegistry.SearchParamLookupContextEnum.SORT);
}
if (param == null) {
@ -1063,8 +1066,8 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
}
private void throwInvalidRequestExceptionForUnknownSortParameter(String theResourceName, String theParamName) {
Collection<String> validSearchParameterNames =
mySearchParamRegistry.getValidSearchParameterNamesIncludingMeta(theResourceName);
Collection<String> validSearchParameterNames = mySearchParamRegistry.getValidSearchParameterNamesIncludingMeta(
theResourceName, ISearchParamRegistry.SearchParamLookupContextEnum.SORT);
String msg = myContext
.getLocalizer()
.getMessageSanitized(
@ -1527,7 +1530,8 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
String paramName = nextInclude.getParamName();
if (isNotBlank(paramName)) {
param = mySearchParamRegistry.getActiveSearchParam(resType, paramName);
param = mySearchParamRegistry.getActiveSearchParam(
resType, paramName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
} else {
param = null;
}
@ -1845,7 +1849,10 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
// in this context, so let's just assume it could be anything.
targetResourceTypes = possibleTypes;
} else {
for (var next : mySearchParamRegistry.getActiveSearchParams(myResourceName).values().stream()
for (var next : mySearchParamRegistry
.getActiveSearchParams(myResourceName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH)
.values()
.stream()
.filter(t -> t.getParamType().equals(RestSearchParameterTypeEnum.REFERENCE))
.collect(Collectors.toList())) {
@ -1928,16 +1935,16 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
QueryStack theQueryStack, @Nonnull SearchParameterMap theParams, RequestDetails theRequest) {
RuntimeSearchParam comboParam = null;
List<String> comboParamNames = null;
List<RuntimeSearchParam> exactMatchParams =
mySearchParamRegistry.getActiveComboSearchParams(myResourceName, theParams.keySet());
List<RuntimeSearchParam> exactMatchParams = mySearchParamRegistry.getActiveComboSearchParams(
myResourceName, theParams.keySet(), ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (!exactMatchParams.isEmpty()) {
comboParam = exactMatchParams.get(0);
comboParamNames = new ArrayList<>(theParams.keySet());
}
if (comboParam == null) {
List<RuntimeSearchParam> candidateComboParams =
mySearchParamRegistry.getActiveComboSearchParams(myResourceName);
List<RuntimeSearchParam> candidateComboParams = mySearchParamRegistry.getActiveComboSearchParams(
myResourceName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
for (RuntimeSearchParam nextCandidate : candidateComboParams) {
List<String> nextCandidateParamNames =
JpaParamUtil.resolveComponentParameters(mySearchParamRegistry, nextCandidate).stream()
@ -2006,8 +2013,8 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
IQueryParameterType nextOr = nextPermutation.get(paramIndex);
String nextOrValue = nextOr.getValueAsQueryToken(myContext);
RuntimeSearchParam nextParamDef =
mySearchParamRegistry.getActiveSearchParam(myResourceName, nextParamName);
RuntimeSearchParam nextParamDef = mySearchParamRegistry.getActiveSearchParam(
myResourceName, nextParamName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (theComboParam.getComboSearchParamType() == ComboSearchParamType.NON_UNIQUE) {
if (nextParamDef.getParamType() == RestSearchParameterTypeEnum.STRING) {
nextOrValue = StringUtil.normalizeStringForSearchIndexing(nextOrValue);
@ -2119,7 +2126,8 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
// Reference params are only eligible for using a composite index if they
// are qualified
RuntimeSearchParam nextParamDef = mySearchParamRegistry.getActiveSearchParam(myResourceName, nextParamName);
RuntimeSearchParam nextParamDef = mySearchParamRegistry.getActiveSearchParam(
myResourceName, nextParamName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (nextParamDef.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
ReferenceParam param = (ReferenceParam) nextValues.get(0).get(0);
if (isBlank(param.getResourceType())) {

View File

@ -466,7 +466,8 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
RuntimeSearchParam param = null;
if (!isMeta) {
param = mySearchParamRegistry.getActiveSearchParam(nextType, chain);
param = mySearchParamRegistry.getActiveSearchParam(
nextType, chain, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (param == null) {
ourLog.debug("Type {} doesn't have search param {}", nextType, param);
continue;
@ -555,8 +556,8 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
resourceTypes = determineResourceTypes(Collections.singleton(theResourceName), theParamName);
if (resourceTypes.isEmpty()) {
RuntimeSearchParam searchParamByName =
mySearchParamRegistry.getActiveSearchParam(theResourceName, theParamName);
RuntimeSearchParam searchParamByName = mySearchParamRegistry.getActiveSearchParam(
theResourceName, theParamName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (searchParamByName == null) {
throw new InternalErrorException(Msg.code(1244) + "Could not find parameter " + theParamName);
}
@ -628,7 +629,8 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
if (linkIndex == -1) {
Set<Class<? extends IBaseResource>> resourceTypes = new HashSet<>();
for (String resourceName : theResourceNames) {
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(resourceName, theParamNameChain);
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(
resourceName, theParamNameChain, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (param != null && param.hasTargets()) {
Set<String> targetTypes = param.getTargets();
@ -644,7 +646,8 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
String paramNameTail = theParamNameChain.substring(linkIndex + 1);
Set<String> targetResourceTypeNames = new HashSet<>();
for (String resourceName : theResourceNames) {
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(resourceName, paramNameHead);
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(
resourceName, paramNameHead, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (param != null && param.hasTargets()) {
targetResourceTypeNames.addAll(param.getTargets());
@ -656,7 +659,8 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
public List<String> createResourceLinkPaths(
String theResourceName, String theParamName, List<String> theParamQualifiers) {
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(theResourceName, theParamName);
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(
theResourceName, theParamName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (param != null) {
List<String> path = param.getPathsSplit();
@ -687,7 +691,8 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
? theParamQualifiers.subList(1, theParamQualifiers.size())
: List.of();
param = mySearchParamRegistry.getActiveSearchParam(theResourceName, paramNameHead);
param = mySearchParamRegistry.getActiveSearchParam(
theResourceName, paramNameHead, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (param != null) {
Set<String> tailPaths = param.getTargets().stream()
.filter(t -> isBlank(qualifier) || qualifier.equals(t))

View File

@ -441,7 +441,7 @@ public class InstanceReindexServiceImpl implements IInstanceReindexService {
private void fillInParamNames(
ResourceTable theEntity, Collection<SearchParamPresentEntity> theTarget, String theResourceName) {
Map<Long, String> hashes = new HashMap<>();
ResourceSearchParams searchParams = mySearchParamRegistry.getActiveSearchParams(theResourceName);
ResourceSearchParams searchParams = mySearchParamRegistry.getActiveSearchParams(theResourceName, null);
for (RuntimeSearchParam next : searchParams.values()) {
hashes.put(
SearchParamPresentEntity.calculateHashPresence(

View File

@ -423,7 +423,7 @@ public class JpaBulkExportProcessorTest {
// when
RuntimeSearchParam searchParam = new RuntimeSearchParam(new IdType("1"), "", "", "", "", RestSearchParameterTypeEnum.STRING, Collections.singleton(""), Collections.singleton(""), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, Collections.singleton(""));
when(mySearchParamRegistry.getActiveSearchParam(any(), any())).thenReturn(searchParam);
when(mySearchParamRegistry.getActiveSearchParam(any(), any(), any())).thenReturn(searchParam);
// expandAllPatientPidsFromGroup
when(myDaoRegistry.getResourceDao(eq("Group")))
.thenReturn(groupDao);

View File

@ -23,6 +23,8 @@ import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -68,13 +70,13 @@ class HSearchSortHelperImplTest {
void testGetParamType() {
SortSpec sortSpec = new SortSpec();
sortSpec.setParamName("_tag");
when(mockSearchParamRegistry.getActiveSearchParams("Observation")).thenReturn(mockResourceSearchParams);
when(mockSearchParamRegistry.getActiveSearchParams(eq("Observation"), any())).thenReturn(mockResourceSearchParams);
when(mockResourceSearchParams.get("the-param-name")).thenReturn(mockRuntimeSearchParam);
when(mockRuntimeSearchParam.getParamType()).thenReturn(RestSearchParameterTypeEnum.TOKEN);
Optional<RestSearchParameterTypeEnum> paramType = tested.getParamType("Observation", "the-param-name");
verify(mockSearchParamRegistry, times(1)).getActiveSearchParams("Observation");
verify(mockSearchParamRegistry, times(1)).getActiveSearchParams(eq("Observation"), any());
verify(mockResourceSearchParams, times(1)).get("the-param-name");
assertFalse(paramType.isEmpty());
}

View File

@ -207,7 +207,8 @@ public class HfqlExecutor implements IHfqlExecutor {
*/
private void massageWhereClauses(HfqlStatement theStatement) {
String fromResourceName = theStatement.getFromResourceName();
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams(fromResourceName);
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams(
fromResourceName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
for (HfqlStatement.WhereClause nextWhereClause : theStatement.getWhereClauses()) {
@ -311,7 +312,9 @@ public class HfqlExecutor implements IHfqlExecutor {
QualifierDetails qualifiedParamName = QualifierDetails.extractQualifiersFromParameterName(paramName);
RuntimeSearchParam searchParam = mySearchParamRegistry.getActiveSearchParam(
statement.getFromResourceName(), qualifiedParamName.getParamName());
statement.getFromResourceName(),
qualifiedParamName.getParamName(),
ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (searchParam == null) {
throw newInvalidRequestExceptionUnknownSearchParameter(paramName);
}

View File

@ -58,7 +58,7 @@ import org.hl7.fhir.instance.model.api.IIdType;
*/
@Entity()
@Table(
name = "HFJ_IDX_CMP_STRING_UNIQ",
name = ResourceIndexedComboStringUnique.HFJ_IDX_CMP_STRING_UNIQ,
indexes = {
@Index(
name = ResourceIndexedComboStringUnique.IDX_IDXCMPSTRUNIQ_STRING,
@ -75,6 +75,7 @@ public class ResourceIndexedComboStringUnique extends BaseResourceIndexedCombo
public static final int MAX_STRING_LENGTH = 500;
public static final String IDX_IDXCMPSTRUNIQ_STRING = "IDX_IDXCMPSTRUNIQ_STRING";
public static final String IDX_IDXCMPSTRUNIQ_RESOURCE = "IDX_IDXCMPSTRUNIQ_RESOURCE";
public static final String HFJ_IDX_CMP_STRING_UNIQ = "HFJ_IDX_CMP_STRING_UNIQ";
@SequenceGenerator(name = "SEQ_IDXCMPSTRUNIQ_ID", sequenceName = "SEQ_IDXCMPSTRUNIQ_ID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_IDXCMPSTRUNIQ_ID")

View File

@ -41,7 +41,7 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
@Entity
@Table(
name = "HFJ_IDX_CMB_TOK_NU",
name = ResourceIndexedComboTokenNonUnique.HFJ_IDX_CMB_TOK_NU,
indexes = {
// TODO: The hash index was added in 7.4.0 - In 7.6.0 we should drop the string index
@Index(name = "IDX_IDXCMBTOKNU_STR", columnList = "IDX_STRING", unique = false),
@ -51,6 +51,8 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
public class ResourceIndexedComboTokenNonUnique extends BaseResourceIndexedCombo
implements Comparable<ResourceIndexedComboTokenNonUnique>, IResourceIndexComboSearchParameter {
public static final String HFJ_IDX_CMB_TOK_NU = "HFJ_IDX_CMB_TOK_NU";
@SequenceGenerator(name = "SEQ_IDXCMBTOKNU_ID", sequenceName = "SEQ_IDXCMBTOKNU_ID")
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_IDXCMBTOKNU_ID")
@Id

View File

@ -52,7 +52,7 @@ import static org.apache.commons.lang3.StringUtils.defaultString;
@EntityListeners(IndexStorageOptimizationListener.class)
@Entity
@Table(
name = "HFJ_SPIDX_STRING",
name = ResourceIndexedSearchParamString.HFJ_SPIDX_STRING,
indexes = {
/*
* Note: We previously had indexes with the following names,
@ -76,6 +76,7 @@ public class ResourceIndexedSearchParamString extends BaseResourceIndexedSearchP
public static final int MAX_LENGTH = 768;
public static final int HASH_PREFIX_LENGTH = 1;
private static final long serialVersionUID = 1L;
public static final String HFJ_SPIDX_STRING = "HFJ_SPIDX_STRING";
@Id
@SequenceGenerator(name = "SEQ_SPIDX_STRING", sequenceName = "SEQ_SPIDX_STRING")

View File

@ -56,7 +56,7 @@ import static org.apache.commons.lang3.StringUtils.trim;
@EntityListeners(IndexStorageOptimizationListener.class)
@Entity
@Table(
name = "HFJ_SPIDX_TOKEN",
name = ResourceIndexedSearchParamToken.HFJ_SPIDX_TOKEN,
indexes = {
/*
* Note: We previously had indexes with the following names,
@ -78,6 +78,7 @@ public class ResourceIndexedSearchParamToken extends BaseResourceIndexedSearchPa
public static final int MAX_LENGTH = 200;
private static final long serialVersionUID = 1L;
public static final String HFJ_SPIDX_TOKEN = "HFJ_SPIDX_TOKEN";
@FullTextField
@Column(name = "SP_SYSTEM", nullable = true, length = MAX_LENGTH)

View File

@ -168,8 +168,10 @@ public class MatchUrlService {
} else if (nextParamName.startsWith("_") && !Constants.PARAM_LANGUAGE.equals(nextParamName)) {
// ignore these since they aren't search params (e.g. _sort)
} else {
RuntimeSearchParam paramDef =
mySearchParamRegistry.getActiveSearchParam(theResourceDefinition.getName(), nextParamName);
RuntimeSearchParam paramDef = mySearchParamRegistry.getActiveSearchParam(
theResourceDefinition.getName(),
nextParamName,
ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (paramDef == null) {
throw throwUnrecognizedParamException(theMatchUrl, theResourceDefinition, nextParamName);
}

View File

@ -356,7 +356,8 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
String componentSpRef = component.getReference();
String expression = component.getExpression();
RuntimeSearchParam componentSp = mySearchParamRegistry.getActiveSearchParamByUrl(componentSpRef);
RuntimeSearchParam componentSp = mySearchParamRegistry.getActiveSearchParamByUrl(
componentSpRef, ISearchParamRegistry.SearchParamLookupContextEnum.INDEX);
Validate.notNull(
componentSp,
"Misconfigured SP %s - failed to load component %s",
@ -426,7 +427,8 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
}
private boolean isNotExtractableCompositeComponent(RuntimeSearchParam.Component c) {
RuntimeSearchParam componentSearchParam = mySearchParamRegistry.getActiveSearchParamByUrl(c.getReference());
RuntimeSearchParam componentSearchParam = mySearchParamRegistry.getActiveSearchParamByUrl(
c.getReference(), ISearchParamRegistry.SearchParamLookupContextEnum.INDEX);
return // Does the sub-param link work?
componentSearchParam == null
||
@ -450,8 +452,8 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
public SearchParamSet<ResourceIndexedComboStringUnique> extractSearchParamComboUnique(
String theResourceType, ResourceIndexedSearchParams theParams) {
SearchParamSet<ResourceIndexedComboStringUnique> retVal = new SearchParamSet<>();
List<RuntimeSearchParam> runtimeComboUniqueParams =
mySearchParamRegistry.getActiveComboSearchParams(theResourceType, ComboSearchParamType.UNIQUE);
List<RuntimeSearchParam> runtimeComboUniqueParams = mySearchParamRegistry.getActiveComboSearchParams(
theResourceType, ComboSearchParamType.UNIQUE, ISearchParamRegistry.SearchParamLookupContextEnum.INDEX);
for (RuntimeSearchParam runtimeParam : runtimeComboUniqueParams) {
Set<ResourceIndexedComboStringUnique> comboUniqueParams =
@ -485,8 +487,10 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
public SearchParamSet<ResourceIndexedComboTokenNonUnique> extractSearchParamComboNonUnique(
String theResourceType, ResourceIndexedSearchParams theParams) {
SearchParamSet<ResourceIndexedComboTokenNonUnique> retVal = new SearchParamSet<>();
List<RuntimeSearchParam> runtimeComboNonUniqueParams =
mySearchParamRegistry.getActiveComboSearchParams(theResourceType, ComboSearchParamType.NON_UNIQUE);
List<RuntimeSearchParam> runtimeComboNonUniqueParams = mySearchParamRegistry.getActiveComboSearchParams(
theResourceType,
ComboSearchParamType.NON_UNIQUE,
ISearchParamRegistry.SearchParamLookupContextEnum.INDEX);
for (RuntimeSearchParam runtimeParam : runtimeComboNonUniqueParams) {
Set<ResourceIndexedComboTokenNonUnique> comboNonUniqueParams =
@ -575,7 +579,8 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
String value = nextParamAsClientParam.getValueAsQueryToken(myContext);
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(theResourceType, key);
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(
theResourceType, key, ISearchParamRegistry.SearchParamLookupContextEnum.INDEX);
if (theParam.getComboSearchParamType() == ComboSearchParamType.NON_UNIQUE
&& param != null
&& param.getParamType() == RestSearchParameterTypeEnum.STRING) {
@ -989,8 +994,9 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
@VisibleForTesting
Collection<RuntimeSearchParam> getSearchParams(IBaseResource theResource) {
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
Collection<RuntimeSearchParam> retVal =
mySearchParamRegistry.getActiveSearchParams(def.getName()).values();
Collection<RuntimeSearchParam> retVal = mySearchParamRegistry
.getActiveSearchParams(def.getName(), ISearchParamRegistry.SearchParamLookupContextEnum.INDEX)
.values();
List<RuntimeSearchParam> defaultList = Collections.emptyList();
retVal = ObjectUtils.defaultIfNull(retVal, defaultList);
return retVal;

View File

@ -199,8 +199,8 @@ public class SearchParamExtractorService {
});
// Everything else
ResourceSearchParams activeSearchParams =
mySearchParamRegistry.getActiveSearchParams(theEntity.getResourceType());
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams(
theEntity.getResourceType(), ISearchParamRegistry.SearchParamLookupContextEnum.INDEX);
theNewParams.findMissingSearchParams(myPartitionSettings, myStorageSettings, theEntity, activeSearchParams);
}
@ -228,7 +228,8 @@ public class SearchParamExtractorService {
retval.put(nextKey, Boolean.TRUE);
}
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams(entity.getResourceType());
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams(
entity.getResourceType(), ISearchParamRegistry.SearchParamLookupContextEnum.INDEX);
activeSearchParams.getReferenceSearchParamNames().forEach(key -> retval.putIfAbsent(key, Boolean.FALSE));
return retval;
}
@ -308,8 +309,10 @@ public class SearchParamExtractorService {
@Override
public ISearchParamExtractor.ISearchParamFilter getSearchParamFilter(@Nonnull PathAndRef thePathAndRef) {
String searchParamName = thePathAndRef.getSearchParamName();
RuntimeSearchParam searchParam =
mySearchParamRegistry.getActiveSearchParam(theEntity.getResourceType(), searchParamName);
RuntimeSearchParam searchParam = mySearchParamRegistry.getActiveSearchParam(
theEntity.getResourceType(),
searchParamName,
ISearchParamRegistry.SearchParamLookupContextEnum.INDEX);
Set<String> upliftRefchainCodes = searchParam.getUpliftRefchainCodes();
if (upliftRefchainCodes.isEmpty()) {
return ISearchParamExtractor.NO_PARAMS;
@ -533,7 +536,9 @@ public class SearchParamExtractorService {
}
RuntimeSearchParam searchParam = mySearchParamRegistry.getActiveSearchParam(
sourceResourceName, nextPathAndRef.getSearchParamName());
sourceResourceName,
nextPathAndRef.getSearchParamName(),
ISearchParamRegistry.SearchParamLookupContextEnum.INDEX);
extractResourceLinks(
theRequestPartitionId,
theExistingParams,

View File

@ -250,7 +250,8 @@ public class InMemoryResourceMatcher {
}
String resourceName = theResourceDefinition.getName();
RuntimeSearchParam paramDef = mySearchParamRegistry.getActiveSearchParam(resourceName, theParamName);
RuntimeSearchParam paramDef = mySearchParamRegistry.getActiveSearchParam(
resourceName, theParamName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
InMemoryMatchResult checkUnsupportedResult =
checkForUnsupportedParameters(theParamName, paramDef, theAndOrParams);
if (!checkUnsupportedResult.supported()) {
@ -589,6 +590,10 @@ public class InMemoryResourceMatcher {
case NOT:
return !theSearchParams.matchParam(
theStorageSettings, theResourceName, theParamName, theParamDef, theQueryParam);
case ABOVE:
case BELOW:
case TEXT:
case OF_TYPE:
default:
return theSearchParams.matchParam(
theStorageSettings, theResourceName, theParamName, theParamDef, theQueryParam);
@ -688,9 +693,22 @@ public class InMemoryResourceMatcher {
return getValidationSupportOrNull() != null;
case NOT:
return true;
case TEXT:
case OF_TYPE:
case ABOVE:
case BELOW:
default:
return false;
}
case NUMBER:
case DATE:
case STRING:
case REFERENCE:
case COMPOSITE:
case QUANTITY:
case URI:
case HAS:
case SPECIAL:
default:
return false;
}

View File

@ -61,9 +61,12 @@ import java.util.Collection;
import java.util.Collections;
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 ca.uhn.fhir.rest.server.util.ISearchParamRegistry.isAllowedForContext;
import static org.apache.commons.lang3.StringUtils.isBlank;
public class SearchParamRegistryImpl
@ -76,7 +79,7 @@ public class SearchParamRegistryImpl
Collections.unmodifiableSet(Sets.newHashSet("*:url", "Subscription:*", "SearchParameter:*"));
private static final Logger ourLog = LoggerFactory.getLogger(SearchParamRegistryImpl.class);
private static final int MAX_MANAGED_PARAM_COUNT = 10000;
public static final int MAX_MANAGED_PARAM_COUNT = 10000;
private static final long REFRESH_INTERVAL = DateUtils.MILLIS_PER_MINUTE;
private final JpaSearchParamCache myJpaSearchParamCache = new JpaSearchParamCache();
@ -112,45 +115,55 @@ public class SearchParamRegistryImpl
}
@Override
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName) {
public RuntimeSearchParam getActiveSearchParam(
String theResourceName, String theParamName, SearchParamLookupContextEnum theContext) {
requiresActiveSearchParams();
// Can still be null in unit test scenarios
if (myActiveSearchParams != null) {
return myActiveSearchParams.get(theResourceName, theParamName);
} else {
return null;
RuntimeSearchParam param = myActiveSearchParams.get(theResourceName, theParamName);
if (param != null) {
if (isAllowedForContext(param, theContext)) {
return param;
}
}
}
return null;
}
@Nonnull
@Override
public ResourceSearchParams getActiveSearchParams(String theResourceName) {
public ResourceSearchParams getActiveSearchParams(String theResourceName, SearchParamLookupContextEnum theContext) {
requiresActiveSearchParams();
return getActiveSearchParams().getSearchParamMap(theResourceName);
return getActiveSearchParams().getSearchParamMap(theResourceName).toFilteredForContext(theContext);
}
private void requiresActiveSearchParams() {
if (myActiveSearchParams == null) {
// forced refreshes should not use a cache - we're forcibly refrsching it, after all
// forced refreshes should not use a cache - we're forcibly refreshing it, after all
myResourceChangeListenerCache.forceRefresh();
}
}
@Override
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
return myJpaSearchParamCache.getActiveComboSearchParams(theResourceName);
public List<RuntimeSearchParam> getActiveComboSearchParams(
String theResourceName, SearchParamLookupContextEnum theContext) {
return filteredForContext(myJpaSearchParamCache.getActiveComboSearchParams(theResourceName), theContext);
}
@Override
public List<RuntimeSearchParam> getActiveComboSearchParams(
String theResourceName, ComboSearchParamType theParamType) {
return myJpaSearchParamCache.getActiveComboSearchParams(theResourceName, theParamType);
String theResourceName, ComboSearchParamType theParamType, SearchParamLookupContextEnum theContext) {
return filteredForContext(
myJpaSearchParamCache.getActiveComboSearchParams(theResourceName, theParamType), theContext);
}
@Override
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
return myJpaSearchParamCache.getActiveComboSearchParams(theResourceName, theParamNames);
public List<RuntimeSearchParam> getActiveComboSearchParams(
String theResourceName, Set<String> theParamNames, SearchParamLookupContextEnum theContext) {
return filteredForContext(
myJpaSearchParamCache.getActiveComboSearchParams(theResourceName, theParamNames), theContext);
}
@Override
@ -160,13 +173,15 @@ public class SearchParamRegistryImpl
@Nullable
@Override
public RuntimeSearchParam getActiveSearchParamByUrl(String theUrl) {
public RuntimeSearchParam getActiveSearchParamByUrl(String theUrl, SearchParamLookupContextEnum theContext) {
if (myActiveSearchParams != null) {
return myActiveSearchParams.getByUrl(theUrl);
} else {
return null;
RuntimeSearchParam param = myActiveSearchParams.getByUrl(theUrl);
if (isAllowedForContext(param, theContext)) {
return param;
}
}
return null;
}
@Override
public Optional<RuntimeSearchParam> getActiveComboSearchParamById(String theResourceName, IIdType theId) {
@ -307,7 +322,7 @@ public class SearchParamRegistryImpl
ourLog.debug(
"Adding search parameter {}.{} to SearchParamRegistry",
nextBaseName,
StringUtils.defaultString(name, "[composite]"));
Objects.toString(name, "[composite]"));
retval++;
}
return retval;
@ -365,6 +380,11 @@ public class SearchParamRegistryImpl
return ReadOnlySearchParamCache.fromRuntimeSearchParamCache(myActiveSearchParams);
}
@VisibleForTesting
public void setActiveSearchParams(RuntimeSearchParamCache theSearchParams) {
myActiveSearchParams = theSearchParams;
}
/**
* All SearchParameters with the name "phonetic" encode the normalized index value using this phonetic encoder.
*
@ -451,13 +471,10 @@ public class SearchParamRegistryImpl
mySearchParameterCanonicalizer = theSearchParameterCanonicalizerForUnitTest;
}
@VisibleForTesting
public int getMaxManagedParamCountForUnitTests() {
return MAX_MANAGED_PARAM_COUNT;
}
@VisibleForTesting
public void setActiveSearchParams(RuntimeSearchParamCache theSearchParams) {
myActiveSearchParams = theSearchParams;
private static List<RuntimeSearchParam> filteredForContext(
List<RuntimeSearchParam> theActiveComboSearchParams, SearchParamLookupContextEnum theContext) {
return theActiveComboSearchParams.stream()
.filter(t -> isAllowedForContext(t, theContext))
.collect(Collectors.toList());
}
}

View File

@ -469,12 +469,22 @@ public class SearchParameterCanonicalizer {
setEncoder(theRuntimeSearchParam, next.getValue());
} else if (HapiExtensions.EXTENSION_SEARCHPARAM_UPLIFT_REFCHAIN.equals(nextUrl)) {
addUpliftRefchain(theRuntimeSearchParam, next);
} else if (HapiExtensions.EXT_SEARCHPARAM_ENABLED_FOR_SEARCHING.equals(nextUrl)) {
addEnabledForSearching(theRuntimeSearchParam, next.getValue());
}
}
}
}
}
private void addEnabledForSearching(RuntimeSearchParam theRuntimeSearchParam, IBaseDatatype theValue) {
if (theValue instanceof IPrimitiveType) {
String stringValue = ((IPrimitiveType<?>) theValue).getValueAsString();
boolean enabledForSearching = Boolean.parseBoolean(stringValue);
theRuntimeSearchParam.setEnabledForSearching(enabledForSearching);
}
}
@SuppressWarnings("unchecked")
private void addUpliftRefchain(
RuntimeSearchParam theRuntimeSearchParam, IBaseExtension<? extends IBaseExtension, ?> theExtension) {

View File

@ -162,7 +162,7 @@ public enum JpaParamUtil {
List<RuntimeSearchParam.Component> components = theParamDef.getComponents();
for (RuntimeSearchParam.Component next : components) {
String url = next.getReference();
RuntimeSearchParam componentParam = theSearchParamRegistry.getActiveSearchParamByUrl(url);
RuntimeSearchParam componentParam = theSearchParamRegistry.getActiveSearchParamByUrl(url, null);
if (componentParam == null) {
throw new InternalErrorException(Msg.code(499) + "Can not find SearchParameter: " + url);
}

View File

@ -263,7 +263,7 @@ public class SearchParamExtractorDstu3Test {
}
@Override
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName) {
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName, SearchParamLookupContextEnum theContext) {
throw new UnsupportedOperationException();
}
@ -278,7 +278,7 @@ public class SearchParamExtractorDstu3Test {
}
@Override
public ResourceSearchParams getActiveSearchParams(String theResourceName) {
public ResourceSearchParams getActiveSearchParams(String theResourceName, SearchParamLookupContextEnum theContext) {
RuntimeResourceDefinition nextResDef = ourCtx.getResourceDefinition(theResourceName);
ResourceSearchParams retval = new ResourceSearchParams(theResourceName);
for (RuntimeSearchParam nextSp : nextResDef.getSearchParams()) {
@ -291,23 +291,23 @@ public class SearchParamExtractorDstu3Test {
}
@Override
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames, SearchParamLookupContextEnum theContext) {
throw new UnsupportedOperationException();
}
@Nullable
@Override
public RuntimeSearchParam getActiveSearchParamByUrl(String theUrl) {
public RuntimeSearchParam getActiveSearchParamByUrl(String theUrl, SearchParamLookupContextEnum theContext) {
throw new UnsupportedOperationException();
}
@Override
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, SearchParamLookupContextEnum theContext) {
throw new UnsupportedOperationException();
}
@Override
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, ComboSearchParamType theParamType) {
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, ComboSearchParamType theParamType, SearchParamLookupContextEnum theContext) {
throw new UnsupportedOperationException(Msg.code(2210));
}

View File

@ -32,6 +32,8 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
import static ca.uhn.fhir.jpa.searchparam.matcher.InMemoryResourceMatcherR5Test.newRequest;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
@ -59,7 +61,7 @@ public class InMemoryResourceMatcherConfigurationR5Test {
@BeforeEach
public void before() {
RuntimeSearchParam codeSearchParam = new RuntimeSearchParam(null, null, null, null, "Observation.code", RestSearchParameterTypeEnum.TOKEN, null, null, RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null);
when(mySearchParamRegistry.getActiveSearchParam("Observation", "code")).thenReturn(codeSearchParam);
when(mySearchParamRegistry.getActiveSearchParam(eq("Observation"), eq("code"), any())).thenReturn(codeSearchParam);
myObservation = new Observation();
CodeableConcept codeableConcept = new CodeableConcept();

View File

@ -86,13 +86,13 @@ public class InMemoryResourceMatcherR5Test {
@BeforeEach
public void before() {
RuntimeSearchParam dateSearchParam = new RuntimeSearchParam(null, null, null, null, "Observation.effective", RestSearchParameterTypeEnum.DATE, null, null, RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null);
when(mySearchParamRegistry.getActiveSearchParam("Observation", "date")).thenReturn(dateSearchParam);
when(mySearchParamRegistry.getActiveSearchParam(eq("Observation"), eq("date"), any())).thenReturn(dateSearchParam);
RuntimeSearchParam codeSearchParam = new RuntimeSearchParam(null, null, null, null, "Observation.code", RestSearchParameterTypeEnum.TOKEN, null, null, RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null);
when(mySearchParamRegistry.getActiveSearchParam("Observation", "code")).thenReturn(codeSearchParam);
when(mySearchParamRegistry.getActiveSearchParam(eq("Observation"), eq("code"), any())).thenReturn(codeSearchParam);
RuntimeSearchParam encSearchParam = new RuntimeSearchParam(null, null, null, null, "Observation.encounter", RestSearchParameterTypeEnum.REFERENCE, null, null, RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null);
when(mySearchParamRegistry.getActiveSearchParam("Observation", "encounter")).thenReturn(encSearchParam);
when(mySearchParamRegistry.getActiveSearchParam(eq("Observation"), eq("encounter"), any())).thenReturn(encSearchParam);
myObservation = new Observation();
myObservation.getMeta().setSource(TEST_SOURCE);

View File

@ -138,7 +138,7 @@ public class SearchParamRegistryImplTest {
@Test
void handleInit() {
assertEquals(31, mySearchParamRegistry.getActiveSearchParams("Patient").size());
assertEquals(31, mySearchParamRegistry.getActiveSearchParams("Patient", null).size());
IdDt idBad = new IdDt("SearchParameter/bad");
when(mySearchParamProvider.read(idBad)).thenThrow(new ResourceNotFoundException("id bad"));
@ -151,7 +151,7 @@ public class SearchParamRegistryImplTest {
idList.add(idBad);
idList.add(idGood);
mySearchParamRegistry.handleInit(idList);
assertEquals(32, mySearchParamRegistry.getActiveSearchParams("Patient").size());
assertEquals(32, mySearchParamRegistry.getActiveSearchParams("Patient", null).size());
}
@Test
@ -226,7 +226,7 @@ public class SearchParamRegistryImplTest {
}
private void assertPatientSearchParamSize(int theExpectedSize) {
assertEquals(theExpectedSize, mySearchParamRegistry.getActiveSearchParams("Patient").size());
assertEquals(theExpectedSize, mySearchParamRegistry.getActiveSearchParams("Patient", null).size());
}
private void assertResult(ResourceChangeResult theResult, long theExpectedAdded, long theExpectedUpdated, long theExpectedRemoved) {
@ -253,19 +253,19 @@ public class SearchParamRegistryImplTest {
@Test
public void testGetActiveUniqueSearchParams_Empty() {
assertThat(mySearchParamRegistry.getActiveComboSearchParams("Patient")).isEmpty();
assertThat(mySearchParamRegistry.getActiveComboSearchParams("Patient", null)).isEmpty();
}
@Test
public void testGetActiveSearchParamByUrl_whenSPExists_returnsActiveSp() {
RuntimeSearchParam patientLanguageSp = mySearchParamRegistry.getActiveSearchParamByUrl("SearchParameter/Patient-language");
RuntimeSearchParam patientLanguageSp = mySearchParamRegistry.getActiveSearchParamByUrl("SearchParameter/Patient-language", null);
assertNotNull(patientLanguageSp);
assertEquals(patientLanguageSp.getId().getIdPart(), "Patient-language");
}
@Test
public void testGetActiveSearchParamByUrl_whenSPNotExist_returnsNull() {
RuntimeSearchParam nonExistingSp = mySearchParamRegistry.getActiveSearchParamByUrl("SearchParameter/nonExistingSp");
RuntimeSearchParam nonExistingSp = mySearchParamRegistry.getActiveSearchParamByUrl("SearchParameter/nonExistingSp", null);
assertNull(nonExistingSp);
}
@ -284,7 +284,7 @@ public class SearchParamRegistryImplTest {
assertFalse(retried.get());
mySearchParamRegistry.forceRefresh();
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams("Patient");
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams("Patient", null);
assertTrue(retried.get());
assertEquals(ourBuiltInSearchParams.getSearchParamMap("Patient").size(), activeSearchParams.size());
}
@ -297,7 +297,7 @@ public class SearchParamRegistryImplTest {
resetDatabaseToOrigSearchParamsPlusNewOneWithStatus(Enumerations.PublicationStatus.ACTIVE);
mySearchParamRegistry.forceRefresh();
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams("Patient");
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams("Patient", null);
RuntimeSearchParam converted = activeSearchParams.get("foo");
assertNotNull(converted);
@ -332,7 +332,7 @@ public class SearchParamRegistryImplTest {
mySearchParamRegistry.forceRefresh();
RuntimeSearchParam canonicalSp = mySearchParamRegistry.getRuntimeSearchParam("Encounter", "subject");
RuntimeSearchParam canonicalSp = mySearchParamRegistry.getRuntimeSearchParam("Encounter", "subject", null);
assertEquals("Modified Subject", canonicalSp.getDescription());
assertTrue(canonicalSp.hasUpliftRefchain("name1"));
assertFalse(canonicalSp.hasUpliftRefchain("name99"));

View File

@ -71,7 +71,7 @@ public class SubscriptionLoader extends BaseResourceCacheSynchronizer {
protected SearchParameterMap getSearchParameterMap() {
SearchParameterMap map = new SearchParameterMap();
if (mySearchParamRegistry.getActiveSearchParam("Subscription", "status") != null) {
if (mySearchParamRegistry.getActiveSearchParam("Subscription", "status", null) != null) {
map.add(
Subscription.SP_STATUS,
new TokenOrListParam()

View File

@ -71,7 +71,7 @@ public class SubscriptionTopicLoader extends BaseResourceCacheSynchronizer {
protected SearchParameterMap getSearchParameterMap() {
SearchParameterMap map = new SearchParameterMap();
if (mySearchParamRegistry.getActiveSearchParam("SubscriptionTopic", "status") != null) {
if (mySearchParamRegistry.getActiveSearchParam("SubscriptionTopic", "status", null) != null) {
map.add(SubscriptionTopic.SP_STATUS, new TokenParam(null, Enumerations.PublicationStatus.ACTIVE.toCode()));
}
map.setLoadSynchronousUpTo(SubscriptionConstants.MAX_SUBSCRIPTION_RESULTS);

View File

@ -42,7 +42,7 @@ public class MatchUrlServiceTest extends BaseJpaTest {
public void testTranslateMatchUrl() {
RuntimeResourceDefinition resourceDef = ourCtx.getResourceDefinition(Condition.class);
ISearchParamRegistry searchParamRegistry = mock(ISearchParamRegistry.class);
when(searchParamRegistry.getActiveSearchParam(any(), eq("patient"))).thenReturn(resourceDef.getSearchParam("patient"));
when(searchParamRegistry.getActiveSearchParam(any(), eq("patient"), any())).thenReturn(resourceDef.getSearchParam("patient"));
SearchParameterMap match = myMatchUrlService.translateMatchUrl("Condition?patient=304&_lastUpdated=>2011-01-01T11:12:21.0000Z", resourceDef);
assertEquals("2011-01-01T11:12:21.0000Z", match.getLastUpdated().getLowerBound().getValueAsString());
assertEquals(ReferenceParam.class, match.get("patient").get(0).get(0).getClass());

View File

@ -76,7 +76,7 @@ public class ChainingR4SearchTest extends BaseJpaR4Test {
msgHeader.setEvent(new Coding("http://foo", "bar", "blah"));
inputBundle.addEntry().setResource(msgHeader);
RuntimeSearchParam sp = mySearchParamRegistry.getActiveSearchParam("Bundle", "message");
RuntimeSearchParam sp = mySearchParamRegistry.getActiveSearchParam("Bundle", "message", null);
assertEquals("Bundle.entry[0].resource", sp.getPath());
assertThat(sp.getBase()).containsExactly("Bundle");
assertEquals(RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, sp.getStatus());

View File

@ -12,6 +12,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.util.JpaParamUtil;
import ca.uhn.fhir.jpa.test.util.ComboSearchParameterTestHelper;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.DateAndListParam;
import ca.uhn.fhir.rest.param.DateOrListParam;
@ -42,6 +43,7 @@ import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.SearchParameter;
import org.hl7.fhir.r4.model.ServiceRequest;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.TransactionStatus;
@ -69,6 +71,12 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
@Autowired
private IJobCoordinator myJobCoordinator;
private ComboSearchParameterTestHelper myComboSearchParameterTestHelper;
@BeforeEach
public void beforeEach() {
myComboSearchParameterTestHelper = new ComboSearchParameterTestHelper(mySearchParameterDao, mySearchParamRegistry);
}
@AfterEach
public void purgeUniqueIndexes() {
@ -76,42 +84,7 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
}
private void createUniqueBirthdateAndGenderSps() {
SearchParameter sp = new SearchParameter();
sp.setId("SearchParameter/patient-gender");
sp.setType(Enumerations.SearchParamType.TOKEN);
sp.setCode("gender");
sp.setExpression("Patient.gender");
sp.setStatus(PublicationStatus.ACTIVE);
sp.addBase("Patient");
mySearchParameterDao.update(sp, mySrd);
sp = new SearchParameter();
sp.setId("SearchParameter/patient-birthdate");
sp.setType(Enumerations.SearchParamType.DATE);
sp.setCode("birthdate");
sp.setExpression("Patient.birthDate");
sp.setStatus(PublicationStatus.ACTIVE);
sp.addBase("Patient");
mySearchParameterDao.update(sp, mySrd);
sp = new SearchParameter();
sp.setId("SearchParameter/patient-gender-birthdate");
sp.setType(Enumerations.SearchParamType.COMPOSITE);
sp.setStatus(PublicationStatus.ACTIVE);
sp.addBase("Patient");
sp.addComponent()
.setExpression("Patient")
.setDefinition("SearchParameter/patient-gender");
sp.addComponent()
.setExpression("Patient")
.setDefinition("SearchParameter/patient-birthdate");
sp.addExtension()
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
.setValue(new BooleanType(true));
mySearchParameterDao.update(sp, mySrd);
mySearchParamRegistry.forceRefresh();
myComboSearchParameterTestHelper.createBirthdateAndGenderSps(true);
myMessages.clear();
}
@ -774,7 +747,7 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
myStorageSettings.setSchedulingDisabled(true);
myStorageSettings.setReindexThreadCount(1);
List<RuntimeSearchParam> uniqueSearchParams = mySearchParamRegistry.getActiveComboSearchParams("Observation");
List<RuntimeSearchParam> uniqueSearchParams = mySearchParamRegistry.getActiveComboSearchParams("Observation", null);
assertThat(uniqueSearchParams).isEmpty();
Patient pt1 = new Patient();
@ -803,7 +776,7 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
createUniqueObservationSubjectDateCode();
uniqueSearchParams = mySearchParamRegistry.getActiveComboSearchParams("Observation");
uniqueSearchParams = mySearchParamRegistry.getActiveComboSearchParams("Observation", null);
assertThat(uniqueSearchParams).hasSize(1);
assertThat(uniqueSearchParams.get(0).getComponents()).hasSize(3);
@ -820,7 +793,7 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
myResourceIndexedComboStringUniqueDao.deleteAll();
});
assertThat(mySearchParamRegistry.getActiveComboSearchParams("Observation")).hasSize(1);
assertThat(mySearchParamRegistry.getActiveComboSearchParams("Observation", null)).hasSize(1);
executeReindex();
@ -1653,7 +1626,7 @@ public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test
@Test
public void testDetectUniqueSearchParams() {
createUniqueBirthdateAndGenderSps();
List<RuntimeSearchParam> params = mySearchParamRegistry.getActiveComboSearchParams("Patient");
List<RuntimeSearchParam> params = mySearchParamRegistry.getActiveComboSearchParams("Patient", null);
assertThat(params).hasSize(1);
assertEquals(ComboSearchParamType.UNIQUE, params.get(0).getComboSearchParamType());

View File

@ -254,9 +254,9 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
// check the 2 parameters are different
// when fetched from the system
RuntimeSearchParam paramdefault = mySearchParamRegistry.getActiveSearchParam("Patient",
"fuzzydefault");
"fuzzydefault", null);
RuntimeSearchParam parammodified = mySearchParamRegistry.getActiveSearchParam("Patient",
"fuzzymodified");
"fuzzymodified", null);
// verify the encoders are different!
assertThat(parammodified).isNotEqualTo(paramdefault);
@ -594,7 +594,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
mySearchParamRegistry.forceRefresh();
RuntimeSearchParam sp = mySearchParamRegistry.getActiveSearchParam("Patient", "family");
RuntimeSearchParam sp = mySearchParamRegistry.getActiveSearchParam("Patient", "family", null);
assertEquals(RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, sp.getStatus());
}

View File

@ -133,7 +133,7 @@ public class SearchParamExtractorR4Test implements ITestDataBuilder {
@Test
public void testTokenText_DisabledInSearchParam_Coding() {
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation").get("code");
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation", null).get("code");
RuntimeSearchParam codeSearchParam = new RuntimeSearchParam(existingCodeSp);
codeSearchParam.addExtension(HapiExtensions.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new Extension(HapiExtensions.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new BooleanType(true)));
mySearchParamRegistry.addSearchParam(codeSearchParam);
@ -186,7 +186,7 @@ public class SearchParamExtractorR4Test implements ITestDataBuilder {
StorageSettings storageSettings = new StorageSettings();
storageSettings.setSuppressStringIndexingInTokens(true);
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation").get("code");
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation", null).get("code");
RuntimeSearchParam codeSearchParam = new RuntimeSearchParam(existingCodeSp);
codeSearchParam.addExtension(HapiExtensions.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new Extension(HapiExtensions.EXT_SEARCHPARAM_TOKEN_SUPPRESS_TEXT_INDEXING, new BooleanType(false)));
mySearchParamRegistry.addSearchParam(codeSearchParam);
@ -220,7 +220,7 @@ public class SearchParamExtractorR4Test implements ITestDataBuilder {
enc.addLocation().setLocation(new Reference("Location/123"));
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new StorageSettings(), new PartitionSettings(), ourCtx, mySearchParamRegistry);
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam("Encounter", "location");
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam("Encounter", "location", null);
assertNotNull(param);
ISearchParamExtractor.SearchParamSet<PathAndRef> links = extractor.extractResourceLinks(enc, false);
assertThat(links).hasSize(1);
@ -235,7 +235,7 @@ public class SearchParamExtractorR4Test implements ITestDataBuilder {
consent.setSource(new Reference().setReference("Consent/999"));
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new StorageSettings(), new PartitionSettings(), ourCtx, mySearchParamRegistry);
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam("Consent", Consent.SP_SOURCE_REFERENCE);
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam("Consent", Consent.SP_SOURCE_REFERENCE, null);
assertNotNull(param);
ISearchParamExtractor.SearchParamSet<PathAndRef> links = extractor.extractResourceLinks(consent, false);
assertThat(links).hasSize(1);
@ -250,7 +250,7 @@ public class SearchParamExtractorR4Test implements ITestDataBuilder {
p.addIdentifier().setSystem("sys").setValue("val");
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(new StorageSettings(), new PartitionSettings(), ourCtx, mySearchParamRegistry);
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam("Patient", Patient.SP_IDENTIFIER);
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam("Patient", Patient.SP_IDENTIFIER, null);
assertNotNull(param);
ISearchParamExtractor.SearchParamSet<BaseResourceIndexedSearchParam> params = extractor.extractSearchParamTokens(p, param);
assertThat(params).hasSize(1);
@ -325,7 +325,7 @@ public class SearchParamExtractorR4Test implements ITestDataBuilder {
.setCode(new CodeableConcept().addCoding(new Coding().setSystem("http://foo").setCode("code1")))
.setValue(new Quantity().setSystem(UcumServiceUtil.UCUM_CODESYSTEM_URL).setCode("cm").setValue(200));
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation").get("component-value-quantity");
RuntimeSearchParam existingCodeSp = mySearchParamRegistry.getActiveSearchParams("Observation", null).get("component-value-quantity");
SearchParamExtractorR4 extractor = new SearchParamExtractorR4(storageSettings, new PartitionSettings(), ourCtx, mySearchParamRegistry);
List<String> list = extractor.extractParamValuesAsStrings(existingCodeSp, o1);
@ -363,8 +363,8 @@ public class SearchParamExtractorR4Test implements ITestDataBuilder {
.stream()
.map(t->(ResourceIndexedSearchParamToken)t)
.collect(Collectors.toList());
list.forEach(t->t.calculateHashes());
ourLog.info("Found tokens:\n * {}", list.stream().map(t->t.toString()).collect(Collectors.joining("\n * ")));
list.forEach(ResourceIndexedSearchParamToken::calculateHashes);
ourLog.info("Found tokens:\n * {}", list.stream().map(ResourceIndexedSearchParamToken::toString).collect(Collectors.joining("\n * ")));
assertThat(list).containsExactlyInAnyOrder(new ResourceIndexedSearchParamToken(new PartitionSettings(), "Patient", "deceased", null, "false"), new ResourceIndexedSearchParamToken(new PartitionSettings(), "Patient", "identifier", "http://foo1", "bar1"), new ResourceIndexedSearchParamToken(new PartitionSettings(), "Patient", "identifier", "http://foo2", "bar2"), new ResourceIndexedSearchParamToken(new PartitionSettings(), "Patient", "identifier:of-type", "http://terminology.hl7.org/CodeSystem/v2-0203", "MR|bar1"), new ResourceIndexedSearchParamToken(new PartitionSettings(), "Patient", "identifier:of-type", "http://terminology.hl7.org/CodeSystem/v2-0203", "MR|bar2"));

View File

@ -159,7 +159,7 @@ public class MultitenantBatchOperationR4Test extends BaseMultitenantResourceProv
myBatch2JobHelper.awaitJobCompletion(jobId.getValue());
ourLog.info("Search params: {}", mySearchParamRegistry.getActiveSearchParams("Observation").getSearchParamNames());
ourLog.info("Search params: {}", mySearchParamRegistry.getActiveSearchParams("Observation", null).getSearchParamNames());
logAllTokenIndexes();
@ -196,7 +196,7 @@ public class MultitenantBatchOperationR4Test extends BaseMultitenantResourceProv
myBatch2JobHelper.awaitJobCompletion(jobId.getValue());
ourLog.info("Search params: {}", mySearchParamRegistry.getActiveSearchParams("Observation").getSearchParamNames());
ourLog.info("Search params: {}", mySearchParamRegistry.getActiveSearchParams("Observation", null).getSearchParamNames());
logAllTokenIndexes();
runInTransaction(() -> {
@ -224,7 +224,7 @@ public class MultitenantBatchOperationR4Test extends BaseMultitenantResourceProv
doCreateResource(reindexTestHelper.buildObservationWithAlleleExtension(Observation.ObservationStatus.CANCELLED));
reindexTestHelper.createAlleleSearchParameter();
ourLog.info("Search params: {}", mySearchParamRegistry.getActiveSearchParams("Observation").getSearchParamNames());
ourLog.info("Search params: {}", mySearchParamRegistry.getActiveSearchParams("Observation", null).getSearchParamNames());
// The searchparam value is on the observation, but it hasn't been indexed yet
myTenantClientInterceptor.setTenantId(TENANT_A);

View File

@ -403,7 +403,7 @@ public class ResourceProviderCustomSearchParamR4Test extends BaseResourceProvide
mySearchParameterDao.create(fooSp, mySrd);
mySearchParamRegistry.forceRefresh();
assertNotNull(mySearchParamRegistry.getActiveSearchParam("Patient", "foo"));
assertNotNull(mySearchParamRegistry.getActiveSearchParam("Patient", "foo", null));
Patient pat = new Patient();
pat.setGender(AdministrativeGender.MALE);

View File

@ -353,7 +353,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
IFhirResourceDao<SearchParameter> searchParameterDao = myDaoRegistry.getResourceDao(SearchParameter.class);
searchParameterDao.create(searchParameter, (RequestDetails) null);
RuntimeSearchParam sp = mySearchParamRegistry.getActiveSearchParam("Organization", "_profile");
RuntimeSearchParam sp = mySearchParamRegistry.getActiveSearchParam("Organization", "_profile", null);
assertNotNull(sp);
IFhirResourceDao<Organization> organizationDao = myDaoRegistry.getResourceDao(Organization.class);

View File

@ -104,7 +104,7 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test implements IValueSet
@Test
public void testValueSetUrlSP() {
RuntimeSearchParam sp = mySearchParamRegistry.getActiveSearchParam("ValueSet", "url");
RuntimeSearchParam sp = mySearchParamRegistry.getActiveSearchParam("ValueSet", "url", null);
assertEquals("url", sp.getName());
}

View File

@ -140,7 +140,7 @@ public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test {
public void testCreate_BundleWithComposition_UsingSimpleUplift() {
// Setup
RuntimeSearchParam subjectSp = mySearchParamRegistry.getRuntimeSearchParam("Bundle", "composition");
RuntimeSearchParam subjectSp = mySearchParamRegistry.getRuntimeSearchParam("Bundle", "composition", null);
SearchParameter sp = new SearchParameter();
Extension upliftRefChain = sp.addExtension().setUrl(HapiExtensions.EXTENSION_SEARCHPARAM_UPLIFT_REFCHAIN);
upliftRefChain.addExtension(HapiExtensions.EXTENSION_SEARCHPARAM_UPLIFT_REFCHAIN_PARAM_CODE, new CodeType("type"));
@ -1058,7 +1058,7 @@ public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test {
}
private void createSearchParam_EncounterSubject_WithUpliftOnName() {
RuntimeSearchParam subjectSp = mySearchParamRegistry.getRuntimeSearchParam("Encounter", "subject");
RuntimeSearchParam subjectSp = mySearchParamRegistry.getRuntimeSearchParam("Encounter", "subject", null);
SearchParameter sp = new SearchParameter();
Extension upliftRefChain = sp.addExtension().setUrl(HapiExtensions.EXTENSION_SEARCHPARAM_UPLIFT_REFCHAIN);
upliftRefChain.addExtension(HapiExtensions.EXTENSION_SEARCHPARAM_UPLIFT_REFCHAIN_PARAM_CODE, new CodeType("name"));

View File

@ -0,0 +1,258 @@
package ca.uhn.fhir.jpa.provider.r5;
import ca.uhn.fhir.batch2.jobs.reindex.ReindexAppCtx;
import ca.uhn.fhir.batch2.jobs.reindex.ReindexJobParameters;
import ca.uhn.fhir.batch2.model.JobInstanceStartRequest;
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.test.Batch2JobHelper;
import ca.uhn.fhir.jpa.test.util.ComboSearchParameterTestHelper;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.gclient.StringClientParam;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import jakarta.annotation.Nonnull;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.CapabilityStatement;
import org.hl7.fhir.r5.model.Enumerations;
import org.hl7.fhir.r5.model.Extension;
import org.hl7.fhir.r5.model.SearchParameter;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import static ca.uhn.fhir.util.HapiExtensions.EXT_SEARCHPARAM_ENABLED_FOR_SEARCHING;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Named.named;
import static org.junit.jupiter.params.provider.Arguments.arguments;
public class SearchParameterDisabledForQueryingR5Test extends BaseResourceProviderR5Test {
@Autowired(required = false)
protected Batch2JobHelper myBatch2JobHelper;
private ComboSearchParameterTestHelper myComboSearchParameterTestHelper;
@BeforeEach
void beforeEach() {
myStorageSettings.setMarkResourcesForReindexingUponSearchParameterChange(false);
myComboSearchParameterTestHelper = new ComboSearchParameterTestHelper(mySearchParameterDao, mySearchParamRegistry);
}
@AfterEach
void afterEach() {
JpaStorageSettings defaults = new JpaStorageSettings();
myStorageSettings.setMarkResourcesForReindexingUponSearchParameterChange(defaults.isMarkResourcesForReindexingUponSearchParameterChange());
}
@ParameterizedTest
@MethodSource("standardSearchParameters")
void testIndexAndSearch(TestParameters theParameters) {
// Setup
createPatient(withId("A"), withFamily("SIMPSON"), withGiven("HOMER"));
SearchParameter sp = theParameters.mySearchParameter;
ourLog.info(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(sp));
mySearchParameterDao.update(sp, mySrd);
mySearchParamRegistry.forceRefresh();
// Test
reindexAllPatientsAndWaitForCompletion();
// Verify
runInTransaction(() -> {
List<ResourceIndexedSearchParamString> indexes = myResourceIndexedSearchParamStringDao
.findAll()
.stream()
.filter(t -> t.getParamName().equals(sp.getCode()))
.toList();
assertEquals(1, indexes.size());
assertEquals(theParameters.myStringIndexValue, indexes.get(0).getValueNormalized());
});
// Test
try {
Bundle outcome = myClient
.search()
.forResource("Patient")
.where(new StringClientParam(sp.getCode()).matches().value(theParameters.myStringIndexValue))
.returnBundle(Bundle.class)
.execute();
if (theParameters.myExpectedErrorCode == null) {
assertEquals(1, outcome.getEntry().size());
} else {
fail();
}
} catch (InvalidRequestException e) {
if (theParameters.myExpectedErrorCode != null) {
String expectedErrorMessage = "HAPI-" + theParameters.myExpectedErrorCode + ": Search parameter \"" + sp.getCode() + "\" for resource type \"Patient\" is not active for searching";
assertThat(e.getMessage()).contains(expectedErrorMessage);
String expectedValidParams = "Valid search parameters for this search are: [_id, _lastUpdated, _text, active, address, address-city, address-country, address-postalcode, address-state, address-use, birthdate, death-date, deceased, email, family, gender, general-practitioner, given, identifier, language, link, name, organization, part-agree, phone, phonetic, telecom]";
if (theParameters.mySearchParameter.getCode().equals("family")) {
expectedValidParams = expectedErrorMessage.replace(", family", "");
}
assertThat(e.getMessage()).contains(expectedValidParams);
} else {
fail();
}
}
}
@ParameterizedTest
@MethodSource("standardSearchParameters")
void testCapabilityStatement(TestParameters theParameters) {
// Setup
SearchParameter sp = theParameters.mySearchParameter;
mySearchParameterDao.update(sp, mySrd);
mySearchParamRegistry.forceRefresh();
// Test
CapabilityStatement cs = myClient.capabilities().ofType(CapabilityStatement.class).execute();
// Verify
CapabilityStatement.CapabilityStatementRestResourceComponent patient = cs.getRestFirstRep().getResource().stream().filter(t -> t.getType().equals("Patient")).findFirst().orElseThrow();
Set<String> searchParamNames = patient.getSearchParam().stream().map(CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent::getName).collect(Collectors.toSet());
if (theParameters.myEnabledForSearching == Boolean.FALSE) {
assertThat(searchParamNames).doesNotContain(theParameters.mySearchParameter.getCode());
} else {
assertThat(searchParamNames).contains(theParameters.mySearchParameter.getCode());
}
}
@ParameterizedTest
@CsvSource({
// theEnabledForSearching, theUnique
" true , true",
" false , true",
" , true",
" true , false",
" false , false",
" , false"
})
public void testComboUniqueSearchParameter(Boolean theEnabledForSearching, boolean theUnique) {
myComboSearchParameterTestHelper.createBirthdateAndGenderSps(theUnique, t -> {
if (theEnabledForSearching != null) {
t.addExtension(EXT_SEARCHPARAM_ENABLED_FOR_SEARCHING, new BooleanType(theEnabledForSearching));
}
});
createPatient(withId("A"), withBirthdate("2020-01-02"), withGender("male"));
// createPatient(withId("B"), withBirthdate("2020-01-02"), withGender("female"));
logAllDateIndexes();
logAllTokenIndexes();
logAllUniqueIndexes();
// Test
SearchParameterMap map = SearchParameterMap
.newSynchronous()
.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-02"))
.add(Patient.SP_GENDER, new TokenParam( "male"));
myCaptureQueriesListener.clear();
IBundleProvider outcome = myPatientDao.search(map, mySrd);
myCaptureQueriesListener.logSelectQueries();
// Verify
assertThat(toUnqualifiedVersionlessIdValues(outcome)).containsExactly("Patient/A");
String sql = myCaptureQueriesListener.getSelectQueries().get(0).getSql(true, true);
if (theEnabledForSearching == Boolean.FALSE) {
assertThat(sql).contains(ResourceIndexedSearchParamToken.HFJ_SPIDX_TOKEN);
assertThat(sql).doesNotContain(ResourceIndexedComboStringUnique.HFJ_IDX_CMP_STRING_UNIQ);
assertThat(sql).doesNotContain(ResourceIndexedComboTokenNonUnique.HFJ_IDX_CMB_TOK_NU);
} else {
assertThat(sql).doesNotContain(ResourceIndexedSearchParamToken.HFJ_SPIDX_TOKEN);
assertThat(sql).containsAnyOf(ResourceIndexedComboStringUnique.HFJ_IDX_CMP_STRING_UNIQ, ResourceIndexedComboTokenNonUnique.HFJ_IDX_CMB_TOK_NU);
}
}
private void reindexAllPatientsAndWaitForCompletion() {
ReindexJobParameters parameters = new ReindexJobParameters();
parameters.addUrl("Patient?");
JobInstanceStartRequest startRequest = new JobInstanceStartRequest();
startRequest.setJobDefinitionId(ReindexAppCtx.JOB_REINDEX);
startRequest.setParameters(parameters);
Batch2JobStartResponse res = myJobCoordinator.startInstance(mySrd, startRequest);
myBatch2JobHelper.awaitJobCompletion(res);
}
private static List<Arguments> standardSearchParameters() {
return List.of(
arguments(named("Custom/EnabledTrue", new TestParameters(createSearchParameterCustom(true), "SIMPSONHOMER", null))),
arguments(named("Custom/EnabledFalse", new TestParameters(createSearchParameterCustom(false), "SIMPSONHOMER", 2539))),
arguments(named("Custom/EnabledNull", new TestParameters(createSearchParameterCustom(null), "SIMPSONHOMER", null))),
arguments(named("BuiltIn/EnabledTrue", new TestParameters(createSearchParameterBuiltIn(true), "SIMPSON", null))),
arguments(named("BuiltIn/EnabledFalse", new TestParameters(createSearchParameterBuiltIn(false), "SIMPSON", 2540))),
arguments(named("BuiltIn/EnabledNull", new TestParameters(createSearchParameterBuiltIn(null), "SIMPSON", null)))
);
}
private static @Nonnull SearchParameter createSearchParameterBuiltIn(Boolean theEnabledForSearching) {
SearchParameter retVal = createSearchParameter(theEnabledForSearching, "family", "Patient.name.family");
retVal.setId("individual-family");
retVal.setUrl("http://hl7.org/fhir/SearchParameter/individual-family");
return retVal;
}
private static @Nonnull SearchParameter createSearchParameterCustom(Boolean theEnabledForSearching) {
return createSearchParameter(theEnabledForSearching, "names", "Patient.name.family + Patient.name.given");
}
private static SearchParameter createSearchParameter(Boolean theEnabledForSearching, String code, String expression) {
SearchParameter sp = new SearchParameter();
if (theEnabledForSearching != null) {
sp.addExtension(EXT_SEARCHPARAM_ENABLED_FOR_SEARCHING, new BooleanType(theEnabledForSearching));
}
sp.setId(code);
sp.setName(code);
sp.setCode(code);
sp.setType(Enumerations.SearchParamType.STRING);
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
sp.setExpression(expression);
sp.addBase(Enumerations.VersionIndependentResourceTypesAll.PATIENT);
return sp;
}
private static class TestParameters {
private final SearchParameter mySearchParameter;
private final String myStringIndexValue;
private final Boolean myEnabledForSearching;
private final Integer myExpectedErrorCode;
private TestParameters(SearchParameter theSearchParameter, String theStringIndexValue, Integer theExpectedErrorCode) {
mySearchParameter = theSearchParameter;
myStringIndexValue = theStringIndexValue;
myExpectedErrorCode = theExpectedErrorCode;
Extension ext = mySearchParameter.getExtensionByUrl(EXT_SEARCHPARAM_ENABLED_FOR_SEARCHING);
if (ext != null) {
myEnabledForSearching = ext.getValueBooleanType().booleanValue();
} else {
myEnabledForSearching = null;
}
}
}
}

View File

@ -0,0 +1,89 @@
package ca.uhn.fhir.jpa.test.util;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
import ca.uhn.fhir.util.HapiExtensions;
import ca.uhn.hapi.converters.canonical.VersionCanonicalizer;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r5.model.BooleanType;
import org.hl7.fhir.r5.model.Enumerations;
import org.hl7.fhir.r5.model.SearchParameter;
import static org.junit.jupiter.api.Assertions.assertEquals;
@SuppressWarnings({"rawtypes", "unchecked"})
public class ComboSearchParameterTestHelper {
private final IFhirResourceDao mySearchParameterDao;
private final VersionCanonicalizer myVersionCanonicalizer;
private final ISearchParamRegistry mySearchParamRegistry;
public ComboSearchParameterTestHelper(IFhirResourceDao<?> theSearchParameterDao, ISearchParamRegistry theSearchParamRegistry) {
mySearchParameterDao = theSearchParameterDao;
mySearchParamRegistry = theSearchParamRegistry;
FhirContext context = mySearchParameterDao.getContext();
myVersionCanonicalizer = new VersionCanonicalizer(context);
assertEquals("SearchParameter", context.getResourceType(mySearchParameterDao.getResourceType()));
}
public void createBirthdateAndGenderSps(boolean theUnique, ISearchParamCustomizer... theSearchParamCustomizer) {
SearchParameter sp = new SearchParameter();
sp.setId("SearchParameter/patient-gender");
sp.setType(Enumerations.SearchParamType.TOKEN);
sp.setCode("gender");
sp.setExpression("Patient.gender");
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
sp.addBase(Enumerations.VersionIndependentResourceTypesAll.PATIENT);
mySearchParameterDao.update(fromCanonoical(sp), new SystemRequestDetails());
sp = new SearchParameter();
sp.setId("SearchParameter/patient-birthdate");
sp.setType(Enumerations.SearchParamType.DATE);
sp.setCode("birthdate");
sp.setExpression("Patient.birthDate");
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
sp.addBase(Enumerations.VersionIndependentResourceTypesAll.PATIENT);
mySearchParameterDao.update(fromCanonoical(sp), new SystemRequestDetails());
sp = new SearchParameter();
sp.setId("SearchParameter/patient-gender-birthdate");
sp.setType(Enumerations.SearchParamType.COMPOSITE);
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
sp.addBase(Enumerations.VersionIndependentResourceTypesAll.PATIENT);
sp.addComponent()
.setExpression("Patient")
.setDefinition("SearchParameter/patient-gender");
sp.addComponent()
.setExpression("Patient")
.setDefinition("SearchParameter/patient-birthdate");
sp.addExtension()
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
.setValue(new BooleanType(true));
for (var next : theSearchParamCustomizer) {
next.accept(sp);
}
mySearchParameterDao.update(fromCanonoical(sp), new SystemRequestDetails());
mySearchParamRegistry.forceRefresh();
}
private IBaseResource fromCanonoical(SearchParameter theSearchParameter) {
return myVersionCanonicalizer.searchParameterFromCanonical(theSearchParameter);
}
@FunctionalInterface
public interface ISearchParamCustomizer {
void accept(SearchParameter theSearchParameter);
}
}

View File

@ -17,6 +17,7 @@ import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorR4;
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.server.util.FhirContextSearchParamRegistry;
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
import ca.uhn.fhir.rest.server.util.ResourceSearchParams;
import ca.uhn.fhir.test.utilities.ITestDataBuilder;
import org.hl7.fhir.r4.model.Observation;
@ -51,7 +52,7 @@ class ExtendedHSearchIndexExtractorTest implements ITestDataBuilder.WithSupport
extractedParams.myCompositeParams.add(composite);
// run: now translate to HSearch
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams("Observation");
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams("Observation", ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
ExtendedHSearchIndexExtractor extractor = new ExtendedHSearchIndexExtractor(
myJpaStorageSettings, myFhirContext, activeSearchParams, mySearchParamExtractor);
ExtendedHSearchIndexData indexData = extractor.extract(new Observation(), extractedParams);
@ -74,7 +75,7 @@ class ExtendedHSearchIndexExtractorTest implements ITestDataBuilder.WithSupport
searchParams.myQuantityParams.add(searchParamQuantity);
// run: now translate to HSearch
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams("Patient");
ResourceSearchParams activeSearchParams = mySearchParamRegistry.getActiveSearchParams("Patient", ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
ExtendedHSearchIndexExtractor extractor = new ExtendedHSearchIndexExtractor(
myJpaStorageSettings, myFhirContext, activeSearchParams, mySearchParamExtractor);
ExtendedHSearchIndexData indexData = extractor.extract(new SearchParameter(), searchParams);

View File

@ -40,6 +40,7 @@ import static org.hl7.fhir.r5.model.Enumerations.SearchParamType.URI;
import static org.hl7.fhir.r5.model.Enumerations.VersionIndependentResourceTypesAll.OBSERVATION;
import static org.hl7.fhir.r5.model.Enumerations.VersionIndependentResourceTypesAll.PATIENT;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.lenient;
@ -78,7 +79,7 @@ public class SearchParameterDaoValidatorTest {
private void createAndMockSearchParameter(Enumerations.SearchParamType theType, String theDefinition, String theCodeValue, String theExpression) {
SearchParameter observationCodeSp = createSearchParameter(theType, theDefinition, theCodeValue, theExpression);
RuntimeSearchParam observationCodeRuntimeSearchParam = mySearchParameterCanonicalizer.canonicalizeSearchParameter(observationCodeSp);
lenient().when(mySearchParamRegistry.getActiveSearchParamByUrl(eq(theDefinition))).thenReturn(observationCodeRuntimeSearchParam);
lenient().when(mySearchParamRegistry.getActiveSearchParamByUrl(eq(theDefinition), any())).thenReturn(observationCodeRuntimeSearchParam);
}
@Test

View File

@ -34,7 +34,9 @@ import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyCollection;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -111,7 +113,7 @@ public class ResourceLinkPredicateBuilderTest {
String resourceType = "Bundle";
RuntimeSearchParam mockSearchParam = mock(RuntimeSearchParam.class);
when(mockSearchParam.getPathsSplit()).thenReturn(List.of("Patient.given", "Bundle.composition.subject", "Bundle.type"));
when(mySearchParamRegistry.getActiveSearchParam(resourceType, paramName)).thenReturn(mockSearchParam);
when(mySearchParamRegistry.getActiveSearchParam(eq(resourceType), eq(paramName), any())).thenReturn(mockSearchParam);
List<String> result = myResourceLinkPredicateBuilder.createResourceLinkPaths(resourceType, paramName, List.of());
assertThat(result).containsExactlyInAnyOrder("Bundle.composition.subject", "Bundle.type");
}
@ -128,14 +130,14 @@ public class ResourceLinkPredicateBuilderTest {
public void createResourceLinkPaths_withChainAndSearchParameterFoundNoQualifiers_returnsPath() {
String paramName = "subject.identifier";
String resourceType = "Observation";
when(mySearchParamRegistry.getActiveSearchParam("Observation", "subject.identifier")).thenReturn(null);
when(mySearchParamRegistry.getActiveSearchParam(eq("Observation"), eq("subject.identifier"), any())).thenReturn(null);
RuntimeSearchParam observationSubjectSP = mock(RuntimeSearchParam.class);
when(observationSubjectSP.getPathsSplit()).thenReturn(List.of("Observation.subject"));
when(observationSubjectSP.getTargets()).thenReturn(Set.of("Patient"));
when(mySearchParamRegistry.getActiveSearchParam("Observation", "subject")).thenReturn(observationSubjectSP);
when(mySearchParamRegistry.getActiveSearchParam(eq("Observation"), eq("subject"), any())).thenReturn(observationSubjectSP);
RuntimeSearchParam patientIdentifierSP = mock(RuntimeSearchParam.class);
when(patientIdentifierSP.getPathsSplit()).thenReturn(List.of("Patient.identifier"));
when(mySearchParamRegistry.getActiveSearchParam("Patient", "identifier")).thenReturn(patientIdentifierSP);
when(mySearchParamRegistry.getActiveSearchParam(eq("Patient"),eq( "identifier"), any())).thenReturn(patientIdentifierSP);
List<String> result = myResourceLinkPredicateBuilder.createResourceLinkPaths(resourceType, paramName, List.of());
assertThat(result).containsExactlyInAnyOrder("Observation.subject.identifier");
}
@ -145,23 +147,23 @@ public class ResourceLinkPredicateBuilderTest {
String paramName = "subject.managingOrganization.identifier";
String resourceType = "Observation";
when(mySearchParamRegistry.getActiveSearchParam("Observation", "subject.managingOrganization.identifier")).thenReturn(null);
when(mySearchParamRegistry.getActiveSearchParam(eq("Observation"), eq("subject.managingOrganization.identifier"), any())).thenReturn(null);
RuntimeSearchParam observationSubjectSP = mock(RuntimeSearchParam.class);
when(observationSubjectSP.getPathsSplit()).thenReturn(List.of("Observation.subject"));
when(observationSubjectSP.getTargets()).thenReturn(Set.of("Patient"));
when(mySearchParamRegistry.getActiveSearchParam("Observation", "subject")).thenReturn(observationSubjectSP);
when(mySearchParamRegistry.getActiveSearchParam(eq("Observation"), eq("subject"), any())).thenReturn(observationSubjectSP);
when(mySearchParamRegistry.getActiveSearchParam("Patient", "managingOrganization.identifier")).thenReturn(null);
when(mySearchParamRegistry.getActiveSearchParam(eq("Patient"), eq("managingOrganization.identifier"), any())).thenReturn(null);
RuntimeSearchParam organizationSP = mock(RuntimeSearchParam.class);
when(organizationSP.getPathsSplit()).thenReturn(List.of("Patient.managingOrganization"));
when(organizationSP.getTargets()).thenReturn(Set.of("Organization"));
when(mySearchParamRegistry.getActiveSearchParam("Patient", "managingOrganization")).thenReturn(organizationSP);
when(mySearchParamRegistry.getActiveSearchParam(eq("Patient"), eq("managingOrganization"), any())).thenReturn(organizationSP);
RuntimeSearchParam organizationIdentifierSP = mock(RuntimeSearchParam.class);
when(organizationIdentifierSP.getPathsSplit()).thenReturn(List.of("Organization.identifier"));
when(mySearchParamRegistry.getActiveSearchParam("Organization", "identifier")).thenReturn(organizationIdentifierSP);
when(mySearchParamRegistry.getActiveSearchParam(eq("Organization"), eq("identifier"), any())).thenReturn(organizationIdentifierSP);
List<String> result = myResourceLinkPredicateBuilder.createResourceLinkPaths(resourceType, paramName, List.of("Patient", "Organization"));
assertThat(result).containsExactlyInAnyOrder("Observation.subject.managingOrganization.identifier");
@ -171,11 +173,11 @@ public class ResourceLinkPredicateBuilderTest {
public void createResourceLinkPaths_withChainAndSearchParameterFoundWithNonMatchingQualifier_returnsEmpty() {
String paramName = "subject.identifier";
String resourceType = "Observation";
when(mySearchParamRegistry.getActiveSearchParam("Observation", "subject.identifier")).thenReturn(null);
when(mySearchParamRegistry.getActiveSearchParam(eq("Observation"), eq("subject.identifier"), any())).thenReturn(null);
RuntimeSearchParam observationSubjectSP = mock(RuntimeSearchParam.class);
when(observationSubjectSP.getPathsSplit()).thenReturn(List.of("Observation.subject"));
when(observationSubjectSP.getTargets()).thenReturn(Set.of("Patient"));
when(mySearchParamRegistry.getActiveSearchParam("Observation", "subject")).thenReturn(observationSubjectSP);
when(mySearchParamRegistry.getActiveSearchParam(eq("Observation"), eq("subject"), any())).thenReturn(observationSubjectSP);
List<String> result = myResourceLinkPredicateBuilder.createResourceLinkPaths(resourceType, paramName, List.of("Group"));
assertThat(result).isEmpty();
}

View File

@ -71,6 +71,7 @@ public class MdmRuleValidator implements IMdmRuleValidator {
mySearchParamRetriever = theSearchParamRetriever;
}
@Override
public void validate(MdmRulesJson theMdmRules) {
validateMdmTypes(theMdmRules);
validateSearchParams(theMdmRules);
@ -127,7 +128,9 @@ public class MdmRuleValidator implements IMdmRuleValidator {
}
public void validateTypeHasIdentifier(String theResourceType) {
if (mySearchParamRetriever.getActiveSearchParam(theResourceType, "identifier") == null) {
if (mySearchParamRetriever.getActiveSearchParam(
theResourceType, "identifier", ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH)
== null) {
throw new ConfigurationException(
Msg.code(1510) + "Resource Type " + theResourceType
+ " is not supported, as it does not have an 'identifier' field, which is necessary for MDM workflow.");
@ -162,7 +165,9 @@ public class MdmRuleValidator implements IMdmRuleValidator {
private void validateResourceSearchParam(String theFieldName, String theResourceType, String theSearchParam) {
String searchParam = SearchParameterUtil.stripModifier(theSearchParam);
if (mySearchParamRetriever.getActiveSearchParam(theResourceType, searchParam) == null) {
if (mySearchParamRetriever.getActiveSearchParam(
theResourceType, searchParam, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH)
== null) {
throw new ConfigurationException(Msg.code(1511) + "Error in " + theFieldName + ": " + theResourceType
+ " does not have a search parameter called '" + theSearchParam + "'");
}

View File

@ -67,7 +67,8 @@ public class MdmSearchParamSvc {
public List<String> getValueFromResourceForSearchParam(IBaseResource theResource, String theSearchParam) {
String resourceType = myFhirContext.getResourceType(theResource);
String searchParam = SearchParameterUtil.stripModifier(theSearchParam);
RuntimeSearchParam activeSearchParam = mySearchParamRegistry.getActiveSearchParam(resourceType, searchParam);
RuntimeSearchParam activeSearchParam = mySearchParamRegistry.getActiveSearchParam(
resourceType, searchParam, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
return mySearchParamExtractorService.extractParamValuesAsStrings(activeSearchParam, theResource);
}

View File

@ -16,19 +16,23 @@ import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class MdmRuleValidatorTest extends BaseR4Test {
@Override
@BeforeEach
public void before() {
when(mySearchParamRetriever.getActiveSearchParam("Patient", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Practitioner", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Medication", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("AllergyIntolerance", "identifier")).thenReturn(null);
when(mySearchParamRetriever.getActiveSearchParam("Organization", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Organization", "active")).thenReturn(mock(RuntimeSearchParam.class));
super.before();
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Practitioner"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Medication"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("AllergyIntolerance"), eq("identifier"), any())).thenReturn(null);
when(mySearchParamRetriever.getActiveSearchParam(eq("Organization"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Organization"), eq("active"), any())).thenReturn(mock(RuntimeSearchParam.class));
}
@Test

View File

@ -15,6 +15,8 @@ import org.junit.jupiter.api.Test;
import java.util.Arrays;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -30,13 +32,14 @@ public class CustomResourceMatcherR4Test extends BaseR4Test {
private static Patient ourHenryJohn;
private static Patient ourHenryJOHN;
@Override
@BeforeEach
public void before() {
super.before();
when(mySearchParamRetriever.getActiveSearchParam("Patient", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Practitioner", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Medication", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("AllergyIntolerance", "identifier")).thenReturn(null);
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Practitioner"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Medication"),eq( "identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("AllergyIntolerance"), eq("identifier"), any())).thenReturn(null);
}
@Test

View File

@ -14,6 +14,8 @@ import org.junit.jupiter.api.Test;
import java.util.Arrays;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -26,9 +28,9 @@ public class FhirPathResourceMatcherR4Test extends BaseMdmRulesR4Test {
@BeforeEach
public void before() {
super.before();
when(mySearchParamRetriever.getActiveSearchParam("Patient", "birthdate")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Patient", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Patient", "active")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("birthdate"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("active"), any())).thenReturn(mock(RuntimeSearchParam.class));
{
myLeft = new Patient();

View File

@ -13,6 +13,8 @@ import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -26,11 +28,11 @@ public class MdmResourceMatcherSvcLoggingTest extends BaseMdmRulesR4Test {
public void before() {
super.before();
when(mySearchParamRetriever.getActiveSearchParam("Patient", "birthdate")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Patient", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Practitioner", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Medication", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Patient", "active")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("birthdate"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Practitioner"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Medication"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("active"), any())).thenReturn(mock(RuntimeSearchParam.class));
myMdmResourceMatcherSvc = buildMatcher(buildActiveBirthdateIdRules());

View File

@ -7,6 +7,8 @@ import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@ -20,11 +22,11 @@ public class MdmResourceMatcherSvcR4Test extends BaseMdmRulesR4Test {
public void before() {
super.before();
when(mySearchParamRetriever.getActiveSearchParam("Patient", "birthdate")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Patient", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Practitioner", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Medication", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Patient", "active")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("birthdate"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Practitioner"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Medication"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("active"), any())).thenReturn(mock(RuntimeSearchParam.class));
myMdmResourceMatcherSvc = buildMatcher(buildActiveBirthdateIdRules());

View File

@ -47,11 +47,11 @@ public class ResourceMatcherR4Test extends BaseMdmRulesR4Test {
public void before() {
super.before();
when(mySearchParamRetriever.getActiveSearchParam("Patient", "birthdate")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Patient", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Practitioner", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Medication", "identifier")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam("Patient", "active")).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("birthdate"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Practitioner"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Medication"), eq("identifier"), any())).thenReturn(mock(RuntimeSearchParam.class));
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("active"), any())).thenReturn(mock(RuntimeSearchParam.class));
{
myLeft = new Patient();

View File

@ -22,6 +22,8 @@ import static ca.uhn.fhir.mdm.api.MdmConstants.HAPI_ENTERPRISE_IDENTIFIER_SYSTEM
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;
@ -41,9 +43,11 @@ public class EIDHelperR4Test extends BaseR4Test {
private EIDHelper myEidHelper;
@Override
@BeforeEach
public void before() {
when(mySearchParamRetriever.getActiveSearchParam("Patient", "identifier"))
super.before();
when(mySearchParamRetriever.getActiveSearchParam(eq("Patient"), eq("identifier"), any()))
.thenReturn(new RuntimeSearchParam(null, null, "identifier", "Description", "identifier", RestSearchParameterTypeEnum.STRING, new HashSet<>(), new HashSet<>(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null));
myMdmSettings = new MdmSettings(new MdmRuleValidator(ourFhirContext, mySearchParamRetriever)) {

View File

@ -420,12 +420,14 @@ public class RestfulServerConfiguration implements ISearchParamRegistry {
}
@Override
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName) {
return getActiveSearchParams(theResourceName).get(theParamName);
public RuntimeSearchParam getActiveSearchParam(
String theResourceName, String theParamName, SearchParamLookupContextEnum theContext) {
return getActiveSearchParams(theResourceName, theContext).get(theParamName);
}
@Override
public ResourceSearchParams getActiveSearchParams(@Nonnull String theResourceName) {
public ResourceSearchParams getActiveSearchParams(
@Nonnull String theResourceName, SearchParamLookupContextEnum theContext) {
Validate.notBlank(theResourceName, "theResourceName must not be null or blank");
ResourceSearchParams retval = new ResourceSearchParams(theResourceName);
@ -442,7 +444,7 @@ public class RestfulServerConfiguration implements ISearchParamRegistry {
@Nullable
@Override
public RuntimeSearchParam getActiveSearchParamByUrl(String theUrl) {
public RuntimeSearchParam getActiveSearchParamByUrl(String theUrl, SearchParamLookupContextEnum theContext) {
throw new UnsupportedOperationException(Msg.code(286));
}

View File

@ -130,7 +130,8 @@ public class SearchPreferHandlingInterceptor {
}
}
RuntimeSearchParam activeSearchParam = searchParamRetriever.getActiveSearchParam(resourceName, paramName);
RuntimeSearchParam activeSearchParam = searchParamRetriever.getActiveSearchParam(
resourceName, paramName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (activeSearchParam == null) {
if (theHandling == PreferHandlingEnum.LENIENT) {
@ -144,8 +145,11 @@ public class SearchPreferHandlingInterceptor {
} else {
// Strict handling
List<String> allowedParams =
searchParamRetriever.getActiveSearchParams(resourceName).getSearchParamNames().stream()
List<String> allowedParams = searchParamRetriever
.getActiveSearchParams(
resourceName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH)
.getSearchParamNames()
.stream()
.sorted()
.distinct()
.collect(Collectors.toList());

View File

@ -318,6 +318,7 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
case UPDATE:
terser.setElement(resource, "conditionalUpdate", "true");
break;
case UPDATE_REWRITE_HISTORY:
case HISTORY_INSTANCE:
case HISTORY_SYSTEM:
case HISTORY_TYPE:
@ -401,12 +402,13 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
*/
ResourceSearchParams searchParams;
ISearchParamRegistry searchParamRegistry;
ResourceSearchParams serverConfigurationActiveSearchParams =
serverConfiguration.getActiveSearchParams(resourceName);
ResourceSearchParams serverConfigurationActiveSearchParams = serverConfiguration.getActiveSearchParams(
resourceName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
if (mySearchParamRegistry != null) {
searchParamRegistry = mySearchParamRegistry;
searchParams = mySearchParamRegistry
.getActiveSearchParams(resourceName)
.getActiveSearchParams(
resourceName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH)
.makeCopy();
for (String nextBuiltInSpName : serverConfigurationActiveSearchParams.getSearchParamNames()) {
if (nextBuiltInSpName.startsWith("_")
@ -465,7 +467,8 @@ public class ServerCapabilityStatementProvider implements IServerConformanceProv
}
for (RuntimeSearchParam t : searchParamRegistry
.getActiveSearchParams(nextResourceName)
.getActiveSearchParams(
nextResourceName, ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH)
.values()) {
if (t.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
if (isNotBlank(t.getName())) {

View File

@ -35,6 +35,8 @@ import java.util.List;
import java.util.Optional;
import java.util.Set;
import static ca.uhn.fhir.rest.server.util.ISearchParamRegistry.isAllowedForContext;
public class FhirContextSearchParamRegistry implements ISearchParamRegistry {
private final List<RuntimeSearchParam> myExtraSearchParams = new ArrayList<>();
@ -54,21 +56,26 @@ public class FhirContextSearchParamRegistry implements ISearchParamRegistry {
}
@Override
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName) {
return getActiveSearchParams(theResourceName).get(theParamName);
public RuntimeSearchParam getActiveSearchParam(
String theResourceName, String theParamName, SearchParamLookupContextEnum theContext) {
return getActiveSearchParams(theResourceName, theContext).get(theParamName);
}
@Override
public ResourceSearchParams getActiveSearchParams(String theResourceName) {
public ResourceSearchParams getActiveSearchParams(String theResourceName, SearchParamLookupContextEnum theContext) {
ResourceSearchParams retval = new ResourceSearchParams(theResourceName);
RuntimeResourceDefinition nextResDef = myCtx.getResourceDefinition(theResourceName);
for (RuntimeSearchParam nextSp : nextResDef.getSearchParams()) {
if (isAllowedForContext(nextSp, theContext)) {
retval.put(nextSp.getName(), nextSp);
}
}
for (RuntimeSearchParam next : myExtraSearchParams) {
if (isAllowedForContext(next, theContext)) {
retval.put(next.getName(), next);
}
}
return retval;
}
@ -78,29 +85,31 @@ public class FhirContextSearchParamRegistry implements ISearchParamRegistry {
}
@Override
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
public List<RuntimeSearchParam> getActiveComboSearchParams(
String theResourceName, Set<String> theParamNames, SearchParamLookupContextEnum theContext) {
throw new UnsupportedOperationException(Msg.code(2066));
}
@Nullable
@Override
public RuntimeSearchParam getActiveSearchParamByUrl(String theUrl) {
public RuntimeSearchParam getActiveSearchParamByUrl(String theUrl, SearchParamLookupContextEnum theContext) {
// simple implementation for test support
return myCtx.getResourceTypes().stream()
.flatMap(type -> getActiveSearchParams(type).values().stream())
.flatMap(type -> getActiveSearchParams(type, theContext).values().stream())
.filter(rsp -> theUrl.equals(rsp.getUri()))
.findFirst()
.orElse(null);
}
@Override
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
public List<RuntimeSearchParam> getActiveComboSearchParams(
String theResourceName, SearchParamLookupContextEnum theContext) {
throw new UnsupportedOperationException(Msg.code(2068));
}
@Override
public List<RuntimeSearchParam> getActiveComboSearchParams(
String theResourceName, ComboSearchParamType theParamType) {
String theResourceName, ComboSearchParamType theParamType, SearchParamLookupContextEnum theContext) {
throw new UnsupportedOperationException(Msg.code(2209));
}

View File

@ -25,6 +25,7 @@ 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 jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IIdType;
@ -50,14 +51,18 @@ public interface ISearchParamRegistry {
}
/**
* @param theContext The context to return active search params for, or {@literal null} to return any active search params
* @return Returns {@literal null} if no match
*/
RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName);
RuntimeSearchParam getActiveSearchParam(
String theResourceName, String theParamName, @Nullable SearchParamLookupContextEnum theContext);
/**
* @param theContext The context to return active search params for, or {@literal null} to return any active search params
* @return Returns all active search params for the given resource
*/
ResourceSearchParams getActiveSearchParams(String theResourceName);
ResourceSearchParams getActiveSearchParams(
String theResourceName, @Nullable SearchParamLookupContextEnum theContext);
/**
* Request that the cache be refreshed now, in the current thread
@ -77,13 +82,17 @@ public interface ISearchParamRegistry {
*/
default void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {}
default List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
/**
* @param theContext The context to return active search params for, or {@literal null} to return any active search params
*/
default List<RuntimeSearchParam> getActiveComboSearchParams(
String theResourceName, SearchParamLookupContextEnum theContext) {
return Collections.emptyList();
}
// TODO ND remove default implementation
default List<RuntimeSearchParam> getActiveComboSearchParams(
String theResourceName, ComboSearchParamType theParamType) {
String theResourceName, ComboSearchParamType theParamType, SearchParamLookupContextEnum theContext) {
return Collections.emptyList();
}
@ -92,7 +101,11 @@ public interface ISearchParamRegistry {
return Optional.empty();
}
default List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
/**
* @param theContext The context to return active search params for, or {@literal null} to return any active search params
*/
default List<RuntimeSearchParam> getActiveComboSearchParams(
String theResourceName, Set<String> theParamNames, SearchParamLookupContextEnum theContext) {
return Collections.emptyList();
}
@ -100,10 +113,13 @@ public interface ISearchParamRegistry {
* Returns a collection containing all of the valid active search parameters. This method is intended for
* creating error messages for users as opposed to actual search processing. It will include meta parameters
* such as <code>_id</code> and <code>_lastUpdated</code>.
*
* @param theContext The context to return active search params for, or {@literal null} to return any active search params
*/
default Collection<String> getValidSearchParameterNamesIncludingMeta(String theResourceName) {
default Collection<String> getValidSearchParameterNamesIncludingMeta(
String theResourceName, SearchParamLookupContextEnum theContext) {
TreeSet<String> retval;
ResourceSearchParams activeSearchParams = getActiveSearchParams(theResourceName);
ResourceSearchParams activeSearchParams = getActiveSearchParams(theResourceName, theContext);
if (activeSearchParams == null) {
retval = new TreeSet<>();
} else {
@ -117,23 +133,25 @@ public interface ISearchParamRegistry {
/**
* Fetch a SearchParameter by URL
*
* @param theContext The context to return active search params for, or {@literal null} to return any active search params
* @return Returns <code>null</code> if it can't be found
*/
@Nullable
RuntimeSearchParam getActiveSearchParamByUrl(String theUrl);
RuntimeSearchParam getActiveSearchParamByUrl(String theUrl, SearchParamLookupContextEnum theContext);
/**
* Find a search param for a resource. First, check the resource itself, then check the top-level `Resource` resource.
*
* @param theResourceType the resource type.
* @param theParamName the search parameter name.
*
* @param theContext The context to return active search params for, or {@literal null} to return any active search params
* @return the {@link RuntimeSearchParam} that is found.
*/
default RuntimeSearchParam getRuntimeSearchParam(String theResourceType, String theParamName) {
RuntimeSearchParam availableSearchParamDef = getActiveSearchParam(theResourceType, theParamName);
default RuntimeSearchParam getRuntimeSearchParam(
String theResourceType, String theParamName, SearchParamLookupContextEnum theContext) {
RuntimeSearchParam availableSearchParamDef = getActiveSearchParam(theResourceType, theParamName, theContext);
if (availableSearchParamDef == null) {
availableSearchParamDef = getActiveSearchParam("Resource", theParamName);
availableSearchParamDef = getActiveSearchParam("Resource", theParamName, theContext);
}
if (availableSearchParamDef == null) {
throw new InvalidRequestException(
@ -145,17 +163,54 @@ public interface ISearchParamRegistry {
/**
* Get all the search params for a resource. First, check the resource itself, then check the top-level `Resource` resource and combine the two.
*
* @param theContext The context to return active search params for, or {@literal null} to return any active search params
* @param theResourceType the resource type.
*
* @return the {@link ResourceSearchParams} that has all the search params.
*/
default ResourceSearchParams getRuntimeSearchParams(String theResourceType) {
default ResourceSearchParams getRuntimeSearchParams(
String theResourceType, SearchParamLookupContextEnum theContext) {
ResourceSearchParams availableSearchParams =
getActiveSearchParams(theResourceType).makeCopy();
ResourceSearchParams resourceSearchParams = getActiveSearchParams("Resource");
getActiveSearchParams(theResourceType, theContext).makeCopy();
ResourceSearchParams resourceSearchParams = getActiveSearchParams("Resource", theContext);
resourceSearchParams
.getSearchParamNames()
.forEach(param -> availableSearchParams.addSearchParamIfAbsent(param, resourceSearchParams.get(param)));
return availableSearchParams;
}
/**
* Describes the context for looking up individual search parameters or lists of search parameters.
* These can be thought of as filter criteria - Most search parameters generally apply to all
* context, but some may be explicitly defined to only work for some.
*
* @since 7.6.0
*/
enum SearchParamLookupContextEnum {
/**
* Search parameter should be used when indexing a resource that is being persisted
*/
INDEX,
/**
* Search parameter should be used for searching. This includes explicit searches such as
* standard REST FHIR searches, but also includes resolving match URLs, subscription criteria,
* etc.
*/
SEARCH,
/**
* Search parameter should be used for sorting via the {@literal _sort} parameter.
*/
SORT
}
static boolean isAllowedForContext(
@Nonnull RuntimeSearchParam theSearchParam, @Nullable SearchParamLookupContextEnum theContext) {
/*
* I'm thinking that a future enhancement might be to allow a SearchParameter to declare that it
* is supported for searching or for sorting or for both - But for now these are one and the same.
*/
if (theContext == SearchParamLookupContextEnum.SEARCH || theContext == SearchParamLookupContextEnum.SORT) {
return theSearchParam.isEnabledForSearching();
}
return true;
}
}

View File

@ -30,9 +30,13 @@ import java.util.Map;
import java.util.Set;
import java.util.stream.Stream;
import static ca.uhn.fhir.rest.server.util.ISearchParamRegistry.isAllowedForContext;
public class ResourceSearchParams {
private final String myResourceName;
private final Map<String, RuntimeSearchParam> myMap;
private final Map<ISearchParamRegistry.SearchParamLookupContextEnum, ResourceSearchParams> myContextToParams =
new HashMap<>();
public ResourceSearchParams(String theResourceName) {
myResourceName = theResourceName;
@ -48,6 +52,32 @@ public class ResourceSearchParams {
return myMap.values();
}
/**
* Returns a filtered view of this {@link ResourceSearchParams} instance if
* any parameters are not valid for the given {@literal theContext}.
*/
public ResourceSearchParams toFilteredForContext(ISearchParamRegistry.SearchParamLookupContextEnum theContext) {
if (theContext == null) {
return this;
}
synchronized (this) {
ResourceSearchParams retVal = myContextToParams.get(theContext);
if (retVal == null) {
Map<String, RuntimeSearchParam> filteredMap = new HashMap<>(myMap.size());
for (var nextEntry : myMap.entrySet()) {
String key = nextEntry.getKey();
RuntimeSearchParam nextParam = nextEntry.getValue();
if (isAllowedForContext(nextParam, theContext)) {
filteredMap.put(key, nextParam);
}
}
retVal = new ResourceSearchParams(myResourceName, filteredMap);
myContextToParams.put(theContext, retVal);
}
return retVal;
}
}
public static ResourceSearchParams empty(String theResourceName) {
return new ResourceSearchParams(theResourceName, Collections.emptyMap());
}
@ -57,6 +87,7 @@ public class ResourceSearchParams {
}
public void remove(String theName) {
myContextToParams.clear();
myMap.remove(theName);
}
@ -69,10 +100,12 @@ public class ResourceSearchParams {
}
public RuntimeSearchParam put(String theName, RuntimeSearchParam theSearchParam) {
myContextToParams.clear();
return myMap.put(theName, theSearchParam);
}
public void addSearchParamIfAbsent(String theParamName, RuntimeSearchParam theRuntimeSearchParam) {
myContextToParams.clear();
myMap.putIfAbsent(theParamName, theRuntimeSearchParam);
}

View File

@ -519,15 +519,29 @@ public abstract class BaseStorageDao {
return;
}
ResourceSearchParams searchParams = mySearchParamRegistry.getActiveSearchParams(getResourceName());
ResourceSearchParams searchParams = mySearchParamRegistry.getActiveSearchParams(
getResourceName(), ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
Set<String> paramNames = theSource.keySet();
for (String nextParamName : paramNames) {
QualifierDetails qualifiedParamName = QualifierDetails.extractQualifiersFromParameterName(nextParamName);
RuntimeSearchParam param = searchParams.get(qualifiedParamName.getParamName());
if (param == null) {
Collection<String> validNames =
mySearchParamRegistry.getValidSearchParameterNamesIncludingMeta(getResourceName());
Collection<String> validNames = mySearchParamRegistry.getValidSearchParameterNamesIncludingMeta(
getResourceName(), ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
RuntimeSearchParam notEnabledForSearchParam = mySearchParamRegistry.getActiveSearchParam(
getResourceName(), qualifiedParamName.getParamName(), null);
if (notEnabledForSearchParam != null) {
String msg = getContext()
.getLocalizer()
.getMessageSanitized(
BaseStorageDao.class,
"invalidSearchParameterNotEnabledForSearch",
qualifiedParamName.getParamName(),
getResourceName(),
validNames);
throw new InvalidRequestException(Msg.code(2539) + msg);
} else {
String msg = getContext()
.getLocalizer()
.getMessageSanitized(
@ -538,10 +552,13 @@ public abstract class BaseStorageDao {
validNames);
throw new InvalidRequestException(Msg.code(524) + msg);
}
}
// Should not be null since the check above would have caught it
RuntimeSearchParam paramDef =
mySearchParamRegistry.getActiveSearchParam(getResourceName(), qualifiedParamName.getParamName());
RuntimeSearchParam paramDef = mySearchParamRegistry.getActiveSearchParam(
getResourceName(),
qualifiedParamName.getParamName(),
ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
for (String nextValue : theSource.get(nextParamName)) {
QualifiedParamList qualifiedParam = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(

View File

@ -105,8 +105,10 @@ public class DaoResourceLinkResolver<T extends IResourcePersistentId> implements
RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(resourceType);
Class<? extends IBaseResource> type = resourceDef.getImplementingClass();
RuntimeSearchParam searchParam =
mySearchParamRegistry.getActiveSearchParam(theSourceResourceName, thePathAndRef.getSearchParamName());
RuntimeSearchParam searchParam = mySearchParamRegistry.getActiveSearchParam(
theSourceResourceName,
thePathAndRef.getSearchParamName(),
ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
T persistentId = null;
if (theTransactionDetails != null) {

View File

@ -74,7 +74,7 @@ public class SearchParameterDaoValidator {
for (IPrimitiveType<?> nextBaseType : searchParameter.getBase()) {
String nextBase = nextBaseType.getValueAsString();
RuntimeSearchParam existingSearchParam =
mySearchParamRegistry.getActiveSearchParam(nextBase, searchParameter.getCode());
mySearchParamRegistry.getActiveSearchParam(nextBase, searchParameter.getCode(), null);
if (existingSearchParam != null) {
boolean isBuiltIn = existingSearchParam.getId() == null;
isBuiltIn |= existingSearchParam.getUri().startsWith("http://hl7.org/fhir/SearchParameter/");
@ -221,7 +221,7 @@ public class SearchParameterDaoValidator {
.filter(SearchParameter.SearchParameterComponentComponent::hasDefinition)
.map(SearchParameter.SearchParameterComponentComponent::getDefinition)
.filter(Objects::nonNull)
.map(mySearchParamRegistry::getActiveSearchParamByUrl)
.map((String url) -> mySearchParamRegistry.getActiveSearchParamByUrl(url, null))
.filter(Objects::nonNull)
.forEach(theRuntimeSp -> validateComponentSpTypeAgainstWhiteList(
theRuntimeSp, getAllowedSearchParameterTypes(theSearchParameter)));

View File

@ -130,7 +130,8 @@ public class DaoRegistryGraphQLStorageServices implements IGraphQLStorageService
RuntimeResourceDefinition typeDef = fhirContext.getResourceDefinition(theType);
SearchParameterMap params = new SearchParameterMap();
ResourceSearchParams searchParams = mySearchParamRegistry.getRuntimeSearchParams(typeDef.getName());
ResourceSearchParams searchParams = mySearchParamRegistry.getRuntimeSearchParams(
typeDef.getName(), ISearchParamRegistry.SearchParamLookupContextEnum.SEARCH);
for (Argument nextArgument : resourceSearchParam) {