From 8e714b6b14adf2387bcfd84fb43bc74f819ce796 Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Mon, 30 Mar 2020 05:36:24 -0400 Subject: [PATCH] Work on uniques --- .../ca/uhn/fhir/jpa/dao/SearchBuilder.java | 13 +- .../dao/predicate/BasePredicateBuilder.java | 10 ++ .../jpa/dao/predicate/PredicateBuilder.java | 32 ++--- .../dao/predicate/PredicateBuilderCoords.java | 10 +- .../dao/predicate/PredicateBuilderDate.java | 8 +- .../dao/predicate/PredicateBuilderNumber.java | 8 +- .../predicate/PredicateBuilderQuantity.java | 10 +- .../predicate/PredicateBuilderReference.java | 30 ++--- .../dao/predicate/PredicateBuilderString.java | 10 +- .../dao/predicate/PredicateBuilderTag.java | 1 + .../dao/predicate/PredicateBuilderToken.java | 13 +- .../dao/predicate/PredicateBuilderUri.java | 6 +- .../fhir/jpa/dao/r4/PartitioningR4Test.java | 111 ++++++++++++++++++ .../ResourceIndexedCompositeStringUnique.java | 6 + 14 files changed, 214 insertions(+), 54 deletions(-) diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java index 2d68d0778a9..3599a7310d2 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/SearchBuilder.java @@ -871,7 +871,7 @@ public class SearchBuilder implements ISearchBuilder { .add(StorageProcessingMessage.class, msg); JpaInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequest, Pointcut.JPA_PERFTRACE_INFO, params); - addPredicateCompositeStringUnique(theParams, indexString); + addPredicateCompositeStringUnique(theParams, indexString, myPartitionId); } } } @@ -886,9 +886,16 @@ public class SearchBuilder implements ISearchBuilder { } } - private void addPredicateCompositeStringUnique(@Nonnull SearchParameterMap theParams, String theIndexedString) { - myQueryRoot.setHasIndexJoins(true); + private void addPredicateCompositeStringUnique(@Nonnull SearchParameterMap theParams, String theIndexedString, PartitionId thePartitionId) { Join join = myQueryRoot.join("myParamsCompositeStringUnique", JoinType.LEFT); + + if (thePartitionId != null) { + Integer partitionId = thePartitionId.getPartitionId(); + Predicate predicate = myCriteriaBuilder.equal(join.get("myPartitionIdValue").as(Integer.class), partitionId); + myQueryRoot.addPredicate(predicate); + } + + myQueryRoot.setHasIndexJoins(true); Predicate predicate = myCriteriaBuilder.equal(join.get("myIndexString"), theIndexedString); myQueryRoot.addPredicate(predicate); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/BasePredicateBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/BasePredicateBuilder.java index ed5f8a344d0..191844780a3 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/BasePredicateBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/BasePredicateBuilder.java @@ -24,9 +24,11 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.IDao; import ca.uhn.fhir.jpa.dao.SearchBuilder; +import ca.uhn.fhir.jpa.model.entity.BaseResourceIndex; import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam; import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate; +import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri; import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.entity.SearchParamPresent; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; @@ -203,6 +205,14 @@ abstract class BasePredicateBuilder { return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, num); } + void addPartitionIdPredicate(PartitionId thePartitionId, Join theJoin, List theCodePredicates) { + if (thePartitionId != null) { + Integer partitionId = thePartitionId.getPartitionId(); + Predicate partitionPredicate = myCriteriaBuilder.equal(theJoin.get("myPartitionIdValue").as(Integer.class), partitionId); + myQueryRoot.addPredicate(partitionPredicate); + } + } + static String createLeftAndRightMatchLikeExpression(String likeExpression) { return "%" + likeExpression.replace("%", "[%]") + "%"; } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilder.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilder.java index 7e88d5de53b..af31d66a1b2 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilder.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilder.java @@ -55,40 +55,40 @@ public class PredicateBuilder { myPredicateBuilderUri = thePredicateBuilderFactory.newPredicateBuilderUri(theSearchBuilder); } - void addPredicateCoords(String theResourceName, String theParamName, List theNextAnd) { - myPredicateBuilderCoords.addPredicate(theResourceName, theParamName, theNextAnd, null); + void addPredicateCoords(String theResourceName, String theParamName, List theNextAnd, PartitionId thePartitionId) { + myPredicateBuilderCoords.addPredicate(theResourceName, theParamName, theNextAnd, null, thePartitionId); } - Predicate addPredicateDate(String theResourceName, String theParamName, List theNextAnd, SearchFilterParser.CompareOperation theOperation) { - return myPredicateBuilderDate.addPredicate(theResourceName, theParamName, theNextAnd, theOperation); + Predicate addPredicateDate(String theResourceName, String theParamName, List theNextAnd, SearchFilterParser.CompareOperation theOperation, PartitionId thePartitionId) { + return myPredicateBuilderDate.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, thePartitionId); } - Predicate addPredicateNumber(String theResourceName, String theParamName, List theNextAnd, SearchFilterParser.CompareOperation theOperation) { - return myPredicateBuilderNumber.addPredicate(theResourceName, theParamName, theNextAnd, theOperation); + Predicate addPredicateNumber(String theResourceName, String theParamName, List theNextAnd, SearchFilterParser.CompareOperation theOperation, PartitionId thePartitionId) { + return myPredicateBuilderNumber.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, thePartitionId); } - Predicate addPredicateQuantity(String theResourceName, String theParamName, List theNextAnd, SearchFilterParser.CompareOperation theOperation) { - return myPredicateBuilderQuantity.addPredicate(theResourceName, theParamName, theNextAnd, theOperation); + Predicate addPredicateQuantity(String theResourceName, String theParamName, List theNextAnd, SearchFilterParser.CompareOperation theOperation, PartitionId thePartitionId) { + return myPredicateBuilderQuantity.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, thePartitionId); } - void addPredicateString(String theResourceName, String theParamName, List theNextAnd) { - myPredicateBuilderString.addPredicate(theResourceName, theParamName, theNextAnd, SearchFilterParser.CompareOperation.sw); + void addPredicateString(String theResourceName, String theParamName, List theNextAnd, PartitionId thePartitionId) { + myPredicateBuilderString.addPredicate(theResourceName, theParamName, theNextAnd, SearchFilterParser.CompareOperation.sw, thePartitionId); } - Predicate addPredicateString(String theResourceName, String theParamName, List theNextAnd, SearchFilterParser.CompareOperation theOperation) { - return myPredicateBuilderString.addPredicate(theResourceName, theParamName, theNextAnd, theOperation); + Predicate addPredicateString(String theResourceName, String theParamName, List theNextAnd, SearchFilterParser.CompareOperation theOperation, PartitionId thePartitionId) { + return myPredicateBuilderString.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, thePartitionId); } void addPredicateTag(List> theAndOrParams, String theParamName) { myPredicateBuilderTag.addPredicateTag(theAndOrParams, theParamName); } - Predicate addPredicateToken(String theResourceName, String theParamName, List theNextAnd, SearchFilterParser.CompareOperation theOperation) { - return myPredicateBuilderToken.addPredicate(theResourceName, theParamName, theNextAnd, theOperation); + Predicate addPredicateToken(String theResourceName, String theParamName, List theNextAnd, SearchFilterParser.CompareOperation theOperation, PartitionId thePartitionId) { + return myPredicateBuilderToken.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, thePartitionId); } - Predicate addPredicateUri(String theResourceName, String theName, List theSingletonList, SearchFilterParser.CompareOperation theOperation) { - return myPredicateBuilderUri.addPredicate(theResourceName, theName, theSingletonList, theOperation); + Predicate addPredicateUri(String theResourceName, String theName, List theSingletonList, SearchFilterParser.CompareOperation theOperation, PartitionId thePartitionId) { + return myPredicateBuilderUri.addPredicate(theResourceName, theName, theSingletonList, theOperation, thePartitionId); } public void searchForIdsWithAndOr(String theResourceName, String theNextParamName, List> theAndOrParams, RequestDetails theRequest, PartitionId thePartitionId) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderCoords.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderCoords.java index 933b7335e80..b00335fabe3 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderCoords.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderCoords.java @@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.dao.predicate; */ import ca.uhn.fhir.jpa.dao.SearchBuilder; +import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamCoords; import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.util.CoordCalculator; @@ -147,15 +148,18 @@ public class PredicateBuilderCoords extends BasePredicateBuilder implements IPre public Predicate addPredicate(String theResourceName, String theParamName, List theList, - SearchFilterParser.CompareOperation theOperation) { + SearchFilterParser.CompareOperation theOperation, + PartitionId thePartitionId) { Join join = createJoin(SearchBuilderJoinEnum.COORDS, theParamName); if (theList.get(0).getMissing() != null) { - addPredicateParamMissing(theResourceName, theParamName, theList.get(0).getMissing(), join); + addPredicateParamMissing(theResourceName, theParamName, theList.get(0).getMissing(), join, thePartitionId); return null; } - List codePredicates = new ArrayList(); + List codePredicates = new ArrayList<>(); + addPartitionIdPredicate(thePartitionId, join, codePredicates); + for (IQueryParameterType nextOr : theList) { Predicate singleCode = createPredicateCoords(nextOr, diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderDate.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderDate.java index 466182b138f..ec97488396c 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderDate.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderDate.java @@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.dao.predicate; */ import ca.uhn.fhir.jpa.dao.SearchBuilder; +import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate; import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.model.api.IQueryParameterType; @@ -58,7 +59,8 @@ public class PredicateBuilderDate extends BasePredicateBuilder implements IPredi public Predicate addPredicate(String theResourceName, String theParamName, List theList, - SearchFilterParser.CompareOperation operation) { + SearchFilterParser.CompareOperation operation, + PartitionId thePartitionId) { boolean newJoin = false; if (myJoinMap == null) { @@ -75,11 +77,13 @@ public class PredicateBuilderDate extends BasePredicateBuilder implements IPredi if (theList.get(0).getMissing() != null) { Boolean missing = theList.get(0).getMissing(); - addPredicateParamMissing(theResourceName, theParamName, missing, join); + addPredicateParamMissing(theResourceName, theParamName, missing, join, thePartitionId); return null; } List codePredicates = new ArrayList<>(); + addPartitionIdPredicate(thePartitionId, join, codePredicates); + for (IQueryParameterType nextOr : theList) { IQueryParameterType params = nextOr; Predicate p = createPredicateDate(params, diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderNumber.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderNumber.java index 21f46c0635c..e2078552568 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderNumber.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderNumber.java @@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.dao.predicate; */ import ca.uhn.fhir.jpa.dao.SearchBuilder; +import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamNumber; import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.model.api.IQueryParameterType; @@ -53,16 +54,19 @@ class PredicateBuilderNumber extends BasePredicateBuilder implements IPredicateB public Predicate addPredicate(String theResourceName, String theParamName, List theList, - SearchFilterParser.CompareOperation operation) { + SearchFilterParser.CompareOperation operation, + PartitionId thePartitionId) { Join join = createJoin(SearchBuilderJoinEnum.NUMBER, theParamName); if (theList.get(0).getMissing() != null) { - addPredicateParamMissing(theResourceName, theParamName, theList.get(0).getMissing(), join); + addPredicateParamMissing(theResourceName, theParamName, theList.get(0).getMissing(), join, thePartitionId); return null; } List codePredicates = new ArrayList<>(); + addPartitionIdPredicate(thePartitionId, join, codePredicates); + for (IQueryParameterType nextOr : theList) { if (nextOr instanceof NumberParam) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderQuantity.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderQuantity.java index e9737ee56df..11747869515 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderQuantity.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderQuantity.java @@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.dao.predicate; import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam; +import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamQuantity; import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.model.api.IQueryParameterType; @@ -51,16 +52,19 @@ class PredicateBuilderQuantity extends BasePredicateBuilder implements IPredicat public Predicate addPredicate(String theResourceName, String theParamName, List theList, - SearchFilterParser.CompareOperation operation) { + SearchFilterParser.CompareOperation theOperation, + PartitionId thePartitionId) { Join join = createJoin(SearchBuilderJoinEnum.QUANTITY, theParamName); if (theList.get(0).getMissing() != null) { - addPredicateParamMissing(theResourceName, theParamName, theList.get(0).getMissing(), join); + addPredicateParamMissing(theResourceName, theParamName, theList.get(0).getMissing(), join, thePartitionId); return null; } List codePredicates = new ArrayList(); + addPartitionIdPredicate(thePartitionId, join, codePredicates); + for (IQueryParameterType nextOr : theList) { Predicate singleCode = createPredicateQuantity(nextOr, @@ -68,7 +72,7 @@ class PredicateBuilderQuantity extends BasePredicateBuilder implements IPredicat theParamName, myCriteriaBuilder, join, - operation); + theOperation); codePredicates.add(singleCode); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderReference.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderReference.java index 83141850610..0050e6769ea 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderReference.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderReference.java @@ -188,6 +188,7 @@ class PredicateBuilderReference extends BasePredicateBuilder { } List codePredicates = new ArrayList<>(); + addPartitionIdPredicate(thePartitionId, join, codePredicates); // Resources by ID List targetPids = myIdHelperService.resolveResourcePersistentIds(targetIds, theRequest); @@ -538,12 +539,12 @@ class PredicateBuilderReference extends BasePredicateBuilder { switch (nextParamDef.getParamType()) { case DATE: for (List nextAnd : theAndOrParams) { - myPredicateBuilder.addPredicateDate(theResourceName, theParamName, nextAnd, null); + myPredicateBuilder.addPredicateDate(theResourceName, theParamName, nextAnd, null, thePartitionId); } break; case QUANTITY: for (List nextAnd : theAndOrParams) { - myPredicateBuilder.addPredicateQuantity(theResourceName, theParamName, nextAnd, null); + myPredicateBuilder.addPredicateQuantity(theResourceName, theParamName, nextAnd, null, thePartitionId); } break; case REFERENCE: @@ -553,21 +554,21 @@ class PredicateBuilderReference extends BasePredicateBuilder { break; case STRING: for (List nextAnd : theAndOrParams) { - myPredicateBuilder.addPredicateString(theResourceName, theParamName, nextAnd, SearchFilterParser.CompareOperation.sw); + myPredicateBuilder.addPredicateString(theResourceName, theParamName, nextAnd, SearchFilterParser.CompareOperation.sw, thePartitionId); } break; case TOKEN: for (List nextAnd : theAndOrParams) { if ("Location.position".equals(nextParamDef.getPath())) { - myPredicateBuilder.addPredicateCoords(theResourceName, theParamName, nextAnd); + myPredicateBuilder.addPredicateCoords(theResourceName, theParamName, nextAnd, thePartitionId); } else { - myPredicateBuilder.addPredicateToken(theResourceName, theParamName, nextAnd, null); + myPredicateBuilder.addPredicateToken(theResourceName, theParamName, nextAnd, null, thePartitionId); } } break; case NUMBER: for (List nextAnd : theAndOrParams) { - myPredicateBuilder.addPredicateNumber(theResourceName, theParamName, nextAnd, null); + myPredicateBuilder.addPredicateNumber(theResourceName, theParamName, nextAnd, null, thePartitionId); } break; case COMPOSITE: @@ -577,14 +578,14 @@ class PredicateBuilderReference extends BasePredicateBuilder { break; case URI: for (List nextAnd : theAndOrParams) { - myPredicateBuilder.addPredicateUri(theResourceName, theParamName, nextAnd, SearchFilterParser.CompareOperation.eq); + myPredicateBuilder.addPredicateUri(theResourceName, theParamName, nextAnd, SearchFilterParser.CompareOperation.eq, thePartitionId); } break; case HAS: case SPECIAL: for (List nextAnd : theAndOrParams) { if ("Location.position".equals(nextParamDef.getPath())) { - myPredicateBuilder.addPredicateCoords(theResourceName, theParamName, nextAnd); + myPredicateBuilder.addPredicateCoords(theResourceName, theParamName, nextAnd, thePartitionId); } } break; @@ -688,13 +689,13 @@ class PredicateBuilderReference extends BasePredicateBuilder { } else { RestSearchParameterTypeEnum typeEnum = searchParam.getParamType(); if (typeEnum == RestSearchParameterTypeEnum.URI) { - return myPredicateBuilder.addPredicateUri(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new UriParam(theFilter.getValue())), theFilter.getOperation()); + return myPredicateBuilder.addPredicateUri(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new UriParam(theFilter.getValue())), theFilter.getOperation(), thePartitionId); } else if (typeEnum == RestSearchParameterTypeEnum.STRING) { - return myPredicateBuilder.addPredicateString(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new StringParam(theFilter.getValue())), theFilter.getOperation()); + return myPredicateBuilder.addPredicateString(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new StringParam(theFilter.getValue())), theFilter.getOperation(), thePartitionId); } else if (typeEnum == RestSearchParameterTypeEnum.DATE) { - return myPredicateBuilder.addPredicateDate(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new DateParam(theFilter.getValue())), theFilter.getOperation()); + return myPredicateBuilder.addPredicateDate(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new DateParam(theFilter.getValue())), theFilter.getOperation(), thePartitionId); } else if (typeEnum == RestSearchParameterTypeEnum.NUMBER) { - return myPredicateBuilder.addPredicateNumber(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new NumberParam(theFilter.getValue())), theFilter.getOperation()); + return myPredicateBuilder.addPredicateNumber(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new NumberParam(theFilter.getValue())), theFilter.getOperation(), thePartitionId); } else if (typeEnum == RestSearchParameterTypeEnum.REFERENCE) { String paramName = theFilter.getParamPath().getName(); SearchFilterParser.CompareOperation operation = theFilter.getOperation(); @@ -704,7 +705,7 @@ class PredicateBuilderReference extends BasePredicateBuilder { ReferenceParam referenceParam = new ReferenceParam(resourceType, chain, value); return addPredicate(theResourceName, paramName, Collections.singletonList(referenceParam), operation, theRequest, thePartitionId); } else if (typeEnum == RestSearchParameterTypeEnum.QUANTITY) { - return myPredicateBuilder.addPredicateQuantity(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new QuantityParam(theFilter.getValue())), theFilter.getOperation()); + return myPredicateBuilder.addPredicateQuantity(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(new QuantityParam(theFilter.getValue())), theFilter.getOperation(), thePartitionId); } else if (typeEnum == RestSearchParameterTypeEnum.COMPOSITE) { throw new InvalidRequestException("Composite search parameters not currently supported with _filter clauses"); } else if (typeEnum == RestSearchParameterTypeEnum.TOKEN) { @@ -713,7 +714,7 @@ class PredicateBuilderReference extends BasePredicateBuilder { null, null, theFilter.getValue()); - return myPredicateBuilder.addPredicateToken(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(param), theFilter.getOperation()); + return myPredicateBuilder.addPredicateToken(theResourceName, theFilter.getParamPath().getName(), Collections.singletonList(param), theFilter.getOperation(), thePartitionId); } } return null; @@ -754,6 +755,7 @@ class PredicateBuilderReference extends BasePredicateBuilder { qp = new SpecialParam(); break; } + throw new InternalErrorException("Don't know how to convert param type: " + theParam.getParamType()); case URI: case HAS: default: diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderString.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderString.java index 221db21ae11..349d84e5be7 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderString.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderString.java @@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.dao.predicate; import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.SearchBuilder; +import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString; import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.util.StringNormalizer; @@ -56,16 +57,19 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB public Predicate addPredicate(String theResourceName, String theParamName, List theList, - SearchFilterParser.CompareOperation operation) { + SearchFilterParser.CompareOperation theOperation, + PartitionId thePartitionId) { Join join = createJoin(SearchBuilderJoinEnum.STRING, theParamName); if (theList.get(0).getMissing() != null) { - addPredicateParamMissing(theResourceName, theParamName, theList.get(0).getMissing(), join); + addPredicateParamMissing(theResourceName, theParamName, theList.get(0).getMissing(), join, thePartitionId); return null; } List codePredicates = new ArrayList<>(); + addPartitionIdPredicate(thePartitionId, join, codePredicates); + for (IQueryParameterType nextOr : theList) { IQueryParameterType theParameter = nextOr; Predicate singleCode = createPredicateString(theParameter, @@ -73,7 +77,7 @@ class PredicateBuilderString extends BasePredicateBuilder implements IPredicateB theParamName, myCriteriaBuilder, join, - operation); + theOperation); codePredicates.add(singleCode); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderTag.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderTag.java index f5f4e0a4700..cb8198d9077 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderTag.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderTag.java @@ -43,6 +43,7 @@ import java.util.List; import static org.apache.commons.lang3.StringUtils.isNotBlank; +// FIXME: add partition @Component @Scope("prototype") class PredicateBuilderTag extends BasePredicateBuilder { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderToken.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderToken.java index 5ba6374c4ae..0a167efd735 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderToken.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderToken.java @@ -26,6 +26,7 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam; +import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken; import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; @@ -70,22 +71,24 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu public Predicate addPredicate(String theResourceName, String theParamName, List theList, - SearchFilterParser.CompareOperation operation) { + SearchFilterParser.CompareOperation theOperation, + PartitionId thePartitionId) { if (theList.get(0).getMissing() != null) { Join join = createJoin(SearchBuilderJoinEnum.TOKEN, theParamName); - addPredicateParamMissing(theResourceName, theParamName, theList.get(0).getMissing(), join); + addPredicateParamMissing(theResourceName, theParamName, theList.get(0).getMissing(), join, thePartitionId); return null; } List codePredicates = new ArrayList<>(); + List tokens = new ArrayList<>(); for (IQueryParameterType nextOr : theList) { if (nextOr instanceof TokenParam) { TokenParam id = (TokenParam) nextOr; if (id.isText()) { - myPredicateBuilder.addPredicateString(theResourceName, theParamName, theList); + myPredicateBuilder.addPredicateString(theResourceName, theParamName, theList, thePartitionId); break; } } @@ -98,7 +101,9 @@ class PredicateBuilderToken extends BasePredicateBuilder implements IPredicateBu } Join join = createJoin(SearchBuilderJoinEnum.TOKEN, theParamName); - Collection singleCode = createPredicateToken(tokens, theResourceName, theParamName, myCriteriaBuilder, join, operation); + addPartitionIdPredicate(thePartitionId, join, codePredicates); + + Collection singleCode = createPredicateToken(tokens, theResourceName, theParamName, myCriteriaBuilder, join, theOperation); assert singleCode != null; codePredicates.addAll(singleCode); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderUri.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderUri.java index d4814b6617b..18de2fe86d1 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderUri.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/predicate/PredicateBuilderUri.java @@ -67,10 +67,7 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil } List codePredicates = new ArrayList<>(); - if (thePartitionId != null) { - Predicate partitionPredicate = myCriteriaBuilder.like(join.get("myUri").as(String.class), createLeftMatchLikeExpression(value)); - codePredicates.add(partitionPredicate); - } + addPartitionIdPredicate(thePartitionId, join, codePredicates); for (IQueryParameterType nextOr : theList) { @@ -185,4 +182,5 @@ class PredicateBuilderUri extends BasePredicateBuilder implements IPredicateBuil myQueryRoot.addPredicate(outerPredicate); return outerPredicate; } + } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/PartitioningR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/PartitioningR4Test.java index bf63a643bf9..be76df610b1 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/PartitioningR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/PartitioningR4Test.java @@ -8,6 +8,8 @@ import ca.uhn.fhir.jpa.model.entity.*; import ca.uhn.fhir.jpa.searchparam.SearchParamConstants; 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.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.util.TestUtil; @@ -379,6 +381,107 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest { assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID")); } + @Test + public void testSearch_StringParam_SearchAllTenants() { + IIdType patientIdNull = createPatient(null, withFamily("FAMILY")); + IIdType patientId1 = createPatient(1, withFamily("FAMILY")); + IIdType patientId2 = createPatient(2, withFamily("FAMILY")); + + addReadTenant(null); + + myCaptureQueriesListener.clear(); + SearchParameterMap map = new SearchParameterMap(); + map.add(Patient.SP_FAMILY, new StringParam("FAMILY")); + map.setLoadSynchronous(true); + IBundleProvider results = myPatientDao.search(map); + List ids = toUnqualifiedVersionlessIds(results); + assertThat(ids, Matchers.contains(patientIdNull, patientId1, patientId2)); + + String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true); + ourLog.info("Search SQL:\n{}", searchSql); + assertEquals(0, StringUtils.countMatches(searchSql, "PARTITION_ID")); + assertEquals(1, StringUtils.countMatches(searchSql, "SP_VALUE_NORMALIZED")); + } + + @Test + public void testSearch_StringParam_SearchOneTenant() { + createPatient(null, withFamily("FAMILY")); + IIdType patientId1 = createPatient(1, withFamily("FAMILY")); + createPatient(2, withFamily("FAMILY")); + + addReadTenant(1); + + myCaptureQueriesListener.clear(); + SearchParameterMap map = new SearchParameterMap(); + map.add(Patient.SP_FAMILY, new StringParam("FAMILY")); + map.setLoadSynchronous(true); + IBundleProvider results = myPatientDao.search(map); + List ids = toUnqualifiedVersionlessIds(results); + myCaptureQueriesListener.logSelectQueriesForCurrentThread(); + assertThat(ids, Matchers.contains(patientId1)); + + String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true); + ourLog.info("Search SQL:\n{}", searchSql); + assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID")); + assertEquals(1, StringUtils.countMatches(searchSql, "SP_VALUE_NORMALIZED")); + } + + @Test + public void testSearch_UniqueParam_SearchAllTenants() { + createUniqueCompositeSp(); + + IIdType id = createPatient(1, withBirthdate("2020-01-01")); + + myCaptureQueriesListener.clear(); + SearchParameterMap map = new SearchParameterMap(); + map.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-01")); + map.setLoadSynchronous(true); + IBundleProvider results = myPatientDao.search(map); + List ids = toUnqualifiedVersionlessIds(results); + myCaptureQueriesListener.logSelectQueriesForCurrentThread(); + assertThat(ids, Matchers.contains(id)); + + String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true); + ourLog.info("Search SQL:\n{}", searchSql); + assertEquals(0, StringUtils.countMatches(searchSql, "PARTITION_ID")); + assertEquals(1, StringUtils.countMatches(searchSql, "IDX_STRING='Patient?birthdate=2020-01-01'")); + } + + + @Test + public void testSearch_UniqueParam_SearchOneTenant() { + createUniqueCompositeSp(); + + IIdType id = createPatient(1, withBirthdate("2020-01-01")); + + addReadTenant(1); + myCaptureQueriesListener.clear(); + SearchParameterMap map = new SearchParameterMap(); + map.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-01")); + map.setLoadSynchronous(true); + IBundleProvider results = myPatientDao.search(map); + List ids = toUnqualifiedVersionlessIds(results); + myCaptureQueriesListener.logSelectQueriesForCurrentThread(); + assertThat(ids, Matchers.contains(id)); + + String searchSql = myCaptureQueriesListener.getSelectQueriesForCurrentThread().get(0).getSql(true, true); + ourLog.info("Search SQL:\n{}", searchSql); + assertEquals(1, StringUtils.countMatches(searchSql, "PARTITION_ID")); + assertEquals(1, StringUtils.countMatches(searchSql, "IDX_STRING='Patient?birthdate=2020-01-01'")); + + // Same query, different partition + addReadTenant(2); + myCaptureQueriesListener.clear(); + map = new SearchParameterMap(); + map.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-01")); + map.setLoadSynchronous(true); + results = myPatientDao.search(map); + ids = toUnqualifiedVersionlessIds(results); + myCaptureQueriesListener.logSelectQueriesForCurrentThread(); + assertThat(ids, Matchers.empty()); + + } + private void createUniqueCompositeSp() { SearchParameter sp = new SearchParameter(); sp.setId("SearchParameter/patient-birthdate"); @@ -447,6 +550,14 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest { return t -> t.setActive(true); } + private Consumer withFamily(String theFamily) { + return t -> t.addName().setFamily(theFamily); + } + + private Consumer withBirthdate(String theBirthdate) { + return t -> t.getBirthDateElement().setValueAsString(theBirthdate); + } + private Consumer withId(String theId) { return t -> { assertThat(theId, matchesPattern("[a-zA-Z0-9]+")); diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedCompositeStringUnique.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedCompositeStringUnique.java index b9c9b747ea5..86db8be7253 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedCompositeStringUnique.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedCompositeStringUnique.java @@ -50,6 +50,12 @@ public class ResourceIndexedCompositeStringUnique implements Comparable