Skip to content

Commit

Permalink
Library evaluation provider into CR (#394)
Browse files Browse the repository at this point in the history
* library evaluate provider

* testing for library evaluate and cql evaluate

* removing file errors

* more test coverage, update class names
  • Loading branch information
Capt-Mac authored Dec 21, 2023
1 parent 6ee71b7 commit 16f8f32
Show file tree
Hide file tree
Showing 16 changed files with 803 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.opencds.cqf.fhir.cr.cql;
package org.opencds.cqf.fhir.cr.cpg;

import ca.uhn.fhir.context.FhirVersionEnum;
import java.util.ArrayList;
Expand Down Expand Up @@ -88,4 +88,8 @@ public IBaseOperationOutcome createIssue(String severity, String details, Reposi
.setDetails(new org.hl7.fhir.r4.model.CodeableConcept().setText(details)));
}
}

// expressionEvaluator
// libraryEvaluator

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.opencds.cqf.fhir.cr.cql.r4;
package org.opencds.cqf.fhir.cr.cpg.r4;

import static org.opencds.cqf.fhir.utility.r4.Parameters.parameters;
import static org.opencds.cqf.fhir.utility.r4.Parameters.part;
Expand All @@ -15,7 +15,7 @@
import org.opencds.cqf.fhir.cql.Engines;
import org.opencds.cqf.fhir.cql.EvaluationSettings;
import org.opencds.cqf.fhir.cql.LibraryEngine;
import org.opencds.cqf.fhir.cr.cql.BaseCqlExecutionProcessor;
import org.opencds.cqf.fhir.cr.cpg.BaseCqlExecutionProcessor;
import org.opencds.cqf.fhir.utility.repository.Repositories;

public class R4CqlExecutionService {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package org.opencds.cqf.fhir.cr.cpg.r4;

import static org.opencds.cqf.fhir.utility.r4.Parameters.parameters;
import static org.opencds.cqf.fhir.utility.r4.Parameters.part;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Endpoint;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Library;
import org.hl7.fhir.r4.model.OperationOutcome;
import org.hl7.fhir.r4.model.Parameters;
import org.opencds.cqf.fhir.api.Repository;
import org.opencds.cqf.fhir.cql.Engines;
import org.opencds.cqf.fhir.cql.EvaluationSettings;
import org.opencds.cqf.fhir.cql.LibraryEngine;
import org.opencds.cqf.fhir.cr.cpg.BaseCqlExecutionProcessor;
import org.opencds.cqf.fhir.utility.repository.Repositories;

public class R4LibraryEvaluationService {

protected Repository repository;
protected EvaluationSettings evaluationSettings;

public R4LibraryEvaluationService(Repository repository, EvaluationSettings evaluationSettings) {
this.repository = repository;
this.evaluationSettings = evaluationSettings;
}

public Parameters evaluate(
IdType theId,
String subject,
List<String> expression,
Parameters parameters,
Bundle data,
List<Parameters> prefetchData,
Endpoint dataEndpoint,
Endpoint contentEndpoint,
Endpoint terminologyEndpoint) {

var baseCqlExecutionProcessor = new BaseCqlExecutionProcessor();

if (prefetchData != null) {
return parameters(part("invalid parameters", (OperationOutcome)
baseCqlExecutionProcessor.createIssue("warning", "prefetchData is not yet supported", repository)));
}

if (contentEndpoint != null) {
repository = Repositories.proxy(repository, dataEndpoint, contentEndpoint, terminologyEndpoint);
}
var libraryEngine = new LibraryEngine(repository, this.evaluationSettings);
var library = repository.read(Library.class, theId);
var engine = Engines.forRepositoryAndSettings(evaluationSettings, repository, data);
var libraryManager = engine.getEnvironment().getLibraryManager();
var libraryIdentifier = baseCqlExecutionProcessor.resolveLibraryIdentifier(null, library, libraryManager);

Set<String> expressionSet = null;
if (expression != null) {
expressionSet = new HashSet<>(expression);
}
try {
return (Parameters) libraryEngine.evaluate(libraryIdentifier, subject, parameters, data, expressionSet);
} catch (Exception e) {
return parameters(part("evaluation error", (OperationOutcome)
baseCqlExecutionProcessor.createIssue("error", e.getMessage(), repository)));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package org.opencds.cqf.fhir.cr.cpg.r4;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.opencds.cqf.fhir.utility.r4.Parameters.datePart;
import static org.opencds.cqf.fhir.utility.r4.Parameters.parameters;

import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.IntegerType;
import org.hl7.fhir.r4.model.OperationOutcome;
import org.hl7.fhir.r4.model.Parameters;
import org.junit.jupiter.api.Test;

public class CqlEvaluationServiceTest {
@Test
void libraryEvaluationService_inlineAsthma() {
var content = "library AsthmaTest version '1.0.0'\n" + "\n"
+ "using FHIR version '4.0.1'\n"
+ "\n"
+ "include FHIRHelpers version '4.0.1'\n"
+ "\n"
+ "codesystem \"SNOMED\": 'http://snomed.info/sct'\n"
+ "\n"
+ "code \"Asthma\": '195967001' from \"SNOMED\"\n"
+ "\n"
+ "context Patient\n"
+ "\n"
+ "define \"Asthma Diagnosis\":\n"
+ " [Condition: \"Asthma\"]\n"
+ "\n"
+ "define \"Has Asthma Diagnosis\":\n"
+ " exists(\"Asthma Diagnosis\")\n";
var when = Library.given()
.repositoryFor("libraryeval")
.when()
.subject("Patient/SimplePatient")
.content(content)
.evaluateCql();
var results = when.then().parameters();
assertTrue(results.hasParameter());
assertEquals(3, results.getParameter().size());
}

@Test
void libraryEvaluationService_contentAndExpression() {
var content = "library SimpleR4Library\n" + "\n"
+ "using FHIR version '4.0.1'\n"
+ "\n"
+ "include FHIRHelpers version '4.0.1' called FHIRHelpers\n"
+ "\n"
+ "context Patient\n"
+ "\n"
+ "define simpleBooleanExpression: true\n"
+ "\n"
+ "define observationRetrieve: [Observation]\n"
+ "\n"
+ "define observationHasCode: not IsNull(([Observation]).code)\n"
+ "\n"
+ "define \"Initial Population\": observationHasCode\n"
+ "\n"
+ "define \"Denominator\": \"Initial Population\"\n"
+ "\n"
+ "define \"Numerator\": \"Denominator\"";
var when = Library.given()
.repositoryFor("libraryeval")
.when()
.subject("Patient/SimplePatient")
.expression("Numerator")
.content(content)
.evaluateCql();
var results = when.then().parameters();
assertFalse(results.isEmpty());
assertEquals(1, results.getParameter().size());
assertTrue(results.getParameter("Numerator").getValue() instanceof BooleanType);
assertTrue(((BooleanType) results.getParameter("Numerator").getValue()).booleanValue());
;
}

@Test
void libraryEvaluationService_arithmetic() {
var when = Library.given()
.repositoryFor("libraryeval")
.when()
.expression("5*5")
.evaluateCql();
var results = when.then().parameters();
assertTrue(results.getParameter("return").getValue() instanceof IntegerType);
assertEquals("25", ((IntegerType) results.getParameter("return").getValue()).asStringValue());
}

@Test
void libraryEvaluationService_paramsAndExpression() {
Parameters evaluationParams = parameters(datePart("%inputDate", "2019-11-01"));
var when = Library.given()
.repositoryFor("libraryeval")
.when()
.subject("Patient/SimplePatient")
.parameters(evaluationParams)
.expression("year from %inputDate before 2020")
.evaluateCql();
var results = when.then().parameters();
assertTrue(results.getParameter("return").getValue() instanceof BooleanType);
assertTrue(((BooleanType) results.getParameter("return").getValue()).booleanValue());
}

@Test
void libraryEvaluationService_ErrorLibrary() {
var expression = "Interval[1,5]";
var when = Library.given()
.repositoryFor("libraryeval")
.when()
.expression(expression)
.evaluateCql();
var report = when.then().parameters();
assertTrue(report.hasParameter());
assertTrue(report.getParameterFirstRep().hasName());
assertEquals("evaluation error", report.getParameterFirstRep().getName());
assertTrue(report.getParameterFirstRep().hasResource());
assertTrue(report.getParameterFirstRep().getResource() instanceof OperationOutcome);
assertEquals(
"Unsupported interval point type for FHIR conversion java.lang.Integer",
((OperationOutcome) report.getParameterFirstRep().getResource())
.getIssueFirstRep()
.getDetails()
.getText());
}
}
Loading

0 comments on commit 16f8f32

Please sign in to comment.