Skip to content

Commit

Permalink
Merge pull request #25 from MeasureAuthoringTool/MAT-4516
Browse files Browse the repository at this point in the history
MAT-4516 include return types for all defines in elm
  • Loading branch information
adongare authored Aug 19, 2022
2 parents 57da630 + 9935757 commit 52c15c4
Show file tree
Hide file tree
Showing 6 changed files with 1,618 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.io.UncheckedIOException;

@RestController
Expand All @@ -45,6 +46,7 @@ public CqlConversionPayload cqlToElmJson(
@RequestParam(value = "disable-method-invocation", defaultValue = "false")
Boolean disableMethodInvocation,
@RequestParam(value = "validate-units", defaultValue = "true") Boolean validateUnits,
@RequestParam(value = "result-types", defaultValue = "true") Boolean resultTypes,
@RequestHeader("Authorization") String accessToken) {

RequestData requestData =
Expand All @@ -58,6 +60,7 @@ public CqlConversionPayload cqlToElmJson(
.disableListPromotion(disableListPromotion)
.disableMethodInvocation(disableMethodInvocation)
.validateUnits(validateUnits)
.resultTypes(resultTypes)
.build();

cqlConversionService.setUpLibrarySourceProvider(cqlData, accessToken);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ public class RequestData {
Boolean disableListPromotion;
Boolean disableMethodInvocation;
Boolean validateUnits;
Boolean resultTypes;

public InputStream getCqlDataInputStream() {
return new ByteArrayInputStream(cqlData.getBytes());
Expand All @@ -38,6 +39,7 @@ public MultivaluedMap<String, String> createMap() {
map.add("disable-method-invocation", disableMethodInvocation.toString());
map.add("validate-units", validateUnits.toString());
map.add("validate-units", validateUnits.toString());
map.add("result-types", resultTypes.toString());

// Enforcing detailed errors and not providing an option to Client
map.add("detailed-errors", Boolean.TRUE.toString());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
package gov.cms.mat.cql_elm_translation.controllers;

import gov.cms.mat.cql.dto.CqlConversionPayload;
import gov.cms.mat.cql_elm_translation.ResourceFileUtil;
import gov.cms.mat.cql_elm_translation.data.RequestData;
import gov.cms.mat.cql_elm_translation.service.CqlConversionService;
import gov.cms.mat.cql_elm_translation.service.MatXmlConversionService;
import org.cqframework.cql.cql2elm.CqlTranslator;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

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.mockito.ArgumentMatchers.any;

@ExtendWith(MockitoExtension.class)
class CqlConversionControllerTest implements ResourceFileUtil {
Expand All @@ -23,25 +28,21 @@ class CqlConversionControllerTest implements ResourceFileUtil {

@InjectMocks private CqlConversionController cqlConversionController;

// @Test
// void cqlToElmJson() {
// String cqlData = "cqlData";
// String result = "json-data";
// when(cqlConversionService.processCqlDataWithErrors(any())).thenReturn(result);
//
// String json = cqlConversionController.cqlToElmJson(cqlData,
// LibraryBuilder.SignatureLevel.All,
// true,
// true,
// true,
// true,
// true,
// true);
//
// assertEquals(result, json);
// verify(cqlConversionService).processCqlDataWithErrors(any());
// //verify(cqlConversionService).processQdmVersion(cqlData);
// }
@Test
void cqlToElmJson() {
String cqlData = getData("/cv_populations.cql");
String result = getData("/cv_populations.json");
CqlConversionPayload payload = CqlConversionPayload.builder().json(result).build();
Mockito.when(cqlConversionService.processCqlDataWithErrors(any(RequestData.class)))
.thenReturn(payload);

CqlConversionPayload cqlConversionPayload =
cqlConversionController.cqlToElmJson(
cqlData, null, true, true, true, true, true, true, true, true, "test");

assertEquals(result, cqlConversionPayload.getJson());
Mockito.verify(cqlConversionService).processCqlDataWithErrors(any());
}

// @Test
// void xmlToElmJson() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
package gov.cms.mat.cql_elm_translation.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import gov.cms.mat.cql.dto.CqlConversionPayload;
import gov.cms.mat.cql_elm_translation.ResourceFileUtil;
import gov.cms.mat.cql_elm_translation.data.RequestData;
import org.cqframework.cql.cql2elm.CqlTranslator;
import org.cqframework.cql.cql2elm.LibraryBuilder;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;
import java.util.Iterator;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

class CqlConversionServicePropertyTest implements ResourceFileUtil {
CqlConversionService cqlConversionService = new CqlConversionService(null);
Expand All @@ -20,6 +30,7 @@ class CqlConversionServicePropertyTest implements ResourceFileUtil {
Boolean disableListPromotion;
Boolean disableMethodInvocation;
Boolean validateUnits;
Boolean resultTypes;

@BeforeEach
public void setUp() {
Expand All @@ -30,6 +41,7 @@ public void setUp() {
disableListPromotion = Boolean.TRUE;
disableMethodInvocation = Boolean.TRUE;
validateUnits = Boolean.TRUE;
resultTypes = Boolean.TRUE;

cqlConversionService = new CqlConversionService(null);
}
Expand Down Expand Up @@ -101,6 +113,51 @@ void process_validateUnits() {
assertEquals(jsonDefault, jsonAnnotations); // NO change TODO not expected
}

@Test
void testProcessCqlDataWithErrors() throws JsonProcessingException {
cqlData = getData("/cv_populations.cql");
RequestData requestData = buildRequestData();
CqlConversionPayload cqlConversionPayload =
cqlConversionService.processCqlDataWithErrors(requestData);
String elmJson = cqlConversionPayload.getJson();
ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(elmJson);
ArrayNode defines = (ArrayNode) rootNode.get("library").get("statements").get("def");

// initial population
JsonNode ipNode = findCqlDefinitionNode("Initial Population", defines);
assertEquals(ipNode.get("resultTypeSpecifier").get("type").asText(), "ListTypeSpecifier");
assertEquals(
ipNode.get("resultTypeSpecifier").get("elementType").get("name").asText(),
"{http://hl7.org/fhir}Encounter");

// Measure Population Exclusions
JsonNode mpeNode = findCqlDefinitionNode("Measure Population Exclusions", defines);
assertEquals(mpeNode.get("resultTypeSpecifier").get("type").asText(), "ListTypeSpecifier");
assertEquals(
mpeNode.get("resultTypeSpecifier").get("elementType").get("name").asText(),
"{http://hl7.org/fhir}Encounter");

// Boolean define
JsonNode booleanNode = findCqlDefinitionNode("Unused Boolean Definition", defines);
assertEquals(booleanNode.get("resultTypeName").asText(), "{urn:hl7-org:elm-types:r1}Boolean");

// Integer type for function
JsonNode moNode = findCqlDefinitionNode("Measure Observation", defines);
assertEquals(moNode.get("resultTypeName").asText(), "{urn:hl7-org:elm-types:r1}Integer");
}

private JsonNode findCqlDefinitionNode(String cqlDefinition, ArrayNode defines) {
Iterator<JsonNode> definitionIterator = defines.iterator();
while (definitionIterator.hasNext()) {
JsonNode node = definitionIterator.next();
if (node.get("name").asText().contains(cqlDefinition)) {
return node;
}
}
return null;
}

private String getJson() {
CqlTranslator cqlTranslator = buildCqlTranslator();

Expand All @@ -124,6 +181,7 @@ private RequestData buildRequestData() {
.disableListPromotion(disableListPromotion)
.disableMethodInvocation(disableMethodInvocation)
.validateUnits(validateUnits)
.resultTypes(resultTypes)
.build();
}
}
54 changes: 54 additions & 0 deletions src/test/resources/cv_populations.cql
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
library TestCVPopulations version '0.0.004'

using FHIR version '4.0.1'

include FHIRHelpers version '4.0.001' called FHIRHelpers
include SupplementalDataElementsFHIR4 version '2.0.000' called SDE
include MATGlobalCommonFunctionsFHIR4 version '5.0.000' called Global

codesystem "LOINC": 'http://loinc.org'

valueset "Competing Conditions for Respiratory Conditions": 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.102.12.1017'
valueset "Encounter Inpatient": 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.666.5.307'
valueset "Level of Severity of Retinopathy Findings": 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.526.3.1283'

code "Functional Assessment of Chronic Illness Therapy - Palliative Care Questionnaire (FACIT-Pal)": '71007-9' from "LOINC" display 'Functional Assessment of Chronic Illness Therapy - Palliative Care Questionnaire (FACIT-Pal)'

parameter "Measurement Period" Interval<DateTime>

context Patient

define "SDE Ethnicity":
SDE."SDE Ethnicity"

define "SDE Payer":
SDE."SDE Payer"

define "SDE Race":
SDE."SDE Race"

define "Initial Population":
["Encounter": "Encounter Inpatient"] Enc
where Enc.period ends during "Measurement Period"

define "Measure Population":
"Initial Population"

define "Measure Population Exclusions":
"Initial Population" Pop
where exists ( Pop.diagnosis diag
where diag.rank = 1
)

define "Valid Encounter":
["Encounter": "Encounter Inpatient"] Encounter
where Encounter.period during "Measurement Period"
and Encounter.length >= 24 hours

define function "Measure Observation"(Enc "Encounter" ):
Count("Valid Encounter")


define "Unused Boolean Definition":
exists ["Communication": "Level of Severity of Retinopathy Findings"] Communication
where Communication.sent in "Measurement Period"
Loading

0 comments on commit 52c15c4

Please sign in to comment.