Skip to content

Commit

Permalink
Load resources like Questionnaire, StructureMap,PlanDefinition from r…
Browse files Browse the repository at this point in the history
…esources folder when using appId with `/debug` (#3065)

* Update loading on resources locally

* Load SMS, PD and Qs locally from configJson

* Add resources to DB

* Run spotlessApply

* Update resources to DB

* Fix resource addition to DB

* Fix some resources not updated

* Add tests for loading local resources

* Add docs

* Fix spotless errors

* Beautify docs

* Fix coverage

* Test exception

---------

Co-authored-by: SebaMutuku <[email protected]>
Co-authored-by: Sebastian <[email protected]>
  • Loading branch information
3 people authored Jun 1, 2024
1 parent f64baa8 commit ee6d05e
Show file tree
Hide file tree
Showing 12 changed files with 359 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ package org.smartregister.fhircore.engine.configuration

import android.content.Context
import android.database.SQLException
import ca.uhn.fhir.context.ConfigurationException
import ca.uhn.fhir.context.FhirContext
import ca.uhn.fhir.parser.DataFormatException
import com.google.android.fhir.FhirEngine
import com.google.android.fhir.db.ResourceNotFoundException
import com.google.android.fhir.get
Expand All @@ -38,7 +40,6 @@ import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import okhttp3.RequestBody.Companion.toRequestBody
import okio.ByteString.Companion.decodeBase64
import org.apache.commons.lang3.StringUtils
import org.hl7.fhir.r4.model.Base
import org.hl7.fhir.r4.model.Binary
import org.hl7.fhir.r4.model.Bundle
Expand Down Expand Up @@ -298,7 +299,7 @@ constructor(
}
}

private suspend fun populateConfigurationsMap(
suspend fun populateConfigurationsMap(
context: Context,
composition: Composition,
loadFromAssets: Boolean,
Expand All @@ -308,21 +309,33 @@ constructor(
if (loadFromAssets) {
retrieveAssetConfigs(context, appId).forEach { fileName ->
// Create binary config from asset and add to map, skip composition resource
// Use file name as the key. Conventionally navigation configs MUST end with
// "_config.<extension>"
// Use file name as the key. Conventionally configs MUST end with _config.<extension>"
// File names in asset should match the configType/id (MUST be unique) in the config JSON
// Resource configs are saved to the database
if (!fileName.equals(String.format(COMPOSITION_CONFIG_PATH, appId), ignoreCase = true)) {
val configKey =
fileName
.lowercase(Locale.ENGLISH)
.substring(
fileName.indexOfLast { it == '/' }.plus(1),
fileName.lastIndexOf(CONFIG_SUFFIX),
)
.camelCase()

val configJson = context.assets.open(fileName).bufferedReader().readText()
configsJsonMap[configKey] = configJson
if (fileName.contains(RESOURCES_PATH)) {
try {
val resource = configJson.decodeResourceFromString<Resource>()
if (resource.resourceType != null) {
addOrUpdate(resource)
}
} catch (configurationException: ConfigurationException) {
Timber.e("Error parsing FHIR resource", configurationException)
} catch (dataFormatException: DataFormatException) {
Timber.e("Error parsing FHIR resource", dataFormatException)
}
} else {
val configKey =
fileName
.lowercase(Locale.ENGLISH)
.substring(
fileName.indexOfLast { it == '/' }.plus(1),
fileName.lastIndexOf(CONFIG_SUFFIX),
)
.camelCase()
configsJsonMap[configKey] = configJson
}
}
}
} else {
Expand Down Expand Up @@ -422,14 +435,17 @@ constructor(
} else {
val chunkedResourceIdList = entry.value.chunked(MANIFEST_PROCESSOR_BATCH_SIZE)

chunkedResourceIdList.forEach { parentIt ->
chunkedResourceIdList.forEach { sectionComponents ->
Timber.d(
"Fetching config resource ${entry.key}: with ids ${StringUtils.join(parentIt,",")}",
"Fetching config resource ${entry.key}: with ids ${sectionComponents.joinToString(",")}",
)
processCompositionManifestResources(
entry.key,
parentIt.map { sectionComponent -> sectionComponent.focus.extractId() },
patientRelatedResourceTypes,
resourceType = entry.key,
resourceIdList =
sectionComponents.map { sectionComponent ->
sectionComponent.focus.extractId()
},
patientRelatedResourceTypes = patientRelatedResourceTypes,
)
}
}
Expand Down Expand Up @@ -622,7 +638,7 @@ constructor(
this.apply {
url =
url
?: "${openSrpApplication?.getFhirServerHost().toString()?.trimEnd { it == '/' }}/${this.referenceValue()}"
?: """${openSrpApplication?.getFhirServerHost()?.toString()?.trimEnd { it == '/' }}/${this.referenceValue()}"""
}

fun writeToFile(resource: Resource): File {
Expand Down Expand Up @@ -811,13 +827,14 @@ constructor(
const val TYPE_REFERENCE_DELIMITER = "/"
const val DEFAULT_COUNT = 200
const val PAGINATION_NEXT = "next"
const val RESOURCES_PATH = "resources/"

/**
* The list of resources whose types can be synced down as part of the Composition configs.
* These are hardcoded as they are not meant to be easily configurable to avoid config vs data
* sync issues
*/
val FILTER_RESOURCE_LIST =
private val FILTER_RESOURCE_LIST =
listOf(
ResourceType.Questionnaire.name,
ResourceType.StructureMap.name,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"resourceType": "Questionnaire",
"id": "3440",
"language": "en",
"name": "G6PD Test Photo Result",
"title": "G6PD Test Photo Result",
"status": "active",
"subjectType": [
"Patient"
],
"publisher": "ONA-Systems",
"useContext": [
{
"code": {
"system": "http://hl7.org/fhir/codesystem-usage-context-type.html",
"code": "focus"
},
"valueCodeableConcept": {
"coding": [
{
"system": "http://fhir.ona.io",
"code": "000002",
"display": "G6PD Test Photo Results"
}
]
}
}
],
"extension": [
{
"url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-targetStructureMap",
"valueCanonical": "https://fhir.labs.smartregister.org/StructureMap/5875"
},
{
"url": "http://hl7.org/fhir/StructureDefinition/cqf-library",
"valueCanonical": "Library/46831"
},
{
"url": "http://hl7.org/fhir/StructureDefinition/cqf-library",
"valueCanonical": "Library/46823"
}
],
"item": [
{
"extension": [
{
"url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-observationExtract",
"valueBoolean": true
}
],
"linkId": "result_type",
"code": [
{
"system": "http://fhir.ona.io",
"code": "000001",
"display": "G6PD Result Type"
}
],
"text": "G6PD Result Type",
"type": "choice",
"required": true,
"answerOption": [
{
"valueCoding": {
"system": "http://snomed.info/sct",
"code": "410680006",
"display": "Number"
}
},
{
"valueCoding": {
"system": "http://snomed.info/sct",
"code": "405358009",
"display": "Error"
}
},
{
"valueCoding": {
"system": "http://snomed.info/sct",
"code": "385432009",
"display": "N/A"
}
}
]
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ object Faker {
context = ApplicationProvider.getApplicationContext<HiltTestApplication>(),
openSrpApplication =
object : OpenSrpApplication() {
override fun getFhirServerHost(): URL? {
override fun getFhirServerHost(): URL {
return URL("http://my_test_fhirbase_url/fhir/")
}
},
Expand Down
Loading

0 comments on commit ee6d05e

Please sign in to comment.