cqframework / clinical_quality_language

Clinical Quality Language (CQL) is an HL7 specification for the expression of clinical knowledge that can be used within both the Clinical Decision Support (CDS) and Clinical Quality Measurement (CQM) domains. This repository contains complementary tooling in support of that specification.
https://confluence.hl7.org/display/CDS/Clinical+Quality+Language
Apache License 2.0
258 stars 120 forks source link

Includes Bug #151

Closed cmoesel closed 7 years ago

cmoesel commented 7 years ago

The includes operator is generally defined for lists and intervals. In some cases, a non-list item may be promoted to a list during CQL-to-ELM translation.

There is at least one case, however, where this promotion is not occurring, and CQL-to-ELM produces ELM that allows the includes operator to be executed on a single item that is not an interval or list (and is not promoted). This happens when using a tuple returned from a multi-source query.

Example CQL:

library multisource_example

// The below multi-source query should return a list of tuples like this:
// { Odd: 1, Even: 2 },
// { Odd: 1, Even: 4 },
// { Odd: 3, Even: 2 },
// { Odd: 3, Even: 4 }
//
// This is because a multi-source query returns a cartesion product (as described in the spec).
define oddsAndEvens:
  from (List{1, 3}) Odd, (List{2, 4}) Even

// Since the value of Odd in each tuple is an integer (not a list), it should be promoted
// to a list, or CQL-to-ELM should produce an error.  But... it goes through unscathed!
define shouldNotBeAllowed:
  (oddsAndEvens) OE where OE.Odd includes 3

This produces ELM containing this snippet:

<def name="shouldNotBeAllowed" context="Patient" accessLevel="Public">
  <expression xsi:type="Query">
    <source alias="OE">
      <expression name="oddsAndEvens" xsi:type="ExpressionRef"/>
    </source>
    <where xsi:type="Contains">
      <operand path="Odd" scope="OE" xsi:type="Property"/>
      <operand valueType="t:Integer" value="3" xsi:type="Literal"/>
    </where>
  </expression>
</def>

In reality, the Odd property on OE is an Integer, so it is not valid as the first operand in Contains.

@mulcahyk has identified at least one eCQM that triggers this bug. As a result of the invalid Contains operator in the ELM, that measure cannot be properly executed.

mulcahyk commented 7 years ago

Here is the eCQM that causes this issue: CMS146_v5_2_Artifacts.zip

brynrhodes commented 7 years ago

The problem is that the result type of the tuple was being incorrectly inferred by the translator. Odd and Even were being incorrectly considered Lists of Integers, which is why no error or list promotion was occurring. I corrected the type inference so that Odd and Even are now correctly integers, and the list promotion is now occurring as expected.

cmoesel commented 7 years ago

I've tested it and merged it. Thanks!

For those using the CoffeeScript execution engine (@mulcahyk), note that it will still not handle this fix well. This fix uses the CQL-to-ELM promotion feature to promote the single value to a list (containing only the single value). It uses the ToList operator, which is not yet implemented in the CoffeeScript CQL execution engine. So... that will need to be added.