cqframework / cql-engine

Clinical Quality Language Evaluation Engine

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Translator wraps argument in ToList or not based on unconnected define

duncand opened this issue · comments

See the following CQL, which is partially defined by external functions.

define Sources: List { 'x', 'y' }
define Results1: Sources s return f1(s)
define function f1(s String) returns Any: external
define Results2: Sources s return f2(s)
define function f2(s String) returns Any: Tuple { a1: f3(s) }
define function f3(s String) returns Any: external
define Validation: Equivalent(Results1, Results2)
define ResultsPaired: Sources s return Tuple { LHS: f1(s), RHS: f2(s) }
define Diffs: ResultsPaired p where not Equivalent(p.LHS, p.RHS)

In this example, Results1 and Results2 would have the same value, a 2 element List where each list item is a Tuple. The functions f1() and f2() would each result in a Tuple, and f3() would result in a String.

Having the same value, Results1 and Results2 should compare as equal whether they are compared either as a whole List (via Validation) or element-wise per each corresponding Tuple (via Diffs). But in fact when evaluating this CQL, Validation correctly says the Results match while Diffs incorrectly reports that the tuples of Results do NOT match, these being contradictory answers.

Now, as a modification, alter the Validation line so it uses Equal() rather than Equivalent(), or alternately just comment-out the Validation line entirely.

With that change to Validation, Diffs inexplicably gives a different answer, saying that there are no mismatching Tuple in Results, and giving the correct answer.

So changing Validation causes Diffs to give different answers, even though nothing else is defined in terms of Validation.

The problem turns out to be that the Translator is producing different ELM for Diffs depending on whether or not another Equivalent() call exists further up in the same CQL.

This is the incorrect ELM output when the Validation line does exist:

            <where xsi:type="Not">
               <operand xsi:type="Equivalent">
                  <operand xsi:type="As">
                     <operand path="LHS" scope="p" xsi:type="Property"/>
                     <asTypeSpecifier xsi:type="ListTypeSpecifier">
                        <elementType name="t:Any" xsi:type="NamedTypeSpecifier"/>
                     </asTypeSpecifier>
                  </operand>
                  <operand xsi:type="ToList">
                     <operand path="RHS" scope="p" xsi:type="Property"/>
                  </operand>
               </operand>
            </where>

While this is the correct ELM output when the Validation line doesn't exist:

            <where xsi:type="Not">
               <operand xsi:type="Equivalent">
                  <operand path="LHS" scope="p" xsi:type="Property"/>
                  <operand path="RHS" scope="p" xsi:type="Property"/>
               </operand>
            </where>

So the Translator is inconsistently either wrapping or not wrapping the RHS argument in a ToList(), even though the definition of Diffs is unchanged between the cases, and the Engine is not giving the same answers as a result.

Fundamentally, this is a Translator problem, since unconnected code should not be affecting how other code translates.

This is a translator issue, would need to be reported there.