001package ca.uhn.fhir.cql.dstu3.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.dstu3.evaluation.MeasureEvaluation; 027import ca.uhn.fhir.cql.dstu3.evaluation.MeasureEvaluationSeed; 028import ca.uhn.fhir.cql.dstu3.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.dstu3.model.Extension; 038import org.hl7.fhir.dstu3.model.IdType; 039import org.hl7.fhir.dstu3.model.Library; 040import org.hl7.fhir.dstu3.model.Measure; 041import org.hl7.fhir.dstu3.model.MeasureReport; 042import org.hl7.fhir.dstu3.model.StringType; 043import org.hl7.fhir.exceptions.FHIRException; 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 dstu3 $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/STU3/measure-operations.html#evaluate-measure">https://hl7.org/fhir/STU3/measure-operations.html#evaluate-measure</a> 054 */ 055@Component 056public class MeasureOperationsProvider { 057 @Autowired 058 private LibraryResolutionProvider<Library> libraryResolutionProvider; 059 @Autowired 060 private DaoRegistry registry; 061 @Autowired 062 private IFhirResourceDao<Measure> myMeasureDao; 063 @Autowired 064 private EvaluationProviderFactory factory; 065 @Autowired 066 private LibraryHelper libraryHelper; 067 068 /* 069 * 070 * NOTE that the source, user, and pass parameters are not standard parameters 071 * for the FHIR $evaluate-measure operation 072 * 073 */ 074 @Operation(name = ProviderConstants.CQL_EVALUATE_MEASURE, idempotent = true, type = Measure.class) 075 public MeasureReport evaluateMeasure(@IdParam IdType theId, 076 @OperationParam(name = "periodStart") String periodStart, 077 @OperationParam(name = "periodEnd") String periodEnd, 078 @OperationParam(name = "measure") String measureRef, 079 @OperationParam(name = "reportType") String reportType, 080 @OperationParam(name = "patient") String patientRef, 081 @OperationParam(name = "productLine") String productLine, 082 @OperationParam(name = "practitioner") String practitionerRef, 083 @OperationParam(name = "lastReceivedOn") String lastReceivedOn, 084 @OperationParam(name = "source") String source, 085 @OperationParam(name = "user") String user, 086 @OperationParam(name = "pass") String pass, 087 RequestDetails theRequestDetails) throws InternalErrorException, FHIRException { 088 LibraryLoader libraryLoader = this.libraryHelper.createLibraryLoader(this.libraryResolutionProvider); 089 MeasureEvaluationSeed seed = new MeasureEvaluationSeed(this.factory, libraryLoader, 090 this.libraryResolutionProvider, this.libraryHelper); 091 Measure measure = myMeasureDao.read(theId, theRequestDetails); 092 093 if (measure == null) { 094 throw new RuntimeException(Msg.code(1639) + "Could not find Measure/" + theId.getIdPart()); 095 } 096 097 seed.setup(measure, periodStart, periodEnd, productLine, source, user, pass, theRequestDetails); 098 099 // resolve report type 100 MeasureEvaluation evaluator = new MeasureEvaluation(this.registry, 101 seed.getMeasurementPeriod()); 102 if (reportType != null) { 103 switch (reportType) { 104 case "patient": 105 return evaluator.evaluatePatientMeasure(seed.getMeasure(), seed.getContext(), patientRef, theRequestDetails); 106 case "patient-list": 107 return evaluator.evaluatePatientListMeasure(seed.getMeasure(), seed.getContext(), practitionerRef, theRequestDetails); 108 case "population": 109 return evaluator.evaluatePopulationMeasure(seed.getMeasure(), seed.getContext(), theRequestDetails); 110 default: 111 throw new IllegalArgumentException(Msg.code(1640) + "Invalid report type: " + reportType); 112 } 113 } 114 115 // default report type is patient 116 MeasureReport report = evaluator.evaluatePatientMeasure(seed.getMeasure(), seed.getContext(), patientRef, theRequestDetails); 117 if (productLine != null) { 118 Extension ext = new Extension(); 119 ext.setUrl("http://hl7.org/fhir/us/cqframework/cqfmeasures/StructureDefinition/cqfm-productLine"); 120 ext.setValue(new StringType(productLine)); 121 report.addExtension(ext); 122 } 123 124 return report; 125 } 126}