Skip to content
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

Add variable Extension support #1328

Merged
merged 165 commits into from
Sep 1, 2022
Merged
Show file tree
Hide file tree
Changes from 109 commits
Commits
Show all changes
165 commits
Select commit Hold shift + click to select a range
64ba13c
Added root level and item level variable extension support in Questio…
shoaibmushtaq25 Apr 21, 2022
8780a17
Refactored QuestionnaireViewModel to make code more readable
shoaibmushtaq25 Apr 25, 2022
a01940c
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Apr 25, 2022
9da5928
Merge branch 'master' of github.com:opensrp/android-fhir into sm/1059…
shoaibmushtaq25 Apr 27, 2022
7e48cf1
Refactored ancestors logic and add a Path to Variables map to save an…
shoaibmushtaq25 Apr 27, 2022
02e277b
Merge branch 'sm/1059_support_variable_extension' of github.com:opens…
shoaibmushtaq25 Apr 27, 2022
5bcfab9
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Apr 27, 2022
bbd55f5
Refactored variables code to make it more readable
shoaibmushtaq25 Apr 27, 2022
1087186
Refactored ancestors variables code to make it readable
shoaibmushtaq25 Apr 27, 2022
b20068f
Refactored to make the variables update for all siblings and ancestor…
shoaibmushtaq25 Apr 27, 2022
750bb74
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Apr 27, 2022
37c6d3c
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Apr 28, 2022
3aa52c4
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 May 6, 2022
a6fb990
Code readability improvements
shoaibmushtaq25 May 9, 2022
1b27bd6
Refactored, removed the extra functions
shoaibmushtaq25 May 9, 2022
5dadc75
Move Extension URl to MoreQuestionnaireItemComponents file
shoaibmushtaq25 May 10, 2022
f035779
Added unit tests for variable extension in QuestionnaireViewModelTest
shoaibmushtaq25 May 10, 2022
c62c08f
Add more unit tests for variable extension
shoaibmushtaq25 May 10, 2022
495727d
Added more unit tests for variable extension for invalid expresssions
shoaibmushtaq25 May 11, 2022
ded2a04
Added some documemtation for Variables extensions
shoaibmushtaq25 May 11, 2022
c032a8b
Fix spellings
shoaibmushtaq25 May 11, 2022
676e1d3
Added unit tests for FHIRPathEnginehostServices
shoaibmushtaq25 May 12, 2022
b1d1db9
Fix unit test in FHIRPathEngineHostServices
shoaibmushtaq25 May 12, 2022
35d217e
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 May 12, 2022
fe95e9a
Fixed wrong ArgumentMatchers on FHIRPathEngineHostServices file
shoaibmushtaq25 May 12, 2022
2f25b7e
Merge branch 'master' into sm/1059_support_variable_extension
maimoonak May 12, 2022
74aba60
Update Variables logic based on PR feedback
shoaibmushtaq25 May 13, 2022
7b7de19
Merge branch 'sm/1059_support_variable_extension' of github.com:opens…
shoaibmushtaq25 May 13, 2022
14a85ed
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 May 13, 2022
9585c23
Update nullability of updateVariable in quetionnaireViewModel
shoaibmushtaq25 May 13, 2022
7177219
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 May 13, 2022
bf0ff0d
Docs updated
shoaibmushtaq25 May 16, 2022
63bb6b3
Merge branch 'sm/1059_support_variable_extension' of github.com:opens…
shoaibmushtaq25 May 16, 2022
b2cfce4
Docs updated
shoaibmushtaq25 May 16, 2022
5b40268
Added more tests to FHIRPathEngineHostServices
shoaibmushtaq25 May 16, 2022
e5732cb
Added more unit test for QuestionnaireViewModel
shoaibmushtaq25 May 16, 2022
4e8ee59
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 May 18, 2022
474d495
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 May 19, 2022
d845b52
Update evaluateVariable method to make it re-usable
shoaibmushtaq25 May 19, 2022
a5eff26
Merge branch 'sm/1059_support_variable_extension' of github.com:opens…
shoaibmushtaq25 May 19, 2022
8ff2d99
updated variableName
shoaibmushtaq25 May 19, 2022
5f6a049
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 May 20, 2022
0d35b86
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 May 24, 2022
6f887bf
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 May 30, 2022
38ebbc6
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 May 30, 2022
ab76d99
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 2, 2022
b380d62
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 6, 2022
da24c63
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 6, 2022
7d0a072
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 7, 2022
e008b41
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 7, 2022
7c883ee
Removed unnecesary configs and Test runner
shoaibmushtaq25 Jun 7, 2022
ab7dfd2
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 9, 2022
cb10218
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 10, 2022
14cb554
Updated code to add dependent variables logic in pathToVariablesMap
shoaibmushtaq25 Jun 13, 2022
27cfd74
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 13, 2022
d3ecaa0
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 15, 2022
2904941
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 16, 2022
3b86fc5
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 20, 2022
70b851b
Add findDependents logic to find linkid and variable dependents
shoaibmushtaq25 Jun 20, 2022
97586f6
Fix spotless check
shoaibmushtaq25 Jun 20, 2022
7bea0c6
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 22, 2022
eecdbce
Fix broken unit tests
shoaibmushtaq25 Jun 22, 2022
0cd8441
Merge branch 'sm/1059_support_variable_extension' of github.com:opens…
shoaibmushtaq25 Jun 22, 2022
760befe
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 22, 2022
c0abb76
Fix broken unit tests, make variable null instead of empty
shoaibmushtaq25 Jun 22, 2022
c94c23e
Add more unit tests for QuestionnaireViewModel
shoaibmushtaq25 Jun 23, 2022
29925b9
Add more unit tests
shoaibmushtaq25 Jun 23, 2022
1dbb776
Fix regex for linkId and variable name
shoaibmushtaq25 Jun 23, 2022
0b1b57a
Added more tests
shoaibmushtaq25 Jun 24, 2022
b212dd7
Added documentation
shoaibmushtaq25 Jun 24, 2022
0e44bcd
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 24, 2022
ae004f5
Refactor some unit tests of QuestionnaireViewModel
shoaibmushtaq25 Jun 24, 2022
a2e0f26
Merge branch 'sm/1059_support_variable_extension' of github.com:opens…
shoaibmushtaq25 Jun 24, 2022
624c3a4
Added more test coverage
shoaibmushtaq25 Jun 28, 2022
bfdeaf9
Added more test case and require check for expression language
shoaibmushtaq25 Jun 28, 2022
8bfa16b
Fix regex to match variable name
shoaibmushtaq25 Jun 29, 2022
b39f2ed
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jun 30, 2022
63d894b
Added missing unit tests for page flow
shoaibmushtaq25 Jul 1, 2022
710c4fd
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 1, 2022
fa0c5c6
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 1, 2022
4f59276
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 5, 2022
66e176b
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 5, 2022
558eaa9
Fix spotless Check
shoaibmushtaq25 Jul 5, 2022
0f93bbf
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 6, 2022
e0be917
Fix spotless check
shoaibmushtaq25 Jul 6, 2022
35d2ec2
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 6, 2022
efdd925
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 8, 2022
f564ac7
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 13, 2022
94fc5f3
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 18, 2022
a937dc8
Spotless apply
shoaibmushtaq25 Jul 18, 2022
b203b56
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 20, 2022
c7c9a72
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 21, 2022
b462f1a
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 21, 2022
e0b110d
Changed solution approach, wrote a method to use it to calculate expr…
shoaibmushtaq25 Jul 22, 2022
3ddebef
Remove questionnairePreOrderList
shoaibmushtaq25 Jul 22, 2022
c01a57a
Refactored findVariable method to make it more readable
shoaibmushtaq25 Jul 22, 2022
4dcd62c
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 22, 2022
c0a103b
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 26, 2022
e9b1895
Removed broken, unrelated unit tests of QuestionnaireViewModel
shoaibmushtaq25 Jul 26, 2022
fa8769d
Make evaluateExpression internal to access it for use and testing
shoaibmushtaq25 Jul 26, 2022
e3ecb4c
Spotless apply
shoaibmushtaq25 Jul 26, 2022
91ff3c3
Added unit tests for root level and questionnaire item, origin variables
shoaibmushtaq25 Jul 26, 2022
aff9e23
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 26, 2022
9844af8
Added more tests for variables in QuestionnaireViewModelTest
shoaibmushtaq25 Jul 26, 2022
7b7f375
Merge branch 'sm/1059_support_variable_extension' of github.com:opens…
shoaibmushtaq25 Jul 26, 2022
86828d5
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 27, 2022
2f72822
Added failure cases and their test cases for fhirpath expressions
shoaibmushtaq25 Jul 27, 2022
f611540
Merge branch 'sm/1059_support_variable_extension' of github.com:opens…
shoaibmushtaq25 Jul 27, 2022
721e5b8
Remove un-related unit tests
shoaibmushtaq25 Jul 27, 2022
30a833b
feedback resolved around documentation
shoaibmushtaq25 Jul 27, 2022
86907e6
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Jul 27, 2022
680ca34
Merge branch 'sm/1059_support_variable_extension' of github.com:opens…
shoaibmushtaq25 Jul 27, 2022
9aafd1b
Fix some documentation and spotless apply
shoaibmushtaq25 Jul 27, 2022
ddae2f4
Revert "Fix some documentation and spotless apply"
shoaibmushtaq25 Jul 28, 2022
59f09d0
Refactored documentation
shoaibmushtaq25 Jul 28, 2022
c8d2131
spelling correction
shoaibmushtaq25 Jul 28, 2022
3a62325
Resolved feedback comments around documentation and immutability of m…
shoaibmushtaq25 Jul 29, 2022
a3a4d1d
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 2, 2022
7c5cfcd
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 2, 2022
c24bddd
Fix docs
shoaibmushtaq25 Aug 2, 2022
c9ea5f6
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 3, 2022
2999aec
Fix docs , apply spotless
shoaibmushtaq25 Aug 4, 2022
68ada2d
Fix docs , apply spotless
shoaibmushtaq25 Aug 4, 2022
d24bee3
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 7, 2022
21ff143
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 10, 2022
537d888
Separate out apis for varaibles expression into ExpressionEvaluator
shoaibmushtaq25 Aug 11, 2022
26f0745
Changed Junit Assertions to Truth Assertions
shoaibmushtaq25 Aug 11, 2022
da5662b
Add a unit test, update documentation, spotless apply
shoaibmushtaq25 Aug 11, 2022
d8490b1
Rename unit test
shoaibmushtaq25 Aug 11, 2022
32ec1bb
Added more documentation
shoaibmushtaq25 Aug 12, 2022
55dc6a6
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 12, 2022
13c9a09
Improve code readibility in Expression Evaluator and remove commented…
shoaibmushtaq25 Aug 12, 2022
e5f72d7
Fix documentation
shoaibmushtaq25 Aug 12, 2022
49b026e
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 12, 2022
2adb305
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
shoaibmushtaq25 Aug 12, 2022
e2eb5b6
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
shoaibmushtaq25 Aug 12, 2022
eb481d0
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
shoaibmushtaq25 Aug 12, 2022
0dcbf71
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
shoaibmushtaq25 Aug 12, 2022
a4126dc
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
shoaibmushtaq25 Aug 12, 2022
1f39f8e
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
shoaibmushtaq25 Aug 12, 2022
0c81269
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 12, 2022
a00889d
Added docs, Did refatoring in ExpressionEvaluator
shoaibmushtaq25 Aug 13, 2022
3085ece
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 15, 2022
661bc27
Fix documentation
shoaibmushtaq25 Aug 15, 2022
b6e2aef
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
shoaibmushtaq25 Aug 18, 2022
3a8ce89
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
shoaibmushtaq25 Aug 18, 2022
9992144
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
shoaibmushtaq25 Aug 18, 2022
d95d068
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
shoaibmushtaq25 Aug 18, 2022
10ea5b1
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
shoaibmushtaq25 Aug 18, 2022
3ad9705
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 18, 2022
dd5c954
Refactored methods to make it more readable
shoaibmushtaq25 Aug 18, 2022
aef2a0a
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 19, 2022
076c3d0
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 19, 2022
ad0efa0
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 19, 2022
2614bc4
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 21, 2022
b5ad3ec
Update datacapture/src/main/java/com/google/android/fhir/datacapture/…
shoaibmushtaq25 Aug 22, 2022
db6fbae
Renamed maps and fix documentation
shoaibmushtaq25 Aug 22, 2022
cdba224
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 24, 2022
54dbc4d
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 24, 2022
3e45be7
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 24, 2022
be11e35
Fix documentation
shoaibmushtaq25 Aug 24, 2022
852d1fd
Renamed variablesMap
shoaibmushtaq25 Aug 25, 2022
b738ea6
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 25, 2022
5189736
Merge branch 'master' into sm/1059_support_variable_extension
shoaibmushtaq25 Aug 26, 2022
203687c
Added a todo, apply spotless
shoaibmushtaq25 Aug 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.google.android.fhir.datacapture
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved

import org.hl7.fhir.r4.model.Base
import org.hl7.fhir.r4.model.TypeDetails
import org.hl7.fhir.r4.model.ValueSet
import org.hl7.fhir.r4.utils.FHIRPathEngine

object FHIRPathEngineHostServices : FHIRPathEngine.IEvaluationContext {
override fun resolveConstant(appContext: Any?, name: String?, beforeContext: Boolean): Base? {
return if ((appContext as Map<*, *>).containsKey(name)) appContext[name] as Base else null
}

@Throws(UnsupportedOperationException::class)
override fun resolveConstantType(appContext: Any?, name: String?): TypeDetails {
throw UnsupportedOperationException()
}

@Throws(UnsupportedOperationException::class)
override fun log(argument: String?, focus: MutableList<Base>?): Boolean {
throw UnsupportedOperationException()
}

@Throws(UnsupportedOperationException::class)
override fun resolveFunction(
functionName: String?
): FHIRPathEngine.IEvaluationContext.FunctionDetails {
throw UnsupportedOperationException()
}

@Throws(UnsupportedOperationException::class)
override fun checkFunction(
appContext: Any?,
functionName: String?,
parameters: MutableList<TypeDetails>?
): TypeDetails {
throw UnsupportedOperationException()
}

@Throws(UnsupportedOperationException::class)
override fun executeFunction(
appContext: Any?,
focus: MutableList<Base>?,
functionName: String?,
parameters: MutableList<MutableList<Base>>?
): MutableList<Base> {
throw UnsupportedOperationException()
}

@Throws(UnsupportedOperationException::class)
override fun resolveReference(appContext: Any?, url: String?): Base {
throw UnsupportedOperationException()
}

@Throws(UnsupportedOperationException::class)
override fun conformsToProfile(appContext: Any?, item: Base?, url: String?): Boolean {
throw UnsupportedOperationException()
}

@Throws(UnsupportedOperationException::class)
override fun resolveValueSet(appContext: Any?, url: String?): ValueSet {
throw UnsupportedOperationException()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021 Google LLC
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -62,6 +62,12 @@ internal const val EXTENSION_ENTRY_FORMAT_URL =
internal const val ITEM_ENABLE_WHEN_EXPRESSION_URL: String =
"http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression"

internal const val VARIABLE_EXTENSION_URL = "http://hl7.org/fhir/StructureDefinition/variable"
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved

internal val Questionnaire.QuestionnaireItemComponent.variableExpressions: List<Expression>
get() =
this.extension.filter { it.url == VARIABLE_EXTENSION_URL }.map { it.castToExpression(it.value) }

// Item control code, or null
internal val Questionnaire.QuestionnaireItemComponent.itemControl: ItemControlTypes?
get() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021 Google LLC
* Copyright 2022 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,6 +17,7 @@
package com.google.android.fhir.datacapture

import org.hl7.fhir.r4.model.CanonicalType
import org.hl7.fhir.r4.model.Expression
import org.hl7.fhir.r4.model.Questionnaire

/**
Expand All @@ -31,6 +32,10 @@ val Questionnaire.targetStructureMap: String?
return if (extensionValue is CanonicalType) extensionValue.valueAsString else null
}

internal val Questionnaire.variableExpressions: List<Expression>
get() =
this.extension.filter { it.url == VARIABLE_EXTENSION_URL }.map { it.castToExpression(it.value) }

/**
* See
* [Extension: target structure map](http://build.fhir.org/ig/HL7/sdc/StructureDefinition-sdc-questionnaire-targetStructureMap.html)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,17 @@ import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import org.hl7.fhir.exceptions.FHIRException
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext
import org.hl7.fhir.r4.model.Base
import org.hl7.fhir.r4.model.CodeableConcept
import org.hl7.fhir.r4.model.Coding
import org.hl7.fhir.r4.model.Expression
import org.hl7.fhir.r4.model.Questionnaire
import org.hl7.fhir.r4.model.QuestionnaireResponse
import org.hl7.fhir.r4.model.ResourceType
import org.hl7.fhir.r4.model.ValueSet
import org.hl7.fhir.r4.utils.FHIRPathEngine
import timber.log.Timber

internal class QuestionnaireViewModel(application: Application, state: SavedStateHandle) :
Expand Down Expand Up @@ -145,6 +150,25 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat
}
}

/** The map from each item in the [Questionnaire] to its parent. */
private val questionnaireItemParentMap =
mutableMapOf<
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
Questionnaire.QuestionnaireItemComponent, Questionnaire.QuestionnaireItemComponent>()

init {
/** Adds each child-parent pair in the [Questionnaire] to the parent map. */
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
fun buildParentList(item: Questionnaire.QuestionnaireItemComponent) {
for (child in item.item) {
questionnaireItemParentMap[child] = item
buildParentList(child)
}
}

for (item in questionnaire.item) {
buildParentList(item)
}
}

/** The map from each item in the [QuestionnaireResponse] to its parent. */
private val questionnaireResponseItemParentMap =
mutableMapOf<
Expand All @@ -168,6 +192,13 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat
/** Tracks modifications in order to update the UI. */
private val modificationCount = MutableStateFlow(0)

private val fhirPathEngine: FHIRPathEngine =
with(FhirContext.forCached(FhirVersionEnum.R4)) {
FHIRPathEngine(HapiWorkerContext(this, this.validationSupport)).apply {
hostServices = FHIRPathEngineHostServices
}
}

/**
* Contains [QuestionnaireResponse.QuestionnaireResponseItemComponent]s that have been modified by
* the user. [QuestionnaireResponse.QuestionnaireResponseItemComponent]s that have not been
Expand Down Expand Up @@ -496,6 +527,168 @@ internal class QuestionnaireViewModel(application: Application, state: SavedStat

return null
}

/**
* This function is to evaluate expression either calculated expression or variable expression The
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
* function first evaluates the expression, if found null, then parse the expression and find the
* related variable values from same questionnaireItem [Questionnaire.QuestionnaireItemComponent],
* also find in parent hierarchy of current origin [Questionnaire.QuestionnaireItemComponent] also
* find at questionnaire/root[Questionnaire] level and calculate and return the result of
* expression recursively,
*
* @param expression the [Expression] Either Variable expression or Calculated expression
* @param origin the [Questionnaire.QuestionnaireItemComponent] where this expression is defined,
* null if expression defined at questionnaire [Questionnaire] level
*
* @return [Base] the result of expression
*/
internal fun evaluateExpression(
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
expression: Expression,
origin: Questionnaire.QuestionnaireItemComponent? = null
): Base? {

val result = evaluateVariable(expression)
if (result != null) {
return result
}

buildMap<String, Base?> {
buildList {
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
val variableRegex = Regex("[%]([A-Za-z0-9\\-]{1,64})")
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
val variableMatches = variableRegex.findAll(expression.expression)

addAll(
variableMatches.map { it.groupValues[1] }.toList().filterNot { variable ->
reservedVariables.any { it == variable }
}
)
}
.takeIf { it.isNotEmpty() }
?.forEach { variableName ->
findVariable(variableName, origin)?.also { (questionnaireItem, expression) ->
put(expression.name, evaluateExpression(expression, questionnaireItem))
}
}
}
.also {
return evaluateVariable(expression, it)
}
}

/**
* function to find a variable, first check at origin if not found, then check in parent
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
* hierarchy, if not found, then check at root level and return the Pair
*
* @param variableName the [String] to match the variable
* @param origin the [Questionnaire.QuestionnaireItemComponent] from where we have to track
* hierarchy
*
* @return [Pair] containing [Questionnaire.QuestionnaireItemComponent] and [Expression]
*/
private fun findVariable(
variableName: String,
origin: Questionnaire.QuestionnaireItemComponent?
): Pair<Questionnaire.QuestionnaireItemComponent?, Expression>? {
return findVariableAtOrigin(variableName, origin)
?: findVariableInParent(variableName, origin) ?: findVariableAtRoot(variableName)
}

/**
* This function find the specific variable name [String] at the origin
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
* [Questionnaire.QuestionnaireItemComponent]
*
* @param origin the [Questionnaire.QuestionnaireItemComponent] from where we have to track
* hierarchy up in the parent
* @param variableName the [String] to match the variable in the parent hierarchy
*
* @return [Pair] containing [Questionnaire.QuestionnaireItemComponent] and [Expression]
*/
private fun findVariableAtOrigin(
variableName: String,
origin: Questionnaire.QuestionnaireItemComponent? = null
): Pair<Questionnaire.QuestionnaireItemComponent?, Expression>? {
origin?.variableExpressions?.find { it.name == variableName }.also {
it?.let {
return Pair(origin, it)
}
}
return null
}

/**
* This function find the specific variable name [String] in the parent hierarchy of origin
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
* [Questionnaire.QuestionnaireItemComponent]
*
* @param origin the [Questionnaire.QuestionnaireItemComponent] from where we have to track
* hierarchy up in the parent
* @param variableName the [String] to match the variable in the parent hierarchy
*
* @return [Pair] containing [Questionnaire.QuestionnaireItemComponent] and [Expression]
*/
private fun findVariableInParent(
variableName: String,
origin: Questionnaire.QuestionnaireItemComponent? = null
): Pair<Questionnaire.QuestionnaireItemComponent?, Expression>? {
var parent = questionnaireItemParentMap[origin]
while (parent != null) {
parent.variableExpressions.find { it.name == variableName }.also {
it?.let {
return Pair(parent!!, it)
}
}
parent = questionnaireItemParentMap[parent]
}
return null
}

/**
* This function find the specific variable name [String] at root/questionnaire [Questionnaire]
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
* level
*
* @param variableName the [String] to match the variable at questionnaire [Questionnaire] level
*
* @return [Expression] the matching expression
*/
private fun findVariableAtRoot(
variableName: String
): Pair<Questionnaire.QuestionnaireItemComponent?, Expression>? {
questionnaire.variableExpressions.find { it.name == variableName }.also {
it?.let {
return Pair(null, it)
}
}
return null
}

/**
* function to evaluate the value of variable expression and return the evaluated value
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
*
* @param expression the [Expression] the expression to evaluate
* @param inputVariables the [Map] of Variable names to their values
*
* @return [Base] the result of expression
*/
private fun evaluateVariable(
expression: Expression,
inputVariables: Map<String, Base?> = mapOf()
) =
try {

shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
require(!expression.name.isNullOrEmpty()) {
"Expression name should be a valid expression name"
}

require(expression.hasLanguage() && expression.language == "text/fhirpath") {
"Unsupported expression language, language should be text/fhirpath"
}

fhirPathEngine
.evaluate(inputVariables, questionnaireResponse, null, null, expression.expression)
.firstOrNull()
shoaibmushtaq25 marked this conversation as resolved.
Show resolved Hide resolved
} catch (exception: FHIRException) {
Timber.w("Could not evaluate expression with FHIRPathEngine", exception)
null
}
}

/** Questionnaire state for the Fragment to consume. */
Expand Down Expand Up @@ -527,3 +720,6 @@ internal fun QuestionnairePagination.nextPage(): QuestionnairePagination {
check(hasNextPage) { "Can't call nextPage() if hasNextPage is false ($this)" }
return copy(currentPageIndex = currentPageIndex + 1)
}

private val reservedVariables =
listOf("sct", "loinc", "ucum", "resource", "rootResource", "context", "map-codes")
Loading