issue-2901 review fixes

This commit is contained in:
leif stawnyczy 2021-09-03 15:36:42 -04:00
parent 78c71ce761
commit 64270a51e0
11 changed files with 171 additions and 85 deletions

View File

@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.api.dao;
*/ */
import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome; import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.api.model.DeleteConflictList; import ca.uhn.fhir.jpa.api.model.DeleteConflictList;
import ca.uhn.fhir.jpa.api.model.DeleteMethodOutcome; import ca.uhn.fhir.jpa.api.model.DeleteMethodOutcome;
@ -168,7 +169,7 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
* @param theIds - list of IIdType ids (for the same resource) * @param theIds - list of IIdType ids (for the same resource)
* @return * @return
*/ */
Map<IIdType, ResourcePersistentId> getIdsOfExistingResources(Collection<IIdType> theIds); Map<IIdType, ResourcePersistentId> getIdsOfExistingResources(RequestPartitionId partitionId, Collection<IIdType> theIds);
/** /**
* Read a resource by its internal PID * Read a resource by its internal PID

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.dao; package ca.uhn.fhir.jpa.dao;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId; import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
@ -18,7 +19,7 @@ public class AutoVersioningServiceImpl implements IAutoVersioningService {
private DaoRegistry myDaoRegistry; private DaoRegistry myDaoRegistry;
@Override @Override
public Map<IIdType, ResourcePersistentId> getExistingAutoversionsForIds(Collection<IIdType> theIds) { public Map<IIdType, ResourcePersistentId> getExistingAutoversionsForIds(RequestPartitionId theRequestPartitionId, Collection<IIdType> theIds) {
HashMap<IIdType, ResourcePersistentId> idToPID = new HashMap<>(); HashMap<IIdType, ResourcePersistentId> idToPID = new HashMap<>();
HashMap<String, List<IIdType>> resourceTypeToIds = new HashMap<>(); HashMap<String, List<IIdType>> resourceTypeToIds = new HashMap<>();
@ -33,7 +34,8 @@ public class AutoVersioningServiceImpl implements IAutoVersioningService {
for (String resourceType : resourceTypeToIds.keySet()) { for (String resourceType : resourceTypeToIds.keySet()) {
IFhirResourceDao dao = myDaoRegistry.getResourceDao(resourceType); IFhirResourceDao dao = myDaoRegistry.getResourceDao(resourceType);
Map<IIdType, ResourcePersistentId> idAndPID = dao.getIdsOfExistingResources(resourceTypeToIds.get(resourceType)); Map<IIdType, ResourcePersistentId> idAndPID = dao.getIdsOfExistingResources(theRequestPartitionId,
resourceTypeToIds.get(resourceType));
idToPID.putAll(idAndPID); idToPID.putAll(idAndPID);
} }

View File

@ -37,7 +37,6 @@ import ca.uhn.fhir.jpa.api.model.LazyDaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.index.IdHelperService; import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService; import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
import ca.uhn.fhir.jpa.delete.DeleteConflictService; import ca.uhn.fhir.jpa.delete.DeleteConflictService;
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
import ca.uhn.fhir.jpa.model.entity.BaseHasResource; import ca.uhn.fhir.jpa.model.entity.BaseHasResource;
import ca.uhn.fhir.jpa.model.entity.BaseTag; import ca.uhn.fhir.jpa.model.entity.BaseTag;
import ca.uhn.fhir.jpa.model.entity.ForcedId; import ca.uhn.fhir.jpa.model.entity.ForcedId;
@ -52,7 +51,6 @@ import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.patch.FhirPatch; import ca.uhn.fhir.jpa.patch.FhirPatch;
import ca.uhn.fhir.jpa.patch.JsonPatchUtils; import ca.uhn.fhir.jpa.patch.JsonPatchUtils;
import ca.uhn.fhir.jpa.patch.XmlPatchUtils; import ca.uhn.fhir.jpa.patch.XmlPatchUtils;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider; import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
import ca.uhn.fhir.jpa.search.cache.SearchCacheStatusEnum; import ca.uhn.fhir.jpa.search.cache.SearchCacheStatusEnum;
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc; import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
@ -141,6 +139,7 @@ import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -1160,7 +1159,8 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
} }
@Override @Override
public Map<IIdType, ResourcePersistentId> getIdsOfExistingResources(Collection<IIdType> theIds) { public Map<IIdType, ResourcePersistentId> getIdsOfExistingResources(RequestPartitionId thePartitionId,
Collection<IIdType> theIds) {
// these are the found Ids that were in the db // these are the found Ids that were in the db
HashMap<IIdType, ResourcePersistentId> collected = new HashMap<>(); HashMap<IIdType, ResourcePersistentId> collected = new HashMap<>();
@ -1168,26 +1168,40 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
return collected; return collected;
} }
List<String> idPortions = theIds List<ResourcePersistentId> resourcePersistentIds = myIdHelperService.resolveResourcePersistentIdsWithCache(thePartitionId,
.stream() theIds.stream().collect(Collectors.toList()));
.map(IIdType::getIdPart)
.collect(Collectors.toList());
Collection<Object[]> matches = myForcedIdDao.findResourcesByForcedId(getResourceName(), // we'll use this map to fetch pids that require versions
idPortions); HashMap<Long, ResourcePersistentId> pidsToVersionToResourcePid = new HashMap<>();
for (Object[] match : matches) { // fill in our map
String resourceType = (String) match[0]; for (ResourcePersistentId pid : resourcePersistentIds) {
String forcedId = (String) match[1]; if (pid.getVersion() == null) {
Long pid = (Long) match[2]; pidsToVersionToResourcePid.put(pid.getIdAsLong(), pid);
Long versionId = (Long) match[3]; }
IIdType id = new IdDt(resourceType, forcedId); Optional<IIdType> idOp = theIds.stream()
// we won't put the version on the IIdType .filter(i -> i.getIdPart().equals(pid.getAssociatedResourceId().getIdPart()))
// so callers can use this as a lookup to match to .findFirst();
ResourcePersistentId persistentId = new ResourcePersistentId(pid); // this should always be present
persistentId.setVersion(versionId); // since it was passed in.
// but land of optionals...
idOp.ifPresent(id -> {
collected.put(id, pid);
});
}
collected.put(id, persistentId); // set any versions we don't already have
if (!pidsToVersionToResourcePid.isEmpty()) {
Collection<Object[]> resourceEntries = myResourceTableDao
.getResourceVersionsForPid(new ArrayList<>(pidsToVersionToResourcePid.keySet()));
for (Object[] record : resourceEntries) {
// order matters!
Long retPid = (Long)record[0];
String resType = (String)record[1];
Long version = (Long)record[2];
pidsToVersionToResourcePid.get(retPid).setVersion(version);
}
} }
return collected; return collected;

View File

@ -25,6 +25,7 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome; import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
@ -209,7 +210,7 @@ public abstract class BaseStorageDao {
IIdType referenceElement = nextReference.getReferenceElement(); IIdType referenceElement = nextReference.getReferenceElement();
if (!referenceElement.hasBaseUrl()) { if (!referenceElement.hasBaseUrl()) {
Map<IIdType, ResourcePersistentId> idToPID = myAutoVersioningService.getExistingAutoversionsForIds( Map<IIdType, ResourcePersistentId> idToPID = myAutoVersioningService.getExistingAutoversionsForIds(RequestPartitionId.allPartitions(),
Collections.singletonList(referenceElement) Collections.singletonList(referenceElement)
); );
@ -220,7 +221,7 @@ public abstract class BaseStorageDao {
Long version; Long version;
if (idToPID.containsKey(referenceElement)) { if (idToPID.containsKey(referenceElement)) {
// the resource exists... latest id // the resource exists... latest id
// will bbe the value in the ResourcePersistentId // will be the value in the ResourcePersistentId
version = idToPID.get(referenceElement).getVersion(); version = idToPID.get(referenceElement).getVersion();
} }
else if (myDaoConfig.isAutoCreatePlaceholderReferenceTargets()) { else if (myDaoConfig.isAutoCreatePlaceholderReferenceTargets()) {

View File

@ -25,6 +25,7 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.interceptor.model.TransactionWriteOperationsDetails; import ca.uhn.fhir.interceptor.model.TransactionWriteOperationsDetails;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
@ -1268,7 +1269,9 @@ public abstract class BaseTransactionProcessor {
} else { } else {
// get a map of // get a map of
// existing ids -> PID (for resources that exist in the DB) // existing ids -> PID (for resources that exist in the DB)
Map<IIdType, ResourcePersistentId> idToPID = myAutoVersioningService.getExistingAutoversionsForIds(theReferencesToAutoVersion.stream() // should this be allPartitions?
Map<IIdType, ResourcePersistentId> idToPID = myAutoVersioningService.getExistingAutoversionsForIds(RequestPartitionId.allPartitions(),
theReferencesToAutoVersion.stream()
.map(ref -> ref.getReferenceElement()).collect(Collectors.toList())); .map(ref -> ref.getReferenceElement()).collect(Collectors.toList()));
for (IBaseReference baseRef : theReferencesToAutoVersion) { for (IBaseReference baseRef : theReferencesToAutoVersion) {

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.dao; package ca.uhn.fhir.jpa.dao;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId; import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
@ -17,7 +18,8 @@ public interface IAutoVersioningService {
* If the returned map does not return an IIdType -> ResourcePersistentId * If the returned map does not return an IIdType -> ResourcePersistentId
* then it means that it is a non-existing resource in the DB * then it means that it is a non-existing resource in the DB
* @param theIds * @param theIds
* @param thePartitionId - the partition id
* @return * @return
*/ */
Map<IIdType, ResourcePersistentId> getExistingAutoversionsForIds(Collection<IIdType> theIds); Map<IIdType, ResourcePersistentId> getExistingAutoversionsForIds(RequestPartitionId thePartitionId, Collection<IIdType> theIds);
} }

View File

@ -111,23 +111,6 @@ public interface IForcedIdDao extends JpaRepository<ForcedId, Long> {
"WHERE f.myResourceType = :resource_type AND f.myForcedId IN ( :forced_id )") "WHERE f.myResourceType = :resource_type AND f.myForcedId IN ( :forced_id )")
Collection<Object[]> findAndResolveByForcedIdWithNoType(@Param("resource_type") String theResourceType, @Param("forced_id") Collection<String> theForcedIds); Collection<Object[]> findAndResolveByForcedIdWithNoType(@Param("resource_type") String theResourceType, @Param("forced_id") Collection<String> theForcedIds);
/**
* This method returns a collection where eah row is an element in the collection.
* Each element in the collection is an object array where order matters.
* The returned order of each object array element is:
* ResourceType (Patient, etc - String), ForcedId (String), ResourcePID (Long), Version (Long)
* @param theResourceType
* @param theForcedIds
* @return
*/
@Query("" +
"SELECT " +
" f.myResourceType, f.myForcedId, f.myResourcePid, t.myVersion " +
"FROM ForcedId f " +
"JOIN ResourceTable t ON t.myId = f.myResourcePid " +
"WHERE f.myResourceType = :resource_type AND f.myForcedId IN ( :forced_id )")
Collection<Object[]> findResourcesByForcedId(@Param("resource_type") String theResourceType, @Param("forced_id") Collection<String> theForcedIds);
/** /**
* This method returns a Collection where each row is an element in the collection. Each element in the collection * This method returns a Collection where each row is an element in the collection. Each element in the collection
* is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way. * is an object array, where the order matters (the array represents columns returned by the query). Be careful if you change this query in any way.

View File

@ -100,6 +100,16 @@ public interface IResourceTableDao extends JpaRepository<ResourceTable, Long> {
@Query("SELECT t.myVersion FROM ResourceTable t WHERE t.myId = :pid") @Query("SELECT t.myVersion FROM ResourceTable t WHERE t.myId = :pid")
Long findCurrentVersionByPid(@Param("pid") Long thePid); Long findCurrentVersionByPid(@Param("pid") Long thePid);
/**
* This query will return rows with the following values:
* Id (resource pid - long), ResourceType (Patient, etc), version (long)
* Order matters!
* @param pid - list of pids to get versions for
* @return
*/
@Query("SELECT t.myId, t.myResourceType, t.myVersion FROM ResourceTable t WHERE t.myId IN ( :pid )")
Collection<Object[]> getResourceVersionsForPid(@Param("pid") List<Long> pid);
@Query("SELECT t FROM ResourceTable t LEFT JOIN FETCH t.myForcedId WHERE t.myPartitionId.myPartitionId IS NULL AND t.myId = :pid") @Query("SELECT t FROM ResourceTable t LEFT JOIN FETCH t.myForcedId WHERE t.myPartitionId.myPartitionId IS NULL AND t.myId = :pid")
Optional<ResourceTable> readByPartitionIdNull(@Param("pid") Long theResourceId); Optional<ResourceTable> readByPartitionIdNull(@Param("pid") Long theResourceId);

View File

@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.dao; package ca.uhn.fhir.jpa.dao;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
@ -36,12 +37,14 @@ public class AutoVersioningServiceImplTests {
map.put(type, pid); map.put(type, pid);
IFhirResourceDao daoMock = Mockito.mock(IFhirResourceDao.class); IFhirResourceDao daoMock = Mockito.mock(IFhirResourceDao.class);
Mockito.when(daoMock.getIdsOfExistingResources(Mockito.anyList())) Mockito.when(daoMock.getIdsOfExistingResources(Mockito.any(RequestPartitionId.class),
Mockito.anyList()))
.thenReturn(map); .thenReturn(map);
Mockito.when(daoRegistry.getResourceDao(Mockito.anyString())) Mockito.when(daoRegistry.getResourceDao(Mockito.anyString()))
.thenReturn(daoMock); .thenReturn(daoMock);
Map<IIdType, ResourcePersistentId> retMap = myAutoversioningService.getExistingAutoversionsForIds(Collections.singletonList(type)); Map<IIdType, ResourcePersistentId> retMap = myAutoversioningService.getExistingAutoversionsForIds(RequestPartitionId.allPartitions(),
Collections.singletonList(type));
Assertions.assertTrue(retMap.containsKey(type)); Assertions.assertTrue(retMap.containsKey(type));
Assertions.assertEquals(pid.getVersion(), map.get(type).getVersion()); Assertions.assertEquals(pid.getVersion(), map.get(type).getVersion());
@ -52,12 +55,14 @@ public class AutoVersioningServiceImplTests {
IIdType type = new IdDt("Patient/RED"); IIdType type = new IdDt("Patient/RED");
IFhirResourceDao daoMock = Mockito.mock(IFhirResourceDao.class); IFhirResourceDao daoMock = Mockito.mock(IFhirResourceDao.class);
Mockito.when(daoMock.getIdsOfExistingResources(Mockito.anyList())) Mockito.when(daoMock.getIdsOfExistingResources(Mockito.any(RequestPartitionId.class),
Mockito.anyList()))
.thenReturn(new HashMap<>()); .thenReturn(new HashMap<>());
Mockito.when(daoRegistry.getResourceDao(Mockito.anyString())) Mockito.when(daoRegistry.getResourceDao(Mockito.anyString()))
.thenReturn(daoMock); .thenReturn(daoMock);
Map<IIdType, ResourcePersistentId> retMap = myAutoversioningService.getExistingAutoversionsForIds(Collections.singletonList(type)); Map<IIdType, ResourcePersistentId> retMap = myAutoversioningService.getExistingAutoversionsForIds(RequestPartitionId.allPartitions(),
Collections.singletonList(type));
Assertions.assertTrue(retMap.isEmpty()); Assertions.assertTrue(retMap.isEmpty());
} }
@ -73,13 +78,14 @@ public class AutoVersioningServiceImplTests {
// when // when
IFhirResourceDao daoMock = Mockito.mock(IFhirResourceDao.class); IFhirResourceDao daoMock = Mockito.mock(IFhirResourceDao.class);
Mockito.when(daoMock.getIdsOfExistingResources(Mockito.anyList())) Mockito.when(daoMock.getIdsOfExistingResources(Mockito.any(RequestPartitionId.class), Mockito.anyList()))
.thenReturn(map); .thenReturn(map);
Mockito.when(daoRegistry.getResourceDao(Mockito.anyString())) Mockito.when(daoRegistry.getResourceDao(Mockito.anyString()))
.thenReturn(daoMock); .thenReturn(daoMock);
// test // test
Map<IIdType, ResourcePersistentId> retMap = myAutoversioningService.getExistingAutoversionsForIds( Map<IIdType, ResourcePersistentId> retMap = myAutoversioningService.getExistingAutoversionsForIds(
RequestPartitionId.allPartitions(),
Arrays.asList(type, type2) Arrays.asList(type, type2)
); );

View File

@ -2,8 +2,11 @@ package ca.uhn.fhir.jpa.dao;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao; import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails; import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
@ -13,12 +16,14 @@ 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 org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Request;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks; import org.mockito.InjectMocks;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito; import org.mockito.Mockito;
import org.mockito.junit.MockitoTestRule;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import java.util.ArrayList; import java.util.ArrayList;
@ -54,27 +59,40 @@ class BaseHapiFhirResourceDaoTest {
@InjectMocks @InjectMocks
private BaseHapiFhirResourceDao myBaseHapiFhirResourceDao = new SimpleTestDao(); private BaseHapiFhirResourceDao myBaseHapiFhirResourceDao = new SimpleTestDao();
// @Mock
// private IForcedIdDao myIForcedIdDao;
@Mock @Mock
private IForcedIdDao myIForcedIdDao; private IdHelperService myIdHelperService;
@Mock
private IResourceTableDao myResourceTableDao;
//TODO - all other dependency mocks //TODO - all other dependency mocks
private ResourcePersistentId getResourcePersistentIdFromResource(IIdType theId, long thePid) {
ResourcePersistentId id = new ResourcePersistentId(thePid);
String idPortion = theId.getIdPart();
IIdType newId = new IdDt(theId.getResourceType(), idPortion);
id.setAssociatedResourceId(newId);
return id;
}
/** /**
* Creates a match entry to be returned by myIForcedIdDao. * Gets a ResourceTable record for getResourceVersionsForPid
* This ordering matters (see IForcedIdDao) * Order matters!
* @param theId * @param resourceType
* @param thePID * @param pid
* @param theResourceVersion * @param version
* @return * @return
*/ */
private Object[] createMatchEntryForGetIdsOfExistingResources(IIdType theId, long thePID, long theResourceVersion) { private Object[] getResourceTableRecordForResourceTypeAndPid(String resourceType, long pid, long version) {
Object[] arr = new Object[] { return new Object[] {
theId.getResourceType(), pid, // long
theId.getIdPart(), resourceType, // string
thePID, version // long
theResourceVersion
}; };
return arr;
} }
@Test @Test
@ -83,31 +101,38 @@ class BaseHapiFhirResourceDaoTest {
IIdType patientIdAndType = new IdDt("Patient/RED"); IIdType patientIdAndType = new IdDt("Patient/RED");
long patientPID = 1L; long patientPID = 1L;
long patientResourceVersion = 2L; long patientResourceVersion = 2L;
ResourcePersistentId pat1ResourcePID = getResourcePersistentIdFromResource(patientIdAndType, patientPID);
IIdType patient2IdAndType = new IdDt("Patient/BLUE"); IIdType patient2IdAndType = new IdDt("Patient/BLUE");
long patient2PID = 3L; long patient2PID = 3L;
long patient2ResourceVersion = 4L; long patient2ResourceVersion = 4L;
ResourcePersistentId pat2ResourcePID = getResourcePersistentIdFromResource(patient2IdAndType, patient2PID);
List<IIdType> inputList = new ArrayList<>(); List<IIdType> inputList = new ArrayList<>();
inputList.add(patientIdAndType); inputList.add(patientIdAndType);
inputList.add(patient2IdAndType); inputList.add(patient2IdAndType);
Collection<Object[]> matches = Arrays.asList( Collection<Object[]> matches = Arrays.asList(
createMatchEntryForGetIdsOfExistingResources(patientIdAndType, patientPID, patientResourceVersion), getResourceTableRecordForResourceTypeAndPid(patientIdAndType.getResourceType(), patientPID, patientResourceVersion),
createMatchEntryForGetIdsOfExistingResources(patient2IdAndType, patient2PID, patient2ResourceVersion) getResourceTableRecordForResourceTypeAndPid(patient2IdAndType.getResourceType(), patient2PID, patient2ResourceVersion)
); );
// when // when
Mockito.when(myIForcedIdDao.findResourcesByForcedId(Mockito.anyString(), Mockito.when(myIdHelperService.resolveResourcePersistentIdsWithCache(Mockito.any(RequestPartitionId.class),
Mockito.anyList())).thenReturn(matches); Mockito.anyList()))
.thenReturn(Arrays.asList(pat1ResourcePID, pat2ResourcePID));
Mockito.when(myResourceTableDao.getResourceVersionsForPid(Mockito.anyList()))
.thenReturn(matches);
Map<IIdType, ResourcePersistentId> idToPIDOfExistingResources = myBaseHapiFhirResourceDao.getIdsOfExistingResources(inputList); Map<IIdType, ResourcePersistentId> idToPIDOfExistingResources = myBaseHapiFhirResourceDao.getIdsOfExistingResources(RequestPartitionId.allPartitions(),
inputList);
Assertions.assertEquals(inputList.size(), idToPIDOfExistingResources.size()); Assertions.assertEquals(inputList.size(), idToPIDOfExistingResources.size());
Assertions.assertTrue(idToPIDOfExistingResources.containsKey(patientIdAndType)); Assertions.assertTrue(idToPIDOfExistingResources.containsKey(patientIdAndType));
Assertions.assertTrue(idToPIDOfExistingResources.containsKey(patient2IdAndType)); Assertions.assertTrue(idToPIDOfExistingResources.containsKey(patient2IdAndType));
Assertions.assertEquals(idToPIDOfExistingResources.get(patientIdAndType).getIdAsLong(), patientPID);
Assertions.assertEquals(idToPIDOfExistingResources.get(patient2IdAndType).getIdAsLong(), patient2PID); Assertions.assertEquals(patientPID, idToPIDOfExistingResources.get(patientIdAndType).getIdAsLong());
Assertions.assertEquals(idToPIDOfExistingResources.get(patientIdAndType).getVersion(), patientResourceVersion); Assertions.assertEquals(patient2PID, idToPIDOfExistingResources.get(patient2IdAndType).getIdAsLong(), patient2PID);
Assertions.assertEquals(idToPIDOfExistingResources.get(patient2IdAndType).getVersion(), patient2ResourceVersion); Assertions.assertEquals(patientResourceVersion, idToPIDOfExistingResources.get(patientIdAndType).getVersion());
Assertions.assertEquals(patient2ResourceVersion, idToPIDOfExistingResources.get(patient2IdAndType).getVersion());
} }
@Test @Test
@ -116,10 +141,12 @@ class BaseHapiFhirResourceDaoTest {
IIdType patient = new IdDt("Patient/RED"); IIdType patient = new IdDt("Patient/RED");
// when // when
Mockito.when(myIForcedIdDao.findResourcesByForcedId(Mockito.anyString(), Mockito.anyList())) Mockito.when(myIdHelperService.resolveResourcePersistentIdsWithCache(Mockito.any(RequestPartitionId.class),
Mockito.anyList()))
.thenReturn(new ArrayList<>()); .thenReturn(new ArrayList<>());
Map<IIdType, ResourcePersistentId> map = myBaseHapiFhirResourceDao.getIdsOfExistingResources(Collections.singletonList(patient)); Map<IIdType, ResourcePersistentId> map = myBaseHapiFhirResourceDao.getIdsOfExistingResources(RequestPartitionId.allPartitions(),
Collections.singletonList(patient));
Assertions.assertTrue(map.isEmpty()); Assertions.assertTrue(map.isEmpty());
} }
@ -135,15 +162,17 @@ class BaseHapiFhirResourceDaoTest {
inputList.add(patientIdAndType); inputList.add(patientIdAndType);
inputList.add(patient2IdAndType); inputList.add(patient2IdAndType);
Collection<Object[]> matches = Collections.singletonList(
createMatchEntryForGetIdsOfExistingResources(patientIdAndType, patientPID, patientResourceVersion)
);
// when // when
Mockito.when(myIForcedIdDao.findResourcesByForcedId(Mockito.anyString(), Mockito.anyList())) Mockito.when(myIdHelperService
.thenReturn(matches); .resolveResourcePersistentIdsWithCache(Mockito.any(RequestPartitionId.class),
Mockito.anyList()))
.thenReturn(Collections.singletonList(getResourcePersistentIdFromResource(patientIdAndType, patientPID)));
Mockito.when(myResourceTableDao.getResourceVersionsForPid(Mockito.anyList()))
.thenReturn(Collections
.singletonList(getResourceTableRecordForResourceTypeAndPid(patientIdAndType.getResourceType(), patientPID, patientResourceVersion)));
Map<IIdType, ResourcePersistentId> map = myBaseHapiFhirResourceDao.getIdsOfExistingResources(inputList); Map<IIdType, ResourcePersistentId> map = myBaseHapiFhirResourceDao.getIdsOfExistingResources(RequestPartitionId.allPartitions(),
inputList);
// verify // verify
Assertions.assertFalse(map.isEmpty()); Assertions.assertFalse(map.isEmpty());

View File

@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.dao.r4; package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.model.entity.ModelConfig; import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.partition.SystemRequestDetails; import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
@ -538,7 +539,6 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
AuditEvent createdEvent = myAuditEventDao.read(id); AuditEvent createdEvent = myAuditEventDao.read(id);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(createdEvent)); ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(createdEvent));
} }
@Test @Test
@ -558,7 +558,6 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
IIdType id = myObservationDao.create(obsToCreate, mySrd).getId(); IIdType id = myObservationDao.create(obsToCreate, mySrd).getId();
Observation createdObs = myObservationDao.read(id); Observation createdObs = myObservationDao.read(id);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(createdObs));
assertEquals("Patient/ABC", createdObs.getSubject().getReference()); assertEquals("Patient/ABC", createdObs.getSubject().getReference());
} }
@ -575,8 +574,9 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
mySystemDao.transaction(new SystemRequestDetails(), (Bundle) builder.getBundle()); mySystemDao.transaction(new SystemRequestDetails(), (Bundle) builder.getBundle());
// verify subresource is created
Patient returned = myPatientDao.read(patientRef.getReferenceElement()); Patient returned = myPatientDao.read(patientRef.getReferenceElement());
Assertions.assertTrue(returned != null); assertNotNull(returned);
} }
@ -607,10 +607,45 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
Bundle transaction = mySystemDao.transaction(new SystemRequestDetails(), (Bundle) builder.getBundle()); Bundle transaction = mySystemDao.transaction(new SystemRequestDetails(), (Bundle) builder.getBundle());
Patient returned = myPatientDao.read(patientRef.getReferenceElement()); Patient returned = myPatientDao.read(patientRef.getReferenceElement());
Assertions.assertTrue(returned != null); assertNotNull(returned);
Assertions.assertTrue(returned.getActive()); Assertions.assertTrue(returned.getActive());
Assertions.assertEquals(2, returned.getIdElement().getVersionIdPartAsLong());
Observation retObservation = myObservationDao.read(obs.getIdElement()); Observation retObservation = myObservationDao.read(obs.getIdElement());
Assertions.assertTrue(retObservation != null); assertNotNull(retObservation);
} }
@Test
public void testAutocreatePlaceholderWithExistingTargetWithServerAssignedIdTest() {
myDaoConfig.setAutoCreatePlaceholderReferenceTargets(true);
myModelConfig.setAutoVersionReferenceAtPaths("Observation.subject");
// create
Patient patient = new Patient();
patient.setIdElement(new IdType("Patient"));
DaoMethodOutcome ret = myPatientDao.create(patient);
// update
patient.setActive(true);
myPatientDao.update(patient);
// observation (with version 2)
Observation obs = new Observation();
obs.setId("Observation/DEF");
Reference patientRef = new Reference("Patient/" + ret.getId().getIdPart());
obs.setSubject(patientRef);
BundleBuilder builder = new BundleBuilder(myFhirCtx);
builder.addTransactionUpdateEntry(obs);
Bundle transaction = mySystemDao.transaction(new SystemRequestDetails(), (Bundle) builder.getBundle());
Patient returned = myPatientDao.read(patientRef.getReferenceElement());
assertNotNull(returned);
Assertions.assertEquals(2, returned.getIdElement().getVersionIdPartAsLong());
Observation retObservation = myObservationDao.read(obs.getIdElement());
assertNotNull(retObservation);
}
} }