Empi 62 resource history (#1894)

This commit is contained in:
Ken Stevens 2020-06-03 18:00:20 -04:00 committed by GitHub
parent d2f018919c
commit 9136231b3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 100 additions and 40 deletions

View File

@ -13,31 +13,35 @@ import javax.annotation.Nonnull;
import static org.junit.Assert.assertEquals;
public abstract class BaseLinkR4Test extends BaseProviderR4Test {
protected static final StringType NO_MATCH_RESULT = new StringType(EmpiMatchResultEnum.NO_MATCH.name());
protected static final StringType MATCH_RESULT = new StringType(EmpiMatchResultEnum.MATCH.name());
protected static final StringType POSSIBLE_MATCH_RESULT = new StringType(EmpiMatchResultEnum.POSSIBLE_MATCH.name());
protected static final StringType POSSIBLE_DUPLICATE_RESULT = new StringType(EmpiMatchResultEnum.POSSIBLE_DUPLICATE.name());
protected Patient myPatient;
protected Person myPerson;
protected EmpiLink myLink;
protected StringType myPatientId;
protected StringType myPersonId;
protected StringType myNoMatch;
protected StringType myPossibleMatch;
protected StringType myPossibleDuplicate;
protected StringType myVersionlessPersonId;
@Before
public void before() {
super.before();
myPatient = createPatientAndUpdateLinks(new Patient());
myPatientId = new StringType(myPatient.getIdElement().toUnqualifiedVersionless().getValue());
myPatientId = new StringType(myPatient.getIdElement().getValue());
myPerson = getPersonFromTarget(myPatient);
myPersonId = new StringType(myPerson.getIdElement().toUnqualifiedVersionless().getValue());
myLink = getLink();
assertEquals(EmpiLinkSourceEnum.AUTO, myLink.getLinkSource());
assertEquals(EmpiMatchResultEnum.MATCH, myLink.getMatchResult());
myPersonId = new StringType(myPerson.getIdElement().getValue());
myVersionlessPersonId = new StringType(myPerson.getIdElement().toVersionless().getValue());
myNoMatch = new StringType(EmpiMatchResultEnum.NO_MATCH.name());
myPossibleMatch = new StringType(EmpiMatchResultEnum.POSSIBLE_MATCH.name());
myPossibleDuplicate = new StringType(EmpiMatchResultEnum.POSSIBLE_DUPLICATE.name());
myLink = getLink();
// Tests require our initial link to be a POSSIBLE_MATCH
myLink.setMatchResult(EmpiMatchResultEnum.POSSIBLE_MATCH);
myEmpiLinkDao.save(myLink);
assertEquals(EmpiLinkSourceEnum.AUTO, myLink.getLinkSource());
}
@Nonnull

View File

@ -27,9 +27,9 @@ public class EmpiProviderMergePersonsR4Test extends BaseProviderR4Test {
super.loadEmpiSearchParameters();
myFromPerson = createPerson();
myFromPersonId = new StringType(myFromPerson.getIdElement().toUnqualifiedVersionless().getValue());
myFromPersonId = new StringType(myFromPerson.getIdElement().getValue());
myToPerson = createPerson();
myToPersonId = new StringType(myToPerson.getIdElement().toUnqualifiedVersionless().getValue());
myToPersonId = new StringType(myToPerson.getIdElement().getValue());
}
@Test
@ -55,8 +55,8 @@ public class EmpiProviderMergePersonsR4Test extends BaseProviderR4Test {
@Test
public void testUnmanagedMerge() {
StringType fromPersonId = new StringType(createUnmanagedPerson().getIdElement().toVersionless().getValue());
StringType toPersonId = new StringType(createUnmanagedPerson().getIdElement().toVersionless().getValue());
StringType fromPersonId = new StringType(createUnmanagedPerson().getIdElement().getValue());
StringType toPersonId = new StringType(createUnmanagedPerson().getIdElement().getValue());
try {
myEmpiProviderR4.mergePersons(fromPersonId, toPersonId, myRequestDetails);
fail();
@ -68,8 +68,8 @@ public class EmpiProviderMergePersonsR4Test extends BaseProviderR4Test {
@Test
public void testMergePatients() {
try {
StringType patientId = new StringType(createPatient().getIdElement().toVersionless().getValue());
StringType otherPatientId = new StringType(createPatient().getIdElement().toVersionless().getValue());
StringType patientId = new StringType(createPatient().getIdElement().getValue());
StringType otherPatientId = new StringType(createPatient().getIdElement().getValue());
myEmpiProviderR4.mergePersons(patientId, otherPatientId, myRequestDetails);
fail();
} catch (InvalidRequestException e) {

View File

@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.empi.provider;
import ca.uhn.fhir.empi.api.EmpiLinkSourceEnum;
import ca.uhn.fhir.empi.api.EmpiMatchResultEnum;
import ca.uhn.fhir.jpa.entity.EmpiLink;
import ca.uhn.fhir.model.primitive.IdDt;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.Patient;
@ -52,7 +53,7 @@ private static final Logger ourLog = LoggerFactory.getLogger(EmpiProviderQueryLi
List<Parameters.ParametersParameterComponent> list = result.getParameter();
assertThat(list, hasSize(1));
List<Parameters.ParametersParameterComponent> part = list.get(0).getPart();
assertEmpiLink(4, part, myPersonId.getValue(), myPatientId.getValue(), EmpiMatchResultEnum.MATCH);
assertEmpiLink(4, part, myPersonId.getValue(), myPatientId.getValue(), EmpiMatchResultEnum.POSSIBLE_MATCH);
}
@Test
@ -81,13 +82,12 @@ private static final Logger ourLog = LoggerFactory.getLogger(EmpiProviderQueryLi
assertEmpiLink(2, part, myPerson1Id.getValue(), myPerson2Id.getValue(), EmpiMatchResultEnum.POSSIBLE_DUPLICATE);
}
private void assertEmpiLink(int theExpectedSize, List<Parameters.ParametersParameterComponent> thePart, String thePersonId, String theTargetId, EmpiMatchResultEnum theMatchResult) {
assertThat(thePart, hasSize(theExpectedSize));
assertThat(thePart.get(0).getName(), is("personId"));
assertThat(thePart.get(0).getValue().toString(), is(thePersonId));
assertThat(thePart.get(0).getValue().toString(), is(removeVersion(thePersonId)));
assertThat(thePart.get(1).getName(), is("targetId"));
assertThat(thePart.get(1).getValue().toString(), is(theTargetId));
assertThat(thePart.get(1).getValue().toString(), is(removeVersion(theTargetId)));
if (theExpectedSize > 2) {
assertThat(thePart.get(2).getName(), is("matchResult"));
assertThat(thePart.get(2).getValue().toString(), is(theMatchResult.name()));
@ -95,4 +95,8 @@ private static final Logger ourLog = LoggerFactory.getLogger(EmpiProviderQueryLi
assertThat(thePart.get(3).getValue().toString(), is("AUTO"));
}
}
private String removeVersion(String theId) {
return new IdDt(theId).toVersionless().getValue();
}
}

View File

@ -4,6 +4,7 @@ import ca.uhn.fhir.empi.api.EmpiConstants;
import ca.uhn.fhir.empi.api.EmpiLinkSourceEnum;
import ca.uhn.fhir.empi.api.EmpiMatchResultEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Person;
import org.hl7.fhir.r4.model.StringType;
@ -11,6 +12,8 @@ import org.junit.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.matchesPattern;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
@ -19,17 +22,46 @@ public class EmpiProviderUpdateLinkR4Test extends BaseLinkR4Test {
@Test
public void testUpdateLinkHappyPath() {
myEmpiProviderR4.updateLink(myPersonId, myPatientId, myNoMatch, myRequestDetails);
myEmpiProviderR4.updateLink(myPersonId, myPatientId, NO_MATCH_RESULT, myRequestDetails);
myLink = getLink();
assertEquals(EmpiLinkSourceEnum.MANUAL, myLink.getLinkSource());
assertEquals(EmpiMatchResultEnum.NO_MATCH, myLink.getMatchResult());
}
@Test
public void testUpdateLinkTwiceFailsDueToWrongVersion() {
myEmpiProviderR4.updateLink(myPersonId, myPatientId, MATCH_RESULT, myRequestDetails);
try {
myEmpiProviderR4.updateLink(myPersonId, myPatientId, NO_MATCH_RESULT, myRequestDetails);
fail();
} catch (ResourceVersionConflictException e) {
assertThat(e.getMessage(), matchesPattern("Requested resource Person/\\d+/_history/1 is not the latest version. Latest version is Person/\\d+/_history/2"));
}
}
@Test
public void testUpdateLinkTwiceWorksWhenNoVersionProvided() {
myEmpiProviderR4.updateLink(myPersonId, myPatientId, MATCH_RESULT, myRequestDetails);
Person person = myEmpiProviderR4.updateLink(myVersionlessPersonId, myPatientId, NO_MATCH_RESULT, myRequestDetails);
assertThat(person.getLink(), hasSize(0));
}
@Test
public void testUnlinkLink() {
myEmpiProviderR4.updateLink(myPersonId, myPatientId, NO_MATCH_RESULT, myRequestDetails);
try {
myEmpiProviderR4.updateLink(myPersonId, myPatientId, MATCH_RESULT, myRequestDetails);
fail();
} catch (ResourceVersionConflictException e) {
assertThat(e.getMessage(), matchesPattern("Requested resource Person/\\d+/_history/1 is not the latest version. Latest version is Person/\\d+/_history/2"));
}
}
@Test
public void testUpdateIllegalResultPM() {
try {
myEmpiProviderR4.updateLink(myPersonId, myPatientId, myPossibleMatch, myRequestDetails);
myEmpiProviderR4.updateLink(myPersonId, myPatientId, POSSIBLE_MATCH_RESULT, myRequestDetails);
fail();
} catch (InvalidRequestException e) {
assertEquals("$empi-update-link illegal matchResult value 'POSSIBLE_MATCH'. Must be NO_MATCH or MATCH", e.getMessage());
@ -39,7 +71,7 @@ public class EmpiProviderUpdateLinkR4Test extends BaseLinkR4Test {
@Test
public void testUpdateIllegalResultPD() {
try {
myEmpiProviderR4.updateLink(myPersonId, myPatientId, myPossibleDuplicate, myRequestDetails);
myEmpiProviderR4.updateLink(myPersonId, myPatientId, POSSIBLE_DUPLICATE_RESULT, myRequestDetails);
fail();
} catch (InvalidRequestException e) {
assertEquals("$empi-update-link illegal matchResult value 'POSSIBLE_DUPLICATE'. Must be NO_MATCH or MATCH", e.getMessage());
@ -49,7 +81,7 @@ public class EmpiProviderUpdateLinkR4Test extends BaseLinkR4Test {
@Test
public void testUpdateIllegalFirstArg() {
try {
myEmpiProviderR4.updateLink(myPatientId, myPatientId, myNoMatch, myRequestDetails);
myEmpiProviderR4.updateLink(myPatientId, myPatientId, NO_MATCH_RESULT, myRequestDetails);
fail();
} catch (InvalidRequestException e) {
assertEquals("personId must have form Person/<id> where <id> is the id of the person", e.getMessage());
@ -59,7 +91,7 @@ public class EmpiProviderUpdateLinkR4Test extends BaseLinkR4Test {
@Test
public void testUpdateIllegalSecondArg() {
try {
myEmpiProviderR4.updateLink(myPersonId, myPersonId, myNoMatch, myRequestDetails);
myEmpiProviderR4.updateLink(myPersonId, myPersonId, NO_MATCH_RESULT, myRequestDetails);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), endsWith("must have form Patient/<id> or Practitioner/<id> where <id> is the id of the resource"));
@ -70,7 +102,7 @@ public class EmpiProviderUpdateLinkR4Test extends BaseLinkR4Test {
public void testUpdateStrangePerson() {
Person person = createUnmanagedPerson();
try {
myEmpiProviderR4.updateLink(new StringType(person.getIdElement().toVersionless().getValue()), myPatientId, myNoMatch, myRequestDetails);
myEmpiProviderR4.updateLink(new StringType(person.getIdElement().getValue()), myPatientId, NO_MATCH_RESULT, myRequestDetails);
fail();
} catch (InvalidRequestException e) {
assertEquals("Only EMPI Managed Person resources may be updated via this operation. The Person resource provided is not tagged as managed by hapi-empi", e.getMessage());
@ -83,7 +115,7 @@ public class EmpiProviderUpdateLinkR4Test extends BaseLinkR4Test {
patient.getMeta().addTag().setSystem(EmpiConstants.SYSTEM_EMPI_MANAGED).setCode(EmpiConstants.CODE_NO_EMPI_MANAGED);
createPatient(patient);
try {
myEmpiProviderR4.updateLink(myPersonId, new StringType(patient.getIdElement().toVersionless().getValue()), myNoMatch, myRequestDetails);
myEmpiProviderR4.updateLink(myPersonId, new StringType(patient.getIdElement().getValue()), NO_MATCH_RESULT, myRequestDetails);
fail();
} catch (InvalidRequestException e) {
assertEquals("The target is marked with the " + EmpiConstants.CODE_NO_EMPI_MANAGED + " tag which means it may not be EMPI linked.", e.getMessage());

View File

@ -30,6 +30,7 @@ import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.TransactionLogMessages;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
import ca.uhn.fhir.validation.IResourceLoader;
import org.hl7.fhir.instance.model.api.IAnyResource;
@ -47,9 +48,9 @@ public abstract class BaseEmpiProvider {
myResourceLoader = theResourceLoader;
}
protected IAnyResource getPersonFromIdOrThrowException(String theParamName, String theId) {
protected IAnyResource getLatestPersonFromIdOrThrowException(String theParamName, String theId) {
IdDt personId = getPersonIdDtOrThrowException(theParamName, theId);
return loadResource(personId);
return loadResource(personId.toUnqualifiedVersionless());
}
private IdDt getPersonIdDtOrThrowException(String theParamName, String theId) {
@ -61,9 +62,9 @@ public abstract class BaseEmpiProvider {
return personId;
}
protected IAnyResource getTargetFromIdOrThrowException(String theParamName, String theId) {
protected IAnyResource getLatestTargetFromIdOrThrowException(String theParamName, String theId) {
IIdType targetId = getTargetIdDtOrThrowException(theParamName, theId);
return loadResource(targetId);
return loadResource(targetId.toUnqualifiedVersionless());
}
protected IIdType getTargetIdDtOrThrowException(String theParamName, String theId) {
@ -168,4 +169,15 @@ public abstract class BaseEmpiProvider {
return getTargetIdDtOrThrowException(theName, targetId);
}
protected void validateSameVersion(IAnyResource theResource, IPrimitiveType<String> theResourceId) {
String storedId = theResource.getIdElement().getValue();
String requestedId = theResourceId.getValue();
if (hasVersionIdPart(requestedId) && !storedId.equals(requestedId)) {
throw new ResourceVersionConflictException("Requested resource " + requestedId + " is not the latest version. Latest version is " + storedId);
}
}
private boolean hasVersionIdPart(String theId) {
return new IdDt(theId).hasVersionIdPart();
}
}

View File

@ -91,9 +91,11 @@ public class EmpiProviderDstu3 extends BaseEmpiProvider {
@OperationParam(name=ProviderConstants.EMPI_MERGE_PERSONS_TO_PERSON_ID, min = 1, max = 1) StringType theToPersonId,
RequestDetails theRequestDetails) {
validateMergeParameters(theFromPersonId, theToPersonId);
IAnyResource fromPerson = getPersonFromIdOrThrowException(ProviderConstants.EMPI_MERGE_PERSONS_FROM_PERSON_ID, theFromPersonId.getValue());
IAnyResource toPerson = getPersonFromIdOrThrowException(ProviderConstants.EMPI_MERGE_PERSONS_TO_PERSON_ID, theToPersonId.getValue());
IAnyResource fromPerson = getLatestPersonFromIdOrThrowException(ProviderConstants.EMPI_MERGE_PERSONS_FROM_PERSON_ID, theFromPersonId.getValue());
IAnyResource toPerson = getLatestPersonFromIdOrThrowException(ProviderConstants.EMPI_MERGE_PERSONS_TO_PERSON_ID, theToPersonId.getValue());
validateMergeResources(fromPerson, toPerson);
validateSameVersion(fromPerson, theFromPersonId);
validateSameVersion(toPerson, theToPersonId);
return (Person) myPersonMergerSvc.mergePersons(fromPerson, toPerson, createEmpiContext(theRequestDetails));
}
@ -106,8 +108,10 @@ public class EmpiProviderDstu3 extends BaseEmpiProvider {
validateUpdateLinkParameters(thePersonId, theTargetId, theMatchResult);
EmpiMatchResultEnum matchResult = extractMatchResultOrNull(theMatchResult);
IAnyResource person = getPersonFromIdOrThrowException(ProviderConstants.EMPI_UPDATE_LINK_PERSON_ID, thePersonId.getValue());
IAnyResource target = getTargetFromIdOrThrowException(ProviderConstants.EMPI_UPDATE_LINK_TARGET_ID, theTargetId.getValue());
IAnyResource person = getLatestPersonFromIdOrThrowException(ProviderConstants.EMPI_UPDATE_LINK_PERSON_ID, thePersonId.getValue());
IAnyResource target = getLatestTargetFromIdOrThrowException(ProviderConstants.EMPI_UPDATE_LINK_TARGET_ID, theTargetId.getValue());
validateSameVersion(person, thePersonId);
validateSameVersion(target, theTargetId);
return (Person) myEmpiLinkUpdaterSvc.updateLink(person, target, matchResult, createEmpiContext(theRequestDetails));
}

View File

@ -92,9 +92,11 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
@OperationParam(name=ProviderConstants.EMPI_MERGE_PERSONS_TO_PERSON_ID, min = 1, max = 1) StringType theToPersonId,
RequestDetails theRequestDetails) {
validateMergeParameters(theFromPersonId, theToPersonId);
IAnyResource fromPerson = getPersonFromIdOrThrowException(ProviderConstants.EMPI_MERGE_PERSONS_FROM_PERSON_ID, theFromPersonId.getValue());
IAnyResource toPerson = getPersonFromIdOrThrowException(ProviderConstants.EMPI_MERGE_PERSONS_TO_PERSON_ID, theToPersonId.getValue());
IAnyResource fromPerson = getLatestPersonFromIdOrThrowException(ProviderConstants.EMPI_MERGE_PERSONS_FROM_PERSON_ID, theFromPersonId.getValue());
IAnyResource toPerson = getLatestPersonFromIdOrThrowException(ProviderConstants.EMPI_MERGE_PERSONS_TO_PERSON_ID, theToPersonId.getValue());
validateMergeResources(fromPerson, toPerson);
validateSameVersion(fromPerson, theFromPersonId);
validateSameVersion(toPerson, theToPersonId);
return (Person) myPersonMergerSvc.mergePersons(fromPerson, toPerson, createEmpiContext(theRequestDetails));
}
@ -107,8 +109,10 @@ public class EmpiProviderR4 extends BaseEmpiProvider {
validateUpdateLinkParameters(thePersonId, theTargetId, theMatchResult);
EmpiMatchResultEnum matchResult = extractMatchResultOrNull(theMatchResult);
IAnyResource person = getPersonFromIdOrThrowException(ProviderConstants.EMPI_UPDATE_LINK_PERSON_ID, thePersonId.getValue());
IAnyResource target = getTargetFromIdOrThrowException(ProviderConstants.EMPI_UPDATE_LINK_TARGET_ID, theTargetId.getValue());
IAnyResource person = getLatestPersonFromIdOrThrowException(ProviderConstants.EMPI_UPDATE_LINK_PERSON_ID, thePersonId.getValue());
IAnyResource target = getLatestTargetFromIdOrThrowException(ProviderConstants.EMPI_UPDATE_LINK_TARGET_ID, theTargetId.getValue());
validateSameVersion(person, thePersonId);
validateSameVersion(target, theTargetId);
return (Person) myEmpiLinkUpdaterSvc.updateLink(person, target, matchResult, createEmpiContext(theRequestDetails));
}