-
Notifications
You must be signed in to change notification settings - Fork 302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix issue with empty context with initial expression #1228
Changes from 20 commits
01ba81c
117f474
cb89b67
9e4ca7f
2b96744
512f760
03ac5e9
dffe99c
5b1d462
9a26aab
ed18ff5
a3deda3
2f004af
5d12a9e
6197c6f
ffc9709
dacf027
8d7ad14
e048cb3
b630b16
31d78d9
5284d6c
b2b6187
34e7e81
5a32c3f
c67a406
82f7a23
2f27423
85398df
8c02a1a
b978015
748fe39
61d59bd
93e3b7a
957b991
59ce913
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -46,7 +46,6 @@ import org.hl7.fhir.r4.model.Questionnaire | |||||||||
import org.hl7.fhir.r4.model.QuestionnaireResponse | ||||||||||
import org.hl7.fhir.r4.model.Resource | ||||||||||
import org.hl7.fhir.r4.model.StringType | ||||||||||
import org.hl7.fhir.r4.model.StructureMap | ||||||||||
import org.hl7.fhir.r4.model.Type | ||||||||||
import org.hl7.fhir.r4.model.UriType | ||||||||||
import org.hl7.fhir.r4.utils.FHIRPathEngine | ||||||||||
|
@@ -197,27 +196,54 @@ object ResourceMapper { | |||||||||
vararg resources: Resource | ||||||||||
) { | ||||||||||
if (questionnaireItem.type != Questionnaire.QuestionnaireItemType.GROUP) { | ||||||||||
questionnaireItem.fetchExpression?.let { exp -> | ||||||||||
val resourceType = exp.expression.substringBefore(".").removePrefix("%") | ||||||||||
|
||||||||||
// Match the first resource of the same type | ||||||||||
val contextResource = | ||||||||||
resources.firstOrNull { it.resourceType.name.equals(resourceType) } ?: return | ||||||||||
|
||||||||||
val answerExtracted = fhirPathEngine.evaluate(contextResource, exp.expression) | ||||||||||
answerExtracted.firstOrNull()?.let { answer -> | ||||||||||
questionnaireItem.initial = | ||||||||||
mutableListOf( | ||||||||||
Questionnaire.QuestionnaireItemInitialComponent().setValue(answer.asExpectedType()) | ||||||||||
) | ||||||||||
} | ||||||||||
questionnaireItem.initialExpression?.let { exp -> | ||||||||||
evaluateInitialExpressionAndSetInitialValue(exp, resources, questionnaireItem) | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
populateInitialValues(questionnaireItem.item, *resources) | ||||||||||
} | ||||||||||
|
||||||||||
private val Questionnaire.QuestionnaireItemComponent.fetchExpression: Expression? | ||||||||||
private fun evaluateInitialExpressionAndSetInitialValue( | ||||||||||
exp: Expression, | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. avoid using abbreviations
Suggested change
|
||||||||||
resources: Array<out Resource>, | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i don't feel like this out here is justified? I thought it's only useful for declarations on class/interface. can you elaborate why this is needed? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually |
||||||||||
questionnaireItem: Questionnaire.QuestionnaireItemComponent | ||||||||||
) { | ||||||||||
val resourceType = exp.expression.substringBefore(".").removePrefix("%") | ||||||||||
val contextResource = | ||||||||||
resources.firstOrNull { it.resourceType.name.lowercase().equals(resourceType.lowercase()) } | ||||||||||
|
||||||||||
val extractedAnswers = getAnswers(contextResource, resources, exp) | ||||||||||
extractedAnswers.firstOrNull()?.let { answer -> | ||||||||||
// Resetting QuestionnaireItemInitialComponent value using provided initialExpression | ||||||||||
questionnaireItem.initial = | ||||||||||
mutableListOf( | ||||||||||
Questionnaire.QuestionnaireItemInitialComponent().setValue(answer.asExpectedType()) | ||||||||||
) | ||||||||||
} | ||||||||||
} | ||||||||||
|
||||||||||
private fun getAnswers( | ||||||||||
contextResource: Resource?, | ||||||||||
resources: Array<out Resource>, | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ditto |
||||||||||
exp: Expression | ||||||||||
): MutableList<Base> { | ||||||||||
var extractedAnswers = mutableListOf<Base>() | ||||||||||
if (contextResource == null) { | ||||||||||
if (resources.isNotEmpty()) { | ||||||||||
// Using the first provided resource as a base resource inorder to fetch answers from the | ||||||||||
// functions | ||||||||||
extractedAnswers = fhirPathEngine.evaluate(resources[0], exp.expression.removePrefix("%")) | ||||||||||
} | ||||||||||
} else { | ||||||||||
// Using the resource extracted from provided expression as a base resource inorder to fetch | ||||||||||
// answers from the functions | ||||||||||
extractedAnswers = fhirPathEngine.evaluate(contextResource, exp.expression.removePrefix("%")) | ||||||||||
} | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this code seems duplicated to me. you're just saying if the context resource is empty just take the first resource as the context resource right? i feel this code is actually harder to read and doesn't add any more functionality. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @jingtang10, this code added functionality to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the only thing that's different in the code is that if the type doesn't match the expected expression the first resource is passed anyway as context. |
||||||||||
return extractedAnswers | ||||||||||
} | ||||||||||
|
||||||||||
private val Questionnaire.QuestionnaireItemComponent.initialExpression: Expression? | ||||||||||
get() { | ||||||||||
return this.extension.firstOrNull { it.url == ITEM_INITIAL_EXPRESSION_URL }?.let { | ||||||||||
it.value as Expression | ||||||||||
|
@@ -514,7 +540,7 @@ private fun wrapAnswerInFieldType(answer: Base, fieldType: Field): Base { | |||||||||
return answer | ||||||||||
} | ||||||||||
|
||||||||||
private const val ITEM_INITIAL_EXPRESSION_URL: String = | ||||||||||
const val ITEM_INITIAL_EXPRESSION_URL: String = | ||||||||||
"http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-initialExpression" | ||||||||||
|
||||||||||
private val Field.isList: Boolean | ||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is much better as a extension function on questionnaireItem.
fun QuestionnaireItem.setInitialValueFromInitialExpression()
seems appropriate.you're passing the questionnaire item to the
evaluateInitialExpressionAndSetInitialValue
function which seems odd to me. All this happens within the context of the questionnaire item, so should probably be an extension function.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jingtang10 I have created an extension function with slight modifications. Please re-review the PR.