Skip to content

CQL 1.3 Impact Guidance

Peter Muir MD edited this page Sep 16, 2022 · 6 revisions

This topic discusses changes between the 1.2 and 1.3 versions of the specification and assessing the potential impact of those changes on existing CQL content. A high-level description of the changes can be found on the history page of the specification. There is also a detailed change log. Note that as of May 5 2022, the current release CQL version 1.5.1 is Normative Release 1 (mixed Normative/Trial-use content).

Ratio and Date Types

CQL 1.3 supports two new system-defined types, Ratio and Date. Ratios represent a relationship between two quantities, such as a titre (e.g. 1:128), or a concentration (e.g. 5 'mg':10'mL').

Impact Consider using these types for content that is naturally represented as a ratio or date.

Added difference of and duration between syntax

CQL 1.3 added support for difference of and duration between syntax. In CQL 1.2, duration as a keyword could only be applied to intervals, where difference could only be used with a between:

difference in days between DateTimeX and DateTimeY
duration in days of IntervalX

In CQL, the grammar was updated to allow difference and duration to be applied to intervals, as well as to date and time values using the between keyword:

difference in days of IntervalX
duration in days between DateTimeX and DateTimeY

Impact Consider using these new keywords to simplify expressions. For example difference in days between start of IntervalX and end of IntervalX can now be simplified to difference in days of IntervalX.

Relaxed quantity semantics

In CQL 1.2, invalid quantity arithmetic and comparison operations were defined to return an error at runtime (i.e. when the expression is evaluated):

3 'cm' + 12 's'

In 1.2, this expression would have resulted in a run-time error, but in 1.3, the semantics were relaxed to return null instead.

Impact Consider the impact of a quantity arithmetic or comparison operation returning null instead of throwing an error.

Exists now ignores null elements

In 1.2, exists was defined to return true for any non-empty list, even if the list only had null elements:

exists { null }

In 1.2, this expression would return true, but in 1.3, the exists operator was changed to ignore null elements, consistent with other aggregate operators such as Min, Max, and Count. The result is that if a list only contains null elements, exists will now return false.

Impact Because this behavior was surprising, the use of exists on a singleton list was an anti-pattern in CQL 1.2, so this will likely not be encountered. However, if it is encountered, the new behavior provides the intuitive result.

Implicit conversion from Integer or Decimal to Quantity

CQL 1.3 now supports implicit conversion from an Integer or Decimal to a Quantity:

2 + 5 'mg'

In 1.2, this expression would result in an error, but in 1.3, the Integer value (2) is implicitly converted to a quantity with a default unit of '1'.

Impact Consider simplifying expressions that add default units to values to convert them to quantities.

Equality semantics

In CQL 1.3, equality for types with components now returns null only if the values have different elements specified:

@2014 = @2014
@2014-01 = @2014

In 1.2, both these expressions would return null, on the grounds that since the values have unknown components, complete equality cannot be known. In 1.3, the first expression will return true, but the second expression will return null, because the values have difference components specified. Note that the previous behavior can still be achieved if necessary by performing the comparison at the millisecond precision:

@2014 same millisecond as @2014

This behavior is true for structured values as well:

{ id: 1, name: 'Joe', phone: null } = { id: 1, name: 'Joe', phone: null }
{ id: 2, name: 'John', phone: '123-4567' } = { id: 2, name: 'John', phone: null }

In 1.2, both these expressions would return null, again, on the grounds that since the values have unknown components, complete equality cannot be known. But in 1.3, the first expression will return true, but the second expression will return null, because the values have different components specified.

Impact Consider using equality (=) rather than equivalence (~) for some comparisons where equivalence was only used to avoid the possibility of a null when the values had the same set of components specified. This pattern is often used when comparing two structured values, such as two Encounters.

List membership and duplicate detection

In 1.3, list membership and duplicate detection now use equality rather than equivalence semantics:

null in { 1, null }

In 1.2, this expression would return true because null is equivalent (~) to null. But in 1.3, this expression will return null. Note that because equivalence for strings is defined to ignore case, this change impacts strings as well:

distinct { 'Adam', 'adam' }

In 1.2, this expression would have returned a list with only a single element, 'Adam'. But in 1.3, the values are considered unique and the expression will return both elements.

Impact Review usages of in and contains to consider what happens in the case that the element being searched for is null. Typically, this would have resulted in false, and so the change would have no impact.

Date and time equality and comparison semantics

In 1.3, Date and Time equality and comparison semantics were clarified:

Comparison is performed by considering each precision in order, beginning with years (or hours for time values). Comparison continues at each precision until:

  • A determination can be made (true or false)
  • A null is determined (one input has a value and the other does not)
  • Neither input has a value (in which case the result of the last precision is returned)
  • Or, the final precision has been reached (days or milliseconds)

In addition, symbolic comparison operators are now performed at the finest precision specified in either input:

@2012-01 >= @2012-01

In this example, the comparison proceeds to the month precision and then returns the result, true in this case.

@2012-01-01 >= @2012-01

In this example, however, the comparison proceeds to the day precision and returns null because only the first value has a day component.

If no precision is specified, comparison keywords are synonyms for the symbolic operators:

  • X same as Y is equivalent to X = Y
  • X before Y is equivalent to X < Y
  • X after Y is equivalent to X > Y
  • X same or before Y is equivalent to X <= Y
  • X same or after Y is equivalent to X >= Y

If precision is specified, comparison proceeds to that precision, even if neither input has a value for that precision:

@2012-01 same day as @2012-01

In this example, the comparison proceeds to the day precision, resulting in null.

Impact In general, this change will have very little impact, since the recommendation for CQL content includes specifying precision for date and time comparisons. In the case where no precision is specified, the new behavior will result in the expected comparison, only producing a null when values are specified to different levels of precision.

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