From 751c8735337482a3b90dfe5ce8b668272332e75c Mon Sep 17 00:00:00 2001 From: Rohit Kandimalla Date: Wed, 29 May 2024 07:21:47 -0400 Subject: [PATCH 01/16] MAT-7055 Updating context path to be qdm specific --- .../service/DataCriteriaService.java | 3 +- .../utils/cql/QdmDatatypeUtil.java | 140 +++++++++++++----- src/main/resources/application.yaml | 2 +- .../dto/ElementLookupTest.java | 24 +-- 4 files changed, 116 insertions(+), 53 deletions(-) diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/service/DataCriteriaService.java b/src/main/java/gov/cms/mat/cql_elm_translation/service/DataCriteriaService.java index 08ba3d87..e3cc43f7 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/service/DataCriteriaService.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/service/DataCriteriaService.java @@ -233,6 +233,7 @@ private String splitByPipeAndGetLast(String criteria) { DataElementDescriptor getCriteriaType(String dataType) { return QdmDatatypeUtil.isValidNegation(dataType) ? QdmDatatypeUtil.getDescriptorForNegation(dataType) - : new DataElementDescriptor(dataType.replace(",", "").replace(" ", "").replace("Not", ""), dataType); + : new DataElementDescriptor( + dataType.replace(",", "").replace(" ", "").replace("Not", ""), dataType); } } diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/QdmDatatypeUtil.java b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/QdmDatatypeUtil.java index a35c4e99..5794cfd4 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/QdmDatatypeUtil.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/QdmDatatypeUtil.java @@ -8,45 +8,107 @@ public class QdmDatatypeUtil { private static final Map negationRationale; static { - negationRationale = Map.ofEntries( - Map.entry("Assessment, Not Ordered", new DataElementDescriptor("AssessmentOrder", "Assessment, Order")), - Map.entry( - "Assessment, Not Performed", new DataElementDescriptor("AssessmentPerformed", "Assessment, Performed")), - Map.entry( - "Assessment, Not Recommended", new DataElementDescriptor("AssessmentRecommended", "Assessment, Recommended")), - Map.entry("Communication, Not Performed", new DataElementDescriptor("CommunicationPerformed", "Communication, Performed")), - Map.entry("Device, Not Ordered", new DataElementDescriptor("DeviceOrder", "Device, Order")), - Map.entry("Device, Not Recommended" , new DataElementDescriptor("DeviceRecommended", "Device, Recommended")), - Map.entry("Diagnostic Study, Not Ordered", new DataElementDescriptor("DiagnosticStudyOrder", "Diagnostic Study, Order")), - Map.entry("Diagnostic Study, Not Performed", new DataElementDescriptor("DiagnosticStudyPerformed", "Diagnostic Study, Performed")), - Map.entry("Diagnostic Study, Not Recommended", new DataElementDescriptor("DiagnosticStudyRecommended", "Diagnostic Study, Recommended")), - Map.entry("Encounter, Not Ordered", new DataElementDescriptor("EncounterOrder", "Encounter, Order")), - Map.entry("Encounter, Not Recommended", new DataElementDescriptor("EncounterRecommended", "Encounter Recommended")), - Map.entry("Intervention, Not Ordered", new DataElementDescriptor("InterventionOrder", "Intervention, Order")), - Map.entry("Intervention, Not Performed", new DataElementDescriptor("InterventionPerformed", "Intervention, Performed")), - Map.entry("Intervention, Not Recommended", new DataElementDescriptor("InterventionRecommended", "Intervention, Recommended")), - Map.entry("Immunization, Not Ordered", new DataElementDescriptor("ImmunizationOrder", "Immunization, Order")), - Map.entry("Immunization, Not Administered", new DataElementDescriptor("ImmunizationAdministered", "Immunization, Administered")), - Map.entry("Laboratory Test, Not Ordered", new DataElementDescriptor("LaboratoryTestOrder", "Laboratory Test, Order")), - Map.entry("Laboratory Test, Not Performed", new DataElementDescriptor("LaboratoryTestPerformed", "Laboratory Test, Performed")), - Map.entry("Laboratory Test, Not Recommended", new DataElementDescriptor("LaboratoryTestRecommended", "Laboratory Test, Recommended")), - Map.entry("Medication, Not Administered", new DataElementDescriptor("MedicationAdministered", "Medication, Administered")), - Map.entry("Medication, Not Discharged", new DataElementDescriptor("MedicationDischarge", "Medication, Discharge")), - Map.entry("Medication, Not Dispensed", new DataElementDescriptor("MedicationDispensed", "Medication, Dispensed")), - Map.entry("Medication, Not Ordered", new DataElementDescriptor("MedicationOrder", "Medication, Order")), - Map.entry("Physical Exam, Not Ordered", new DataElementDescriptor("PhysicalExamOrder", "Physical Exam, Order")), - Map.entry("Physical Exam, Not Performed", new DataElementDescriptor("PhysicalExamPerformed", "Physical Exam, Performed")), - Map.entry("Physical Exam, Not Recommended", new DataElementDescriptor("PhysicalExamRecommended", "Physical Exam, Recommended")), - Map.entry("Procedure, Not Ordered", new DataElementDescriptor("ProcedureOrder", "Procedure, Order")), - Map.entry("Procedure, Not Performed", new DataElementDescriptor("ProcedurePerformed", "Procedure, Performed")), - Map.entry("Procedure, Not Recommended", new DataElementDescriptor("ProcedureRecommended", "Procedure, Recommended")), - Map.entry("Substance, Not Administered", new DataElementDescriptor("SubstanceAdministered", "Substance, Administered")), - Map.entry("Substance, Not Ordered", new DataElementDescriptor("SubstanceOrder", "Substance, Order")), - Map.entry("Substance, Not Recommended", new DataElementDescriptor("SubstanceRecommended", "Substance, Recommended")) - - - - ); + negationRationale = + Map.ofEntries( + Map.entry( + "Assessment, Not Ordered", + new DataElementDescriptor("AssessmentOrder", "Assessment, Order")), + Map.entry( + "Assessment, Not Performed", + new DataElementDescriptor("AssessmentPerformed", "Assessment, Performed")), + Map.entry( + "Assessment, Not Recommended", + new DataElementDescriptor("AssessmentRecommended", "Assessment, Recommended")), + Map.entry( + "Communication, Not Performed", + new DataElementDescriptor("CommunicationPerformed", "Communication, Performed")), + Map.entry( + "Device, Not Ordered", new DataElementDescriptor("DeviceOrder", "Device, Order")), + Map.entry( + "Device, Not Recommended", + new DataElementDescriptor("DeviceRecommended", "Device, Recommended")), + Map.entry( + "Diagnostic Study, Not Ordered", + new DataElementDescriptor("DiagnosticStudyOrder", "Diagnostic Study, Order")), + Map.entry( + "Diagnostic Study, Not Performed", + new DataElementDescriptor( + "DiagnosticStudyPerformed", "Diagnostic Study, Performed")), + Map.entry( + "Diagnostic Study, Not Recommended", + new DataElementDescriptor( + "DiagnosticStudyRecommended", "Diagnostic Study, Recommended")), + Map.entry( + "Encounter, Not Ordered", + new DataElementDescriptor("EncounterOrder", "Encounter, Order")), + Map.entry( + "Encounter, Not Recommended", + new DataElementDescriptor("EncounterRecommended", "Encounter Recommended")), + Map.entry( + "Intervention, Not Ordered", + new DataElementDescriptor("InterventionOrder", "Intervention, Order")), + Map.entry( + "Intervention, Not Performed", + new DataElementDescriptor("InterventionPerformed", "Intervention, Performed")), + Map.entry( + "Intervention, Not Recommended", + new DataElementDescriptor("InterventionRecommended", "Intervention, Recommended")), + Map.entry( + "Immunization, Not Ordered", + new DataElementDescriptor("ImmunizationOrder", "Immunization, Order")), + Map.entry( + "Immunization, Not Administered", + new DataElementDescriptor( + "ImmunizationAdministered", "Immunization, Administered")), + Map.entry( + "Laboratory Test, Not Ordered", + new DataElementDescriptor("LaboratoryTestOrder", "Laboratory Test, Order")), + Map.entry( + "Laboratory Test, Not Performed", + new DataElementDescriptor("LaboratoryTestPerformed", "Laboratory Test, Performed")), + Map.entry( + "Laboratory Test, Not Recommended", + new DataElementDescriptor( + "LaboratoryTestRecommended", "Laboratory Test, Recommended")), + Map.entry( + "Medication, Not Administered", + new DataElementDescriptor("MedicationAdministered", "Medication, Administered")), + Map.entry( + "Medication, Not Discharged", + new DataElementDescriptor("MedicationDischarge", "Medication, Discharge")), + Map.entry( + "Medication, Not Dispensed", + new DataElementDescriptor("MedicationDispensed", "Medication, Dispensed")), + Map.entry( + "Medication, Not Ordered", + new DataElementDescriptor("MedicationOrder", "Medication, Order")), + Map.entry( + "Physical Exam, Not Ordered", + new DataElementDescriptor("PhysicalExamOrder", "Physical Exam, Order")), + Map.entry( + "Physical Exam, Not Performed", + new DataElementDescriptor("PhysicalExamPerformed", "Physical Exam, Performed")), + Map.entry( + "Physical Exam, Not Recommended", + new DataElementDescriptor("PhysicalExamRecommended", "Physical Exam, Recommended")), + Map.entry( + "Procedure, Not Ordered", + new DataElementDescriptor("ProcedureOrder", "Procedure, Order")), + Map.entry( + "Procedure, Not Performed", + new DataElementDescriptor("ProcedurePerformed", "Procedure, Performed")), + Map.entry( + "Procedure, Not Recommended", + new DataElementDescriptor("ProcedureRecommended", "Procedure, Recommended")), + Map.entry( + "Substance, Not Administered", + new DataElementDescriptor("SubstanceAdministered", "Substance, Administered")), + Map.entry( + "Substance, Not Ordered", + new DataElementDescriptor("SubstanceOrder", "Substance, Order")), + Map.entry( + "Substance, Not Recommended", + new DataElementDescriptor("SubstanceRecommended", "Substance, Recommended"))); } public static boolean isValidNegation(final String negation) { diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 37b6361b..61b2f81a 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -1,7 +1,7 @@ server: port: 8084 servlet: - context-path: /api + context-path: /api/qdm spring: profiles: diff --git a/src/test/java/gov/cms/mat/cql_elm_translation/dto/ElementLookupTest.java b/src/test/java/gov/cms/mat/cql_elm_translation/dto/ElementLookupTest.java index f0c7f0fe..bd301cfe 100644 --- a/src/test/java/gov/cms/mat/cql_elm_translation/dto/ElementLookupTest.java +++ b/src/test/java/gov/cms/mat/cql_elm_translation/dto/ElementLookupTest.java @@ -5,7 +5,6 @@ import java.util.HashSet; import java.util.Set; - import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.equalTo; @@ -14,16 +13,17 @@ class ElementLookupTest { @Test void testHashSetUniqueness() { - ElementLookup elementLookup1 = ElementLookup.builder() - .id("ID1") - .oid("111.222.333") - .name("TestCode") - .codeName("TestCodeName") - .codeSystemName("Amazing Code System") - .release("Release1") - .displayName("Test Code") - .datatype("Code") - .build(); + ElementLookup elementLookup1 = + ElementLookup.builder() + .id("ID1") + .oid("111.222.333") + .name("TestCode") + .codeName("TestCodeName") + .codeSystemName("Amazing Code System") + .release("Release1") + .displayName("Test Code") + .datatype("Code") + .build(); ElementLookup elementLookup2 = elementLookup1.toBuilder().id("ID2").build(); @@ -32,4 +32,4 @@ void testHashSetUniqueness() { set.add(elementLookup2); assertThat(set.size(), is(equalTo(1))); } -} \ No newline at end of file +} From 58307498f4253eb1eac1b2e3a1f69843939c468d Mon Sep 17 00:00:00 2001 From: Joseph Kotanchik Date: Thu, 6 Jun 2024 15:59:45 -0400 Subject: [PATCH 02/16] MAT-6935: Retain Code System versions when parsing CQL. --- .../cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java index 1d15ced9..4e35932f 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java @@ -163,6 +163,7 @@ public void enterCodesystemDefinition(cqlParser.CodesystemDefinitionContext ctx) CQLCodeSystem codeSystem = new CQLCodeSystem(); codeSystem.setId(csDef.getId()); codeSystem.setOID(csDef.getId()); + codeSystem.setCodeSystemVersion(csDef.getVersion()); codeSystem.setCodeSystemName(csDef.getName()); codeSystemMap.putIfAbsent(identifier, codeSystem); @@ -577,6 +578,7 @@ private Element resolve(String identifier, CompiledLibrary library) { .codeName(codeDef.getDisplay()) .codeSystemName(codeDef.getCodeSystem().getName()) .codeSystemOID(cqlCodeSystem == null ? null : cqlCodeSystem.getOID()) + .codeSystemVersion(cqlCodeSystem == null ? null : cqlCodeSystem.getCodeSystemVersion()) .codeIdentifier(formattedIdentifier) .build(); declaredCodes.add(declaredCode); From 567ea452216eb26914ff5fa49094bf3493e9cd66 Mon Sep 17 00:00:00 2001 From: Prateek Keerthi Date: Tue, 11 Jun 2024 11:16:34 -0400 Subject: [PATCH 03/16] MAT-6935 extracting the version from the url --- .../utils/cql/parsing/Cql2ElmListener.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java index 4e35932f..93c0df9e 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java @@ -12,6 +12,8 @@ import java.util.Set; import java.util.Stack; import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import gov.cms.mat.cql_elm_translation.utils.cql.parsing.model.CQLCodeSystem; import gov.cms.mat.cql_elm_translation.utils.cql.parsing.model.CQLFunctionArgument; @@ -163,13 +165,25 @@ public void enterCodesystemDefinition(cqlParser.CodesystemDefinitionContext ctx) CQLCodeSystem codeSystem = new CQLCodeSystem(); codeSystem.setId(csDef.getId()); codeSystem.setOID(csDef.getId()); - codeSystem.setCodeSystemVersion(csDef.getVersion()); + codeSystem.setCodeSystemVersion(getParsedVersion(csDef.getVersion())); codeSystem.setCodeSystemName(csDef.getName()); codeSystemMap.putIfAbsent(identifier, codeSystem); } } + private String getParsedVersion(String version){ + if(version != null) { + String versionRegex= "urn:hl7:version:(\\d+(\\.\\d+)?)"; + Pattern pattern= Pattern.compile(versionRegex); + Matcher matcher=pattern.matcher(version); + if(matcher.find()){ + return matcher.group(1); + } + } + return version; + } + @Override public void enterQualifiedFunction(QualifiedFunctionContext ctx) { if (ctx.identifierOrFunctionIdentifier() != null From e08acd789ec5a6f6de0cc36a067e29c34fd040fa Mon Sep 17 00:00:00 2001 From: Prateek Keerthi Date: Wed, 12 Jun 2024 10:27:56 -0400 Subject: [PATCH 04/16] MAT-6935 refactored code --- .../utils/cql/parsing/Cql2ElmListener.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java index 93c0df9e..a8774d03 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java @@ -12,8 +12,6 @@ import java.util.Set; import java.util.Stack; import java.util.UUID; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import gov.cms.mat.cql_elm_translation.utils.cql.parsing.model.CQLCodeSystem; import gov.cms.mat.cql_elm_translation.utils.cql.parsing.model.CQLFunctionArgument; @@ -172,13 +170,10 @@ public void enterCodesystemDefinition(cqlParser.CodesystemDefinitionContext ctx) } } - private String getParsedVersion(String version){ - if(version != null) { - String versionRegex= "urn:hl7:version:(\\d+(\\.\\d+)?)"; - Pattern pattern= Pattern.compile(versionRegex); - Matcher matcher=pattern.matcher(version); - if(matcher.find()){ - return matcher.group(1); + private String getParsedVersion(String version) { + if (version != null) { + if (version.startsWith("urn:hl7:version:")) { + return version.substring("urn:hl7:version:".length()); } } return version; @@ -592,7 +587,8 @@ private Element resolve(String identifier, CompiledLibrary library) { .codeName(codeDef.getDisplay()) .codeSystemName(codeDef.getCodeSystem().getName()) .codeSystemOID(cqlCodeSystem == null ? null : cqlCodeSystem.getOID()) - .codeSystemVersion(cqlCodeSystem == null ? null : cqlCodeSystem.getCodeSystemVersion()) + .codeSystemVersion( + cqlCodeSystem == null ? null : cqlCodeSystem.getCodeSystemVersion()) .codeIdentifier(formattedIdentifier) .build(); declaredCodes.add(declaredCode); From f6e44d0b2f34146f1c1802abdfa6950a295d4e2b Mon Sep 17 00:00:00 2001 From: Prateek Keerthi Date: Wed, 12 Jun 2024 10:32:23 -0400 Subject: [PATCH 05/16] MAT-6935 fixed codacy issue --- .../utils/cql/parsing/Cql2ElmListener.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java index a8774d03..0ccd6b2b 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java @@ -171,10 +171,8 @@ public void enterCodesystemDefinition(cqlParser.CodesystemDefinitionContext ctx) } private String getParsedVersion(String version) { - if (version != null) { - if (version.startsWith("urn:hl7:version:")) { - return version.substring("urn:hl7:version:".length()); - } + if (version != null && version.startsWith("urn:hl7:version:")) { + return version.substring("urn:hl7:version:".length()); } return version; } From b551230284df57e1c63daa5530f59898ef1150d6 Mon Sep 17 00:00:00 2001 From: CeciliaLiu8 Date: Tue, 18 Jun 2024 06:32:46 -0500 Subject: [PATCH 06/16] MAT-7294 qdm get translator version --- .../config/TranslatorVersionConfig.java | 17 +++++++ .../TranslatorVersionController.java | 36 +++++++++++++ src/main/resources/application.yaml | 3 ++ .../TranslatorVersionControllerTest.java | 50 +++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 src/main/java/gov/cms/mat/cql_elm_translation/config/TranslatorVersionConfig.java create mode 100644 src/main/java/gov/cms/mat/cql_elm_translation/controllers/TranslatorVersionController.java create mode 100644 src/test/java/gov/cms/mat/cql_elm_translation/controllers/TranslatorVersionControllerTest.java diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/config/TranslatorVersionConfig.java b/src/main/java/gov/cms/mat/cql_elm_translation/config/TranslatorVersionConfig.java new file mode 100644 index 00000000..0f4aedeb --- /dev/null +++ b/src/main/java/gov/cms/mat/cql_elm_translation/config/TranslatorVersionConfig.java @@ -0,0 +1,17 @@ +package gov.cms.mat.cql_elm_translation.config; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +import lombok.Data; + +@Configuration +@Data +public class TranslatorVersionConfig { + + @Value("${madie.translatorVersion.currentVersion}") + private String currentTranslatorVersion; + + @Value("${madie.translatorVersion.mostRecentVersion}") + private String mostRecentTranslatorVersion; +} diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/controllers/TranslatorVersionController.java b/src/main/java/gov/cms/mat/cql_elm_translation/controllers/TranslatorVersionController.java new file mode 100644 index 00000000..9b52ba37 --- /dev/null +++ b/src/main/java/gov/cms/mat/cql_elm_translation/controllers/TranslatorVersionController.java @@ -0,0 +1,36 @@ +package gov.cms.mat.cql_elm_translation.controllers; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import gov.cms.mat.cql_elm_translation.config.TranslatorVersionConfig; +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@RestController +@AllArgsConstructor +@RequestMapping("/translator-version") +public class TranslatorVersionController { + + private TranslatorVersionConfig translatorVersionConfig; + + @GetMapping() + public ResponseEntity getTranslatorVersion( + @RequestParam(required = true, name = "draft") boolean draft) { + log.info( + "Current translator version: " + translatorVersionConfig.getCurrentTranslatorVersion()); + log.info( + "Most recent translator version: " + + translatorVersionConfig.getMostRecentTranslatorVersion()); + String result = + draft + ? translatorVersionConfig.getMostRecentTranslatorVersion() + : translatorVersionConfig.getCurrentTranslatorVersion(); + return ResponseEntity.status(HttpStatus.OK).body(result); + } +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 61b2f81a..687ee4bc 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -28,6 +28,9 @@ madie: baseUrl: ${CQL_LIBRARY_SERVICE_URL:http://localhost:8082/api} cql: uri: /cql-libraries/cql + translatorVersion: + currentVersion: "3.3.2" + mostRecentVersion: "3.10.0" springdoc: swagger-ui: diff --git a/src/test/java/gov/cms/mat/cql_elm_translation/controllers/TranslatorVersionControllerTest.java b/src/test/java/gov/cms/mat/cql_elm_translation/controllers/TranslatorVersionControllerTest.java new file mode 100644 index 00000000..6f5b2810 --- /dev/null +++ b/src/test/java/gov/cms/mat/cql_elm_translation/controllers/TranslatorVersionControllerTest.java @@ -0,0 +1,50 @@ +package gov.cms.mat.cql_elm_translation.controllers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.lenient; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import gov.cms.mat.cql_elm_translation.config.TranslatorVersionConfig; + +@ExtendWith(MockitoExtension.class) +public class TranslatorVersionControllerTest { + + @Mock private TranslatorVersionConfig translatorVersionConfig; + @InjectMocks private TranslatorVersionController translatorVersionController; + + private static final String CURRENT_VERSION = "3.3.2"; + private static final String MOST_RECENT_VERSION = "3.10.0"; + + @BeforeEach + void beforeEach() { + lenient() + .when(translatorVersionConfig.getCurrentTranslatorVersion()) + .thenReturn(CURRENT_VERSION); + lenient() + .when(translatorVersionConfig.getMostRecentTranslatorVersion()) + .thenReturn(MOST_RECENT_VERSION); + } + + @Test + public void testGetTranslatorVersionIsDraft() { + ResponseEntity results = translatorVersionController.getTranslatorVersion(true); + assertTrue(results.getStatusCode().equals(HttpStatus.OK)); + assertEquals(results.getBody(), MOST_RECENT_VERSION); + } + + @Test + public void testGetTranslatorVersionVersioned() { + ResponseEntity results = translatorVersionController.getTranslatorVersion(false); + assertTrue(results.getStatusCode().equals(HttpStatus.OK)); + assertEquals(results.getBody(), CURRENT_VERSION); + } +} From 7526d063d4011b2b679701b34be1e22bee3f6924 Mon Sep 17 00:00:00 2001 From: CeciliaLiu8 Date: Wed, 26 Jun 2024 15:10:38 -0500 Subject: [PATCH 07/16] MAT-7189 exception when getting current node is null --- .../utils/cql/parsing/model/CQLGraph.java | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/model/CQLGraph.java b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/model/CQLGraph.java index ad97e0f3..0c0fbee1 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/model/CQLGraph.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/model/CQLGraph.java @@ -9,6 +9,9 @@ import java.util.Queue; import java.util.Set; +import lombok.extern.slf4j.Slf4j; + +@Slf4j public class CQLGraph { private final Map> graph = new HashMap<>(); @@ -49,20 +52,32 @@ public boolean isPath(String source, String destination) { while (!queue.isEmpty()) { String currentNode = queue.remove(); - List adjacentVertices = new ArrayList<>(this.graph.get(currentNode)); - - for (String adjacentNode : adjacentVertices) { - // we've found the destination node that we were looking for, so return true. - if (adjacentNode.equals(destination)) { - return true; - } - // if it's not the destination node and the node hasn't been visited yet, add it to the - // queue to be visited. - if (!visited.contains(adjacentNode)) { - visited.add(adjacentNode); - queue.add(adjacentNode); + if (this.graph.get(currentNode) != null) { + List adjacentVertices = new ArrayList<>(this.graph.get(currentNode)); + + for (String adjacentNode : adjacentVertices) { + // we've found the destination node that we were looking for, so return true. + if (adjacentNode.equals(destination)) { + return true; + } + + // if it's not the destination node and the node hasn't been visited yet, add it to the + // queue to be visited. + if (!visited.contains(adjacentNode)) { + visited.add(adjacentNode); + queue.add(adjacentNode); + } } + } else { + log.error( + "source = " + + source + + " destination = " + + destination + + " this.graph.get currentNode: " + + currentNode + + " is null"); } } From 92c3edd3ad7da176d81a9eeaf8f88f8f32ae94a1 Mon Sep 17 00:00:00 2001 From: riddhi-desai Date: Tue, 2 Jul 2024 16:40:27 -0400 Subject: [PATCH 08/16] MAT-7412 update okta-spring-boot-starter --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2aab1032..71377440 100644 --- a/pom.xml +++ b/pom.xml @@ -245,7 +245,7 @@ com.okta.spring okta-spring-boot-starter - 3.0.6 + 3.0.7 com.jayway.jsonpath From d388c2c557aa1a9fcf5c11f3492127fb828af86c Mon Sep 17 00:00:00 2001 From: Prateek Keerthi Date: Mon, 8 Jul 2024 10:44:48 -0500 Subject: [PATCH 09/16] MAT-7279 update java models --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2aab1032..594b8593 100644 --- a/pom.xml +++ b/pom.xml @@ -267,7 +267,7 @@ gov.cms.madie madie-java-models - 0.6.30-SNAPSHOT + 0.6.42-SNAPSHOT jackson-core From 576cf000bf34ffac32ec2db76e3ed45b6c7d5b69 Mon Sep 17 00:00:00 2001 From: Rohit Kandimalla Date: Tue, 9 Jul 2024 15:16:33 -0400 Subject: [PATCH 10/16] MAT-7352 check to see if a library is already parsed by Antlr to avoid duplicate parsing --- .../utils/cql/parsing/Cql2ElmListener.java | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java index 0ccd6b2b..4501b924 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java @@ -563,18 +563,27 @@ private Element resolve(String identifier, CompiledLibrary library) { currentContext, def.getPath() + "-" + def.getVersion() + "|" + def.getLocalIdentifier()); libraryAccessor = def; try { - parseChildLibraries(def); - libraries.add( - CQLIncludeLibrary.builder() - .cqlLibraryName(def.getPath()) - .aliasName(def.getLocalIdentifier()) - .version(def.getVersion()) - // TODO: should be taken from librarySetId - .id(def.getTrackerId().toString()) - .setId(def.getTrackerId().toString()) - .build()); + var parsedLibrary = + libraries.stream() + .filter( + l -> + l.getCqlLibraryName().equalsIgnoreCase(def.getPath()) + && l.getVersion().equalsIgnoreCase(def.getVersion())) + .findFirst(); + if (parsedLibrary.isEmpty()) { + parseChildLibraries(def); + libraries.add( + CQLIncludeLibrary.builder() + .cqlLibraryName(def.getPath()) + .aliasName(def.getLocalIdentifier()) + .version(def.getVersion()) + // TODO: should be taken from librarySetId + .id(def.getTrackerId().toString()) + .setId(def.getTrackerId().toString()) + .build()); + } } catch (IOException e) { - e.printStackTrace(); + log.error(e.getMessage()); } } else if (element instanceof CodeDef codeDef) { codes.add(formattedIdentifier); From ad223707a4209b7da7e8248bd9cd4baa7402eccd Mon Sep 17 00:00:00 2001 From: Rohit Kandimalla Date: Tue, 9 Jul 2024 15:23:49 -0400 Subject: [PATCH 11/16] MAT-7352 logged exceptions while parsing cql libraries --- .../utils/cql/parsing/Cql2ElmListener.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java index 4501b924..005b9d22 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java @@ -583,7 +583,9 @@ private Element resolve(String identifier, CompiledLibrary library) { .build()); } } catch (IOException e) { - log.error(e.getMessage()); + log.error( + "IOException while parsing child library [{}] " + e.getMessage(), + def.getPath() + "-" + def.getVersion()); } } else if (element instanceof CodeDef codeDef) { codes.add(formattedIdentifier); From 96b87361c5151ffb3455f22ae2fc2ca238f26e5a Mon Sep 17 00:00:00 2001 From: riddhi-desai Date: Tue, 9 Jul 2024 15:24:27 -0400 Subject: [PATCH 12/16] update spring-boot-starter-parent --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index bd4e72fb..ac71d7bd 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.4 + 3.2.7 gov.cms.madie cql-elm-translation From c0db92ac7539cbf647fc8256ab30004881b2be9e Mon Sep 17 00:00:00 2001 From: Greg Akins Date: Thu, 18 Jul 2024 14:30:28 -0400 Subject: [PATCH 13/16] MAT-7481: Adding configurable version for cqframework translator --- src/main/resources/application.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 687ee4bc..b76a83c5 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -29,8 +29,8 @@ madie: cql: uri: /cql-libraries/cql translatorVersion: - currentVersion: "3.3.2" - mostRecentVersion: "3.10.0" + currentVersion: ${CURRENT_TRANSLATOR_VERSION:3.3.2} + mostRecentVersion: ${MOST_RECENT_TRANSLATOR_VERSION:3.3.2} springdoc: swagger-ui: From 7ce0b8ba8ff24dfb4d77c31fe6a475fd5b7799f4 Mon Sep 17 00:00:00 2001 From: adongare Date: Fri, 26 Jul 2024 11:17:51 -0400 Subject: [PATCH 14/16] MAT-7450 Fetch CQL Parameters, Definitions, Functions, and Fluent Functions required for CQL Builder UI --- .../controllers/CqlToolsController.java | 11 +++ .../dto/CqlBuilderLookup.java | 23 +++++ .../service/CqlParsingService.java | 87 ++++++++++++++++--- .../service/DataCriteriaService.java | 4 - .../utils/cql/CQLTools.java | 2 + .../utils/cql/parsing/Cql2ElmListener.java | 15 +++- .../cql/parsing/model/DefinitionContent.java | 1 + 7 files changed, 126 insertions(+), 17 deletions(-) create mode 100644 src/main/java/gov/cms/mat/cql_elm_translation/dto/CqlBuilderLookup.java diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/controllers/CqlToolsController.java b/src/main/java/gov/cms/mat/cql_elm_translation/controllers/CqlToolsController.java index 35b4d502..7ac3ffd7 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/controllers/CqlToolsController.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/controllers/CqlToolsController.java @@ -2,6 +2,7 @@ import gov.cms.madie.models.dto.TranslatedLibrary; import gov.cms.madie.models.measure.Measure; +import gov.cms.mat.cql_elm_translation.dto.CqlBuilderLookup; import gov.cms.mat.cql_elm_translation.dto.CqlLookupRequest; import gov.cms.mat.cql_elm_translation.dto.CqlLookups; import gov.cms.mat.cql_elm_translation.dto.SourceDataCriteria; @@ -103,4 +104,14 @@ public ResponseEntity getCqlLookups( cqlParsingService.getCqlLookups( lookupRequest.getCql(), lookupRequest.getMeasureExpressions(), accessToken)); } + + @PutMapping( + value = "/cql-builder-lookups", + produces = MediaType.APPLICATION_JSON_VALUE, + consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity getCqlBuilderLookups( + @RequestBody String cql, @RequestHeader("Authorization") String accessToken) { + log.info("Preparing CqlBuilder Lookups"); + return ResponseEntity.ok(cqlParsingService.getCqlBuilderLookups(cql, accessToken)); + } } diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/dto/CqlBuilderLookup.java b/src/main/java/gov/cms/mat/cql_elm_translation/dto/CqlBuilderLookup.java new file mode 100644 index 00000000..edef860f --- /dev/null +++ b/src/main/java/gov/cms/mat/cql_elm_translation/dto/CqlBuilderLookup.java @@ -0,0 +1,23 @@ +package gov.cms.mat.cql_elm_translation.dto; + +import lombok.Builder; +import lombok.Data; + +import java.util.Set; + +@Data +@Builder +public class CqlBuilderLookup { + private Set parameters; + private Set definitions; + private Set functions; + private Set fluentFunctions; + + @Builder + public static class Lookup { + private String name; + private String libraryName; + private String libraryAlias; + private String logic; + } +} diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/service/CqlParsingService.java b/src/main/java/gov/cms/mat/cql_elm_translation/service/CqlParsingService.java index 695fa2ce..f3f7dd0b 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/service/CqlParsingService.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/service/CqlParsingService.java @@ -1,5 +1,6 @@ package gov.cms.mat.cql_elm_translation.service; +import gov.cms.mat.cql_elm_translation.dto.CqlBuilderLookup; import gov.cms.mat.cql_elm_translation.dto.CqlLookups; import gov.cms.mat.cql_elm_translation.dto.ElementLookup; import gov.cms.mat.cql_elm_translation.utils.cql.CQLTools; @@ -45,13 +46,13 @@ public Set getAllDefinitions(String cql, String accessToken) { } /** - * Parses the CQL and generates cql artifacts(including for the CQL of the included Libraries). - * refer CQL artifacts- gov.cms.mat.cql_elm_translation.dto.CQLLookups + * Parses the CQL and generates only used cql artifacts(including for the CQL of the included + * Libraries). refer CQL artifacts- gov.cms.mat.cql_elm_translation.dto.CQLLookups * * @param cql- measure cql * @param measureExpressions- set of cql definitions used in measure groups, SDEs & RAVs * @param accessToken Requesting User's Okta Bearer token - * @return CQLLookups + * @return CQLLookups -> building blocks for HQMF and Human Readable generation */ public CqlLookups getCqlLookups(String cql, Set measureExpressions, String accessToken) { if (StringUtils.isBlank(cql) || CollectionUtils.isEmpty(measureExpressions)) { @@ -104,6 +105,78 @@ public CqlLookups getCqlLookups(String cql, Set measureExpressions, Stri .build(); } + /** + * Parses the CQL and collect all CQL building blocks irrespective of used or unused(including for + * the CQL of the included Libraries) + * + * @param cql- measure cql + * @param accessToken Requesting User's Okta Bearer token + * @return CqlBuilderLookup -> building blocks for CQL Definition UI builder + */ + public CqlBuilderLookup getCqlBuilderLookups(String cql, String accessToken) { + if (StringUtils.isBlank(cql)) { + return null; + } + + CQLTools cqlTools = parseCql(cql, accessToken, cqlLibraryService, null); + // all parameters + Set parameters = + cqlTools.getAllParameters().stream().map(this::buildParameterLookup).collect(toSet()); + + // get all CQLDefinitions including functions + Set allCqlDefinitions = buildCqlDefinitions(cqlTools); + // prepare lookups for definitions, functions and fluent functions from CQLDefinitions + Set definitions = new HashSet<>(); + Set functions = new HashSet<>(); + Set fluentFunctions = new HashSet<>(); + for (CQLDefinition cqlDefinition : allCqlDefinitions) { + CqlBuilderLookup.Lookup lookup = + buildCqlBuilderLookup( + cqlDefinition.getName(), + cqlDefinition.getLogic(), + cqlDefinition.getParentLibrary(), + cqlDefinition.getLibraryDisplayName()); + if (cqlDefinition.isFunction()) { + if (StringUtils.startsWith(cqlDefinition.getLogic(), "define fluent function")) { + fluentFunctions.add(lookup); + } else { + functions.add(lookup); + } + } else { + definitions.add(lookup); + } + } + return CqlBuilderLookup.builder() + .parameters(parameters) + .definitions(definitions) + .functions(functions) + .fluentFunctions(fluentFunctions) + .build(); + } + + private CqlBuilderLookup.Lookup buildParameterLookup(CQLParameter parameter) { + String[] parts = parameter.getParameterName().split("\\|"); + String name = parameter.getParameterName(); + String libraryName = null; + String libraryAlias = null; + if (parts.length == 3) { + libraryName = parts[0].split("-")[0]; + libraryAlias = parts[1]; + name = parts[2]; + } + return buildCqlBuilderLookup(name, parameter.getParameterLogic(), libraryName, libraryAlias); + } + + private CqlBuilderLookup.Lookup buildCqlBuilderLookup( + String name, String logic, String libraryName, String libraryAlias) { + return CqlBuilderLookup.Lookup.builder() + .name(name) + .logic(logic) + .libraryName(libraryName) + .libraryAlias(libraryAlias) + .build(); + } + /** * Maps the references between CQL Definitions. In other words, which CQL Definitions and * Functions are called by which other CQL Definition. @@ -328,13 +401,7 @@ private CQLDefinition buildCqlDefinition(DefinitionContent definitionContent) { definition.setLibraryVersion(libraryParts[1]); } } - // TODO could use a stronger comparator for determining if node is Definition or Function - definition.setFunction(definition.getDefinitionLogic().startsWith("define function")); + definition.setFunction(definitionContent.isFunction()); return definition; } - - public Map> getUsedFunctions(String cql, String accessToken) { - CQLTools cqlTools = parseCql(cql, accessToken, cqlLibraryService, null); - return cqlTools.getUsedFunctions(); - } } diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/service/DataCriteriaService.java b/src/main/java/gov/cms/mat/cql_elm_translation/service/DataCriteriaService.java index e3cc43f7..4e8c6fba 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/service/DataCriteriaService.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/service/DataCriteriaService.java @@ -26,10 +26,6 @@ public class DataCriteriaService extends CqlTooling { private final CqlLibraryService cqlLibraryService; - public DataCriteria parseDataCriteriaFromCql(String cql, String accessToken) { - return parseCql(cql, accessToken, cqlLibraryService, null).getDataCriteria(); - } - public Set getRelevantElements(Measure measure, String accessToken) { if (StringUtils.isBlank(measure.getCql())) { log.info("Data criteria not found as cql is blank"); diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/CQLTools.java b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/CQLTools.java index 3dacfb46..72675959 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/CQLTools.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/CQLTools.java @@ -84,6 +84,7 @@ public class CQLTools { private Set usedCodeSystems = new HashSet<>(); private DataCriteria dataCriteria = new DataCriteria(); private Set definitionContents = new HashSet<>(); + private Set allParameters = new HashSet<>(); private Map> callstack = new HashMap<>(); private UsingProperties usingProperties; @@ -140,6 +141,7 @@ public void generate() throws IOException { walker.walk(listener, tree); definitionContents.addAll(listener.getDefinitionContents()); + allParameters.addAll(listener.getParameters()); callstack = graph.getAdjacencyList(); Set librariesSet = new HashSet<>(listener.getLibraries()); diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java index 005b9d22..1911c73c 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/Cql2ElmListener.java @@ -209,6 +209,14 @@ public void enterQualifiedIdentifierExpression(QualifiedIdentifierExpressionCont } } + @Override + public void enterLocalIdentifier(cqlParser.LocalIdentifierContext ctx) { + String identifier = parseString(ctx.identifier().getText()); + if (shouldResolve(identifier)) { + resolve(identifier, getCurrentLibraryContext()); + } + } + @Override public void enterReferentialIdentifier(ReferentialIdentifierContext ctx) { String identifier = parseString(ctx.getText()); @@ -283,6 +291,7 @@ public void enterFunctionDefinition(@NotNull cqlParser.FunctionDefinitionContext .name(currentContext) .content(content) .functionArguments(functionArguments) + .function(true) .build()); graph.addNode(currentContext); } @@ -343,6 +352,9 @@ public void enterParameterDefinition(@NotNull cqlParser.ParameterDefinitionConte String identifier = parseString(ctx.identifier().getText()); this.currentContext = libraryIdentifier + identifier; graph.addNode(currentContext); + if (shouldResolve(identifier)) { + resolve(identifier, getCurrentLibraryContext()); + } } @Override @@ -654,9 +666,6 @@ private void parseChildLibraries(IncludeDef def) throws IOException { cqlLexer lexer = new cqlLexer(CharStreams.fromStream(stream)); CommonTokenStream tokens = new CommonTokenStream(lexer); cqlParser parser = new cqlParser(tokens); - - // CompiledLibrary childLibrary = this.translatedLibraryMap.get(def.getPath() + "-" + - // def.getVersion()); CompiledLibrary childLibrary = this.translatedLibraryMap.get(def.getPath()); Cql2ElmListener listener = new Cql2ElmListener( diff --git a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/model/DefinitionContent.java b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/model/DefinitionContent.java index 860f8355..49d49370 100644 --- a/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/model/DefinitionContent.java +++ b/src/main/java/gov/cms/mat/cql_elm_translation/utils/cql/parsing/model/DefinitionContent.java @@ -11,4 +11,5 @@ public class DefinitionContent { private String name; private String content; private List functionArguments; + private boolean function; } From 4586e7e301f3eca1b0c97f9036a69bf185d80168 Mon Sep 17 00:00:00 2001 From: adongare Date: Fri, 26 Jul 2024 13:25:51 -0400 Subject: [PATCH 15/16] MAT-7450 test cases --- .../service/CqlParsingServiceTest.java | 31 ++++++++++++++++++- src/test/resources/qicore_included_lib.cql | 4 +++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/test/java/gov/cms/mat/cql_elm_translation/service/CqlParsingServiceTest.java b/src/test/java/gov/cms/mat/cql_elm_translation/service/CqlParsingServiceTest.java index 6ea01897..6eea763f 100644 --- a/src/test/java/gov/cms/mat/cql_elm_translation/service/CqlParsingServiceTest.java +++ b/src/test/java/gov/cms/mat/cql_elm_translation/service/CqlParsingServiceTest.java @@ -3,11 +3,13 @@ import gov.cms.mat.cql.CqlTextParser; import gov.cms.mat.cql_elm_translation.ResourceFileUtil; import gov.cms.mat.cql_elm_translation.cql_translator.MadieLibrarySourceProvider; +import gov.cms.mat.cql_elm_translation.dto.CqlBuilderLookup; import gov.cms.mat.cql_elm_translation.dto.CqlLookups; import gov.cms.mat.cql_elm_translation.dto.ElementLookup; import gov.cms.mat.cql_elm_translation.utils.cql.parsing.model.CQLDefinition; import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.jupiter.api.Assertions.assertNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -140,6 +142,14 @@ void testAllDefinitions() { .definitionLogic("define function \"func\":\n" + " true") .build(); + CQLDefinition fluentFunction = + CQLDefinition.builder() + .id("HelperLibrary-0.0.000|Helper|Null Abatement") + .definitionName("Null Abatement") + .definitionLogic("define fluent function \"Null Abatement\"(Conditions List):\n" + + " Conditions C where C.abatement is null") + .build(); + CQLDefinition helperDefine = CQLDefinition.builder() .id("HelperLibrary-0.0.000|Helper|Inpatient Encounter") @@ -155,7 +165,7 @@ void testAllDefinitions() { .build(); assertThat( - allDefs, containsInAnyOrder(define1, define2, define3, define4, helperDefine, function)); + allDefs, containsInAnyOrder(define1, define2, define3, define4, helperDefine, function, fluentFunction)); } @Test @@ -202,4 +212,23 @@ void testGetCqlLookups() { List oids = cqlLookup.getElementLookups().stream().map(ElementLookup::getOid).toList(); assertThat(oids, containsInAnyOrder("204504", "197604", "2.16.840.1.113883.3.464.1003.1065")); } + + @Test + void testGetCqlBuilderLookups() { + MadieLibrarySourceProvider.setUsing(new CqlTextParser(qiCoreMeasureCql).getUsing()); + MadieLibrarySourceProvider.setCqlLibraryService(cqlLibraryService); + doReturn(qiCoreHelperCql).when(cqlLibraryService).getLibraryCql(any(), any(), any()); + doNothing().when(cqlLibraryService).setUpLibrarySourceProvider(anyString(), anyString()); + CqlBuilderLookup lookup = cqlParsingService.getCqlBuilderLookups(qiCoreMeasureCql, "token"); + assertThat(lookup.getParameters().size(), is(2)); + assertThat(lookup.getDefinitions().size(), is(5)); + assertThat(lookup.getFunctions().size(), is(1)); + assertThat(lookup.getFluentFunctions().size(), is(1)); + } + + @Test + void testGetCqlBuilderLookupsForEmptyCql() { + CqlBuilderLookup lookup = cqlParsingService.getCqlBuilderLookups(null, "token"); + assertThat(lookup, is(nullValue())); + } } diff --git a/src/test/resources/qicore_included_lib.cql b/src/test/resources/qicore_included_lib.cql index db10b150..3b52dc61 100644 --- a/src/test/resources/qicore_included_lib.cql +++ b/src/test/resources/qicore_included_lib.cql @@ -5,6 +5,7 @@ using QICore version '4.1.1' valueset "Encounter Inpatient": 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.666.5.307' parameter "Measurement Period" Interval +parameter "test date" Interval context Patient @@ -12,3 +13,6 @@ define "Inpatient Encounter": [Encounter: "Encounter Inpatient"] EncounterInpatient where EncounterInpatient.status = 'finished' and EncounterInpatient.period ends during day of "Measurement Period" + +define fluent function "Null Abatement"(Conditions List): + Conditions C where C.abatement is null \ No newline at end of file From 33b3bb420e12be78ef1d45ad9b9b34ba254aa3fa Mon Sep 17 00:00:00 2001 From: adongare Date: Fri, 26 Jul 2024 13:35:18 -0400 Subject: [PATCH 16/16] MAT-7450 more test cases --- .../controllers/CqlToolsControllerTest.java | 25 +++++++++++++++++++ .../service/CqlParsingServiceTest.java | 9 ++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/test/java/gov/cms/mat/cql_elm_translation/controllers/CqlToolsControllerTest.java b/src/test/java/gov/cms/mat/cql_elm_translation/controllers/CqlToolsControllerTest.java index 99738fba..58cff8c3 100644 --- a/src/test/java/gov/cms/mat/cql_elm_translation/controllers/CqlToolsControllerTest.java +++ b/src/test/java/gov/cms/mat/cql_elm_translation/controllers/CqlToolsControllerTest.java @@ -2,6 +2,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; @@ -25,6 +26,7 @@ import gov.cms.madie.models.dto.TranslatedLibrary; +import gov.cms.mat.cql_elm_translation.dto.CqlBuilderLookup; import gov.cms.mat.cql_elm_translation.dto.CqlLookupRequest; import gov.cms.mat.cql_elm_translation.dto.CqlLookups; import org.cqframework.cql.tools.formatter.CqlFormatterVisitor; @@ -211,4 +213,27 @@ void testGetCqlLookups() { assertThat(cqlLookups.getLibrary(), is(equalTo("Test"))); assertThat(cqlLookups.getVersion(), is(equalTo("0.0.001"))); } + + @Test + void testGetCqlBuilderLookups() { + var p = CqlBuilderLookup.Lookup.builder().name("Parameter").logic("abc").build(); + var d = CqlBuilderLookup.Lookup.builder().name("Definition").logic("abcd").build(); + var f = CqlBuilderLookup.Lookup.builder().name("Function").logic("abcdef").build(); + when(cqlParsingService.getCqlBuilderLookups(anyString(), anyString())) + .thenReturn( + CqlBuilderLookup.builder() + .parameters(Set.of(p)) + .definitions(Set.of(d)) + .functions(Set.of(f)) + .build()); + + ResponseEntity result = + cqlToolsController.getCqlBuilderLookups("CQL", "accessToken"); + CqlBuilderLookup cqlBuilderLookups = result.getBody(); + assertNotNull(cqlBuilderLookups); + assertThat(cqlBuilderLookups.getParameters().size(), is(1)); + assertThat(cqlBuilderLookups.getDefinitions().size(), is(1)); + assertThat(cqlBuilderLookups.getFunctions().size(), is(1)); + assertThat(cqlBuilderLookups.getFluentFunctions(), is(nullValue())); + } } diff --git a/src/test/java/gov/cms/mat/cql_elm_translation/service/CqlParsingServiceTest.java b/src/test/java/gov/cms/mat/cql_elm_translation/service/CqlParsingServiceTest.java index 6eea763f..f5a81327 100644 --- a/src/test/java/gov/cms/mat/cql_elm_translation/service/CqlParsingServiceTest.java +++ b/src/test/java/gov/cms/mat/cql_elm_translation/service/CqlParsingServiceTest.java @@ -146,8 +146,9 @@ void testAllDefinitions() { CQLDefinition.builder() .id("HelperLibrary-0.0.000|Helper|Null Abatement") .definitionName("Null Abatement") - .definitionLogic("define fluent function \"Null Abatement\"(Conditions List):\n" + - " Conditions C where C.abatement is null") + .definitionLogic( + "define fluent function \"Null Abatement\"(Conditions List):\n" + + " Conditions C where C.abatement is null") .build(); CQLDefinition helperDefine = @@ -165,7 +166,9 @@ void testAllDefinitions() { .build(); assertThat( - allDefs, containsInAnyOrder(define1, define2, define3, define4, helperDefine, function, fluentFunction)); + allDefs, + containsInAnyOrder( + define1, define2, define3, define4, helperDefine, function, fluentFunction)); } @Test