Work on multitenancy

This commit is contained in:
jamesagnew 2020-03-30 09:49:17 -04:00
parent 8e714b6b14
commit 2e43c57032
8 changed files with 183 additions and 115 deletions

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IDao; import ca.uhn.fhir.jpa.dao.IDao;
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndex; import ca.uhn.fhir.jpa.model.entity.BaseResourceIndex;
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam; import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.model.entity.PartitionId; import ca.uhn.fhir.jpa.model.entity.PartitionId;
@ -205,7 +206,7 @@ abstract class BasePredicateBuilder {
return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, num); return combineParamIndexPredicateWithParamNamePredicate(theResourceName, theParamName, theFrom, num);
} }
void addPartitionIdPredicate(PartitionId thePartitionId, Join<ResourceTable, ? extends BaseResourceIndex> theJoin, List<Predicate> theCodePredicates) { void addPartitionIdPredicate(PartitionId thePartitionId, Join<ResourceTable, ? extends BasePartitionable> theJoin, List<Predicate> theCodePredicates) {
if (thePartitionId != null) { if (thePartitionId != null) {
Integer partitionId = thePartitionId.getPartitionId(); Integer partitionId = thePartitionId.getPartitionId();
Predicate partitionPredicate = myCriteriaBuilder.equal(theJoin.get("myPartitionIdValue").as(Integer.class), partitionId); Predicate partitionPredicate = myCriteriaBuilder.equal(theJoin.get("myPartitionIdValue").as(Integer.class), partitionId);

View File

@ -79,8 +79,8 @@ public class PredicateBuilder {
return myPredicateBuilderString.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, thePartitionId); return myPredicateBuilderString.addPredicate(theResourceName, theParamName, theNextAnd, theOperation, thePartitionId);
} }
void addPredicateTag(List<List<IQueryParameterType>> theAndOrParams, String theParamName) { void addPredicateTag(List<List<IQueryParameterType>> theAndOrParams, String theParamName, PartitionId thePartitionId) {
myPredicateBuilderTag.addPredicateTag(theAndOrParams, theParamName); myPredicateBuilderTag.addPredicateTag(theAndOrParams, theParamName, thePartitionId);
} }
Predicate addPredicateToken(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, PartitionId thePartitionId) { Predicate addPredicateToken(String theResourceName, String theParamName, List<? extends IQueryParameterType> theNextAnd, SearchFilterParser.CompareOperation theOperation, PartitionId thePartitionId) {

View File

@ -525,7 +525,7 @@ class PredicateBuilderReference extends BasePredicateBuilder {
case Constants.PARAM_TAG: case Constants.PARAM_TAG:
case Constants.PARAM_PROFILE: case Constants.PARAM_PROFILE:
case Constants.PARAM_SECURITY: case Constants.PARAM_SECURITY:
myPredicateBuilder.addPredicateTag(theAndOrParams, theParamName); myPredicateBuilder.addPredicateTag(theAndOrParams, theParamName, thePartitionId);
break; break;
case Constants.PARAM_SOURCE: case Constants.PARAM_SOURCE:

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.dao.predicate;
*/ */
import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchBuilder;
import ca.uhn.fhir.jpa.model.entity.PartitionId;
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;
import ca.uhn.fhir.jpa.model.entity.TagDefinition; import ca.uhn.fhir.jpa.model.entity.TagDefinition;
@ -38,12 +39,18 @@ import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.persistence.criteria.*; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import java.util.List; import java.util.List;
import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank;
// FIXME: add partition
@Component @Component
@Scope("prototype") @Scope("prototype")
class PredicateBuilderTag extends BasePredicateBuilder { class PredicateBuilderTag extends BasePredicateBuilder {
@ -53,7 +60,7 @@ class PredicateBuilderTag extends BasePredicateBuilder {
super(theSearchBuilder); super(theSearchBuilder);
} }
void addPredicateTag(List<List<IQueryParameterType>> theList, String theParamName) { void addPredicateTag(List<List<IQueryParameterType>> theList, String theParamName, PartitionId thePartitionId) {
TagTypeEnum tagType; TagTypeEnum tagType;
if (Constants.PARAM_TAG.equals(theParamName)) { if (Constants.PARAM_TAG.equals(theParamName)) {
tagType = TagTypeEnum.TAG; tagType = TagTypeEnum.TAG;
@ -127,6 +134,8 @@ class PredicateBuilderTag extends BasePredicateBuilder {
continue; continue;
} }
// FIXME: add test for tag:not
// FIXME: add test for :missing
if (paramInverted) { if (paramInverted) {
ourLog.debug("Searching for _tag:not"); ourLog.debug("Searching for _tag:not");
@ -158,7 +167,13 @@ class PredicateBuilderTag extends BasePredicateBuilder {
From<ResourceTag, TagDefinition> defJoin = tagJoin.join("myTag"); From<ResourceTag, TagDefinition> defJoin = tagJoin.join("myTag");
Predicate tagListPredicate = createPredicateTagList(defJoin, myCriteriaBuilder, tagType, tokens); Predicate tagListPredicate = createPredicateTagList(defJoin, myCriteriaBuilder, tagType, tokens);
myQueryRoot.addPredicate(tagListPredicate); List<Predicate> predicates = Lists.newArrayList(tagListPredicate);
if (thePartitionId != null) {
addPartitionIdPredicate(thePartitionId, tagJoin, predicates);
}
myQueryRoot.addPredicates(predicates);
} }

View File

@ -7,9 +7,11 @@ import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.model.entity.*; import ca.uhn.fhir.jpa.model.entity.*;
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants; import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.Constants;
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;
import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
@ -50,13 +52,13 @@ import static org.mockito.Mockito.when;
public class PartitioningR4Test extends BaseJpaR4SystemTest { public class PartitioningR4Test extends BaseJpaR4SystemTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PartitioningR4Test.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PartitioningR4Test.class);
private MyInterceptor myTenantInterceptor; private MyInterceptor myPartitionInterceptor;
private LocalDate myTenantDate; private LocalDate myPartitionDate;
private int myPartitionId; private int myPartitionId;
@After @After
public void after() { public void after() {
myTenantInterceptor.assertNoRemainingIds(); myPartitionInterceptor.assertNoRemainingIds();
myDaoConfig.setPartitioningEnabled(new DaoConfig().isPartitioningEnabled()); myDaoConfig.setPartitioningEnabled(new DaoConfig().isPartitioningEnabled());
@ -73,15 +75,15 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
myDaoConfig.setUniqueIndexesEnabled(true); myDaoConfig.setUniqueIndexesEnabled(true);
myModelConfig.setDefaultSearchParamsCanBeOverridden(true); myModelConfig.setDefaultSearchParamsCanBeOverridden(true);
myTenantDate = LocalDate.of(2020, Month.JANUARY, 14); myPartitionDate = LocalDate.of(2020, Month.JANUARY, 14);
myPartitionId = 3; myPartitionId = 3;
myTenantInterceptor = new MyInterceptor(); myPartitionInterceptor = new MyInterceptor();
} }
@Test @Test
public void testCreateResourceNoTenant() { public void testCreateResourceNoPartition() {
Patient p = new Patient(); Patient p = new Patient();
p.addIdentifier().setSystem("system").setValue("value"); p.addIdentifier().setSystem("system").setValue("value");
p.setBirthDate(new Date()); p.setBirthDate(new Date());
@ -95,12 +97,12 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
@Test @Test
public void testCreateResourceWithTenant() { public void testCreateResourceWithPartition() {
createUniqueCompositeSp(); createUniqueCompositeSp();
createRequestId(); createRequestId();
addCreateTenant(myPartitionId, myTenantDate); addCreatePartition(myPartitionId, myPartitionDate);
addCreateTenant(myPartitionId, myTenantDate); addCreatePartition(myPartitionId, myPartitionDate);
Organization org = new Organization(); Organization org = new Organization();
org.setName("org"); org.setName("org");
@ -118,71 +120,71 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
// HFJ_RESOURCE // HFJ_RESOURCE
ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new); ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new);
assertEquals(myPartitionId, resourceTable.getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, resourceTable.getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, resourceTable.getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, resourceTable.getPartitionId().getPartitionDate());
// HFJ_RES_TAG // HFJ_RES_TAG
List<ResourceTag> tags = myResourceTagDao.findAll(); List<ResourceTag> tags = myResourceTagDao.findAll();
assertEquals(1, tags.size()); assertEquals(1, tags.size());
assertEquals(myPartitionId, tags.get(0).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, tags.get(0).getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, tags.get(0).getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, tags.get(0).getPartitionId().getPartitionDate());
// HFJ_RES_VER // HFJ_RES_VER
ResourceHistoryTable version = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(patientId, 1L); ResourceHistoryTable version = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(patientId, 1L);
assertEquals(myPartitionId, version.getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, version.getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, version.getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, version.getPartitionId().getPartitionDate());
// HFJ_HISTORY_TAG // HFJ_HISTORY_TAG
List<ResourceHistoryTag> historyTags = myResourceHistoryTagDao.findAll(); List<ResourceHistoryTag> historyTags = myResourceHistoryTagDao.findAll();
assertEquals(1, historyTags.size()); assertEquals(1, historyTags.size());
assertEquals(myPartitionId, historyTags.get(0).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, historyTags.get(0).getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, historyTags.get(0).getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, historyTags.get(0).getPartitionId().getPartitionDate());
// HFJ_RES_VER_PROV // HFJ_RES_VER_PROV
assertNotNull(version.getProvenance()); assertNotNull(version.getProvenance());
assertEquals(myPartitionId, version.getProvenance().getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, version.getProvenance().getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, version.getProvenance().getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, version.getProvenance().getPartitionId().getPartitionDate());
// HFJ_SPIDX_STRING // HFJ_SPIDX_STRING
List<ResourceIndexedSearchParamString> strings = myResourceIndexedSearchParamStringDao.findAllForResourceId(patientId); List<ResourceIndexedSearchParamString> strings = myResourceIndexedSearchParamStringDao.findAllForResourceId(patientId);
ourLog.info("\n * {}", strings.stream().map(ResourceIndexedSearchParamString::toString).collect(Collectors.joining("\n * "))); ourLog.info("\n * {}", strings.stream().map(ResourceIndexedSearchParamString::toString).collect(Collectors.joining("\n * ")));
assertEquals(10, strings.size()); assertEquals(10, strings.size());
assertEquals(myPartitionId, strings.get(0).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, strings.get(0).getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, strings.get(0).getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, strings.get(0).getPartitionId().getPartitionDate());
// HFJ_SPIDX_DATE // HFJ_SPIDX_DATE
List<ResourceIndexedSearchParamDate> dates = myResourceIndexedSearchParamDateDao.findAllForResourceId(patientId); List<ResourceIndexedSearchParamDate> dates = myResourceIndexedSearchParamDateDao.findAllForResourceId(patientId);
ourLog.info("\n * {}", dates.stream().map(ResourceIndexedSearchParamDate::toString).collect(Collectors.joining("\n * "))); ourLog.info("\n * {}", dates.stream().map(ResourceIndexedSearchParamDate::toString).collect(Collectors.joining("\n * ")));
assertEquals(2, dates.size()); assertEquals(2, dates.size());
assertEquals(myPartitionId, dates.get(0).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, dates.get(0).getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, dates.get(0).getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, dates.get(0).getPartitionId().getPartitionDate());
assertEquals(myPartitionId, dates.get(1).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, dates.get(1).getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, dates.get(1).getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, dates.get(1).getPartitionId().getPartitionDate());
// HFJ_RES_LINK // HFJ_RES_LINK
List<ResourceLink> resourceLinks = myResourceLinkDao.findAllForResourceId(patientId); List<ResourceLink> resourceLinks = myResourceLinkDao.findAllForResourceId(patientId);
assertEquals(1, resourceLinks.size()); assertEquals(1, resourceLinks.size());
assertEquals(myPartitionId, resourceLinks.get(0).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, resourceLinks.get(0).getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, resourceLinks.get(0).getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, resourceLinks.get(0).getPartitionId().getPartitionDate());
// HFJ_RES_PARAM_PRESENT // HFJ_RES_PARAM_PRESENT
List<SearchParamPresent> presents = mySearchParamPresentDao.findAllForResource(resourceTable); List<SearchParamPresent> presents = mySearchParamPresentDao.findAllForResource(resourceTable);
assertEquals(myPartitionId, presents.size()); assertEquals(myPartitionId, presents.size());
assertEquals(myPartitionId, presents.get(0).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, presents.get(0).getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, 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.findAllForResourceId(patientId); List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAllForResourceId(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(myTenantDate, uniques.get(0).getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, uniques.get(0).getPartitionId().getPartitionDate());
}); });
} }
@Test @Test
public void testCreateWithForcedId() { public void testCreateWithForcedId() {
addCreateTenant(myPartitionId, myTenantDate); addCreatePartition(myPartitionId, myPartitionDate);
addCreateTenant(myPartitionId, myTenantDate); addCreatePartition(myPartitionId, myPartitionDate);
Organization org = new Organization(); Organization org = new Organization();
org.setId("org"); org.setId("org");
@ -199,18 +201,18 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
List<ForcedId> forcedIds = myForcedIdDao.findAll(); List<ForcedId> forcedIds = myForcedIdDao.findAll();
assertEquals(2, forcedIds.size()); assertEquals(2, forcedIds.size());
assertEquals(myPartitionId, forcedIds.get(0).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, forcedIds.get(0).getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, forcedIds.get(0).getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, forcedIds.get(0).getPartitionId().getPartitionDate());
assertEquals(myPartitionId, forcedIds.get(1).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, forcedIds.get(1).getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, forcedIds.get(1).getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, forcedIds.get(1).getPartitionId().getPartitionDate());
}); });
} }
@Test @Test
public void testUpdateResourceWithTenant() { public void testUpdateResourceWithPartition() {
createRequestId(); createRequestId();
addCreateTenant(3, LocalDate.of(2020, Month.JANUARY, 14)); addCreatePartition(3, LocalDate.of(2020, Month.JANUARY, 14));
addCreateTenant(3, LocalDate.of(2020, Month.JANUARY, 14)); addCreatePartition(3, LocalDate.of(2020, Month.JANUARY, 14));
// Create a resource // Create a resource
Patient p = new Patient(); Patient p = new Patient();
@ -221,7 +223,7 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
// HFJ_RESOURCE // HFJ_RESOURCE
ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new); ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new);
assertEquals(myPartitionId, resourceTable.getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, resourceTable.getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, resourceTable.getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, resourceTable.getPartitionId().getPartitionDate());
}); });
// Update that resource // Update that resource
@ -234,66 +236,66 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
// HFJ_RESOURCE // HFJ_RESOURCE
ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new); ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new);
assertEquals(myPartitionId, resourceTable.getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, resourceTable.getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, resourceTable.getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, resourceTable.getPartitionId().getPartitionDate());
// HFJ_RES_VER // HFJ_RES_VER
int version = 2; int version = 2;
ResourceHistoryTable resVer = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(patientId, version); ResourceHistoryTable resVer = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(patientId, version);
assertEquals(myPartitionId, resVer.getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, resVer.getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, resVer.getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, resVer.getPartitionId().getPartitionDate());
// HFJ_HISTORY_TAG // HFJ_HISTORY_TAG
List<ResourceHistoryTag> historyTags = myResourceHistoryTagDao.findAll(); List<ResourceHistoryTag> historyTags = myResourceHistoryTagDao.findAll();
assertEquals(2, historyTags.size()); assertEquals(2, historyTags.size());
assertEquals(myPartitionId, historyTags.get(0).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, historyTags.get(0).getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, historyTags.get(0).getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, historyTags.get(0).getPartitionId().getPartitionDate());
assertEquals(myPartitionId, historyTags.get(1).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, historyTags.get(1).getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, historyTags.get(1).getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, historyTags.get(1).getPartitionId().getPartitionDate());
// HFJ_RES_VER_PROV // HFJ_RES_VER_PROV
assertNotNull(resVer.getProvenance()); assertNotNull(resVer.getProvenance());
assertNotNull(resVer.getPartitionId()); assertNotNull(resVer.getPartitionId());
assertEquals(myPartitionId, resVer.getProvenance().getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, resVer.getProvenance().getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, resVer.getProvenance().getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, resVer.getProvenance().getPartitionId().getPartitionDate());
// HFJ_SPIDX_STRING // HFJ_SPIDX_STRING
List<ResourceIndexedSearchParamString> strings = myResourceIndexedSearchParamStringDao.findAllForResourceId(patientId); List<ResourceIndexedSearchParamString> strings = myResourceIndexedSearchParamStringDao.findAllForResourceId(patientId);
ourLog.info("\n * {}", strings.stream().map(ResourceIndexedSearchParamString::toString).collect(Collectors.joining("\n * "))); ourLog.info("\n * {}", strings.stream().map(ResourceIndexedSearchParamString::toString).collect(Collectors.joining("\n * ")));
assertEquals(10, strings.size()); assertEquals(10, strings.size());
assertEquals(myPartitionId, strings.get(0).getPartitionId().getPartitionId().intValue()); assertEquals(myPartitionId, strings.get(0).getPartitionId().getPartitionId().intValue());
assertEquals(myTenantDate, strings.get(0).getPartitionId().getPartitionDate()); assertEquals(myPartitionDate, strings.get(0).getPartitionId().getPartitionDate());
}); });
} }
@Test @Test
public void testReadAcrossTenants() { public void testReadAcrossPartitions() {
IIdType patientId1 = createPatient(1, withActiveTrue()); IIdType patientId1 = createPatient(1, withActiveTrue());
IIdType patientId2 = createPatient(2, withActiveTrue()); IIdType patientId2 = createPatient(2, withActiveTrue());
addReadTenant(null); addReadPartition(null);
IdType gotId1 = myPatientDao.read(patientId1, mySrd).getIdElement().toUnqualifiedVersionless(); IdType gotId1 = myPatientDao.read(patientId1, mySrd).getIdElement().toUnqualifiedVersionless();
assertEquals(patientId1, gotId1); assertEquals(patientId1, gotId1);
addReadTenant(null); addReadPartition(null);
IdType gotId2 = myPatientDao.read(patientId2, mySrd).getIdElement().toUnqualifiedVersionless(); IdType gotId2 = myPatientDao.read(patientId2, mySrd).getIdElement().toUnqualifiedVersionless();
assertEquals(patientId2, gotId2); assertEquals(patientId2, gotId2);
} }
@Test @Test
public void testReadSpecificTenant_PidId() { public void testReadSpecificPartition_PidId() {
IIdType patientIdNull = createPatient(null, withActiveTrue()); IIdType patientIdNull = createPatient(null, withActiveTrue());
IIdType patientId1 = createPatient(1, withActiveTrue()); IIdType patientId1 = createPatient(1, withActiveTrue());
IIdType patientId2 = createPatient(2, withActiveTrue()); IIdType patientId2 = createPatient(2, withActiveTrue());
// Read in correct tenant // Read in correct Partition
addReadTenant(1); addReadPartition(1);
IdType gotId1 = myPatientDao.read(patientId1, mySrd).getIdElement().toUnqualifiedVersionless(); IdType gotId1 = myPatientDao.read(patientId1, mySrd).getIdElement().toUnqualifiedVersionless();
assertEquals(patientId1, gotId1); assertEquals(patientId1, gotId1);
// Read in null tenant // Read in null Partition
addReadTenant(1); addReadPartition(1);
try { try {
myPatientDao.read(patientIdNull, mySrd).getIdElement().toUnqualifiedVersionless(); myPatientDao.read(patientIdNull, mySrd).getIdElement().toUnqualifiedVersionless();
fail(); fail();
@ -301,8 +303,8 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
assertThat(e.getMessage(), matchesPattern("Resource Patient/[0-9]+ is not known")); assertThat(e.getMessage(), matchesPattern("Resource Patient/[0-9]+ is not known"));
} }
// Read in wrong tenant // Read in wrong Partition
addReadTenant(1); addReadPartition(1);
try { try {
myPatientDao.read(patientId2, mySrd).getIdElement().toUnqualifiedVersionless(); myPatientDao.read(patientId2, mySrd).getIdElement().toUnqualifiedVersionless();
fail(); fail();
@ -312,18 +314,18 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
} }
@Test @Test
public void testReadSpecificTenant_ForcedId() { public void testReadSpecificPartition_ForcedId() {
IIdType patientIdNull = createPatient(null, withActiveTrue(), withId("NULL")); IIdType patientIdNull = createPatient(null, withActiveTrue(), withId("NULL"));
IIdType patientId1 = createPatient(1, withActiveTrue(), withId("ONE")); IIdType patientId1 = createPatient(1, withActiveTrue(), withId("ONE"));
IIdType patientId2 = createPatient(2, withActiveTrue(), withId("TWO")); IIdType patientId2 = createPatient(2, withActiveTrue(), withId("TWO"));
// Read in correct tenant // Read in correct Partition
addReadTenant(1); addReadPartition(1);
IdType gotId1 = myPatientDao.read(patientId1, mySrd).getIdElement().toUnqualifiedVersionless(); IdType gotId1 = myPatientDao.read(patientId1, mySrd).getIdElement().toUnqualifiedVersionless();
assertEquals(patientId1, gotId1); assertEquals(patientId1, gotId1);
// Read in null tenant // Read in null Partition
addReadTenant(1); addReadPartition(1);
try { try {
myPatientDao.read(patientIdNull, mySrd).getIdElement().toUnqualifiedVersionless(); myPatientDao.read(patientIdNull, mySrd).getIdElement().toUnqualifiedVersionless();
fail(); fail();
@ -331,8 +333,8 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
assertThat(e.getMessage(), matchesPattern("Resource Patient/[0-9]+ is not known")); assertThat(e.getMessage(), matchesPattern("Resource Patient/[0-9]+ is not known"));
} }
// Read in wrong tenant // Read in wrong Partition
addReadTenant(1); addReadPartition(1);
try { try {
myPatientDao.read(patientId2, mySrd).getIdElement().toUnqualifiedVersionless(); myPatientDao.read(patientId2, mySrd).getIdElement().toUnqualifiedVersionless();
fail(); fail();
@ -342,12 +344,12 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
} }
@Test @Test
public void testSearch_NoParams_SearchAllTenants() { public void testSearch_NoParams_SearchAllPartitions() {
IIdType patientIdNull = createPatient(null, withActiveTrue()); IIdType patientIdNull = createPatient(null, withActiveTrue());
IIdType patientId1 = createPatient(1, withActiveTrue()); IIdType patientId1 = createPatient(1, withActiveTrue());
IIdType patientId2 = createPatient(2, withActiveTrue()); IIdType patientId2 = createPatient(2, withActiveTrue());
addReadTenant(null); addReadPartition(null);
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -362,12 +364,12 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
} }
@Test @Test
public void testSearch_NoParams_SearchOneTenant() { public void testSearch_NoParams_SearchOnePartition() {
createPatient(null, withActiveTrue()); createPatient(null, withActiveTrue());
IIdType patientId1 = createPatient(1, withActiveTrue()); IIdType patientId1 = createPatient(1, withActiveTrue());
createPatient(2, withActiveTrue()); createPatient(2, withActiveTrue());
addReadTenant(1); addReadPartition(1);
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -382,12 +384,12 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
} }
@Test @Test
public void testSearch_StringParam_SearchAllTenants() { public void testSearch_StringParam_SearchAllPartitions() {
IIdType patientIdNull = createPatient(null, withFamily("FAMILY")); IIdType patientIdNull = createPatient(null, withFamily("FAMILY"));
IIdType patientId1 = createPatient(1, withFamily("FAMILY")); IIdType patientId1 = createPatient(1, withFamily("FAMILY"));
IIdType patientId2 = createPatient(2, withFamily("FAMILY")); IIdType patientId2 = createPatient(2, withFamily("FAMILY"));
addReadTenant(null); addReadPartition(null);
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -404,12 +406,12 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
} }
@Test @Test
public void testSearch_StringParam_SearchOneTenant() { public void testSearch_StringParam_SearchOnePartition() {
createPatient(null, withFamily("FAMILY")); createPatient(null, withFamily("FAMILY"));
IIdType patientId1 = createPatient(1, withFamily("FAMILY")); IIdType patientId1 = createPatient(1, withFamily("FAMILY"));
createPatient(2, withFamily("FAMILY")); createPatient(2, withFamily("FAMILY"));
addReadTenant(1); addReadPartition(1);
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -427,11 +429,57 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
} }
@Test @Test
public void testSearch_UniqueParam_SearchAllTenants() { public void testSearch_TagParam_SearchAllPartitions() {
IIdType patientIdNull = createPatient(null, withActiveTrue(), withTag("http://system", "code"));
IIdType patientId1 = createPatient(1, withActiveTrue(), withTag("http://system", "code"));
IIdType patientId2 = createPatient(2, withActiveTrue(), withTag("http://system", "code"));
addReadPartition(null);
myCaptureQueriesListener.clear();
SearchParameterMap map = new SearchParameterMap();
map.add(Constants.PARAM_TAG, new TokenParam("http://system", "code"));
map.setLoadSynchronous(true);
IBundleProvider results = myPatientDao.search(map);
List<IIdType> 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, "TAG_SYSTEM='http://system'"));
}
@Test
public void testSearch_TagParam_SearchOnePartition() {
IIdType patientIdNull = createPatient(null, withActiveTrue(), withTag("http://system", "code"));
IIdType patientId1 = createPatient(1, withActiveTrue(), withTag("http://system", "code"));
IIdType patientId2 = createPatient(2, withActiveTrue(), withTag("http://system", "code"));
addReadPartition(1);
myCaptureQueriesListener.clear();
SearchParameterMap map = new SearchParameterMap();
map.add(Constants.PARAM_TAG, new TokenParam("http://system", "code"));
map.setLoadSynchronous(true);
IBundleProvider results = myPatientDao.search(map);
List<IIdType> ids = toUnqualifiedVersionlessIds(results);
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, "TAG_SYSTEM='http://system'"));
}
@Test
public void testSearch_UniqueParam_SearchAllPartitions() {
createUniqueCompositeSp(); createUniqueCompositeSp();
IIdType id = createPatient(1, withBirthdate("2020-01-01")); IIdType id = createPatient(1, withBirthdate("2020-01-01"));
addReadPartition(null);
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
map.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-01")); map.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-01"));
@ -449,12 +497,12 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
@Test @Test
public void testSearch_UniqueParam_SearchOneTenant() { public void testSearch_UniqueParam_SearchOnePartition() {
createUniqueCompositeSp(); createUniqueCompositeSp();
IIdType id = createPatient(1, withBirthdate("2020-01-01")); IIdType id = createPatient(1, withBirthdate("2020-01-01"));
addReadTenant(1); addReadPartition(1);
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
map.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-01")); map.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-01"));
@ -470,7 +518,7 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
assertEquals(1, StringUtils.countMatches(searchSql, "IDX_STRING='Patient?birthdate=2020-01-01'")); assertEquals(1, StringUtils.countMatches(searchSql, "IDX_STRING='Patient?birthdate=2020-01-01'"));
// Same query, different partition // Same query, different partition
addReadTenant(2); addReadPartition(2);
myCaptureQueriesListener.clear(); myCaptureQueriesListener.clear();
map = new SearchParameterMap(); map = new SearchParameterMap();
map.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-01")); map.add(Patient.SP_BIRTHDATE, new DateParam("2020-01-01"));
@ -509,29 +557,29 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
} }
private void addCreateTenant(int thePartitionId, LocalDate theTenantDate) { private void addCreatePartition(int thePartitionId, LocalDate thePartitionDate) {
registerInterceptorIfNeeded(); registerInterceptorIfNeeded();
myTenantInterceptor.addCreateTenant(new PartitionId(thePartitionId, theTenantDate)); myPartitionInterceptor.addCreatePartition(new PartitionId(thePartitionId, thePartitionDate));
} }
private void addReadTenant(Integer thePartitionId) { private void addReadPartition(Integer thePartitionId) {
registerInterceptorIfNeeded(); registerInterceptorIfNeeded();
PartitionId partitionId = null; PartitionId partitionId = null;
if (thePartitionId != null) { if (thePartitionId != null) {
partitionId = new PartitionId(thePartitionId, null); partitionId = new PartitionId(thePartitionId, null);
} }
myTenantInterceptor.addReadTenant(partitionId); myPartitionInterceptor.addReadPartition(partitionId);
} }
private void registerInterceptorIfNeeded() { private void registerInterceptorIfNeeded() {
if (!myInterceptorRegistry.getAllRegisteredInterceptors().contains(myTenantInterceptor)) { if (!myInterceptorRegistry.getAllRegisteredInterceptors().contains(myPartitionInterceptor)) {
myInterceptorRegistry.registerInterceptor(myTenantInterceptor); myInterceptorRegistry.registerInterceptor(myPartitionInterceptor);
} }
} }
public IIdType createPatient(Integer thePartitionId, Consumer<Patient>... theModifiers) { public IIdType createPatient(Integer thePartitionId, Consumer<Patient>... theModifiers) {
if (thePartitionId != null) { if (thePartitionId != null) {
addCreateTenant(thePartitionId, null); addCreatePartition(thePartitionId, null);
} }
Patient p = new Patient(); Patient p = new Patient();
@ -565,6 +613,11 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
}; };
} }
private Consumer<Patient> withTag(String theSystem, String theCode) {
return t->t.getMeta().addTag(theSystem, theCode, theCode);
}
@Interceptor @Interceptor
public static class MyInterceptor { public static class MyInterceptor {
@ -572,17 +625,17 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
private final List<PartitionId> myCreatePartitionIds = new ArrayList<>(); private final List<PartitionId> myCreatePartitionIds = new ArrayList<>();
private final List<PartitionId> myReadPartitionIds = new ArrayList<>(); private final List<PartitionId> myReadPartitionIds = new ArrayList<>();
public void addCreateTenant(PartitionId thePartitionId) { public void addCreatePartition(PartitionId thePartitionId) {
Validate.notNull(thePartitionId); Validate.notNull(thePartitionId);
myCreatePartitionIds.add(thePartitionId); myCreatePartitionIds.add(thePartitionId);
} }
public void addReadTenant(PartitionId thePartitionId) { public void addReadPartition(PartitionId thePartitionId) {
myReadPartitionIds.add(thePartitionId); myReadPartitionIds.add(thePartitionId);
} }
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE) @Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE)
public PartitionId tenantIdentifyCreate(IBaseResource theResource, ServletRequestDetails theRequestDetails) { public PartitionId PartitionIdentifyCreate(IBaseResource theResource, ServletRequestDetails theRequestDetails) {
assertNotNull(theResource); assertNotNull(theResource);
PartitionId retVal = myCreatePartitionIds.remove(0); PartitionId retVal = myCreatePartitionIds.remove(0);
ourLog.info("Returning partition for create: {}", retVal); ourLog.info("Returning partition for create: {}", retVal);
@ -590,7 +643,7 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
} }
@Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_READ) @Hook(Pointcut.STORAGE_PARTITION_IDENTIFY_READ)
public PartitionId tenantIdentifyRead(ServletRequestDetails theRequestDetails) { public PartitionId PartitionIdentifyRead(ServletRequestDetails theRequestDetails) {
PartitionId retVal = myReadPartitionIds.remove(0); PartitionId retVal = myReadPartitionIds.remove(0);
ourLog.info("Returning partition for read: {}", retVal); ourLog.info("Returning partition for read: {}", retVal);
return retVal; return retVal;

View File

@ -0,0 +1,30 @@
package ca.uhn.fhir.jpa.model.entity;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
@MappedSuperclass
public class BasePartitionable implements Serializable {
@Embedded
private PartitionId myPartitionId;
/**
* This is here to support queries only, do not set this field directly
*/
@SuppressWarnings("unused")
@Column(name = PartitionId.PARTITION_ID, insertable = false, updatable = false, nullable = true)
private Integer myPartitionIdValue;
public PartitionId getPartitionId() {
return myPartitionId;
}
public void setPartitionId(PartitionId thePartitionId) {
myPartitionId = thePartitionId;
}
}

View File

@ -20,31 +20,11 @@ package ca.uhn.fhir.jpa.model.entity;
* #L% * #L%
*/ */
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.MappedSuperclass; import javax.persistence.MappedSuperclass;
import java.io.Serializable; import java.io.Serializable;
@MappedSuperclass @MappedSuperclass
public abstract class BaseResourceIndex implements Serializable { public abstract class BaseResourceIndex extends BasePartitionable implements Serializable {
@Embedded
private PartitionId myPartitionId;
/**
* This is here to support queries only, do not set this field directly
*/
@SuppressWarnings("unused")
@Column(name = PartitionId.PARTITION_ID, insertable = false, updatable = false, nullable = true)
private Integer myPartitionIdValue;
public PartitionId getPartitionId() {
return myPartitionId;
}
public void setPartitionId(PartitionId thePartitionId) {
myPartitionId = thePartitionId;
}
public abstract Long getId(); public abstract Long getId();

View File

@ -28,7 +28,7 @@ import javax.persistence.MappedSuperclass;
import java.io.Serializable; import java.io.Serializable;
@MappedSuperclass @MappedSuperclass
public class BaseTag implements Serializable { public class BaseTag extends BasePartitionable implements Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -39,9 +39,6 @@ public class BaseTag implements Serializable {
@Column(name = "TAG_ID", insertable = false, updatable = false) @Column(name = "TAG_ID", insertable = false, updatable = false)
private Long myTagId; private Long myTagId;
@Embedded
private PartitionId myPartitionId;
public Long getTagId() { public Long getTagId() {
return myTagId; return myTagId;
} }
@ -54,12 +51,4 @@ public class BaseTag implements Serializable {
myTag = theTag; myTag = theTag;
} }
public PartitionId getPartitionId() {
return myPartitionId;
}
public void setPartitionId(PartitionId thePartitionId) {
myPartitionId = thePartitionId;
}
} }