Jd 20240704 fix mdm phonetic matching on humanname exception (#6078)

* failing test

* fix and changelog

* edit changelog issue number

* mvn spotless

* address code review comment

---------

Co-authored-by: jdar <justin.dar@smiledigitalhealth.com>
This commit is contained in:
jdar8 2024-07-12 09:54:45 -07:00 committed by GitHub
parent 40d42f3ba5
commit ec7538c78f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 69 additions and 3 deletions

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 6077
title: "Previously, when a MDM rule tried to perform a phonetic match by HumanName (eg. Patient.name), a
`ClassCastException` was thrown. This has now been fixed."

View File

@ -45,9 +45,17 @@ public class PhoneticEncoderMatcher implements IMdmFieldMatcher {
@Override
public boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theParams) {
String leftString = StringMatcherUtils.extractString((IPrimitiveType<?>) theLeftBase, theParams.getExact());
String rightString = StringMatcherUtils.extractString((IPrimitiveType<?>) theRightBase, theParams.getExact());
if (theLeftBase instanceof IPrimitiveType && theRightBase instanceof IPrimitiveType) {
String leftString = StringMatcherUtils.extractString((IPrimitiveType<?>) theLeftBase, theParams.getExact());
String rightString =
StringMatcherUtils.extractString((IPrimitiveType<?>) theRightBase, theParams.getExact());
return matches(leftString, rightString);
return matches(leftString, rightString);
}
ourLog.warn(
"Unable to evaluate match between {} and {} because they are not an instance of PrimitiveType.",
theLeftBase.getClass().getSimpleName(),
theRightBase.getClass().getSimpleName());
return false;
}
}

View File

@ -6,15 +6,29 @@ import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.rules.json.MdmFieldMatchJson;
import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson;
import ca.uhn.fhir.mdm.rules.json.MdmRulesJson;
import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.PhoneticEncoderMatcher;
import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import org.hl7.fhir.r4.model.HumanName;
import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.slf4j.LoggerFactory;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
public class ResourceMatcherR4Test extends BaseMdmRulesR4Test {
@ -23,6 +37,10 @@ public class ResourceMatcherR4Test extends BaseMdmRulesR4Test {
public static final String PHONE_NUMBER = "123 456789";
private Patient myLeft;
private Patient myRight;
@Mock
private Appender<ILoggingEvent> myAppender;
@Captor
ArgumentCaptor<ILoggingEvent> myLoggingEvent;
@Override
@BeforeEach
@ -61,6 +79,41 @@ public class ResourceMatcherR4Test extends BaseMdmRulesR4Test {
assertMatchResult(MdmMatchResultEnum.MATCH, 7L, 3.0, false, false, result);
}
@Test
public void testMetaphoneOnName() {
Logger logger = (Logger) LoggerFactory.getLogger(PhoneticEncoderMatcher.class);
logger.addAppender(myAppender);
// Given: MDM rules that match by Patient.name using some phonetic algorithm
MdmFieldMatchJson lastNameMatchField = new MdmFieldMatchJson()
.setName(PATIENT_FAMILY)
.setResourceType("Patient")
.setResourcePath("name")
.setMatcher(new MdmMatcherJson().setAlgorithm(MatchTypeEnum.METAPHONE));
MdmRulesJson retval = new MdmRulesJson();
retval.setVersion("test version");
retval.addMatchField(lastNameMatchField);
retval.setMdmTypes(List.of("Patient"));
retval.putMatchResult(PATIENT_FAMILY, MdmMatchResultEnum.MATCH);
// When
MdmResourceMatcherSvc matcherSvc = buildMatcher(retval);
MdmMatchOutcome result = matcherSvc.match(myLeft, myRight);
// Then: expect a logged message notifying that we are unable to phonetically match by HumanName
verify(myAppender, times(1)).doAppend(myLoggingEvent.capture());
ILoggingEvent event = myLoggingEvent.getValue();
assertEquals(Level.WARN, event.getLevel());
assertEquals("Unable to evaluate match between HumanName and HumanName because they are not an instance of PrimitiveType.", event.getFormattedMessage());
logger.detachAppender(myAppender);
verifyNoMoreInteractions(myAppender);
System.clearProperty("unit_test");
assertMatchResult(MdmMatchResultEnum.NO_MATCH, 0L, 0.0, false, false, result);
}
@Test
public void testStringMatchResult() {
MdmResourceMatcherSvc matcherSvc = buildMatcher(buildNamePhoneRules(MatchTypeEnum.STRING));