This page is part of the Clinical Quality Language Specification (v2.0.0-ballot: R2 STU 1) based on FHIR (HL7® FHIR® Standard) R4. This version is a pre-release. The current official version is 1.5.3. For a full list of available versions, see the Directory of published versions
Page standards status: Informative | Maturity Level: N/A |
2.0 Change Log
Clinical Quality Language has been published as an HL7 and ANSI Normative standard since December of 2020. ANSI Normative standards must be reaffirmed every 5 years, so the time has come to reaffirm the specification. In addition, we have been steadily gathering implementer feedback and author feature requests over the years. There have been 2 errata publications where we have found issues that needed correction or clarification, but feedback and requests that are substantive in nature have had to wait for the next release. We have discussed, resolved, and applied that feedback to the specification, and will be balloting the proposed update in the September cycle.
As a result, there are two ballots for CQL in the September cycle.
Signup pools are still open through Thursday, August 7th.
This topic will provide an overview of the substantive changes to the specification proposed in the ballot.
Importantly, no breaking changes have been introduced in CQL R2.
Directives provide an ability for translator options to be provided as part of the language.
https://build.fhir.org/ig/HL7/cql/03-developersguide.html#directives
The first usage of directives is to provide a default comparison precision:
#DefaultComparisonPrecision: minutes
Means that all comparisons within the library that do not explicitly specify a precision will be performed to the minute.
#DefaultComparisonPrecision: minutes default included libraries
Means that this behavior will also be carried to included libraries that do not specify their own default comparison precision.
https://build.fhir.org/ig/HL7/cql/03-developersguide.html#defaultcomparisonprecision
CQL R2 introduces several enhancements to data model support.
Using statements can now include namespace qualifiers, allowing models to be referenced globally in the same way that libraries are.
using hl7.fhir.us.core.USCore
Using statements can now also include a called
clause, allowing multiple versions of the same model to referenced:
using hl7.fhir.us.core.USCore version '7.0.0' called USCore7
using hl7.fhir.us.core.USCore version '8.0.0' called USCore8
https://build.fhir.org/ig/HL7/cql/03-developersguide.html#data-models-1
In addition, the components of models can now be defined directly within CQL with the introduction of define type
, define context
, and define conversion
statements:
https://build.fhir.org/ig/HL7/cql/03-developersguide.html#defining-models
Type Definitions
CQL R2 includes support for defining named types with the new define type
statement:
define public type Quantity extends System.Any {
value System.Decimal,
unit System.String
}
Once defined in a library, these types function like any other type defined in a model brought in with a using statement, allowing authors to build data models directly in CQL.
https://build.fhir.org/ig/HL7/cql/03-developersguide.html#defining-class-types
Context Definitions
CQL R2 includes support for defining contexts with the new define context
statement:
define context Patient of type FHIR.Patient with key { id }
Once a context is defined, it can be used in a context statement like any context brought in with a using statement.
In addition, types can declare their relationship to contexts with the related to
clause of the define type
statement:
define type Observation extends DomainResource {
subject Patient,
code CodeableConcept,
value Choice<CodeableConcept, Quantity>
...
}
related to Patient by { subject }
https://build.fhir.org/ig/HL7/cql/03-developersguide.html#defining-contexts
Conversion Definitions
CQL R2 includes support for defining conversions with the new define conversion
statement:
define implicit conversion
from FHIR.Period to System.Interval<System.DateTime>
using FHIRHelpers.ToInterval
Once an implicit conversion is defined, it can be used to support implicit conversions like any other conversion brought in with a using statement.
Once an explicit conversion is defined, it can be referenced with the convert
function like any other conversion.
https://build.fhir.org/ig/HL7/cql/03-developersguide.html#defining-conversions
CQL R2 includes support for parameter constraints:
/*
@constraint: error
@message: Measurement period must be a year
*/
define IsYearly: start of "Measurement Period" same year as end of "Measurement Period"
These constraints are expressions that must evaluate to true in order to make use of any expressions within the library.
https://build.fhir.org/ig/HL7/cql/03-developersguide.html#parameter-constraints
CQL R2 also introduces support for parameter binding:
include ColorectalCancerElements called CCE
bind { AsOf: end of "Measurement Period" }
This example illustrates setting the AsOf
parameter in the ColorectalCancerElements
library to the end of "Measurement Period"
in the current library.
https://build.fhir.org/ig/HL7/cql/03-developersguide.html#parameter-binding
CQL R2 introduces support for equivalent contains, a contains operator that uses equivalent semantics, rather than equality semantics.
define "EquivalentContainsIsTrue": { 'A', 'B', 'C' } ~contains 'a'
define "EquivalentContainsIsFalse": { 'B', 'C' } ~contains 'a'
This support enables not only equivalent contains use cases like the above examples, but terminological contains as well:
define CodeSystemContainsExample: SNOMED ~contains "Random SNOMED Code"
define ValueSetContainsExample: "Inpatient Encounter" ~contains "Random CPT Code"
In addition to providing a generally useful operation, this is used in the retrieve later to enable an important set of use cases involving negation and direct-reference codes.
https://build.fhir.org/ig/HL7/cql/09-b-cqlreference.html#equivalentcontains
https://build.fhir.org/ig/HL7/cql/09-b-cqlreference.html#contains-codesystem
https://build.fhir.org/ig/HL7/cql/09-b-cqlreference.html#in-codesystem
CQL R2 introduced the equivalent in operator to clearly distinguish between equality- and equivalent-based membership:
define "EquivalentInIsTrue": 'a' ~in { 'A', 'B', 'C' }
define "EquivalentInIsFalse": 'a' ~in { 'B', 'C' }
And as with the ~contains operator, the terminological membership operators then make use of this new equivalent in:
define InCodeSystemExample: "Random SNOMED Code" ~in "SNOMED"
define InValueSetExample: "Random CPT Code" ~in "Inpatient Encounter"
For backwards compatibility, in
still resolves to the terminological membership operators, but using the new ~in
operator makes it explicit that equivalent in is being used.
https://build.fhir.org/ig/HL7/cql/09-b-cqlreference.html#equivalentin
https://build.fhir.org/ig/HL7/cql/09-b-cqlreference.html#in-codesystem
https://build.fhir.org/ig/HL7/cql/09-b-cqlreference.html#in-valueset
A significant outstanding issue with supporting the use of direct-reference codes throughout CQL is the negation patterns. When the extent of an activity is represented with a value set, rather than a specific code, then the negation statement looking for negation of a particular code requires the use of the new ~contains
operation. This can now be specified explicitly as in:
define "Reason for Macular Edema Absent Not Communicated (Explicit equivalent contains)":
[CommunicationNotDone: reasonCode ~contains "Macular edema absent (situation)"]
And this now means that direct-reference codes can be the target of a negation retrieve, such as:
define "Reason for Macular Edema Absent Not Communicated (Implicit equivalent contains)":
[CommunicationNotDone: "Macular edema absent (situation)"]
https://build.fhir.org/ig/HL7/cql/04-logicalspecification.html#codecomparator
CQL R2 adds the ability to round Quantity values:
define "QuantityRound": Round(2.54 'cm') // 2 'cm'
https://build.fhir.org/ig/HL7/cql/09-b-cqlreference.html#round
CQL R2 adds a MatchesFull function, which is a regex match that is required to match the entire string, as opposed to the Matches operation which by default uses partial matching.
define MatchesFullFalse: 'http://fhir.org/guides/cqf/common/Library/FHIR-ModelInfo|4.0.1'.matchesFull('Library') // returns false
define MatchesFullAlsoFalse: 'N8000123123'.matchesFull('N[0-9]{8}') // returns false as the string is not an 8 char number (it has 10)
define MatchesFullTrue: 'N8000123123'.matchesFull('N[0-9]{10}') // returns true as the string has an 10 number sequence in it starting with `N`
https://build.fhir.org/ig/HL7/cql/09-b-cqlreference.html#matchesfull
CQL R2 adds a Slice function that is a generalization of the Take, Skip, and Tail functions:
define SliceStart: Slice({ 1, 2, 3, 4, 5 }, 1) // { 2, 3, 4, 5 }
define SliceEnd: Slice({ 1, 2, 3, 4, 5 }, 1, 3) // { 2, 3 }
https://build.fhir.org/ig/HL7/cql/09-b-cqlreference.html#slice
In addition, CQL R2 incorporates updates made to FHIRPath as part of a ballot earlier this year. In that update, FHIRPath added support for several capabilities and functions that were already defined in CQL. This support was added to FHIRPath with the same semantics as CQL, and now this update to CQL R2 adds FHIRPath mappings for that functionality to ensure that we maintain alignment between the two specifications.
https://build.fhir.org/ig/HL7/cql/16-i-fhirpathtranslation.html