Skip to content

Commit

Permalink
Merge pull request #162 from MeasureAuthoringTool/MAT-6198
Browse files Browse the repository at this point in the history
MAT-6198 Exported transaction test case bundles are invalid due to MeasureReport missing request component
  • Loading branch information
adongare authored Sep 28, 2023
2 parents ac39553 + 67f8847 commit a951ceb
Showing 14 changed files with 83 additions and 95 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package gov.cms.madie.madiefhirservice.cql;

import gov.cms.madie.madiefhirservice.utils.FhirResourceHelpers;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.antlr.v4.runtime.ParserRuleContext;
@@ -35,14 +36,9 @@ public class LibraryCqlVisitor extends cqlBaseVisitor<String> {
private final Map<Integer, Library> libraryCacheMap = new HashMap<>();
private final Map<String, String> valueSetNameUri = new HashMap<>();
private final List<Pair<String, String>> includedLibraries = new ArrayList<>();
private String fhirBaseUrl;
private String name;
private String version;

public LibraryCqlVisitor(String fhirBaseUrl) {
this.fhirBaseUrl = fhirBaseUrl;
}

/**
* Stores off lib name and version.
*
@@ -70,7 +66,11 @@ public String visitIncludeDefinition(cqlParser.IncludeDefinitionContext ctx) {
RelatedArtifact relatedArtifact = new RelatedArtifact();
relatedArtifact.setType(RelatedArtifact.RelatedArtifactType.DEPENDSON);
var nameVersion = getNameVersionFromInclude(ctx);
relatedArtifact.setUrl(fhirBaseUrl + "/Library/" + nameVersion.getLeft());
String url =
FhirResourceHelpers.buildResourceFullUrl("Library", nameVersion.getLeft())
+ "|"
+ nameVersion.getRight();
relatedArtifact.setResource(url);
relatedArtifacts.add(relatedArtifact);
includedLibraries.add(nameVersion);
includes.add(ctx);
@@ -94,7 +94,7 @@ public String visitValuesetDefinition(cqlParser.ValuesetDefinitionContext ctx) {
.add(new ValuesetModel(vsName, uri, null, null));
RelatedArtifact relatedArtifact = new RelatedArtifact();
relatedArtifact.setType(RelatedArtifact.RelatedArtifactType.DEPENDSON);
relatedArtifact.setUrl(uri);
relatedArtifact.setResource(uri);
relatedArtifacts.add(relatedArtifact);

// need to be polished once we human readable file
@@ -108,7 +108,7 @@ public String visitCodesystemDefinition(cqlParser.CodesystemDefinitionContext ct
codeSystems.add(ctx);
RelatedArtifact relatedArtifact = new RelatedArtifact();
relatedArtifact.setType(RelatedArtifact.RelatedArtifactType.DEPENDSON);
relatedArtifact.setUrl(
relatedArtifact.setResource(
getUnquotedFullText(ctx.codesystemId())
+ (ctx.versionSpecifier() != null
? "|" + getUnquotedFullText(ctx.versionSpecifier())
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@
import org.antlr.v4.runtime.CommonTokenStream;
import org.cqframework.cql.gen.cqlLexer;
import org.cqframework.cql.gen.cqlParser;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
@@ -13,11 +12,8 @@
@Service
public class LibraryCqlVisitorFactory {

@Value("${fhir-base-url}")
private String fhirBaseUrl;

public LibraryCqlVisitor visit(String cql) {
LibraryCqlVisitor result = new LibraryCqlVisitor(fhirBaseUrl);
LibraryCqlVisitor result = new LibraryCqlVisitor();
cqlParser.LibraryContext ctx = getLibraryContext(cql);
result.visit(ctx);
return result;
Original file line number Diff line number Diff line change
@@ -197,14 +197,13 @@ private void sortParameters(
if (madieMeasure.getGroups() != null) {
madieMeasure.getGroups().stream()
.forEach(
(g) ->
{
if (CollectionUtils.isNotEmpty(g.getStratifications())) {
strats.addAll(
g.getStratifications().stream()
.map(s -> s.getCqlDefinition())
.collect(Collectors.toList()));
}
(g) -> {
if (CollectionUtils.isNotEmpty(g.getStratifications())) {
strats.addAll(
g.getStratifications().stream()
.map(s -> s.getCqlDefinition())
.collect(Collectors.toList()));
}
});
}

Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@

import gov.cms.madie.madiefhirservice.constants.UriConstants;
import gov.cms.madie.madiefhirservice.cql.LibraryCqlVisitorFactory;
import gov.cms.madie.madiefhirservice.utils.FhirResourceHelpers;
import gov.cms.madie.models.library.CqlLibrary;
import gov.cms.madie.models.common.Version;
import lombok.extern.slf4j.Slf4j;
@@ -17,7 +18,6 @@
import org.hl7.fhir.r4.model.Meta;
import org.hl7.fhir.r4.model.RelatedArtifact;
import org.hl7.fhir.r4.model.Identifier.IdentifierUse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
@@ -39,9 +39,6 @@ public class LibraryTranslatorService {

private final LibraryCqlVisitorFactory libCqlVisitorFactory;

@Value("${fhir-base-url}")
private String fhirBaseUrl;

public LibraryTranslatorService(LibraryCqlVisitorFactory libCqlVisitorFactory) {
this.libCqlVisitorFactory = libCqlVisitorFactory;
}
@@ -64,7 +61,8 @@ public Library convertToFhirLibrary(CqlLibrary cqlLibrary) {
library.setContent(
createContent(cqlLibrary.getCql(), cqlLibrary.getElmJson(), cqlLibrary.getElmXml()));
library.setType(createType(UriConstants.LIBRARY_SYSTEM_TYPE_URI, SYSTEM_CODE));
library.setUrl(fhirBaseUrl + "/Library/" + cqlLibrary.getCqlLibraryName());
library.setUrl(
FhirResourceHelpers.buildResourceFullUrl("Library", cqlLibrary.getCqlLibraryName()));
library.setDataRequirement(distinctDataRequirements(visitor.getDataRequirements()));
library.setRelatedArtifact(distinctArtifacts(visitor.getRelatedArtifacts()));
library.setMeta(createLibraryMeta());
@@ -148,7 +146,7 @@ private List<RelatedArtifact> distinctArtifacts(List<RelatedArtifact> artifacts)
result.add(a);
}
});
result.sort(Comparator.comparing(RelatedArtifact::getUrl));
result.sort(Comparator.comparing(RelatedArtifact::getResource));
return result;
}

Original file line number Diff line number Diff line change
@@ -19,7 +19,6 @@
import org.hl7.fhir.r4.model.Library;
import org.hl7.fhir.r4.model.Narrative;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.Resource;
import org.springframework.stereotype.Service;

import java.util.HashMap;
@@ -50,7 +49,8 @@ public Bundle createMeasureBundle(
measureTranslatorService.createFhirMeasureForMadieMeasure(madieMeasure);

// Bundle entry for Measure resource
Bundle.BundleEntryComponent measureEntryComponent = getBundleEntryComponent(measure);
Bundle.BundleEntryComponent measureEntryComponent =
FhirResourceHelpers.getBundleEntryComponent(measure, "Transaction");
Bundle bundle =
new Bundle().setType(Bundle.BundleType.TRANSACTION).addEntry(measureEntryComponent);
// Bundle entries for all the library resources of a MADiE Measure
@@ -90,31 +90,20 @@ public Bundle createMeasureBundle(
public List<Bundle.BundleEntryComponent> createBundleComponentsForLibrariesOfMadieMeasure(
Measure madieMeasure, final String bundleType, final String accessToken) {
Library library = getMeasureLibraryResourceForMadieMeasure(madieMeasure);
Bundle.BundleEntryComponent mainLibraryBundleComponent = getBundleEntryComponent(library);
Bundle.BundleEntryComponent mainLibraryBundleComponent =
FhirResourceHelpers.getBundleEntryComponent(library, "Transaction");
Map<String, Library> includedLibraryMap = new HashMap<>();
libraryService.getIncludedLibraries(
madieMeasure.getCql(), includedLibraryMap, bundleType, accessToken);
List<Bundle.BundleEntryComponent> libraryBundleComponents =
includedLibraryMap.values().stream()
.map(this::getBundleEntryComponent)
.map((lib) -> FhirResourceHelpers.getBundleEntryComponent(lib, "Transaction"))
.collect(Collectors.toList());
// add main library first in the list
libraryBundleComponents.add(0, mainLibraryBundleComponent);
return libraryBundleComponents;
}

/** Creates BundleEntryComponent for given resource */
public Bundle.BundleEntryComponent getBundleEntryComponent(Resource resource) {
Bundle.BundleEntryRequestComponent requestComponent =
new Bundle.BundleEntryRequestComponent()
.setMethod(Bundle.HTTPVerb.PUT)
.setUrl(resource.getResourceType() + "/" + resource.getIdPart());
return new Bundle.BundleEntryComponent()
.setFullUrl(FhirResourceHelpers.getFullUrl(resource))
.setResource(resource)
.setRequest(requestComponent);
}

/**
* Creates Library resource for main library of MADiE Measure
*
Original file line number Diff line number Diff line change
@@ -59,7 +59,8 @@ public org.hl7.fhir.r4.model.Measure createFhirMeasureForMadieMeasure(Measure ma
.setTitle(madieMeasure.getMeasureName())
.setIdentifier(buildMeasureIdentifiers(madieMeasure))
.setExperimental(madieMeasure.getMeasureMetaData().isExperimental())
.setUrl(FhirResourceHelpers.buildMeasureUrl(madieMeasure.getCqlLibraryName()))
.setUrl(
FhirResourceHelpers.buildResourceFullUrl("Measure", madieMeasure.getCqlLibraryName()))
.setVersion(madieMeasure.getVersion().toString())
.setEffectivePeriod(
getPeriodFromDates(
@@ -76,7 +77,8 @@ public org.hl7.fhir.r4.model.Measure createFhirMeasureForMadieMeasure(Measure ma
.setLibrary(
Collections.singletonList(
new CanonicalType(
FhirResourceHelpers.buildLibraryUrl(madieMeasure.getCqlLibraryName()))))
FhirResourceHelpers.buildResourceFullUrl(
"Library", madieMeasure.getCqlLibraryName()))))
.setPurpose(UNKNOWN)
.setContact(buildContactDetail(madieMeasure.getMeasureMetaData().getSteward(), false))
.setGroup(buildGroups(madieMeasure.getGroups()))
Original file line number Diff line number Diff line change
@@ -73,9 +73,9 @@ public Map<String, Bundle> getTestCaseExportBundle(Measure measure, List<TestCas

String fileName = ExportFileNamesUtil.getTestCaseExportFileName(measure, testCase);
var measureReport = buildMeasureReport(testCase, measure, bundle);
var bundleEntryComponent = FhirResourceHelpers.getBundleEntryComponent(measureReport);
bundleEntryComponent.setFullUrl(
"https://madie.cms.gov/MeasureReport/" + measureReport.getId());
var bundleEntryComponent =
FhirResourceHelpers.getBundleEntryComponent(
measureReport, String.valueOf(bundle.getType()));
bundle.getEntry().add(bundleEntryComponent);
testCaseBundle.put(fileName, bundle);
}
@@ -98,7 +98,8 @@ private MeasureReport buildMeasureReport(
measureReport.setModifierExtension(buildModifierExtension());
measureReport.setStatus(MeasureReport.MeasureReportStatus.COMPLETE);
measureReport.setType(MeasureReport.MeasureReportType.INDIVIDUAL);
measureReport.setMeasure(FhirResourceHelpers.buildMeasureUrl(measure.getCqlLibraryName()));
measureReport.setMeasure(
FhirResourceHelpers.buildResourceFullUrl("Measure", measure.getCqlLibraryName()));
measureReport.setPeriod(
FhirResourceHelpers.getPeriodFromDates(
getUTCDates(measure.getMeasurementPeriodStart()),
Original file line number Diff line number Diff line change
@@ -14,22 +14,28 @@

@Component
public class FhirResourceHelpers {

private static String fhirBaseUrl;
private static String madieUrl;

@Value("${fhir-base-url}")
public void setFhirBaseUrl(String url) {
FhirResourceHelpers.fhirBaseUrl = url;
}

@Value("${madie.url}")
public void setMadieUrl(String url) {
FhirResourceHelpers.madieUrl = url;
}

public static Bundle.BundleEntryComponent getBundleEntryComponent(Resource resource) {
return new Bundle.BundleEntryComponent().setResource(resource);
public static Bundle.BundleEntryComponent getBundleEntryComponent(
Resource resource, String bundleType) {
Bundle.BundleEntryComponent entryComponent =
new Bundle.BundleEntryComponent()
.setFullUrl(buildResourceFullUrl(resource.fhirType(), resource.getIdPart()))
.setResource(resource);
// for the transaction bundles, add request object to the entry
if ("Transaction".equalsIgnoreCase(bundleType)) {
Bundle.BundleEntryRequestComponent requestComponent =
new Bundle.BundleEntryRequestComponent()
.setMethod(Bundle.HTTPVerb.POST)
.setUrl(resource.getResourceType() + "/" + resource.getIdPart());
entryComponent.setRequest(requestComponent);
}
return entryComponent;
}

public static Period getPeriodFromDates(Date startDate, Date endDate) {
@@ -49,22 +55,7 @@ public static Coding buildCoding(String code, String system, String display) {
return new Coding().setCode(code).setSystem(system).setDisplay(display);
}

public static String buildMeasureUrl(String measureLibraryName) {
return madieUrl + "/Measure/" + measureLibraryName;
}

public static String buildLibraryUrl(String libraryName) {
return fhirBaseUrl + "/Library/" + libraryName;
}

public static String getFullUrl(Resource resource) {
String resourceType = String.valueOf(resource.getResourceType());
if ("Measure".equals(resourceType)) {
return buildMeasureUrl(resource.getIdPart());
} else if ("Library".equals(resourceType)) {
return buildLibraryUrl(resource.getIdPart());
} else {
return null;
}
public static String buildResourceFullUrl(String resourceType, String resourceName) {
return madieUrl + "/" + resourceType + "/" + resourceName;
}
}
2 changes: 0 additions & 2 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -3,8 +3,6 @@ server:
servlet:
context-path: /api

fhir-base-url: ${FHIR_BASE_URL:http://ecqi.healthit.gov/ecqms}

madie:
cql-elm:
service:
Original file line number Diff line number Diff line change
@@ -60,19 +60,20 @@ class HumanReadableServiceTest implements ResourceFileUtil {

@BeforeEach
void setUp() {
Group measureGroup1 = Group.builder()
Group measureGroup1 =
Group.builder()
.id("GroupId1")
.groupDescription("some random group")
.measureGroupTypes(List.of(MeasureGroupTypes.OUTCOME))
.scoring(MeasureScoring.COHORT.toString())
.populations(List.of(
.populations(
List.of(
Population.builder()
.id("PopId1")
.name(PopulationType.INITIAL_POPULATION)
.definition("Initial Population")
.description(null)
.build()
))
.id("PopId1")
.name(PopulationType.INITIAL_POPULATION)
.definition("Initial Population")
.description(null)
.build()))
.build();
measureGroup1.setStratifications(null);

@@ -98,7 +99,7 @@ void setUp() {
.setName(madieMeasure.getCqlLibraryName())
.setTitle(madieMeasure.getMeasureName())
.setExperimental(true)
.setUrl("fhirBaseUrl/Measure/" + madieMeasure.getCqlLibraryName())
.setUrl("baseUrl/Measure/" + madieMeasure.getCqlLibraryName())
.setVersion(madieMeasure.getVersion().toString())
.setEffectivePeriod(
getPeriodFromDates(
Original file line number Diff line number Diff line change
@@ -29,8 +29,6 @@
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.ArgumentMatchers.anyString;
@@ -120,12 +118,12 @@ public void testCreateMeasureBundle() {
Bundle.BundleEntryRequestComponent measureEntryRequest = bundle.getEntry().get(0).getRequest();
assertThat(
measureEntryRequest.getUrl(), is(equalTo("Measure/" + madieMeasure.getCqlLibraryName())));
assertThat(measureEntryRequest.getMethod(), is(equalTo(Bundle.HTTPVerb.PUT)));
assertThat(measureEntryRequest.getMethod(), is(equalTo(Bundle.HTTPVerb.POST)));

Bundle.BundleEntryRequestComponent libraryEntryRequest = bundle.getEntry().get(1).getRequest();
assertThat(
libraryEntryRequest.getUrl(), is(equalTo("Library/" + madieMeasure.getCqlLibraryName())));
assertThat(libraryEntryRequest.getMethod(), is(equalTo(Bundle.HTTPVerb.PUT)));
assertThat(libraryEntryRequest.getMethod(), is(equalTo(Bundle.HTTPVerb.POST)));
}

@Test
Original file line number Diff line number Diff line change
@@ -81,7 +81,6 @@ public void setUp() throws JsonProcessingException {
String cvMeasureJson =
getStringFromTestResource("/measures/SimpleFhirMeasureLib/madie_cv_measure.json");
madieCVMeasure = MeasureTestHelper.createMadieMeasureFromJson(cvMeasureJson);
ReflectionTestUtils.setField(fhirResourceHelpers, "fhirBaseUrl", "cms.gov");
ReflectionTestUtils.setField(fhirResourceHelpers, "madieUrl", "madie.cms.gov");
}

Loading

0 comments on commit a951ceb

Please sign in to comment.