Add non unique combo search params (#2809)
* Start work on nonunique combo search params * Work on SQL * Version bump * A fix * Test fixes * Fixes * Undo version bump * Test fixes * Resolve fixme
This commit is contained in:
parent
6af022062f
commit
6d37749be8
|
@ -0,0 +1,28 @@
|
||||||
|
package ca.uhn.fhir.context;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Core Library
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2021 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
public enum ComboSearchParamType {
|
||||||
|
|
||||||
|
UNIQUE,
|
||||||
|
NON_UNIQUE
|
||||||
|
|
||||||
|
}
|
|
@ -416,7 +416,7 @@ class ModelScanner {
|
||||||
if (theResourceDef.isStandardType()) {
|
if (theResourceDef.isStandardType()) {
|
||||||
url = "http://hl7.org/fhir/SearchParameter/" + theResourceDef.getName().toLowerCase() + "-" + searchParam.name();
|
url = "http://hl7.org/fhir/SearchParameter/" + theResourceDef.getName().toLowerCase() + "-" + searchParam.name();
|
||||||
}
|
}
|
||||||
RuntimeSearchParam param = new RuntimeSearchParam(null, url, searchParam.name(), searchParam.description(), searchParam.path(), paramType, providesMembershipInCompartments, toTargetList(searchParam.target()), RuntimeSearchParamStatusEnum.ACTIVE, false, components, base);
|
RuntimeSearchParam param = new RuntimeSearchParam(null, url, searchParam.name(), searchParam.description(), searchParam.path(), paramType, providesMembershipInCompartments, toTargetList(searchParam.target()), RuntimeSearchParamStatusEnum.ACTIVE, null, components, base);
|
||||||
theResourceDef.addSearchParam(param);
|
theResourceDef.addSearchParam(param);
|
||||||
nameToParam.put(param.getName(), param);
|
nameToParam.put(param.getName(), param);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.hl7.fhir.instance.model.api.IBaseExtension;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -55,7 +56,7 @@ public class RuntimeSearchParam {
|
||||||
private final RuntimeSearchParamStatusEnum myStatus;
|
private final RuntimeSearchParamStatusEnum myStatus;
|
||||||
private final String myUri;
|
private final String myUri;
|
||||||
private final Map<String, List<IBaseExtension<?, ?>>> myExtensions = new HashMap<>();
|
private final Map<String, List<IBaseExtension<?, ?>>> myExtensions = new HashMap<>();
|
||||||
private final boolean myUnique;
|
private final ComboSearchParamType myComboSearchParamType;
|
||||||
private final List<Component> myComponents;
|
private final List<Component> myComponents;
|
||||||
private IPhoneticEncoder myPhoneticEncoder;
|
private IPhoneticEncoder myPhoneticEncoder;
|
||||||
|
|
||||||
|
@ -64,20 +65,20 @@ public class RuntimeSearchParam {
|
||||||
*/
|
*/
|
||||||
public RuntimeSearchParam(IIdType theId, String theUri, String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType,
|
public RuntimeSearchParam(IIdType theId, String theUri, String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType,
|
||||||
Set<String> theProvidesMembershipInCompartments, Set<String> theTargets, RuntimeSearchParamStatusEnum theStatus, Collection<String> theBase) {
|
Set<String> theProvidesMembershipInCompartments, Set<String> theTargets, RuntimeSearchParamStatusEnum theStatus, Collection<String> theBase) {
|
||||||
this(theId, theUri, theName, theDescription, thePath, theParamType, theProvidesMembershipInCompartments, theTargets, theStatus, false, Collections.emptyList(), theBase);
|
this(theId, theUri, theName, theDescription, thePath, theParamType, theProvidesMembershipInCompartments, theTargets, theStatus, null, Collections.emptyList(), theBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy constructor
|
* Copy constructor
|
||||||
*/
|
*/
|
||||||
public RuntimeSearchParam(RuntimeSearchParam theSp) {
|
public RuntimeSearchParam(RuntimeSearchParam theSp) {
|
||||||
this(theSp.getId(), theSp.getUri(), theSp.getName(), theSp.getDescription(), theSp.getPath(), theSp.getParamType(), theSp.getProvidesMembershipInCompartments(), theSp.getTargets(), theSp.getStatus(), theSp.isUnique(), theSp.getComponents(), theSp.getBase());
|
this(theSp.getId(), theSp.getUri(), theSp.getName(), theSp.getDescription(), theSp.getPath(), theSp.getParamType(), theSp.getProvidesMembershipInCompartments(), theSp.getTargets(), theSp.getStatus(), theSp.getComboSearchParamType(), theSp.getComponents(), theSp.getBase());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public RuntimeSearchParam(IIdType theId, String theUri, String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, Set<String> theProvidesMembershipInCompartments, Set<String> theTargets, RuntimeSearchParamStatusEnum theStatus, boolean theUnique, List<Component> theComponents, Collection<String> theBase) {
|
public RuntimeSearchParam(IIdType theId, String theUri, String theName, String theDescription, String thePath, RestSearchParameterTypeEnum theParamType, Set<String> theProvidesMembershipInCompartments, Set<String> theTargets, RuntimeSearchParamStatusEnum theStatus, ComboSearchParamType theComboSearchParamType, List<Component> theComponents, Collection<String> theBase) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
myId = theId;
|
myId = theId;
|
||||||
|
@ -110,7 +111,7 @@ public class RuntimeSearchParam {
|
||||||
} else {
|
} else {
|
||||||
myBase = Collections.unmodifiableSet(new HashSet<>(theBase));
|
myBase = Collections.unmodifiableSet(new HashSet<>(theBase));
|
||||||
}
|
}
|
||||||
myUnique = theUnique;
|
myComboSearchParamType = theComboSearchParamType;
|
||||||
if (theComponents != null) {
|
if (theComponents != null) {
|
||||||
myComponents = Collections.unmodifiableList(theComponents);
|
myComponents = Collections.unmodifiableList(theComponents);
|
||||||
} else {
|
} else {
|
||||||
|
@ -122,8 +123,12 @@ public class RuntimeSearchParam {
|
||||||
return myComponents;
|
return myComponents;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isUnique() {
|
/**
|
||||||
return myUnique;
|
* Returns <code>null</code> if this is not a combo search param type
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public ComboSearchParamType getComboSearchParamType() {
|
||||||
|
return myComboSearchParamType;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -94,7 +94,8 @@ import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.search.builder.QueryStack;
|
import ca.uhn.fhir.jpa.search.builder.QueryStack;
|
||||||
import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
|
import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.CompositeUniqueSearchParameterPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.ComboNonUniqueSearchParameterPredicateBuilder;
|
||||||
|
import ca.uhn.fhir.jpa.search.builder.predicate.ComboUniqueSearchParameterPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.CoordsPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.CoordsPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.DatePredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.DatePredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.ForcedIdPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.ForcedIdPredicateBuilder;
|
||||||
|
@ -609,8 +610,14 @@ public abstract class BaseConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Scope("prototype")
|
@Scope("prototype")
|
||||||
public CompositeUniqueSearchParameterPredicateBuilder newCompositeUniqueSearchParameterPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
public ComboUniqueSearchParameterPredicateBuilder newComboUniqueSearchParameterPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
||||||
return new CompositeUniqueSearchParameterPredicateBuilder(theSearchSqlBuilder);
|
return new ComboUniqueSearchParameterPredicateBuilder(theSearchSqlBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Scope("prototype")
|
||||||
|
public ComboNonUniqueSearchParameterPredicateBuilder newComboNonUniqueSearchParameterPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
||||||
|
return new ComboNonUniqueSearchParameterPredicateBuilder(theSearchSqlBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
@ -23,7 +23,7 @@ package ca.uhn.fhir.jpa.config;
|
||||||
import ca.uhn.fhir.i18n.HapiLocalizer;
|
import ca.uhn.fhir.i18n.HapiLocalizer;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
import org.hibernate.PessimisticLockException;
|
import org.hibernate.PessimisticLockException;
|
||||||
|
@ -81,7 +81,7 @@ public class HapiFhirHibernateJpaDialect extends HibernateJpaDialect {
|
||||||
if (constraintName.contains(ResourceHistoryTable.IDX_RESVER_ID_VER)) {
|
if (constraintName.contains(ResourceHistoryTable.IDX_RESVER_ID_VER)) {
|
||||||
throw new ResourceVersionConflictException(messageToPrepend + myLocalizer.getMessage(HapiFhirHibernateJpaDialect.class, "resourceVersionConstraintFailure"));
|
throw new ResourceVersionConflictException(messageToPrepend + myLocalizer.getMessage(HapiFhirHibernateJpaDialect.class, "resourceVersionConstraintFailure"));
|
||||||
}
|
}
|
||||||
if (constraintName.contains(ResourceIndexedCompositeStringUnique.IDX_IDXCMPSTRUNIQ_STRING)) {
|
if (constraintName.contains(ResourceIndexedComboStringUnique.IDX_IDXCMPSTRUNIQ_STRING)) {
|
||||||
throw new ResourceVersionConflictException(messageToPrepend + myLocalizer.getMessage(HapiFhirHibernateJpaDialect.class, "resourceIndexedCompositeStringUniqueConstraintFailure"));
|
throw new ResourceVersionConflictException(messageToPrepend + myLocalizer.getMessage(HapiFhirHibernateJpaDialect.class, "resourceIndexedCompositeStringUniqueConstraintFailure"));
|
||||||
}
|
}
|
||||||
if (constraintName.contains(ForcedId.IDX_FORCEDID_TYPE_FID)) {
|
if (constraintName.contains(ForcedId.IDX_FORCEDID_TYPE_FID)) {
|
||||||
|
|
|
@ -129,7 +129,6 @@ import javax.persistence.TypedQuery;
|
||||||
import javax.persistence.criteria.CriteriaBuilder;
|
import javax.persistence.criteria.CriteriaBuilder;
|
||||||
import javax.persistence.criteria.CriteriaQuery;
|
import javax.persistence.criteria.CriteriaQuery;
|
||||||
import javax.persistence.criteria.Root;
|
import javax.persistence.criteria.Root;
|
||||||
import javax.validation.constraints.Null;
|
|
||||||
import javax.xml.stream.events.Characters;
|
import javax.xml.stream.events.Characters;
|
||||||
import javax.xml.stream.events.XMLEvent;
|
import javax.xml.stream.events.XMLEvent;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -1404,7 +1403,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synchronize composite params
|
// Synchronize composite params
|
||||||
mySearchParamWithInlineReferencesExtractor.storeCompositeStringUniques(newParams, entity, existingParams);
|
mySearchParamWithInlineReferencesExtractor.storeUniqueComboParameters(newParams, entity, existingParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
@ -42,7 +43,7 @@ import ca.uhn.fhir.jpa.entity.ResourceSearchView;
|
||||||
import ca.uhn.fhir.jpa.interceptor.JpaPreResourceAccessDetails;
|
import ca.uhn.fhir.jpa.interceptor.JpaPreResourceAccessDetails;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTag;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTag;
|
||||||
|
@ -868,9 +869,11 @@ public class LegacySearchBuilder implements ISearchBuilder {
|
||||||
// Since we're going to remove elements below
|
// Since we're going to remove elements below
|
||||||
theParams.values().forEach(nextAndList -> ensureSubListsAreWritable(nextAndList));
|
theParams.values().forEach(nextAndList -> ensureSubListsAreWritable(nextAndList));
|
||||||
|
|
||||||
List<RuntimeSearchParam> activeUniqueSearchParams = mySearchParamRegistry.getActiveUniqueSearchParams(myResourceName, theParams.keySet());
|
List<RuntimeSearchParam> activeUniqueSearchParams = mySearchParamRegistry.getActiveComboSearchParams(myResourceName, theParams.keySet());
|
||||||
if (activeUniqueSearchParams.size() > 0) {
|
if (activeUniqueSearchParams.size() > 0) {
|
||||||
|
|
||||||
|
Validate.isTrue(activeUniqueSearchParams.get(0).getComboSearchParamType()== ComboSearchParamType.UNIQUE, "Non unique combo parameters are not supported with the legacy search builder");
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(myResourceName);
|
sb.append(myResourceName);
|
||||||
sb.append("?");
|
sb.append("?");
|
||||||
|
@ -943,7 +946,7 @@ public class LegacySearchBuilder implements ISearchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPredicateCompositeStringUnique(@Nonnull SearchParameterMap theParams, String theIndexedString, RequestPartitionId theRequestPartitionId) {
|
private void addPredicateCompositeStringUnique(@Nonnull SearchParameterMap theParams, String theIndexedString, RequestPartitionId theRequestPartitionId) {
|
||||||
From<?, ResourceIndexedCompositeStringUnique> join = myQueryStack.createJoin(SearchBuilderJoinEnum.COMPOSITE_UNIQUE, null);
|
From<?, ResourceIndexedComboStringUnique> join = myQueryStack.createJoin(SearchBuilderJoinEnum.COMPOSITE_UNIQUE, null);
|
||||||
|
|
||||||
if (!theRequestPartitionId.isAllPartitions()) {
|
if (!theRequestPartitionId.isAllPartitions()) {
|
||||||
Integer partitionId = theRequestPartitionId.getFirstPartitionIdOrNull();
|
Integer partitionId = theRequestPartitionId.getFirstPartitionIdOrNull();
|
||||||
|
|
|
@ -20,7 +20,7 @@ package ca.uhn.fhir.jpa.dao.data;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.Modifying;
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
import org.springframework.data.jpa.repository.Query;
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
@ -28,15 +28,15 @@ import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface IResourceIndexedCompositeStringUniqueDao extends JpaRepository<ResourceIndexedCompositeStringUnique, Long> {
|
public interface IResourceIndexedComboStringUniqueDao extends JpaRepository<ResourceIndexedComboStringUnique, Long> {
|
||||||
|
|
||||||
@Query("SELECT r FROM ResourceIndexedCompositeStringUnique r WHERE r.myIndexString = :str")
|
@Query("SELECT r FROM ResourceIndexedComboStringUnique r WHERE r.myIndexString = :str")
|
||||||
ResourceIndexedCompositeStringUnique findByQueryString(@Param("str") String theQueryString);
|
ResourceIndexedComboStringUnique findByQueryString(@Param("str") String theQueryString);
|
||||||
|
|
||||||
@Query("SELECT r FROM ResourceIndexedCompositeStringUnique r WHERE r.myResourceId = :resId")
|
@Query("SELECT r FROM ResourceIndexedComboStringUnique r WHERE r.myResourceId = :resId")
|
||||||
List<ResourceIndexedCompositeStringUnique> findAllForResourceIdForUnitTest(@Param("resId") Long theResourceId);
|
List<ResourceIndexedComboStringUnique> findAllForResourceIdForUnitTest(@Param("resId") Long theResourceId);
|
||||||
|
|
||||||
@Modifying
|
@Modifying
|
||||||
@Query("delete from ResourceIndexedCompositeStringUnique t WHERE t.myResourceId = :resid")
|
@Query("delete from ResourceIndexedComboStringUnique t WHERE t.myResourceId = :resid")
|
||||||
void deleteByResourceId(@Param("resid") Long theResourcePid);
|
void deleteByResourceId(@Param("resid") Long theResourcePid);
|
||||||
}
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package ca.uhn.fhir.jpa.dao.data;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2021 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Modifying;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
|
public interface IResourceIndexedComboTokensNonUniqueDao extends JpaRepository<ResourceIndexedComboTokenNonUnique, Long> {
|
||||||
|
|
||||||
|
@Modifying
|
||||||
|
@Query("DELETE FROM ResourceIndexedComboTokenNonUnique t WHERE t.myResourceId = :res_id")
|
||||||
|
void deleteByResourceId(@Param("res_id") Long theResourcePid);
|
||||||
|
}
|
|
@ -50,7 +50,8 @@ import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionResourceEntity;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryProvenanceEntity;
|
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryProvenanceEntity;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTag;
|
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTag;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||||
|
@ -136,7 +137,8 @@ public class ExpungeEverythingService {
|
||||||
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamToken.class));
|
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamToken.class));
|
||||||
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamUri.class));
|
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamUri.class));
|
||||||
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamCoords.class));
|
counter.addAndGet(expungeEverythingByType(ResourceIndexedSearchParamCoords.class));
|
||||||
counter.addAndGet(expungeEverythingByType(ResourceIndexedCompositeStringUnique.class));
|
counter.addAndGet(expungeEverythingByType(ResourceIndexedComboStringUnique.class));
|
||||||
|
counter.addAndGet(expungeEverythingByType(ResourceIndexedComboTokenNonUnique.class));
|
||||||
counter.addAndGet(expungeEverythingByType(ResourceLink.class));
|
counter.addAndGet(expungeEverythingByType(ResourceLink.class));
|
||||||
counter.addAndGet(expungeEverythingByType(SearchResult.class));
|
counter.addAndGet(expungeEverythingByType(SearchResult.class));
|
||||||
counter.addAndGet(expungeEverythingByType(SearchInclude.class));
|
counter.addAndGet(expungeEverythingByType(SearchInclude.class));
|
||||||
|
|
|
@ -28,7 +28,8 @@ import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTagDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTagDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedComboStringUniqueDao;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedComboTokensNonUniqueDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamCoordsDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamCoordsDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamNumberDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamNumberDao;
|
||||||
|
@ -95,7 +96,9 @@ public class ResourceExpungeService implements IResourceExpungeService {
|
||||||
@Autowired
|
@Autowired
|
||||||
private IResourceIndexedSearchParamNumberDao myResourceIndexedSearchParamNumberDao;
|
private IResourceIndexedSearchParamNumberDao myResourceIndexedSearchParamNumberDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
private IResourceIndexedComboStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
||||||
|
@Autowired
|
||||||
|
private IResourceIndexedComboTokensNonUniqueDao myResourceIndexedComboTokensNonUniqueDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IResourceLinkDao myResourceLinkDao;
|
private IResourceLinkDao myResourceLinkDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -289,9 +292,12 @@ public class ResourceExpungeService implements IResourceExpungeService {
|
||||||
if (resource == null || resource.isParamsTokenPopulated()) {
|
if (resource == null || resource.isParamsTokenPopulated()) {
|
||||||
myResourceIndexedSearchParamTokenDao.deleteByResourceId(theResourceId);
|
myResourceIndexedSearchParamTokenDao.deleteByResourceId(theResourceId);
|
||||||
}
|
}
|
||||||
if (resource == null || resource.isParamsCompositeStringUniquePresent()) {
|
if (resource == null || resource.isParamsComboStringUniquePresent()) {
|
||||||
myResourceIndexedCompositeStringUniqueDao.deleteByResourceId(theResourceId);
|
myResourceIndexedCompositeStringUniqueDao.deleteByResourceId(theResourceId);
|
||||||
}
|
}
|
||||||
|
if (resource == null || resource.isParamsComboTokensNonUniquePresent()) {
|
||||||
|
myResourceIndexedComboTokensNonUniqueDao.deleteByResourceId(theResourceId);
|
||||||
|
}
|
||||||
if (myDaoConfig.getIndexMissingFields() == DaoConfig.IndexEnabledEnum.ENABLED) {
|
if (myDaoConfig.getIndexMissingFields() == DaoConfig.IndexEnabledEnum.ENABLED) {
|
||||||
mySearchParamPresentDao.deleteByResourceId(theResourceId);
|
mySearchParamPresentDao.deleteByResourceId(theResourceId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ public class ResourceTableFKProvider {
|
||||||
// SELECT FKTABLE_NAME, FKCOLUMN_NAME FROM CROSS_REFERENCES WHERE PKTABLE_NAME = 'HFJ_RESOURCE'
|
// SELECT FKTABLE_NAME, FKCOLUMN_NAME FROM CROSS_REFERENCES WHERE PKTABLE_NAME = 'HFJ_RESOURCE'
|
||||||
retval.add(new ResourceForeignKey("HFJ_FORCED_ID", "RESOURCE_PID"));
|
retval.add(new ResourceForeignKey("HFJ_FORCED_ID", "RESOURCE_PID"));
|
||||||
retval.add(new ResourceForeignKey("HFJ_IDX_CMP_STRING_UNIQ", "RES_ID"));
|
retval.add(new ResourceForeignKey("HFJ_IDX_CMP_STRING_UNIQ", "RES_ID"));
|
||||||
|
retval.add(new ResourceForeignKey("HFJ_IDX_CMB_TOK_NU", "RES_ID"));
|
||||||
retval.add(new ResourceForeignKey("HFJ_RES_LINK", "SRC_RESOURCE_ID"));
|
retval.add(new ResourceForeignKey("HFJ_RES_LINK", "SRC_RESOURCE_ID"));
|
||||||
retval.add(new ResourceForeignKey("HFJ_RES_LINK", "TARGET_RESOURCE_ID"));
|
retval.add(new ResourceForeignKey("HFJ_RES_LINK", "TARGET_RESOURCE_ID"));
|
||||||
retval.add(new ResourceForeignKey("HFJ_RES_PARAM_PRESENT", "RES_ID"));
|
retval.add(new ResourceForeignKey("HFJ_RES_PARAM_PRESENT", "RES_ID"));
|
||||||
|
|
|
@ -20,17 +20,11 @@ package ca.uhn.fhir.jpa.dao.index;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
|
||||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndex;
|
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndex;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
|
import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
|
||||||
import ca.uhn.fhir.jpa.util.AddRemoveCount;
|
import ca.uhn.fhir.jpa.util.AddRemoveCount;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
@ -43,15 +37,8 @@ import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class DaoSearchParamSynchronizer {
|
public class DaoSearchParamSynchronizer {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(DaoSearchParamSynchronizer.class);
|
|
||||||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||||
protected EntityManager myEntityManager;
|
protected EntityManager myEntityManager;
|
||||||
@Autowired
|
|
||||||
private DaoConfig myDaoConfig;
|
|
||||||
@Autowired
|
|
||||||
private PartitionSettings myPartitionSettings;
|
|
||||||
@Autowired
|
|
||||||
private ModelConfig myModelConfig;
|
|
||||||
|
|
||||||
public AddRemoveCount synchronizeSearchParamsToDatabase(ResourceIndexedSearchParams theParams, ResourceTable theEntity, ResourceIndexedSearchParams existingParams) {
|
public AddRemoveCount synchronizeSearchParamsToDatabase(ResourceIndexedSearchParams theParams, ResourceTable theEntity, ResourceIndexedSearchParams existingParams) {
|
||||||
AddRemoveCount retVal = new AddRemoveCount();
|
AddRemoveCount retVal = new AddRemoveCount();
|
||||||
|
@ -65,6 +52,7 @@ public class DaoSearchParamSynchronizer {
|
||||||
synchronize(theEntity, retVal, theParams.myUriParams, existingParams.myUriParams);
|
synchronize(theEntity, retVal, theParams.myUriParams, existingParams.myUriParams);
|
||||||
synchronize(theEntity, retVal, theParams.myCoordsParams, existingParams.myCoordsParams);
|
synchronize(theEntity, retVal, theParams.myCoordsParams, existingParams.myCoordsParams);
|
||||||
synchronize(theEntity, retVal, theParams.myLinks, existingParams.myLinks);
|
synchronize(theEntity, retVal, theParams.myLinks, existingParams.myLinks);
|
||||||
|
synchronize(theEntity, retVal, theParams.myComboTokenNonUnique, existingParams.myComboTokenNonUnique);
|
||||||
|
|
||||||
// make sure links are indexed
|
// make sure links are indexed
|
||||||
theEntity.setResourceLinks(theParams.myLinks);
|
theEntity.setResourceLinks(theParams.myLinks);
|
||||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.dao.index;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
|
@ -27,17 +28,19 @@ import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||||
import ca.uhn.fhir.jpa.dao.MatchResourceUrlService;
|
import ca.uhn.fhir.jpa.dao.MatchResourceUrlService;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedComboStringUniqueDao;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||||
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
|
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
|
import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
|
||||||
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorService;
|
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorService;
|
||||||
import ca.uhn.fhir.jpa.searchparam.util.JpaParamUtil;
|
import ca.uhn.fhir.jpa.searchparam.util.JpaParamUtil;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
|
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||||
|
@ -46,15 +49,18 @@ import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.util.FhirTerser;
|
import ca.uhn.fhir.util.FhirTerser;
|
||||||
|
import ca.uhn.fhir.util.StringUtil;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseReference;
|
import org.hl7.fhir.instance.model.api.IBaseReference;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.PersistenceContext;
|
import javax.persistence.PersistenceContext;
|
||||||
import javax.persistence.PersistenceContextType;
|
import javax.persistence.PersistenceContextType;
|
||||||
|
@ -64,8 +70,10 @@ import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
|
@ -92,7 +100,7 @@ public class SearchParamWithInlineReferencesExtractor {
|
||||||
@Autowired
|
@Autowired
|
||||||
private DaoSearchParamSynchronizer myDaoSearchParamSynchronizer;
|
private DaoSearchParamSynchronizer myDaoSearchParamSynchronizer;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
private IResourceIndexedComboStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
private PartitionSettings myPartitionSettings;
|
private PartitionSettings myPartitionSettings;
|
||||||
|
|
||||||
|
@ -140,7 +148,7 @@ public class SearchParamWithInlineReferencesExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle composites
|
* Handle combo parameters
|
||||||
*/
|
*/
|
||||||
extractCompositeStringUniques(theEntity, theParams);
|
extractCompositeStringUniques(theEntity, theParams);
|
||||||
}
|
}
|
||||||
|
@ -148,86 +156,152 @@ public class SearchParamWithInlineReferencesExtractor {
|
||||||
private void extractCompositeStringUniques(ResourceTable theEntity, ResourceIndexedSearchParams theParams) {
|
private void extractCompositeStringUniques(ResourceTable theEntity, ResourceIndexedSearchParams theParams) {
|
||||||
|
|
||||||
final String resourceType = theEntity.getResourceType();
|
final String resourceType = theEntity.getResourceType();
|
||||||
List<RuntimeSearchParam> uniqueSearchParams = mySearchParamRegistry.getActiveUniqueSearchParams(resourceType);
|
List<RuntimeSearchParam> comboSearchParams = mySearchParamRegistry.getActiveComboSearchParams(resourceType);
|
||||||
|
|
||||||
for (RuntimeSearchParam next : uniqueSearchParams) {
|
for (RuntimeSearchParam next : comboSearchParams) {
|
||||||
|
switch (Objects.requireNonNull(next.getComboSearchParamType())) {
|
||||||
|
case UNIQUE:
|
||||||
|
extractComboUniqueParam(theEntity, theParams, resourceType, next);
|
||||||
|
break;
|
||||||
|
case NON_UNIQUE:
|
||||||
|
extractComboNonUniqueParam(theEntity, theParams, resourceType, next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<List<String>> partsChoices = new ArrayList<>();
|
private void extractComboNonUniqueParam(ResourceTable theEntity, ResourceIndexedSearchParams theParams, String theResourceType, RuntimeSearchParam theParam) {
|
||||||
|
Set<String> queryStringsToPopulate = extractParameterCombinationsForComboParam(theParams, theResourceType, theParam);
|
||||||
|
|
||||||
List<RuntimeSearchParam> compositeComponents = JpaParamUtil.resolveComponentParameters(mySearchParamRegistry, next);
|
for (String nextQueryString : queryStringsToPopulate) {
|
||||||
for (RuntimeSearchParam nextCompositeOf : compositeComponents) {
|
ourLog.trace("Adding composite unique SP: {}", nextQueryString);
|
||||||
Collection<? extends BaseResourceIndexedSearchParam> paramsListForCompositePart = null;
|
theParams.myComboTokenNonUnique.add(new ResourceIndexedComboTokenNonUnique(myPartitionSettings, theEntity, nextQueryString));
|
||||||
Collection<ResourceLink> linksForCompositePart = null;
|
}
|
||||||
Collection<String> linksForCompositePartWantPaths = null;
|
}
|
||||||
switch (nextCompositeOf.getParamType()) {
|
|
||||||
case NUMBER:
|
|
||||||
paramsListForCompositePart = theParams.myNumberParams;
|
|
||||||
break;
|
|
||||||
case DATE:
|
|
||||||
paramsListForCompositePart = theParams.myDateParams;
|
|
||||||
break;
|
|
||||||
case STRING:
|
|
||||||
paramsListForCompositePart = theParams.myStringParams;
|
|
||||||
break;
|
|
||||||
case TOKEN:
|
|
||||||
paramsListForCompositePart = theParams.myTokenParams;
|
|
||||||
break;
|
|
||||||
case REFERENCE:
|
|
||||||
linksForCompositePart = theParams.myLinks;
|
|
||||||
linksForCompositePartWantPaths = new HashSet<>(nextCompositeOf.getPathsSplit());
|
|
||||||
break;
|
|
||||||
case QUANTITY:
|
|
||||||
paramsListForCompositePart = theParams.myQuantityParams;
|
|
||||||
break;
|
|
||||||
case URI:
|
|
||||||
paramsListForCompositePart = theParams.myUriParams;
|
|
||||||
break;
|
|
||||||
case SPECIAL:
|
|
||||||
case COMPOSITE:
|
|
||||||
case HAS:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ArrayList<String> nextChoicesList = new ArrayList<>();
|
private void extractComboUniqueParam(ResourceTable theEntity, ResourceIndexedSearchParams theParams, String theResourceType, RuntimeSearchParam theParam) {
|
||||||
partsChoices.add(nextChoicesList);
|
Set<String> queryStringsToPopulate = extractParameterCombinationsForComboParam(theParams, theResourceType, theParam);
|
||||||
|
|
||||||
String key = UrlUtil.escapeUrlParam(nextCompositeOf.getName());
|
for (String nextQueryString : queryStringsToPopulate) {
|
||||||
if (paramsListForCompositePart != null) {
|
ourLog.trace("Adding composite unique SP: {}", nextQueryString);
|
||||||
for (BaseResourceIndexedSearchParam nextParam : paramsListForCompositePart) {
|
theParams.myComboStringUniques.add(new ResourceIndexedComboStringUnique(theEntity, nextQueryString, theParam.getId()));
|
||||||
if (nextParam.getParamName().equals(nextCompositeOf.getName())) {
|
}
|
||||||
IQueryParameterType nextParamAsClientParam = nextParam.toQueryParameterType();
|
}
|
||||||
String value = nextParamAsClientParam.getValueAsQueryToken(myContext);
|
|
||||||
if (isNotBlank(value)) {
|
@Nonnull
|
||||||
value = UrlUtil.escapeUrlParam(value);
|
private Set<String> extractParameterCombinationsForComboParam(ResourceIndexedSearchParams theParams, String theResourceType, RuntimeSearchParam theParam) {
|
||||||
nextChoicesList.add(key + "=" + value);
|
List<List<String>> partsChoices = new ArrayList<>();
|
||||||
}
|
|
||||||
}
|
List<RuntimeSearchParam> compositeComponents = JpaParamUtil.resolveComponentParameters(mySearchParamRegistry, theParam);
|
||||||
|
for (RuntimeSearchParam nextCompositeOf : compositeComponents) {
|
||||||
|
Collection<? extends BaseResourceIndexedSearchParam> paramsListForCompositePart = findParameterIndexes(theParams, nextCompositeOf);
|
||||||
|
|
||||||
|
Collection<ResourceLink> linksForCompositePart = null;
|
||||||
|
switch (nextCompositeOf.getParamType()) {
|
||||||
|
case REFERENCE:
|
||||||
|
linksForCompositePart = theParams.myLinks;
|
||||||
|
break;
|
||||||
|
case NUMBER:
|
||||||
|
case DATE:
|
||||||
|
case STRING:
|
||||||
|
case TOKEN:
|
||||||
|
case QUANTITY:
|
||||||
|
case URI:
|
||||||
|
case SPECIAL:
|
||||||
|
case COMPOSITE:
|
||||||
|
case HAS:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Collection<String> linksForCompositePartWantPaths = null;
|
||||||
|
switch (nextCompositeOf.getParamType()) {
|
||||||
|
case REFERENCE:
|
||||||
|
linksForCompositePartWantPaths = new HashSet<>(nextCompositeOf.getPathsSplit());
|
||||||
|
break;
|
||||||
|
case NUMBER:
|
||||||
|
case DATE:
|
||||||
|
case STRING:
|
||||||
|
case TOKEN:
|
||||||
|
case QUANTITY:
|
||||||
|
case URI:
|
||||||
|
case SPECIAL:
|
||||||
|
case COMPOSITE:
|
||||||
|
case HAS:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<String> nextChoicesList = new ArrayList<>();
|
||||||
|
partsChoices.add(nextChoicesList);
|
||||||
|
|
||||||
|
String key = UrlUtil.escapeUrlParam(nextCompositeOf.getName());
|
||||||
|
if (paramsListForCompositePart != null) {
|
||||||
|
for (BaseResourceIndexedSearchParam nextParam : paramsListForCompositePart) {
|
||||||
|
IQueryParameterType nextParamAsClientParam = nextParam.toQueryParameterType();
|
||||||
|
String value = nextParamAsClientParam.getValueAsQueryToken(myContext);
|
||||||
|
|
||||||
|
RuntimeSearchParam param = mySearchParamRegistry.getActiveSearchParam(theResourceType, key);
|
||||||
|
if (theParam.getComboSearchParamType() == ComboSearchParamType.NON_UNIQUE && param != null && param.getParamType() == RestSearchParameterTypeEnum.STRING) {
|
||||||
|
value = StringUtil.normalizeStringForSearchIndexing(value);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (linksForCompositePart != null) {
|
if (isNotBlank(value)) {
|
||||||
for (ResourceLink nextLink : linksForCompositePart) {
|
value = UrlUtil.escapeUrlParam(value);
|
||||||
if (linksForCompositePartWantPaths.contains(nextLink.getSourcePath())) {
|
nextChoicesList.add(key + "=" + value);
|
||||||
assert isNotBlank(nextLink.getTargetResourceType());
|
|
||||||
assert isNotBlank(nextLink.getTargetResourceId());
|
|
||||||
String value = nextLink.getTargetResourceType() + "/" + nextLink.getTargetResourceId();
|
|
||||||
if (isNotBlank(value)) {
|
|
||||||
value = UrlUtil.escapeUrlParam(value);
|
|
||||||
nextChoicesList.add(key + "=" + value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (linksForCompositePart != null) {
|
||||||
Set<String> queryStringsToPopulate = ResourceIndexedSearchParams.extractCompositeStringUniquesValueChains(resourceType, partsChoices);
|
for (ResourceLink nextLink : linksForCompositePart) {
|
||||||
|
if (linksForCompositePartWantPaths.contains(nextLink.getSourcePath())) {
|
||||||
for (String nextQueryString : queryStringsToPopulate) {
|
assert isNotBlank(nextLink.getTargetResourceType());
|
||||||
if (isNotBlank(nextQueryString)) {
|
assert isNotBlank(nextLink.getTargetResourceId());
|
||||||
ourLog.trace("Adding composite unique SP: {}", nextQueryString);
|
String value = nextLink.getTargetResourceType() + "/" + nextLink.getTargetResourceId();
|
||||||
theParams.myCompositeStringUniques.add(new ResourceIndexedCompositeStringUnique(theEntity, nextQueryString, next.getId()));
|
if (isNotBlank(value)) {
|
||||||
|
value = UrlUtil.escapeUrlParam(value);
|
||||||
|
nextChoicesList.add(key + "=" + value);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ResourceIndexedSearchParams.extractCompositeStringUniquesValueChains(theResourceType, partsChoices);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private Collection<? extends BaseResourceIndexedSearchParam> findParameterIndexes(ResourceIndexedSearchParams theParams, RuntimeSearchParam nextCompositeOf) {
|
||||||
|
Collection<? extends BaseResourceIndexedSearchParam> paramsListForCompositePart = null;
|
||||||
|
switch (nextCompositeOf.getParamType()) {
|
||||||
|
case NUMBER:
|
||||||
|
paramsListForCompositePart = theParams.myNumberParams;
|
||||||
|
break;
|
||||||
|
case DATE:
|
||||||
|
paramsListForCompositePart = theParams.myDateParams;
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
paramsListForCompositePart = theParams.myStringParams;
|
||||||
|
break;
|
||||||
|
case TOKEN:
|
||||||
|
paramsListForCompositePart = theParams.myTokenParams;
|
||||||
|
break;
|
||||||
|
case QUANTITY:
|
||||||
|
paramsListForCompositePart = theParams.myQuantityParams;
|
||||||
|
break;
|
||||||
|
case URI:
|
||||||
|
paramsListForCompositePart = theParams.myUriParams;
|
||||||
|
break;
|
||||||
|
case REFERENCE:
|
||||||
|
case SPECIAL:
|
||||||
|
case COMPOSITE:
|
||||||
|
case HAS:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (paramsListForCompositePart != null) {
|
||||||
|
paramsListForCompositePart = paramsListForCompositePart
|
||||||
|
.stream()
|
||||||
|
.filter(t->t.getParamName().equals(nextCompositeOf.getName()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
return paramsListForCompositePart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -309,19 +383,21 @@ public class SearchParamWithInlineReferencesExtractor {
|
||||||
myDaoSearchParamSynchronizer = theDaoSearchParamSynchronizer;
|
myDaoSearchParamSynchronizer = theDaoSearchParamSynchronizer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void storeCompositeStringUniques(ResourceIndexedSearchParams theParams, ResourceTable theEntity, ResourceIndexedSearchParams existingParams) {
|
public void storeUniqueComboParameters(ResourceIndexedSearchParams theParams, ResourceTable theEntity, ResourceIndexedSearchParams theExistingParams) {
|
||||||
|
|
||||||
// Store composite string uniques
|
/*
|
||||||
|
* String Uniques
|
||||||
|
*/
|
||||||
if (myDaoConfig.isUniqueIndexesEnabled()) {
|
if (myDaoConfig.isUniqueIndexesEnabled()) {
|
||||||
for (ResourceIndexedCompositeStringUnique next : myDaoSearchParamSynchronizer.subtract(existingParams.myCompositeStringUniques, theParams.myCompositeStringUniques)) {
|
for (ResourceIndexedComboStringUnique next : myDaoSearchParamSynchronizer.subtract(theExistingParams.myComboStringUniques, theParams.myComboStringUniques)) {
|
||||||
ourLog.debug("Removing unique index: {}", next);
|
ourLog.debug("Removing unique index: {}", next);
|
||||||
myEntityManager.remove(next);
|
myEntityManager.remove(next);
|
||||||
theEntity.getParamsCompositeStringUnique().remove(next);
|
theEntity.getParamsComboStringUnique().remove(next);
|
||||||
}
|
}
|
||||||
boolean haveNewParams = false;
|
boolean haveNewStringUniqueParams = false;
|
||||||
for (ResourceIndexedCompositeStringUnique next : myDaoSearchParamSynchronizer.subtract(theParams.myCompositeStringUniques, existingParams.myCompositeStringUniques)) {
|
for (ResourceIndexedComboStringUnique next : myDaoSearchParamSynchronizer.subtract(theParams.myComboStringUniques, theExistingParams.myComboStringUniques)) {
|
||||||
if (myDaoConfig.isUniqueIndexesCheckedBeforeSave()) {
|
if (myDaoConfig.isUniqueIndexesCheckedBeforeSave()) {
|
||||||
ResourceIndexedCompositeStringUnique existing = myResourceIndexedCompositeStringUniqueDao.findByQueryString(next.getIndexString());
|
ResourceIndexedComboStringUnique existing = myResourceIndexedCompositeStringUniqueDao.findByQueryString(next.getIndexString());
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
|
|
||||||
String searchParameterId = "(unknown)";
|
String searchParameterId = "(unknown)";
|
||||||
|
@ -335,12 +411,12 @@ public class SearchParamWithInlineReferencesExtractor {
|
||||||
}
|
}
|
||||||
ourLog.debug("Persisting unique index: {}", next);
|
ourLog.debug("Persisting unique index: {}", next);
|
||||||
myEntityManager.persist(next);
|
myEntityManager.persist(next);
|
||||||
haveNewParams = true;
|
haveNewStringUniqueParams = true;
|
||||||
}
|
}
|
||||||
if (theParams.myCompositeStringUniques.size() > 0 || haveNewParams) {
|
if (theParams.myComboStringUniques.size() > 0 || haveNewStringUniqueParams) {
|
||||||
theEntity.setParamsCompositeStringUniquePresent(true);
|
theEntity.setParamsComboStringUniquePresent(true);
|
||||||
} else {
|
} else {
|
||||||
theEntity.setParamsCompositeStringUniquePresent(false);
|
theEntity.setParamsComboStringUniquePresent(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,7 +170,7 @@ class QueryRootEntryResourceTable extends QueryRootEntry {
|
||||||
join = myResourceTableRoot.join("mySearchParamPresents", JoinType.LEFT);
|
join = myResourceTableRoot.join("mySearchParamPresents", JoinType.LEFT);
|
||||||
break;
|
break;
|
||||||
case COMPOSITE_UNIQUE:
|
case COMPOSITE_UNIQUE:
|
||||||
join = myResourceTableRoot.join("myParamsCompositeStringUnique", JoinType.LEFT);
|
join = myResourceTableRoot.join("myParamsComboStringUnique", JoinType.LEFT);
|
||||||
break;
|
break;
|
||||||
case RESOURCE_TAGS:
|
case RESOURCE_TAGS:
|
||||||
join = myResourceTableRoot.join("myTags", JoinType.LEFT);
|
join = myResourceTableRoot.join("myTags", JoinType.LEFT);
|
||||||
|
|
|
@ -34,7 +34,8 @@ import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||||
import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
|
import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
|
||||||
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.BaseJoiningPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.BaseJoiningPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.CompositeUniqueSearchParameterPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.ComboNonUniqueSearchParameterPredicateBuilder;
|
||||||
|
import ca.uhn.fhir.jpa.search.builder.predicate.ComboUniqueSearchParameterPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.CoordsPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.CoordsPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.DatePredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.DatePredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.ForcedIdPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.ForcedIdPredicateBuilder;
|
||||||
|
@ -1214,11 +1215,18 @@ public class QueryStack {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPredicateCompositeUnique(String theIndexString, RequestPartitionId theRequestPartitionId) {
|
public void addPredicateCompositeUnique(String theIndexString, RequestPartitionId theRequestPartitionId) {
|
||||||
CompositeUniqueSearchParameterPredicateBuilder predicateBuilder = mySqlBuilder.addCompositeUniquePredicateBuilder();
|
ComboUniqueSearchParameterPredicateBuilder predicateBuilder = mySqlBuilder.addComboUniquePredicateBuilder();
|
||||||
Condition predicate = predicateBuilder.createPredicateIndexString(theRequestPartitionId, theIndexString);
|
Condition predicate = predicateBuilder.createPredicateIndexString(theRequestPartitionId, theIndexString);
|
||||||
mySqlBuilder.addPredicate(predicate);
|
mySqlBuilder.addPredicate(predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addPredicateCompositeNonUnique(String theIndexString, RequestPartitionId theRequestPartitionId) {
|
||||||
|
ComboNonUniqueSearchParameterPredicateBuilder predicateBuilder = mySqlBuilder.addComboNonUniquePredicateBuilder();
|
||||||
|
Condition predicate = predicateBuilder.createPredicateHashComplete(theRequestPartitionId, theIndexString);
|
||||||
|
mySqlBuilder.addPredicate(predicate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void addPredicateEverythingOperation(String theResourceName, Long theTargetPid) {
|
public void addPredicateEverythingOperation(String theResourceName, Long theTargetPid) {
|
||||||
ResourceLinkPredicateBuilder table = mySqlBuilder.addReferencePredicateBuilder(this, null);
|
ResourceLinkPredicateBuilder table = mySqlBuilder.addReferencePredicateBuilder(this, null);
|
||||||
Condition predicate = table.createEverythingPredicate(theResourceName, theTargetPid);
|
Condition predicate = table.createEverythingPredicate(theResourceName, theTargetPid);
|
||||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.search.builder;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
|
@ -85,6 +86,7 @@ import ca.uhn.fhir.rest.param.StringParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
|
import ca.uhn.fhir.util.StringUtil;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
@ -119,6 +121,7 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
@ -213,7 +216,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
|
|
||||||
// Attempt to lookup via composite unique key.
|
// Attempt to lookup via composite unique key.
|
||||||
if (isCompositeUniqueSpCandidate()) {
|
if (isCompositeUniqueSpCandidate()) {
|
||||||
attemptCompositeUniqueSpProcessing(theQueryStack, theParams, theRequest);
|
attemptComboUniqueSpProcessing(theQueryStack, theParams, theRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
SearchContainedModeEnum searchContainedMode = theParams.getSearchContainedMode();
|
SearchContainedModeEnum searchContainedMode = theParams.getSearchContainedMode();
|
||||||
|
@ -366,7 +369,10 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
QueryStack queryStack3 = new QueryStack(theParams, myDaoConfig, myDaoConfig.getModelConfig(), myContext, sqlBuilder, mySearchParamRegistry, myPartitionSettings);
|
QueryStack queryStack3 = new QueryStack(theParams, myDaoConfig, myDaoConfig.getModelConfig(), myContext, sqlBuilder, mySearchParamRegistry, myPartitionSettings);
|
||||||
|
|
||||||
if (theParams.keySet().size() > 1 || theParams.getSort() != null || theParams.keySet().contains(Constants.PARAM_HAS)) {
|
if (theParams.keySet().size() > 1 || theParams.getSort() != null || theParams.keySet().contains(Constants.PARAM_HAS)) {
|
||||||
sqlBuilder.setNeedResourceTableRoot(true);
|
List<RuntimeSearchParam> activeComboParams = mySearchParamRegistry.getActiveComboSearchParams(myResourceName, theParams.keySet());
|
||||||
|
if (activeComboParams.isEmpty()) {
|
||||||
|
sqlBuilder.setNeedResourceTableRoot(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JdbcTemplate jdbcTemplate = new JdbcTemplate(myEntityManagerFactory.getDataSource());
|
JdbcTemplate jdbcTemplate = new JdbcTemplate(myEntityManagerFactory.getDataSource());
|
||||||
|
@ -1009,12 +1015,34 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void attemptCompositeUniqueSpProcessing(QueryStack theQueryStack3, @Nonnull SearchParameterMap theParams, RequestDetails theRequest) {
|
private void attemptComboUniqueSpProcessing(QueryStack theQueryStack3, @Nonnull SearchParameterMap theParams, RequestDetails theRequest) {
|
||||||
// Since we're going to remove elements below
|
RuntimeSearchParam comboParam = null;
|
||||||
theParams.values().forEach(nextAndList -> ensureSubListsAreWritable(nextAndList));
|
List<String> comboParamNames = null;
|
||||||
|
List<RuntimeSearchParam> exactMatchParams = mySearchParamRegistry.getActiveComboSearchParams(myResourceName, theParams.keySet());
|
||||||
|
if (exactMatchParams.size() > 0) {
|
||||||
|
comboParam = exactMatchParams.get(0);
|
||||||
|
comboParamNames = new ArrayList<>(theParams.keySet());
|
||||||
|
}
|
||||||
|
|
||||||
List<RuntimeSearchParam> activeUniqueSearchParams = mySearchParamRegistry.getActiveUniqueSearchParams(myResourceName, theParams.keySet());
|
if (comboParam == null) {
|
||||||
if (activeUniqueSearchParams.size() > 0) {
|
List<RuntimeSearchParam> candidateComboParams = mySearchParamRegistry.getActiveComboSearchParams(myResourceName);
|
||||||
|
for (RuntimeSearchParam nextCandidate : candidateComboParams) {
|
||||||
|
List<String> nextCandidateParamNames = JpaParamUtil
|
||||||
|
.resolveComponentParameters(mySearchParamRegistry, nextCandidate)
|
||||||
|
.stream()
|
||||||
|
.map(t -> t.getName())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
if (theParams.keySet().containsAll(nextCandidateParamNames)) {
|
||||||
|
comboParam = nextCandidate;
|
||||||
|
comboParamNames = nextCandidateParamNames;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comboParam != null) {
|
||||||
|
// Since we're going to remove elements below
|
||||||
|
theParams.values().forEach(nextAndList -> ensureSubListsAreWritable(nextAndList));
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(myResourceName);
|
sb.append(myResourceName);
|
||||||
|
@ -1022,9 +1050,8 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
|
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
|
|
||||||
ArrayList<String> keys = new ArrayList<>(theParams.keySet());
|
Collections.sort(comboParamNames);
|
||||||
Collections.sort(keys);
|
for (String nextParamName : comboParamNames) {
|
||||||
for (String nextParamName : keys) {
|
|
||||||
List<List<IQueryParameterType>> nextValues = theParams.get(nextParamName);
|
List<List<IQueryParameterType>> nextValues = theParams.get(nextParamName);
|
||||||
|
|
||||||
nextParamName = UrlUtil.escapeUrlParam(nextParamName);
|
nextParamName = UrlUtil.escapeUrlParam(nextParamName);
|
||||||
|
@ -1047,6 +1074,13 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
List<? extends IQueryParameterType> nextAnd = nextValues.remove(0);
|
List<? extends IQueryParameterType> nextAnd = nextValues.remove(0);
|
||||||
IQueryParameterType nextOr = nextAnd.remove(0);
|
IQueryParameterType nextOr = nextAnd.remove(0);
|
||||||
String nextOrValue = nextOr.getValueAsQueryToken(myContext);
|
String nextOrValue = nextOr.getValueAsQueryToken(myContext);
|
||||||
|
|
||||||
|
if (comboParam.getComboSearchParamType() == ComboSearchParamType.NON_UNIQUE) {
|
||||||
|
if (nextParamDef.getParamType() == RestSearchParameterTypeEnum.STRING) {
|
||||||
|
nextOrValue = StringUtil.normalizeStringForSearchIndexing(nextOrValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
nextOrValue = UrlUtil.escapeUrlParam(nextOrValue);
|
nextOrValue = UrlUtil.escapeUrlParam(nextOrValue);
|
||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
|
@ -1061,18 +1095,25 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
|
|
||||||
if (sb != null) {
|
if (sb != null) {
|
||||||
String indexString = sb.toString();
|
String indexString = sb.toString();
|
||||||
ourLog.debug("Checking for unique index for query: {}", indexString);
|
ourLog.debug("Checking for {} combo index for query: {}", comboParam.getComboSearchParamType(), indexString);
|
||||||
|
|
||||||
// Interceptor broadcast: JPA_PERFTRACE_INFO
|
// Interceptor broadcast: JPA_PERFTRACE_INFO
|
||||||
StorageProcessingMessage msg = new StorageProcessingMessage()
|
StorageProcessingMessage msg = new StorageProcessingMessage()
|
||||||
.setMessage("Using unique index for query for search: " + indexString);
|
.setMessage("Using " + comboParam.getComboSearchParamType() + " index for query for search: " + indexString);
|
||||||
HookParams params = new HookParams()
|
HookParams params = new HookParams()
|
||||||
.add(RequestDetails.class, theRequest)
|
.add(RequestDetails.class, theRequest)
|
||||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||||
.add(StorageProcessingMessage.class, msg);
|
.add(StorageProcessingMessage.class, msg);
|
||||||
CompositeInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequest, Pointcut.JPA_PERFTRACE_INFO, params);
|
CompositeInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequest, Pointcut.JPA_PERFTRACE_INFO, params);
|
||||||
|
|
||||||
theQueryStack3.addPredicateCompositeUnique(indexString, myRequestPartitionId);
|
switch (comboParam.getComboSearchParamType()) {
|
||||||
|
case UNIQUE:
|
||||||
|
theQueryStack3.addPredicateCompositeUnique(indexString, myRequestPartitionId);
|
||||||
|
break;
|
||||||
|
case NON_UNIQUE:
|
||||||
|
theQueryStack3.addPredicateCompositeNonUnique(indexString, myRequestPartitionId);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove any empty parameters remaining after this
|
// Remove any empty parameters remaining after this
|
||||||
theParams.clean();
|
theParams.clean();
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package ca.uhn.fhir.jpa.search.builder.predicate;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2021 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
|
import ca.uhn.fhir.jpa.search.builder.sql.SearchQueryBuilder;
|
||||||
|
import com.healthmarketscience.sqlbuilder.BinaryCondition;
|
||||||
|
import com.healthmarketscience.sqlbuilder.Condition;
|
||||||
|
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
|
||||||
|
|
||||||
|
public class ComboNonUniqueSearchParameterPredicateBuilder extends BaseSearchParamPredicateBuilder {
|
||||||
|
|
||||||
|
private final DbColumn myColumnIndexString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public ComboNonUniqueSearchParameterPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
||||||
|
super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_IDX_CMB_TOK_NU"));
|
||||||
|
|
||||||
|
myColumnIndexString = getTable().addColumn("IDX_STRING");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Condition createPredicateHashComplete(RequestPartitionId theRequestPartitionId, String theIndexString) {
|
||||||
|
BinaryCondition predicate = BinaryCondition.equalTo(myColumnIndexString, generatePlaceholder(theIndexString));
|
||||||
|
return combineWithRequestPartitionIdPredicate(theRequestPartitionId, predicate);
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,14 +26,14 @@ import com.healthmarketscience.sqlbuilder.BinaryCondition;
|
||||||
import com.healthmarketscience.sqlbuilder.Condition;
|
import com.healthmarketscience.sqlbuilder.Condition;
|
||||||
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
|
import com.healthmarketscience.sqlbuilder.dbspec.basic.DbColumn;
|
||||||
|
|
||||||
public class CompositeUniqueSearchParameterPredicateBuilder extends BaseSearchParamPredicateBuilder {
|
public class ComboUniqueSearchParameterPredicateBuilder extends BaseSearchParamPredicateBuilder {
|
||||||
|
|
||||||
private final DbColumn myColumnString;
|
private final DbColumn myColumnString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public CompositeUniqueSearchParameterPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
public ComboUniqueSearchParameterPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
||||||
super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_IDX_CMP_STRING_UNIQ"));
|
super(theSearchSqlBuilder, theSearchSqlBuilder.addTable("HFJ_IDX_CMP_STRING_UNIQ"));
|
||||||
|
|
||||||
myColumnString = getTable().addColumn("IDX_STRING");
|
myColumnString = getTable().addColumn("IDX_STRING");
|
|
@ -27,7 +27,8 @@ import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.search.builder.QueryStack;
|
import ca.uhn.fhir.jpa.search.builder.QueryStack;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.BaseJoiningPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.BaseJoiningPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.CompositeUniqueSearchParameterPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.ComboNonUniqueSearchParameterPredicateBuilder;
|
||||||
|
import ca.uhn.fhir.jpa.search.builder.predicate.ComboUniqueSearchParameterPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.CoordsPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.CoordsPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.DatePredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.DatePredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.ForcedIdPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.ForcedIdPredicateBuilder;
|
||||||
|
@ -145,12 +146,20 @@ public class SearchQueryBuilder {
|
||||||
/**
|
/**
|
||||||
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a Composite Unique search parameter
|
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a Composite Unique search parameter
|
||||||
*/
|
*/
|
||||||
public CompositeUniqueSearchParameterPredicateBuilder addCompositeUniquePredicateBuilder() {
|
public ComboUniqueSearchParameterPredicateBuilder addComboUniquePredicateBuilder() {
|
||||||
CompositeUniqueSearchParameterPredicateBuilder retVal = mySqlBuilderFactory.newCompositeUniqueSearchParameterPredicateBuilder(this);
|
ComboUniqueSearchParameterPredicateBuilder retVal = mySqlBuilderFactory.newComboUniqueSearchParameterPredicateBuilder(this);
|
||||||
addTable(retVal, null);
|
addTable(retVal, null);
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a Composite Unique search parameter
|
||||||
|
*/
|
||||||
|
public ComboNonUniqueSearchParameterPredicateBuilder addComboNonUniquePredicateBuilder() {
|
||||||
|
ComboNonUniqueSearchParameterPredicateBuilder retVal = mySqlBuilderFactory.newComboNonUniqueSearchParameterPredicateBuilder(this);
|
||||||
|
addTable(retVal, null);
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a COORDS search parameter
|
* Add and return a predicate builder (or a root query if no root query exists yet) for selecting on a COORDS search parameter
|
||||||
|
|
|
@ -21,7 +21,8 @@ package ca.uhn.fhir.jpa.search.builder.sql;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.search.builder.QueryStack;
|
import ca.uhn.fhir.jpa.search.builder.QueryStack;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.CompositeUniqueSearchParameterPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.ComboNonUniqueSearchParameterPredicateBuilder;
|
||||||
|
import ca.uhn.fhir.jpa.search.builder.predicate.ComboUniqueSearchParameterPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.CoordsPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.CoordsPredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.DatePredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.DatePredicateBuilder;
|
||||||
import ca.uhn.fhir.jpa.search.builder.predicate.ForcedIdPredicateBuilder;
|
import ca.uhn.fhir.jpa.search.builder.predicate.ForcedIdPredicateBuilder;
|
||||||
|
@ -45,10 +46,15 @@ public class SqlObjectFactory {
|
||||||
@Autowired
|
@Autowired
|
||||||
private ApplicationContext myApplicationContext;
|
private ApplicationContext myApplicationContext;
|
||||||
|
|
||||||
public CompositeUniqueSearchParameterPredicateBuilder newCompositeUniqueSearchParameterPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
public ComboUniqueSearchParameterPredicateBuilder newComboUniqueSearchParameterPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
||||||
return myApplicationContext.getBean(CompositeUniqueSearchParameterPredicateBuilder.class, theSearchSqlBuilder);
|
return myApplicationContext.getBean(ComboUniqueSearchParameterPredicateBuilder.class, theSearchSqlBuilder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ComboNonUniqueSearchParameterPredicateBuilder newComboNonUniqueSearchParameterPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
||||||
|
return myApplicationContext.getBean(ComboNonUniqueSearchParameterPredicateBuilder.class, theSearchSqlBuilder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public CoordsPredicateBuilder coordsPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
public CoordsPredicateBuilder coordsPredicateBuilder(SearchQueryBuilder theSearchSqlBuilder) {
|
||||||
return myApplicationContext.getBean(CoordsPredicateBuilder.class, theSearchSqlBuilder);
|
return myApplicationContext.getBean(CoordsPredicateBuilder.class, theSearchSqlBuilder);
|
||||||
}
|
}
|
||||||
|
@ -112,4 +118,5 @@ public class SqlObjectFactory {
|
||||||
public SearchQueryExecutor newSearchQueryExecutor(GeneratedSql theGeneratedSql, Integer theMaxResultsToFetch) {
|
public SearchQueryExecutor newSearchQueryExecutor(GeneratedSql theGeneratedSql, Integer theMaxResultsToFetch) {
|
||||||
return myApplicationContext.getBean(SearchQueryExecutor.class, theGeneratedSql, theMaxResultsToFetch);
|
return myApplicationContext.getBean(SearchQueryExecutor.class, theGeneratedSql, theMaxResultsToFetch);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import ca.uhn.fhir.jpa.bulk.export.api.IBulkDataExportSvc;
|
||||||
import ca.uhn.fhir.jpa.config.BaseConfig;
|
import ca.uhn.fhir.jpa.config.BaseConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedComboTokensNonUniqueDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamTokenDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamTokenDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceLinkDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceLinkDao;
|
||||||
|
@ -161,6 +162,8 @@ public abstract class BaseJpaTest extends BaseTest {
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IResourceIndexedSearchParamDateDao myResourceIndexedSearchParamDateDao;
|
protected IResourceIndexedSearchParamDateDao myResourceIndexedSearchParamDateDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
protected IResourceIndexedComboTokensNonUniqueDao myResourceIndexedComboTokensNonUniqueDao;
|
||||||
|
@Autowired
|
||||||
private IdHelperService myIdHelperService;
|
private IdHelperService myIdHelperService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private MemoryCacheService myMemoryCacheService;
|
private MemoryCacheService myMemoryCacheService;
|
||||||
|
@ -306,6 +309,12 @@ public abstract class BaseJpaTest extends BaseTest {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void logAllNonUniqueIndexes() {
|
||||||
|
runInTransaction(() -> {
|
||||||
|
ourLog.info("Non unique indexes:\n * {}", myResourceIndexedComboTokensNonUniqueDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
protected void logAllTokenIndexes() {
|
protected void logAllTokenIndexes() {
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
ourLog.info("Token indexes:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
ourLog.info("Token indexes:\n * {}", myResourceIndexedSearchParamTokenDao.findAll().stream().map(t -> t.toString()).collect(Collectors.joining("\n * ")));
|
||||||
|
|
|
@ -17,7 +17,7 @@ import ca.uhn.fhir.jpa.bulk.export.api.IBulkDataExportSvc;
|
||||||
import ca.uhn.fhir.jpa.config.TestDstu3Config;
|
import ca.uhn.fhir.jpa.config.TestDstu3Config;
|
||||||
import ca.uhn.fhir.jpa.dao.BaseJpaTest;
|
import ca.uhn.fhir.jpa.dao.BaseJpaTest;
|
||||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedComboStringUniqueDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamStringDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamStringDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamTokenDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamTokenDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceReindexJobDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceReindexJobDao;
|
||||||
|
@ -150,7 +150,7 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
||||||
@Qualifier("myCoverageDaoDstu3")
|
@Qualifier("myCoverageDaoDstu3")
|
||||||
protected IFhirResourceDao<Coverage> myCoverageDao;
|
protected IFhirResourceDao<Coverage> myCoverageDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
protected IResourceIndexedComboStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myAllergyIntoleranceDaoDstu3")
|
@Qualifier("myAllergyIntoleranceDaoDstu3")
|
||||||
protected IFhirResourceDao<AllergyIntolerance> myAllergyIntoleranceDao;
|
protected IFhirResourceDao<AllergyIntolerance> myAllergyIntoleranceDao;
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
|
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
||||||
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
|
import ca.uhn.fhir.jpa.search.reindex.ResourceReindexingSvcImpl;
|
||||||
|
import ca.uhn.fhir.jpa.util.SpringObjectCaster;
|
||||||
|
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.mockito.ArgumentMatchers;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
public abstract class BaseComboParamsR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(BaseComboParamsR4Test.class);
|
||||||
|
@Autowired
|
||||||
|
protected ISearchParamRegistry mySearchParamRegistry;
|
||||||
|
protected List<String> myMessages = new ArrayList<>();
|
||||||
|
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void before() {
|
||||||
|
myModelConfig.setDefaultSearchParamsCanBeOverridden(true);
|
||||||
|
myDaoConfig.setSchedulingDisabled(true);
|
||||||
|
myDaoConfig.setUniqueIndexesEnabled(true);
|
||||||
|
|
||||||
|
myInterceptorBroadcaster = mock(IInterceptorBroadcaster.class);
|
||||||
|
when(mySrd.getInterceptorBroadcaster()).thenReturn(myInterceptorBroadcaster);
|
||||||
|
when(mySrd.getServer().getPagingProvider()).thenReturn(new DatabaseBackedPagingProvider());
|
||||||
|
|
||||||
|
when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.JPA_PERFTRACE_WARNING))).thenReturn(true);
|
||||||
|
when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.JPA_PERFTRACE_INFO))).thenReturn(true);
|
||||||
|
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.JPA_PERFTRACE_INFO), ArgumentMatchers.any(HookParams.class))).thenAnswer(t -> {
|
||||||
|
HookParams params = t.getArgument(1, HookParams.class);
|
||||||
|
myMessages.add("INFO " + params.get(StorageProcessingMessage.class).getMessage());
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.JPA_PERFTRACE_WARNING), ArgumentMatchers.any(HookParams.class))).thenAnswer(t -> {
|
||||||
|
HookParams params = t.getArgument(1, HookParams.class);
|
||||||
|
myMessages.add("WARN " + params.get(StorageProcessingMessage.class).getMessage());
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.JPA_PERFTRACE_SEARCH_REUSING_CACHED), ArgumentMatchers.any(HookParams.class))).thenAnswer(t -> {
|
||||||
|
HookParams params = t.getArgument(1, HookParams.class);
|
||||||
|
myMessages.add("REUSING CACHED SEARCH");
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void after() throws Exception {
|
||||||
|
myModelConfig.setDefaultSearchParamsCanBeOverridden(new ModelConfig().isDefaultSearchParamsCanBeOverridden());
|
||||||
|
myDaoConfig.setUniqueIndexesCheckedBeforeSave(new DaoConfig().isUniqueIndexesCheckedBeforeSave());
|
||||||
|
myDaoConfig.setSchedulingDisabled(new DaoConfig().isSchedulingDisabled());
|
||||||
|
myDaoConfig.setUniqueIndexesEnabled(new DaoConfig().isUniqueIndexesEnabled());
|
||||||
|
myDaoConfig.setReindexThreadCount(new DaoConfig().getReindexThreadCount());
|
||||||
|
|
||||||
|
ResourceReindexingSvcImpl svc = SpringObjectCaster.getTargetObject(myResourceReindexingSvc, ResourceReindexingSvcImpl.class);
|
||||||
|
svc.initExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void logCapturedMessages() {
|
||||||
|
ourLog.info("Messages:\n {}", String.join("\n ", myMessages));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -26,7 +26,8 @@ import ca.uhn.fhir.jpa.dao.data.IMdmLinkDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IPartitionDao;
|
import ca.uhn.fhir.jpa.dao.data.IPartitionDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTagDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTagDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedComboStringUniqueDao;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedComboTokensNonUniqueDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamCoordsDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamCoordsDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamQuantityDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamQuantityDao;
|
||||||
|
@ -228,7 +229,9 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IResourceIndexedSearchParamDateDao myResourceIndexedSearchParamDateDao;
|
protected IResourceIndexedSearchParamDateDao myResourceIndexedSearchParamDateDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
protected IResourceIndexedComboStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
||||||
|
@Autowired
|
||||||
|
protected IResourceIndexedComboTokensNonUniqueDao myResourceIndexedComboTokensNonUniqueDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myAllergyIntoleranceDaoR4")
|
@Qualifier("myAllergyIntoleranceDaoR4")
|
||||||
protected IFhirResourceDao<AllergyIntolerance> myAllergyIntoleranceDao;
|
protected IFhirResourceDao<AllergyIntolerance> myAllergyIntoleranceDao;
|
||||||
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
import ca.uhn.fhir.rest.param.DateParam;
|
||||||
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
|
import ca.uhn.fhir.util.HapiExtensions;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.hl7.fhir.r4.model.BooleanType;
|
||||||
|
import org.hl7.fhir.r4.model.DateType;
|
||||||
|
import org.hl7.fhir.r4.model.Enumerations;
|
||||||
|
import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
|
||||||
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
import org.hl7.fhir.r4.model.SearchParameter;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
public class FhirResourceDaoR4ComboNonUniqueParamTest extends BaseComboParamsR4Test {
|
||||||
|
|
||||||
|
private void createNamesAndGenderSp() {
|
||||||
|
SearchParameter sp = new SearchParameter();
|
||||||
|
sp.setId("SearchParameter/patient-family");
|
||||||
|
sp.setType(Enumerations.SearchParamType.STRING);
|
||||||
|
sp.setCode("family");
|
||||||
|
sp.setExpression("Patient.name.family + '|'");
|
||||||
|
sp.setStatus(PublicationStatus.ACTIVE);
|
||||||
|
sp.addBase("Patient");
|
||||||
|
mySearchParameterDao.update(sp);
|
||||||
|
|
||||||
|
sp = new SearchParameter();
|
||||||
|
sp.setId("SearchParameter/patient-given");
|
||||||
|
sp.setType(Enumerations.SearchParamType.STRING);
|
||||||
|
sp.setCode("given");
|
||||||
|
sp.setExpression("Patient.name.given");
|
||||||
|
sp.setStatus(PublicationStatus.ACTIVE);
|
||||||
|
sp.addBase("Patient");
|
||||||
|
mySearchParameterDao.update(sp);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
sp = new SearchParameter();
|
||||||
|
sp.setId("SearchParameter/patient-names-and-gender");
|
||||||
|
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||||
|
sp.setStatus(PublicationStatus.ACTIVE);
|
||||||
|
sp.addBase("Patient");
|
||||||
|
sp.addComponent()
|
||||||
|
.setExpression("Patient")
|
||||||
|
.setDefinition("SearchParameter/patient-family");
|
||||||
|
sp.addComponent()
|
||||||
|
.setExpression("Patient")
|
||||||
|
.setDefinition("SearchParameter/patient-given");
|
||||||
|
sp.addComponent()
|
||||||
|
.setExpression("Patient")
|
||||||
|
.setDefinition("SearchParameter/patient-gender");
|
||||||
|
sp.addExtension()
|
||||||
|
.setUrl(HapiExtensions.EXT_SP_UNIQUE)
|
||||||
|
.setValue(new BooleanType(false));
|
||||||
|
mySearchParameterDao.update(sp);
|
||||||
|
|
||||||
|
mySearchParamRegistry.forceRefresh();
|
||||||
|
|
||||||
|
myMessages.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateAndUse() {
|
||||||
|
createNamesAndGenderSp();
|
||||||
|
|
||||||
|
IIdType id1 = createPatient1();
|
||||||
|
assertNotNull(id1);
|
||||||
|
|
||||||
|
IIdType id2 = createPatient2();
|
||||||
|
assertNotNull(id2);
|
||||||
|
|
||||||
|
logAllNonUniqueIndexes();
|
||||||
|
runInTransaction(() -> {
|
||||||
|
List<ResourceIndexedComboTokenNonUnique> indexedTokens = myResourceIndexedComboTokensNonUniqueDao.findAll();
|
||||||
|
indexedTokens.sort(Comparator.comparing(t -> t.getId()));
|
||||||
|
assertEquals(2, indexedTokens.size());
|
||||||
|
assertEquals(-7504889232313729794L, indexedTokens.get(0).getHashComplete().longValue());
|
||||||
|
});
|
||||||
|
|
||||||
|
myMessages.clear();
|
||||||
|
SearchParameterMap params = SearchParameterMap.newSynchronous();
|
||||||
|
params.add("family", new StringParam("fAmIlY1|")); // weird casing to test normalization
|
||||||
|
params.add("given", new StringParam("gIVEn1"));
|
||||||
|
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
IBundleProvider results = myPatientDao.search(params, mySrd);
|
||||||
|
List<String> actual = toUnqualifiedVersionlessIdValues(results);
|
||||||
|
myCaptureQueriesListener.logSelectQueries();
|
||||||
|
assertThat(actual, containsInAnyOrder(id1.toUnqualifiedVersionless().getValue()));
|
||||||
|
|
||||||
|
String sql = myCaptureQueriesListener.getSelectQueries().get(0).getSql(true, false);
|
||||||
|
assertEquals("SELECT t0.RES_ID FROM HFJ_IDX_CMB_TOK_NU t0 WHERE (t0.IDX_STRING = 'Patient?family=FAMILY1%5C%7C&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale&given=GIVEN1')", sql);
|
||||||
|
|
||||||
|
logCapturedMessages();
|
||||||
|
assertThat(myMessages.toString(), containsString("[INFO Using NON_UNIQUE index for query for search: Patient?family=FAMILY1%5C%7C&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale&given=GIVEN1]"));
|
||||||
|
myMessages.clear();
|
||||||
|
|
||||||
|
// Remove 1, add another
|
||||||
|
|
||||||
|
myPatientDao.delete(id1);
|
||||||
|
|
||||||
|
IIdType id3 = createPatient1();
|
||||||
|
assertNotNull(id3);
|
||||||
|
|
||||||
|
params = SearchParameterMap.newSynchronous();
|
||||||
|
params.add("family", new StringParam("fAmIlY1|")); // weird casing to test normalization
|
||||||
|
params.add("given", new StringParam("gIVEn1"));
|
||||||
|
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
|
||||||
|
results = myPatientDao.search(params, mySrd);
|
||||||
|
actual = toUnqualifiedVersionlessIdValues(results);
|
||||||
|
myCaptureQueriesListener.logSelectQueries();
|
||||||
|
assertThat(actual, containsInAnyOrder(id3.toUnqualifiedVersionless().getValue()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchWithExtraParameters() {
|
||||||
|
createNamesAndGenderSp();
|
||||||
|
|
||||||
|
IIdType id1 = createPatient1();
|
||||||
|
assertNotNull(id1);
|
||||||
|
|
||||||
|
IIdType id2 = createPatient2();
|
||||||
|
assertNotNull(id2);
|
||||||
|
|
||||||
|
logAllNonUniqueIndexes();
|
||||||
|
runInTransaction(() -> {
|
||||||
|
List<ResourceIndexedComboTokenNonUnique> indexedTokens = myResourceIndexedComboTokensNonUniqueDao.findAll();
|
||||||
|
indexedTokens.sort(Comparator.comparing(t -> t.getId()));
|
||||||
|
assertEquals(2, indexedTokens.size());
|
||||||
|
assertEquals(-7504889232313729794L, indexedTokens.get(0).getHashComplete().longValue());
|
||||||
|
});
|
||||||
|
|
||||||
|
myMessages.clear();
|
||||||
|
SearchParameterMap params = SearchParameterMap.newSynchronous();
|
||||||
|
params.add("family", new StringParam("fAmIlY1|")); // weird casing to test normalization
|
||||||
|
params.add("given", new StringParam("gIVEn1"));
|
||||||
|
params.add("gender", new TokenParam("http://hl7.org/fhir/administrative-gender", "male"));
|
||||||
|
params.add("birthdate", new DateParam("2021-02-02"));
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
IBundleProvider results = myPatientDao.search(params, mySrd);
|
||||||
|
List<String> actual = toUnqualifiedVersionlessIdValues(results);
|
||||||
|
myCaptureQueriesListener.logSelectQueries();
|
||||||
|
assertThat(actual, containsInAnyOrder(id1.toUnqualifiedVersionless().getValue()));
|
||||||
|
|
||||||
|
String sql = myCaptureQueriesListener.getSelectQueries().get(0).getSql(true, false);
|
||||||
|
assertEquals("SELECT t1.RES_ID FROM HFJ_RESOURCE t1 LEFT OUTER JOIN HFJ_IDX_CMB_TOK_NU t0 ON (t1.RES_ID = t0.RES_ID) LEFT OUTER JOIN HFJ_SPIDX_DATE t2 ON (t1.RES_ID = t2.RES_ID) WHERE ((t0.IDX_STRING = 'Patient?family=FAMILY1%5C%7C&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale&given=GIVEN1') AND ((t2.HASH_IDENTITY = '5247847184787287691') AND ((t2.SP_VALUE_LOW_DATE_ORDINAL >= '20210202') AND (t2.SP_VALUE_HIGH_DATE_ORDINAL <= '20210202'))))", sql);
|
||||||
|
|
||||||
|
logCapturedMessages();
|
||||||
|
assertThat(myMessages.toString(), containsString("[INFO Using NON_UNIQUE index for query for search: Patient?family=FAMILY1%5C%7C&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale&given=GIVEN1]"));
|
||||||
|
myMessages.clear();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private IIdType createPatient2() {
|
||||||
|
Patient pt2 = new Patient();
|
||||||
|
pt2.getNameFirstRep().setFamily("Family2").addGiven("Given2");
|
||||||
|
pt2.setGender(Enumerations.AdministrativeGender.MALE);
|
||||||
|
pt2.setBirthDateElement(new DateType("2021-02-02"));
|
||||||
|
IIdType id2 = myPatientDao.create(pt2).getId().toUnqualified();
|
||||||
|
return id2;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IIdType createPatient1() {
|
||||||
|
Patient pt1 = new Patient();
|
||||||
|
pt1.getNameFirstRep().setFamily("Family1").addGiven("Given1");
|
||||||
|
pt1.setGender(Enumerations.AdministrativeGender.MALE);
|
||||||
|
pt1.setBirthDateElement(new DateType("2021-02-02"));
|
||||||
|
return myPatientDao.create(pt1).getId().toUnqualified();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,19 +1,12 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r4;
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
|
||||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
|
||||||
import ca.uhn.fhir.jpa.search.reindex.ResourceReindexingSvcImpl;
|
import ca.uhn.fhir.jpa.search.reindex.ResourceReindexingSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.searchparam.util.JpaParamUtil;
|
import ca.uhn.fhir.jpa.searchparam.util.JpaParamUtil;
|
||||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
|
||||||
import ca.uhn.fhir.jpa.util.SpringObjectCaster;
|
import ca.uhn.fhir.jpa.util.SpringObjectCaster;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.DateParam;
|
import ca.uhn.fhir.rest.param.DateParam;
|
||||||
|
@ -27,17 +20,12 @@ import ca.uhn.fhir.util.HapiExtensions;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
|
import org.hl7.fhir.r4.model.Enumerations.PublicationStatus;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentMatchers;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.transaction.TransactionStatus;
|
import org.springframework.transaction.TransactionStatus;
|
||||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
@ -57,56 +45,10 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
public class FhirResourceDaoR4ComboUniqueParamTest extends BaseComboParamsR4Test {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4UniqueSearchParamTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4ComboUniqueParamTest.class);
|
||||||
@Autowired
|
|
||||||
private ISearchParamRegistry mySearchParamRegistry;
|
|
||||||
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
|
||||||
private List<String> myMessages = new ArrayList<>();
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
public void after() throws Exception {
|
|
||||||
myModelConfig.setDefaultSearchParamsCanBeOverridden(new ModelConfig().isDefaultSearchParamsCanBeOverridden());
|
|
||||||
myDaoConfig.setUniqueIndexesCheckedBeforeSave(new DaoConfig().isUniqueIndexesCheckedBeforeSave());
|
|
||||||
myDaoConfig.setSchedulingDisabled(new DaoConfig().isSchedulingDisabled());
|
|
||||||
myDaoConfig.setUniqueIndexesEnabled(new DaoConfig().isUniqueIndexesEnabled());
|
|
||||||
myDaoConfig.setReindexThreadCount(new DaoConfig().getReindexThreadCount());
|
|
||||||
|
|
||||||
ResourceReindexingSvcImpl svc = SpringObjectCaster.getTargetObject(myResourceReindexingSvc, ResourceReindexingSvcImpl.class);
|
|
||||||
svc.initExecutor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void before() {
|
|
||||||
myModelConfig.setDefaultSearchParamsCanBeOverridden(true);
|
|
||||||
myDaoConfig.setSchedulingDisabled(true);
|
|
||||||
myDaoConfig.setUniqueIndexesEnabled(true);
|
|
||||||
|
|
||||||
myInterceptorBroadcaster = mock(IInterceptorBroadcaster.class);
|
|
||||||
when(mySrd.getInterceptorBroadcaster()).thenReturn(myInterceptorBroadcaster);
|
|
||||||
when(mySrd.getServer().getPagingProvider()).thenReturn(new DatabaseBackedPagingProvider());
|
|
||||||
|
|
||||||
when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.JPA_PERFTRACE_WARNING))).thenReturn(true);
|
|
||||||
when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.JPA_PERFTRACE_INFO))).thenReturn(true);
|
|
||||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.JPA_PERFTRACE_INFO), ArgumentMatchers.any(HookParams.class))).thenAnswer(t -> {
|
|
||||||
HookParams params = t.getArgument(1, HookParams.class);
|
|
||||||
myMessages.add("INFO " + params.get(StorageProcessingMessage.class).getMessage());
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.JPA_PERFTRACE_WARNING), ArgumentMatchers.any(HookParams.class))).thenAnswer(t -> {
|
|
||||||
HookParams params = t.getArgument(1, HookParams.class);
|
|
||||||
myMessages.add("WARN " + params.get(StorageProcessingMessage.class).getMessage());
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.JPA_PERFTRACE_SEARCH_REUSING_CACHED), ArgumentMatchers.any(HookParams.class))).thenAnswer(t -> {
|
|
||||||
HookParams params = t.getArgument(1, HookParams.class);
|
|
||||||
myMessages.add("REUSING CACHED SEARCH");
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void createUniqueBirthdateAndGenderSps() {
|
private void createUniqueBirthdateAndGenderSps() {
|
||||||
|
@ -647,7 +589,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
// Make sure entries are saved
|
// Make sure entries are saved
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
List<ResourceIndexedCompositeStringUnique> all = myResourceIndexedCompositeStringUniqueDao.findAll();
|
List<ResourceIndexedComboStringUnique> all = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
assertEquals(2, all.size());
|
assertEquals(2, all.size());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -691,7 +633,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||||
@Override
|
@Override
|
||||||
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus status) {
|
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus status) {
|
||||||
List<ResourceIndexedCompositeStringUnique> all = myResourceIndexedCompositeStringUniqueDao.findAll();
|
List<ResourceIndexedComboStringUnique> all = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
assertEquals(2, all.size());
|
assertEquals(2, all.size());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -706,7 +648,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
ResourceReindexingSvcImpl svc = SpringObjectCaster.getTargetObject(myResourceReindexingSvc, ResourceReindexingSvcImpl.class);
|
ResourceReindexingSvcImpl svc = SpringObjectCaster.getTargetObject(myResourceReindexingSvc, ResourceReindexingSvcImpl.class);
|
||||||
svc.initExecutor();
|
svc.initExecutor();
|
||||||
|
|
||||||
List<RuntimeSearchParam> uniqueSearchParams = mySearchParamRegistry.getActiveUniqueSearchParams("Observation");
|
List<RuntimeSearchParam> uniqueSearchParams = mySearchParamRegistry.getActiveComboSearchParams("Observation");
|
||||||
assertEquals(0, uniqueSearchParams.size());
|
assertEquals(0, uniqueSearchParams.size());
|
||||||
|
|
||||||
Patient pt1 = new Patient();
|
Patient pt1 = new Patient();
|
||||||
|
@ -735,7 +677,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
createUniqueObservationSubjectDateCode();
|
createUniqueObservationSubjectDateCode();
|
||||||
|
|
||||||
uniqueSearchParams = mySearchParamRegistry.getActiveUniqueSearchParams("Observation");
|
uniqueSearchParams = mySearchParamRegistry.getActiveComboSearchParams("Observation");
|
||||||
assertEquals(1, uniqueSearchParams.size());
|
assertEquals(1, uniqueSearchParams.size());
|
||||||
assertEquals(3, uniqueSearchParams.get(0).getComponents().size());
|
assertEquals(3, uniqueSearchParams.get(0).getComponents().size());
|
||||||
|
|
||||||
|
@ -745,7 +687,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
assertEquals(0, myResourceReindexingSvc.forceReindexingPass());
|
assertEquals(0, myResourceReindexingSvc.forceReindexingPass());
|
||||||
|
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
List<ResourceIndexedComboStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
assertEquals(1, uniques.size(), uniques.toString());
|
assertEquals(1, uniques.size(), uniques.toString());
|
||||||
assertThat(uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue(), either(equalTo("Observation/" + id2.getIdPart())).or(equalTo("Observation/" + id3.getIdPart())));
|
assertThat(uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue(), either(equalTo("Observation/" + id2.getIdPart())).or(equalTo("Observation/" + id3.getIdPart())));
|
||||||
assertEquals("Observation?code=foo%7Cbar&date=2011-01-01&subject=Patient%2F" + id1.getIdPart(), uniques.get(0).getIndexString());
|
assertEquals("Observation?code=foo%7Cbar&date=2011-01-01&subject=Patient%2F" + id1.getIdPart(), uniques.get(0).getIndexString());
|
||||||
|
@ -753,7 +695,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
myResourceIndexedCompositeStringUniqueDao.deleteAll();
|
myResourceIndexedCompositeStringUniqueDao.deleteAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
assertEquals(1, mySearchParamRegistry.getActiveUniqueSearchParams("Observation").size());
|
assertEquals(1, mySearchParamRegistry.getActiveComboSearchParams("Observation").size());
|
||||||
|
|
||||||
myResourceReindexingSvc.markAllResourcesForReindexing("Observation");
|
myResourceReindexingSvc.markAllResourcesForReindexing("Observation");
|
||||||
assertEquals(1, myResourceReindexingSvc.forceReindexingPass());
|
assertEquals(1, myResourceReindexingSvc.forceReindexingPass());
|
||||||
|
@ -762,7 +704,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
assertEquals(0, myResourceReindexingSvc.forceReindexingPass());
|
assertEquals(0, myResourceReindexingSvc.forceReindexingPass());
|
||||||
|
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
List<ResourceIndexedComboStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
assertEquals(1, uniques.size(), uniques.toString());
|
assertEquals(1, uniques.size(), uniques.toString());
|
||||||
assertThat(uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue(), either(equalTo("Observation/" + id2.getIdPart())).or(equalTo("Observation/" + id3.getIdPart())));
|
assertThat(uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue(), either(equalTo("Observation/" + id2.getIdPart())).or(equalTo("Observation/" + id3.getIdPart())));
|
||||||
assertEquals("Observation?code=foo%7Cbar&date=2011-01-01&subject=Patient%2F" + id1.getIdPart(), uniques.get(0).getIndexString());
|
assertEquals("Observation?code=foo%7Cbar&date=2011-01-01&subject=Patient%2F" + id1.getIdPart(), uniques.get(0).getIndexString());
|
||||||
|
@ -833,7 +775,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||||
@Override
|
@Override
|
||||||
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus status) {
|
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus status) {
|
||||||
List<ResourceIndexedCompositeStringUnique> all = myResourceIndexedCompositeStringUniqueDao.findAll();
|
List<ResourceIndexedComboStringUnique> all = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
assertEquals(2, all.size());
|
assertEquals(2, all.size());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -873,7 +815,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
});
|
});
|
||||||
|
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
List<ResourceIndexedComboStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
ourLog.info("** Uniques: {}", uniques);
|
ourLog.info("** Uniques: {}", uniques);
|
||||||
assertEquals(1, uniques.size(), uniques.toString());
|
assertEquals(1, uniques.size(), uniques.toString());
|
||||||
assertEquals("Coverage/" + id3.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
assertEquals("Coverage/" + id3.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||||
|
@ -1042,7 +984,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||||
@Override
|
@Override
|
||||||
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus status) {
|
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus status) {
|
||||||
List<ResourceIndexedCompositeStringUnique> all = myResourceIndexedCompositeStringUniqueDao.findAll();
|
List<ResourceIndexedComboStringUnique> all = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
assertEquals(1, all.size(), all.toString());
|
assertEquals(1, all.size(), all.toString());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1074,7 +1016,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id1.getValue()));
|
assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id1.getValue()));
|
||||||
|
|
||||||
logCapturedMessages();
|
logCapturedMessages();
|
||||||
assertThat(myMessages.toString(), containsString("Using unique index for query for search: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
|
assertThat(myMessages.toString(), containsString("Using UNIQUE index for query for search: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
|
||||||
myMessages.clear();
|
myMessages.clear();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1102,7 +1044,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
String searchId = results.getUuid();
|
String searchId = results.getUuid();
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id1));
|
assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id1));
|
||||||
logCapturedMessages();
|
logCapturedMessages();
|
||||||
assertThat(myMessages.toString(), containsString("Using unique index for query for search: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
|
assertThat(myMessages.toString(), containsString("Using UNIQUE index for query for search: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
|
||||||
myMessages.clear();
|
myMessages.clear();
|
||||||
|
|
||||||
// Other order
|
// Other order
|
||||||
|
@ -1126,7 +1068,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
results = myPatientDao.search(params, mySrd);
|
results = myPatientDao.search(params, mySrd);
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(results), empty());
|
assertThat(toUnqualifiedVersionlessIdValues(results), empty());
|
||||||
logCapturedMessages();
|
logCapturedMessages();
|
||||||
assertThat(myMessages.toString(), containsString("Using unique index for query for search: Patient?birthdate=2011-01-03&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
|
assertThat(myMessages.toString(), containsString("Using UNIQUE index for query for search: Patient?birthdate=2011-01-03&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
|
||||||
myMessages.clear();
|
myMessages.clear();
|
||||||
|
|
||||||
myMessages.clear();
|
myMessages.clear();
|
||||||
|
@ -1151,7 +1093,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
pt1.setBirthDateElement(new DateType("2011-01-01"));
|
pt1.setBirthDateElement(new DateType("2011-01-01"));
|
||||||
IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
List<ResourceIndexedComboStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
assertEquals(1, uniques.size(), uniques.toString());
|
assertEquals(1, uniques.size(), uniques.toString());
|
||||||
assertEquals("Patient/" + id1.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
assertEquals("Patient/" + id1.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||||
assertEquals("Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale", uniques.get(0).getIndexString());
|
assertEquals("Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale", uniques.get(0).getIndexString());
|
||||||
|
@ -1161,7 +1103,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
public void testUniqueValuesAreIndexed_RefAndDateAndToken() {
|
public void testUniqueValuesAreIndexed_RefAndDateAndToken() {
|
||||||
createUniqueObservationSubjectDateCode();
|
createUniqueObservationSubjectDateCode();
|
||||||
|
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques;
|
List<ResourceIndexedComboStringUnique> uniques;
|
||||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
assertEquals(0, uniques.size(), uniques.toString());
|
assertEquals(0, uniques.size(), uniques.toString());
|
||||||
|
|
||||||
|
@ -1190,7 +1132,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testUniqueValuesAreIndexed_Reference_UsingModifierSyntax() {
|
public void testUniqueValuesAreIndexed_Reference_UsingModifierSyntax() {
|
||||||
createUniqueNameAndManagingOrganizationSps();
|
createUniqueNameAndManagingOrganizationSps();
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques;
|
List<ResourceIndexedComboStringUnique> uniques;
|
||||||
|
|
||||||
Organization org = new Organization();
|
Organization org = new Organization();
|
||||||
org.setId("Organization/ORG");
|
org.setId("Organization/ORG");
|
||||||
|
@ -1204,7 +1146,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
IIdType id1 = myPatientDao.update(pt1, "Patient?name=FAMILY1&organization:Organization=ORG", mySrd).getId().toUnqualifiedVersionless();
|
IIdType id1 = myPatientDao.update(pt1, "Patient?name=FAMILY1&organization:Organization=ORG", mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
logCapturedMessages();
|
logCapturedMessages();
|
||||||
assertThat(myMessages.toString(), containsString("Using unique index for query for search: Patient?name=FAMILY1&organization=Organization%2FORG"));
|
assertThat(myMessages.toString(), containsString("Using UNIQUE index for query for search: Patient?name=FAMILY1&organization=Organization%2FORG"));
|
||||||
myMessages.clear();
|
myMessages.clear();
|
||||||
|
|
||||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
|
@ -1221,7 +1163,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
id1 = myPatientDao.update(pt1, "Patient?name=FAMILY1&organization:Organization=ORG", mySrd).getId().toUnqualifiedVersionless();
|
id1 = myPatientDao.update(pt1, "Patient?name=FAMILY1&organization:Organization=ORG", mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
logCapturedMessages();
|
logCapturedMessages();
|
||||||
assertThat(myMessages.toString(), containsString("Using unique index for query for search: Patient?name=FAMILY1&organization=Organization%2FORG"));
|
assertThat(myMessages.toString(), containsString("Using UNIQUE index for query for search: Patient?name=FAMILY1&organization=Organization%2FORG"));
|
||||||
myMessages.clear();
|
myMessages.clear();
|
||||||
|
|
||||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
|
@ -1231,10 +1173,6 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void logCapturedMessages() {
|
|
||||||
ourLog.info("Messages:\n {}", String.join("\n ", myMessages));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUniqueValuesAreIndexed_StringAndReference() {
|
public void testUniqueValuesAreIndexed_StringAndReference() {
|
||||||
createUniqueNameAndManagingOrganizationSps();
|
createUniqueNameAndManagingOrganizationSps();
|
||||||
|
@ -1253,7 +1191,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
pt1.setManagingOrganization(new Reference("Organization/ORG"));
|
pt1.setManagingOrganization(new Reference("Organization/ORG"));
|
||||||
IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
List<ResourceIndexedComboStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
Collections.sort(uniques);
|
Collections.sort(uniques);
|
||||||
|
|
||||||
assertEquals(3, uniques.size());
|
assertEquals(3, uniques.size());
|
||||||
|
@ -1270,7 +1208,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testUniqueValuesAreIndexed_StringAndReference_UsingConditional() {
|
public void testUniqueValuesAreIndexed_StringAndReference_UsingConditional() {
|
||||||
createUniqueNameAndManagingOrganizationSps();
|
createUniqueNameAndManagingOrganizationSps();
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques;
|
List<ResourceIndexedComboStringUnique> uniques;
|
||||||
|
|
||||||
Organization org = new Organization();
|
Organization org = new Organization();
|
||||||
org.setId("Organization/ORG");
|
org.setId("Organization/ORG");
|
||||||
|
@ -1303,7 +1241,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testUniqueValuesAreIndexed_StringAndReference_UsingConditionalInTransaction() {
|
public void testUniqueValuesAreIndexed_StringAndReference_UsingConditionalInTransaction() {
|
||||||
createUniqueNameAndManagingOrganizationSps();
|
createUniqueNameAndManagingOrganizationSps();
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques;
|
List<ResourceIndexedComboStringUnique> uniques;
|
||||||
|
|
||||||
Organization org = new Organization();
|
Organization org = new Organization();
|
||||||
org.setId("Organization/ORG");
|
org.setId("Organization/ORG");
|
||||||
|
@ -1385,7 +1323,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
createUniqueBirthdateAndGenderSps();
|
createUniqueBirthdateAndGenderSps();
|
||||||
|
|
||||||
Patient pt;
|
Patient pt;
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques;
|
List<ResourceIndexedComboStringUnique> uniques;
|
||||||
|
|
||||||
pt = new Patient();
|
pt = new Patient();
|
||||||
pt.setGender(Enumerations.AdministrativeGender.MALE);
|
pt.setGender(Enumerations.AdministrativeGender.MALE);
|
||||||
|
@ -1416,7 +1354,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
org.setName("ORG");
|
org.setName("ORG");
|
||||||
myOrganizationDao.update(org);
|
myOrganizationDao.update(org);
|
||||||
|
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques;
|
List<ResourceIndexedComboStringUnique> uniques;
|
||||||
Patient pt;
|
Patient pt;
|
||||||
|
|
||||||
pt = new Patient();
|
pt = new Patient();
|
||||||
|
@ -1464,7 +1402,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
myResourceReindexingSvc.forceReindexingPass();
|
myResourceReindexingSvc.forceReindexingPass();
|
||||||
myResourceReindexingSvc.forceReindexingPass();
|
myResourceReindexingSvc.forceReindexingPass();
|
||||||
|
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
List<ResourceIndexedComboStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
assertEquals(1, uniques.size(), uniques.toString());
|
assertEquals(1, uniques.size(), uniques.toString());
|
||||||
assertEquals("Observation/" + id2.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
assertEquals("Observation/" + id2.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||||
assertEquals("Observation?code=foo%7Cbar&date=2011-01-01&subject=Patient%2F" + id1.getIdPart(), uniques.get(0).getIndexString());
|
assertEquals("Observation?code=foo%7Cbar&date=2011-01-01&subject=Patient%2F" + id1.getIdPart(), uniques.get(0).getIndexString());
|
||||||
|
@ -1486,10 +1424,10 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testDetectUniqueSearchParams() {
|
public void testDetectUniqueSearchParams() {
|
||||||
createUniqueBirthdateAndGenderSps();
|
createUniqueBirthdateAndGenderSps();
|
||||||
List<RuntimeSearchParam> params = mySearchParamRegistry.getActiveUniqueSearchParams("Patient");
|
List<RuntimeSearchParam> params = mySearchParamRegistry.getActiveComboSearchParams("Patient");
|
||||||
|
|
||||||
assertEquals(1, params.size());
|
assertEquals(1, params.size());
|
||||||
assertEquals(params.get(0).isUnique(), true);
|
assertEquals(ComboSearchParamType.UNIQUE, params.get(0).getComboSearchParamType());
|
||||||
assertEquals(2, params.get(0).getComponents().size());
|
assertEquals(2, params.get(0).getComponents().size());
|
||||||
|
|
||||||
// Should be alphabetical order
|
// Should be alphabetical order
|
||||||
|
@ -1565,7 +1503,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id2.getValue()));
|
assertThat(toUnqualifiedVersionlessIdValues(results), containsInAnyOrder(id2.getValue()));
|
||||||
|
|
||||||
logCapturedMessages();
|
logCapturedMessages();
|
||||||
assertThat(myMessages.toString(), containsString("Using unique index for query for search: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
|
assertThat(myMessages.toString(), containsString("Using UNIQUE index for query for search: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale"));
|
||||||
myMessages.clear();
|
myMessages.clear();
|
||||||
|
|
||||||
}
|
}
|
|
@ -12,7 +12,7 @@ import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
||||||
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
|
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTag;
|
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTag;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||||
|
@ -435,7 +435,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
||||||
assertEquals(myPartitionDate, presents.get(0).getPartitionId().getPartitionDate());
|
assertEquals(myPartitionDate, presents.get(0).getPartitionId().getPartitionDate());
|
||||||
|
|
||||||
// HFJ_IDX_CMP_STRING_UNIQ
|
// HFJ_IDX_CMP_STRING_UNIQ
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAllForResourceIdForUnitTest(patientId);
|
List<ResourceIndexedComboStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAllForResourceIdForUnitTest(patientId);
|
||||||
assertEquals(1, uniques.size());
|
assertEquals(1, uniques.size());
|
||||||
assertEquals(myPartitionId, uniques.get(0).getPartitionId().getPartitionId().intValue());
|
assertEquals(myPartitionId, uniques.get(0).getPartitionId().getPartitionId().intValue());
|
||||||
assertEquals(myPartitionDate, uniques.get(0).getPartitionId().getPartitionDate());
|
assertEquals(myPartitionDate, uniques.get(0).getPartitionId().getPartitionDate());
|
||||||
|
@ -519,7 +519,7 @@ public class PartitioningSqlR4Test extends BasePartitioningR4Test {
|
||||||
assertEquals(myPartitionDate, presents.get(0).getPartitionId().getPartitionDate());
|
assertEquals(myPartitionDate, presents.get(0).getPartitionId().getPartitionDate());
|
||||||
|
|
||||||
// HFJ_IDX_CMP_STRING_UNIQ
|
// HFJ_IDX_CMP_STRING_UNIQ
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAllForResourceIdForUnitTest(patientId);
|
List<ResourceIndexedComboStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAllForResourceIdForUnitTest(patientId);
|
||||||
assertEquals(1, uniques.size());
|
assertEquals(1, uniques.size());
|
||||||
assertEquals(null, uniques.get(0).getPartitionId().getPartitionId());
|
assertEquals(null, uniques.get(0).getPartitionId().getPartitionId());
|
||||||
assertEquals(myPartitionDate, uniques.get(0).getPartitionId().getPartitionDate());
|
assertEquals(myPartitionDate, uniques.get(0).getPartitionId().getPartitionDate());
|
||||||
|
|
|
@ -327,7 +327,7 @@ public class SearchParamExtractorR4Test {
|
||||||
public void testExtensionContainingReference() {
|
public void testExtensionContainingReference() {
|
||||||
String path = "Patient.extension('http://patext').value.as(Reference)";
|
String path = "Patient.extension('http://patext').value.as(Reference)";
|
||||||
|
|
||||||
RuntimeSearchParam sp = new RuntimeSearchParam(null, null, "extpat", "Patient SP", path, RestSearchParameterTypeEnum.REFERENCE, new HashSet<>(), Sets.newHashSet("Patient"), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null);
|
RuntimeSearchParam sp = new RuntimeSearchParam(null, null, "extpat", "Patient SP", path, RestSearchParameterTypeEnum.REFERENCE, new HashSet<>(), Sets.newHashSet("Patient"), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null);
|
||||||
mySearchParamRegistry.addSearchParam(sp);
|
mySearchParamRegistry.addSearchParam(sp);
|
||||||
|
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
|
@ -440,7 +440,7 @@ public class SearchParamExtractorR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName, Set<String> theParamNames) {
|
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,7 +451,7 @@ public class SearchParamExtractorR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName) {
|
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ import ca.uhn.fhir.jpa.dao.BaseJpaTest;
|
||||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceHistoryTableDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedComboStringUniqueDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamDateDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamQuantityDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamQuantityDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamStringDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedSearchParamStringDao;
|
||||||
|
@ -185,7 +185,7 @@ public abstract class BaseJpaR5Test extends BaseJpaTest implements ITestDataBuil
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IResourceIndexedSearchParamDateDao myResourceIndexedSearchParamDateDao;
|
protected IResourceIndexedSearchParamDateDao myResourceIndexedSearchParamDateDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
protected IResourceIndexedComboStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myAllergyIntoleranceDaoR5")
|
@Qualifier("myAllergyIntoleranceDaoR5")
|
||||||
protected IFhirResourceDao<AllergyIntolerance> myAllergyIntoleranceDao;
|
protected IFhirResourceDao<AllergyIntolerance> myAllergyIntoleranceDao;
|
||||||
|
|
|
@ -102,6 +102,21 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
|
|
||||||
version.onTable("HFJ_IDX_CMP_STRING_UNIQ")
|
version.onTable("HFJ_IDX_CMP_STRING_UNIQ")
|
||||||
.modifyColumn("20210713.1","IDX_STRING").nonNullable().withType(ColumnTypeEnum.STRING, 500);
|
.modifyColumn("20210713.1","IDX_STRING").nonNullable().withType(ColumnTypeEnum.STRING, 500);
|
||||||
|
|
||||||
|
version.onTable("HFJ_RESOURCE")
|
||||||
|
.addColumn("20210720.1", "SP_CMPTOKS_PRESENT").nullable().type(ColumnTypeEnum.BOOLEAN);
|
||||||
|
|
||||||
|
version.addIdGenerator("20210720.2", "SEQ_IDXCMBTOKNU_ID");
|
||||||
|
|
||||||
|
Builder.BuilderAddTableByColumns cmpToks = version
|
||||||
|
.addTableByColumns("20210720.3", "HFJ_IDX_CMB_TOK_NU", "PID");
|
||||||
|
cmpToks.addColumn("PID").nonNullable().type(ColumnTypeEnum.LONG);
|
||||||
|
cmpToks.addColumn("RES_ID").nonNullable().type(ColumnTypeEnum.LONG);
|
||||||
|
cmpToks.addColumn("HASH_COMPLETE").nonNullable().type(ColumnTypeEnum.LONG);
|
||||||
|
cmpToks.addColumn("IDX_STRING").nonNullable().type(ColumnTypeEnum.STRING, 500);
|
||||||
|
cmpToks.addForeignKey("20210720.4", "FK_IDXCMBTOKNU_RES_ID").toColumn("RES_ID").references("HFJ_RESOURCE", "RES_ID");
|
||||||
|
cmpToks.addIndex("20210720.5", "IDX_IDXCMBTOKNU_STR").unique(false).withColumns("IDX_STRING");
|
||||||
|
cmpToks.addIndex("20210720.6", "IDX_IDXCMBTOKNU_RES").unique(false).withColumns("RES_ID");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init540() {
|
private void init540() {
|
||||||
|
|
|
@ -43,6 +43,7 @@ import javax.persistence.Temporal;
|
||||||
import javax.persistence.TemporalType;
|
import javax.persistence.TemporalType;
|
||||||
import javax.persistence.Transient;
|
import javax.persistence.Transient;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@MappedSuperclass
|
@MappedSuperclass
|
||||||
public abstract class BaseResourceIndexedSearchParam extends BaseResourceIndex {
|
public abstract class BaseResourceIndexedSearchParam extends BaseResourceIndex {
|
||||||
|
@ -182,6 +183,17 @@ public abstract class BaseResourceIndexedSearchParam extends BaseResourceIndex {
|
||||||
return hash(thePartitionSettings, theRequestPartitionId, theResourceType, theParamName);
|
return hash(thePartitionSettings, theRequestPartitionId, theResourceType, theParamName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static long calculateHashIdentity(PartitionSettings thePartitionSettings, RequestPartitionId theRequestPartitionId, String theResourceType, String theParamName, List<String> theAdditionalValues) {
|
||||||
|
String[] values = new String[theAdditionalValues.size() + 2];
|
||||||
|
values[0] = theResourceType;
|
||||||
|
values[1] = theParamName;
|
||||||
|
for (int i = 0; i < theAdditionalValues.size(); i++) {
|
||||||
|
values[i + 2] = theAdditionalValues.get(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return hash(thePartitionSettings, theRequestPartitionId, values);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies a fast and consistent hashing algorithm to a set of strings
|
* Applies a fast and consistent hashing algorithm to a set of strings
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -32,10 +32,10 @@ import javax.persistence.*;
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@Table(name = "HFJ_IDX_CMP_STRING_UNIQ", indexes = {
|
@Table(name = "HFJ_IDX_CMP_STRING_UNIQ", indexes = {
|
||||||
@Index(name = ResourceIndexedCompositeStringUnique.IDX_IDXCMPSTRUNIQ_STRING, columnList = "IDX_STRING", unique = true),
|
@Index(name = ResourceIndexedComboStringUnique.IDX_IDXCMPSTRUNIQ_STRING, columnList = "IDX_STRING", unique = true),
|
||||||
@Index(name = ResourceIndexedCompositeStringUnique.IDX_IDXCMPSTRUNIQ_RESOURCE, columnList = "RES_ID", unique = false)
|
@Index(name = ResourceIndexedComboStringUnique.IDX_IDXCMPSTRUNIQ_RESOURCE, columnList = "RES_ID", unique = false)
|
||||||
})
|
})
|
||||||
public class ResourceIndexedCompositeStringUnique extends BasePartitionable implements Comparable<ResourceIndexedCompositeStringUnique> {
|
public class ResourceIndexedComboStringUnique extends BasePartitionable implements Comparable<ResourceIndexedComboStringUnique> {
|
||||||
|
|
||||||
public static final int MAX_STRING_LENGTH = 500;
|
public static final int MAX_STRING_LENGTH = 500;
|
||||||
public static final String IDX_IDXCMPSTRUNIQ_STRING = "IDX_IDXCMPSTRUNIQ_STRING";
|
public static final String IDX_IDXCMPSTRUNIQ_STRING = "IDX_IDXCMPSTRUNIQ_STRING";
|
||||||
|
@ -66,14 +66,14 @@ public class ResourceIndexedCompositeStringUnique extends BasePartitionable impl
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public ResourceIndexedCompositeStringUnique() {
|
public ResourceIndexedComboStringUnique() {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public ResourceIndexedCompositeStringUnique(ResourceTable theResource, String theIndexString, IIdType theSearchParameterId) {
|
public ResourceIndexedComboStringUnique(ResourceTable theResource, String theIndexString, IIdType theSearchParameterId) {
|
||||||
setResource(theResource);
|
setResource(theResource);
|
||||||
setIndexString(theIndexString);
|
setIndexString(theIndexString);
|
||||||
setPartitionId(theResource.getPartitionId());
|
setPartitionId(theResource.getPartitionId());
|
||||||
|
@ -81,7 +81,7 @@ public class ResourceIndexedCompositeStringUnique extends BasePartitionable impl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(ResourceIndexedCompositeStringUnique theO) {
|
public int compareTo(ResourceIndexedComboStringUnique theO) {
|
||||||
CompareToBuilder b = new CompareToBuilder();
|
CompareToBuilder b = new CompareToBuilder();
|
||||||
b.append(myIndexString, theO.getIndexString());
|
b.append(myIndexString, theO.getIndexString());
|
||||||
return b.toComparison();
|
return b.toComparison();
|
||||||
|
@ -91,11 +91,11 @@ public class ResourceIndexedCompositeStringUnique extends BasePartitionable impl
|
||||||
public boolean equals(Object theO) {
|
public boolean equals(Object theO) {
|
||||||
if (this == theO) return true;
|
if (this == theO) return true;
|
||||||
|
|
||||||
if (!(theO instanceof ResourceIndexedCompositeStringUnique)) {
|
if (!(theO instanceof ResourceIndexedComboStringUnique)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResourceIndexedCompositeStringUnique that = (ResourceIndexedCompositeStringUnique) theO;
|
ResourceIndexedComboStringUnique that = (ResourceIndexedComboStringUnique) theO;
|
||||||
|
|
||||||
return new EqualsBuilder()
|
return new EqualsBuilder()
|
||||||
.append(myIndexString, that.myIndexString)
|
.append(myIndexString, that.myIndexString)
|
|
@ -0,0 +1,190 @@
|
||||||
|
package ca.uhn.fhir.jpa.model.entity;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Model
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2021 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
|
import org.apache.commons.lang3.builder.CompareToBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||||
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
|
|
||||||
|
import javax.persistence.Column;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.ForeignKey;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Index;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.ManyToOne;
|
||||||
|
import javax.persistence.SequenceGenerator;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
import javax.persistence.Transient;
|
||||||
|
|
||||||
|
import static ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam.hash;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name = "HFJ_IDX_CMB_TOK_NU", indexes = {
|
||||||
|
@Index(name = "IDX_IDXCMBTOKNU_STR", columnList = "IDX_STRING", unique = false),
|
||||||
|
@Index(name = "IDX_IDXCMBTOKNU_RES", columnList = "RES_ID", unique = false)
|
||||||
|
})
|
||||||
|
public class ResourceIndexedComboTokenNonUnique extends BaseResourceIndex implements Comparable<ResourceIndexedComboTokenNonUnique> {
|
||||||
|
|
||||||
|
@SequenceGenerator(name = "SEQ_IDXCMBTOKNU_ID", sequenceName = "SEQ_IDXCMBTOKNU_ID")
|
||||||
|
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_IDXCMBTOKNU_ID")
|
||||||
|
@Id
|
||||||
|
@Column(name = "PID")
|
||||||
|
private Long myId;
|
||||||
|
|
||||||
|
@ManyToOne
|
||||||
|
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", foreignKey = @ForeignKey(name = "FK_IDXCMBTOKNU_RES_ID"))
|
||||||
|
private ResourceTable myResource;
|
||||||
|
|
||||||
|
@Column(name = "RES_ID", insertable = false, updatable = false)
|
||||||
|
private Long myResourceId;
|
||||||
|
|
||||||
|
@Column(name = "HASH_COMPLETE", nullable = false)
|
||||||
|
private Long myHashComplete;
|
||||||
|
|
||||||
|
@Column(name = "IDX_STRING", nullable = false, length = ResourceIndexedComboStringUnique.MAX_STRING_LENGTH)
|
||||||
|
private String myIndexString;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
private transient PartitionSettings myPartitionSettings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public ResourceIndexedComboTokenNonUnique() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceIndexedComboTokenNonUnique(PartitionSettings thePartitionSettings, ResourceTable theEntity, String theQueryString) {
|
||||||
|
myPartitionSettings = thePartitionSettings;
|
||||||
|
myResource = theEntity;
|
||||||
|
myIndexString = theQueryString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIndexString() {
|
||||||
|
return myIndexString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIndexString(String theIndexString) {
|
||||||
|
myIndexString = theIndexString;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object theO) {
|
||||||
|
if (this == theO) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theO == null || getClass() != theO.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourceIndexedComboTokenNonUnique that = (ResourceIndexedComboTokenNonUnique) theO;
|
||||||
|
|
||||||
|
return new EqualsBuilder()
|
||||||
|
.append(myResource, that.myResource)
|
||||||
|
.append(myHashComplete, that.myHashComplete)
|
||||||
|
.isEquals();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T extends BaseResourceIndex> void copyMutableValuesFrom(T theSource) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long getId() {
|
||||||
|
return myId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setId(Long theId) {
|
||||||
|
myId = theId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void calculateHashes() {
|
||||||
|
PartitionSettings partitionSettings = getPartitionSettings();
|
||||||
|
PartitionablePartitionId partitionId = getPartitionId();
|
||||||
|
String queryString = myIndexString;
|
||||||
|
setHashComplete(calculateHashComplete(partitionSettings, partitionId, queryString));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return new HashCodeBuilder(17, 37)
|
||||||
|
.append(myResource)
|
||||||
|
.append(myHashComplete)
|
||||||
|
.toHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public PartitionSettings getPartitionSettings() {
|
||||||
|
return myPartitionSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourceTable getResource() {
|
||||||
|
return myResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResource(ResourceTable theResource) {
|
||||||
|
myResource = theResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getHashComplete() {
|
||||||
|
return myHashComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHashComplete(Long theHashComplete) {
|
||||||
|
myHashComplete = theHashComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int compareTo(ResourceIndexedComboTokenNonUnique theO) {
|
||||||
|
CompareToBuilder b = new CompareToBuilder();
|
||||||
|
b.append(myHashComplete, theO.getHashComplete());
|
||||||
|
return b.toComparison();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this)
|
||||||
|
.append("id", myId)
|
||||||
|
.append("resourceId", myResourceId)
|
||||||
|
.append("hashComplete", myHashComplete)
|
||||||
|
.append("indexString", myIndexString)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long calculateHashComplete(PartitionSettings partitionSettings, PartitionablePartitionId thePartitionId, String queryString) {
|
||||||
|
RequestPartitionId requestPartitionId = PartitionablePartitionId.toRequestPartitionId(thePartitionId);
|
||||||
|
return hash(partitionSettings, requestPartitionId, queryString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long calculateHashComplete(PartitionSettings partitionSettings, RequestPartitionId partitionId, String queryString) {
|
||||||
|
return hash(partitionSettings, partitionId, queryString);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -192,11 +192,20 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
// Added in 3.0.0 - Should make this a primitive Boolean at some point
|
// Added in 3.0.0 - Should make this a primitive Boolean at some point
|
||||||
@OptimisticLock(excluded = true)
|
@OptimisticLock(excluded = true)
|
||||||
@Column(name = "SP_CMPSTR_UNIQ_PRESENT")
|
@Column(name = "SP_CMPSTR_UNIQ_PRESENT")
|
||||||
private Boolean myParamsCompositeStringUniquePresent = false;
|
private Boolean myParamsComboStringUniquePresent = false;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
|
@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
|
||||||
@OptimisticLock(excluded = true)
|
@OptimisticLock(excluded = true)
|
||||||
private Collection<ResourceIndexedCompositeStringUnique> myParamsCompositeStringUnique;
|
private Collection<ResourceIndexedComboStringUnique> myParamsComboStringUnique;
|
||||||
|
|
||||||
|
// Added in 5.5.0 - Should make this a primitive Boolean at some point
|
||||||
|
@OptimisticLock(excluded = true)
|
||||||
|
@Column(name = "SP_CMPTOKS_PRESENT")
|
||||||
|
private Boolean myParamsComboTokensNonUniquePresent = false;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "myResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
|
||||||
|
@OptimisticLock(excluded = true)
|
||||||
|
private Collection<ResourceIndexedComboTokenNonUnique> myParamsComboTokensNonUnique;
|
||||||
|
|
||||||
@OneToMany(mappedBy = "mySourceResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
|
@OneToMany(mappedBy = "mySourceResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
|
||||||
@OptimisticLock(excluded = true)
|
@OptimisticLock(excluded = true)
|
||||||
|
@ -312,11 +321,18 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
myLanguage = theLanguage;
|
myLanguage = theLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<ResourceIndexedCompositeStringUnique> getParamsCompositeStringUnique() {
|
public Collection<ResourceIndexedComboStringUnique> getParamsComboStringUnique() {
|
||||||
if (myParamsCompositeStringUnique == null) {
|
if (myParamsComboStringUnique == null) {
|
||||||
myParamsCompositeStringUnique = new ArrayList<>();
|
myParamsComboStringUnique = new ArrayList<>();
|
||||||
}
|
}
|
||||||
return myParamsCompositeStringUnique;
|
return myParamsComboStringUnique;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<ResourceIndexedComboTokenNonUnique> getmyParamsComboTokensNonUnique() {
|
||||||
|
if (myParamsComboTokensNonUnique == null) {
|
||||||
|
myParamsComboTokensNonUnique = new ArrayList<>();
|
||||||
|
}
|
||||||
|
return myParamsComboTokensNonUnique;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<ResourceIndexedSearchParamCoords> getParamsCoords() {
|
public Collection<ResourceIndexedSearchParamCoords> getParamsCoords() {
|
||||||
|
@ -494,15 +510,26 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
myHasLinks = theHasLinks;
|
myHasLinks = theHasLinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isParamsCompositeStringUniquePresent() {
|
public boolean isParamsComboStringUniquePresent() {
|
||||||
if (myParamsCompositeStringUniquePresent == null) {
|
if (myParamsComboStringUniquePresent == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return myParamsCompositeStringUniquePresent;
|
return myParamsComboStringUniquePresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setParamsCompositeStringUniquePresent(boolean theParamsCompositeStringUniquePresent) {
|
public void setParamsComboStringUniquePresent(boolean theParamsComboStringUniquePresent) {
|
||||||
myParamsCompositeStringUniquePresent = theParamsCompositeStringUniquePresent;
|
myParamsComboStringUniquePresent = theParamsComboStringUniquePresent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isParamsComboTokensNonUniquePresent() {
|
||||||
|
if (myParamsComboTokensNonUniquePresent == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return myParamsComboTokensNonUniquePresent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParamsComboTokensNonUniquePresent(boolean theParamsComboTokensNonUniquePresent) {
|
||||||
|
myParamsComboStringUniquePresent = theParamsComboTokensNonUniquePresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isParamsCoordsPopulated() {
|
public boolean isParamsCoordsPopulated() {
|
||||||
|
|
|
@ -93,7 +93,7 @@ public abstract class BaseSearchParamExtractor implements ISearchParamExtractor
|
||||||
|
|
||||||
public static final Set<String> COORDS_INDEX_PATHS;
|
public static final Set<String> COORDS_INDEX_PATHS;
|
||||||
private static final Pattern SPLIT = Pattern.compile("\\||( or )");
|
private static final Pattern SPLIT = Pattern.compile("\\||( or )");
|
||||||
private static final Pattern SPLIT_R4 = Pattern.compile("\\|");
|
private static final Pattern SPLIT_R4 = Pattern.compile("\\s+\\|");
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseSearchParamExtractor.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseSearchParamExtractor.class);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
|
|
@ -26,7 +26,8 @@ import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboStringUnique;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedComboTokenNonUnique;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber;
|
||||||
|
@ -70,7 +71,8 @@ public final class ResourceIndexedSearchParams {
|
||||||
final public Collection<ResourceIndexedSearchParamUri> myUriParams = new ArrayList<>();
|
final public Collection<ResourceIndexedSearchParamUri> myUriParams = new ArrayList<>();
|
||||||
final public Collection<ResourceIndexedSearchParamCoords> myCoordsParams = new ArrayList<>();
|
final public Collection<ResourceIndexedSearchParamCoords> myCoordsParams = new ArrayList<>();
|
||||||
|
|
||||||
final public Collection<ResourceIndexedCompositeStringUnique> myCompositeStringUniques = new HashSet<>();
|
final public Collection<ResourceIndexedComboStringUnique> myComboStringUniques = new HashSet<>();
|
||||||
|
final public Collection<ResourceIndexedComboTokenNonUnique> myComboTokenNonUnique = new HashSet<>();
|
||||||
final public Collection<ResourceLink> myLinks = new HashSet<>();
|
final public Collection<ResourceLink> myLinks = new HashSet<>();
|
||||||
final public Set<String> myPopulatedResourceLinkParameters = new HashSet<>();
|
final public Set<String> myPopulatedResourceLinkParameters = new HashSet<>();
|
||||||
|
|
||||||
|
@ -106,8 +108,11 @@ public final class ResourceIndexedSearchParams {
|
||||||
myLinks.addAll(theEntity.getResourceLinks());
|
myLinks.addAll(theEntity.getResourceLinks());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theEntity.isParamsCompositeStringUniquePresent()) {
|
if (theEntity.isParamsComboStringUniquePresent()) {
|
||||||
myCompositeStringUniques.addAll(theEntity.getParamsCompositeStringUnique());
|
myComboStringUniques.addAll(theEntity.getParamsComboStringUnique());
|
||||||
|
}
|
||||||
|
if (theEntity.isParamsComboTokensNonUniquePresent()) {
|
||||||
|
myComboTokenNonUnique.addAll(theEntity.getmyParamsComboTokensNonUnique());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +130,7 @@ public final class ResourceIndexedSearchParams {
|
||||||
theEntity.setParamsDatePopulated(myDateParams.isEmpty() == false);
|
theEntity.setParamsDatePopulated(myDateParams.isEmpty() == false);
|
||||||
theEntity.setParamsUriPopulated(myUriParams.isEmpty() == false);
|
theEntity.setParamsUriPopulated(myUriParams.isEmpty() == false);
|
||||||
theEntity.setParamsCoordsPopulated(myCoordsParams.isEmpty() == false);
|
theEntity.setParamsCoordsPopulated(myCoordsParams.isEmpty() == false);
|
||||||
theEntity.setParamsCompositeStringUniquePresent(myCompositeStringUniques.isEmpty() == false);
|
theEntity.setParamsComboStringUniquePresent(myComboStringUniques.isEmpty() == false);
|
||||||
theEntity.setHasLinks(myLinks.isEmpty() == false);
|
theEntity.setHasLinks(myLinks.isEmpty() == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +310,8 @@ public final class ResourceIndexedSearchParams {
|
||||||
", dateParams=" + myDateParams +
|
", dateParams=" + myDateParams +
|
||||||
", uriParams=" + myUriParams +
|
", uriParams=" + myUriParams +
|
||||||
", coordsParams=" + myCoordsParams +
|
", coordsParams=" + myCoordsParams +
|
||||||
", compositeStringUniques=" + myCompositeStringUniques +
|
", comboStringUniques=" + myComboStringUniques +
|
||||||
|
", comboTokenNonUniques=" + myComboTokenNonUnique +
|
||||||
", links=" + myLinks +
|
", links=" + myLinks +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
@ -431,6 +437,9 @@ public final class ResourceIndexedSearchParams {
|
||||||
List<String> values = new ArrayList<>();
|
List<String> values = new ArrayList<>();
|
||||||
Set<String> queryStringsToPopulate = new HashSet<>();
|
Set<String> queryStringsToPopulate = new HashSet<>();
|
||||||
extractCompositeStringUniquesValueChains(theResourceType, thePartsChoices, values, queryStringsToPopulate);
|
extractCompositeStringUniquesValueChains(theResourceType, thePartsChoices, values, queryStringsToPopulate);
|
||||||
|
|
||||||
|
values.removeIf(StringUtils::isBlank);
|
||||||
|
|
||||||
return queryStringsToPopulate;
|
return queryStringsToPopulate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,26 +40,25 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
public class JpaSearchParamCache {
|
public class JpaSearchParamCache {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(JpaSearchParamCache.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(JpaSearchParamCache.class);
|
||||||
|
|
||||||
private volatile Map<String, List<RuntimeSearchParam>> myActiveUniqueSearchParams = Collections.emptyMap();
|
private volatile Map<String, List<RuntimeSearchParam>> myActiveComboSearchParams = Collections.emptyMap();
|
||||||
private volatile Map<String, Map<Set<String>, List<RuntimeSearchParam>>> myActiveParamNamesToUniqueSearchParams = Collections.emptyMap();
|
private volatile Map<String, Map<Set<String>, List<RuntimeSearchParam>>> myActiveParamNamesToComboSearchParams = Collections.emptyMap();
|
||||||
|
|
||||||
public List<RuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName) {
|
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
|
||||||
List<RuntimeSearchParam> retval = myActiveUniqueSearchParams.get(theResourceName);
|
List<RuntimeSearchParam> retval = myActiveComboSearchParams.get(theResourceName);
|
||||||
if (retval == null) {
|
if (retval == null) {
|
||||||
retval = Collections.emptyList();
|
retval = Collections.emptyList();
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<RuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName, Set<String> theParamNames) {
|
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
|
||||||
Map<Set<String>, List<RuntimeSearchParam>> paramNamesToParams = myActiveParamNamesToUniqueSearchParams.get(theResourceName);
|
Map<Set<String>, List<RuntimeSearchParam>> paramNamesToParams = myActiveParamNamesToComboSearchParams.get(theResourceName);
|
||||||
if (paramNamesToParams == null) {
|
if (paramNamesToParams == null) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
@ -72,8 +71,8 @@ public class JpaSearchParamCache {
|
||||||
}
|
}
|
||||||
|
|
||||||
void populateActiveSearchParams(IInterceptorService theInterceptorBroadcaster, IPhoneticEncoder theDefaultPhoneticEncoder, RuntimeSearchParamCache theActiveSearchParams) {
|
void populateActiveSearchParams(IInterceptorService theInterceptorBroadcaster, IPhoneticEncoder theDefaultPhoneticEncoder, RuntimeSearchParamCache theActiveSearchParams) {
|
||||||
Map<String, List<RuntimeSearchParam>> activeUniqueSearchParams = new HashMap<>();
|
Map<String, List<RuntimeSearchParam>> resourceNameToComboSearchParams = new HashMap<>();
|
||||||
Map<String, Map<Set<String>, List<RuntimeSearchParam>>> activeParamNamesToUniqueSearchParams = new HashMap<>();
|
Map<String, Map<Set<String>, List<RuntimeSearchParam>>> activeParamNamesToComboSearchParams = new HashMap<>();
|
||||||
|
|
||||||
Map<String, RuntimeSearchParam> idToRuntimeSearchParam = new HashMap<>();
|
Map<String, RuntimeSearchParam> idToRuntimeSearchParam = new HashMap<>();
|
||||||
List<RuntimeSearchParam> jpaSearchParams = new ArrayList<>();
|
List<RuntimeSearchParam> jpaSearchParams = new ArrayList<>();
|
||||||
|
@ -83,7 +82,7 @@ public class JpaSearchParamCache {
|
||||||
*/
|
*/
|
||||||
for (String theResourceName : theActiveSearchParams.getResourceNameKeys()) {
|
for (String theResourceName : theActiveSearchParams.getResourceNameKeys()) {
|
||||||
Map<String, RuntimeSearchParam> searchParamMap = theActiveSearchParams.getSearchParamMap(theResourceName);
|
Map<String, RuntimeSearchParam> searchParamMap = theActiveSearchParams.getSearchParamMap(theResourceName);
|
||||||
List<RuntimeSearchParam> uniqueSearchParams = activeUniqueSearchParams.computeIfAbsent(theResourceName, k -> new ArrayList<>());
|
List<RuntimeSearchParam> comboSearchParams = resourceNameToComboSearchParams.computeIfAbsent(theResourceName, k -> new ArrayList<>());
|
||||||
Collection<RuntimeSearchParam> nextSearchParamsForResourceName = searchParamMap.values();
|
Collection<RuntimeSearchParam> nextSearchParamsForResourceName = searchParamMap.values();
|
||||||
|
|
||||||
ourLog.trace("Resource {} has {} params", theResourceName, searchParamMap.size());
|
ourLog.trace("Resource {} has {} params", theResourceName, searchParamMap.size());
|
||||||
|
@ -99,10 +98,9 @@ public class JpaSearchParamCache {
|
||||||
idToRuntimeSearchParam.put(nextCandidate.getUri(), nextCandidate);
|
idToRuntimeSearchParam.put(nextCandidate.getUri(), nextCandidate);
|
||||||
}
|
}
|
||||||
|
|
||||||
RuntimeSearchParam nextCandidateCasted = nextCandidate;
|
jpaSearchParams.add(nextCandidate);
|
||||||
jpaSearchParams.add(nextCandidateCasted);
|
if (nextCandidate.getComboSearchParamType() != null) {
|
||||||
if (nextCandidateCasted.isUnique()) {
|
comboSearchParams.add(nextCandidate);
|
||||||
uniqueSearchParams.add(nextCandidateCasted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setPhoneticEncoder(theDefaultPhoneticEncoder, nextCandidate);
|
setPhoneticEncoder(theDefaultPhoneticEncoder, nextCandidate);
|
||||||
|
@ -137,19 +135,19 @@ public class JpaSearchParamCache {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (next.isUnique()) {
|
if (next.getComboSearchParamType() != null) {
|
||||||
for (String nextBase : next.getBase()) {
|
for (String nextBase : next.getBase()) {
|
||||||
activeParamNamesToUniqueSearchParams.computeIfAbsent(nextBase, v -> new HashMap<>());
|
activeParamNamesToComboSearchParams.computeIfAbsent(nextBase, v -> new HashMap<>());
|
||||||
activeParamNamesToUniqueSearchParams.get(nextBase).computeIfAbsent(paramNames, t -> new ArrayList<>());
|
activeParamNamesToComboSearchParams.get(nextBase).computeIfAbsent(paramNames, t -> new ArrayList<>());
|
||||||
activeParamNamesToUniqueSearchParams.get(nextBase).get(paramNames).add(next);
|
activeParamNamesToComboSearchParams.get(nextBase).get(paramNames).add(next);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Have {} unique search params", activeParamNamesToUniqueSearchParams.size());
|
ourLog.info("Have {} unique search params", activeParamNamesToComboSearchParams.size());
|
||||||
|
|
||||||
myActiveUniqueSearchParams = activeUniqueSearchParams;
|
myActiveComboSearchParams = resourceNameToComboSearchParams;
|
||||||
myActiveParamNamesToUniqueSearchParams = activeParamNamesToUniqueSearchParams;
|
myActiveParamNamesToComboSearchParams = activeParamNamesToComboSearchParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPhoneticEncoder(IPhoneticEncoder theDefaultPhoneticEncoder, RuntimeSearchParam searchParam) {
|
void setPhoneticEncoder(IPhoneticEncoder theDefaultPhoneticEncoder, RuntimeSearchParam searchParam) {
|
||||||
|
|
|
@ -109,13 +109,13 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry, IResourceC
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName) {
|
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
|
||||||
return myJpaSearchParamCache.getActiveUniqueSearchParams(theResourceName);
|
return myJpaSearchParamCache.getActiveComboSearchParams(theResourceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName, Set<String> theParamNames) {
|
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
|
||||||
return myJpaSearchParamCache.getActiveUniqueSearchParams(theResourceName, theParamNames);
|
return myJpaSearchParamCache.getActiveComboSearchParams(theResourceName, theParamNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.searchparam.registry;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ComboSearchParamType;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum;
|
import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum;
|
||||||
|
@ -148,14 +149,16 @@ public class SearchParameterCanonicalizer {
|
||||||
|
|
||||||
IIdType id = theNextSp.getIdElement();
|
IIdType id = theNextSp.getIdElement();
|
||||||
String uri = "";
|
String uri = "";
|
||||||
boolean unique = false;
|
ComboSearchParamType unique = null;
|
||||||
|
|
||||||
List<ExtensionDt> uniqueExts = theNextSp.getUndeclaredExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE);
|
List<ExtensionDt> uniqueExts = theNextSp.getUndeclaredExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE);
|
||||||
if (uniqueExts.size() > 0) {
|
if (uniqueExts.size() > 0) {
|
||||||
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
||||||
if (uniqueExtsValuePrimitive != null) {
|
if (uniqueExtsValuePrimitive != null) {
|
||||||
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||||
unique = true;
|
unique = ComboSearchParamType.UNIQUE;
|
||||||
|
} else if ("false".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||||
|
unique = ComboSearchParamType.NON_UNIQUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,14 +231,16 @@ public class SearchParameterCanonicalizer {
|
||||||
|
|
||||||
IIdType id = theNextSp.getIdElement();
|
IIdType id = theNextSp.getIdElement();
|
||||||
String uri = "";
|
String uri = "";
|
||||||
boolean unique = false;
|
ComboSearchParamType unique = null;
|
||||||
|
|
||||||
List<Extension> uniqueExts = theNextSp.getExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE);
|
List<Extension> uniqueExts = theNextSp.getExtensionsByUrl(HapiExtensions.EXT_SP_UNIQUE);
|
||||||
if (uniqueExts.size() > 0) {
|
if (uniqueExts.size() > 0) {
|
||||||
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
||||||
if (uniqueExtsValuePrimitive != null) {
|
if (uniqueExtsValuePrimitive != null) {
|
||||||
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||||
unique = true;
|
unique = ComboSearchParamType.UNIQUE;
|
||||||
|
} else if ("false".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||||
|
unique = ComboSearchParamType.NON_UNIQUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -311,7 +316,7 @@ public class SearchParameterCanonicalizer {
|
||||||
|
|
||||||
IIdType id = theNextSp.getIdElement();
|
IIdType id = theNextSp.getIdElement();
|
||||||
String uri = terser.getSinglePrimitiveValueOrNull(theNextSp, "url");
|
String uri = terser.getSinglePrimitiveValueOrNull(theNextSp, "url");
|
||||||
boolean unique = false;
|
ComboSearchParamType unique = null;
|
||||||
|
|
||||||
String value = ((IBaseHasExtensions) theNextSp).getExtension()
|
String value = ((IBaseHasExtensions) theNextSp).getExtension()
|
||||||
.stream()
|
.stream()
|
||||||
|
@ -322,7 +327,9 @@ public class SearchParameterCanonicalizer {
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse("");
|
.orElse("");
|
||||||
if ("true".equalsIgnoreCase(value)) {
|
if ("true".equalsIgnoreCase(value)) {
|
||||||
unique = true;
|
unique = ComboSearchParamType.UNIQUE;
|
||||||
|
} else if ("false".equalsIgnoreCase(value)) {
|
||||||
|
unique = ComboSearchParamType.NON_UNIQUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RuntimeSearchParam.Component> components = new ArrayList<>();
|
List<RuntimeSearchParam.Component> components = new ArrayList<>();
|
||||||
|
|
|
@ -132,11 +132,11 @@ public class SearchParamExtractorDstu3Test {
|
||||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, searchParamRegistry);
|
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, searchParamRegistry);
|
||||||
extractor.start();
|
extractor.start();
|
||||||
|
|
||||||
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "", RestSearchParameterTypeEnum.STRING, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null));
|
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "", RestSearchParameterTypeEnum.STRING, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null));
|
||||||
Patient resource = new Patient();
|
Patient resource = new Patient();
|
||||||
extractor.extractSearchParamStrings(resource);
|
extractor.extractSearchParamStrings(resource);
|
||||||
|
|
||||||
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", null, RestSearchParameterTypeEnum.STRING, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null));
|
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", null, RestSearchParameterTypeEnum.STRING, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null));
|
||||||
extractor.extractSearchParamStrings(resource);
|
extractor.extractSearchParamStrings(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +148,7 @@ public class SearchParamExtractorDstu3Test {
|
||||||
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, searchParamRegistry);
|
SearchParamExtractorDstu3 extractor = new SearchParamExtractorDstu3(new ModelConfig(), new PartitionSettings(), ourCtx, searchParamRegistry);
|
||||||
extractor.start();
|
extractor.start();
|
||||||
|
|
||||||
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "communication.language.coding.system | communication.language.coding.code", RestSearchParameterTypeEnum.STRING, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null));
|
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "communication.language.coding.system | communication.language.coding.code", RestSearchParameterTypeEnum.STRING, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null));
|
||||||
Patient resource = new Patient();
|
Patient resource = new Patient();
|
||||||
resource.getCommunicationFirstRep().getLanguage().getCodingFirstRep().setCode("blah");
|
resource.getCommunicationFirstRep().getLanguage().getCodingFirstRep().setCode("blah");
|
||||||
Set<ResourceIndexedSearchParamString> strings = extractor.extractSearchParamStrings(resource);
|
Set<ResourceIndexedSearchParamString> strings = extractor.extractSearchParamStrings(resource);
|
||||||
|
@ -166,37 +166,37 @@ public class SearchParamExtractorDstu3Test {
|
||||||
extractor.start();
|
extractor.start();
|
||||||
|
|
||||||
{
|
{
|
||||||
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "Patient", RestSearchParameterTypeEnum.STRING, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null));
|
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "Patient", RestSearchParameterTypeEnum.STRING, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null));
|
||||||
Patient resource = new Patient();
|
Patient resource = new Patient();
|
||||||
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamString> outcome = extractor.extractSearchParamStrings(resource);
|
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamString> outcome = extractor.extractSearchParamStrings(resource);
|
||||||
assertThat(outcome.getWarnings(), Matchers.contains("Search param foo is of unexpected datatype: class org.hl7.fhir.dstu3.model.Patient"));
|
assertThat(outcome.getWarnings(), Matchers.contains("Search param foo is of unexpected datatype: class org.hl7.fhir.dstu3.model.Patient"));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "Patient", RestSearchParameterTypeEnum.TOKEN, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null));
|
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "Patient", RestSearchParameterTypeEnum.TOKEN, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null));
|
||||||
Patient resource = new Patient();
|
Patient resource = new Patient();
|
||||||
ISearchParamExtractor.SearchParamSet<BaseResourceIndexedSearchParam> outcome = extractor.extractSearchParamTokens(resource);
|
ISearchParamExtractor.SearchParamSet<BaseResourceIndexedSearchParam> outcome = extractor.extractSearchParamTokens(resource);
|
||||||
assertThat(outcome.getWarnings(), Matchers.contains("Search param foo is of unexpected datatype: class org.hl7.fhir.dstu3.model.Patient"));
|
assertThat(outcome.getWarnings(), Matchers.contains("Search param foo is of unexpected datatype: class org.hl7.fhir.dstu3.model.Patient"));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "Patient", RestSearchParameterTypeEnum.QUANTITY, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null));
|
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "Patient", RestSearchParameterTypeEnum.QUANTITY, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null));
|
||||||
Patient resource = new Patient();
|
Patient resource = new Patient();
|
||||||
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamQuantity> outcome = extractor.extractSearchParamQuantity(resource);
|
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamQuantity> outcome = extractor.extractSearchParamQuantity(resource);
|
||||||
assertThat(outcome.getWarnings(), Matchers.contains("Search param foo is of unexpected datatype: class org.hl7.fhir.dstu3.model.Patient"));
|
assertThat(outcome.getWarnings(), Matchers.contains("Search param foo is of unexpected datatype: class org.hl7.fhir.dstu3.model.Patient"));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "Patient", RestSearchParameterTypeEnum.DATE, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null));
|
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "Patient", RestSearchParameterTypeEnum.DATE, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null));
|
||||||
Patient resource = new Patient();
|
Patient resource = new Patient();
|
||||||
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamDate> outcome = extractor.extractSearchParamDates(resource);
|
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamDate> outcome = extractor.extractSearchParamDates(resource);
|
||||||
assertThat(outcome.getWarnings(), Matchers.contains("Search param foo is of unexpected datatype: class org.hl7.fhir.dstu3.model.Patient"));
|
assertThat(outcome.getWarnings(), Matchers.contains("Search param foo is of unexpected datatype: class org.hl7.fhir.dstu3.model.Patient"));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "Patient", RestSearchParameterTypeEnum.NUMBER, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null));
|
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "Patient", RestSearchParameterTypeEnum.NUMBER, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null));
|
||||||
Patient resource = new Patient();
|
Patient resource = new Patient();
|
||||||
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamNumber> outcome = extractor.extractSearchParamNumber(resource);
|
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamNumber> outcome = extractor.extractSearchParamNumber(resource);
|
||||||
assertThat(outcome.getWarnings(), Matchers.contains("Search param foo is of unexpected datatype: class org.hl7.fhir.dstu3.model.Patient"));
|
assertThat(outcome.getWarnings(), Matchers.contains("Search param foo is of unexpected datatype: class org.hl7.fhir.dstu3.model.Patient"));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "Patient", RestSearchParameterTypeEnum.URI, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null));
|
searchParamRegistry.addSearchParam(new RuntimeSearchParam(null, null, "foo", "foo", "Patient", RestSearchParameterTypeEnum.URI, Sets.newHashSet(), Sets.newHashSet(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, null, null, null));
|
||||||
Patient resource = new Patient();
|
Patient resource = new Patient();
|
||||||
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamUri> outcome = extractor.extractSearchParamUri(resource);
|
ISearchParamExtractor.SearchParamSet<ResourceIndexedSearchParamUri> outcome = extractor.extractSearchParamUri(resource);
|
||||||
assertThat(outcome.getWarnings(), Matchers.contains("Search param foo is of unexpected datatype: class org.hl7.fhir.dstu3.model.Patient"));
|
assertThat(outcome.getWarnings(), Matchers.contains("Search param foo is of unexpected datatype: class org.hl7.fhir.dstu3.model.Patient"));
|
||||||
|
@ -269,7 +269,7 @@ public class SearchParamExtractorDstu3Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName, Set<String> theParamNames) {
|
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -280,7 +280,7 @@ public class SearchParamExtractorDstu3Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName) {
|
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -282,7 +282,7 @@ public class SearchParamExtractorMegaTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName, Set<String> theParamNames) {
|
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,7 +293,7 @@ public class SearchParamExtractorMegaTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName) {
|
public List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,13 +59,13 @@ public class InMemoryResourceMatcherR5Test {
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void before() {
|
public void before() {
|
||||||
RuntimeSearchParam dateSearchParam = new RuntimeSearchParam(null, null, null, null, "Observation.effective", RestSearchParameterTypeEnum.DATE, null, null, RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null);
|
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("Observation", "date")).thenReturn(dateSearchParam);
|
||||||
|
|
||||||
RuntimeSearchParam codeSearchParam = new RuntimeSearchParam(null, null, null, null, "Observation.code", RestSearchParameterTypeEnum.TOKEN, null, null, RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null);
|
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("Observation", "code")).thenReturn(codeSearchParam);
|
||||||
|
|
||||||
RuntimeSearchParam encSearchParam = new RuntimeSearchParam(null, null, null, null, "Observation.encounter", RestSearchParameterTypeEnum.REFERENCE, null, null, RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null);
|
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("Observation", "encounter")).thenReturn(encSearchParam);
|
||||||
|
|
||||||
myObservation = new Observation();
|
myObservation = new Observation();
|
||||||
|
|
|
@ -293,7 +293,7 @@ public class SearchParamRegistryImplTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetActiveUniqueSearchParams_Empty() {
|
public void testGetActiveUniqueSearchParams_Empty() {
|
||||||
assertThat(mySearchParamRegistry.getActiveUniqueSearchParams("Patient"), is(empty()));
|
assertThat(mySearchParamRegistry.getActiveComboSearchParams("Patient"), is(empty()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -45,7 +45,7 @@ public class EIDHelperR4Test extends BaseR4Test {
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void before() {
|
public void before() {
|
||||||
when(mySearchParamRetriever.getActiveSearchParam("Patient", "identifier"))
|
when(mySearchParamRetriever.getActiveSearchParam("Patient", "identifier"))
|
||||||
.thenReturn(new RuntimeSearchParam(null, null, "identifier", "Description", "identifier", RestSearchParameterTypeEnum.STRING, new HashSet<>(), new HashSet<>(), RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE, false, null, null));
|
.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)) {
|
myMdmSettings = new MdmSettings(new MdmRuleValidator(ourFhirContext, mySearchParamRetriever)) {
|
||||||
{
|
{
|
||||||
|
|
|
@ -496,7 +496,7 @@ public class RestfulServerConfiguration implements ISearchParamRegistry {
|
||||||
Set<String> targets = Collections.emptySet();
|
Set<String> targets = Collections.emptySet();
|
||||||
RuntimeSearchParam.RuntimeSearchParamStatusEnum status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE;
|
RuntimeSearchParam.RuntimeSearchParamStatusEnum status = RuntimeSearchParam.RuntimeSearchParamStatusEnum.ACTIVE;
|
||||||
Collection<String> base = Collections.singletonList(theSearchMethodBinding.getResourceName());
|
Collection<String> base = Collections.singletonList(theSearchMethodBinding.getResourceName());
|
||||||
RuntimeSearchParam param = new RuntimeSearchParam(id, uri, nextParamName, description, path, type, providesMembershipInCompartments, targets, status, false, null, base);
|
RuntimeSearchParam param = new RuntimeSearchParam(id, uri, nextParamName, description, path, type, providesMembershipInCompartments, targets, status, null, null, base);
|
||||||
theMapToPopulate.put(nextParamName, param);
|
theMapToPopulate.put(nextParamName, param);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,11 +70,11 @@ public interface ISearchParamRegistry {
|
||||||
default void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {
|
default void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<RuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName) {
|
default List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
default List<RuntimeSearchParam> getActiveUniqueSearchParams(String theResourceName, Set<String> theParamNames) {
|
default List<RuntimeSearchParam> getActiveComboSearchParams(String theResourceName, Set<String> theParamNames) {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue