Add circular reference handling, and DeleteConflict handling
This commit is contained in:
parent
7e694ded3f
commit
fac14240c8
|
@ -231,6 +231,7 @@ public class EmpiLinkDaoSvc {
|
|||
*
|
||||
* @return A list of Long representing the related Person Pids.
|
||||
*/
|
||||
@Transactional
|
||||
public List<Long> deleteAllEmpiLinksAndReturnPersonPids() {
|
||||
List<EmpiLink> all = myEmpiLinkDao.findAll();
|
||||
return deleteEmpiLinksAndReturnPersonPids(all);
|
||||
|
|
|
@ -22,10 +22,19 @@ package ca.uhn.fhir.jpa.empi.svc;
|
|||
|
||||
import ca.uhn.fhir.empi.api.IEmpiResetSvc;
|
||||
import ca.uhn.fhir.empi.util.EmpiUtil;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.api.model.DeleteConflict;
|
||||
import ca.uhn.fhir.jpa.api.model.DeleteConflictList;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||
import ca.uhn.fhir.jpa.dao.expunge.IResourceExpungeService;
|
||||
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||
import ca.uhn.fhir.jpa.empi.dao.EmpiLinkDaoSvc;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -47,9 +56,18 @@ public class EmpiResetSvcImpl implements IEmpiResetSvc {
|
|||
@Autowired
|
||||
private IResourceExpungeService myResourceExpungeService;
|
||||
|
||||
@Autowired
|
||||
private IResourceTableDao myResourceTable;
|
||||
|
||||
@Autowired
|
||||
private DaoRegistry myDaoRegistry;
|
||||
@Autowired
|
||||
private HapiTransactionService myTransactionService;
|
||||
|
||||
@Override
|
||||
public long expungeAllEmpiLinksOfTargetType(String theResourceType) {
|
||||
throwExceptionIfInvalidTargetType(theResourceType);
|
||||
|
||||
List<Long> longs = myEmpiLinkDaoSvc.deleteAllEmpiLinksOfTypeAndReturnPersonPids(theResourceType);
|
||||
myResourceExpungeService.expungeCurrentVersionOfResources(null, longs, new AtomicInteger(longs.size()));
|
||||
return longs.size();
|
||||
|
@ -69,9 +87,43 @@ public class EmpiResetSvcImpl implements IEmpiResetSvc {
|
|||
List<Long> longs = myEmpiLinkDaoSvc.deleteAllEmpiLinksAndReturnPersonPids();
|
||||
longs = longs.stream()
|
||||
.distinct().collect(Collectors.toList());
|
||||
|
||||
DeleteConflictList dlc = new DeleteConflictList();
|
||||
List<Long> finalLongs = longs;
|
||||
myTransactionService.execute(null, tx -> {
|
||||
finalLongs.stream().forEach(pid -> {
|
||||
deleteCascade(pid, dlc);
|
||||
});
|
||||
return null;
|
||||
});
|
||||
|
||||
IFhirResourceDao personDao = myDaoRegistry.getResourceDao("Person");
|
||||
while (!dlc.isEmpty()) {
|
||||
myTransactionService.execute(null, tx -> {
|
||||
deleteConflictBatch(dlc, personDao);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
myResourceExpungeService.expungeHistoricalVersionsOfIds(null, longs, new AtomicInteger(longs.size()));
|
||||
myResourceExpungeService.expungeCurrentVersionOfResources(null, longs, new AtomicInteger(longs.size()));
|
||||
//myResourceExpungeService.expungeCurrentVersionOfResources(null, longs, new AtomicInteger(longs.size()));
|
||||
return longs.size();
|
||||
}
|
||||
|
||||
private void deleteConflictBatch(DeleteConflictList theDcl, IFhirResourceDao<IBaseResource> theDao) {
|
||||
DeleteConflictList newBatch = new DeleteConflictList();
|
||||
for (DeleteConflict next: theDcl) {
|
||||
IdDt nextSource = next.getSourceId();
|
||||
ourLog.info("Have delete conflict {} - Cascading delete", next);
|
||||
theDao.delete(nextSource.toVersionless(), newBatch, null, null);
|
||||
}
|
||||
theDcl.removeIf(x -> true);
|
||||
theDcl.addAll(newBatch);
|
||||
}
|
||||
|
||||
private void deleteCascade(Long pid, DeleteConflictList theDcl) {
|
||||
ourLog.debug("About to cascade delete: " + pid);
|
||||
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao("Person");
|
||||
resourceDao.delete(new IdType("Person/" + pid), theDcl, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,8 @@ abstract public class BaseEmpiR4Test extends BaseJpaR4Test {
|
|||
private static final ContactPoint TEST_TELECOM = new ContactPoint()
|
||||
.setSystem(ContactPoint.ContactPointSystem.PHONE)
|
||||
.setValue("555-555-5555");
|
||||
private static final String NAME_GIVEN_FRANK = "Frank";
|
||||
protected static final String FRANK_ID = "ID.FRANK.789";
|
||||
|
||||
@Autowired
|
||||
protected FhirContext myFhirContext;
|
||||
|
@ -244,6 +246,11 @@ abstract public class BaseEmpiR4Test extends BaseJpaR4Test {
|
|||
return buildPatientWithNameAndId(NAME_GIVEN_PAUL, PAUL_ID);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected Patient buildFrankPatient() {
|
||||
return buildPatientWithNameAndId(NAME_GIVEN_FRANK, FRANK_ID);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
protected Patient buildJaneWithBirthday(Date theToday) {
|
||||
return buildPatientWithNameIdAndBirthday(NAME_GIVEN_JANE, JANE_ID, theToday);
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
package ca.uhn.fhir.jpa.empi.provider;
|
||||
|
||||
import ca.uhn.fhir.jpa.entity.EmpiLink;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
|
@ -92,14 +94,46 @@ public class EmpiProviderClearLinkR4Test extends BaseLinkR4Test {
|
|||
|
||||
Person personFromTarget = getPersonFromTarget(patientAndUpdateLinks);
|
||||
Person personFromTarget2 = getPersonFromTarget(patientAndUpdateLinks1);
|
||||
Person.PersonLinkComponent plc = new Person.PersonLinkComponent();
|
||||
plc.setAssurance(Person.IdentityAssuranceLevel.LEVEL2);
|
||||
plc.setTarget(new Reference(personFromTarget2.getIdElement().toUnqualifiedVersionless()));
|
||||
personFromTarget.getLink().add(plc);
|
||||
myPersonDao.update(personFromTarget);
|
||||
linkPersons(personFromTarget, personFromTarget2);
|
||||
|
||||
//SUT
|
||||
myEmpiProviderR4.clearEmpiLinks(null);
|
||||
|
||||
assertNoPatientLinksExist();
|
||||
IBundleProvider search = myPersonDao.search(new SearchParameterMap().setLoadSynchronous(true));
|
||||
assertThat(search.size(), is(equalTo(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPersonsWithCircularReferenceCanBeCleared() {
|
||||
Patient patientAndUpdateLinks = createPatientAndUpdateLinks(buildPaulPatient());
|
||||
Patient patientAndUpdateLinks1 = createPatientAndUpdateLinks(buildJanePatient());
|
||||
Patient patientAndUpdateLinks2 = createPatientAndUpdateLinks(buildFrankPatient());
|
||||
|
||||
Person personFromTarget = getPersonFromTarget(patientAndUpdateLinks);
|
||||
Person personFromTarget1 = getPersonFromTarget(patientAndUpdateLinks1);
|
||||
Person personFromTarget2 = getPersonFromTarget(patientAndUpdateLinks2);
|
||||
|
||||
// A -> B -> C -> A linkages.
|
||||
linkPersons(personFromTarget, personFromTarget1);
|
||||
linkPersons(personFromTarget1, personFromTarget2);
|
||||
linkPersons(personFromTarget2, personFromTarget);
|
||||
|
||||
//SUT
|
||||
myEmpiProviderR4.clearEmpiLinks(null);
|
||||
|
||||
assertNoPatientLinksExist();
|
||||
IBundleProvider search = myPersonDao.search(new SearchParameterMap().setLoadSynchronous(true));
|
||||
assertThat(search.size(), is(equalTo(0)));
|
||||
|
||||
}
|
||||
|
||||
private void linkPersons(Person theSourcePerson, Person theTargetPerson) {
|
||||
Person.PersonLinkComponent plc1 = new Person.PersonLinkComponent();
|
||||
plc1.setAssurance(Person.IdentityAssuranceLevel.LEVEL2);
|
||||
plc1.setTarget(new Reference(theTargetPerson.getIdElement().toUnqualifiedVersionless()));
|
||||
theSourcePerson.getLink().add(plc1);
|
||||
myPersonDao.update(theSourcePerson);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue