Added support for Quantity in the default enable when evaluator
This commit is contained in:
parent
b29e8d987c
commit
076d18977d
|
@ -24,18 +24,15 @@ package org.hl7.fhir.convertors;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hl7.fhir.dstu3.model.Coding;
|
|
||||||
import org.hl7.fhir.dstu3.model.ContactDetail;
|
import org.hl7.fhir.dstu3.model.ContactDetail;
|
||||||
import org.hl7.fhir.dstu3.model.Contributor.ContributorType;
|
import org.hl7.fhir.dstu3.model.Contributor.ContributorType;
|
||||||
import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus;
|
import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus;
|
||||||
import org.hl7.fhir.dstu3.model.ExpansionProfile.DesignationIncludeDesignationComponent;
|
import org.hl7.fhir.dstu3.model.ExpansionProfile.DesignationIncludeDesignationComponent;
|
||||||
import org.hl7.fhir.dstu3.model.ExpansionProfile.SystemVersionProcessingMode;
|
import org.hl7.fhir.dstu3.model.ExpansionProfile.SystemVersionProcessingMode;
|
||||||
import org.hl7.fhir.dstu3.model.Extension;
|
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.r4.model.Expression.ExpressionLanguage;
|
import org.hl7.fhir.r4.model.Expression.ExpressionLanguage;
|
||||||
import org.hl7.fhir.r4.model.Questionnaire.EnableWhenBehavior;
|
import org.hl7.fhir.r4.model.Questionnaire.EnableWhenBehavior;
|
||||||
import org.hl7.fhir.r4.model.BooleanType;
|
import org.hl7.fhir.r4.model.BooleanType;
|
||||||
import org.hl7.fhir.r4.model.Contributor;
|
|
||||||
import org.hl7.fhir.r4.model.Identifier;
|
import org.hl7.fhir.r4.model.Identifier;
|
||||||
import org.hl7.fhir.r4.model.Reference;
|
import org.hl7.fhir.r4.model.Reference;
|
||||||
import org.hl7.fhir.r4.model.Type;
|
import org.hl7.fhir.r4.model.Type;
|
||||||
|
|
|
@ -8,6 +8,8 @@ import org.hl7.fhir.r4.elementmodel.Element;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
import org.hl7.fhir.r4.model.Questionnaire.*;
|
import org.hl7.fhir.r4.model.Questionnaire.*;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Evaluates Questionnaire.item.enableWhen against a QuestionnaireResponse.
|
* Evaluates Questionnaire.item.enableWhen against a QuestionnaireResponse.
|
||||||
* Ignores possible modifierExtensions and extensions.
|
* Ignores possible modifierExtensions and extensions.
|
||||||
|
@ -53,7 +55,7 @@ public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator {
|
||||||
if (operator == QuestionnaireItemOperator.EXISTS){
|
if (operator == QuestionnaireItemOperator.EXISTS){
|
||||||
Type answer = enableCondition.getAnswer();
|
Type answer = enableCondition.getAnswer();
|
||||||
if (!(answer instanceof BooleanType)){
|
if (!(answer instanceof BooleanType)){
|
||||||
throw new RuntimeException("Exists-operator requires answerBoolean");
|
throw new UnprocessableEntityException("Exists-operator requires answerBoolean");
|
||||||
}
|
}
|
||||||
return new EnableWhenResult(((BooleanType)answer).booleanValue() != answerItems.isEmpty(),
|
return new EnableWhenResult(((BooleanType)answer).booleanValue() != answerItems.isEmpty(),
|
||||||
linkId, enableCondition, questionnaireResponse);
|
linkId, enableCondition, questionnaireResponse);
|
||||||
|
@ -69,23 +71,44 @@ public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator {
|
||||||
try {
|
try {
|
||||||
actualAnswer = answer.asType();
|
actualAnswer = answer.asType();
|
||||||
} catch (FHIRException e) {
|
} catch (FHIRException e) {
|
||||||
throw new RuntimeException("Unexpected answer type", e);
|
throw new UnprocessableEntityException("Unexpected answer type", e);
|
||||||
}
|
}
|
||||||
if (!actualAnswer.getClass().equals(expectedAnswer.getClass())) {
|
if (!actualAnswer.getClass().equals(expectedAnswer.getClass())) {
|
||||||
throw new RuntimeException("Expected answer and actual answer have incompatible types");
|
throw new UnprocessableEntityException("Expected answer and actual answer have incompatible types");
|
||||||
}
|
}
|
||||||
if (expectedAnswer instanceof Coding) {
|
if (expectedAnswer instanceof Coding) {
|
||||||
return compareCodingAnswer((Coding)expectedAnswer, (Coding)actualAnswer, questionnaireItemOperator);
|
return compareCodingAnswer((Coding)expectedAnswer, (Coding)actualAnswer, questionnaireItemOperator);
|
||||||
} else if ((expectedAnswer instanceof PrimitiveType)) {
|
} else if ((expectedAnswer instanceof PrimitiveType)) {
|
||||||
return comparePrimitiveAnswer((PrimitiveType<?>)actualAnswer, (PrimitiveType<?>)expectedAnswer, questionnaireItemOperator);
|
return comparePrimitiveAnswer((PrimitiveType<?>)actualAnswer, (PrimitiveType<?>)expectedAnswer, questionnaireItemOperator);
|
||||||
|
} else if (expectedAnswer instanceof Quantity) {
|
||||||
|
return compareQuantityAnswer((Quantity)expectedAnswer, (Quantity)actualAnswer, questionnaireItemOperator);
|
||||||
}
|
}
|
||||||
// TODO: Quantity, Attachment, reference?
|
// TODO: Attachment, reference?
|
||||||
throw new RuntimeException("Unimplemented answer type: " + expectedAnswer.getClass());
|
throw new UnprocessableEntityException("Unimplemented answer type: " + expectedAnswer.getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean compareQuantityAnswer(Quantity actualAnswer, Quantity expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||||
|
return compareComparable(actualAnswer.getValue(), expectedAnswer.getValue(), questionnaireItemOperator);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean comparePrimitiveAnswer(PrimitiveType<?> actualAnswer, PrimitiveType<?> expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
private boolean comparePrimitiveAnswer(PrimitiveType<?> actualAnswer, PrimitiveType<?> expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||||
if (actualAnswer.getValue() instanceof Comparable){
|
if (actualAnswer.getValue() instanceof Comparable){
|
||||||
|
return compareComparable((Comparable)actualAnswer.getValue(), (Comparable) expectedAnswer.getValue(), questionnaireItemOperator);
|
||||||
|
} else if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
||||||
|
return actualAnswer.equalsShallow(expectedAnswer);
|
||||||
|
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
||||||
|
return !actualAnswer.equalsShallow(expectedAnswer);
|
||||||
|
}
|
||||||
|
throw new UnprocessableEntityException("Bad operator for PrimitiveType comparison");
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
int result = ((Comparable)actualAnswer.getValue()).compareTo(expectedAnswer.getValue());
|
private boolean compareComparable(Comparable actual, Comparable expected,
|
||||||
|
QuestionnaireItemOperator questionnaireItemOperator) {
|
||||||
|
int result = actual.compareTo(expected);
|
||||||
|
|
||||||
if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
||||||
return result == 0;
|
return result == 0;
|
||||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
||||||
|
@ -99,13 +122,9 @@ public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator {
|
||||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.GREATER_THAN){
|
} else if (questionnaireItemOperator == QuestionnaireItemOperator.GREATER_THAN){
|
||||||
return result > 0;
|
return result > 0;
|
||||||
}
|
}
|
||||||
throw new RuntimeException("Bad operator for PrimitiveType comparison");
|
|
||||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
throw new UnprocessableEntityException("Bad operator for PrimitiveType comparison");
|
||||||
return actualAnswer.equalsShallow(expectedAnswer);
|
|
||||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
|
||||||
return !actualAnswer.equalsShallow(expectedAnswer);
|
|
||||||
}
|
|
||||||
throw new RuntimeException("Bad operator for PrimitiveType comparison");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Element> findQuestionAnswers(Element questionnaireResponse, String question) {
|
private List<Element> findQuestionAnswers(Element questionnaireResponse, String question) {
|
||||||
|
@ -134,7 +153,7 @@ public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator {
|
||||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
||||||
return result == false;
|
return result == false;
|
||||||
}
|
}
|
||||||
throw new RuntimeException("Bad operator for Coding comparison");
|
throw new UnprocessableEntityException("Bad operator for Coding comparison");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean compareCodes(Coding expectedCoding, Coding value) {
|
private boolean compareCodes(Coding expectedCoding, Coding value) {
|
||||||
|
|
|
@ -328,12 +328,12 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequiredQuestionWithEnableWhenHidesQuestion() {
|
public void testRequiredQuestionQuantityWithEnableWhenHidesQuestionHasAnswerTrue() {
|
||||||
|
|
||||||
Questionnaire q = new Questionnaire();
|
Questionnaire q = new Questionnaire();
|
||||||
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.STRING);
|
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.QUANTITY);
|
||||||
|
|
||||||
// create the questionnaire
|
//link1 question is enabled when link0 has answer
|
||||||
QuestionnaireItemComponent item1 = new QuestionnaireItemComponent();
|
QuestionnaireItemComponent item1 = new QuestionnaireItemComponent();
|
||||||
item1.setLinkId("link1").setRequired(true);
|
item1.setLinkId("link1").setRequired(true);
|
||||||
q.addItem(item1);
|
q.addItem(item1);
|
||||||
|
@ -341,12 +341,11 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
||||||
item1.addEnableWhen(enable);
|
item1.addEnableWhen(enable);
|
||||||
enable.setQuestion("link0");
|
enable.setQuestion("link0");
|
||||||
enable.setHasAnswer(true);
|
enable.setHasAnswer(true);
|
||||||
|
enable.setAnswer(new Quantity().setValue(1L));
|
||||||
|
|
||||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||||
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||||
//qa.addItem().setLinkId("link0").addAnswer().setValue(new StringType("FOO"));
|
|
||||||
|
|
||||||
String reference = qa.getQuestionnaire().getReference();
|
String reference = qa.getQuestionnaire().getReference();
|
||||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||||
|
@ -356,6 +355,62 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
||||||
assertThat(errors.toString(), containsString("No issues"));
|
assertThat(errors.toString(), containsString("No issues"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRequiredQuestionQuantityWithEnableWhenHidesQuestionValue() {
|
||||||
|
|
||||||
|
Questionnaire q = new Questionnaire();
|
||||||
|
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.QUANTITY);
|
||||||
|
|
||||||
|
//link1 question is enabled when link0 has answer
|
||||||
|
QuestionnaireItemComponent item1 = new QuestionnaireItemComponent();
|
||||||
|
item1.setLinkId("link1").setRequired(true);
|
||||||
|
q.addItem(item1);
|
||||||
|
QuestionnaireItemEnableWhenComponent enable = new QuestionnaireItemEnableWhenComponent();
|
||||||
|
item1.addEnableWhen(enable);
|
||||||
|
enable.setQuestion("link0");
|
||||||
|
enable.setAnswer(new Quantity().setValue(2L));
|
||||||
|
|
||||||
|
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||||
|
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||||
|
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||||
|
qa.addItem().setLinkId("link0").addAnswer().setValue(new Quantity().setValue(1L));
|
||||||
|
|
||||||
|
String reference = qa.getQuestionnaire().getReference();
|
||||||
|
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||||
|
ValidationResult errors = myVal.validateWithResult(qa);
|
||||||
|
|
||||||
|
ourLog.info(errors.toString());
|
||||||
|
assertThat(errors.toString(), containsString("No issues"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRequiredQuestionQuantityWithEnableWhenEnablesQuestionValue() {
|
||||||
|
|
||||||
|
Questionnaire q = new Questionnaire();
|
||||||
|
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.QUANTITY);
|
||||||
|
|
||||||
|
//link1 question is enabled when link0 has answer
|
||||||
|
QuestionnaireItemComponent item1 = new QuestionnaireItemComponent();
|
||||||
|
item1.setLinkId("link1").setRequired(true);
|
||||||
|
q.addItem(item1);
|
||||||
|
QuestionnaireItemEnableWhenComponent enable = new QuestionnaireItemEnableWhenComponent();
|
||||||
|
item1.addEnableWhen(enable);
|
||||||
|
enable.setQuestion("link0");
|
||||||
|
enable.setAnswer(new Quantity().setValue(1L));
|
||||||
|
|
||||||
|
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||||
|
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||||
|
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||||
|
qa.addItem().setLinkId("link0").addAnswer().setValue(new Quantity().setValue(1L));
|
||||||
|
|
||||||
|
String reference = qa.getQuestionnaire().getReference();
|
||||||
|
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||||
|
ValidationResult errors = myVal.validateWithResult(qa);
|
||||||
|
|
||||||
|
ourLog.info(errors.toString());
|
||||||
|
assertThat(errors.toString(), containsString("No response found for required item link1"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequiredQuestionWithEnableWhenHasAnswerTrueWithAnswer() {
|
public void testRequiredQuestionWithEnableWhenHasAnswerTrueWithAnswer() {
|
||||||
|
|
||||||
|
@ -451,7 +506,6 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
||||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||||
|
|
||||||
ValidationResult errors = myVal.validateWithResult(qr);
|
ValidationResult errors = myVal.validateWithResult(qr);
|
||||||
|
|
||||||
assertThat(errors.toString(), Matchers.not(containsString("No issues")));
|
assertThat(errors.toString(), Matchers.not(containsString("No issues")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue