[3040] finish implementation (#3049)

* [3040] finish implementation

* Update hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_mdm/mdm_operations.md

Co-authored-by: Tadgh <tadgh@cs.toronto.edu>

* Update hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_mdm/mdm_operations.md

Co-authored-by: Tadgh <tadgh@cs.toronto.edu>

* Update hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_mdm/mdm_operations.md

Co-authored-by: Tadgh <tadgh@cs.toronto.edu>

* [3040] throw exception if link exists

* [3040] add matchResult parameter/update documentation

Co-authored-by: Tadgh <tadgh@cs.toronto.edu>
This commit is contained in:
katiesmilecdr 2021-10-07 13:42:21 -04:00 committed by GitHub
parent a474e88ed4
commit 3c80dba90e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 436 additions and 0 deletions

View File

@ -0,0 +1,5 @@
---
type: add
issue: 3020
jira: SMILE-3192
title: "Added `$mdm-create-link` operation and documentation."

View File

@ -396,6 +396,78 @@ Any supported MDM type can be used. The following request body shows how to upda
The operation returns the updated Golden Resource. For the query above `Patient` resource will be returned. Note that this is the only way to modify MDM-managed Golden Resources. The operation returns the updated Golden Resource. For the query above `Patient` resource will be returned. Note that this is the only way to modify MDM-managed Golden Resources.
## Create Link
Use the `$mdm-create-link` operation to create an MDM link from a Golden Resource to a Target Resource without the need for any pre-existing matching data within the two resources. This operation takes the following parameters:
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Cardinality</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td>goldenResourceId</td>
<td>String</td>
<td>1..1</td>
<td>
The id of the Golden Resource.
</td>
</tr>
<tr>
<td>resourceId</td>
<td>String</td>
<td>1..1</td>
<td>
The id of the target resource.
</td>
</tr>
<tr>
<td>matchResult</td>
<td>String</td>
<td>0..1</td>
<td>
Optional matchResult. If omitted, it automatically set the default to MATCH, otherwise the value should be
MATCH, POSSIBLE_MATCH or NO_MATCH.
</td>
</tr>
</tbody>
</table>
MDM links created in this way will automatically have their `linkSource` set to `MANUAL`.
### Example
Use an HTTP POST to the following URL to invoke this operation:
```url
http://example.com/$mdm-create-link
```
Any supported MDM type can be used. The following request body shows how to update link on the Patient resource type:
```json
{
"resourceType": "Parameters",
"parameter": [ {
"name": "goldenResourceId",
"valueString": "Patient/123"
}, {
"name": "resourceId",
"valueString": "Patient/456"
}, {
"name": "matchResult",
"valueString": "MATCH"
} ]
}
```
The operation returns the Golden Resource. For the query above, `Patient` will be returned.
## Merge Golden Resources ## Merge Golden Resources
The `$mdm-merge-golden-resources` operation can be used to merge one Golden Resource with another. When doing this, you will need to decide which resource to merge from and which one to merge to. The `$mdm-merge-golden-resources` operation can be used to merge one Golden Resource with another. When doing this, you will need to decide which resource to merge from and which one to merge to.

View File

@ -35,6 +35,7 @@ import ca.uhn.fhir.jpa.mdm.svc.GoldenResourceMergerSvcImpl;
import ca.uhn.fhir.jpa.mdm.svc.IMdmModelConverterSvc; import ca.uhn.fhir.jpa.mdm.svc.IMdmModelConverterSvc;
import ca.uhn.fhir.jpa.mdm.svc.MdmControllerSvcImpl; import ca.uhn.fhir.jpa.mdm.svc.MdmControllerSvcImpl;
import ca.uhn.fhir.jpa.mdm.svc.MdmEidUpdateService; import ca.uhn.fhir.jpa.mdm.svc.MdmEidUpdateService;
import ca.uhn.fhir.jpa.mdm.svc.MdmLinkCreateSvcImpl;
import ca.uhn.fhir.jpa.mdm.svc.MdmLinkQuerySvcImplSvc; import ca.uhn.fhir.jpa.mdm.svc.MdmLinkQuerySvcImplSvc;
import ca.uhn.fhir.jpa.mdm.svc.MdmLinkSvcImpl; import ca.uhn.fhir.jpa.mdm.svc.MdmLinkSvcImpl;
import ca.uhn.fhir.jpa.mdm.svc.MdmLinkUpdaterSvcImpl; import ca.uhn.fhir.jpa.mdm.svc.MdmLinkUpdaterSvcImpl;
@ -55,6 +56,7 @@ import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmGoldenResourceFindingSvc;
import ca.uhn.fhir.mdm.api.IGoldenResourceMergerSvc; import ca.uhn.fhir.mdm.api.IGoldenResourceMergerSvc;
import ca.uhn.fhir.mdm.api.IMdmBatchJobSubmitterFactory; import ca.uhn.fhir.mdm.api.IMdmBatchJobSubmitterFactory;
import ca.uhn.fhir.mdm.api.IMdmControllerSvc; import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
import ca.uhn.fhir.mdm.api.IMdmLinkCreateSvc;
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc; import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc; import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc; import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
@ -233,6 +235,12 @@ public class MdmConsumerConfig {
return new MdmLinkUpdaterSvcImpl(); return new MdmLinkUpdaterSvcImpl();
} }
@Bean
IMdmLinkCreateSvc mdmLinkCreateSvc() {
return new MdmLinkCreateSvcImpl();
}
@Bean @Bean
MdmLoader mdmLoader() { MdmLoader mdmLoader() {
return new MdmLoader(); return new MdmLoader();

View File

@ -24,6 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.mdm.api.IGoldenResourceMergerSvc; import ca.uhn.fhir.mdm.api.IGoldenResourceMergerSvc;
import ca.uhn.fhir.mdm.api.IMdmBatchJobSubmitterFactory; import ca.uhn.fhir.mdm.api.IMdmBatchJobSubmitterFactory;
import ca.uhn.fhir.mdm.api.IMdmControllerSvc; import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
import ca.uhn.fhir.mdm.api.IMdmLinkCreateSvc;
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc; import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc; import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
import ca.uhn.fhir.mdm.api.MdmLinkJson; import ca.uhn.fhir.mdm.api.MdmLinkJson;
@ -65,6 +66,8 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
@Autowired @Autowired
IMdmLinkUpdaterSvc myIMdmLinkUpdaterSvc; IMdmLinkUpdaterSvc myIMdmLinkUpdaterSvc;
@Autowired @Autowired
IMdmLinkCreateSvc myIMdmLinkCreateSvc;
@Autowired
IMdmBatchJobSubmitterFactory myMdmBatchJobSubmitterFactory; IMdmBatchJobSubmitterFactory myMdmBatchJobSubmitterFactory;
public MdmControllerSvcImpl() { public MdmControllerSvcImpl() {
@ -106,6 +109,17 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
return myIMdmLinkUpdaterSvc.updateLink(goldenResource, source, matchResult, theMdmTransactionContext); return myIMdmLinkUpdaterSvc.updateLink(goldenResource, source, matchResult, theMdmTransactionContext);
} }
@Override
public IAnyResource createLink(String theGoldenResourceId, String theSourceResourceId, @Nullable String theMatchResult, MdmTransactionContext theMdmTransactionContext) {
MdmMatchResultEnum matchResult = MdmControllerUtil.extractMatchResultOrNull(theMatchResult);
IAnyResource goldenResource = myMdmControllerHelper.getLatestGoldenResourceFromIdOrThrowException(ProviderConstants.MDM_CREATE_LINK_GOLDEN_RESOURCE_ID, theGoldenResourceId);
IAnyResource source = myMdmControllerHelper.getLatestSourceFromIdOrThrowException(ProviderConstants.MDM_CREATE_LINK_RESOURCE_ID, theSourceResourceId);
myMdmControllerHelper.validateSameVersion(goldenResource, theGoldenResourceId);
myMdmControllerHelper.validateSameVersion(source, theSourceResourceId);
return myIMdmLinkCreateSvc.createLink(goldenResource, source, matchResult, theMdmTransactionContext);
}
@Override @Override
public IBaseParameters submitMdmClearJob(List<String> theUrls, IPrimitiveType<BigDecimal> theBatchSize, ServletRequestDetails theRequestDetails) { public IBaseParameters submitMdmClearJob(List<String> theUrls, IPrimitiveType<BigDecimal> theBatchSize, ServletRequestDetails theRequestDetails) {
MultiUrlProcessor multiUrlProcessor = new MultiUrlProcessor(myFhirContext, myMdmBatchJobSubmitterFactory.getClearJobSubmitter()); MultiUrlProcessor multiUrlProcessor = new MultiUrlProcessor(myFhirContext, myMdmBatchJobSubmitterFactory.getClearJobSubmitter());

View File

@ -0,0 +1,96 @@
package ca.uhn.fhir.jpa.mdm.svc;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLinkCreateSvc;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.mdm.util.MessageHelper;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
public class MdmLinkCreateSvcImpl implements IMdmLinkCreateSvc {
private static final Logger ourLog = Logs.getMdmTroubleshootingLog();
@Autowired
FhirContext myFhirContext;
@Autowired
IdHelperService myIdHelperService;
@Autowired
MdmLinkDaoSvc myMdmLinkDaoSvc;
@Autowired
IMdmSettings myMdmSettings;
@Autowired
MessageHelper myMessageHelper;
@Transactional
@Override
public IAnyResource createLink(IAnyResource theGoldenResource, IAnyResource theSourceResource, MdmMatchResultEnum theMatchResult, MdmTransactionContext theMdmContext) {
String sourceType = myFhirContext.getResourceType(theSourceResource);
validateCreateLinkRequest(theGoldenResource, theSourceResource, sourceType);
Long goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
Long targetId = myIdHelperService.getPidOrThrowException(theSourceResource);
Optional<MdmLink> optionalMdmLink = myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
if (optionalMdmLink.isPresent()) {
throw new InvalidRequestException(myMessageHelper.getMessageForPresentLink(theGoldenResource, theSourceResource));
}
List<MdmLink> mdmLinks = myMdmLinkDaoSvc.getMdmLinksBySourcePidAndMatchResult(targetId, MdmMatchResultEnum.MATCH);
if (mdmLinks.size() > 0 && theMatchResult == MdmMatchResultEnum.MATCH) {
throw new InvalidRequestException(myMessageHelper.getMessageForMultipleGoldenRecords(theSourceResource));
}
MdmLink mdmLink = myMdmLinkDaoSvc.getOrCreateMdmLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
mdmLink.setLinkSource(MdmLinkSourceEnum.MANUAL);
if (theMatchResult == null) {
mdmLink.setMatchResult(MdmMatchResultEnum.MATCH);
} else {
mdmLink.setMatchResult(theMatchResult);
}
ourLog.info("Manually creating a " + theGoldenResource.getIdElement().toVersionless() + " to " + theSourceResource.getIdElement().toVersionless() + " mdm link.");
myMdmLinkDaoSvc.save(mdmLink);
return theGoldenResource;
}
private void validateCreateLinkRequest(IAnyResource theGoldenRecord, IAnyResource theSourceResource, String theSourceType) {
String goldenRecordType = myFhirContext.getResourceType(theGoldenRecord);
if (!myMdmSettings.isSupportedMdmType(goldenRecordType)) {
throw new InvalidRequestException(myMessageHelper.getMessageForUnsupportedFirstArgumentTypeInUpdate(goldenRecordType));
}
if (!myMdmSettings.isSupportedMdmType(theSourceType)) {
throw new InvalidRequestException(myMessageHelper.getMessageForUnsupportedSecondArgumentTypeInUpdate(theSourceType));
}
if (!Objects.equals(goldenRecordType, theSourceType)) {
throw new InvalidRequestException(myMessageHelper.getMessageForArgumentTypeMismatchInUpdate(goldenRecordType, theSourceType));
}
if (!MdmResourceUtil.isMdmManaged(theGoldenRecord)) {
throw new InvalidRequestException(myMessageHelper.getMessageForUnmanagedResource());
}
if (!MdmResourceUtil.isMdmAllowed(theSourceResource)) {
throw new InvalidRequestException(myMessageHelper.getMessageForUnsupportedSourceResource());
}
}
}

View File

@ -0,0 +1,175 @@
package ca.uhn.fhir.jpa.mdm.provider;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.mdm.api.MdmConstants;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.util.MessageHelper;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.StringType;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.fail;
public class MdmProviderCreateLinkR4Test extends BaseLinkR4Test {
@Autowired
private MessageHelper myMessageHelper;
@Test
public void testCreateLinkWithMatchResult() {
assertLinkCount(1);
Patient patient = createPatient(buildPatientWithNameAndId("PatientGiven", "ID.PatientGiven.123"), true, false);
StringType patientId = new StringType(patient.getIdElement().getValue());
Patient sourcePatient = createPatient(buildPatientWithNameAndId("SourcePatientGiven", "ID.SourcePatientGiven.123"), true, false);
StringType sourcePatientId = new StringType(sourcePatient.getIdElement().getValue());
myMdmProvider.createLink(sourcePatientId, patientId, MATCH_RESULT, myRequestDetails);
assertLinkCount(2);
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
assertEquals(MdmMatchResultEnum.MATCH, links.get(0).getMatchResult());
}
@Test
public void testCreateLinkWithNullMatchResult() {
assertLinkCount(1);
Patient patient = createPatient(buildPatientWithNameAndId("PatientGiven", "ID.PatientGiven.123"), true, false);
StringType patientId = new StringType(patient.getIdElement().getValue());
Patient sourcePatient = createPatient(buildPatientWithNameAndId("SourcePatientGiven", "ID.SourcePatientGiven.123"), true, false);
StringType sourcePatientId = new StringType(sourcePatient.getIdElement().getValue());
myMdmProvider.createLink(sourcePatientId, patientId, null, myRequestDetails);
assertLinkCount(2);
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
assertEquals(MdmMatchResultEnum.MATCH, links.get(0).getMatchResult());
}
@Test
public void testCreateLinkTwiceWithDifferentGoldenResourceAndMatchResult() {
assertLinkCount(1);
Patient patient = createPatient(buildPatientWithNameAndId("PatientGiven", "ID.PatientGiven.123"), true, false);
StringType patientId = new StringType(patient.getIdElement().getValue());
Patient sourcePatient = createPatient(buildPatientWithNameAndId("SourcePatientGiven", "ID.SourcePatientGiven.123"), true, false);
StringType sourcePatientId = new StringType(sourcePatient.getIdElement().getValue());
myMdmProvider.createLink(sourcePatientId, patientId, MATCH_RESULT, myRequestDetails);
Patient sourcePatient2 = createPatient(buildPatientWithNameAndId("SourcePatientGiven2", "ID.SourcePatientGiven.123.2"), true, false);
StringType sourcePatientId2 = new StringType(sourcePatient2.getIdElement().getValue());
try {
myMdmProvider.createLink(sourcePatientId2, patientId, MATCH_RESULT, myRequestDetails);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), endsWith("Use $mdm-query-links to see more details."));
}
}
@Test
public void testCreateLinkTwiceWithDifferentGoldenResourceAndNoMatchResult() {
assertLinkCount(1);
Patient patient = createPatient(buildPatientWithNameAndId("PatientGiven", "ID.PatientGiven.123"), true, false);
StringType patientId = new StringType(patient.getIdElement().getValue());
Patient sourcePatient = createPatient(buildPatientWithNameAndId("SourcePatientGiven", "ID.SourcePatientGiven.123"), true, false);
StringType sourcePatientId = new StringType(sourcePatient.getIdElement().getValue());
myMdmProvider.createLink(sourcePatientId, patientId, MATCH_RESULT, myRequestDetails);
Patient sourcePatient2 = createPatient(buildPatientWithNameAndId("SourcePatientGiven2", "ID.SourcePatientGiven.123.2"), true, false);
StringType sourcePatientId2 = new StringType(sourcePatient2.getIdElement().getValue());
myMdmProvider.createLink(sourcePatientId2, patientId, NO_MATCH_RESULT, myRequestDetails);
assertLinkCount(3);
List<MdmLink> links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
assertEquals(MdmLinkSourceEnum.MANUAL, links.get(1).getLinkSource());
assertEquals(MdmMatchResultEnum.NO_MATCH, links.get(1).getMatchResult());
}
@Test
public void testCreateExistentLink() {
assertLinkCount(1);
try {
myMdmProvider.createLink(mySourcePatientId, myPatientId, MATCH_RESULT,myRequestDetails);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), startsWith("Link already exists"));
}
assertLinkCount(1);
}
@Test
public void testCreateIllegalResultPD() {
try {
myMdmProvider.createLink(mySourcePatientId, myPatientId, POSSIBLE_DUPLICATE_RESULT, myRequestDetails);
fail();
} catch (InvalidRequestException e) {
assertEquals("$mdm-create-link illegal matchResult value 'POSSIBLE_DUPLICATE'. Must be NO_MATCH, MATCH or POSSIBLE_MATCH", e.getMessage());
}
}
@Test
public void testCreateIllegalFirstArg() {
try {
myMdmProvider.createLink(new StringType(""), myPatientId, MATCH_RESULT, myRequestDetails);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), endsWith(" must have form <resourceType>/<id> where <id> is the id of the resource"));
}
}
@Test
public void testCreateIllegalSecondArg() {
try {
myMdmProvider.createLink(myPatientId, new StringType(""), MATCH_RESULT, myRequestDetails);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), endsWith(" must have form <resourceType>/<id> where <id> is the id of the resource and <resourceType> is the type of the resource"));
}
}
@Test
public void testCreateStrangePatient() {
Patient patient = createPatient();
try {
myMdmProvider.createLink(new StringType(patient.getIdElement().getValue()), myPatientId, MATCH_RESULT, myRequestDetails);
fail();
} catch (InvalidRequestException e) {
String expectedMessage = myMessageHelper.getMessageForUnmanagedResource();
assertEquals(expectedMessage, e.getMessage());
}
}
@Test
public void testExcludedGoldenResource() {
Patient patient = new Patient();
patient.getMeta().addTag().setSystem(MdmConstants.SYSTEM_MDM_MANAGED).setCode(MdmConstants.CODE_NO_MDM_MANAGED);
createPatient(patient);
try {
myMdmProvider.createLink(mySourcePatientId, new StringType(patient.getIdElement().getValue()), MATCH_RESULT, myRequestDetails);
fail();
} catch (InvalidRequestException e) {
assertEquals(myMessageHelper.getMessageForUnsupportedSourceResource(), e.getMessage());
}
}
}

View File

@ -44,5 +44,7 @@ public interface IMdmControllerSvc {
IAnyResource updateLink(String theGoldenResourceId, String theSourceResourceId, String theMatchResult, MdmTransactionContext theMdmTransactionContext); IAnyResource updateLink(String theGoldenResourceId, String theSourceResourceId, String theMatchResult, MdmTransactionContext theMdmTransactionContext);
IAnyResource createLink(String theGoldenResourceId, String theSourceResourceId, @Nullable String theMatchResult, MdmTransactionContext theMdmTransactionContext);
IBaseParameters submitMdmClearJob(List<String> theUrls, IPrimitiveType<BigDecimal> theBatchSize, ServletRequestDetails theRequestDetails); IBaseParameters submitMdmClearJob(List<String> theUrls, IPrimitiveType<BigDecimal> theBatchSize, ServletRequestDetails theRequestDetails);
} }

View File

@ -0,0 +1,10 @@
package ca.uhn.fhir.mdm.api;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import org.hl7.fhir.instance.model.api.IAnyResource;
import javax.annotation.Nullable;
public interface IMdmLinkCreateSvc {
IAnyResource createLink(IAnyResource theGoldenResource, IAnyResource theSourceResource, MdmMatchResultEnum theMatchResult, MdmTransactionContext theMdmContext);
}

View File

@ -35,6 +35,7 @@ public class MdmTransactionContext {
SUBMIT_RESOURCE_TO_MDM, SUBMIT_RESOURCE_TO_MDM,
QUERY_LINKS, QUERY_LINKS,
UPDATE_LINK, UPDATE_LINK,
CREATE_LINK,
DUPLICATE_GOLDEN_RESOURCES, DUPLICATE_GOLDEN_RESOURCES,
NOT_DUPLICATE, NOT_DUPLICATE,
MERGE_GOLDEN_RESOURCES, MERGE_GOLDEN_RESOURCES,

View File

@ -38,6 +38,8 @@ import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import javax.annotation.Nullable;
public abstract class BaseMdmProvider { public abstract class BaseMdmProvider {
@ -81,6 +83,22 @@ public abstract class BaseMdmProvider {
validateNotNull(ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, theResourceId); validateNotNull(ProviderConstants.MDM_UPDATE_LINK_RESOURCE_ID, theResourceId);
} }
protected void validateCreateLinkParameters(IPrimitiveType<String> theGoldenResourceId, IPrimitiveType<String> theResourceId, @Nullable IPrimitiveType<String> theMatchResult) {
validateNotNull(ProviderConstants.MDM_CREATE_LINK_GOLDEN_RESOURCE_ID, theGoldenResourceId);
validateNotNull(ProviderConstants.MDM_CREATE_LINK_RESOURCE_ID, theResourceId);
if (theMatchResult != null) {
MdmMatchResultEnum matchResult = MdmMatchResultEnum.valueOf(theMatchResult.getValue());
switch (matchResult) {
case NO_MATCH:
case POSSIBLE_MATCH:
case MATCH:
break;
default:
throw new InvalidRequestException(ProviderConstants.MDM_CREATE_LINK + " illegal " + ProviderConstants.MDM_CREATE_LINK_MATCH_RESULT +
" value '" + matchResult + "'. Must be " + MdmMatchResultEnum.NO_MATCH + ", " + MdmMatchResultEnum.MATCH + " or " + MdmMatchResultEnum.POSSIBLE_MATCH);
}
}
}
protected MdmTransactionContext createMdmContext(RequestDetails theRequestDetails, MdmTransactionContext.OperationType theOperationType, String theResourceType) { protected MdmTransactionContext createMdmContext(RequestDetails theRequestDetails, MdmTransactionContext.OperationType theOperationType, String theResourceType) {
TransactionLogMessages transactionLogMessages = TransactionLogMessages.createFromTransactionGuid(theRequestDetails.getTransactionGuid()); TransactionLogMessages transactionLogMessages = TransactionLogMessages.createFromTransactionGuid(theRequestDetails.getTransactionGuid());

View File

@ -53,6 +53,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
@ -180,6 +181,18 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
); );
} }
@Operation(name = ProviderConstants.MDM_CREATE_LINK)
public IBaseResource createLink(@OperationParam(name = ProviderConstants.MDM_CREATE_LINK_GOLDEN_RESOURCE_ID, min = 1, max = 1) IPrimitiveType<String> theGoldenResourceId,
@OperationParam(name = ProviderConstants.MDM_CREATE_LINK_RESOURCE_ID, min = 1, max = 1) IPrimitiveType<String> theResourceId,
@OperationParam(name = ProviderConstants.MDM_CREATE_LINK_MATCH_RESULT, min = 0, max = 1) IPrimitiveType<String> theMatchResult,
ServletRequestDetails theRequestDetails) {
validateCreateLinkParameters(theGoldenResourceId, theResourceId, theMatchResult);
return myMdmControllerSvc.createLink(theGoldenResourceId.getValueAsString(), theResourceId.getValue(), extractStringOrNull(theMatchResult),
createMdmContext(theRequestDetails, MdmTransactionContext.OperationType.CREATE_LINK,
getResourceType(ProviderConstants.MDM_CREATE_LINK_GOLDEN_RESOURCE_ID, theGoldenResourceId))
);
}
@Operation(name = ProviderConstants.OPERATION_MDM_CLEAR, returnParameters = { @Operation(name = ProviderConstants.OPERATION_MDM_CLEAR, returnParameters = {
@OperationParam(name = ProviderConstants.OPERATION_BATCH_RESPONSE_JOB_ID, typeName = "decimal") @OperationParam(name = ProviderConstants.OPERATION_BATCH_RESPONSE_JOB_ID, typeName = "decimal")
}) })

View File

@ -90,4 +90,21 @@ public class MessageHelper {
public String getMessageForNoLink(String theGoldenRecord, String theSourceResource) { public String getMessageForNoLink(String theGoldenRecord, String theSourceResource) {
return "No link exists between " + theGoldenRecord + " and " + theSourceResource; return "No link exists between " + theGoldenRecord + " and " + theSourceResource;
} }
public String getMessageForPresentLink(IAnyResource theGoldenRecord, IAnyResource theSourceResource) {
return getMessageForPresentLink(theGoldenRecord.getIdElement().toVersionless().toString(),
theSourceResource.getIdElement().toVersionless().toString());
}
public String getMessageForPresentLink(String theGoldenRecord, String theSourceResource) {
return "Link already exists between " + theGoldenRecord + " and " + theSourceResource + ". Use $mdm-update-link instead.";
}
public String getMessageForMultipleGoldenRecords(IAnyResource theSourceResource) {
return getMessageForMultipleGoldenRecords(theSourceResource.getIdElement().toVersionless().toString());
}
public String getMessageForMultipleGoldenRecords(String theSourceResource) {
return theSourceResource + " already has matched golden resource. Use $mdm-query-links to see more details.";
}
} }

View File

@ -80,6 +80,11 @@ public class ProviderConstants {
public static final String MDM_UPDATE_LINK_RESOURCE_ID = "resourceId"; public static final String MDM_UPDATE_LINK_RESOURCE_ID = "resourceId";
public static final String MDM_UPDATE_LINK_MATCH_RESULT = "matchResult"; public static final String MDM_UPDATE_LINK_MATCH_RESULT = "matchResult";
public static final String MDM_CREATE_LINK = "$mdm-create-link";
public static final String MDM_CREATE_LINK_GOLDEN_RESOURCE_ID = "goldenResourceId";
public static final String MDM_CREATE_LINK_RESOURCE_ID = "resourceId";
public static final String MDM_CREATE_LINK_MATCH_RESULT = "matchResult";
public static final String MDM_QUERY_LINKS = "$mdm-query-links"; public static final String MDM_QUERY_LINKS = "$mdm-query-links";
public static final String MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID = "goldenResourceId"; public static final String MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID = "goldenResourceId";
public static final String MDM_QUERY_LINKS_RESOURCE_ID = "resourceId"; public static final String MDM_QUERY_LINKS_RESOURCE_ID = "resourceId";