CQL¶
Clinical Quality Language is how clinical criteria are expressed against this specification: the population logic behind a report, a cohort, or a decision-support rule. One language, so a criterion written once means the same thing whether it is evaluated for one patient at the point of care or for a whole panel in a report.
This page is the contract for authoring against this IG rather than against base FHIR.
The model¶
A CQL library compiled against the stock FHIR R4 model can only see base R4. A retrieve
written [Observation: "HbA1c"] resolves to base Observation, and anything derived from it
names http://hl7.org/fhir/StructureDefinition/Observation. Criteria written that way are not
bound to this specification at all: they cannot see its profiles, its slices or its extensions.
This IG therefore publishes its own CQL model definition, generated from its profiles. Declare it at the top of a library:
using Nexus version '1.26.0'
Each type in the model is one profile. Retrieves then carry the profile's canonical, so a criterion's declared data requirements name this specification's profiles:
define "Latest HbA1c":
Last([NexusEmrCoreObservation: "HbA1c"] O
sort by (effective as FHIR.dateTime).value)
The primary code path¶
[SomeType: "a-code"] is the natural way to filter a retrieve by code, and it works only when
the type declares which element the code applies to — its primary code path. For most
resources base FHIR already declares one (Observation.code, Encounter.type,
MedicationRequest.medication). For some it declares none, and the consequence is not a
compile error.
A bare code filter on a type with no primary code path is not an error
It compiles. The translator emits a warning, the retrieve is left filtering on nothing
determinable, and the data requirements derived from it carry a code filter with no path
— which is invalid against FHIR's own drq-1 invariant. Nothing fails.
Tooling for this IG treats that warning as an error. If you are using other tooling, name the element explicitly and the question does not arise:
[NexusEmrCoreFamilyMemberHistory: condition.code in "Colorectal Cancer"]
This specification declares a primary code path on the profiles below, using HL7's
cqf-modelInfo-primaryCodePath
extension. Base FHIR declares none for any of these resources, so a bare code filter on them
works only against this IG's model.
| Profile | Resource | Primary code path |
|---|---|---|
| DocumentReference | DocumentReference |
type |
| Invoice | Invoice |
type |
| Schedule | Schedule |
serviceType |
| Slot | Slot |
serviceType |
A profile that is absent from this table and has no base-FHIR code path is absent on
purpose. FamilyMemberHistory is the instructive case: its only required coded element is
relationship (mother, father), and a criterion about family history means condition.code.
Declaring relationship would make the natural authoring form compile, run, and match the
wrong element — worse than declaring nothing, because it would appear to work.
Data requirements¶
Static analysis of a criteria library yields a second artifact: a Library with
type = module-definition, declaring the resource types it reads, the code and value-set
filters it applies, and the elements it touches. It is derived from the logic, never
authored beside it, so it cannot drift from what the criteria actually do.
That manifest is what makes a cohort cheap to keep current: intersect what changed with what each cohort declares it depends on, and re-evaluate only the affected ones. It also distinguishes criteria whose membership changes by pure passage of time ("no visit in six months") from criteria anchored to another event ("two results ninety days apart") — only the first needs re-checking when nothing has happened.
Units¶
Quantity comparisons carry units, and unit conversion is not always safe to infer. UCUM
converts 55 mmol/mol to 5.5 % because both are dimensionless ratios; for HbA1c that is
wrong by nearly two points, because IFCC and NGSP are related by an affine formula rather
than a ratio. Conversions that genuinely cannot be inferred — creatinine in umol/L against
a threshold in mg/dL, which needs a molecular weight — are correctly refused.
Criteria over a measurement should therefore state the unit they mean rather than assume one.