FHIR Chat · Using CQL execution framework to evaluate FHIR constraints · cql

Stream: cql

Topic: Using CQL execution framework to evaluate FHIR constraints


view this post on Zulip Kevin Olbrich (Jan 21 2018 at 01:44):

In theory it should be possible to generate code that reflects the constraints on resources as defined in the FHIR definition files. According to the documentation, the expressions are defined in FHIRPath, which is itself a subset of CQL. What I would like to do is use the CQL-to-ELM translator to generate an ELM tree for each of the constraints and then use that tree to generate code in a target language. By doing this we can automate code generation and make sure that it actually matches the definitions as much as possible. Has anyone tried this? Is this possible? Am I wasting my time?

view this post on Zulip Grahame Grieve (Jan 21 2018 at 03:08):

The build tool parses them all to an ast, and evaluates them, but doesn’t do any code generation. I don’t know of anyone who has done that. Btw, you can use the java ast if you want (if you’re using java)

view this post on Zulip Kevin Olbrich (Jan 21 2018 at 08:26):

@Grahame Grieve can you point me at the code the build tool uses to parse the constraints?

view this post on Zulip Grahame Grieve (Jan 21 2018 at 08:50):

org.hl7.fhir.r4.model.ExpressionNode and org.hl7.fhir.r4.utils.FHIRPathEngine

view this post on Zulip Kevin Olbrich (Jan 21 2018 at 22:37):

Weird... there are constraints that look like this hasValue() | (children().count() > id.count()) all over the place, but I can't find a definition of hasValue() in the FHIRPath specification (http://hl7.org/fhirpath/).

view this post on Zulip Grahame Grieve (Jan 21 2018 at 22:53):

hmm. that's something we haven't quite figured out; it's technically a feature of the primitive types in FHIR

view this post on Zulip Kevin Olbrich (Jan 21 2018 at 22:55):

So is hasValue() really just checking to see if the Element is a primitive?

view this post on Zulip Grahame Grieve (Jan 21 2018 at 22:57):

no. better to explain it in terms of an element

view this post on Zulip Grahame Grieve (Jan 21 2018 at 22:57):

<status value="active"/>

view this post on Zulip Grahame Grieve (Jan 21 2018 at 22:57):

hasValue() == true

view this post on Zulip Grahame Grieve (Jan 21 2018 at 22:57):

<status><extension url="balh"><valueCode value="blah"/></extension/></status>

view this post on Zulip Grahame Grieve (Jan 21 2018 at 22:58):

hasValue() == false

view this post on Zulip Kevin Olbrich (Jan 21 2018 at 23:34):

I see, there are a few things that aren't primitives, but do have a value.

view this post on Zulip Kevin Olbrich (Jan 21 2018 at 23:39):

What would hasValue() evaluate to for <extension url="foo"><valueCode="bar"/></extension>?

view this post on Zulip Kevin Olbrich (Jan 21 2018 at 23:58):

Shouldn't that constraint be something like hasValue() or (children().count() > 0)? What does the id.count() have to do with it?

view this post on Zulip Grahame Grieve (Jan 22 2018 at 01:35):

hasValue() returns null on Extension because it's not a primitive

view this post on Zulip Grahame Grieve (Jan 22 2018 at 01:35):

what's the context of this constraint?

view this post on Zulip Kevin Olbrich (Jan 22 2018 at 04:53):

I'm talking about the ele-1 constraint from Element (hasValue() | (children().count() > id.count())). It's not clear to me why children().count() > id.count() is used instead of children().count() > 0.

view this post on Zulip Grahame Grieve (Jan 22 2018 at 04:55):

oh because it can have an id but that doesn't as content. So there must be at least one more child than the the count of id (which will be 0 or 1)

view this post on Zulip Kevin Olbrich (Jan 22 2018 at 15:06):

@Bryn Rhodes so if I wanted to use the cql-to-elm translator to generate an ELM tree for the ele-1 constraint, how would I go about doing it? --- (BTW... it took longer than I care to admit for me to realize that the ELM here is not the elm programming language)

view this post on Zulip Bryn Rhodes (Jan 22 2018 at 20:28):

Simplest way would be to take the ele-1 constraint and put it in a .cql file and call the command-line translator on it. There's context though, so you would need to set up a library to express the definition, something like this:

view this post on Zulip Bryn Rhodes (Jan 22 2018 at 20:29):

library "ele-1" using FHIR version '3.0.0' parameter Context Patient define Constraint: <content of the ele-1 constraint>

view this post on Zulip Kevin Olbrich (Jan 22 2018 at 20:53):

I'll give that a try, thanks!

view this post on Zulip Kevin Olbrich (Jan 22 2018 at 21:03):

if I send this...

library "ele-1"

using FHIR version '3.0.0'
parameter Context Patient
define Constraint:
    hasValue() | (children().count() > id.count())

To the cql-to-elm translator docker container I get this in response...

{
    "library": {
        "annotation": [
            {
                "startLine": 6,
                "startChar": 2,
                "endLine": 6,
                "endChar": 11,
                "message": "Could not resolve call to operator hasValue with signature ().",
                "errorType": "semantic",
                "errorSeverity": "error",
                "type": "CqlToElmError"
            }
        ],
        "identifier": {
            "id": "ele-1"
        },
        "schemaIdentifier": {
            "id": "urn:hl7-org:elm",
            "version": "r1"
        },
        "usings": {
            "def": [
                {
                    "localIdentifier": "System",
                    "uri": "urn:hl7-org:elm-types:r1"
                },
                {
                    "localId": "1",
                    "localIdentifier": "FHIR",
                    "uri": "http://hl7.org/fhir",
                    "version": "3.0.0"
                }
            ]
        },
        "parameters": {
            "def": [
                {
                    "localId": "3",
                    "name": "Context",
                    "accessLevel": "Public",
                    "parameterTypeSpecifier": {
                        "localId": "2",
                        "name": "{http://hl7.org/fhir}Patient",
                        "type": "NamedTypeSpecifier"
                    }
                }
            ]
        },
        "statements": {...

view this post on Zulip Kevin Olbrich (Jan 23 2018 at 16:14):

@Bryn Rhodes looks like this doesn't work as expected. Any idea how to correct this? It seems like I'm just missing some definitions, but I have no idea where to find them.

view this post on Zulip Bryn Rhodes (Jan 23 2018 at 16:23):

Since it is a constraint, it needs to be evaluated in the context of the definition, so it needs a bit more setup:

view this post on Zulip Bryn Rhodes (Jan 23 2018 at 16:28):

I'll log this as an issue and get it running in the translator. hasValue() in particular it looks like is missing, I may need to add that to FHIR Helpers.

view this post on Zulip Kevin Olbrich (Jan 23 2018 at 16:28):

Awesome! Thanks!


Last updated: Apr 12 2022 at 19:14 UTC