001package ca.uhn.fhir.cql.r4.provider; 002 003/*- 004 * #%L 005 * HAPI FHIR JPA Server - Clinical Quality Language 006 * %% 007 * Copyright (C) 2014 - 2022 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import ca.uhn.fhir.i18n.Msg; 024import ca.uhn.fhir.cql.common.provider.EvaluationProviderFactory; 025import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider; 026import ca.uhn.fhir.cql.r4.evaluation.MeasureEvaluation; 027import ca.uhn.fhir.cql.r4.evaluation.MeasureEvaluationSeed; 028import ca.uhn.fhir.cql.r4.helper.LibraryHelper; 029import ca.uhn.fhir.jpa.api.dao.DaoRegistry; 030import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; 031import ca.uhn.fhir.rest.annotation.IdParam; 032import ca.uhn.fhir.rest.annotation.Operation; 033import ca.uhn.fhir.rest.annotation.OperationParam; 034import ca.uhn.fhir.rest.api.server.RequestDetails; 035import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; 036import ca.uhn.fhir.rest.server.provider.ProviderConstants; 037import org.hl7.fhir.exceptions.FHIRException; 038import org.hl7.fhir.r4.model.Extension; 039import org.hl7.fhir.r4.model.IdType; 040import org.hl7.fhir.r4.model.Library; 041import org.hl7.fhir.r4.model.Measure; 042import org.hl7.fhir.r4.model.MeasureReport; 043import org.hl7.fhir.r4.model.StringType; 044import org.opencds.cqf.cql.engine.execution.LibraryLoader; 045import org.springframework.beans.factory.annotation.Autowired; 046import org.springframework.stereotype.Component; 047 048/** 049 * This class implements the r4 $evaluate-measure operation defined in the FHIR Clinical Reasoning module. 050 * Changes should comply with the specification in as far as is possible, and questions about Measure or CQL evaluation can be directed to the original authors. 051 * @author Jonathan Percival 052 * @author Bryn Rhodes 053 * @see <a href="https://hl7.org/fhir/measure-operation-evaluate-measure.html">https://hl7.org/fhir/measure-operation-evaluate-measure.html</a> 054 */ 055@Component 056public class MeasureOperationsProvider { 057 @Autowired 058 private LibraryResolutionProvider<Library> libraryResolutionProvider; 059 @Autowired 060 private IFhirResourceDao<Measure> myMeasureDao; 061 @Autowired 062 private DaoRegistry registry; 063 @Autowired 064 private EvaluationProviderFactory factory; 065 @Autowired 066 private LibraryHelper libraryHelper; 067 068 069 /* 070 * 071 * NOTE that the source, user, and pass parameters are not standard parameters 072 * for the FHIR $evaluate-measure operation 073 * 074 */ 075 @Operation(name = ProviderConstants.CQL_EVALUATE_MEASURE, idempotent = true, type = Measure.class) 076 public MeasureReport evaluateMeasure(@IdParam IdType theId, 077 @OperationParam(name = "periodStart") String periodStart, 078 @OperationParam(name = "periodEnd") String periodEnd, 079 @OperationParam(name = "measure") String measureRef, 080 @OperationParam(name = "reportType") String reportType, 081 @OperationParam(name = "patient") String patientRef, 082 @OperationParam(name = "productLine") String productLine, 083 @OperationParam(name = "practitioner") String practitionerRef, 084 @OperationParam(name = "lastReceivedOn") String lastReceivedOn, 085 @OperationParam(name = "source") String source, 086 @OperationParam(name = "user") String user, 087 @OperationParam(name = "pass") String pass, 088 RequestDetails theRequestDetails) throws InternalErrorException, FHIRException { 089 LibraryLoader libraryLoader = this.libraryHelper.createLibraryLoader(this.libraryResolutionProvider); 090 091 MeasureEvaluationSeed seed = new MeasureEvaluationSeed(this.factory, libraryLoader, 092 this.libraryResolutionProvider, this.libraryHelper); 093 Measure measure = myMeasureDao.read(theId, theRequestDetails); 094 095 if (measure == null) { 096 throw new RuntimeException(Msg.code(1663) + "Could not find Measure/" + theId.getIdPart()); 097 } 098 099 seed.setup(measure, periodStart, periodEnd, productLine, source, user, pass, theRequestDetails); 100 101 // resolve report type 102 MeasureEvaluation evaluator = new MeasureEvaluation(seed.getDataProvider(), this.registry, 103 seed.getMeasurementPeriod()); 104 if (reportType != null) { 105 switch (reportType) { 106 case "patient": 107 return evaluator.evaluatePatientMeasure(seed.getMeasure(), seed.getContext(), patientRef, theRequestDetails); 108 case "patient-list": 109 return evaluator.evaluateSubjectListMeasure(seed.getMeasure(), seed.getContext(), practitionerRef, theRequestDetails); 110 case "population": 111 return evaluator.evaluatePopulationMeasure(seed.getMeasure(), seed.getContext(), theRequestDetails); 112 default: 113 throw new IllegalArgumentException(Msg.code(1664) + "Invalid report type: " + reportType); 114 } 115 } 116 117 // default report type is patient 118 MeasureReport report = evaluator.evaluatePatientMeasure(seed.getMeasure(), seed.getContext(), patientRef, theRequestDetails); 119 if (productLine != null) { 120 Extension ext = new Extension(); 121 ext.setUrl("http://hl7.org/fhir/us/cqframework/cqfmeasures/StructureDefinition/cqfm-productLine"); 122 ext.setValue(new StringType(productLine)); 123 report.addExtension(ext); 124 } 125 126 return report; 127 } 128}