From f6af4a4a223fa6d81fe5f8cba49eab9230178655 Mon Sep 17 00:00:00 2001 From: Chris0296 <38321098+Chris0296@users.noreply.github.com> Date: Fri, 22 Mar 2024 09:30:39 -0700 Subject: [PATCH] Add common getExpansion() function (#763) * Add common getExpansion() function * Mock out server calls * Specify charset * Add TerminologyServerClient Bean to config * Refactor - make client non VSAC specific & add statuc variables * getExpansion changes * Refactor - take credentials from properties, cleanup, add IT * Fix issue with authoritative source url and system-version parameter Update test file to reflect actual value set * Remove addition of ValueSet level system-version param & update test to reflect. Privatise getters/setters. --------- Co-authored-by: Adam Stevenson --- .../org/opencds/cqf/ruler/cr/CrConfig.java | 6 + .../cqf/ruler/cr/CrRulerProperties.java | 11 ++ .../ruler/cr/KnowledgeArtifactProcessor.java | 97 +++++++++++- .../cqf/ruler/cr/TerminologyServerClient.java | 79 ++++++++++ plugin/cr/src/main/resources/application.yaml | 2 + .../cr/KnowledgeArtifactProcessorIT.java | 51 ++++++ .../cr/KnowledgeArtifactProcessorTest.java | 75 +++++++++ .../ruler/cr/r4/test/valueset-expanded.json | 146 ++++++++++++++++++ ...alueset-2.16.840.1.113762.1.4.1116.89.json | 32 +--- .../cr/r4/valueset/valueset-vsm-authored.json | 41 +++++ 10 files changed, 508 insertions(+), 32 deletions(-) create mode 100644 plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/TerminologyServerClient.java create mode 100644 plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/KnowledgeArtifactProcessorIT.java create mode 100644 plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/KnowledgeArtifactProcessorTest.java create mode 100644 plugin/cr/src/test/resources/org/opencds/cqf/ruler/cr/r4/test/valueset-expanded.json create mode 100644 plugin/cr/src/test/resources/org/opencds/cqf/ruler/cr/r4/valueset/valueset-vsm-authored.json diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/CrConfig.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/CrConfig.java index 5de6987de..21953802c 100644 --- a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/CrConfig.java +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/CrConfig.java @@ -116,4 +116,10 @@ public KnowledgeArtifactProcessor knowledgeArtifactProcessor() { return new KnowledgeArtifactProcessor(); } + @Bean + @Conditional(OnR4Condition.class) + public TerminologyServerClient terminologyServerClient() { + return new TerminologyServerClient(crRulerProperties().getVsacUsername(), crRulerProperties().getVsacApiKey()); + } + } diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/CrRulerProperties.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/CrRulerProperties.java index 26b344342..08f9da88a 100644 --- a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/CrRulerProperties.java +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/CrRulerProperties.java @@ -20,5 +20,16 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } + private String vsacUsername; + + public String getVsacUsername() { return vsacUsername; } + + public void setVsacUsername(String vsacUsername) { this.vsacUsername = vsacUsername; } + + private String vsacApiKey; + + public String getVsacApiKey() { return vsacApiKey; } + + public void setVsacApiKey(String vsacApiKey) { this.vsacApiKey = vsacApiKey; } } diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/KnowledgeArtifactProcessor.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/KnowledgeArtifactProcessor.java index dca1d83eb..fb09a8e7e 100644 --- a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/KnowledgeArtifactProcessor.java +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/KnowledgeArtifactProcessor.java @@ -1,6 +1,7 @@ package org.opencds.cqf.ruler.cr; import static java.util.Comparator.comparing; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; @@ -62,6 +63,7 @@ import org.opencds.cqf.ruler.cr.r4.helper.ResourceClassMapHelper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; import ca.uhn.fhir.context.FhirContext; @@ -84,14 +86,20 @@ @Configurable // TODO: This belongs in the Evaluator. Only included in Ruler at dev time for shorter cycle. public class KnowledgeArtifactProcessor { + @Autowired + private TerminologyServerClient terminologyServerClient; private Logger myLog = LoggerFactory.getLogger(KnowledgeArtifactProcessor.class); public static final String CPG_INFERENCEEXPRESSION = "http://hl7.org/fhir/uv/cpg/StructureDefinition/cpg-inferenceExpression"; public static final String CPG_ASSERTIONEXPRESSION = "http://hl7.org/fhir/uv/cpg/StructureDefinition/cpg-assertionExpression"; public static final String CPG_FEATUREEXPRESSION = "http://hl7.org/fhir/uv/cpg/StructureDefinition/cpg-featureExpression"; public static final String releaseLabelUrl = "http://hl7.org/fhir/StructureDefinition/artifact-releaseLabel"; public static final String releaseDescriptionUrl = "http://hl7.org/fhir/StructureDefinition/artifact-releaseDescription"; + public static final String authoritativeSourceUrl = "http://hl7.org/fhir/StructureDefinition/valueset-authoritativeSource"; + public static final String expansionParametersUrl = "http://hl7.org/fhir/us/ecr/StructureDefinition/us-ph-expansion-parameters-extension"; public static final String valueSetPriorityUrl = "http://aphl.org/fhir/vsm/StructureDefinition/vsm-valueset-priority"; public static final String valueSetConditionUrl = "http://aphl.org/fhir/vsm/StructureDefinition/vsm-valueset-condition"; + public static final String vsmValueSetTagCodeSystemUrl = "http://aphl.org/fhir/vsm/CodeSystem/vsm-valueset-tag"; + public static final String vsmValueSetTagVSMAuthoredCode = "vsm-authored"; public static final String valueSetPriorityCode = "priority"; public static final String valueSetConditionCode = "focus"; public final List preservedExtensionUrls = List.of( @@ -1025,6 +1033,7 @@ private UsageContext getOrCreateUsageContext(List usageContexts, S return n; }); } + void recursivePackage( MetadataResource resource, Bundle bundle, @@ -1057,6 +1066,7 @@ void recursivePackage( .forEach(component -> recursivePackage((MetadataResource)component, bundle, hapiFhirRepository, capability, include, artifactVersion, checkArtifactVersion, forceArtifactVersion)); } } + private List combineComponentsAndDependencies(KnowledgeArtifactAdapter adapter) { return Stream.concat(adapter.getComponents().stream(), adapter.getDependencies().stream()).collect(Collectors.toList()); } @@ -1250,7 +1260,7 @@ private void doesValueSetNeedExpansion(ValueSet vset, IFhirResourceDaoValueSet expansionParams = new ArrayList<>(); + ValueSet.ValueSetExpansionParameterComponent parameterNaive = new ValueSet.ValueSetExpansionParameterComponent(); + parameterNaive.setName("naive"); + parameterNaive.setValue(new BooleanType(true)); + expansionParams.add(parameterNaive); + expansion.setParameter(expansionParams); + + for (ValueSet.ConceptSetComponent csc : valueSet.getCompose().getInclude()) { + for (ValueSet.ConceptReferenceComponent crc : csc.getConcept()) { + expansion.addContains() + .setCode(crc.getCode()) + .setSystem(csc.getSystem()) + .setVersion(csc.getVersion()) + .setDisplay(crc.getDisplay()); + } + } + valueSet.setExpansion(expansion); + } else { + try { + expandedValueSet = terminologyServerClient.expand(valueSet, authoritativeSourceUrl, expansionParameters); + valueSet.setExpansion(expandedValueSet.getExpansion()); + } catch (Exception ex) { + myLog.warn("Terminology Server expansion failed: {}", valueSet.getIdElement().getValue(), ex); + } + } + } + + public boolean isVSMAuthoredValueSet(ValueSet valueSet) { + return valueSet.hasMeta() + && valueSet.getMeta().hasTag() + && valueSet.getMeta().getTag(vsmValueSetTagCodeSystemUrl, vsmValueSetTagVSMAuthoredCode) != null; + } + + public boolean hasSimpleCompose(ValueSet valueSet) { + if (valueSet.hasCompose()) { + if (valueSet.getCompose().hasExclude()) { + return false; + } + for (ValueSet.ConceptSetComponent csc : valueSet.getCompose().getInclude()) { + if (csc.hasValueSet()) { + // Cannot expand a compose that references a value set + return false; + } + + if (!csc.hasSystem()) { + // Cannot expand a compose that does not have a system + return false; + } + + if (csc.hasFilter()) { + // Cannot expand a compose that has a filter + return false; + } + + if (!csc.hasConcept()) { + // Cannot expand a compose that does not enumerate concepts + return false; + } + } + + // If all includes are simple, the compose can be expanded + return true; + } + + return false; + } + private class diffCache { private final Map diffs = new HashMap(); private final Map resources = new HashMap(); diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/TerminologyServerClient.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/TerminologyServerClient.java new file mode 100644 index 000000000..36889997f --- /dev/null +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/TerminologyServerClient.java @@ -0,0 +1,79 @@ +package org.opencds.cqf.ruler.cr; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.rest.client.interceptor.AdditionalRequestHeadersInterceptor; +import org.apache.commons.lang3.StringUtils; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.ValueSet; +import org.jetbrains.annotations.NotNull; +import org.opencds.cqf.cql.evaluator.fhir.util.Canonicals; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class TerminologyServerClient { + + private final FhirContext ctx; + + private String username; + + private String getUsername() { + return username; + } + + private void setUsername(String username) { + this.username = username; + } + + private String apiKey; + + private String getApiKey() { + return apiKey; + } + + private void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + public TerminologyServerClient() { + ctx = FhirContext.forR4(); + } + + public TerminologyServerClient(String username, String apiKey) { + this(); + setUsername(username); + setApiKey(apiKey); + } + + public ValueSet expand(ValueSet valueSet, String authoritativeSource, Parameters expansionParameters) { + IGenericClient fhirClient = ctx.newRestfulGenericClient(getAuthoritativeSourceBase(authoritativeSource)); + fhirClient.registerInterceptor(getAuthInterceptor(getUsername(), getApiKey())); + + // Invoke by Value Set ID + return fhirClient + .operation() + .onInstance(valueSet.getId()) + .named("$expand") + .withParameters(expansionParameters) + .returnResourceType(ValueSet.class) + .execute(); + } + + private AdditionalRequestHeadersInterceptor getAuthInterceptor(String username, String apiKey) { + String authString = StringUtils.join("Basic ", Base64.getEncoder() + .encodeToString(StringUtils.join(username, ":", apiKey).getBytes(StandardCharsets.UTF_8))); + AdditionalRequestHeadersInterceptor authInterceptor = new AdditionalRequestHeadersInterceptor(); + authInterceptor.addHeaderValue("Authorization", authString); + return authInterceptor; + } + + // Strips resource and id from the authoritative source URL, these are not needed as the client constructs the URL. + // Converts http URLs to https + private String getAuthoritativeSourceBase(String authoritativeSource) { + authoritativeSource = authoritativeSource.substring(0, authoritativeSource.indexOf(Canonicals.getResourceType(authoritativeSource))); + if (authoritativeSource.startsWith("http://")) { + authoritativeSource = authoritativeSource.replaceFirst("http://", "https://"); + } + return authoritativeSource; + } +} diff --git a/plugin/cr/src/main/resources/application.yaml b/plugin/cr/src/main/resources/application.yaml index 9dc46221d..d68a10686 100644 --- a/plugin/cr/src/main/resources/application.yaml +++ b/plugin/cr/src/main/resources/application.yaml @@ -2,3 +2,5 @@ hapi: fhir: rulercr: enabled: true + vsac-username: + vsac-api-key: diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/KnowledgeArtifactProcessorIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/KnowledgeArtifactProcessorIT.java new file mode 100644 index 000000000..a08375974 --- /dev/null +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/KnowledgeArtifactProcessorIT.java @@ -0,0 +1,51 @@ +package org.opencds.cqf.ruler.cr; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.parser.IParser; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.ValueSet; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.opencds.cqf.ruler.test.RestIntegrationTest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Lazy; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; + +@Lazy +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + classes = {KnowledgeArtifactProcessorIT.class, CrConfig.class}, + properties = {"hapi.fhir.fhir_version=r4", "hapi.fhir.security.basic_auth.enabled=false"}) +public class KnowledgeArtifactProcessorIT extends RestIntegrationTest { + + @Autowired + KnowledgeArtifactProcessor processor; + + @Autowired + TerminologyServerClient client; + + @Disabled + @Test + void testGetExpansionVSAC() throws IOException { + // given + FhirContext ctx = FhirContext.forR4(); + + String input = new String(this.getClass().getResourceAsStream("r4/valueset/valueset-2.16.840.1.113762.1.4.1116.89.json").readAllBytes()); + IParser parser = ctx.newJsonParser(); + ValueSet valueSet = parser.parseResource(ValueSet.class, input); + String codeSystemVersion = valueSet.getCompose().getInclude().get(0).getVersion(); + + Parameters expansionParameters = new Parameters(); + + // when + processor.expandValueSet(valueSet, expansionParameters); + + // then + assertNotNull(valueSet.getExpansion()); + assertEquals(16, valueSet.getExpansion().getTotal()); + } + +} diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/KnowledgeArtifactProcessorTest.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/KnowledgeArtifactProcessorTest.java new file mode 100644 index 000000000..ca63abe7d --- /dev/null +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/KnowledgeArtifactProcessorTest.java @@ -0,0 +1,75 @@ +package org.opencds.cqf.ruler.cr; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.parser.IParser; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.ValueSet; +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 java.io.IOException; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@ExtendWith(MockitoExtension.class) +public class KnowledgeArtifactProcessorTest { + + @InjectMocks + KnowledgeArtifactProcessor processor; + + @Mock + TerminologyServerClient client; + + @Test + void testGetExpansionVSAC() throws IOException { + // given + FhirContext ctx = FhirContext.forR4(); + + String input = new String(this.getClass().getResourceAsStream("r4/valueset/valueset-2.16.840.1.113762.1.4.1116.89.json").readAllBytes()); + IParser parser = ctx.newJsonParser(); + ValueSet valueSet = parser.parseResource(ValueSet.class, input); + + Parameters expansionParameters = new Parameters(); + expansionParameters.addParameter("system-version", "http://snomed.info/sct|http://snomed.info/sct/731000124108/version/20230901"); + + // when + String expandedValueSetString = new String(this.getClass().getResourceAsStream("r4/test/valueset-expanded.json").readAllBytes()); + ValueSet expandedValueSet = parser.parseResource(ValueSet.class, expandedValueSetString); + Mockito.when(client.expand(Mockito.eq(valueSet), Mockito.eq(valueSet.getUrl()), Mockito.eq(expansionParameters))).thenReturn(expandedValueSet); + + processor.expandValueSet(valueSet, expansionParameters); + + // then + assertNotNull(valueSet.getExpansion()); + assertEquals(16, valueSet.getExpansion().getTotal()); + } + + @Test + void testGetExpansionNaive() throws IOException { + FhirContext ctx = FhirContext.forR4(); + + String input = new String(this.getClass().getResourceAsStream("r4/valueset/valueset-vsm-authored.json").readAllBytes()); + IParser parser = ctx.newJsonParser(); + ValueSet valueSet = parser.parseResource(ValueSet.class, input); + Parameters expansionParameters = new Parameters(); + expansionParameters.addParameter("system-version", "http://snomed.info/sct|http://snomed.info/sct/731000124108/version/20230901"); + + // when + processor.expandValueSet(valueSet, expansionParameters); + + // then + assertNotNull(valueSet.getExpansion()); + assertNotNull(valueSet.getExpansion().getParameter().get(0)); + assertEquals("naive", valueSet.getExpansion().getParameter().get(0).getName()); + assertTrue(valueSet.getExpansion().getParameter().get(0).getValueBooleanType().booleanValue()); + assertEquals(1, valueSet.getExpansion().getContains().size()); + assertEquals("ANC.A.DE13", valueSet.getExpansion().getContains().get(0).getCode()); + assertEquals("Co-habitants", valueSet.getExpansion().getContains().get(0).getDisplay()); + } +} diff --git a/plugin/cr/src/test/resources/org/opencds/cqf/ruler/cr/r4/test/valueset-expanded.json b/plugin/cr/src/test/resources/org/opencds/cqf/ruler/cr/r4/test/valueset-expanded.json new file mode 100644 index 000000000..b151bf7bc --- /dev/null +++ b/plugin/cr/src/test/resources/org/opencds/cqf/ruler/cr/r4/test/valueset-expanded.json @@ -0,0 +1,146 @@ +{ + "resourceType": "ValueSet", + "id": "2.16.840.1.113762.1.4.1116.89", + "meta": { + "versionId": "9", + "lastUpdated": "2023-12-21T17:43:03.000-05:00", + "profile": [ + "http://hl7.org/fhir/StructureDefinition/shareablevalueset", + "http://hl7.org/fhir/us/cqfmeasures/StructureDefinition/computable-valueset-cqfm", + "http://hl7.org/fhir/us/cqfmeasures/StructureDefinition/publishable-valueset-cqfm" + ] + }, + "extension": [ + { + "url": "http://hl7.org/fhir/StructureDefinition/valueset-effectiveDate", + "valueDate": "2023-07-11" + } + ], + "url": "http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113762.1.4.1116.89", + "identifier": [ + { + "system": "urn:ietf:rfc:3986", + "value": "urn:oid:2.16.840.1.113762.1.4.1116.89" + } + ], + "version": "20230711", + "name": "LungCancer", + "title": "Lung Cancer", + "status": "active", + "date": "2023-07-11T01:00:57-04:00", + "publisher": "American Society of Clinical Oncology Steward", + "expansion": { + "identifier": "urn:uuid:ff2c66da-152e-4236-9d8a-a7345516cf6b", + "timestamp": "2024-02-28T12:53:56-05:00", + "total": 16, + "offset": 0, + "parameter": [ + { + "name": "count", + "valueInteger": 1000 + }, + { + "name": "offset", + "valueInteger": 0 + } + ], + "contains": [ + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.00", + "display": "Malignant neoplasm of unspecified main bronchus" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.01", + "display": "Malignant neoplasm of right main bronchus" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.02", + "display": "Malignant neoplasm of left main bronchus" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.10", + "display": "Malignant neoplasm of upper lobe, unspecified bronchus or lung" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.11", + "display": "Malignant neoplasm of upper lobe, right bronchus or lung" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.12", + "display": "Malignant neoplasm of upper lobe, left bronchus or lung" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.2", + "display": "Malignant neoplasm of middle lobe, bronchus or lung" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.30", + "display": "Malignant neoplasm of lower lobe, unspecified bronchus or lung" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.31", + "display": "Malignant neoplasm of lower lobe, right bronchus or lung" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.32", + "display": "Malignant neoplasm of lower lobe, left bronchus or lung" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.80", + "display": "Malignant neoplasm of overlapping sites of unspecified bronchus and lung" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.81", + "display": "Malignant neoplasm of overlapping sites of right bronchus and lung" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.82", + "display": "Malignant neoplasm of overlapping sites of left bronchus and lung" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.90", + "display": "Malignant neoplasm of unspecified part of unspecified bronchus or lung" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.91", + "display": "Malignant neoplasm of unspecified part of right bronchus or lung" + }, + { + "system": "http://hl7.org/fhir/sid/icd-10-cm", + "version": "2024", + "code": "C34.92", + "display": "Malignant neoplasm of unspecified part of left bronchus or lung" + } + ] + } +} diff --git a/plugin/cr/src/test/resources/org/opencds/cqf/ruler/cr/r4/valueset/valueset-2.16.840.1.113762.1.4.1116.89.json b/plugin/cr/src/test/resources/org/opencds/cqf/ruler/cr/r4/valueset/valueset-2.16.840.1.113762.1.4.1116.89.json index 77422dd31..22cd468d2 100644 --- a/plugin/cr/src/test/resources/org/opencds/cqf/ruler/cr/r4/valueset/valueset-2.16.840.1.113762.1.4.1116.89.json +++ b/plugin/cr/src/test/resources/org/opencds/cqf/ruler/cr/r4/valueset/valueset-2.16.840.1.113762.1.4.1116.89.json @@ -10,37 +10,7 @@ "compose": { "include": [ { - "system": "http://hl7.org/fhir/sid/icd-9-cm", - "version": "2013", - "concept": [ - { - "code": "162.2", - "display": "Malignant neoplasm of main bronchus" - }, - { - "code": "162.3", - "display": "Malignant neoplasm of upper lobe, bronchus or lung" - }, - { - "code": "162.4", - "display": "Malignant neoplasm of middle lobe, bronchus or lung" - }, - { - "code": "162.5", - "display": "Malignant neoplasm of lower lobe, bronchus or lung" - }, - { - "code": "162.8", - "display": "Malignant neoplasm of other parts of bronchus or lung" - }, - { - "code": "162.9", - "display": "Malignant neoplasm of bronchus and lung, unspecified" - } - ] - }, - { - "system": "http://hl7.org/fhir/sid/icd-10", + "system": "http://hl7.org/fhir/sid/icd-10-cm", "version": "2020", "concept": [ { diff --git a/plugin/cr/src/test/resources/org/opencds/cqf/ruler/cr/r4/valueset/valueset-vsm-authored.json b/plugin/cr/src/test/resources/org/opencds/cqf/ruler/cr/r4/valueset/valueset-vsm-authored.json new file mode 100644 index 000000000..d6e3dcf54 --- /dev/null +++ b/plugin/cr/src/test/resources/org/opencds/cqf/ruler/cr/r4/valueset/valueset-vsm-authored.json @@ -0,0 +1,41 @@ +{ + "resourceType": "ValueSet", + "id": "vsm-authored-example", + "meta": { + "tag" : [{ + "system" : "http://aphl.org/fhir/vsm/CodeSystem/vsm-valueset-tag", + "code" : "vsm-authored" + }] + }, + "extension": [ { + "url": "http://hl7.org/fhir/uv/cpg/StructureDefinition/cpg-knowledgeCapability", + "valueString": "executable" + }, { + "url": "http://hl7.org/fhir/uv/cpg/StructureDefinition/cpg-knowledgeRepresentationLevel", + "valueString": "executable" + } ], + "url": "http://aphl.org/fhir/vsm/ValueSet/vsm-authored-example", + "name": "VSMAuthoredExample", + "title": "VSM Authored Example", + "status": "draft", + "experimental": true, + "description": "An example of a VSM-authored ValueSet - indicated via the Meta.tag with code 'vsm-authored'", + "immutable": true, + "compose": { + "include": [ { + "system": "http://fhir.org/guides/who/anc-cds/CodeSystem/anc-custom-codes", + "concept": [ { + "code": "ANC.A.DE13", + "display": "Co-habitants" + } ] + } ] + }, + "expansion": { + "timestamp": "2021-11-30T07:11:22-07:00", + "contains": [ { + "system": "http://fhir.org/guides/who/anc-cds/CodeSystem/anc-custom-codes", + "code": "ANC.A.DE13", + "display": "Co-habitants" + } ] + } +}