-
Notifications
You must be signed in to change notification settings - Fork 24
CQL 1.3 Impact Guidance
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).
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.
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
.
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.
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.
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.
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.
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.
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
orfalse
)- 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 toX = Y
-
X before Y
is equivalent toX < Y
-
X after Y
is equivalent toX > Y
-
X same or before Y
is equivalent toX <= Y
-
X same or after Y
is equivalent toX >= 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.
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