diff --git a/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/fhir/DataRequirementsProcessor.java b/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/fhir/DataRequirementsProcessor.java index 49877aa4a..3a3c79d6f 100644 --- a/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/fhir/DataRequirementsProcessor.java +++ b/Src/java/elm-fhir/src/main/java/org/cqframework/cql/elm/requirements/fhir/DataRequirementsProcessor.java @@ -4,6 +4,8 @@ import org.cqframework.cql.cql2elm.LibraryManager; import org.cqframework.cql.cql2elm.NamespaceManager; import org.cqframework.cql.cql2elm.model.TranslatedLibrary; +import org.cqframework.cql.elm.tracking.TrackBack; +import org.cqframework.cql.elm.tracking.Trackable; import org.hl7.cql.model.IntervalType; import org.hl7.cql.model.ListType; import org.hl7.cql.model.NamedType; @@ -518,6 +520,36 @@ private String toFHIRTypeCode(org.hl7.cql.model.DataType dataType, AtomicBoolean return "Any"; } + /** + * TODO: This function is used to determine the library identifier in which the reference element was declared + * This is only possible if the ELM includes trackbacks, which are typically only available in ELM coming straight from the translator + * (i.e. de-compiled ELM won't have this) + * The issue is that when code filter expressions are distributed, the references may cross declaration contexts (i.e. a code filter + * expression from the library in which it was first expressed may be evaluated in the context of a data requirement inferred + * from a retrieve in a different library. If the library aliases are consistent, this isn't an issue, but if the library aliases + * are different, this will result in a failure to resolve the reference (or worse, an incorrect reference). + * This is being reported as a warning currently, but it is really an issue with the data requirement distribution, it should be + * rewriting references as it distributes (or better yet, ELM should have a library identifier that is fully resolved, rather + * than relying on library-specific aliases for library referencing elements. + * @param trackable + * @param libraryIdentifier + * @return + */ + private VersionedIdentifier getDeclaredLibraryIdentifier(Trackable trackable, VersionedIdentifier libraryIdentifier) { + if (trackable.getTrackbacks() != null) { + for (TrackBack tb : trackable.getTrackbacks()) { + if (tb.getLibrary() != null) { + return tb.getLibrary(); + } + } + } + + validationMessages.add(new ValidationMessage(ValidationMessage.Source.Publisher, ValidationMessage.IssueType.PROCESSING, "Data requirements processing", + String.format("Library referencing element (%s) is potentially being resolved in a different context than it was declared. Ensure library aliases are consistent", trackable.getClass().getSimpleName()), ValidationMessage.IssueSeverity.WARNING)); + + return libraryIdentifier; + } + private org.hl7.fhir.r5.model.DataRequirement.DataRequirementCodeFilterComponent toCodeFilterComponent(ElmRequirementsContext context, VersionedIdentifier libraryIdentifier, String property, Expression value) { org.hl7.fhir.r5.model.DataRequirement.DataRequirementCodeFilterComponent cfc = new org.hl7.fhir.r5.model.DataRequirement.DataRequirementCodeFilterComponent(); @@ -528,7 +560,8 @@ private org.hl7.fhir.r5.model.DataRequirement.DataRequirementCodeFilterComponent if (value instanceof ValueSetRef) { ValueSetRef vsr = (ValueSetRef)value; - cfc.setValueSet(toReference(context.resolveValueSetRef(libraryIdentifier, vsr))); + VersionedIdentifier declaredLibraryIdentifier = getDeclaredLibraryIdentifier(vsr, libraryIdentifier); + cfc.setValueSet(toReference(context.resolveValueSetRef(declaredLibraryIdentifier, vsr))); } if (value instanceof org.hl7.elm.r1.ToList) { @@ -950,7 +983,8 @@ private void resolveCodeFilterCodes(ElmRequirementsContext context, VersionedIde Expression e) { if (e instanceof org.hl7.elm.r1.CodeRef) { CodeRef cr = (CodeRef)e; - cfc.addCode(toCoding(context, libraryIdentifier, context.toCode(context.resolveCodeRef(libraryIdentifier, cr)))); + VersionedIdentifier declaredLibraryIdentifier = getDeclaredLibraryIdentifier(cr, libraryIdentifier); + cfc.addCode(toCoding(context, libraryIdentifier, context.toCode(context.resolveCodeRef(declaredLibraryIdentifier, cr)))); } if (e instanceof org.hl7.elm.r1.Code) { @@ -959,8 +993,9 @@ private void resolveCodeFilterCodes(ElmRequirementsContext context, VersionedIde if (e instanceof org.hl7.elm.r1.ConceptRef) { ConceptRef cr = (ConceptRef)e; + VersionedIdentifier declaredLibraryIdentifier = getDeclaredLibraryIdentifier(cr, libraryIdentifier); org.hl7.fhir.r5.model.CodeableConcept c = toCodeableConcept(context, libraryIdentifier, - context.toConcept(libraryIdentifier, context.resolveConceptRef(libraryIdentifier, cr))); + context.toConcept(libraryIdentifier, context.resolveConceptRef(declaredLibraryIdentifier, cr))); for (org.hl7.fhir.r5.model.Coding code : c.getCoding()) { cfc.addCode(code); } @@ -972,10 +1007,16 @@ private void resolveCodeFilterCodes(ElmRequirementsContext context, VersionedIde cfc.addCode(code); } } + + if (e instanceof org.hl7.elm.r1.Literal) { + org.hl7.elm.r1.Literal literal = (org.hl7.elm.r1.Literal)e; + cfc.addCode().setCode(literal.getValue()); + } } private org.hl7.fhir.r5.model.Coding toCoding(ElmRequirementsContext context, VersionedIdentifier libraryIdentifier, Code code) { - CodeSystemDef codeSystemDef = context.resolveCodeSystemRef(libraryIdentifier, code.getSystem()); + VersionedIdentifier declaredLibraryIdentifier = getDeclaredLibraryIdentifier(code.getSystem(), libraryIdentifier); + CodeSystemDef codeSystemDef = context.resolveCodeSystemRef(declaredLibraryIdentifier, code.getSystem()); org.hl7.fhir.r5.model.Coding coding = new org.hl7.fhir.r5.model.Coding(); coding.setCode(code.getCode()); coding.setDisplay(code.getDisplay()); diff --git a/Src/java/elm-fhir/src/test/java/org/cqframework/cql/elm/requirements/fhir/DataRequirementsProcessorTest.java b/Src/java/elm-fhir/src/test/java/org/cqframework/cql/elm/requirements/fhir/DataRequirementsProcessorTest.java index 9cb6c137e..6ebd37241 100644 --- a/Src/java/elm-fhir/src/test/java/org/cqframework/cql/elm/requirements/fhir/DataRequirementsProcessorTest.java +++ b/Src/java/elm-fhir/src/test/java/org/cqframework/cql/elm/requirements/fhir/DataRequirementsProcessorTest.java @@ -1406,6 +1406,16 @@ public void TestHEDISBCSE() throws IOException { assertNotNull(moduleDefinitionLibrary); } + private void assertEqualToExpectedModuleDefinitionLibrary(org.hl7.fhir.r5.model.Library actualModuleDefinitionLibrary, String pathToExpectedModuleDefinitionLibrary) { + FhirContext context = getFhirContext(); + IParser parser = context.newJsonParser(); + org.hl7.fhir.r5.model.Library expectedModuleDefinitionLibrary = (org.hl7.fhir.r5.model.Library)parser.parseResource(DataRequirementsProcessorTest.class.getResourceAsStream(pathToExpectedModuleDefinitionLibrary)); + assertNotNull(expectedModuleDefinitionLibrary); + actualModuleDefinitionLibrary.setDate(null); + expectedModuleDefinitionLibrary.setDate(null); + assertTrue(actualModuleDefinitionLibrary.equalsDeep(expectedModuleDefinitionLibrary)); + } + @Test public void TestEXMLogic() throws IOException { CqlTranslatorOptions translatorOptions = getTranslatorOptions(); @@ -1413,13 +1423,19 @@ public void TestEXMLogic() throws IOException { CqlTranslator translator = setupDataRequirementsAnalysis("EXMLogic/EXMLogic.cql", translatorOptions); org.hl7.fhir.r5.model.Library moduleDefinitionLibrary = getModuleDefinitionLibrary(translator, translatorOptions); assertNotNull(moduleDefinitionLibrary); - FhirContext context = getFhirContext(); - IParser parser = context.newJsonParser(); - org.hl7.fhir.r5.model.Library expectedModuleDefinitionLibrary = (org.hl7.fhir.r5.model.Library)parser.parseResource(DataRequirementsProcessorTest.class.getResourceAsStream("EXMLogic/Library-EXMLogic-data-requirements.json")); - assertNotNull(expectedModuleDefinitionLibrary); - moduleDefinitionLibrary.setDate(null); - expectedModuleDefinitionLibrary.setDate(null); - assertTrue(moduleDefinitionLibrary.equalsDeep(expectedModuleDefinitionLibrary)); + assertEqualToExpectedModuleDefinitionLibrary(moduleDefinitionLibrary, "EXMLogic/Library-EXMLogic-data-requirements.json"); + + //outputModuleDefinitionLibrary(moduleDefinitionLibrary); + } + + @Test + public void TestWithDependencies() throws IOException { + CqlTranslatorOptions translatorOptions = getTranslatorOptions(); + translatorOptions.setAnalyzeDataRequirements(false); + CqlTranslator translator = setupDataRequirementsAnalysis("WithDependencies/BSElements.cql", translatorOptions); + org.hl7.fhir.r5.model.Library moduleDefinitionLibrary = getModuleDefinitionLibrary(translator, translatorOptions); + assertNotNull(moduleDefinitionLibrary); + assertEqualToExpectedModuleDefinitionLibrary(moduleDefinitionLibrary, "WithDependencies/Library-BSElements-data-requirements.json"); //outputModuleDefinitionLibrary(moduleDefinitionLibrary); } diff --git a/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/BSElements.cql b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/BSElements.cql new file mode 100644 index 000000000..a01b2a060 --- /dev/null +++ b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/BSElements.cql @@ -0,0 +1,17 @@ +/* Context-independent Data Elements. (e.g., the Retrieves, to be used in more than one context.) */ + +library BSElements version '1.0.000' + +using FHIR version '4.0.1' + +include FHIRCommon version '4.0.1' called FHIRCommon +include FHIRHelpers version '4.0.1' called FHIRHelpers +include CommonConcepts version '1.0.000' called CommonCx +include CommonElements version '1.0.000' called CommonEl + +include Ind2E31A37EB104A7D1 version '1.0.000' called Ind2E31A37EB104A7D1 + +context Patient + +define "4. Biliopancreatic bypass with duodenal switch in patients ages greater than or equal to 18 years with BMI greater than or equal to 50 kg/(meter squared)": + Ind2E31A37EB104A7D1."4. Biliopancreatic bypass with duodenal switch in patients ages greater than or equal to 18 years with BMI greater than or equal to 50 kg/(meter squared)" diff --git a/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/CommonConcepts.cql b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/CommonConcepts.cql new file mode 100644 index 000000000..1436462f6 --- /dev/null +++ b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/CommonConcepts.cql @@ -0,0 +1,67 @@ +/* Common Terminology */ +library CommonConcepts version '1.0.000' + +using FHIR version '4.0.1' + +codesystem "ConditionVerificationStatusCodes": 'http://terminology.hl7.org/CodeSystem/condition-ver-status' + +valueset "Severe Pain Valueset": 'http://example.com/fhir/ValueSet/rc-severePain' +valueset "Functional Disability Valueset": 'http://example.com/fhir/ValueSet/rc_functionalDisabilityDJD' +valueset "Active Condition": 'http://fhir.org/guides/cqf/common/ValueSet/active-condition' + +valueset "ro_bodyMassIndex_kg_per_m2": 'http://example.com/fhir/ValueSet/ro_bodyMassIndex_kg_per_m2' +valueset "ro_weight_kg": 'http://example.com/fhir/ValueSet/ro_weight_kg' +valueset "ro_weight_lb": 'http://example.com/fhir/ValueSet/ro_weight_lb' +valueset "ro_height_in": 'http://example.com/fhir/ValueSet/ro_height_in' +valueset "ro_height_cm": 'http://example.com/fhir/ValueSet/ro_height_cm' +valueset "rc_diabetesMellitusChronic": 'http://example.com/fhir/ValueSet/rc_diabetesMellitusChronic' +valueset "rc_coronaryArteryDisease": 'http://example.com/fhir/ValueSet/rc_coronaryArteryDisease' +valueset "rc_hypertension_cambia": 'http://example.com/fhir/ValueSet/rc_hypertension_cambia' +valueset "rc_obstructiveSleepApnea": 'http://example.com/fhir/ValueSet/rc_obstructiveSleepApnea' +valueset "rc_perforationOfStomach_cambia": 'http://example.com/fhir/ValueSet/rc_perforationOfStomach_cambia' +valueset "rc_gastricMucosalErosion_cambia": 'http://example.com/fhir/ValueSet/rc_gastricMucosalErosion_cambia' +valueset "rp_sleeveGastrectomy_cambia": 'http://example.com/fhir/ValueSet/rp_sleeveGastrectomy_cambia' +valueset "rp_initialAdjustableGastricBanding_cambia": 'http://example.com/fhir/ValueSet/rp_initialAdjustableGastricBanding_cambia' +valueset "rp_initialGastricBypassRouxEnYAnastomosis_cambia": 'http://example.com/fhir/ValueSet/rp_initialGastricBypassRouxEnYAnastomosis_cambia' +valueset "rc_gastricBandComplication_cambia": 'http://example.com/fhir/ValueSet/rc_gastricBandComplication_cambia' +valueset "rp_gastricBandAdjustment_cambia": 'http://example.com/fhir/ValueSet/rp_gastricBandAdjustment_cambia' +valueset "rc_gastricFistula_cambia": 'http://example.com/fhir/ValueSet/rc_gastricFistula_cambia' +valueset "rc_gastricSmallBowelObstructionAcquired_cambia": 'http://example.com/fhir/ValueSet/rc_gastricSmallBowelObstructionAcquired_cambia' +valueset "rc_gastricBandInfection_cambia": 'http://example.com/fhir/ValueSet/rc_gastricBandInfection_cambia' +valueset "rc_esophagitis_cambia": 'http://example.com/fhir/ValueSet/rc_esophagitis_cambia' +valueset "rc_barrettEsophagus": 'http://example.com/fhir/ValueSet/rc_barrettEsophagus' +valueset "rc_gastrojejunalUlcer_cambia": 'http://example.com/fhir/ValueSet/rc_gastrojejunalUlcer_cambia' +valueset "rp_biliopancreaticDiversionWithDuodenalSwitch_cambia": 'http://example.com/fhir/ValueSet/rp_biliopancreaticDiversionWithDuodenalSwitch_cambia' + +/* Duplicates */ +/* +valueset "rp_sleeveGastrectomy_cambia": 'http://example.com/fhir/ValueSet/rp_sleeveGastrectomy_cambia' +valueset "rp_initialAdjustableGastricBanding_cambia": 'http://example.com/fhir/ValueSet/rp_initialAdjustableGastricBanding_cambia' +valueset "rp_initialGastricBypassRouxEnYAnastomosis_cambia": 'http://example.com/fhir/ValueSet/rp_initialGastricBypassRouxEnYAnastomosis_cambia' +valueset "rp_initialGastricBypassRouxEnYAnastomosis_cambia": 'http://example.com/fhir/ValueSet/rp_initialGastricBypassRouxEnYAnastomosis_cambia' +valueset "rp_sleeveGastrectomy_cambia": 'http://example.com/fhir/ValueSet/rp_sleeveGastrectomy_cambia' +valueset "rp_initialAdjustableGastricBanding_cambia": 'http://example.com/fhir/ValueSet/rp_initialAdjustableGastricBanding_cambia' +valueset "rp_initialGastricBypassRouxEnYAnastomosis_cambia": 'http://example.com/fhir/ValueSet/rp_initialGastricBypassRouxEnYAnastomosis_cambia' +*/ +/* End of Duplicates */ + +/* +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +valueset "": 'http://example.com/fhir/ValueSet/' +*/ + +code "condition-confirmed": 'confirmed' from "ConditionVerificationStatusCodes" display 'confirmed' diff --git a/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/CommonElements.cql b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/CommonElements.cql new file mode 100644 index 000000000..1932a1a26 --- /dev/null +++ b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/CommonElements.cql @@ -0,0 +1,22 @@ +/* Context-independent Data Elements. (e.g., the Retrieves, to be used in more than one context.) */ +library CommonElements version '1.0.000' + +using FHIR version '4.0.1' + +include FHIRHelpers version '4.0.1' called FHIRHelpers +include CommonConcepts version '1.0.000' called Cx + +context Patient + +/* Potentially "Common" elements */ +define "sVitalSigns": + [Observation: category in 'vital-sign'] + +define function "Get Active Confirmed Conditions" (value List) returns List: + value C + where C.clinicalStatus in Cx."Active Condition" + and C.verificationStatus ~ ToConcept(Cx."condition-confirmed") + +define function "Get Qualified Observations" (value List) returns List: + value O + where O.status in { 'final', 'amended', 'corrected', 'appended' } diff --git a/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/FHIRCommon.cql b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/FHIRCommon.cql new file mode 100644 index 000000000..e9d32441d --- /dev/null +++ b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/FHIRCommon.cql @@ -0,0 +1,280 @@ +/* +@author: Bryn Rhodes +@description: Common terminologies and functions used in FHIR-based CQL artifacts +*/ +library FHIRCommon version '4.0.1' + +using FHIR version '4.0.1' + +include FHIRHelpers version '4.0.1' + +codesystem "LOINC": 'http://loinc.org' +codesystem "SNOMEDCT": 'http://snomed.info/sct' +codesystem "RoleCode": 'http://terminology.hl7.org/CodeSystem/v3-RoleCode' +codesystem "Diagnosis Role": 'http://terminology.hl7.org/CodeSystem/diagnosis-role' +codesystem "RequestIntent": 'http://terminology.hl7.org/CodeSystem/request-intent' +codesystem "MedicationRequestCategory": 'http://terminology.hl7.org/CodeSystem/medicationrequest-category' +codesystem "ConditionClinicalStatusCodes": 'http://terminology.hl7.org/CodeSystem/condition-clinical' +codesystem "ConditionVerificationStatusCodes": 'http://terminology.hl7.org/CodeSystem/condition-ver-status' +codesystem "AllergyIntoleranceClinicalStatusCodes": 'http://terminology.hl7.org/CodeSystem/allergyintolerance-clinical' +codesystem "AllergyIntoleranceVerificationStatusCodes": 'http://terminology.hl7.org/CodeSystem/allergyintolerance-verification' + +valueset "Active Condition": 'http://fhir.org/guides/cqf/common/ValueSet/active-condition' +valueset "Inactive Condition": 'http://fhir.org/guides/cqf/common/ValueSet/inactive-condition' + +code "Birthdate": '21112-8' from "LOINC" display 'Birth date' +code "Dead": '419099009' from "SNOMEDCT" display 'Dead' +code "ER": 'ER' from "RoleCode" display 'Emergency room' +code "ICU": 'ICU' from "RoleCode" display 'Intensive care unit' +code "Billing": 'billing' from "Diagnosis Role" display 'Billing' + +// Condition Clinical Status Codes - Consider value sets for these +code "active": 'active' from "ConditionClinicalStatusCodes" +code "recurrence": 'recurrence' from "ConditionClinicalStatusCodes" +code "relapse": 'relapse' from "ConditionClinicalStatusCodes" +code "inactive": 'inactive' from "ConditionClinicalStatusCodes" +code "remission": 'remission' from "ConditionClinicalStatusCodes" +code "resolved": 'resolved' from "ConditionClinicalStatusCodes" + +// Condition Verification Status Codes - Consider value sets for these +code "unconfirmed": 'unconfirmed' from ConditionVerificationStatusCodes +code "provisional": 'provisional' from ConditionVerificationStatusCodes +code "differential": 'differential' from ConditionVerificationStatusCodes +code "confirmed": 'confirmed' from ConditionVerificationStatusCodes +code "refuted": 'refuted' from ConditionVerificationStatusCodes +code "entered-in-error": 'entered-in-error' from ConditionVerificationStatusCodes + +code "allergy-active": 'active' from "AllergyIntoleranceClinicalStatusCodes" +code "allergy-inactive": 'inactive' from "AllergyIntoleranceClinicalStatusCodes" +code "allergy-resolved": 'resolved' from "AllergyIntoleranceClinicalStatusCodes" + +// Allergy/Intolerance Verification Status Codes - Consider value sets for these +code "allergy-unconfirmed": 'unconfirmed' from AllergyIntoleranceVerificationStatusCodes +code "allergy-confirmed": 'confirmed' from AllergyIntoleranceVerificationStatusCodes +code "allergy-refuted": 'refuted' from AllergyIntoleranceVerificationStatusCodes + +// MedicationRequest Category Codes +code "Community": 'community' from "MedicationRequestCategory" display 'Community' +code "Discharge": 'discharge' from "MedicationRequestCategory" display 'Discharge' + +// Diagnosis Role Codes +code "AD": 'AD' from "Diagnosis Role" display 'Admission diagnosis' +code "DD": 'DD' from "Diagnosis Role" display 'Discharge diagnosis' +code "CC": 'CC' from "Diagnosis Role" display 'Chief complaint' +code "CM": 'CM' from "Diagnosis Role" display 'Comorbidity diagnosis' +code "pre-op": 'pre-op' from "Diagnosis Role" display 'pre-op diagnosis' +code "post-op": 'post-op' from "Diagnosis Role" display 'post-op diagnosis' +code "billing": 'billing' from "Diagnosis Role" display 'billing diagnosis' + +context Patient + +/* +@description: Normalizes a value that is a choice of timing-valued types to an equivalent interval +@comment: Normalizes a choice type of FHIR.dateTime, FHIR.Period, FHIR.Timing, FHIR.instance, FHIR.string, FHIR.Age, or FHIR.Range types +to an equivalent interval. This selection of choice types is a superset of the majority of choice types that are used as possible +representations for timing-valued elements in FHIR, allowing this function to be used across any resource. NOTE: Due to the +complexity of determining a single interval from a Timing or String type, this function will throw a run-time exception if it is used +with a Timing or String. +*/ +define function ToInterval(choice Choice): +case +when choice is FHIR.dateTime then +Interval[FHIRHelpers.ToDateTime(choice as FHIR.dateTime), FHIRHelpers.ToDateTime(choice as FHIR.dateTime)] +when choice is FHIR.Period then +FHIRHelpers.ToInterval(choice as FHIR.Period) +when choice is FHIR.instant then +Interval[FHIRHelpers.ToDateTime(choice as FHIR.instant), FHIRHelpers.ToDateTime(choice as FHIR.instant)] +when choice is FHIR.Age then +Interval[FHIRHelpers.ToDate(Patient.birthDate) + FHIRHelpers.ToQuantity(choice as FHIR.Age), + FHIRHelpers.ToDate(Patient.birthDate) + FHIRHelpers.ToQuantity(choice as FHIR.Age) + 1 year) +when choice is FHIR.Range then +Interval[FHIRHelpers.ToDate(Patient.birthDate) + FHIRHelpers.ToQuantity((choice as FHIR.Range).low), + FHIRHelpers.ToDate(Patient.birthDate) + FHIRHelpers.ToQuantity((choice as FHIR.Range).high) + 1 year) +when choice is FHIR.Timing then +Message(null as Interval, true, '1', 'Error', 'Cannot compute a single interval from a Timing type') +when choice is FHIR.string then +Message(null as Interval, true, '1', 'Error', 'Cannot compute an interval from a String value') +else +null as Interval +end + +/* +@description: Returns an interval representing the normalized Abatement of a given Condition resource. +@comment: NOTE: Due to the complexity of determining an interval from a String, this function will throw +a run-time exception if used with a Condition instance that has a String as the abatement value. +*/ +define function ToAbatementInterval(condition Condition): +if condition.abatement is FHIR.dateTime then +Interval[FHIRHelpers.ToDateTime(condition.abatement as FHIR.dateTime), FHIRHelpers.ToDateTime(condition.abatement as FHIR.dateTime)] +else if condition.abatement is FHIR.Period then +FHIRHelpers.ToInterval(condition.abatement as FHIR.Period) +else if condition.abatement is FHIR.string then +Message(null as Interval, true, '1', 'Error', 'Cannot compute an interval from a String value') +else if condition.abatement is FHIR.Age then +Interval[FHIRHelpers.ToDate(Patient.birthDate) + FHIRHelpers.ToQuantity(condition.abatement as FHIR.Age), +FHIRHelpers.ToDate(Patient.birthDate) + FHIRHelpers.ToQuantity(condition.abatement as FHIR.Age) + 1 year) +else if condition.abatement is FHIR.Range then +Interval[FHIRHelpers.ToDate(Patient.birthDate) + FHIRHelpers.ToQuantity((condition.abatement as FHIR.Range).low), +FHIRHelpers.ToDate(Patient.birthDate) + FHIRHelpers.ToQuantity((condition.abatement as FHIR.Range).high) + 1 year) +else if condition.abatement is FHIR.boolean then +Interval[end of ToInterval(condition.onset), condition.recordedDate) +else null + +/* +@description: Returns an interval representing the normalized prevalence period of a given Condition resource. +@comment: Uses the ToInterval and ToAbatementInterval functions to determine the widest potential interval from +onset to abatement as specified in the given Condition. +*/ +define function ToPrevalenceInterval(condition Condition): +if condition.clinicalStatus ~ "active" +or condition.clinicalStatus ~ "recurrence" +or condition.clinicalStatus ~ "relapse" then +Interval[start of ToInterval(condition.onset), end of ToAbatementInterval(condition)] +else +Interval[start of ToInterval(condition.onset), end of ToAbatementInterval(condition)) + +/* +@description: Returns any extensions defined on the given resource with the specified url. +@comment: NOTE: Extensions are not the preferred approach, but are used as a way to access +content that is defined by extensions but not yet surfaced in the +CQL model info. +*/ +define function Extensions(domainResource DomainResource, url String): +domainResource.extension E +where E.url = url +return E + +/* +@description: Returns the single extension (if present) on the given resource with the specified url. +@comment: This function uses singleton from to ensure that a run-time exception is thrown if there +is more than one extension on the given resource with the specified url. +*/ +define function Extension(domainResource DomainResource, url String): +singleton from "Extensions"(domainResource, url) + +/* +@description: Returns any extensions defined on the given element with the specified url. +@comment: NOTE: Extensions are not the preferred approach, but are used as a way to access +content that is defined by extensions but not yet surfaced in the CQL model info. +*/ +define function Extensions(element Element, url String): +element.extension E +where E.url = url +return E + +/* +@description: Returns the single extension (if present) on the given element with the specified url. +@comment: This function uses singleton from to ensure that a run-time exception is thrown if there +is more than one extension on the given resource with the specified url. +*/ +define function Extension(element Element, url String): +singleton from Extensions(element, url) + +/* +@description: Returns any modifier extensions defined on the given resource with the specified url. +@comment: NOTE: Extensions are not the preferred approach, but are used as a way to access +content that is defined by extensions but not yet surfaced in the +CQL model info. +*/ +define function ModifierExtensions(domainResource DomainResource, url String): +domainResource.modifierExtension E +where E.url = url +return E + +/* +@description: Returns the single modifier extension (if present) on the given resource with the specified url. +@comment: This function uses singleton from to ensure that a run-time exception is thrown if there +is more than one extension on the given resource with the specified url. +*/ +define function ModifierExtension(domainResource DomainResource, url String): +singleton from ModifierExtensions(domainResource, url) + +/* +@description: Returns any modifier extensions defined on the given element with the specified url. +@comment: NOTE: Extensions are not the preferred approach, but are used as a way to access +content that is defined by extensions but not yet surfaced in the CQL model info. +*/ +define function ModifierExtensions(element BackboneElement, url String): +element.modifierExtension E +where E.url = url +return E + +/* +@description: Returns the single modifier extension (if present) on the given element with the specified url. +@comment: This function uses singleton from to ensure that a run-time exception is thrown if there +is more than one extension on the given resource with the specified url. +*/ +define function ModifierExtension(element BackboneElement, url String): +singleton from ModifierExtensions(element, url) + +/* +@description: Returns any base-FHIR extensions defined on the given resource with the specified id. +@comment: NOTE: Extensions are not the preferred approach, but are used as a way to access +content that is defined by extensions but not yet surfaced in the CQL model info. +*/ +define function BaseExtensions(domainResource DomainResource, id String): +domainResource.extension E +where E.url = ('http://hl7.org/fhir/StructureDefinition/' + id) +return E + +/* +@description: Returns the single base-FHIR extension (if present) on the given resource with the specified id. +@comment: This function uses singleton from to ensure that a run-time exception is thrown if there +is more than one extension on the given resource with the specified url. +*/ +define function BaseExtension(domainResource DomainResource, id String): +singleton from BaseExtensions(domainResource, id) + +/* +@description: Returns any base-FHIR extensions defined on the given element with the specified id. +@comment: NOTE: Extensions are not the preferred approach, but are used as a way to access +content that is defined by extensions but not yet surfaced in the CQL model info. +*/ +define function BaseExtensions(element Element, id String): +element.extension E +where E.url = ('http://hl7.org/fhir/StructureDefinition/' + id) +return E + +/* +@description: Returns the single base-FHIR extension (if present) on the given element with the specified id. +@comment: This function uses singleton from to ensure that a run-time exception is thrown if there +is more than one extension on the given resource with the specified url. +*/ +define function BaseExtension(element Element, id String): +singleton from BaseExtensions(element, id) + +/* +@description: Returns any base-FHIR modifier extensions defined on the given resource with the specified id. +@comment: NOTE: Extensions are not the preferred approach, but are used as a way to access +content that is defined by extensions but not yet surfaced in the CQL model info. +*/ +define function BaseModifierExtensions(domainResource DomainResource, id String): +domainResource.modifierExtension E +where E.url = ('http://hl7.org/fhir/StructureDefinition/' + id) +return E + +/* +@description: Returns the single base-FHIR modifier extension (if present) on the given resource with the specified id. +@comment: This function uses singleton from to ensure that a run-time exception is thrown if there +is more than one extension on the given resource with the specified url. +*/ +define function BaseModifierExtension(domainResource DomainResource, id String): +singleton from BaseModifierExtensions(domainResource, id) + +/* +@description: Returns any base-FHIR modifier extensions defined on the given element with the specified id. +@comment: NOTE: Extensions are not the preferred approach, but are used as a way to access +content that is defined by extensions but not yet surfaced in the CQL model info. +*/ +define function BaseModifierExtensions(element BackboneElement, id String): +element.modifierExtension E +where E.url = ('http://hl7.org/fhir/StructureDefinition/' + id) +return E + +/* +@description: Returns the single base-FHIR extension (if present) on the given element with the specified id. +@comment: This function uses singleton from to ensure that a run-time exception is thrown if there +is more than one extension on the given resource with the specified url. +*/ +define function BaseModifierExtension(element BackboneElement, id String): +singleton from BaseModifierExtensions(element, id) diff --git a/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/FHIRHelpers.cql b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/FHIRHelpers.cql new file mode 100644 index 000000000..7c8a9a90c --- /dev/null +++ b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/FHIRHelpers.cql @@ -0,0 +1,308 @@ +library FHIRHelpers version '4.0.1' + +using FHIR version '4.0.1' + +define function ToInterval(period FHIR.Period): + if period is null then + null + else + Interval[period."start".value, period."end".value] + +define function ToQuantity(quantity FHIR.Quantity): + if quantity is null then + null + else + System.Quantity { value: quantity.value.value, unit: quantity.unit.value } + +define function ToRatio(ratio FHIR.Ratio): + if ratio is null then + null + else + System.Ratio { numerator: ToQuantity(ratio.numerator), denominator: ToQuantity(ratio.denominator) } + +define function ToInterval(range FHIR.Range): + if range is null then + null + else + Interval[ToQuantity(range.low), ToQuantity(range.high)] + +define function ToCode(coding FHIR.Coding): + if coding is null then + null + else + System.Code { + code: coding.code.value, + system: coding.system.value, + version: coding.version.value, + display: coding.display.value + } + +define function ToConcept(concept FHIR.CodeableConcept): + if concept is null then + null + else + System.Concept { + codes: concept.coding C return ToCode(C), + display: concept.text.value + } + + +define function ToString(value AccountStatus): value.value +define function ToString(value ActionCardinalityBehavior): value.value +define function ToString(value ActionConditionKind): value.value +define function ToString(value ActionGroupingBehavior): value.value +define function ToString(value ActionParticipantType): value.value +define function ToString(value ActionPrecheckBehavior): value.value +define function ToString(value ActionRelationshipType): value.value +define function ToString(value ActionRequiredBehavior): value.value +define function ToString(value ActionSelectionBehavior): value.value +define function ToString(value ActivityDefinitionKind): value.value +define function ToString(value ActivityParticipantType): value.value +define function ToString(value AddressType): value.value +define function ToString(value AddressUse): value.value +define function ToString(value AdministrativeGender): value.value +define function ToString(value AdverseEventActuality): value.value +define function ToString(value AggregationMode): value.value +define function ToString(value AllergyIntoleranceCategory): value.value +define function ToString(value AllergyIntoleranceCriticality): value.value +define function ToString(value AllergyIntoleranceSeverity): value.value +define function ToString(value AllergyIntoleranceType): value.value +define function ToString(value AppointmentStatus): value.value +define function ToString(value AssertionDirectionType): value.value +define function ToString(value AssertionOperatorType): value.value +define function ToString(value AssertionResponseTypes): value.value +define function ToString(value AuditEventAction): value.value +define function ToString(value AuditEventAgentNetworkType): value.value +define function ToString(value AuditEventOutcome): value.value +define function ToString(value BindingStrength): value.value +define function ToString(value BiologicallyDerivedProductCategory): value.value +define function ToString(value BiologicallyDerivedProductStatus): value.value +define function ToString(value BiologicallyDerivedProductStorageScale): value.value +define function ToString(value BundleType): value.value +define function ToString(value CapabilityStatementKind): value.value +define function ToString(value CarePlanActivityKind): value.value +define function ToString(value CarePlanActivityStatus): value.value +define function ToString(value CarePlanIntent): value.value +define function ToString(value CarePlanStatus): value.value +define function ToString(value CareTeamStatus): value.value +define function ToString(value CatalogEntryRelationType): value.value +define function ToString(value ChargeItemDefinitionPriceComponentType): value.value +define function ToString(value ChargeItemStatus): value.value +define function ToString(value ClaimResponseStatus): value.value +define function ToString(value ClaimStatus): value.value +define function ToString(value ClinicalImpressionStatus): value.value +define function ToString(value CodeSearchSupport): value.value +define function ToString(value CodeSystemContentMode): value.value +define function ToString(value CodeSystemHierarchyMeaning): value.value +define function ToString(value CommunicationPriority): value.value +define function ToString(value CommunicationRequestStatus): value.value +define function ToString(value CommunicationStatus): value.value +define function ToString(value CompartmentCode): value.value +define function ToString(value CompartmentType): value.value +define function ToString(value CompositionAttestationMode): value.value +define function ToString(value CompositionStatus): value.value +define function ToString(value ConceptMapEquivalence): value.value +define function ToString(value ConceptMapGroupUnmappedMode): value.value +define function ToString(value ConditionalDeleteStatus): value.value +define function ToString(value ConditionalReadStatus): value.value +define function ToString(value ConsentDataMeaning): value.value +define function ToString(value ConsentProvisionType): value.value +define function ToString(value ConsentState): value.value +define function ToString(value ConstraintSeverity): value.value +define function ToString(value ContactPointSystem): value.value +define function ToString(value ContactPointUse): value.value +define function ToString(value ContractPublicationStatus): value.value +define function ToString(value ContractStatus): value.value +define function ToString(value ContributorType): value.value +define function ToString(value CoverageStatus): value.value +define function ToString(value CurrencyCode): value.value +define function ToString(value DayOfWeek): value.value +define function ToString(value DaysOfWeek): value.value +define function ToString(value DetectedIssueSeverity): value.value +define function ToString(value DetectedIssueStatus): value.value +define function ToString(value DeviceMetricCalibrationState): value.value +define function ToString(value DeviceMetricCalibrationType): value.value +define function ToString(value DeviceMetricCategory): value.value +define function ToString(value DeviceMetricColor): value.value +define function ToString(value DeviceMetricOperationalStatus): value.value +define function ToString(value DeviceNameType): value.value +define function ToString(value DeviceRequestStatus): value.value +define function ToString(value DeviceUseStatementStatus): value.value +define function ToString(value DiagnosticReportStatus): value.value +define function ToString(value DiscriminatorType): value.value +define function ToString(value DocumentConfidentiality): value.value +define function ToString(value DocumentMode): value.value +define function ToString(value DocumentReferenceStatus): value.value +define function ToString(value DocumentRelationshipType): value.value +define function ToString(value EligibilityRequestPurpose): value.value +define function ToString(value EligibilityRequestStatus): value.value +define function ToString(value EligibilityResponsePurpose): value.value +define function ToString(value EligibilityResponseStatus): value.value +define function ToString(value EnableWhenBehavior): value.value +define function ToString(value EncounterLocationStatus): value.value +define function ToString(value EncounterStatus): value.value +define function ToString(value EndpointStatus): value.value +define function ToString(value EnrollmentRequestStatus): value.value +define function ToString(value EnrollmentResponseStatus): value.value +define function ToString(value EpisodeOfCareStatus): value.value +define function ToString(value EventCapabilityMode): value.value +define function ToString(value EventTiming): value.value +define function ToString(value EvidenceVariableType): value.value +define function ToString(value ExampleScenarioActorType): value.value +define function ToString(value ExplanationOfBenefitStatus): value.value +define function ToString(value ExposureState): value.value +define function ToString(value ExtensionContextType): value.value +define function ToString(value FHIRAllTypes): value.value +define function ToString(value FHIRDefinedType): value.value +define function ToString(value FHIRDeviceStatus): value.value +define function ToString(value FHIRResourceType): value.value +define function ToString(value FHIRSubstanceStatus): value.value +define function ToString(value FHIRVersion): value.value +define function ToString(value FamilyHistoryStatus): value.value +define function ToString(value FilterOperator): value.value +define function ToString(value FlagStatus): value.value +define function ToString(value GoalLifecycleStatus): value.value +define function ToString(value GraphCompartmentRule): value.value +define function ToString(value GraphCompartmentUse): value.value +define function ToString(value GroupMeasure): value.value +define function ToString(value GroupType): value.value +define function ToString(value GuidanceResponseStatus): value.value +define function ToString(value GuidePageGeneration): value.value +define function ToString(value GuideParameterCode): value.value +define function ToString(value HTTPVerb): value.value +define function ToString(value IdentifierUse): value.value +define function ToString(value IdentityAssuranceLevel): value.value +define function ToString(value ImagingStudyStatus): value.value +define function ToString(value ImmunizationEvaluationStatus): value.value +define function ToString(value ImmunizationStatus): value.value +define function ToString(value InvoicePriceComponentType): value.value +define function ToString(value InvoiceStatus): value.value +define function ToString(value IssueSeverity): value.value +define function ToString(value IssueType): value.value +define function ToString(value LinkType): value.value +define function ToString(value LinkageType): value.value +define function ToString(value ListMode): value.value +define function ToString(value ListStatus): value.value +define function ToString(value LocationMode): value.value +define function ToString(value LocationStatus): value.value +define function ToString(value MeasureReportStatus): value.value +define function ToString(value MeasureReportType): value.value +define function ToString(value MediaStatus): value.value +define function ToString(value MedicationAdministrationStatus): value.value +define function ToString(value MedicationDispenseStatus): value.value +define function ToString(value MedicationKnowledgeStatus): value.value +define function ToString(value MedicationRequestIntent): value.value +define function ToString(value MedicationRequestPriority): value.value +define function ToString(value MedicationRequestStatus): value.value +define function ToString(value MedicationStatementStatus): value.value +define function ToString(value MedicationStatus): value.value +define function ToString(value MessageSignificanceCategory): value.value +define function ToString(value Messageheader_Response_Request): value.value +define function ToString(value MimeType): value.value +define function ToString(value NameUse): value.value +define function ToString(value NamingSystemIdentifierType): value.value +define function ToString(value NamingSystemType): value.value +define function ToString(value NarrativeStatus): value.value +define function ToString(value NoteType): value.value +define function ToString(value NutritiionOrderIntent): value.value +define function ToString(value NutritionOrderStatus): value.value +define function ToString(value ObservationDataType): value.value +define function ToString(value ObservationRangeCategory): value.value +define function ToString(value ObservationStatus): value.value +define function ToString(value OperationKind): value.value +define function ToString(value OperationParameterUse): value.value +define function ToString(value OrientationType): value.value +define function ToString(value ParameterUse): value.value +define function ToString(value ParticipantRequired): value.value +define function ToString(value ParticipantStatus): value.value +define function ToString(value ParticipationStatus): value.value +define function ToString(value PaymentNoticeStatus): value.value +define function ToString(value PaymentReconciliationStatus): value.value +define function ToString(value ProcedureStatus): value.value +define function ToString(value PropertyRepresentation): value.value +define function ToString(value PropertyType): value.value +define function ToString(value ProvenanceEntityRole): value.value +define function ToString(value PublicationStatus): value.value +define function ToString(value QualityType): value.value +define function ToString(value QuantityComparator): value.value +define function ToString(value QuestionnaireItemOperator): value.value +define function ToString(value QuestionnaireItemType): value.value +define function ToString(value QuestionnaireResponseStatus): value.value +define function ToString(value ReferenceHandlingPolicy): value.value +define function ToString(value ReferenceVersionRules): value.value +define function ToString(value ReferredDocumentStatus): value.value +define function ToString(value RelatedArtifactType): value.value +define function ToString(value RemittanceOutcome): value.value +define function ToString(value RepositoryType): value.value +define function ToString(value RequestIntent): value.value +define function ToString(value RequestPriority): value.value +define function ToString(value RequestStatus): value.value +define function ToString(value ResearchElementType): value.value +define function ToString(value ResearchStudyStatus): value.value +define function ToString(value ResearchSubjectStatus): value.value +define function ToString(value ResourceType): value.value +define function ToString(value ResourceVersionPolicy): value.value +define function ToString(value ResponseType): value.value +define function ToString(value RestfulCapabilityMode): value.value +define function ToString(value RiskAssessmentStatus): value.value +define function ToString(value SPDXLicense): value.value +define function ToString(value SearchComparator): value.value +define function ToString(value SearchEntryMode): value.value +define function ToString(value SearchModifierCode): value.value +define function ToString(value SearchParamType): value.value +define function ToString(value SectionMode): value.value +define function ToString(value SequenceType): value.value +define function ToString(value ServiceRequestIntent): value.value +define function ToString(value ServiceRequestPriority): value.value +define function ToString(value ServiceRequestStatus): value.value +define function ToString(value SlicingRules): value.value +define function ToString(value SlotStatus): value.value +define function ToString(value SortDirection): value.value +define function ToString(value SpecimenContainedPreference): value.value +define function ToString(value SpecimenStatus): value.value +define function ToString(value Status): value.value +define function ToString(value StrandType): value.value +define function ToString(value StructureDefinitionKind): value.value +define function ToString(value StructureMapContextType): value.value +define function ToString(value StructureMapGroupTypeMode): value.value +define function ToString(value StructureMapInputMode): value.value +define function ToString(value StructureMapModelMode): value.value +define function ToString(value StructureMapSourceListMode): value.value +define function ToString(value StructureMapTargetListMode): value.value +define function ToString(value StructureMapTransform): value.value +define function ToString(value SubscriptionChannelType): value.value +define function ToString(value SubscriptionStatus): value.value +define function ToString(value SupplyDeliveryStatus): value.value +define function ToString(value SupplyRequestStatus): value.value +define function ToString(value SystemRestfulInteraction): value.value +define function ToString(value TaskIntent): value.value +define function ToString(value TaskPriority): value.value +define function ToString(value TaskStatus): value.value +define function ToString(value TestReportActionResult): value.value +define function ToString(value TestReportParticipantType): value.value +define function ToString(value TestReportResult): value.value +define function ToString(value TestReportStatus): value.value +define function ToString(value TestScriptRequestMethodCode): value.value +define function ToString(value TriggerType): value.value +define function ToString(value TypeDerivationRule): value.value +define function ToString(value TypeRestfulInteraction): value.value +define function ToString(value UDIEntryType): value.value +define function ToString(value UnitsOfTime): value.value +define function ToString(value Use): value.value +define function ToString(value VariableType): value.value +define function ToString(value VisionBase): value.value +define function ToString(value VisionEyes): value.value +define function ToString(value VisionStatus): value.value +define function ToString(value XPathUsageType): value.value +define function ToString(value base64Binary): value.value +define function ToString(value id): value.value +define function ToBoolean(value boolean): value.value +define function ToDate(value date): value.value +define function ToDateTime(value dateTime): value.value +define function ToDecimal(value decimal): value.value +define function ToDateTime(value instant): value.value +define function ToInteger(value integer): value.value +define function ToString(value string): value.value +define function ToTime(value time): value.value +define function ToString(value uri): value.value +define function ToString(value xhtml): value.value diff --git a/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/Ind2E31A37EB104A7D1.cql b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/Ind2E31A37EB104A7D1.cql new file mode 100644 index 000000000..a5f909ddb --- /dev/null +++ b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/Ind2E31A37EB104A7D1.cql @@ -0,0 +1,74 @@ +library Ind2E31A37EB104A7D1 version '1.0.000' + +using FHIR version '4.0.1' + +include FHIRCommon version '4.0.1' called FHIRCommon +include FHIRHelpers version '4.0.1' called FHIRHelpers +include CommonConcepts version '1.0.000' called CommonCx +include CommonElements version '1.0.000' called CommonEl + +context Patient + +/* "Id": "2E31A37EB104A7D1" */ +define "4. Biliopancreatic bypass with duodenal switch in patients ages greater than or equal to 18 years with BMI greater than or equal to 50 kg/(meter squared)": + "ageYears" >= 18 + and "bpd" + and + ( + ("BMI" >= 50) + or (("wt"/(("ht" / 100)^2)) >= 50) + or ((("wt_lb" / 2.2) / (("ht" / 100)^2)) >= 50) + or ((("wt_lb" / 2.2) / (("ht_in" * (2.54/100))^2)) >= 50) + ) + +define "ageYears": + AgeInYearsAt(Today()) + +define "bpd": + exists ( + [ServiceRequest] SR + where SR.code in CommonCx."rp_biliopancreaticDiversionWithDuodenalSwitch_cambia" + and FHIRCommon.ToInterval(SR.authoredOn) starts 30 days or less before Today() + ) + +define "BMI": + Max( + (CommonEl."Get Qualified Observations"(CommonEl."sVitalSigns")) VS + where VS.code in CommonCx."ro_bodyMassIndex_kg_per_m2" + and FHIRCommon.ToInterval(VS.effective) starts 180 days or less before Today() + return VS.value as integer + ) + +define "wt": //'kg' + Max( + (CommonEl."Get Qualified Observations"(CommonEl."sVitalSigns")) VS + where VS.code in CommonCx."ro_weight_kg" + and FHIRCommon.ToInterval(VS.effective) starts 180 days or less before Today() + return VS.value as integer + ) + +define "wt_lb": //'[lb_av]' + Max( + (CommonEl."Get Qualified Observations"(CommonEl."sVitalSigns")) VS + where VS.code in CommonCx."ro_weight_lb" + and FHIRCommon.ToInterval(VS.effective) starts 180 days or less before Today() + return VS.value as integer + ) + +define "ht": //'cm' + First( + ((CommonEl."Get Qualified Observations"(CommonEl."sVitalSigns")) VS + where VS.code in CommonCx."ro_height_cm" + and FHIRCommon.ToInterval(VS.effective) starts 1 year or less before Today() + return FHIRHelpers.ToInteger(VS.value as integer)) VSQuantities + sort descending + ) + +define "ht_in": //'in' + First( + ((CommonEl."Get Qualified Observations"(CommonEl."sVitalSigns")) VS + where VS.code in CommonCx."ro_height_in" + and FHIRCommon.ToInterval(VS.effective) starts 1 year or less before Today() + return FHIRHelpers.ToInteger(VS.value as integer)) VSQuantities + sort descending +) diff --git a/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/Library-BSElements-data-requirements.json b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/Library-BSElements-data-requirements.json new file mode 100644 index 000000000..1501caca2 --- /dev/null +++ b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/Library-BSElements-data-requirements.json @@ -0,0 +1,159 @@ +{ + "resourceType": "Library", + "status": "active", + "type": { + "coding": [ { + "system": "http://terminology.hl7.org/CodeSystem/library-type", + "code": "module-definition" + } ] + }, + "relatedArtifact": [ { + "type": "depends-on", + "display": "FHIR model information", + "resource": "http://fhir.org/guides/cqf/common/Library/FHIR-ModelInfo|4.0.1" + }, { + "type": "depends-on", + "display": "Library FHIRCommon", + "resource": "Library/FHIRCommon|4.0.1" + }, { + "type": "depends-on", + "display": "Library FHIRHelpers", + "resource": "Library/FHIRHelpers|4.0.1" + }, { + "type": "depends-on", + "display": "Library CommonCx", + "resource": "Library/CommonConcepts|1.0.000" + }, { + "type": "depends-on", + "display": "Library CommonEl", + "resource": "Library/CommonElements|1.0.000" + }, { + "type": "depends-on", + "display": "Library Ind2E31A37EB104A7D1", + "resource": "Library/Ind2E31A37EB104A7D1|1.0.000" + }, { + "type": "depends-on", + "display": "Value set rp_biliopancreaticDiversionWithDuodenalSwitch_cambia", + "resource": "http://example.com/fhir/ValueSet/rp_biliopancreaticDiversionWithDuodenalSwitch_cambia" + }, { + "type": "depends-on", + "display": "Value set ro_bodyMassIndex_kg_per_m2", + "resource": "http://example.com/fhir/ValueSet/ro_bodyMassIndex_kg_per_m2" + }, { + "type": "depends-on", + "display": "Value set ro_weight_kg", + "resource": "http://example.com/fhir/ValueSet/ro_weight_kg" + }, { + "type": "depends-on", + "display": "Value set ro_height_cm", + "resource": "http://example.com/fhir/ValueSet/ro_height_cm" + }, { + "type": "depends-on", + "display": "Value set ro_weight_lb", + "resource": "http://example.com/fhir/ValueSet/ro_weight_lb" + }, { + "type": "depends-on", + "display": "Value set ro_height_in", + "resource": "http://example.com/fhir/ValueSet/ro_height_in" + } ], + "parameter": [ { + "name": "Patient", + "use": "out", + "min": 0, + "max": "1", + "type": "Patient" + }, { + "name": "4. Biliopancreatic bypass with duodenal switch in patients ages greater than or equal to 18 years with BMI greater than or equal to 50 kg/(meter squared)", + "use": "out", + "min": 0, + "max": "1", + "type": "boolean" + } ], + "dataRequirement": [ { + "type": "Patient", + "profile": [ "http://hl7.org/fhir/StructureDefinition/Patient" ] + }, { + "type": "ServiceRequest", + "profile": [ "http://hl7.org/fhir/StructureDefinition/ServiceRequest" ], + "mustSupport": [ "code", "authoredOn" ], + "codeFilter": [ { + "path": "code", + "valueSet": "http://example.com/fhir/ValueSet/rp_biliopancreaticDiversionWithDuodenalSwitch_cambia" + } ] + }, { + "type": "Observation", + "profile": [ "http://hl7.org/fhir/StructureDefinition/Observation" ], + "mustSupport": [ "category" ], + "codeFilter": [ { + "path": "category", + "code": [ { + "code": "vital-sign" + } ] + } ] + }, { + "type": "Observation", + "profile": [ "http://hl7.org/fhir/StructureDefinition/Observation" ], + "mustSupport": [ "category", "code", "effective", "value" ], + "codeFilter": [ { + "path": "category", + "code": [ { + "code": "vital-sign" + } ] + }, { + "path": "code", + "valueSet": "http://example.com/fhir/ValueSet/ro_bodyMassIndex_kg_per_m2" + } ] + }, { + "type": "Observation", + "profile": [ "http://hl7.org/fhir/StructureDefinition/Observation" ], + "mustSupport": [ "category", "code", "effective", "value" ], + "codeFilter": [ { + "path": "category", + "code": [ { + "code": "vital-sign" + } ] + }, { + "path": "code", + "valueSet": "http://example.com/fhir/ValueSet/ro_weight_kg" + } ] + }, { + "type": "Observation", + "profile": [ "http://hl7.org/fhir/StructureDefinition/Observation" ], + "mustSupport": [ "category", "code", "effective", "value" ], + "codeFilter": [ { + "path": "category", + "code": [ { + "code": "vital-sign" + } ] + }, { + "path": "code", + "valueSet": "http://example.com/fhir/ValueSet/ro_height_cm" + } ] + }, { + "type": "Observation", + "profile": [ "http://hl7.org/fhir/StructureDefinition/Observation" ], + "mustSupport": [ "category", "code", "effective", "value" ], + "codeFilter": [ { + "path": "category", + "code": [ { + "code": "vital-sign" + } ] + }, { + "path": "code", + "valueSet": "http://example.com/fhir/ValueSet/ro_weight_lb" + } ] + }, { + "type": "Observation", + "profile": [ "http://hl7.org/fhir/StructureDefinition/Observation" ], + "mustSupport": [ "category", "code", "effective", "value" ], + "codeFilter": [ { + "path": "category", + "code": [ { + "code": "vital-sign" + } ] + }, { + "path": "code", + "valueSet": "http://example.com/fhir/ValueSet/ro_height_in" + } ] + } ] +} \ No newline at end of file diff --git a/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/cql-options.json b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/cql-options.json new file mode 100644 index 000000000..23b75c122 --- /dev/null +++ b/Src/java/elm-fhir/src/test/resources/org/cqframework/cql/elm/requirements/fhir/WithDependencies/cql-options.json @@ -0,0 +1,16 @@ +{ + "options":[ + "EnableLocators", + "DisableListDemotion", + "DisableListPromotion" + +], + "formats":[ + "XML", + "JSON" + ], + "validateUnits":true, + "verifyOnly":false, + "errorLevel":"Info", + "signatureLevel":"None" +} diff --git a/Src/java/elm/src/main/java/org/cqframework/cql/elm/evaluating/SimpleElmEngine.java b/Src/java/elm/src/main/java/org/cqframework/cql/elm/evaluating/SimpleElmEngine.java index b8f7974ff..c7563b4bc 100644 --- a/Src/java/elm/src/main/java/org/cqframework/cql/elm/evaluating/SimpleElmEngine.java +++ b/Src/java/elm/src/main/java/org/cqframework/cql/elm/evaluating/SimpleElmEngine.java @@ -251,6 +251,14 @@ else if (left instanceof List) { } } + else if (left instanceof ToList) { + if (right instanceof ToList) { + Expression leftSingleton = ((ToList)left).getOperand(); + Expression rightSingleton = ((ToList)right).getOperand(); + return codesEqual(leftSingleton, rightSingleton); + } + } + return false; } }