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

Overrides Ids when installing an IG #2264

Merged
merged 9 commits into from
Oct 19, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ import com.google.android.fhir.knowledge.npm.NpmPackageDownloader
import com.google.android.fhir.knowledge.npm.OkHttpNpmPackageDownloader
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.hl7.fhir.instance.model.api.IBaseResource
import org.hl7.fhir.r4.model.IdType
import org.hl7.fhir.r4.model.MetadataResource
import org.hl7.fhir.r4.model.Resource
import org.hl7.fhir.r4.model.ResourceType
Expand Down Expand Up @@ -95,7 +97,13 @@ internal constructor(
try {
val resource = jsonParser.parseResource(FileInputStream(file))
if (resource is Resource) {
importResource(igId, resource, file)
val newId = importResource(igId, resource, file)
resource.setId(IdType(resource.resourceType.name, newId))

// Overrides the Id in the file
FileOutputStream(file).use {
it.write(jsonParser.encodeResourceToString(resource).toByteArray())
}
vitorpamplona marked this conversation as resolved.
Show resolved Hide resolved
} else {
Timber.d("Unable to import file: %file")
}
Expand Down Expand Up @@ -124,7 +132,7 @@ internal constructor(
url != null && version != null ->
listOfNotNull(knowledgeDao.getResourceWithUrlAndVersion(url, version))
url != null -> listOfNotNull(knowledgeDao.getResourceWithUrl(url))
id != null -> listOfNotNull(knowledgeDao.getResourceWithUrlLike("%$id"))
id != null -> listOfNotNull(knowledgeDao.getResourcesWithId(resType, id.toLong()))
vitorpamplona marked this conversation as resolved.
Show resolved Hide resolved
name != null && version != null ->
listOfNotNull(knowledgeDao.getResourcesWithNameAndVersion(resType, name, version))
name != null -> knowledgeDao.getResourcesWithName(resType, name)
Expand Down Expand Up @@ -154,11 +162,19 @@ internal constructor(
}
}
when (resource) {
is Resource -> importResource(igId, resource, file)
is Resource -> {
vitorpamplona marked this conversation as resolved.
Show resolved Hide resolved
val newId = importResource(igId, resource, file)
resource.setId(IdType(resource.resourceType.name, newId))

// Overrides the Id in the file
FileOutputStream(file).use {
it.write(jsonParser.encodeResourceToString(resource).toByteArray())
}
}
}
}

private suspend fun importResource(igId: Long?, resource: Resource, file: File) {
private suspend fun importResource(igId: Long?, resource: Resource, file: File): Long {
val metadataResource = resource as? MetadataResource
val res =
ResourceMetadataEntity(
Expand All @@ -169,7 +185,8 @@ internal constructor(
metadataResource?.version,
file,
)
knowledgeDao.insertResource(igId, res)

return knowledgeDao.insertResource(igId, res)
}

private fun loadResource(resourceEntity: ResourceMetadataEntity): IBaseResource {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ abstract class KnowledgeDao {
internal open suspend fun insertResource(
implementationGuideId: Long?,
resource: ResourceMetadataEntity,
) {
): Long {
val resourceMetadata =
if (resource.url != null && resource.version != null) {
getResourceWithUrlAndVersion(resource.url, resource.version)
Expand All @@ -48,6 +48,7 @@ abstract class KnowledgeDao {
// exception if they are different.
val resourceMetadataId = resourceMetadata?.resourceMetadataId ?: insert(resource)
insert(ImplementationGuideResourceMetadataEntity(0, implementationGuideId, resourceMetadataId))
return resourceMetadataId
}

@Transaction
Expand Down Expand Up @@ -108,6 +109,14 @@ abstract class KnowledgeDao {
name: String?,
): List<ResourceMetadataEntity>

@Query(
"SELECT * from ResourceMetadataEntity WHERE resourceType = :resourceType AND resourceMetadataId = :id",
)
internal abstract suspend fun getResourcesWithId(
resourceType: ResourceType,
id: Long?,
): ResourceMetadataEntity?

vitorpamplona marked this conversation as resolved.
Show resolved Hide resolved
@Query(
"SELECT * from ResourceMetadataEntity WHERE resourceType = :resourceType AND name = :name AND version = :version",
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,14 @@ internal class KnowledgeManagerTest {
fun `inserting a library of a different version creates new entry`() = runTest {
val libraryAOld =
Library().apply {
id = "defaultA"
id = "Library/defaultA-A.1.0.0"
name = "defaultA"
url = "www.exampleA.com"
version = "A.1.0.0"
}
val libraryANew =
Library().apply {
id = "defaultA"
id = "Library/defaultA-A.1.0.1"
name = "defaultA"
url = "www.exampleA.com"
version = "A.1.0.1"
Expand All @@ -131,6 +131,18 @@ internal class KnowledgeManagerTest {

val resources = knowledgeDb.knowledgeDao().getResources()
assertThat(resources).hasSize(2)

val resourceA100 =
knowledgeManager
.loadResources(resourceType = "Library", name = "defaultA", version = "A.1.0.0")
.single()
assertThat(resourceA100.idElement.toString()).isEqualTo("Library/1")

val resourceA101 =
knowledgeManager
.loadResources(resourceType = "Library", name = "defaultA", version = "A.1.0.1")
.single()
assertThat(resourceA101.idElement.toString()).isEqualTo("Library/2")
}

fun `installing from npmPackageManager`() = runTest {
Expand All @@ -153,7 +165,8 @@ internal class KnowledgeManagerTest {
}

private fun writeToFile(library: Library): File {
return File(context.filesDir, library.name).apply {
return File(context.filesDir, library.id).apply {
this.parentFile?.mkdirs()
writeText(jsonParser.encodeResourceToString(library))
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"resourceType": "CarePlan",
"id": "Plan-Definition-Example",
"id": "17",
"contained": [ {
"resourceType": "RequestGroup",
"id": "Plan-Definition-Example",
"id": "17",
"instantiatesCanonical": [ "http://example.com/PlanDefinition/Plan-Definition-Example" ],
"status": "draft",
"intent": "proposal",
Expand All @@ -20,12 +20,12 @@
}
} ],
"resource": {
"reference": "Task/Activity-Example"
"reference": "Task/16"
}
} ]
}, {
"resourceType": "Task",
"id": "Activity-Example",
"id": "16",
"extension": [ {
"url": "http://hl7.org/fhir/aphl/StructureDefinition/condition",
"valueExpression": {
Expand All @@ -35,7 +35,7 @@
} ],
"instantiatesCanonical": "http://example.com/ActivityDefinition/Activity-Example",
"basedOn": [ {
"reference": "#RequestGroup/Plan-Definition-Example",
"reference": "#RequestGroup/17",
"type": "RequestGroup"
} ],
"status": "draft",
Expand All @@ -53,7 +53,7 @@
},
"activity": [ {
"reference": {
"reference": "#RequestGroup/Plan-Definition-Example"
"reference": "#RequestGroup/17"
}
} ]
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"resourceType": "CarePlan",
"id": "MedRequest-Example",
"id": "17",
"contained": [
{
"resourceType": "RequestGroup",
"id": "MedRequest-Example",
"id": "17",
"instantiatesCanonical": [
"http://localhost/PlanDefinition/MedRequest-Example"
],
Expand All @@ -18,14 +18,14 @@
"id": "medication-action-1",
"title": "Administer Medication 1",
"resource": {
"reference": "MedicationRequest/MedicationRequest-1"
"reference": "MedicationRequest/16"
}
}
]
},
{
"resourceType": "MedicationRequest",
"id": "MedicationRequest-1",
"id": "16",
"status": "draft",
"intent": "order",
"medicationCodeableConcept": {
Expand All @@ -50,7 +50,7 @@
"activity": [
{
"reference": {
"reference": "#RequestGroup/MedRequest-Example"
"reference": "#RequestGroup/17"
}
}
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,11 @@ internal constructor(
return generateCarePlan(planDefinitionId, patientId, encounterId = null)
}

@WorkerThread
vitorpamplona marked this conversation as resolved.
Show resolved Hide resolved
fun generateCarePlan(planDefinition: CanonicalType, patientId: String): IBaseResource {
return generateCarePlan(planDefinition, patientId, encounterId = null)
}

/**
* Generates a [CarePlan] based on the provided inputs.
*
Expand Down Expand Up @@ -222,6 +227,33 @@ internal constructor(
) as IBaseResource
}

@WorkerThread
fun generateCarePlan(
planDefinition: CanonicalType,
patientId: String,
encounterId: String?,
): IBaseResource {
return planDefinitionProcessor.apply(
/* id = */ null,
/* canonical = */ planDefinition,
/* planDefinition = */ null,
/* subject = */ patientId,
/* encounterId = */ encounterId,
/* practitionerId = */ null,
/* organizationId = */ null,
/* userType = */ null,
/* userLanguage = */ null,
/* userTaskContext = */ null,
/* setting = */ null,
/* settingContext = */ null,
/* parameters = */ null,
/* useServerData = */ null,
/* bundle = */ null,
/* prefetchData = */ null,
libraryProcessor,
) as IBaseResource
}

class Builder(private val applicationContext: Context) {
private var fhirContext: FhirContext? = null
private var fhirEngine: FhirEngine? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import java.lang.IllegalArgumentException
import java.util.TimeZone
import kotlin.reflect.KSuspendFunction1
import org.hl7.fhir.r4.model.Bundle
import org.hl7.fhir.r4.model.CanonicalType
import org.hl7.fhir.r4.model.Library
import org.hl7.fhir.r4.model.MetadataResource
import org.hl7.fhir.r4.model.Resource
Expand Down Expand Up @@ -98,7 +99,10 @@ class FhirOperatorTest {

assertThat(
fhirOperator.generateCarePlan(
planDefinitionId = "plandefinition-RuleFilters-1.0.0",
planDefinition =
CanonicalType(
"http://hl7.org/fhir/us/ecr/PlanDefinition/plandefinition-RuleFilters-1.0.0",
),
patientId = "Reportable",
encounterId = "reportable-encounter",
),
Expand All @@ -113,12 +117,10 @@ class FhirOperatorTest {

val carePlan =
fhirOperator.generateCarePlan(
planDefinitionId = "MedRequest-Example",
planDefinition = CanonicalType("http://localhost/PlanDefinition/MedRequest-Example"),
patientId = "Patient/Patient-Example",
)

println(jsonParser.encodeResourceToString(carePlan))

assertEquals(
readResourceAsString("/plan-definition/med-request/med_request_careplan.json"),
jsonParser.encodeResourceToString(carePlan),
Expand All @@ -137,7 +139,7 @@ class FhirOperatorTest {

val carePlan =
fhirOperator.generateCarePlan(
planDefinitionId = "Plan-Definition-Example",
planDefinition = CanonicalType("http://example.com/PlanDefinition/Plan-Definition-Example"),
patientId = "Patient/Female-Patient-Example",
)

Expand Down Expand Up @@ -287,11 +289,16 @@ class FhirOperatorTest {
private fun writeToFile(resource: Resource): File {
val fileName =
if (resource is MetadataResource && resource.name != null) {
resource.name
if (resource.version != null) {
resource.name + "-" + resource.version
} else {
resource.name
}
} else {
resource.idElement.idPart
resource.idElement.toString()
}
return File(context.filesDir, fileName).apply {
this.parentFile.mkdirs()
writeText(jsonParser.encodeResourceToString(resource))
}
}
Expand Down