Work on muiltitenancy
This commit is contained in:
parent
9df4c58122
commit
691f2c4e9a
|
@ -67,6 +67,12 @@
|
|||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-r5</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
type: add
|
||||
issue: 1783
|
||||
title: "In the JPA sevrer, if overriding built-in search parameters is not enabled, the server
|
||||
will now return an error if a client tries to create a SearchParameter that is
|
||||
trying to override one. Previously, the SearchParameter would be stored but silently ignored,
|
||||
which was confusing."
|
|
@ -219,6 +219,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
retVal.setResourceType(theEntity.getResourceType());
|
||||
retVal.setForcedId(theId.getIdPart());
|
||||
retVal.setResource(theEntity);
|
||||
retVal.setTenantId(theEntity.getTenantId());
|
||||
theEntity.setForcedId(retVal);
|
||||
}
|
||||
}
|
||||
|
@ -1094,6 +1095,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
ResourceHistoryProvenanceEntity provenance = new ResourceHistoryProvenanceEntity();
|
||||
provenance.setResourceHistoryTable(historyEntry);
|
||||
provenance.setResourceTable(entity);
|
||||
provenance.setTenantId(entity.getTenantId());
|
||||
if (haveRequestId) {
|
||||
provenance.setRequestId(left(requestId, Constants.REQUEST_ID_LENGTH));
|
||||
}
|
||||
|
|
|
@ -24,8 +24,6 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoSearchParameterR4;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.dstu2.resource.SearchParameter;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.SearchParamTypeEnum;
|
||||
|
@ -38,8 +36,6 @@ import java.util.List;
|
|||
|
||||
public class FhirResourceDaoSearchParameterDstu2 extends BaseHapiFhirResourceDao<SearchParameter> implements IFhirResourceDaoSearchParameter<SearchParameter> {
|
||||
|
||||
@Autowired
|
||||
private IFhirSystemDao<Bundle, MetaDt> mySystemDao;
|
||||
@Autowired
|
||||
private ISearchParamExtractor mySearchParamExtractor;
|
||||
|
||||
|
@ -79,8 +75,9 @@ public class FhirResourceDaoSearchParameterDstu2 extends BaseHapiFhirResourceDao
|
|||
String expression = theResource.getXpath();
|
||||
FhirContext context = getContext();
|
||||
SearchParamTypeEnum type = theResource.getTypeElement().getValueAsEnum();
|
||||
String code = theResource.getCode();
|
||||
|
||||
FhirResourceDaoSearchParameterR4.validateSearchParam(mySearchParamExtractor, type, status, base, expression, context, getConfig());
|
||||
FhirResourceDaoSearchParameterR4.validateSearchParam(mySearchParamRegistry, mySearchParamExtractor, code, type, status, base, expression, context, getConfig());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -20,15 +20,19 @@ package ca.uhn.fhir.jpa.dao.data;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IResourceIndexedSearchParamDateDao extends JpaRepository<ResourceIndexedSearchParamDate, Long> {
|
||||
@Modifying
|
||||
@Query("delete from ResourceIndexedSearchParamDate t WHERE t.myResourcePid = :resid")
|
||||
void deleteByResourceId(@Param("resid") Long theResourcePid);
|
||||
|
||||
@Query("SELECT t FROM ResourceIndexedSearchParamDate t WHERE t.myResourcePid = :resId")
|
||||
List<ResourceIndexedSearchParamDate> findAllForResourceId(@Param("resId") Long thePatientId);
|
||||
}
|
||||
|
|
|
@ -70,8 +70,9 @@ public class FhirResourceDaoSearchParameterDstu3 extends BaseHapiFhirResourceDao
|
|||
String expression = theResource.getExpression();
|
||||
FhirContext context = getContext();
|
||||
Enumerations.SearchParamType type = theResource.getType();
|
||||
String code = theResource.getCode();
|
||||
|
||||
FhirResourceDaoSearchParameterR4.validateSearchParam(mySearchParamExtractor, type, status, base, expression, context, getConfig());
|
||||
FhirResourceDaoSearchParameterR4.validateSearchParam(mySearchParamRegistry, mySearchParamExtractor, code, type, status, base, expression, context, getConfig());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,11 +2,14 @@ package ca.uhn.fhir.jpa.dao.r4;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSearchParameter;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
|
@ -78,14 +81,15 @@ public class FhirResourceDaoSearchParameterR4 extends BaseHapiFhirResourceDao<Se
|
|||
|
||||
Enum<?> status = theResource.getStatus();
|
||||
List<CodeType> base = theResource.getBase();
|
||||
String code = theResource.getCode();
|
||||
String expression = theResource.getExpression();
|
||||
FhirContext context = getContext();
|
||||
Enum<?> type = theResource.getType();
|
||||
|
||||
FhirResourceDaoSearchParameterR4.validateSearchParam(mySearchParamExtractor, type, status, base, expression, context, getConfig());
|
||||
FhirResourceDaoSearchParameterR4.validateSearchParam(mySearchParamRegistry, mySearchParamExtractor, code, type, status, base, expression, context, getConfig());
|
||||
}
|
||||
|
||||
public static void validateSearchParam(ISearchParamExtractor theSearchParamExtractor, Enum<?> theType, Enum<?> theStatus, List<? extends IPrimitiveType> theBase, String theExpression, FhirContext theContext, DaoConfig theDaoConfig) {
|
||||
public static void validateSearchParam(ISearchParamRegistry theSearchParamRegistry, ISearchParamExtractor theSearchParamExtractor, String theCode, Enum<?> theType, Enum<?> theStatus, List<? extends IPrimitiveType> theBase, String theExpression, FhirContext theContext, DaoConfig theDaoConfig) {
|
||||
if (theStatus == null) {
|
||||
throw new UnprocessableEntityException("SearchParameter.status is missing or invalid");
|
||||
}
|
||||
|
@ -146,6 +150,19 @@ public class FhirResourceDaoSearchParameterR4 extends BaseHapiFhirResourceDao<Se
|
|||
|
||||
}
|
||||
} // if have expression
|
||||
|
||||
// If overriding built-in SPs is disabled on this server, make sure we aren't
|
||||
// doing that
|
||||
if (theDaoConfig.getModelConfig().isDefaultSearchParamsCanBeOverridden() == false) {
|
||||
for (IPrimitiveType<?> nextBaseType : theBase) {
|
||||
String nextBase = nextBaseType.getValueAsString();
|
||||
RuntimeSearchParam existingSearchParam = theSearchParamRegistry.getActiveSearchParam(nextBase, theCode);
|
||||
if (existingSearchParam.getId() == null) {
|
||||
throw new UnprocessableEntityException("Can not override built-in search parameter " + nextBase + ":" + theCode + " because overriding is disabled on this server");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -68,11 +68,12 @@ public class FhirResourceDaoSearchParameterR5 extends BaseHapiFhirResourceDao<Se
|
|||
|
||||
Enum<?> status = theResource.getStatus();
|
||||
List<CodeType> base = theResource.getBase();
|
||||
String code = theResource.getCode();
|
||||
String expression = theResource.getExpression();
|
||||
FhirContext context = getContext();
|
||||
Enum<?> type = theResource.getType();
|
||||
|
||||
FhirResourceDaoSearchParameterR4.validateSearchParam(mySearchParamExtractor, type, status, base, expression, context, getConfig());
|
||||
FhirResourceDaoSearchParameterR4.validateSearchParam(mySearchParamRegistry, mySearchParamExtractor, code, type, status, base, expression, context, getConfig());
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -2,27 +2,39 @@ package ca.uhn.fhir.jpa.dao.r4;
|
|||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.param.QuantityParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.DateType;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
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.SampledData;
|
||||
import org.hl7.fhir.r4.model.SearchParameter;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4CreateTest.class);
|
||||
|
@ -31,6 +43,7 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
|||
public void afterResetDao() {
|
||||
myDaoConfig.setResourceServerIdStrategy(new DaoConfig().getResourceServerIdStrategy());
|
||||
myDaoConfig.setResourceClientIdStrategy(new DaoConfig().getResourceClientIdStrategy());
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(new DaoConfig().isDefaultSearchParamsCanBeOverridden());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -149,7 +162,7 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
|||
p = new Patient();
|
||||
p.setActive(false);
|
||||
try {
|
||||
myPatientDao.create(p).getId();
|
||||
myPatientDao.create(p);
|
||||
fail();
|
||||
} catch (ResourceVersionConflictException e) {
|
||||
// good
|
||||
|
@ -280,6 +293,26 @@ public class FhirResourceDaoR4CreateTest extends BaseJpaR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverrideBuiltInSearchParamFailsIfDisabled() {
|
||||
myModelConfig.setDefaultSearchParamsCanBeOverridden(false);
|
||||
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-birthdate");
|
||||
sp.setType(Enumerations.SearchParamType.DATE);
|
||||
sp.setCode("birthdate");
|
||||
sp.setExpression("Patient.birthDate");
|
||||
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
sp.addBase("Patient");
|
||||
try {
|
||||
mySearchParameterDao.update(sp);
|
||||
fail();
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertEquals("Can not override built-in search parameter Patient:birthdate because overriding is disabled on this server", e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
|
|
|
@ -22,7 +22,6 @@ import ca.uhn.fhir.rest.param.TokenAndListParam;
|
|||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.test.utilities.UnregisterScheduledProcessor;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
|
@ -32,10 +31,7 @@ import org.junit.AfterClass;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.springframework.aop.framework.AopProxyUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.util.ProxyUtils;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
@ -48,8 +44,17 @@ import java.util.UUID;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.jpa.dao.BaseHapiFhirDao.INDEX_STATUS_INDEXED;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.either;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
@ -695,7 +700,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
assertEquals(1, myResourceReindexingSvc.forceReindexingPass());
|
||||
assertEquals(0, myResourceReindexingSvc.forceReindexingPass());
|
||||
|
||||
runInTransaction(()->{
|
||||
runInTransaction(() -> {
|
||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 1, uniques.size());
|
||||
assertThat(uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue(), either(equalTo("Observation/" + id2.getIdPart())).or(equalTo("Observation/" + id3.getIdPart())));
|
||||
|
@ -712,7 +717,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
myResourceReindexingSvc.forceReindexingPass();
|
||||
assertEquals(0, myResourceReindexingSvc.forceReindexingPass());
|
||||
|
||||
runInTransaction(()->{
|
||||
runInTransaction(() -> {
|
||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 1, uniques.size());
|
||||
assertThat(uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue(), either(equalTo("Observation/" + id2.getIdPart())).or(equalTo("Observation/" + id3.getIdPart())));
|
||||
|
|
|
@ -4,8 +4,10 @@ import ca.uhn.fhir.interceptor.api.Hook;
|
|||
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamDate;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
|
@ -17,6 +19,7 @@ import org.apache.commons.lang3.Validate;
|
|||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.BooleanType;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Organization;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.SearchParameter;
|
||||
|
@ -29,13 +32,13 @@ import javax.servlet.ServletException;
|
|||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
|
@ -43,6 +46,8 @@ public class MultitenantR4Test extends BaseJpaR4SystemTest {
|
|||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MultitenantR4Test.class);
|
||||
private MyInterceptor myTenantInterceptor;
|
||||
private LocalDate myTenantDate;
|
||||
private int myTenantId;
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
|
@ -58,6 +63,11 @@ public class MultitenantR4Test extends BaseJpaR4SystemTest {
|
|||
super.before();
|
||||
|
||||
myDaoConfig.setMultiTenancyEnabled(true);
|
||||
myDaoConfig.setUniqueIndexesEnabled(true);
|
||||
myModelConfig.setDefaultSearchParamsCanBeOverridden(true);
|
||||
|
||||
myTenantDate = LocalDate.of(2020, Month.JANUARY, 14);
|
||||
myTenantId = 3;
|
||||
}
|
||||
|
||||
|
||||
|
@ -74,12 +84,14 @@ public class MultitenantR4Test extends BaseJpaR4SystemTest {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateResourceWithTenant() {
|
||||
createUniqueCompositeSp();
|
||||
createRequestId();
|
||||
|
||||
addTenant(3, LocalDate.of(2020, Month.JANUARY, 14));
|
||||
addTenant(3, LocalDate.of(2020, Month.JANUARY, 14));
|
||||
addCreateTenant(myTenantId, myTenantDate);
|
||||
addCreateTenant(myTenantId, myTenantDate);
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setName("org");
|
||||
|
@ -91,75 +103,155 @@ public class MultitenantR4Test extends BaseJpaR4SystemTest {
|
|||
p.addIdentifier().setSystem("system").setValue("value");
|
||||
p.setBirthDate(new Date());
|
||||
p.getManagingOrganization().setReferenceElement(orgId);
|
||||
when(mySrd.getRequestId()).thenReturn("REQUEST_ID");
|
||||
Long patientId = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||
|
||||
runInTransaction(() -> {
|
||||
// HFJ_RESOURCE
|
||||
ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new);
|
||||
assertEquals(3, resourceTable.getTenantId().getTenantId().intValue());
|
||||
assertEquals(LocalDate.of(2020, Month.JANUARY, 14), resourceTable.getTenantId().getTenantDate());
|
||||
|
||||
resourceTable.getProfile()
|
||||
assertEquals(myTenantId, resourceTable.getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, resourceTable.getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_RES_VER
|
||||
ResourceHistoryTable version = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(patientId, 1L);
|
||||
assertEquals(3, version.getTenantId().getTenantId().intValue());
|
||||
assertEquals(LocalDate.of(2020, Month.JANUARY, 14), version.getTenantId().getTenantDate());
|
||||
assertEquals(myTenantId, version.getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, version.getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_RES_VER_PROV
|
||||
assertNotNull(version.getProvenance());
|
||||
assertEquals(myTenantId, version.getProvenance().getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, version.getProvenance().getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_SPIDX_STRING
|
||||
List<ResourceIndexedSearchParamString> strings = myResourceIndexedSearchParamStringDao.findAllForResourceId(patientId);
|
||||
ourLog.info("\n * {}", strings.stream().map(ResourceIndexedSearchParamString::toString).collect(Collectors.joining("\n * ")));
|
||||
assertEquals(10, strings.size());
|
||||
assertEquals(3, strings.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(LocalDate.of(2020, Month.JANUARY, 14), strings.get(0).getTenantId().getTenantDate());
|
||||
assertEquals(myTenantId, strings.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, strings.get(0).getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_SPIDX_DATE
|
||||
List<ResourceIndexedSearchParamDate> dates = myResourceIndexedSearchParamDateDao.findAllForResourceId(patientId);
|
||||
ourLog.info("\n * {}", dates.stream().map(ResourceIndexedSearchParamDate::toString).collect(Collectors.joining("\n * ")));
|
||||
assertEquals(2, dates.size());
|
||||
assertEquals(myTenantId, dates.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, dates.get(0).getTenantId().getTenantDate());
|
||||
assertEquals(myTenantId, dates.get(1).getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, dates.get(1).getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_RES_LINK
|
||||
List<ResourceLink> resourceLinks = myResourceLinkDao.findAllForResourceId(patientId);
|
||||
assertEquals(1, resourceLinks.size());
|
||||
assertEquals(3, resourceLinks.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(LocalDate.of(2020, Month.JANUARY, 14), resourceLinks.get(0).getTenantId().getTenantDate());
|
||||
assertEquals(myTenantId, resourceLinks.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, resourceLinks.get(0).getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_RES_PARAM_PRESENT
|
||||
List<SearchParamPresent> presents = mySearchParamPresentDao.findAllForResource(resourceTable);
|
||||
assertEquals(3, presents.size());
|
||||
assertEquals(3, presents.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(LocalDate.of(2020, Month.JANUARY, 14), presents.get(0).getTenantId().getTenantDate());
|
||||
assertEquals(myTenantId, presents.size());
|
||||
assertEquals(myTenantId, presents.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, presents.get(0).getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_IDX_CMP_STRING_UNIQ
|
||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAllForResourceId(patientId);
|
||||
assertEquals(3, uniques.size());
|
||||
assertEquals(3, uniques.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(LocalDate.of(2020, Month.JANUARY, 14), uniques.get(0).getTenantId().getTenantDate());
|
||||
assertEquals(1, uniques.size());
|
||||
assertEquals(myTenantId, uniques.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, uniques.get(0).getTenantId().getTenantDate());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithForcedId() {
|
||||
addCreateTenant(myTenantId, myTenantDate);
|
||||
addCreateTenant(myTenantId, myTenantDate);
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setId("org");
|
||||
org.setName("org");
|
||||
IIdType orgId = myOrganizationDao.update(org).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setId("pat");
|
||||
p.getManagingOrganization().setReferenceElement(orgId);
|
||||
myPatientDao.update(p, mySrd);
|
||||
|
||||
runInTransaction(() -> {
|
||||
// HFJ_FORCED_ID
|
||||
List<ForcedId> forcedIds = myForcedIdDao.findAll();
|
||||
assertEquals(2, forcedIds.size());
|
||||
assertEquals(myTenantId, forcedIds.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, forcedIds.get(0).getTenantId().getTenantDate());
|
||||
assertEquals(myTenantId, forcedIds.get(1).getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, forcedIds.get(1).getTenantId().getTenantDate());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateResourceWithTenant() {
|
||||
createUniqueCompositeSp();
|
||||
|
||||
addTenant(3, LocalDate.of(2020, Month.JANUARY, 14));
|
||||
createRequestId();
|
||||
addCreateTenant(3, LocalDate.of(2020, Month.JANUARY, 14));
|
||||
|
||||
// Create a resource
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
Long patientId = myPatientDao.create(p).getId().getIdPartAsLong();
|
||||
runInTransaction(() -> {
|
||||
// HFJ_RESOURCE
|
||||
ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new);
|
||||
assertEquals(myTenantId, resourceTable.getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, resourceTable.getTenantId().getTenantDate());
|
||||
});
|
||||
|
||||
// Update that resource
|
||||
p = new Patient();
|
||||
p.setId("Patient/" + patientId);
|
||||
p.setActive(false);
|
||||
myPatientDao.update(p);
|
||||
myPatientDao.update(p, mySrd);
|
||||
|
||||
runInTransaction(() -> {
|
||||
// HFJ_RESOURCE
|
||||
ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new);
|
||||
assertEquals(myTenantId, resourceTable.getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, resourceTable.getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_RES_VER
|
||||
ResourceHistoryTable resVer = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(patientId, 2);
|
||||
assertEquals(tenantId, resVer.getTenantId().getTenantId().intValue());
|
||||
assertEquals(tenantDate, resVer.getTenantId().getTenantDate());
|
||||
int version = 2;
|
||||
ResourceHistoryTable resVer = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(patientId, version);
|
||||
assertEquals(myTenantId, resVer.getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, resVer.getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_RES_VER_PROV
|
||||
assertNotNull(resVer.getProvenance());
|
||||
assertNotNull(resVer.getTenantId());
|
||||
assertEquals(myTenantId, resVer.getProvenance().getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, resVer.getProvenance().getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_SPIDX_STRING
|
||||
List<ResourceIndexedSearchParamString> strings = myResourceIndexedSearchParamStringDao.findAllForResourceId(patientId);
|
||||
ourLog.info("\n * {}", strings.stream().map(ResourceIndexedSearchParamString::toString).collect(Collectors.joining("\n * ")));
|
||||
assertEquals(10, strings.size());
|
||||
assertEquals(myTenantId, strings.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(myTenantDate, strings.get(0).getTenantId().getTenantDate());
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadAcrossTenants() {
|
||||
IIdType patientId1 = createPatient(1, withActiveTrue());
|
||||
IIdType patientId2 = createPatient(1, withActiveTrue());
|
||||
|
||||
IdType gotId1 = myPatientDao.read(patientId1, mySrd).getIdElement().toUnqualifiedVersionless();
|
||||
assertEquals(patientId1, gotId1);
|
||||
IdType gotId2 = myPatientDao.read(patientId2, mySrd).getIdElement().toUnqualifiedVersionless();
|
||||
assertEquals(patientId2, gotId2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchAcrossAllTenants() {
|
||||
|
||||
}
|
||||
|
||||
private void createUniqueCompositeSp() {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-birthdate");
|
||||
|
@ -171,7 +263,7 @@ public class MultitenantR4Test extends BaseJpaR4SystemTest {
|
|||
mySearchParameterDao.update(sp);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-birthdate");
|
||||
sp.setId("SearchParameter/patient-birthdate-unique");
|
||||
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
sp.addBase("Patient");
|
||||
|
@ -186,27 +278,48 @@ public class MultitenantR4Test extends BaseJpaR4SystemTest {
|
|||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
public void addTenant(int theTenantId, LocalDate theTenantDate) {
|
||||
|
||||
|
||||
private void addCreateTenant(int theTenantId, LocalDate theTenantDate) {
|
||||
if (myTenantInterceptor == null) {
|
||||
myTenantInterceptor = new MyInterceptor();
|
||||
myInterceptorRegistry.registerInterceptor(myInterceptor);
|
||||
myInterceptorRegistry.registerInterceptor(myTenantInterceptor);
|
||||
}
|
||||
myTenantInterceptor.addTenant(new TenantId(theTenantId, theTenantDate));
|
||||
myTenantInterceptor.addCreateTenant(new TenantId(theTenantId, theTenantDate));
|
||||
}
|
||||
|
||||
public IIdType createPatient(int theTenantId, Consumer<Patient>... theModifiers) {
|
||||
addCreateTenant(theTenantId, null);
|
||||
Patient p = new Patient();
|
||||
for (Consumer<Patient> next : theModifiers) {
|
||||
next.accept(p);
|
||||
}
|
||||
|
||||
return myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
public void createRequestId() {
|
||||
when(mySrd.getRequestId()).thenReturn("REQUEST_ID");
|
||||
}
|
||||
|
||||
private Consumer<Patient> withActiveTrue() {
|
||||
return t->t.setActive(true);
|
||||
}
|
||||
|
||||
@Interceptor
|
||||
public static class MyInterceptor {
|
||||
|
||||
private final List<TenantId> myTenantIds = new ArrayList<>();
|
||||
|
||||
public void addTenant(TenantId theTenantId) {
|
||||
private final List<TenantId> myCreateTenantIds = new ArrayList<>();
|
||||
|
||||
public void addCreateTenant(TenantId theTenantId) {
|
||||
Validate.notNull(theTenantId);
|
||||
myTenantIds.add(theTenantId);
|
||||
myCreateTenantIds.add(theTenantId);
|
||||
}
|
||||
|
||||
@Hook(Pointcut.STORAGE_TENANT_IDENTIFY_CREATE)
|
||||
public TenantId tenantIdentifyCreate() {
|
||||
TenantId retVal = myTenantIds.remove(0);
|
||||
TenantId retVal = myCreateTenantIds.remove(0);
|
||||
ourLog.info("Returning tenant ID: {}", retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
|
|
@ -70,7 +70,8 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
|||
version.onTable("HFJ_RES_VER").modifyColumn("20200220.1", "RES_ID").nonNullable().failureAllowed().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG);
|
||||
|
||||
// Add mlutiitenancy
|
||||
version.onTable("HFJ_RESOURCE").dropColumn("20200327.1", "RES_PROFILE");
|
||||
version.onTable("HFJ_RESOURCE").dropIndex("20200327.1", "IDX_RES_PROFILE");
|
||||
version.onTable("HFJ_RESOURCE").dropColumn("20200327.2", "RES_PROFILE");
|
||||
}
|
||||
|
||||
protected void init420() { // 20191015 - 20200217
|
||||
|
|
|
@ -62,6 +62,8 @@ public class ForcedId {
|
|||
@ColumnDefault("''")
|
||||
@Column(name = "RESOURCE_TYPE", nullable = true, length = 100, updatable = true)
|
||||
private String myResourceType;
|
||||
@Embedded
|
||||
private TenantId myTenantId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -93,4 +95,12 @@ public class ForcedId {
|
|||
public Long getId() {
|
||||
return myId;
|
||||
}
|
||||
|
||||
public TenantId getTenantId() {
|
||||
return myTenantId;
|
||||
}
|
||||
|
||||
public void setTenantId(TenantId theTenantId) {
|
||||
myTenantId = theTenantId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,18 +51,17 @@ public class ResourceHistoryProvenanceEntity {
|
|||
@Embedded
|
||||
private TenantId myTenantId;
|
||||
|
||||
public ResourceTable getResourceTable() {
|
||||
return myResourceTable;
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ResourceHistoryProvenanceEntity() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void setResourceTable(ResourceTable theResourceTable) {
|
||||
myResourceTable = theResourceTable;
|
||||
}
|
||||
|
||||
public ResourceHistoryTable getResourceHistoryTable() {
|
||||
return myResourceHistoryTable;
|
||||
}
|
||||
|
||||
public void setResourceHistoryTable(ResourceHistoryTable theResourceHistoryTable) {
|
||||
myResourceHistoryTable = theResourceHistoryTable;
|
||||
}
|
||||
|
@ -86,4 +85,12 @@ public class ResourceHistoryProvenanceEntity {
|
|||
public Long getId() {
|
||||
return myId;
|
||||
}
|
||||
|
||||
public TenantId getTenantId() {
|
||||
return myTenantId;
|
||||
}
|
||||
|
||||
public void setTenantId(TenantId theTenantId) {
|
||||
myTenantId = theTenantId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,6 +64,7 @@ public class ResourceIndexedCompositeStringUnique implements Comparable<Resource
|
|||
public ResourceIndexedCompositeStringUnique(ResourceTable theResource, String theIndexString) {
|
||||
setResource(theResource);
|
||||
setIndexString(theIndexString);
|
||||
setTenantId(theResource.getTenantId());
|
||||
}
|
||||
|
||||
public TenantId getTenantId() {
|
||||
|
|
|
@ -183,9 +183,10 @@ public class ResourceIndexedSearchParamDate extends BaseResourceIndexedSearchPar
|
|||
public String toString() {
|
||||
ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
|
||||
b.append("paramName", getParamName());
|
||||
b.append("resourceId", getResource().getId()); // TODO: add a field so we don't need to resolve this
|
||||
b.append("resourceId", getResourcePid());
|
||||
b.append("valueLow", new InstantDt(getValueLow()));
|
||||
b.append("valueHigh", new InstantDt(getValueHigh()));
|
||||
b.append("missing", isMissing());
|
||||
return b.build();
|
||||
}
|
||||
|
||||
|
|
|
@ -53,7 +53,6 @@ import static org.apache.commons.lang3.StringUtils.defaultString;
|
|||
@Table(name = "HFJ_RESOURCE", uniqueConstraints = {}, indexes = {
|
||||
@Index(name = "IDX_RES_DATE", columnList = "RES_UPDATED"),
|
||||
@Index(name = "IDX_RES_LANG", columnList = "RES_TYPE,RES_LANGUAGE"),
|
||||
@Index(name = "IDX_RES_PROFILE", columnList = "RES_PROFILE"),
|
||||
@Index(name = "IDX_RES_TYPE", columnList = "RES_TYPE"),
|
||||
@Index(name = "IDX_INDEXSTATUS", columnList = "SP_INDEX_STATUS")
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue