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 068c06c5fe9..68970015719 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 @@ -1044,7 +1044,13 @@ public class QueryStack { Expression subSelect = new Subquery(sql); join = mySqlBuilder.getOrCreateFirstPredicateBuilder(); - predicate = new InCondition(join.getResourceIdColumn(), subSelect).setNegate(true); + + if (theSourceJoinColumn == null) { + predicate = new InCondition(join.getResourceIdColumn(), subSelect).setNegate(true); + } else { + //-- for the resource link, need join with target_resource_id + predicate = new InCondition(theSourceJoinColumn, subSelect).setNegate(true); + } } else { 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 aa1e6d7ea7e..ffa9f7a0d8b 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 @@ -62,6 +62,7 @@ import ca.uhn.fhir.rest.param.ReferenceParam; import ca.uhn.fhir.rest.param.SpecialParam; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.TokenParam; +import ca.uhn.fhir.rest.param.TokenParamModifier; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; @@ -338,6 +339,7 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder { boolean foundChainMatch = false; List candidateTargetTypes = new ArrayList<>(); List orPredicates = new ArrayList<>(); + boolean paramInverted = false; QueryStack childQueryFactory = myQueryStack.newChildQueryFactoryWithFullBuilderReuse(); for (String nextType : resourceTypes) { String chain = theReferenceParam.getChain(); @@ -383,6 +385,13 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder { if (chainValue == null) { continue; } + + // For the token param, if it's a :not modifier, need switch OR to AND + if (!paramInverted) { + if (((TokenParam) chainValue).getModifier() == TokenParamModifier.NOT) { + paramInverted = true; + } + } foundChainMatch = true; orValues.add(chainValue); } @@ -410,10 +419,17 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder { warnAboutPerformanceOnUnqualifiedResources(theParamName, theRequest, candidateTargetTypes); } - Condition multiTypeOrPredicate = toOrPredicate(orPredicates); + // If :not modifier for a token, switch OR with AND in the multi-type case + Condition multiTypePredicate; + if (paramInverted) { + multiTypePredicate = toAndPredicate(orPredicates); + } else { + multiTypePredicate = toOrPredicate(orPredicates); + } + List pathsToMatch = createResourceLinkPaths(theResourceName, theParamName); Condition pathPredicate = createPredicateSourcePaths(pathsToMatch); - return toAndPredicate(pathPredicate, multiTypeOrPredicate); + return toAndPredicate(pathPredicate, multiTypePredicate); } @Nonnull