-
Notifications
You must be signed in to change notification settings - Fork 24
Authoring Patterns QICore v6.0.0
This page provides discussion and best-practice recommendations for authoring patterns for accessing patient information in FHIR and CQL. For general conventions and guidance regarding the use of FHIR and CQL, refer to the Using CQL topic in the Quality Measure IG.
Feedback on the patterns and discussion here can be provided by submitting a New Issue to this repository.
HL7 Fast Healthcare Interoperability Resources (FHIR) is a platform specification for exchanging healthcare data. FHIR defines a core information model that can be profiled for use in a variety of applications across the healthcare industry. These profiles are defined in Implementation Guides that provide constraints on the ways that FHIR resources can be used in to support interoperability (i.e. the ability of both sides of an interaction to correctly interpret the information being exchanged).
In the United States, the US Core Implementation Guide defines a floor for that interoperability, enabling a broad range of clinical and administrative use cases. For quality improvement use cases, such as decision support and quality measurement, the QI Core Implementation Guide extends US Core to support additional information used for quality improvement. For the most part, US Core covers the data required, but some use cases, such as documentation of events that did not occur, require additional profiles.
Clinical Quality Language(CQL) is high-level, domain-specific language focused on clinical quality and targeted at measure and decision support artifact authors.
To simplify the expression of logic in quality improvement artifacts, CQL can be authored directly against the information model defined by the QI Core profiles. In the simplest terms, that information model provides:
- Patient - Representation of patient demographic and basic characteristics
- Encounters - Encounters between a patient and healthcare providers, typically taking place at a facility or virtually
- Observations - Facts about the patient such as lab results, vital signs, social history, etc.
- Conditions - Conditions the patient has (or does not have)
- Medications - Information related to medications the patient is prescribed and/or using
- Procedures - Information related to procedures ordered and/or performed for the patient
- Devices - Information related to devices the patient is using and/or has been prescribed
- Allergies - Allergies and intolerances the patient has (or does not have)
- Immunizations - Information related to immunizations the patient has received or been recommended
- Communication - Information related to communications with or about the patient
NOTE: The information in this page specifically uses the 6.0.0 version of QI-Core, which depends on the 6.1.0 version of USCore, and both of which are based on the R4 version 4.0.1 of FHIR.
The following sections provide specific examples of best practices for accessing information in each of these high-level areas.
As an aside, whether expressions in general should use the various elements of a profile depends entirely on measure or rule intent. However, there are some general guidelines that should be followed to ensure correct expression and evaluation of CQL.
To begin with, all elements in FHIR profiles have a cardinality that determines whether and how many values may appear in that element. Cardinality is expressed as a range, typically from 0 or 1 to 1 or . A cardinality of 0..1 means the element is optional. A cardinality of 1..1 means the element is required. A cardinality of 0.. means the element may appear any number of times, and a cardinality of 1..* means the element must appear at least once, but may appear multiple times. Although other cardinalities are possible, those described above are the most common.
NOTE: Cardinality determines whether and how many values may appear for a given element, but the fact that an element is specified as required (e.g. 1..1) does not mean that expressions using that profile must use that element.
In addition, elements in FHIR profiles may be marked must support, meaning that implementations are required to provide values for the element if they are present in the system. To ensure expression logic can be evaluated correctly, expressions must only use elements that are marked must support. For a complete discussion of this aspect, refer to the MustSupport Flag topic in the QI-Core Implementation Guide.
And finally, elements in FHIR profiles may be marked as modifier elements, meaning that the value of the element may change the overall meaning of the resource. For example, the clinicalStatus element of a Condition is a modifier element because the value determines whether the Condition overall represents the presence or absence of a condition. As a result, for each modifier element, authors must carefully consider whether each possible value would impact the intent of the expression.
To summarize, cardinality determines whether data will be present at all, must support determines whether the element can be used in an expression, and modifier elements must always be considered to determine the impact of possible values of the element on the result of the expression. End of aside.
FHIR supports various types of terminology-valued elements, including:
Within CQL, references to terminology code systems, value sets, codes, and concepts are directly supported, and all such usages are declared within CQL libraries, as described in the Terminology section of the CQL Author's Guide.
When referencing terminology-valued elements within CQL, the following comparison operations are supported:
As a general rule, the equivalent (~) operator should be used whenever the terminology being compared is a direct-reference code, and the in operator should be used whenever the terminology being compared is a value set. The equal (=) operator should only be used with code-valued elements that have a required binding.
In FHIR, code-valued elements are most often used with required bindings, meaning that the only values that can appear are established by the specification. Because of this, basic string comparison can be used, for example:
where Encounter.status = 'finished'
NOTE: The comparison here is to the code value, not the display
NOTE: Note also that there are edge-cases where the string-valued elements may contain terminology values. For more detail on this case, refer to the Using CQL IG
Most terminology-valued elements in FHIR are CodeableConcepts. If the terminology being compared is a value set (e.g. valueset "Inpatient Encounter"), use the in operator:
where Encounter.type in "Inpatient Encounter"
Note that the in operator works whether the element is single cardinality or multi-cardinality.
If the terminology being compared is a direct-reference code (e.g. code "Blood Pressure"), use the ~ operator:
where Observation.code ~ "Blood Pressure"
Note that this comparison only works if the element is single-cardinality. For multi-cardinality elements with direct-reference code comparison (e.g. code "Right Breast"), each CodeableConcept must be tested using the ~ operator, so an exists is used:
where exists (Condition.bodySite S where S ~ "Right Breast")
Some terminology-valued elements in FHIR use the Coding type specifically. The same comparison patterns are used for elements of this type. For value sets (e.g. valueset "Inpatient Class"), use in:
where Encounter.class in "Inpatient Class"
And for direct-reference codes (e.g. code "Inpatient"), use ~:
where Encounter.class ~ "Inpatient"
Reviewed 2024-06-18
QI-Core defines a QICore Patient profile that extends the USCore patient.
Patient information includes the birth date, and CQL provides a built-in function to calculate the age of a patient, either current age (i.e. as of now), or as of a particular date. In quality improvement artifacts, age is typically calculated as of a particular date such as the start of the measurement period:
define "Patient Age Between 50 and 75":
AgeInYearsAt(date from start of "Measurement Period") between 50 and 75
NOTE: The AgeInYearsAt function in CQL uses the data model (QICore in this case) to understand how to access the patient's birth date information. NOTE: CQL supports age calculation functions using both Date and DateTime values. In both cases the function is shorthand for a date/datetime duration calculation. If the DateTime overloads are used, note that the timezone offset is considered and there may be edge cases that result in unexpected results, depending on how large the timezone offset is from the execution timestamp. To avoid these edge cases, best practice is to use the date from extractor as shown in the above pattern to ensure the Date calculation is used.
Patient gender in FHIR is represented using codes from the AdministrativeGender code system:
define "Patient Is Male":
Patient.gender = 'male'
NOTE: Terminology-valued elements in FHIR resources are bound to value sets. The gender element is an example of a required binding, which means that only the codes in that binding are allowed to be used. This is why the logic here can be specific about comparing to the actual string
'male'
. In general, terminology-valued elements should be compared using terminology operators. For more information see the Using Terminology topic in the Quality Measure IG.
US Core defines extensions for representing the race and ethnicity of a patient using the CDC's race and ethnicity codes. When authoring using QI-Core, these extensions can be accessed directly on the patient using the "slice name" of the extension:
define "Patient Race Includes Alaska Native":
Patient P
where exists (P.race.ombCategory C where C ~ "American Indian or Alaska Native")
and exists (P.race.detailed C where C ~ "Alaska Native")
NOTE: CQL uses the data model (QI-Core in this case) to understand how to access patient information using the
Patient
definition. This definition is available inPatient
contexts.
Reviewed 2024-06-18 - Updates to be made and reviewed again with group based on discussions
QI-Core defines an Encounter profile to model any encounter between a patient and any number of providers in any setting, including virtual.
NOTE: For background information on accessing clinical information with CQL, see the Retrieve topic in the CQL specification.
By default, encounters in QI-Core are characterized by the type
element, which is typically associated with a value set to limit the set of encounters returned to those that a code in the given value set. For example:
define "Office Visit Encounters":
[Encounter: "Office Visit"]
The type element of Encounters is plural meaning that a given Encounter may have multiple types associated with it. When using value sets such as the "Office Visit" example above, the retrieve resolves using the List overload of the in(ValueSet) operator in CQL. However, when attempting to use a direct-reference code, there is no overload of the Equivalent (~) operator to support the comparison.
This issue is being reviewed and may result in a specification or tooling change to support this use case (see Translator Issue 1181). However, at this time there are two possible workarounds:
- Define a value set containing the required code and use that value set to perform the retrieve
- Use an equivalent where clause with an exists to retrieve the expected results, as shown in the below example:
define "Office Visit Encounters By Code":
[Encounter] E
where exists ((E.type) T where T ~ "Office Visit Code")
Note that this latter workaround will typically result in an unrestricted data requirement for Encounters. For this reason, best-practice is to use the first workaround.
The QI-Core profile also supports characterizing encounters by the class
element, which is used to categorize encounters more broadly than the type
element, using the ActEncounterCode value set. For example:
define "Virtual Encounters":
[Encounter: class ~ QICoreCommon."virtual"]
Note that although QDM-based eCQMs have typically used a type-based approach to filtering encounters, because
class
is a required element in USCore, we propose using class to filter encounters first, unless measure intent needs to search for encounters by type across classes. Additional filtering may be required beyond the class to limit encounters based on specialty, for example:
define "Opthalmology Encounter Codes":
[Encounter: class in "Inpatient Encounter Classes"] InpatientEncounter
where InpatientEncounter.type in "Opthalmology Encounter Codes"
Encounters often need to be filtered based on status
and period
, for example:
define "Completed Encounters During the Measurement Period":
[Encounter: "Office Visit"] OfficeVisit
where OfficeVisit.status = 'finished'
and OfficeVisit.period during "Measurement Period"
The CQMCommon library defines a lengthInDays()
function that calculates the difference in days between the start and end of a period. For example, to filter encounters by the duration of stay:
define "Non-Elective Inpatient Encounter Less Than 120 Days":
["Encounter": "Non-Elective Inpatient Encounter"] NonElectiveEncounter
where NonElectiveEncounter.period.lengthInDays() <= 120
Other durations can also be calculated, for example:
define "Non-Elective Inpatient Encounter Over 24 Hours":
["Encounter": "Non-Elective Inpatient Encounter"] NonElectiveEncounter
where duration in hours of NonElectiveEncounter.period >= 24
NOTE: For ongoing encounters, the end of the period is often not specified, which will typically be interpreted in CQL as an ongoing period, resulting in large duration values.
For inpatient encounters, measures and rules often need to consider total hospitalization period, including any immediately prior emergency department and/or observation status encounters. To facilitate this, the CQMCommon library defines a hospitalizationWithObservation()
function that returns the total duration from admission to the emergency department or observation to the end of the inpatient encounter. For example:
define "Comfort Measures Performed":
["Procedure": "Comfort Measures"] InterventionPerformed
where InterventionPerformed.status in { 'completed', 'in-progress' }
define "Encounter with Comfort Measures Performed during Hospitalization":
"Non-Elective Inpatient Encounter Less Than 120 Days" Encounter
with "Comfort Measures Performed" ComfortMeasure
such that start of ComfortMeasure.performed.toInterval() during Encounter.hospitalizationWithObservation()
Reviewed 2024-06-25 - Updates will be made based on discussion and reviewed with group
Change from 4.1.1: QI-Core STU 6 defines two profiles:
- ConditionProblemsHealthConcerns profile to represent information about patient problems and health concerns
- ConditionEncounterDiagnosis profile to represent diagnoses indicated as part of an encounter.
Change from 4.1.1: QI-Core STU6 no longer supports the use of the Encounter.diagnosisPresentOnAdmission element. This concept should be modeled using the Claim profile and is discussed in the Conditions present on admission section below . Measure developers need to consider their measure intent when building measure logic to look for conditions. If the measure intent is looking to capture conditions that were present on admission or a principal diagnosis, the Claim profile is now used to access that billing related content. Please reference the Conditions present on admission section for patterns related to those concepts.
By default, Condition resources are characterized by the code element which is typically associated with a value set of diagnosis codes.
Many clinical systems make a distinction between the active conditions for a patient (i.e. the problem list or health concerns) and the diagnoses associated with an encounter. Problem list items and health concerns are typically documented with additional information about the condition such as prevalence period and clinical status, while encounter diagnoses typically have less information, usually only the diagnosis code as part of the encounter information. Within FHIR, both these types of data are represented using the Condition resource. The category element is used to indicate which kind of data the Condition represents, a problem list item, a health concern, or an encounter diagnosis, and the ConditionHealthProblems and ConditionEncounterDiagnosis profiles separate conditions by these ctaegories.
Depending on measure intent, different approaches may be needed to access condition data. In particular, clinical status and prevalence period would only be expected to be present on problem list items and health concerns:
define "Active Diabetes Conditions":
[ConditionProblemsHealthConcerns: "Diabetes"] Condition
where Condition.isActive()
The QICoreCommon library defines isProblemListItem()
and isHealthConcern()
functions to facilitate identifying the category of a Condition, as well as an isActive()
function to facilitate determining whether the Condition indicates the presence of a particular diagnosis for the patient. The isActive()
function is equivalent to testing the clinicalStatus element for the active, recurrence, and relapse values.
NOTE: If measure intent is such that condition information should be considered whether it is problem list, health concern, or encounter diagnosis, the category check can be omitted.
New to STU 6.0 To determine a condition existed during the encounter, measure developers should use one of the following approaches:
- Encounter.reasonCode = direct reference code or value set (of the Condition)
- Encounter.reasonReference = ConditionProblemHealthConcern or ConditionEncounterDiagnosis
- Claim.diagnosis
This is a change from 4.1.1 where measure developers used the Encounter.diagnosis= value set pattern. Measure developers should note that not all EHRs will have both Encounter.reasonCode and Encounter.reasonReference and patterns are developed below to look for that information both ways to account for differences in EHR implementation. The following example combines the approaches from 1 and 2 above:
define "Encounters with a Diabetes Condition":
"Completed Encounters During the Measurement Period" CompletedEncounter
where CompletedEncounter.reasonCode in "Diabetes"
or CompletedEncounter.reasonReference = [ConditionEncounterDiagnosis: "Diabetes"]
It is also important for measure developers to consider that if their clinical use case requires the use of prevalence period (i.e., onset to abatement time for a condition) or even just onset time, that will require the use of option 2 – the Encounter.reasonReference – format. This is due to the fact that only referenced profiles provide ability to indicate onset and/or abatement times.
Change from 4.1.1 When looking for history of a condition, clinical status and whether or not the condition is documented as a problem list, health concern, or encounter diagnosis are typically less relevant, so those elements are not typically referenced. However, in QI-Core, because the two types of conditions are represented with different profiles, separate retrieve statements are used to gather both:
define "History of Diabetes":
[ConditionProblemsHealthConcerns: "Diabetes"]
union [ConditionEncounterDiagnosis: "Diabetes"]
Note that depending on measure intent, it may still be necessary to reference elements such as:
- Completion status of the associated encounter for encounter diagnoses
- Clinical status of problem list items and health concerns
- Verification status of problem list items and health concerns, especially refuted conditions
For example:
define "History of Diabetes":
([ConditionProblemsHealthConcerns: "Diabetes"] Condition
where Condition.verificationStatus is not null implies Condition.verificationStatus !~ "refuted"
) union (
[ConditionEncounterDiagnosis: "Diabetes"] Condition
where Condition.getEncounter().status = 'finished'
)
The Condition profiles define onset
and abatement
elements that specify the prevalence period of the condition. The elements can be specified as choices of various types to allow systems flexibility in the way that information is represented. The QI-Core profile for Condition constrains those choices to only those that support actual computation of a prevalence period, and the QICoreCommon library defines abatementInterval
and prevalenceInterval
functions to facilitate accessing this information:
define "Active Diabetes Conditions Onset During the Measurement Period":
"Active Diabetes Conditions" Diabetes
where Diabetes.prevalenceInterval() starts during "Measurement Period"
The prevalenceInterval
function takes a Condition resource and returns the interval from the start of the onset to the end of the abatement. If the Condition is active (i.e. has a clinicalStatus of active, recurrence, or relapse), then the ending boundary of the interval is inclusive (i.e. closed). Otherwise, the ending boundary of the interval is exclusive (i.e. open). When looking for whether a condition was active at some point, use the prevalenceInterval function rather than looking at the status element only.
QICore STU6 no longer supports the use of the Encounter.diagnosisPresentOnAdmission element. To express the concept of a condition present on admission, measure developers should be use the QI Core Claim profile.
Reviewed 2024-06-25
QI-Core defines a variety of profiles for use in accessing observations for a patient. Specifically, QI-Core includes the vital signs profiles defined in US Core such as blood pressure, body height and weight, and BMI, as well as several social determinants observations like occupation and sexual orientation. In addition, US Core includes two new profiles around pregnancy:
- Pregnancy status http://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-observation-pregnancystatus.html
- pregnancy intent http://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-observation-pregnancyintent.html.
New QI-Core profiles added (since 4.1.1 and 5.0) include:
-
QI-Core Simple Observation https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-simple-observation.html
-
QI-Core Non Patient Observation https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-nonpatient-observation.html
In general, these profiles do not constrain the value of the status element, meaning that retrieves of these profiles will return observations in any status. As a modifier element, authors must consider the possible values of the observation status when determining how to filter the results of a retrieve of these profiles.
Reviewed 2024-06-25
When using QI-Core to access profiled resources, the result of the retrieve will only include resources that conform to that profile. This means that the retrieve is effectively a filter by conformance, meaning that the expression does not need to provide filters for values that are fixed by the profile definition. When retrieving Respiratory rate, for example, this means that the expression does not need to test that the code of the Observation is the LOINC code for respiratory rate (9279-1), the retrieve will only result in observations that already have that code:
// Respiratory rate - 9279-1
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-respiratory-rate.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-respiratory-rate.html)
define RespiratoryRate:
["USCoreRespiratoryRateProfile"] O
where O.status in { 'final', 'amended', 'corrected' }
As a rule of thumb, if a profile definition defines a fixed value constraint for an element, then the expression does not need to use that element.
// Heart rate - 8867-4
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-heart-rate.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-heart-rate.html)
define HeartRate:
[USCoreHeartRateProfile] O
where O.status in { 'final', 'amended', 'corrected' }
// Body temperature - 8310-5
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-body-temperature.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-body-temperature.html)
define BodyTemperature:
[USCoreBodyTemperatureProfile] O
where O.status in { 'final', 'amended', 'corrected' }
// Body height - 8302-2
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-body-height.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-body-height.html)
define BodyHeight:
[USCoreBodyHeightProfile] O
where O.status in { 'final', 'amended', 'corrected' }
// Head circumference - 9843-4
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-head-occipital-frontal-circumference-percentile.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-head-occipital-frontal-circumference-percentile.html)
define HeadCircumference:
[USCoreHeadCircumferenceProfile] O
where O.status in { 'final', 'amended', 'corrected' }
// Body weight - 29463-7
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-body-weight.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-body-weight.html)
define BodyWeight:
[USCoreBodyWeightProfile] O
where O.status in { 'final', 'amended', 'corrected' }
// Body mass index - 39156-5
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-bmi.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-bmi.html)
define BodyMassIndex:
[USCoreBMIProfile] O
where O.status in { 'final', 'amended', 'corrected' }
// Blood pressure systolic and diastolic - 85354-9
// Systolic blood pressure - 8480-6
// Diastolic blood pressure - 8462-4
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-blood-pressure.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-blood-pressure.html)
define "BloodPressure less than 140 over 90":
[USCoreBloodPressureProfile] BP
where BP.status in { 'final', 'amended', 'corrected' }
and BP.systolic.value < 140 'mm[Hg]'
and BP.diastolic.value < 90 'mm[Hg]'
// USCore Pediatric BMI for Age - 59576-9
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-pediatric-bmi-for-age.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-pediatric-bmi-for-age.html)
define PediatricBMIForAge:
[USCorePediatricBMIforAgeObservationProfile] O
where O.status in { 'final', 'amended', 'corrected' }
// USCore Pediatric Weight for Height - 77606-2
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-pediatric-weight-for-height.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-pediatric-weight-for-height.html)
define PediatricWeightForHeight:
[USCorePediatricWeightForHeightObservationProfile] O
where O.status in { 'final', 'amended', 'corrected' }
// USCore Pulse Oximetry - 59408-5
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-pulse-oximetry.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-pulse-oximetry.html)
define PulseOximetry:
[USCorePulseOximetryProfile] O
where O.status in { 'final', 'amended', 'corrected' }
Note that Oxygen Saturation is now part of the pulse oximetry profile.
Pregnancy Status https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-observation-pregnancystatus.html This profile sets minimum expectations for the Observation resource to record, search, and fetch the “state or condition of being pregnant”. For measure developers looking to capture a pregnancy status, the following pattern can be used:
define "Currently pregnant":
["USCorePregnancyStatusProfile"] PregStatus
where PregStatus.status = 'final'
and PregStatus.value = 'Pregnant'
Pregnancy Intent https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-observation-pregnancyintent.html this profile sets minimum expectations for the Observation resource to record, search, and fetch the “patient’s intent to become pregnant” over the next year.
define "Pregnancy Intent":
["USCorePregnancyIntentProfile"] PregIntent
where PregIntent.status = 'final'
and PregIntent.value = 'No desire to become pregnant (finding)'
Reviewed 2024-06-25
QI-Core includes the USCore Smoking Status profile:
// USCore Smoking Status
// @profile: [https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-smokingstatus.html](https://hl7.org/fhir/us/core/STU6.1/StructureDefinition-us-core-smokingstatus.html)
define SmokingStatus:
["USCoreSmokingStatusProfile"] O
where O.status in { 'final', 'amended', 'corrected' }
Reviewed 2024-06-25
Laboratory results in QI-Core use the [LaboratoryResultObservation] https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-observation-lab.html profile. By default, Laboratory results in QI-Core are characterized by the code element.
define LaboratoryResultObservation:
["LaboratoryResultObservation"] O
where O.status in { 'final', 'amended', 'corrected' }
Reviewed 2024-06-25
Clinical test results (including imaging results) in QI-Core use the [ObservationClinicalResult] https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-observation-clinical-result.html profile. By default, clinical test results in QI-Core are characterized by the code element.
define ObservationClinicalResult:
["ObservationClinicalResult"] O
where O.status in { 'final', 'amended', 'corrected' }
Reviewed 2024-06-25
New from 4.1.1 Surveys and assessments in QI-Core use the [ObservationScreeningAssessment] https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-observation-screening-assessment.html profile. By default, survey observations in QI-Core are characterized by the code element.
define ObservationAssessemt:
["ObservationScreeningAssessment"] O
where O.status in { 'final', 'amended', 'corrected' }
Reviewed 2024-06-25
In addition, QI-Core defines a Simple Observation https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-simple-observation.html profile for use when accessing observations that are not covered by the specific profiles defined in FHIR and US Core. Observations in QI-Core are characterized by the code element, which is typically filtered to a particular value set:
define "Pap Test with Results":
["SimpleObservation": "Pap Test"] PapTest
where PapTest.value is not null
and PapTest.status in { 'final', 'amended', 'corrected', 'preliminary' }
NOTE: As with the other observation profiles, the status of a QI-Core Observation must be considered in order to ensure that the results of the expression will match measure intent. This typically means that the status element will be used in the expression as in the prior example.
Reviewed 2024-06-25
QI-Core defines an [ObservationCancelled] https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-observationcancelled.html profile to support identifying observations that were not performed for a particular reason:
define "Pap Test Refused":
["ObservationCancelled": "Pap Test"] PapTest
where PapTest.notDoneReason in "Patient Refusal"
Reviewed 2024-06-25
QI-Core defines an [ObservationNonPatient] https://hl7.org/fhir/us/qicore/StructureDefinition-qicore-nonpatient-observation.html profile for evaluating resource use and availability rather than focusing on patients:
define "Hemodialysis machine available":
["ObservationNonPatient": "Hemodialysis"] Hemo
where Hemo.status= 'final'
and Hemo.value = 'Equipment available (finding)'
(Reviewed 2024-08-06) FHIR defines several medication-related resources that are profiled for use in the US by US Core, and then by QI-Core for use in quality improvement artifacts. For background on the FHIR medication resources, see the Medication module in the base FHIR specification. Additional guidance on how medication information is profiled within US Core can be found in the Medication list guidance topic in the US Core implementation guide. In comparison to STU 4.1.1, there are no new medication profiles added to STU6 of QI-Core.
QICore defines the MedicationRequest profile to represent medication proposals, plans, and orders, as well as self-reported medications. The following example illustrates an order for Antithrombotic Therapy to be taken by the patient once discharged. MedicationRequest resources in QI-Core are characterized by the medication
element which can be represented as a code or a reference.
define "Antithrombotic Therapy at Discharge":
["MedicationRequest": medication in "Antithrombotic Therapy"] Antithrombotic
where (Antithrombotic.isCommunity() or Antithrombotic.isDischarge())
and Antithrombotic.status in { 'active', 'completed' }
and Antithrombotic.intent = 'order'
NOTE: Because the status
element is a modifier that is not constrained by the profile to a specific value or value set, authors must consider all the possible values of the status to ensure the expression matches measure intent. In this case the statuses of active
and completed
indicate active or filled prescriptions for medications in the Antithrombotic Therapy value set.
NOTE: Because the MedicationRequest profile fixes the value of the doNotPerform
element to false if it is present, that element does not need to be tested in the expression.
QI-Core defines the MedicationNotRequested profile to represent documentation of the reason for not ordering a particular medication or class of medications. By default, MedicationNotRequested resources in QI-Core are characterized by the medication
element which can be represented as a code or a reference.
define "Reason for Not Ordering Antithrombotic":
["MedicationNotRequested": "Antithrombotic Therapy"] NoAntithromboticDischarge
where (NoAntithromboticDischarge.reasonCode in "Medical Reason"
or NoAntithromboticDischarge.reasonCode in "Patient Refusal")
and (NoAntithromboticDischarge.isCommunity() or NoAntithromboticDischarge.isDischarge())
and NoAntithromboticDischarge.status in { 'active', 'completed' }
and NoAntithromboticDischarge.intent = 'order'
NOTE: Because the status
element is a modifier that is not constrained by the profile to a specific value or value set, authors must consider all the possible values of the status to ensure the expression matches measure intent. In this case the statuses of active
and completed
indicate no active or filled prescriptions for medications in the Antithrombotic Therapy value set.
NOTE: Because the MedicationNotRequested profile fixes the value of doNotPerform
to true, that element does not need to be tested in the expression.
QI-Core defines the MedicationAdministration profile to represent the administration of a medication to a patient. By default, MedicationAdministration resources in QICore are characterized by the medication
element, which can be represented as a code or a reference.
define "Low Dose Unfractionated Heparin Administration":
["MedicationAdministration": medication in "Low Dose Unfractionated Heparin for VTE Prophylaxis"] VTEMedication
where VTEMedication.status = 'completed'
and VTEMedication.category ~ QICoreCommon."Inpatient"
NOTE: Because the MedicationAdministration profile does not fix the value of the status
element, authors must consider all the possible values of the element to ensure the expression matches measure intent. In this case, the completed
status indicates the only completed medication administrations should be returned.
QI-Core defines the MedicationAdministrationNotDone profile to represent documentation of the reason a medication administration did not occur. By default, MedicationAdministrationNotDone resources in QI-Core are characterized by the medication
element, which can be represented as a code or a reference.
define "Low Dose Unfractionated Heparin for VTE Prophylaxis Not Administered":
["MedicationAdministrationNotDone": "Low Dose Unfractionated Heparin for VTE Prophylaxis"] VTEMedication
where VTEMedication.category ~ QICoreCommon."Inpatient"
and (VTEMedication.reasonCode in "Medical Reason" or VTEMedication.reasonCode in "Patient Refusal")
NOTE: Because the MedicationAdministrationNotDone profile fixes the value of status
to not-done, that element does not need to be tested in the expression.
Medication dispensed
QI-Core defines the MedicationDispense profile to represent the fulfillment of a medication request, either in a hospital or community pharmacy. By default, MedicationDispense resources in QI-Core are characterized by the medication
element, which can be represented as a code or a reference.
define "Dementia Medication Dispensed":
["MedicationDispense": "Dementia Medications"] MedicationDispense
where MedicationDispense.status in { 'active', 'completed', 'on-hold' }
NOTE: Because the MedicationDispense profile does not fix the value of the status
element, authors must consider all the possible values of the element to ensure the expression matches measure intent. In this case, the active
, completed
, and on-hold
statuses are used to retrieve any positive dispensing event.
QI-Core defines the MedicationDispenseDeclined profile to represent documentation of the reason that a dispense did not occur. By default, MedicationDispenseDeclined resources in QICore are characterized by the medication
element, which can be represented as a code or a reference.
define "Dementia Medication Not Dispensed":
["MedicationDispenseDeclined": "Dementia Medications"] MedicationDispense
where MedicationDispense.statusReason in "Medical Reason"
or MedicationDispense.statusReason in "Patient Refusal"
NOTE: Because the MedicationDispenseDeclined profile fixes the value of the status
element to declined
, that element does not need to be tested in the expression.
In addition to medications ordered at discharge or administered in the hospital setting, measure developers may also want to look for medications that are currently in use by a patient outside the hospital setting or those medications not prescribed by a provider (commonly referred to as OTC or over the counter). Two examples are shown below:
define "Antithrombotic Therapy Active":
["MedicationRequest": "Antithrombotic Therapy"] Antithrombotic
where Antithrombotic.status = 'active'
define "Niacin OTC at home":
["MedicationRequest": "NiacinOTC"] Niacin
where (Niacin.isCommunity())
and Niacin.status = 'active'
and Niacin.intent = 'plan'
and Niacin.reporter = 'patient'
Note that 'Niacin.isCommunity' reflects the MedicationRequest category which indicates the setting in which the medication is taken (or is expected to be taken) is community.
(Reviewed 2024-08-06) FHIR defines several procedure-related resources to support representing the proposal, planning, ordering, and performance of services and procedures for a patient. In comparison to STU 4.1.1, there are no new procedure profiles added to STU6 of QI-Core.
QI-Core defines the Procedure profile to represent an in-progress or complete procedure for a patient. By default, Procedure resources in QI-Core are characterized by the code
element.
define "Application of Intermittent Pneumatic Compression Devices":
["Procedure": "Application of Intermittent Pneumatic Compression Devices (IPC)"] DeviceApplied
where DeviceApplied.status = 'completed'
NOTE: Because the Procedure profile does not fix the value of the status
element, authors must consider all the possible values of the element to ensure the expression meets measure intent. In this case, completed
status is used to indicate that only completed procedures should be returned.
QI-Core defines the ProcedureNotDone profile to represent documentation of the reason a particular procedure, or class of procedures, was not performed. By default, ProcedureNotDone resources in QI-Core are characterized by the code
element.
define "Intermittent Pneumatic Compression Devices Not Applied":
[ProcedureNotDone: "Application of Intermittent Pneumatic Compression Devices (IPC)"] DeviceNotApplied
where DeviceNotApplied.statusReason in "Medical Reason"
or DeviceNotApplied.statusReason in "Patient Refusal"
NOTE: Because the ProcedureNotDone profile fixes the value of the status
element to not-done
, that element does not need to be tested in the expression.
Procedure ordered
QI-Core defines the ServiceRequest profile to represent the proposal, planning, or ordering of a particular service. By default, ServiceRequest resources in QI-Core are characterized by the code
element.
define "Intermittent Pneumatic Compression Devices Ordered":
["ServiceRequest": "Application of intermittent pneumatic compression devices (IPC)"] DeviceOrdered
where DeviceOrdered.status in { 'active', 'completed', 'on-hold' }
NOTE: Because the ServiceRequest profile does not fix the value of the status
element, authors must consider all the possible values of the element to ensure the expression matches measure intent. In this case, the active
, completed
, and on-hold
statuses are used to ensure a positive order.
NOTE: Because the ServiceRequest profile fixes the value of the doNotPerform
element to false if it is present, that element does not need to be tested in the expression.
QI-Core defines the ServiceNotRequested profile to represent documentation of the reason a particular service or class of services was not ordered. By default, ServiceNotRequested resources in QI-Core are characterized by the code
element.
define "Intermittent Pneumatic Compression Devices Not Ordered":
["ServiceNotRequested": "Application of intermittent pneumatic compression devices (IPC)"] DeviceNotOrdered
where (DeviceNotOrdered.reasonRefused in "Medical Reason"
or DeviceNotOrdered.reasonRefused in "Patient Refusal")
and DeviceNotOrdered.status in { 'active', 'completed', 'on-hold' }
NOTE: Because the ServiceNotRequested profile does not fix the value of the status
element, authors must consider all the possible values of the element to ensure the expression matches measure intent. In this case, the active
, completed
, and on-hold
statuses are used to ensure a valid order statement.
NOTE: Because the ServiceNotRequested profile fixes the value of doNotPerform
to true, that element does not need to be tested in the expression.
FHIR defines several resources related to the tracking and management of devices used by patients, including Device and DeviceRequest. It is important to note that the types of devices modelled by these profiles are those that are considered personal use by the patient (examples include frailty devices like canes, glucometers or CPAP machines). In comparison to STU 4.1.1, there are no new device profiles added to STU6 of QI-Core.
QI-Core defines the DeviceRequest profile to represent proposals, planning, and ordering of devices for a patient. By default, DeviceRequest resources in QICore are characterized by the code
element, which can be represented as a code or a reference.
define "Device Indicating Frailty":
[DeviceRequest: "Frailty Device"] FrailtyDeviceOrder
where FrailtyDeviceOrder.status in { 'active', 'on-hold', 'completed' }
and FrailtyDeviceOrder.intent in { 'order', 'original-order', 'reflex-order', 'filler-order', 'instance-order' }
NOTE: Because the DeviceRequest profile does not fix the value of the
status
element, authors must consider all the possible values of the element to ensure the expression matches measure intent. In this case theactive
,completed
andon-hold
statuses are used to ensure a positive device order.
NOTE: Because the DeviceRequest profile fixes the value of the
doNotPerform
element tofalse
if it is present, that element does not need to be tested in the expression.
QI-Core defines the DeviceNotRequested profile to represent documentation of the reason for not ordering a particular device, or class of devices. By default, DeviceNotRequested resources in QI-Core are characterized by the code
element, which can be represented as a code or a reference.
define "CPAP not requested":
["DeviceNotRequested": "CPAP"] CPAPNotRequested
where CPAPNotRequested.status in {'active'}
and CPAPNotRequested.intent in {'plan', 'proposal', 'order'}
NOTE: Because the DeviceNotRequested profile fixes the value of
doNotPerform
to true, this element does not need to be tested in the expression.
For those cases where measurement is looking to capture the use of a device, the Device profile should be used.
define "CPAP in use":
["Device": "CPAP"] CPAPInUse
where CPAPInUse.status in {'active'}
FHIR defines the AllergyIntolerance resource to represent allergies and intolerances for a patient. In comparison to STU 4.1.1, there are no new allergy/ intolerance profiles added to STU6 of QI-Core.
QI-Core defines the AllergyIntolerance profile to represent allergies and intolerances for a patient. By default, AllergyIntolerance resources in QI-Core are characterized by the code
element.
define "Statin Allergy Intolerance":
["AllergyIntolerance": "Statin Allergen"] StatinAllergyIntolerance
where StatinAllergyIntolerance.clinicalStatus is null
or StatinAllergyIntolerance.clinicalStatus ~ QICoreCommon."allergy-active"
NOTE: Because the AllergyIntolerance profile does not constrain the values of the
clinicalStatus
orverificationStatus
elements of the resource, authors must consider the possible values of these elements to ensure the expression matches measure intent. In this case, theclinicalStatus
, if present, must be"allergy-active"
.
US Core guidance for allergies (https://hl7.org/fhir/us/core/STU6.1/AllergyIntolerance-example.html) states that if a patient has been asked, but has indicated they have no known allergies, this would be represented as:
define "No Known Allergies":
["AllergyIntolerance": "No known allergy (situation)"] NKA
where NKA.verificationStatus = "confirmed"
FHIR defines several immunization-related resources to track and manage the immunization information for a patient, including Immunization and ImmunizationRecommendation. In comparison to STU 4.1.1, there are no new immunization profiles added to STU6 of QI-Core.
NOTE: The Immunization resources are reflective of immunization information as recorded in an Immunization Information System. For immunizations as part of clinical workflow, the medication resources should be used?
QI-Core defines the Immunization profile to represent immunization information for a patient. By default, Immunization resources in QI-Core are characterized by the vaccineCode
element.
define "Polio Immunizations":
["Immunization": "Inactivated Polio Vaccine (IPV)"] PolioVaccination
where PolioVaccination.status = 'completed'
NOTE: Because the Immunization profile does not fix the value of the
status
element, authors must consider all the possible values for the element to ensure the expression meets measure intent.
QI-Core defines the ImmunizationNotDone profile to represent documentation of the reason an immunization was not performed. By default, ImmunizationNotDone resources in QI-Core are characterized by the vaccineCode
element.
define "Reason for No Polio Immunization":
["ImmunizationNotDone": "Inactivated Polio Vaccine (IPV)"] PolioVaccination
where PolioVaccination.statusReason in "Medical Reason"
or PolioVaccination.statusReason in "Patient Refusal"
NOTE: Because the ImmunizationNotDone profile fixes the value of the
status
element tonot-done
, this element does not need to be tested in the expression.
QI-Core defines the Communication profile to represent communications with or about the patient. It is important to note that the definition of the profile is "A record of information transmitted from a sender to a receiver". Measure developers looking to model clinical concepts like patient education should use the Procedure profile as that represents "An action that is being or was performed on a patient".
By default, Communication resources in QI-Core are characterized by the topic
element. In comparison to STU 4.1.1, there are no new communication profiles added to STU6 of QI-Core.
define "Lab results communicated":
["Communication": "report-labs"] LabReport
where LabReport.topic = 'report-labs'
and LabReport.status = 'completed'
and LabReport.reasonCode = 'Serum pregnancy test negative (finding)'
NOTE: Because the Communication profile does not fix the value of the
status
element, authors must consider all the possible values for the element to ensure the expression meets measure intent.
NOTE: This expression uses a direct-reference code of "Macular edema absent (situation)" (i.e. referencing a specific code from a code system, rather than a value set consisting of multiple codes). For more information on using direct-reference codes in CQL expressions, refer to the Codes topic in the Using CQL with FHIR IG.
QI-Core defines the CommunicationNotDone to represent documentation of the reason a communication was not done. By default, CommunicationNotDone resources in QI-Core are characterized by the topic
element.
define "Medication Not Available":
["CommunicationNotDone": "progress update"] ProgressUpdate
where ProgressUpdate.topic = 'progress-update'
and ProgressUpdate.status = 'completed'
and ProgressUpdate.reasonCode = 'Medication not available from manufacturer (finding)'
NOTE: Because the CommunicationNotDone profile fixes the value of the
status
element tonot-done
, this element does not need to be tested in the expression.
NOTE: At this time, direct-reference codes cannot be used as the terminology target of a retrieve of a negation profile. Available workarounds for this issue are to either create a value set with the single required code or to use the long-hand expression of the negation statement.
Authoring Patterns - QICore v4.1.1
Authoring Patterns - QICore v5.0.0
Authoring Patterns - QICore v6.0.0
Cooking with CQL Q&A All Categories
Additional Q&A Examples
Developers Introduction to CQL
Specifying Population Criteria