Skip to content

Commit 5ba3a6a

Browse files
authored
populate initial with initialExpression result collection (#2751)
* populate initial with initialExpression result collection * handle invariant rules for initialExpression * convert evaluatedExpressionResult to questionnaireItem.type * updated answerOptions in test to match initialExpressions' result * added rule url in check message for initial value on group or display items. * added test for invariant rule que-8 & codings without system match in initialExpression * - refactored populateInitialValue Handles repeats logic for answerOption * - integrated tests for populateInitialValues * - (spotless fix) ResourceMapperTest.kt * - (feedback) added test & refactored code to use variables. * - (refactor) updated multiline comment
1 parent bf19b7a commit 5ba3a6a

File tree

2 files changed

+541
-13
lines changed

2 files changed

+541
-13
lines changed

datacapture/src/main/java/com/google/android/fhir/datacapture/mapping/ResourceMapper.kt

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2024 Google LLC
2+
* Copyright 2022-2025 Google LLC
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ package com.google.android.fhir.datacapture.mapping
1919
import com.google.android.fhir.datacapture.extensions.createQuestionnaireResponseItem
2020
import com.google.android.fhir.datacapture.extensions.filterByCodeInNameExtension
2121
import com.google.android.fhir.datacapture.extensions.initialExpression
22+
import com.google.android.fhir.datacapture.extensions.initialSelected
2223
import com.google.android.fhir.datacapture.extensions.logicalId
2324
import com.google.android.fhir.datacapture.extensions.questionnaireLaunchContexts
2425
import com.google.android.fhir.datacapture.extensions.targetStructureMap
@@ -248,22 +249,59 @@ object ResourceMapper {
248249
"QuestionnaireItem item is not allowed to have both initial.value and initial expression. See rule at http://build.fhir.org/ig/HL7/sdc/expressions.html#initialExpression."
249250
}
250251

252+
// Initial values can't be specified for groups or display items
253+
check(
254+
!(questionnaireItem.type == Questionnaire.QuestionnaireItemType.GROUP ||
255+
questionnaireItem.type == Questionnaire.QuestionnaireItemType.DISPLAY) ||
256+
(questionnaireItem.initial.isEmpty() && questionnaireItem.initialExpression == null),
257+
) {
258+
"QuestionnaireItem item is not allowed to have initial value or initial expression for groups or display items. See rule at http://build.fhir.org/ig/HL7/sdc/expressions.html#initialExpression."
259+
}
260+
251261
questionnaireItem.initialExpression
252262
?.let {
253263
evaluateToBase(
254-
questionnaireResponse = null,
255-
questionnaireResponseItem = null,
256-
expression = it.expression,
257-
contextMap = launchContexts,
258-
)
259-
.firstOrNull()
264+
questionnaireResponse = null,
265+
questionnaireResponseItem = null,
266+
expression = it.expression,
267+
contextMap = launchContexts,
268+
)
260269
}
261270
?.let {
262-
// Set initial value for the questionnaire item. Questionnaire items should not have both
263-
// initial value and initial expression.
264-
val value = it.asExpectedType(questionnaireItem.type)
265-
questionnaireItem.initial =
266-
mutableListOf(Questionnaire.QuestionnaireItemInitialComponent().setValue(value))
271+
// Set initial value for the questionnaire item.
272+
if (it.isEmpty()) return@let
273+
274+
// If questionnaireItem.repeats is false only first value is selected from initialExpression
275+
// result set
276+
val evaluatedExpressionResult =
277+
if (questionnaireItem.repeats) {
278+
it.map { it.asExpectedType(questionnaireItem.type) }
279+
} else {
280+
listOf(it.first().asExpectedType(questionnaireItem.type))
281+
}
282+
283+
/**
284+
* For answer options, the initialSelected extension is used to highlight initial values.
285+
*
286+
* Note: If the initial expression evaluates to five values (1, 2, 3, 4, 5) but only three
287+
* answer options (1, 2, 3) exist, then 4 and 5 will be ignored. These values are not added
288+
* as additional options, nor would it make sense to do so. This behavior ensures the answer
289+
* options remain consistent with the defined set.
290+
*/
291+
if (questionnaireItem.answerOption.isNotEmpty()) {
292+
questionnaireItem.answerOption.forEach { answerOption ->
293+
answerOption.initialSelected =
294+
evaluatedExpressionResult.any { answerOption.value.equalsDeep(it) }
295+
}
296+
} else {
297+
questionnaireItem.initial =
298+
evaluatedExpressionResult.map {
299+
Questionnaire.QuestionnaireItemInitialComponent()
300+
.setValue(
301+
it,
302+
)
303+
}
304+
}
267305
}
268306

269307
populateInitialValues(questionnaireItem.item, launchContexts)

0 commit comments

Comments
 (0)