diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/QueryStack.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/QueryStack.java index 565027be4cc..42de4a119e0 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/QueryStack.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/QueryStack.java @@ -1139,8 +1139,14 @@ public class QueryStack { // For now, leave the incorrect implementation alone, just in case someone is relying on it, // until the complete fix is available. andPredicates.add(createPredicateReferenceForContainedResource(null, theResourceName, theParamName, nextParamDef, nextAnd, null, theRequest, theRequestPartitionId)); + } else if (nextAnd.stream().filter(t -> t instanceof ReferenceParam).map(t -> (ReferenceParam) t).anyMatch(t -> t.getChain().contains("."))) { + // FIXME for now, restrict contained reference traversal to the last reference in the chain + andPredicates.add(createPredicateReference(theSourceJoinColumn, theResourceName, theParamName, nextAnd, null, theRequest, theRequestPartitionId)); } else { - andPredicates.add(createPredicateReference(theSourceJoinColumn, theResourceName, theParamName, nextAnd, null, theRequest, theRequestPartitionId)); + andPredicates.add(toOrPredicate( + createPredicateReference(theSourceJoinColumn, theResourceName, theParamName, nextAnd, null, theRequest, theRequestPartitionId), + createPredicateReferenceForContainedResource(theSourceJoinColumn, theResourceName, theParamName, nextParamDef, nextAnd, null, theRequest, theRequestPartitionId) + )); } } break; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/SearchBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/SearchBuilder.java index 9f14b0bd4d5..5152973bfff 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/SearchBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/SearchBuilder.java @@ -373,7 +373,7 @@ public class SearchBuilder implements ISearchBuilder { SearchQueryBuilder sqlBuilder = new SearchQueryBuilder(myContext, myDaoConfig.getModelConfig(), myPartitionSettings, myRequestPartitionId, sqlBuilderResourceName, mySqlBuilderFactory, myDialectProvider, theCount); 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) || isTraverseContainedReferenceAtRoot(theParams)) { List activeComboParams = mySearchParamRegistry.getActiveComboSearchParams(myResourceName, theParams.keySet()); if (activeComboParams.isEmpty()) { sqlBuilder.setNeedResourceTableRoot(true); @@ -483,6 +483,13 @@ public class SearchBuilder implements ISearchBuilder { return Optional.of(executor); } + private boolean isTraverseContainedReferenceAtRoot(SearchParameterMap theParams) { + return myModelConfig.isIndexOnContainedResources() && theParams.values().stream() + .flatMap(Collection::stream) + .flatMap(Collection::stream) + .anyMatch(t -> t instanceof ReferenceParam); + } + private List normalizeIdListForLastNInClause(List lastnResourceIds) { /* The following is a workaround to a known issue involving Hibernate. If queries are used with "in" clauses with large and varying diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/predicate/ResourceLinkPredicateBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/predicate/ResourceLinkPredicateBuilder.java index 0019801f5a0..9ff5581d3af 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/predicate/ResourceLinkPredicateBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/predicate/ResourceLinkPredicateBuilder.java @@ -402,10 +402,6 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder { andPredicates.add(childQueryFactory.searchForIdsWithAndOr(myColumnTargetResourceId, subResourceName, chain, chainParamValues, theRequest, theRequestPartitionId, SearchContainedModeEnum.FALSE)); orPredicates.add(toAndPredicate(andPredicates)); - - if (getModelConfig().isIndexOnContainedResources() && theReferenceParam.getChain().contains(".")) { - orPredicates.add(childQueryFactory.createPredicateReferenceForContainedResource(myColumnTargetResourceId, subResourceName, chain, param, orValues, null, theRequest, theRequestPartitionId)); - } } if (candidateTargetTypes.isEmpty()) { diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/ChainedContainedR4SearchTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/ChainedContainedR4SearchTest.java index 78f156df1fa..3a52940a811 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/ChainedContainedR4SearchTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/ChainedContainedR4SearchTest.java @@ -12,9 +12,9 @@ import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.StringType; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -93,7 +93,6 @@ public class ChainedContainedR4SearchTest extends BaseJpaR4Test { } @Test - @Disabled public void testShouldResolveATwoLinkChainWithAContainedResource() throws Exception { IIdType oid1; @@ -105,6 +104,7 @@ public class ChainedContainedR4SearchTest extends BaseJpaR4Test { Observation obs = new Observation(); obs.getContained().add(p); obs.getCode().setText("Observation 1"); + obs.setValue(new StringType("Test")); obs.getSubject().setReference("#pat"); oid1 = myObservationDao.create(obs, mySrd).getId().toUnqualifiedVersionless(); @@ -113,6 +113,7 @@ public class ChainedContainedR4SearchTest extends BaseJpaR4Test { } String url = "/Observation?subject.name=Smith"; +// String url = "/Observation?subject.name=Smith&value-string=Test"; myCaptureQueriesListener.clear(); List oids = searchAndReturnUnqualifiedVersionlessIdValues(url); ourLog.info(">>> " + myCaptureQueriesListener.getSelectQueriesForCurrentThread()); @@ -198,7 +199,6 @@ public class ChainedContainedR4SearchTest extends BaseJpaR4Test { } @Test - @Disabled public void testShouldResolveAThreeLinkChainWithAContainedResourceAtTheBeginningOfTheChain() throws Exception { // This case seems like it would be less frequent in production, but we don't want to // paint ourselves into a corner where we require the contained link to be the last