Skip to content

Authoring Patterns QICore v4.1.1

Bryn Rhodes edited this page May 15, 2024 · 50 revisions

Draft_QDM5.6 to QICore4.1.1_March2023.docx

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.

QICore Information Model Overview

Reviewed 2023-11-16

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:

  1. Patient - Representation of patient demographic and basic characteristics
  2. Encounters - Encounters between a patient and healthcare providers, typically taking place at a facility or virtually
  3. Observations - Facts about the patient such as lab results, vital signs, social history, etc.
  4. Conditions - Conditions the patient has (or does not have)
  5. Allergies - Allergies and intolerances the patient has (or does not have)
  6. Medications - Information related to medications the patient is prescribed and/or using
  7. Procedures - Information related to procedures ordered and/or performed for the patient
  8. Devices - Information related to devices the patient is using and/or has been prescribed
  9. Immunizations - Information related to immunizations the patient has received or been recommended
  10. Communication - Information related to communications with or about the patient

In addition to the patterns on this page, an index of the QICore 4.1.1 model info is available that documents the primary code paths for each QICore profile.

NOTE: The information in this page specifically uses the 4.1.1 version of QICore, which depends on the 3.1.1 version of USCore, and both of which are based on the R4 version 4.0.1 of FHIR. As of this writing (2023-01-26) QICore 5.0.0 is currently in ballot reconciliation and is expected to be published soon. A 5.0.0 version of this page will be produced once that publication is finalized.

NOTE: As with all FHIR implementation guides, the QICore profiles use the FHIR data types to define the types of values that are allowed to be used for elements in the profiles. For example, the Patient birthDate element is of type date to indicate that the allowed values are dates. For ease of use within CQL, the FHIR data types are mapped to the CQL system-defined types, as defined in the Quality Measure IG FHIR Type Mapping topic. Because of this mapping, the type of the birthDate element when accessed in CQL is the CQL system type System.Date.

The following sections provide specific examples of best practices for accessing information in each of these high-level areas.

Use of Terminologies

Reviewed 2024-05-07

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.

code

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

CodeableConcept

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")

Coding

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"

Patient

QICore defines a QICore Patient profile that extends the USCore patient.

Patient age

Reviewed 2023-07-11

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

Reviewed 2023-03-07

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 the bound value set are allowed to be used. This allows the logic in this example to compare using 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.

Patient race and ethnicity

Reviewed 2023-03-14

US Core defines extensions for representing the race and ethnicity of a patient using the CDC's race and ethnicity codes. When authoring using QICore, 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 (QICore in this case) to understand how to access patient information using the Patient definition. This definition is available in Patient contexts.

Patient deceased

Reviewed 2023-11-16

Some elements in QICore profiles allow for values to be represented in different ways. For example, the deceased element allows values of Boolean and DateTime. This means that the value of the deceased element for any particular patient may be either a Boolean (true or false) or a DateTime. In FHIR and CQL, these types of elements are called choice types.

NOTE: Because the QICore model is using CQL system-defined types (see the FHIR Type Mapping topic), the spelling of the types uses the CQL type names (e.g. Boolean rather than boolean).

When accessing choice types in CQL expressions, authors can typically just treat the element as the type they are interested in accessing. For example:

define "Patient Is Deceased":
  Patient.deceased is true

define "Patient Deceased During Measurement Period":
  Patient.deceased during day of "Measurement Period"

In the first expression, the deceased element is treated as a Boolean, whereas in the second expression, the deceased element is treated as a DateTime.

NOTE: No value conversions take place when accessing choice types, when using the "Patient Is Deceased" expression above, for example, if the Patient record has a DateTime value for the deceased element, the result of that expression will be false.

Encounters

QICore 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.

Office visit encounters

Reviewed 2023-02-28

By default, encounters in QICore are characterized by the type element, which is typically associated with a value set to limit the set of encounters returned to those with a code in the given value set. For example:

define "Office Visit Encounters":
  [Encounter: "Office Visit"]

Accessing Encounters with a Direct-reference code

Reviewed 2023-07-25

The type element of Encounters is multi-cardinality, 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<Concept> 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:

  1. Define a value set containing the required code and use that value set to perform the retrieve
  2. 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.

Encounters by class

Reviewed 2023-02-16

The QICore 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"

Completed encounters in a period

Reviewed 2023-02-21

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"

Encounters with a certain length

Reviewed 2023-02-28

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.

Hospitalization

Reviewed 2023-02-28

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()

Conditions

QICore defines the Condition profile to represent information about patient problems, health concerns, and diagnoses.

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 QICore 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.

Active conditions

Reviewed 2023-02-21

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.

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":
  [Condition: Diabetes] Condition
    where (Condition.isProblemListItem() or Condition.isHealthConcern())
      and 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.

Encounters with a condition

Reviewed 2023-06-27

For encounter diagnoses, CQMCommon defines an encounterDiagnosis() function to facilitate identifying encounter diagnoses:

define "Encounters with a Diabetes Condition":
  "Completed Encounters During the Measurement Period" CompletedEncounter
    where exists (
      (CompletedEncounter.encounterDiagnosis()) EncounterDiagnosis 
        where EncounterDiagnosis.code in "Diabetes"
    )

Note the absence of testing for the clinical status of the condition.

History of a condition

Reviewed 2023-02-21

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.

define "History of Diabetes":
  [Condition: Diabetes] Condition

Note that depending on measure intent, it may still be necessary to reference elements such as:

  1. Completion status of the associated encounter for encounter diagnoses
  2. Clinical status of problem list items and health concerns
  3. Verification status of problem list items and health concerns, especially refuted conditions

For example:

define "History of Diabetes":
  [Condition: Diabetes] Condition
    where (Condition.isEncounterDiagnosis() and Condition.getEncounter().status = 'finished')
      or (
        (Condition.isProblemListItem() or Condition.isHealthConcern()) 
          and Condition.verificationStatus is not null implies Condition.verificationStatus !~ "refuted"
    )

Onset, abatement, and prevalence period

Reviewed 2023-08-22

The Condition resource defines 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 QICore 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.

Conditions present on admission

Reviewed 2023-03-07

The QICore Condition profile also defines a diagnosisPresentOnAdmission indicator to allow systems to indicate whether a particular diagnosis was present on admission for an encounter:

define "Encounter With Diabetes Diagnosis Present on Admission":
  "Non-Elective Inpatient Encounter Less Than 120 Days" IPEncounter
    where exists (IPEncounter.diagnosis D
      where D.condition.getCondition().code in "Diabetes"
        and D.diagnosisPresentOnAdmission in "Present on Admission or Clinically Undetermined"
    )

Note that this expression is using the condition reference from the Encounter to retrieve the specific encounter diagnosis. This is done using the getCondition() function defined in QICoreCommon, as opposed to retrieving the Condition resources directly as in the previous examples.

Observations

QICore defines a variety of profiles for use in accessing observations for a patient. Specifically, QICore includes the Vital Signs profiles defined in the base FHIR specification, as well as several additional Vital Signs profiles defined in USCore such as Pediatric BMI.

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.

Vital Signs

Reviewed 2023-03-09

When using QICore 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: http://hl7.org/fhir/StructureDefinition/resprate
define RespiratoryRate:
  ["observation-resprate"] 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: http://hl7.org/fhir/StructureDefinition/heartrate
define HeartRate:
  ["observation-heartrate"] O
    where O.status in { 'final', 'amended', 'corrected' }

// Oxygen saturation - 2708-6
// @profile: http://hl7.org/fhir/StructureDefinition/oxygensat
define OxygenSaturation:
  ["observation-oxygensat"] O
    where O.status in { 'final', 'amended', 'corrected' }

// Body temperature - 8310-5
// @profile: http://hl7.org/fhir/StructureDefinition/bodytemp
define BodyTemperature:
  ["observation-bodytemp"] O
    where O.status in { 'final', 'amended', 'corrected' }

// Body height - 8302-2
// @profile: http://hl7.org/fhir/StructureDefinition/bodyheight
define BodyHeight:
  ["observation-bodyheight"] O
    where O.status in { 'final', 'amended', 'corrected' }

// Head circumference - 9843-4
// @profile: http://hl7.org/fhir/StructureDefinition/headcircum
define HeadCircumference:
  ["observation-headcircum"] O
    where O.status in { 'final', 'amended', 'corrected' }

// Body weight - 29463-7
// @profile: http://hl7.org/fhir/StructureDefinition/bodyweight
define BodyWeight:
  ["observation-bodyweight"] O
    where O.status in { 'final', 'amended', 'corrected' }

// Body mass index - 39156-5
// @profile: http://hl7.org/fhir/StructureDefinition/bmi
define BodyMassIndex:
  ["observation-bmi"] 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: http://hl7.org/fhir/StructureDefinition/bp
define "BloodPressure less than 140 over 90":
  ["observation-bp"] BP
    where BP.status in { 'final', 'amended', 'corrected' }
      and BP.SystolicBP.value < 140 'mm[Hg]'
      and BP.DiastolicBP.value < 90 'mm[Hg]'

// USCore Pediatric BMI for Age - 59576-9
// @profile: http://hl7.org/fhir/us/core/StructureDefinition/pediatric-bmi-for-age
define PediatricBMIForAge:
  [USCorePediatricBMIforAgeObservationProfile] O
    where O.status in { 'final', 'amended', 'corrected' }

// USCore Pediatric Weight for Height - 77606-2
// @profile: http://hl7.org/fhir/us/core/StructureDefinition/pediatric-weight-for-height
define PediatricWeightForHeight:
  [USCorePediatricWeightForHeightObservationProfile] O
    where O.status in { 'final', 'amended', 'corrected' }

// USCore Pulse Oximetry - 59408-5
// @profile: http://hl7.org/fhir/us/core/StructureDefinition/us-core-pulse-oximetry
define PulseOximetry:
  [USCorePulseOximetryProfile] O
    where O.status in { 'final', 'amended', 'corrected' }

Smoking Status

Reviewed 2023-03-14

QICore includes the USCore Smoking Status profile:

// USCore Smoking Status
// @profile: http://hl7.org/fhir/us/core/StructureDefinition/us-core-smokingstatus
define SmokingStatus:
  ["USCoreSmokingStatusProfile"] O
    where O.status in { 'final', 'amended', 'corrected' }

Laboratory Result

Reviewed 2023-03-07

Laboratory results in QICore use the USCoreLaboratoryResultObservationProfile. Laboratory results in QICore are characterized by the code element.

// @profile: http://hl7.org/fhir/us/core/StructureDefinition/us-core-observation-lab
define LaboratoryResult:
  ["US Core Laboratory Result Observation Profile"] O
    where O.status in { 'final', 'amended', 'corrected' }

Other Observations

Reviewed 2023-03-07

In addition, QICore defines a general Observation profile for use when accessing observations that are not covered by the specific profiles defined in FHIR and US Core. Observations in QICore are characterized by the code element, which is typically filtered to a particular value set:

define "Pap Test with Results":
  [Observation: "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 QICore 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.

Observations not done

Reviewed 2023-03-09

QICore defines an ObservationNotDone profile to support identifying observations that were not performed for a particular reason:

define "Pap Test Refused":
  ["ObservationNotDone": "Pap Test"] PapTest
    where PapTest.notDoneReason in "Patient Refusal"

Observations with coded values

Reviewed 2023-11-16

Observations in QICore have a value element that allows the value of the observation to be represented differently. Vital signs, for example, are typically represented as a Quantity, whereas survey and exam observation values are often represented with codes. The following example illustrates a request for Observations of "Medical equipment used" that have a value that is a code in the "Frailty Device" value set.

define "Has Criteria Indicating Frailty":
  ([Observation: "Medical equipment used"]) FrailtyDeviceApplied
    where FrailtyDeviceApplied.value as Concept in "Frailty Device"

As is common in QICore (and FHIR generally), coded values are represented with the CQL type Concept, which supports providing multiple, equivalent codings for a concept.

NOTE: The as Concept is required here because CQL allows the InValueSet operation to be invoked with both a Concept and a String, and the value element of an Observation allows both representations. This means that which overload should be invoked is ambiguous and so the as Concept is required in order to ensure the correct version of InValueSet is used.

NOTE: The spelling of Concept is used here rather than CodeableConcept because QICore uses CQL system-defined types, as defined by the FHIR Type Mapping topic.

Medications

FHIR defines several medication-related resources that are profiled for use in the US by USCore, and then by QICore for use in quality improvement artifacts. For background on the FHIR medication resources, see the Medications 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.

Medication ordered

Reviewed 2024-05-07

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 QICore 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 in { 'order', 'original-order', 'reflex-order', 'filler-order', 'instance-order' }

NOTE: Because the retrieve uses terminology to filter access to resources, this pattern only returns MedicationRequests that have a medication element represented as a code. See the following section for a pattern to retrieve MedicationRequest resources that have a medication element represented as a reference.

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 intent is a modifier element in MedicationRequest, authors must consider all the possible values of the element to ensure the expression matches measure intent. The intent element can have values drawn from the Request Intent value set. In this case the query is asking for all orders, so the order code and all children are used.

NOTE: Because the MedicationRequest profile does fixes the value of the doNotPerform element to false, the expression does not need to test this element.

Medication ordered (as a reference)

Reviewed 2023-08-11

Because the QICore MedicationRequest profile allows the medication element to be represented as either a code or a reference, a different pattern is currently required to access medication data from systems that represent medication using a reference:

define fluent function medication(medicationRequest MedicationRequest):
  singleton from ([Medication] M where M.id = medicationRequest.medication.reference.getId())

define fluent function medicationIs(medicationRequest MedicationRequest, valueSet ValueSet):
  medicationRequest.medication in valueSet
    or medicationRequest.medication().code in valueSet

define "Antithrombotic Therapy at Discharge (combined)":
  ["MedicationRequest"] Antithrombotic
    where Antithrombotic.medicationIs("Antithrombotic Therapy")
      and (Antithrombotic.isCommunity() or Antithrombotic.isDischarge())
      and Antithrombotic.status in { 'active', 'completed' }
      and Antithrombotic.intent = 'order'

This pattern defines a medicationIs() fluent function that resolves the reference, retrieving the Medication resource by its id element directly and then comparing the code of the referenced medication for the value set.

NOTE: The standards group is currently looking at whether a technical solution to this can be provided, such that the distinction between terminology and reference can be handled with a single pattern, rather than requiring that distinction to be addressed in authoring expressions directly. As such, this pattern is not recommended for use at this time; best practice is to continue to use the terminology filtering approach directly in the retrieve. This best practice recommendations applies to all the Medication-related patterns (MedicationRequest, MedicationNotRequested, MedicationAdministration, MedicationNotAdministered, MedicationDispense, and MedicationNotDispensed)

Medication not ordered

Reviewed: 2023-07-11

NOTE: There is a known issue in the MedicationNotRequested profile definition in QICore STU 4.1.1 in that it incorrectly fixes the category to community. There is no current or planned work around in v4.1.1, as the issue has been resolved in QICore STU v5.0.0.

QICore 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 QICore 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.intent in { 'order', 'original-order', 'reflex-order', 'filler-order', 'instance-order' }

NOTE: Because intent is a modifier element in MedicationNotRequested, authors must consider all the possible values of the element to ensure the expression matches measure intent. The intent element can have values drawn from the Request Intent value set. In this case the query is asking for all orders, so the order code and all children are used.

NOTE: Because the MedicationNotRequested profile fixes the value of doNotPerform to true, that element does not need to be tested in the expression.

Medication administered

Reviewed 2023-03-07

QICore 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.

Medication not administered

Reviewed 2023-03-07

QICore defines the MedicationAdministrationNotDone profile to represent documentation of the reason a medication administration did not occur. By default, MedicationAdministrationNotDone resources in QICore 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

Reviewed 2023-03-07

QICore defines the MedicationDispense profile to represent the fulfillment of a medication request, either in a hospital or community pharmacy. By default, MedicationDispense resources in QICore are charaacterized by the medication element, which can be represented as a code or a reference.

define "Dementia Medication Dispensed":
  ["MedicationDispense": medication in "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.

Medication not dispensed

Reviewed 2023-03-07

QICore defines the MedicationDispenseNotDone profile to represent documentation of the reason that a dispense did not occur. By default, MedicationDispenseNotDone resources in QICore are characterized by the medication element, which can be represented as a code or a reference.

define "Dementia Medication Not Dispensed":
    ["MedicationDispenseNotDone": "Dementia Medications"] MedicationDispense
      where MedicationDispense.statusReason in "Medical Reason"
        or MedicationDispense.statusReason in "Patient Refusal"

NOTE: Because the MedicationDispenseNotDone profile fixes the value of the status element to declined, that element does not need to be tested in the expression.

Medication in use

TODO

Procedures

FHIR defines several procedure-related resources to support representing the proposal, planning, ordering, and performance of services and procedures for a patient.

Procedure performed

Reviewed 2023-03-09

QICore defines the Procedure profile to represent an in-progress or complete procedure for a patient. By default, Procedure resources in QICore 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.

Procedure not done

Reviewed 2023-03-09

QICore 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 QICore 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

Reviewed 2023-03-09

QICore defines the ServiceRequest profile to represent the proposal, planning, or ordering of a particular service. By default, ServiceRequest resources in QICore 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' }
      and DeviceOrdered.intent in { 'order', 'original-order', 'reflex-order', 'filler-order', 'instance-order' }
      and DeviceOrdered.doNotPerform is not true

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 intent is a modifier element in ServiceRequest, authors must consider all the possible values of the element to ensure the expression matches measure intent. The intent element can have values drawn from the Request Intent value set. In this case the query is asking for all orders, so the order code and all children are used.

NOTE: Because the ServiceRequest profile does not fix the value of the doNotPerform element, authors must consider the value of this element to ensure the expression matches measure intent. In this case, the doNotPerform element is tested to ensure it is not true. This phrasing is important in that it captures both the case that there is no value for the doNotPerform element, as well as when the value is specified as false.

Procedure not ordered

Reviewed 2023-03-09

QICore 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 QICore are characterized by the code element.

define "Intermittent Pneumatic Compression Devices Not Ordered":
  ["ServiceNotRequested": "Application of intermittent pneumatic compression devices (IPC)"] DeviceNotOrdered
    where DeviceNotOrdered.intent in { 'order', 'original-order', 'reflex-order', 'filler-order', 'instance-order' }
      and (DeviceNotOrdered.reasonRefused in "Medical Reason" or DeviceNotOrdered.reasonRefused in "Patient Refusal")

NOTE: Because intent is a modifier element in ServiceRequest, authors must consider all the possible values of the element to ensure the expression matches measure intent. The intent element can have values drawn from the Request Intent value set. In this case the query is asking for all orders, so the order code and all children are used.

NOTE: Because the ServiceNotRequested profile fixes the value of doNotPerform to true, that element does not need to be tested in the expression.

Devices

FHIR defines several resources related to the tracking and management of devices used by patients, including Device and DeviceRequest.

Device ordered

Reviewed 2023-03-14

QICore 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' }
      and FrailtyDeviceOrder.doNotPerform() is not true

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 the active, completed and on-hold statuses are used to ensure a positive device order.

NOTE: Because intent is a modifier element in DeviceRequest, authors must consider all the possible values of the element to ensure the expression matches measure intent. The intent element can have values drawn from the Request Intent value set. In this case the query is asking for all orders, so the order code and all children are used.

NOTE: Because the DeviceRequest profile does not fix the value of the doNotPerform element, authors must consider the value of this element to ensure the expression matches measure intent. In this case, the doNotPerform element is tested to ensure it is not true. This phrasing is important in that it captures both the case that there is no value for the doNotPerform element, as well as when the value is specified as false.

NOTE: The 4.1.1 version of this profile does not define doNotPerform as an allowable extension, so the QICoreCommon library includes a doNotPerform() function that accesses the modifier extension if it is present in the instance.

Device not ordered

Reviewed 2023-03-14

QICore 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 QICore are characterized by the code element, which can be represented as a code or a reference.

define "Venous Foot Pumps Not Ordered":
  ["DeviceNotRequested": "Venous Foot Pumps (VFP)"] DeviceNotOrdered
    where DeviceNotOrdered.intent in { 'order', 'original-order', 'reflex-order', 'filler-order', 'instance-order' }
      and (DeviceNotOrdered.doNotPerformReason in "Medical Reason" or DeviceNotOrdered.doNotPerformReason in "Patient Refusal")

NOTE: Because intent is a modifier element in DeviceNotRequested, authors must consider all the possible values of the element to ensure the expression matches measure intent. The intent element can have values drawn from the Request Intent value set. In this case the query is asking for all orders, so the order code and all children are used.

NOTE: Because the DeviceNotRequested profile fixes the value of doNotPerform to true, this element does not need to be tested in the expression.

Device in use

TODO

Allergies

FHIR defines the AllergyIntolerance resource to represent allergies and intolerances for a patient.

Current allergies

Reviewed 2023-03-07

QICore defines the AllergyIntolerance profile to represent allergies and intolerances for a patient. By default, AllergyIntolerance resources in QICore 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 or verificationStatus elements of the resource, authors must consider the possible values of these elements to ensure the expression matches measure intent. In this case, the clinicalStatus, if present, must be "allergy-active".

No known allergies

TODO

No evidence of a particular allergy

TODO

Immunizations

FHIR defines several immunization-related resources to track and manage the immunization information for a patient, including Immunization and ImmunizationRecommendation.

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?

Immunization performed

Reviewed 2023-03-09

QICore defines the Immunization profile to represent immunization information for a patient. By default, Immunization resources in QICore 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.

Immunization not performed

Reviewed 2023-03-09

QICore defines the ImmunizationNotDone profile to represent documentation of the reason an immunization was not performed. By default, ImmunizationNotDone resources in QICore 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 to not-done, this element does not need to be tested in the expression.

Immunization recommended

TODO

Communications

Communication

Reviewed 2023-03-09

QICore defines the Communication profile to represent communications with or about the patient. By default, Communication resources in QICore are characterized by the reasonCode element.

define "Macular Edema Absence Communicated":
  ["Communication": "Macular edema absent (situation)"] MacularEdemaAbsentCommunicated
    with "Office Visit Encounters" EncounterDiabeticRetinopathy
      such that MacularEdemaAbsentCommunicated.sent after start of EncounterDiabeticRetinopathy.period
    where MacularEdemaAbsentCommunication.status = 'completed'

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 Quality Measure IG.

Communication not done

Reviewed 2023-06-01

QICore defines the CommunicationNotDone to represent documentation of the reason a communication was not done. By default, CommunicationNotDone resources in QICore are characterized by the reasonCode element.

define "Reason for Macular Edema Absent Not Communicated":
  ["CommunicationNotDone": "Macular Edema Absent Findings"] MacularEdemaAbsentNotCommunicated
    with "Office Visit Encounters" EncounterDiabeticRetinopathy
      such that MacularEdemaAbsentNotCommunicated.sent during EncounterDiabeticRetinopathy.period
    where MacularEdemaAbsentNotCommunicated.statusReason in "Medical Reason"
        or MacularEdemaAbsentNotCommunicated.statusReason in "Patient Refusal"

NOTE: Because the CommunicationNotDone profile fixes the value of the status element to not-done, this element does not need to be tested in the expression.

NOTE: The positive counterpart for this statement (Macular Edema Absence Communicated) uses a direct-reference code, and ideally the negative statement would as well. However, at this time, direct-reference codes cannot be used as the terminology target of a retrieve of a negation profile. The workaround for this issue is to create a value set with the single required code and use the value set negation pattern.

Communication ordered

Wiki Index

Home

Authoring Patterns - QICore v4.1.1

Authoring Patterns - QICore v5.0.0

Authoring Patterns - QICore v6.0.0

Authoring Measures in CQL

Composite Measure Development

Cooking with CQL Examples

Cooking with CQL Q&A All Categories
Additional Q&A Examples

CQL 1.3 Impact Guidance

CQL Error Messages

Developers Introduction to CQL

Discussion Items

Example Measures

Formatting and Usage Topics

Formatting Conventions

Library Versioning

Negation in QDM

QDM Known Issues

Specific Occurrences

Specifying Population Criteria

Supplemental Data Elements

Terminology in CQL

Translator Options For Measure Development

Unions in CQL

Clone this wiki locally