Work on multitenancy
This commit is contained in:
parent
ebf395bee9
commit
1d1aadb813
|
@ -25,15 +25,13 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
|||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Optional;
|
||||
import java.util.List;
|
||||
|
||||
public interface IResourceIndexedCompositeStringUniqueDao extends JpaRepository<ResourceIndexedCompositeStringUnique, Long> {
|
||||
|
||||
@Query("SELECT r FROM ResourceIndexedCompositeStringUnique r WHERE r.myIndexString = :str")
|
||||
ResourceIndexedCompositeStringUnique findByQueryString(@Param("str") String theQueryString);
|
||||
|
||||
@Query("SELECT r.myResourceId FROM ResourceIndexedCompositeStringUnique r WHERE r.myIndexString IN :str")
|
||||
Collection<Long> findResourcePidsByQueryStrings(@Param("str") Collection<String> theQueryString);
|
||||
|
||||
@Query("SELECT r FROM ResourceIndexedCompositeStringUnique r WHERE r.myResourceId = :resId")
|
||||
List<ResourceIndexedCompositeStringUnique> findAllForResourceId(@Param("resId") Long theResourceId);
|
||||
}
|
||||
|
|
|
@ -20,9 +20,8 @@ package ca.uhn.fhir.jpa.dao.data;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
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;
|
||||
|
@ -32,6 +31,9 @@ import java.util.List;
|
|||
public interface IResourceIndexedSearchParamStringDao extends JpaRepository<ResourceIndexedSearchParamString, Long> {
|
||||
|
||||
@Modifying
|
||||
@Query("delete from ResourceIndexedSearchParamString t WHERE t.myResourcePid = :resid")
|
||||
void deleteByResourceId(@Param("resid") Long theResourcePid);
|
||||
@Query("DELETE FROM ResourceIndexedSearchParamString t WHERE t.myResourcePid = :resId")
|
||||
void deleteByResourceId(@Param("resId") Long theResourcePid);
|
||||
|
||||
@Query("SELECT t FROM ResourceIndexedSearchParamString t WHERE t.myResourcePid = :resId")
|
||||
List<ResourceIndexedSearchParamString> findAllForResourceId(@Param("resId") Long thePatientId);
|
||||
}
|
||||
|
|
|
@ -20,16 +20,20 @@ package ca.uhn.fhir.jpa.dao.data;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||
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 IResourceLinkDao extends JpaRepository<ResourceLink, Long> {
|
||||
|
||||
@Modifying
|
||||
@Query("delete from ResourceLink t WHERE t.mySourceResourcePid = :resid")
|
||||
void deleteByResourceId(@Param("resid") Long theResourcePid);
|
||||
@Query("DELETE FROM ResourceLink t WHERE t.mySourceResourcePid = :resId")
|
||||
void deleteByResourceId(@Param("resId") Long theResourcePid);
|
||||
|
||||
@Query("SELECT t FROM ResourceLink t WHERE t.mySourceResourcePid = :resId")
|
||||
List<ResourceLink> findAllForResourceId(@Param("resId") Long thePatientId);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
package ca.uhn.fhir.jpa.dao.data;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.SearchParamPresent;
|
||||
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;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
|
@ -23,18 +29,10 @@ import java.util.Date;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
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 ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.SearchParamPresent;
|
||||
|
||||
public interface ISearchParamPresentDao extends JpaRepository<SearchParamPresent, Long> {
|
||||
|
||||
@Query("SELECT s FROM SearchParamPresent s WHERE s.myResource = :res")
|
||||
Collection<SearchParamPresent> findAllForResource(@Param("res") ResourceTable theResource);
|
||||
List<SearchParamPresent> findAllForResource(@Param("res") ResourceTable theResource);
|
||||
|
||||
@Modifying
|
||||
@Query("delete from SearchParamPresent t WHERE t.myResourcePid = :resid")
|
||||
|
|
|
@ -66,6 +66,7 @@ public class SearchParamPresenceSvcImpl implements ISearchParamPresenceSvc {
|
|||
present.setResource(theResource);
|
||||
present.setParamName(paramName);
|
||||
present.setPresent(next.getValue());
|
||||
present.setTenantId(theResource.getTenantId());
|
||||
present.calculateHashes();
|
||||
|
||||
newHashToPresence.put(present.getHashPresence(), present);
|
||||
|
|
|
@ -4,13 +4,22 @@ 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.ResourceHistoryTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.SearchParamPresent;
|
||||
import ca.uhn.fhir.jpa.model.entity.TenantId;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
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.Organization;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.SearchParameter;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
|
@ -19,6 +28,7 @@ import org.junit.Test;
|
|||
import javax.servlet.ServletException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.Month;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -62,30 +72,88 @@ public class MultitenantR4Test extends BaseJpaR4SystemTest {
|
|||
|
||||
@Test
|
||||
public void testCreateResourceWithTenant() {
|
||||
createUniqueCompositeSp();
|
||||
|
||||
int expectId = 3;
|
||||
LocalDate expectDate = LocalDate.of(2020, Month.JANUARY, 14);
|
||||
myInterceptorRegistry.registerInterceptor(new MyInterceptor(new TenantId(expectId, expectDate)));
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setName("org");
|
||||
IIdType orgId = myOrganizationDao.create(org).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("FAM");
|
||||
p.addIdentifier().setSystem("system").setValue("value");
|
||||
p.setBirthDate(new Date());
|
||||
p.getManagingOrganization().setReferenceElement(orgId);
|
||||
Long patientId = myPatientDao.create(p).getId().getIdPartAsLong();
|
||||
|
||||
runInTransaction(() -> {
|
||||
// HFJ_RESOURCE
|
||||
ResourceTable resourceTable = myResourceTableDao.findById(patientId).orElseThrow(IllegalArgumentException::new);
|
||||
assertEquals(expectId, resourceTable.getTenantId().getTenantId().intValue());
|
||||
assertEquals(expectDate, resourceTable.getTenantId().getTenantDate());
|
||||
|
||||
List<ResourceIndexedSearchParamString> strings = myResourceIndexedSearchParamStringDao.findAll();
|
||||
// HFJ_RES_VER
|
||||
ResourceHistoryTable version = myResourceHistoryTableDao.findForIdAndVersionAndFetchProvenance(patientId, 1L);
|
||||
assertEquals(expectId, version.getTenantId().getTenantId().intValue());
|
||||
assertEquals(expectDate, version.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(expectId, strings.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(expectDate, strings.get(0).getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_RES_LINK
|
||||
List<ResourceLink> resourceLinks = myResourceLinkDao.findAllForResourceId(patientId);
|
||||
assertEquals(1, resourceLinks.size());
|
||||
assertEquals(expectId, resourceLinks.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(expectDate, resourceLinks.get(0).getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_RES_PARAM_PRESENT
|
||||
List<SearchParamPresent> presents = mySearchParamPresentDao.findAllForResource(resourceTable);
|
||||
assertEquals(3, presents.size());
|
||||
assertEquals(expectId, presents.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(expectDate, presents.get(0).getTenantId().getTenantDate());
|
||||
|
||||
// HFJ_IDX_CMP_STRING_UNIQ
|
||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAllForResourceId(patientId);
|
||||
assertEquals(3, uniques.size());
|
||||
assertEquals(expectId, uniques.get(0).getTenantId().getTenantId().intValue());
|
||||
assertEquals(expectDate, uniques.get(0).getTenantId().getTenantDate());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void createUniqueCompositeSp() {
|
||||
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");
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/patient-birthdate");
|
||||
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
sp.addBase("Patient");
|
||||
sp.addComponent()
|
||||
.setExpression("Patient")
|
||||
.setDefinition("SearchParameter/patient-birthdate");
|
||||
sp.addExtension()
|
||||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
@Interceptor
|
||||
public static class MyInterceptor {
|
||||
|
||||
|
|
|
@ -48,6 +48,8 @@ public class ResourceIndexedCompositeStringUnique implements Comparable<Resource
|
|||
private Long myResourceId;
|
||||
@Column(name = "IDX_STRING", nullable = false, length = MAX_STRING_LENGTH)
|
||||
private String myIndexString;
|
||||
@Embedded
|
||||
private TenantId myTenantId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -64,6 +66,14 @@ public class ResourceIndexedCompositeStringUnique implements Comparable<Resource
|
|||
setIndexString(theIndexString);
|
||||
}
|
||||
|
||||
public TenantId getTenantId() {
|
||||
return myTenantId;
|
||||
}
|
||||
|
||||
public void setTenantId(TenantId theTenantId) {
|
||||
myTenantId = theTenantId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(ResourceIndexedCompositeStringUnique theO) {
|
||||
CompareToBuilder b = new CompareToBuilder();
|
||||
|
@ -116,6 +126,7 @@ public class ResourceIndexedCompositeStringUnique implements Comparable<Resource
|
|||
.append("id", myId)
|
||||
.append("resourceId", myResourceId)
|
||||
.append("indexString", myIndexString)
|
||||
.append("tenant", myTenantId)
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,12 +46,14 @@ public class SearchParamPresent implements Serializable {
|
|||
@ManyToOne()
|
||||
@JoinColumn(name = "RES_ID", referencedColumnName = "RES_ID", nullable = false, foreignKey = @ForeignKey(name = "FK_RESPARMPRES_RESID"))
|
||||
private ResourceTable myResource;
|
||||
@Column(name="RES_ID", nullable = false, insertable = false, updatable = false)
|
||||
@Column(name = "RES_ID", nullable = false, insertable = false, updatable = false)
|
||||
private Long myResourcePid;
|
||||
@Transient
|
||||
private transient String myParamName;
|
||||
@Column(name = "HASH_PRESENCE")
|
||||
private Long myHashPresence;
|
||||
@Embedded
|
||||
private TenantId myTenantId;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -110,9 +112,18 @@ public class SearchParamPresent implements Serializable {
|
|||
b.append("resPid", myResource.getIdDt().toUnqualifiedVersionless().getValue());
|
||||
b.append("paramName", myParamName);
|
||||
b.append("present", myPresent);
|
||||
b.append("tenant", myTenantId);
|
||||
return b.build();
|
||||
}
|
||||
|
||||
public TenantId getTenantId() {
|
||||
return myTenantId;
|
||||
}
|
||||
|
||||
public void setTenantId(TenantId theTenantId) {
|
||||
myTenantId = theTenantId;
|
||||
}
|
||||
|
||||
public static long calculateHashPresence(String theResourceType, String theParamName, Boolean thePresent) {
|
||||
String string = thePresent != null ? Boolean.toString(thePresent) : Boolean.toString(false);
|
||||
return BaseResourceIndexedSearchParam.hash(theResourceType, theParamName, string);
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
package ca.uhn.fhir.jpa.model.entity;
|
||||
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import java.time.LocalDate;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
|
||||
@Embeddable
|
||||
public class TenantId implements Cloneable {
|
||||
|
||||
@Column(name = "TENANT_ID", nullable = true)
|
||||
@Column(name = "TENANT_ID", nullable = true, insertable = true, updatable = false)
|
||||
private Integer myTenantId;
|
||||
@Column(name = "TENANT_DATE", nullable = true)
|
||||
@Column(name = "TENANT_DATE", nullable = true, insertable = true, updatable = false)
|
||||
private LocalDate myTenantDate;
|
||||
|
||||
/**
|
||||
|
@ -57,9 +56,6 @@ public class TenantId implements Cloneable {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||
.append("id", myTenantId)
|
||||
.append("date", myTenantDate)
|
||||
.toString();
|
||||
return defaultIfNull(myTenantId, "null").toString();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue