diff --git a/workflow/src/main/java/com/google/android/fhir/workflow/FhirEngineR4MeasureProcessor.java b/workflow/src/main/java/com/google/android/fhir/workflow/FhirEngineR4MeasureProcessor.java new file mode 100644 index 0000000000..72bb431772 --- /dev/null +++ b/workflow/src/main/java/com/google/android/fhir/workflow/FhirEngineR4MeasureProcessor.java @@ -0,0 +1,29 @@ +package com.google.android.fhir.workflow; + +import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.r4.model.Measure; +import org.hl7.fhir.r4.model.MeasureReport; +import org.hl7.fhir.r4.model.Parameters; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.opencds.cqf.fhir.api.Repository; +import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions; +import org.opencds.cqf.fhir.cr.measure.common.MeasureEvalType; +import org.opencds.cqf.fhir.cr.measure.common.SubjectProvider; +import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureProcessor; + +import java.util.List; + +public class FhirEngineR4MeasureProcessor extends R4MeasureProcessor { + public FhirEngineR4MeasureProcessor(Repository repository, MeasureEvaluationOptions measureEvaluationOptions) { + super(repository, measureEvaluationOptions); + } + + public FhirEngineR4MeasureProcessor(Repository repository, MeasureEvaluationOptions measureEvaluationOptions, SubjectProvider subjectProvider) { + super(repository, measureEvaluationOptions, subjectProvider); + } + + public MeasureReport evaluateMeasure(Measure measure, String periodStart, String periodEnd, String reportType, List subjectIds, IBaseBundle additionalData, Parameters parameters, MeasureEvalType evalType) { + return super.evaluateMeasure(measure, periodStart, periodEnd, reportType, subjectIds, additionalData, parameters, evalType); + } +} diff --git a/workflow/src/main/java/com/google/android/fhir/workflow/FhirOperator.kt b/workflow/src/main/java/com/google/android/fhir/workflow/FhirOperator.kt index 7ccdc1aea3..163f274af6 100644 --- a/workflow/src/main/java/com/google/android/fhir/workflow/FhirOperator.kt +++ b/workflow/src/main/java/com/google/android/fhir/workflow/FhirOperator.kt @@ -31,6 +31,7 @@ import org.hl7.fhir.instance.model.api.IBaseParameters import org.hl7.fhir.instance.model.api.IBaseResource import org.hl7.fhir.r4.model.CanonicalType import org.hl7.fhir.r4.model.IdType +import org.hl7.fhir.r4.model.Measure import org.hl7.fhir.r4.model.MeasureReport import org.hl7.fhir.r4.model.Parameters import org.hl7.fhir.r4.model.PlanDefinition @@ -38,8 +39,8 @@ import org.hl7.fhir.r4.model.Reference import org.opencds.cqf.fhir.cql.EvaluationSettings import org.opencds.cqf.fhir.cql.LibraryEngine import org.opencds.cqf.fhir.cr.measure.MeasureEvaluationOptions +import org.opencds.cqf.fhir.cr.measure.common.MeasureEvalType import org.opencds.cqf.fhir.cr.measure.common.MeasureReportType -import org.opencds.cqf.fhir.cr.measure.r4.R4MeasureProcessor import org.opencds.cqf.fhir.cr.plandefinition.PlanDefinitionProcessor import org.opencds.cqf.fhir.utility.monad.Eithers import org.opencds.cqf.fhir.utility.repository.ProxyRepository @@ -72,8 +73,8 @@ internal constructor( MeasureEvaluationOptions().apply { evaluationSettings = this@FhirOperator.evaluationSettings } private val libraryProcessor = LibraryEngine(repository, evaluationSettings) + private val measureProcessor = FhirEngineR4MeasureProcessor(repository, measureEvaluationOptions) private val planDefinitionProcessor = PlanDefinitionProcessor(repository, evaluationSettings) - private val measureProcessor = R4MeasureProcessor(repository, measureEvaluationOptions) /** * The function evaluates a FHIR library against the database. @@ -154,6 +155,58 @@ internal constructor( return report } + @WorkerThread + fun evaluateMeasure( + measure: Measure, + start: String, + end: String, + reportType: String, + subjectId: String? = null, + practitioner: String? = null, + additionalData: IBaseBundle? = null, + parameters: Parameters? = null, + ): MeasureReport { + val subject = + if (!practitioner.isNullOrBlank()) { + checkAndAddType(practitioner, "Practitioner") + } else if (!subjectId.isNullOrBlank()) { + checkAndAddType(subjectId, "Patient") + } else { + // List of null is required to run population-level measures + null + } + + val subjectIds = if (subject == null) listOf() else listOf(subject) + + val evalType = + MeasureEvalType.fromCode(reportType) + .orElse( + if (subjectIds.isNotEmpty()) { + MeasureEvalType.SUBJECT + } else { + MeasureEvalType.POPULATION + }, + ) as MeasureEvalType + + val report = + measureProcessor.evaluateMeasure( + /* measure = */ measure, + /* periodStart = */ start, + /* periodEnd = */ end, + /* reportType = */ reportType, + /* subjectIds = */ subjectIds, + /* additionalData = */ additionalData, + /* parameters = */ parameters, + /* evalType = */ evalType, + ) + + // add subject reference for non-individual reportTypes + if (report.type.name == MeasureReportType.SUMMARY.name && !subject.isNullOrBlank()) { + report.setSubject(Reference(subject)) + } + return report + } + /** * Generates a [CarePlan] based on the provided inputs. *