Skip to content

Commit

Permalink
Add support for additional data during CQL evaluation (google#2420)
Browse files Browse the repository at this point in the history
* Add support for additional data during CQL evaluation

* Add unit test

* Fix failing tests ✅

* Spotless Apply
- Ignore white spaces on XML diff assertion

* Refactor + Clean up build 💚

* Add default values for nullable params

* Spotless clean

* Collapse all overloaded FhirOperator evaluateLibrary functions to one

* Fix build 💚

* Update test data ✅

* Fix failing benchmark test ✅

---------

Co-authored-by: Jing Tang <[email protected]>
  • Loading branch information
ndegwamartin and jingtang10 authored Mar 22, 2024
1 parent bb19c19 commit a4f5f0f
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 106 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@
"doseNumberPositiveInt": 2,
"seriesDosesPositiveInt": 2
}
]
],
"location": {
"reference": "Location/nairobi-047"
}
}
}
]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2023 Google LLC
* Copyright 2022-2024 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 @@ -71,7 +71,7 @@ class D_FhirJsonParserBenchmark {
val fhirHelpersLibrary = jsonParser.parseResource(fhirHelpersJson) as Library

assertThat(immunityCheckLibrary.id).isEqualTo("Library/ImmunityCheck-1.0.0")
assertThat(immunityCheckLibrary.content[0].data.size).isEqualTo(575)
assertThat(immunityCheckLibrary.content[0].data.size).isEqualTo(810)
assertThat(fhirHelpersLibrary.id).isEqualTo("Library/FHIRHelpers-4.0.1")
assertThat(fhirHelpersLibrary.content[0].data.size).isEqualTo(17845)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2023 Google LLC
* Copyright 2022-2024 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 @@ -84,9 +84,9 @@ class F_CqlEvaluatorBenchmark {

val results =
fhirOperator.evaluateLibrary(
"http://localhost/Library/ImmunityCheck|1.0.0",
"d4d35004-24f8-40e4-8084-1ad75924514f",
setOf("CompletedImmunization"),
libraryUrl = "http://localhost/Library/ImmunityCheck|1.0.0",
patientId = "d4d35004-24f8-40e4-8084-1ad75924514f",
expressions = setOf("CompletedImmunization"),
) as Parameters

assertThat(results.getParameterBool("CompletedImmunization")).isTrue()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import kotlinx.coroutines.runBlocking
import org.hl7.fhir.instance.model.api.IBaseResource
import org.hl7.fhir.r4.model.Bundle
import org.hl7.fhir.r4.model.Library
import org.hl7.fhir.r4.model.Location
import org.hl7.fhir.r4.model.Parameters
import org.junit.Before
import org.junit.Rule
Expand Down Expand Up @@ -122,15 +123,58 @@ class FhirOperatorLibraryEvaluateTest {
// Load Library that checks if Patient has taken a vaccine
knowledgeManager.install(copy("/immunity-check/ImmunityCheck.json"))

// Evaluates a specific Patient
val results =
fhirOperator.evaluateLibrary(
libraryUrl = "http://localhost/Library/ImmunityCheck|1.0.0",
patientId = "d4d35004-24f8-40e4-8084-1ad75924514f",
expressions = setOf("CompletedImmunization"),
) as Parameters

assertThat(results.getParameterBool("CompletedImmunization")).isTrue()
}

@Test
fun evaluateImmunityCheckWithAdditionalData() = runBlocking {
val patientImmunizationHistory = load("/immunity-check/ImmunizationHistory.json") as Bundle
for (entry in patientImmunizationHistory.entry) {
fhirEngine.create(entry.resource)
}

// Load Library that checks if Patient has taken a vaccine
knowledgeManager.install(copy("/immunity-check/ImmunityCheck.json"))
knowledgeManager.install(copy("/immunity-check/FhirHelpers.json"))

val location =
"""
{
"resourceType": "Location",
"id": "nairobi-047",
"name": "Nairobi mobile clinic"
}
"""
.trimIndent()

val additionalDataBundle =
Bundle().apply {
addEntry(
Bundle.BundleEntryComponent().apply {
resource = jsonParser.parseResource(location) as Location
},
)
}

// Evaluates a specific Patient
val results =
fhirOperator.evaluateLibrary(
"http://localhost/Library/ImmunityCheck|1.0.0",
"d4d35004-24f8-40e4-8084-1ad75924514f",
setOf("CompletedImmunization"),
null,
additionalDataBundle,
null,
) as Parameters

assertThat(results.getParameterBool("CompletedImmunization")).isTrue()
assertThat(results.hasParameter("GetFinalDoseWithLocationData")).isTrue()
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,70 +71,6 @@ internal constructor(
private val measureProcessor = R4MeasureProcessor(repository, measureEvaluationOptions)
private val planDefinitionProcessor = PlanDefinitionProcessor(repository, evaluationSettings)

/**
* The function evaluates a FHIR library against the database.
*
* NOTE: The API may internally result in a blocking IO operation. The user should call the API
* from a worker thread or it may throw [BlockingMainThreadException] exception.
*
* @param libraryUrl the url of the Library to evaluate
* @param expressions names of expressions in the Library to evaluate. If null the result contains
* all evaluations or variables in library.
* @return a Parameters resource that contains an evaluation result for each expression requested.
* Or if expressions param is null then result contains all evaluations or variables in given
* library.
*/
@WorkerThread
fun evaluateLibrary(libraryUrl: String, expressions: Set<String>?): IBaseParameters {
return evaluateLibrary(libraryUrl, null, null, expressions)
}

/**
* The function evaluates a FHIR library against a patient's records.
*
* NOTE: The API may internally result in a blocking IO operation. The user should call the API
* from a worker thread or it may throw [BlockingMainThreadException] exception.
*
* @param libraryUrl the url of the Library to evaluate
* @param patientId the Id of the patient to be evaluated
* @param expressions names of expressions in the Library to evaluate. If null the result contains
* all evaluations or variables in library.
* @return a Parameters resource that contains an evaluation result for each expression requested.
* Or if expressions param is null then result contains all evaluations or variables in given
* library.
*/
@WorkerThread
fun evaluateLibrary(
libraryUrl: String,
patientId: String,
expressions: Set<String>?,
): IBaseParameters {
return evaluateLibrary(libraryUrl, patientId, null, expressions)
}

/**
* The function evaluates a FHIR library against the database.
*
* NOTE: The API may internally result in a blocking IO operation. The user should call the API
* from a worker thread or it may throw [BlockingMainThreadException] exception.
*
* @param libraryUrl the url of the Library to evaluate
* @param parameters list of parameters to be passed to the CQL library
* @param expressions names of expressions in the Library to evaluate. If null the result contains
* all evaluations or variables in library.
* @return a Parameters resource that contains an evaluation result for each expression requested.
* Or if expressions param is null then result contains all evaluations or variables in given
* library.
*/
@WorkerThread
fun evaluateLibrary(
libraryUrl: String,
parameters: Parameters,
expressions: Set<String>?,
): IBaseParameters {
return evaluateLibrary(libraryUrl, null, parameters, expressions)
}

/**
* The function evaluates a FHIR library against the database.
*
Expand All @@ -144,6 +80,8 @@ internal constructor(
* @param libraryUrl the url of the Library to evaluate
* @param patientId the Id of the patient to be evaluated, if applicable
* @param parameters list of parameters to be passed to the CQL library, if applicable
* @param additionalData Bundle of additional resources to be passed to the CQL library, if
* applicable
* @param expressions names of expressions in the Library to evaluate. If null the result contains
* all evaluations or variables in library.
* @return a Parameters resource that contains an evaluation result for each expression requested.
Expand All @@ -153,15 +91,16 @@ internal constructor(
@WorkerThread
fun evaluateLibrary(
libraryUrl: String,
patientId: String?,
parameters: Parameters?,
expressions: Set<String>?,
patientId: String? = null,
parameters: Parameters? = null,
additionalData: IBaseBundle? = null,
expressions: Set<String>? = null,
): IBaseParameters {
return libraryProcessor.evaluate(
/* url = */ libraryUrl,
/* patientId = */ patientId,
/* parameters = */ parameters,
/* additionalData = */ null,
/* additionalData = */ additionalData,
/* expressions = */ expressions,
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2023 Google LLC
* Copyright 2022-2024 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 @@ -116,9 +116,9 @@ class FhirOperatorLibraryEvaluateJavaTest {
// Evaluates a specific Patient
val results =
fhirOperator.evaluateLibrary(
"http://localhost/Library/ImmunityCheck|1.0.0",
"d4d35004-24f8-40e4-8084-1ad75924514f",
setOf("CompletedImmunization"),
libraryUrl = "http://localhost/Library/ImmunityCheck|1.0.0",
patientId = "d4d35004-24f8-40e4-8084-1ad75924514f",
expressions = setOf("CompletedImmunization"),
) as Parameters

assertThat(results.getParameterBool("CompletedImmunization")).isTrue()
Expand All @@ -140,7 +140,9 @@ class FhirOperatorLibraryEvaluateJavaTest {
knowledgeManager.install(writeToFile(library))

// Evaluates expression without any extra data
val results = fhirOperator.evaluateLibrary(library.url, setOf("GetName")) as Parameters
val results =
fhirOperator.evaluateLibrary(libraryUrl = library.url, expressions = setOf("GetName"))
as Parameters

assertThat((results.parameterFirstRep.value as StringType).value).isEqualTo("MyName")
}
Expand Down Expand Up @@ -171,7 +173,12 @@ class FhirOperatorLibraryEvaluateJavaTest {
}

// Evaluates the library with a parameter
val results = fhirOperator.evaluateLibrary(library.url, params, setOf("SumOne")) as Parameters
val results =
fhirOperator.evaluateLibrary(
libraryUrl = library.url,
parameters = params,
expressions = setOf("SumOne"),
) as Parameters

assertThat((results.parameterFirstRep.value as DecimalType).value).isEqualTo(BigDecimal(2))
}
Expand Down

0 comments on commit a4f5f0f

Please sign in to comment.