Skip to content

Commit

Permalink
Refactor configs processing implementation
Browse files Browse the repository at this point in the history
- Add support to fetch List configuration composition contents
  • Loading branch information
ndegwamartin committed Jul 10, 2023
1 parent e0a9fcc commit d645c8b
Show file tree
Hide file tree
Showing 7 changed files with 295 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import org.hl7.fhir.r4.model.Base
import org.hl7.fhir.r4.model.Binary
import org.hl7.fhir.r4.model.Bundle
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent
import org.hl7.fhir.r4.model.Composition
import org.hl7.fhir.r4.model.ListResource
import org.hl7.fhir.r4.model.Resource
import org.hl7.fhir.r4.model.ResourceType
import org.json.JSONObject
Expand All @@ -47,7 +48,6 @@ import org.smartregister.fhircore.engine.util.extension.camelCase
import org.smartregister.fhircore.engine.util.extension.decodeJson
import org.smartregister.fhircore.engine.util.extension.decodeResourceFromString
import org.smartregister.fhircore.engine.util.extension.extractId
import org.smartregister.fhircore.engine.util.extension.extractLogicalIdUuid
import org.smartregister.fhircore.engine.util.extension.fileExtension
import org.smartregister.fhircore.engine.util.extension.generateMissingId
import org.smartregister.fhircore.engine.util.extension.interpolate
Expand Down Expand Up @@ -363,38 +363,54 @@ constructor(
)
}
.forEach { resourceGroup ->
val chunkedResourceIdList = resourceGroup.value.chunked(MANIFEST_PROCESSOR_BATCH_SIZE)
if (resourceGroup.key == ResourceType.List.name) {

chunkedResourceIdList.forEach {
val resourceIds =
it.joinToString(",") { sectionComponent -> sectionComponent.focus.extractId() }
processCompositionManifestResources(resourceGroup.key, resourceIds)
resourceGroup.value.forEach {
processCompositionManifestResources(
FHIR_GATEWAY_MODE_HEADER_VALUE,
"${resourceGroup.key}/${it.focus.extractId()}"
)
}
} else {
val chunkedResourceIdList = resourceGroup.value.chunked(MANIFEST_PROCESSOR_BATCH_SIZE)

chunkedResourceIdList.forEach {
val resourceIds =
it.joinToString(",") { sectionComponent -> sectionComponent.focus.extractId() }
processCompositionManifestResources(
searchPath = "${resourceGroup.key}?${Composition.SP_RES_ID}=$resourceIds"
)
}
}
}
}
}
}

private suspend fun processCompositionManifestResources(
resourceType: String,
resourceIds: String
gatewayModeHeaderValue: String? = null,
searchPath: String
) {
val searchPath = resourceType + "?${Composition.SP_RES_ID}=$resourceIds"
val resultBundle =
if (gatewayModeHeaderValue.isNullOrEmpty()) fhirResourceDataSource.getResource(searchPath)
else
fhirResourceDataSource.getResourceWithGatewayModeHeader(gatewayModeHeaderValue, searchPath)

fhirResourceDataSource.getResource(searchPath).entry.forEach { bundleEntryComponent ->
resultBundle.entry.forEach { bundleEntryComponent ->
when (bundleEntryComponent.resource) {
is ListResource -> {
addOrUpdate(bundleEntryComponent.resource)
val list = bundleEntryComponent.resource as ListResource
list.entry.forEach { listEntryComponent ->
val resourceKey = listEntryComponent.item.reference.substringBefore("/")
val resourceId = listEntryComponent.item.reference.extractLogicalIdUuid()
is Bundle -> {
val bundle = bundleEntryComponent.resource as Bundle
bundle.entry.forEach { entryComponent ->
when (entryComponent.resource) {
is Bundle -> {

val listResourceUrlPath = resourceKey + "?${Composition.SP_RES_ID}=$resourceId"
fhirResourceDataSource.getResource(listResourceUrlPath).entry.forEach {
listEntryResourceBundle ->
addOrUpdate(listEntryResourceBundle.resource)
Timber.d("Fetched and processed List reference $listResourceUrlPath")
val bundle = entryComponent.resource as Bundle
addOrUpdate(bundle)
bundle.entry.forEach { innerEntryComponent ->
saveListEntryResource(innerEntryComponent)
}
}
else -> saveListEntryResource(entryComponent)
}
}
}
Expand All @@ -406,6 +422,14 @@ constructor(
}
}

private suspend fun saveListEntryResource(entryComponent: BundleEntryComponent) {

addOrUpdate(entryComponent.resource)
Timber.d(
"Fetched and processed List reference ${entryComponent.resource.resourceType}/${entryComponent.resource.id}"
)
}

/**
* Using this [FhirEngine] and [DispatcherProvider], update this stored resources with the passed
* resource, or create it if not found.
Expand Down Expand Up @@ -447,5 +471,6 @@ constructor(
const val CONFIG_SUFFIX = "_config"
const val ICON_PREFIX = "ic_"
const val MANIFEST_PROCESSOR_BATCH_SIZE = 30
const val FHIR_GATEWAY_MODE_HEADER_VALUE = "list-entries"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ class FhirResourceDataSource @Inject constructor(private val resourceService: Fh
suspend fun getResource(path: String): Bundle {
return resourceService.getResource(path)
}
suspend fun getResourceWithGatewayModeHeader(
gatewayModeHeaderValue: String,
path: String
): Bundle {
return resourceService.getResourceWithGatewayModeHeader(gatewayModeHeaderValue, path)
}

suspend fun insert(resourceType: String, resourceId: String, payload: String): Resource {
return resourceService.insertResource(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import retrofit2.Retrofit
import retrofit2.http.Body
import retrofit2.http.DELETE
import retrofit2.http.GET
import retrofit2.http.Header
import retrofit2.http.PATCH
import retrofit2.http.PUT
import retrofit2.http.Path
Expand All @@ -35,6 +36,11 @@ import retrofit2.http.Url
interface FhirResourceService {

@GET suspend fun getResource(@Url url: String): Bundle
@GET
suspend fun getResourceWithGatewayModeHeader(
@Header("FHIR-Gateway-Mode") fhirGatewayMode: String? = null,
@Url url: String
): Bundle

@PUT("{resourceType}/{id}")
suspend fun insertResource(
Expand Down
95 changes: 95 additions & 0 deletions android/engine/src/test/assets/sample_commodities_list_bundle.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
{
"resourceType": "Bundle",
"id": "the-commodities-bundle-id",
"type": "batch-response",
"link": [
{
"relation": "self",
"url": "http://test-localhost.local"
}
],
"entry": [
{
"resource": {
"resourceType": "Group",
"id": "1000001",
"type": "medication",
"code": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "1000002",
"display": "Supply management"
}
]
},
"name": "Albendazole 400mg Tablets",
"characteristic": [
{
"code": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "1000003",
"display": "Unit of measure"
}
]
},
"valueCodeableConcept": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "100004",
"display": "Unit"
}
],
"text": "Tablets"
},
"exclude": true
}
]
}
},
{
"resource": {
"resourceType": "Group",
"id": "2000001",
"type": "medication",
"code": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "2000002",
"display": "Supply management"
}
]
},
"name": "Albendazole 400mg Tablets",
"characteristic": [
{
"code": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "2000003",
"display": "Unit of measure"
}
]
},
"valueCodeableConcept": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "200004",
"display": "Unit"
}
],
"text": "Capsules"
},
"exclude": true
}
]
}
}
]
}
Loading

0 comments on commit d645c8b

Please sign in to comment.