cqframework / cql-execution

A JavaScript framework for executing CQL
Apache License 2.0
63 stars 31 forks source link

TypeError: Cannot read property 'operand' of undefined #92

Closed ramanathanga closed 3 years ago

ramanathanga commented 5 years ago

Hi,

We are trying to setup CQL execution engine in our environment and faced issues during build and execution. We are trying to build and execute the sample age calculation program given in github.

OS : RHEL7.5

We did see several syntax error issues during cake build and now see following typeerror during executing java script.

[id>@<server lib]$ node age-exec.js /u13/DigitalMeasures/cql-execution-master/lib/elm/expression.js:12 if (json.operand != null) { ^

TypeError: Cannot read property 'operand' of undefined at new Expression (/u13/DigitalMeasures/cql-execution-master/lib/elm/expression.js:12:16) at new ParameterDef (/u13/DigitalMeasures/cql-execution-master/lib/elm/parameters.js:11:7) at new Library (/u13/DigitalMeasures/cql-execution-master/lib/elm/library.js:24:39) at Object. (/u13/DigitalMeasures/cql-execution-master/lib/age-exec.js:9:9) at Object. (/u13/DigitalMeasures/cql-execution-master/lib/age-exec.js:82:4) at Module._compile (internal/modules/cjs/loader.js:759:30) at Object.Module._extensions..js (internal/modules/cjs/loader.js:770:10) at Module.load (internal/modules/cjs/loader.js:628:32) at Function.Module._load (internal/modules/cjs/loader.js:555:12) at Function.Module.runMain (internal/modules/cjs/loader.js:822:10)

From stackoverflow, we see typeError is generally seen if props is not loaded correctly. Could you help us as this is the sample age calculation program given in your example and we are facing issues while executing.

https://stackoverflow.com/questions/53473858/nodejs-typeerror-cannot-read-property-name-of-undefined

FYI. Below are the modules installed globally until now for build

@babel babelify browserify coffeescript moment npm ucum.js

Thanks & Regards, Ganesh Ramanathan, Venkata Balaji Yadalla.

cmoesel commented 5 years ago

Hi @ramanathanga. Thanks for submitting this issue. We haven't run into this before, but it's been a while since I've tried installing and running everything from scratch. I'll take a shot at that and see if I can reproduce the issue. If I can reproduce it, I'll try to determine the solution. If I can't reproduce it, I'll send along the detailed steps I took to get it to work successfully.

Unfortunately, I may not have time to do this until tomorrow, but I wanted you to know that we're looking into it.

ramanathanga commented 5 years ago

Hi @ramanathanga. Thanks for submitting this issue. We haven't run into this before, but it's been a while since I've tried installing and running everything from scratch. I'll take a shot at that and see if I can reproduce the issue. If I can reproduce it, I'll try to determine the solution. If I can't reproduce it, I'll send along the detailed steps I took to get it to work successfully.

Unfortunately, I may not have time to do this until tomorrow, but I wanted you to know that we're looking into it.

Thank you for the response Chris.

cmoesel commented 5 years ago

It seems I'm not able to reproduce this. There should be only a few steps needed. See below for the full session of everything I did. I am running on MacOS, but did this on a volume with a Case-Sensitive File System (to ensure there weren't any issues w/ case sensitivity, since you are on linux).

CSFS  $ node --version
v12.3.1
CSFS  $ yarn --version
1.16.0
CSFS  $ coffee --version
CoffeeScript version 1.12.7
CSFS  $ git clone git@github.com:cqframework/cql-execution.git
Cloning into 'cql-execution'...
remote: Enumerating objects: 86, done.
remote: Counting objects: 100% (86/86), done.
remote: Compressing objects: 100% (68/68), done.
remote: Total 7341 (delta 28), reused 48 (delta 18), pack-reused 7255
Receiving objects: 100% (7341/7341), 5.58 MiB | 15.35 MiB/s, done.
Resolving deltas: 100% (5452/5452), done.
CSFS  $ cd cql-execution/
cql-execution (master) $ yarn install
yarn install v1.16.0
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...

$ ./node_modules/.bin/cake build && ./node_modules/.bin/cake build-cql4browsers
Completed transpiling src to lib, exit code 0
Completed transpiling test to lib-test, exit code 0
Browserifing cql4browsers...
Done! Output to ./src/example/browser/cql4browsers.js
✨  Done in 27.32s.
cql-execution (master) $ cd lib/example/
example (master) $ node exec-age.js
{
  "patientResults": {
    "1": {
      "Patient": {
        "json": {
          "id": "1",
          "meta": {
            "profile": [
              "patient-qicore-qicore-patient"
            ]
          },
          "resourceType": "Patient",
          "identifier": [
            {
              "value": "1"
            }
          ],
          "name": {
            "given": [
              "John"
            ],
            "family": [
              "Smith"
            ]
          },
          "gender": "M",
          "birthDate": "1980-02-17T06:15"
        },
        "_bundle": {
          "json": {
            "resourceType": "Bundle",
            "id": "example1",
            "meta": {
              "versionId": "1",
              "lastUpdated": "2014-08-18T01:43:30Z"
            },
            "base": "http://example.com/base",
            "entry": [
              {
                "resource": {
                  "id": "1",
                  "meta": {
                    "profile": [
                      "patient-qicore-qicore-patient"
                    ]
                  },
                  "resourceType": "Patient",
                  "identifier": [
                    {
                      "value": "1"
                    }
                  ],
                  "name": {
                    "given": [
                      "John"
                    ],
                    "family": [
                      "Smith"
                    ]
                  },
                  "gender": "M",
                  "birthDate": "1980-02-17T06:15"
                }
              }
            ]
          }
        }
      },
      "InDemographic": false
    },
    "2": {
      "Patient": {
        "json": {
          "id": "2",
          "meta": {
            "profile": [
              "patient-qicore-qicore-patient"
            ]
          },
          "resourceType": "Patient",
          "identifier": [
            {
              "value": "2"
            }
          ],
          "name": {
            "given": [
              "Sally"
            ],
            "family": [
              "Smith"
            ]
          },
          "gender": "F",
          "birthDate": "2007-08-02T11:47"
        },
        "_bundle": {
          "json": {
            "resourceType": "Bundle",
            "id": "example1",
            "meta": {
              "versionId": "1",
              "lastUpdated": "2014-08-18T01:43:30Z"
            },
            "base": "http://example.com/base",
            "entry": [
              {
                "resource": {
                  "id": "2",
                  "meta": {
                    "profile": [
                      "patient-qicore-qicore-patient"
                    ]
                  },
                  "resourceType": "Patient",
                  "identifier": [
                    {
                      "value": "2"
                    }
                  ],
                  "name": {
                    "given": [
                      "Sally"
                    ],
                    "family": [
                      "Smith"
                    ]
                  },
                  "gender": "F",
                  "birthDate": "2007-08-02T11:47"
                }
              }
            ]
          }
        }
      },
      "InDemographic": true
    }
  },
  "populationResults": {},
  "localIdPatientResultsMap": {
    "1": {
      "AgeAtMP": {}
    },
    "2": {
      "AgeAtMP": {}
    }
  }
}
example (master) $
cmoesel commented 5 years ago

I also just did the same thing using Node 8 (which I think may be what the documentation suggests). It worked for me with Node 8 as well. Perhaps you can try again just doing exactly the steps I did above? (Having installed Node and Yarn as a prerequisite; you may be able to skip installing coffee because I think yarn installs it locally).

cmoesel commented 5 years ago

That said, if you just need to use the execution engine as-is (without modifying its source code), you could just pull it in as a dependency into your own project. See https://github.com/cqframework/cql-exec-examples as an example.

ramanathanga commented 5 years ago

Thanks Chris for the responses, we have few questions.

1) Regarding Yarn, is that the Apache Hadoop Yarn (or) https://yarnpkg.com/en/ 2) Should the node, coffee, yarn installed Globally or locally? 3) Are separate modules required additionally like example below: @babel babelify browserify coffeescript moment npm ucum.js 4) What is the role of Yarn here? 5) Can this be scaled to cluster of servers for parallelism? 6) Is there a Release notes or a document that can explain steps to follow to install.

cmoesel commented 5 years ago

Hi Ganesh,

Regarding Yarn, is that the Apache Hadoop Yarn (or) https://yarnpkg.com/en/

The README.md contains the high-level installation requirements in the "Project Configuration" section near the top of the document. In those instructions, Yarn is linked to the correct Yarn project.

Should the node, coffee, yarn installed Globally or locally?

node and yarn -- yes. For coffee, there is a way to use it without globally installing it, but I think most of the documentation assumes it is installed.

Are separate modules required additionally like example below:

This is a node.js project. All of the required modules are listed in the package.json. They, and their own dependencies, will be installed to the project automatically when you run yarn install.

What is the role of Yarn here?

Yarn is a node.js package manager, similar to npm. It manages the project's dependency modules.

Can this be scaled to cluster of servers for parallelism?

This depends on your use case. For measures that use only Patient context, you should be able to run this on several servers in parallel and split your patients between the servers. Any measures that uses Population context, however, require all patients to be processed on the same server. Note that this project uses Node.js, which is single-threaded -- and this project uses only synchronous functions, so within a given process, patients are processed serially, one at a time. For large populations of patients, this means it may be a long-running process.

Is there a Release notes or a document that can explain steps to follow to install.

Within the project, we have brief install directions in the README. It's important to note, however, that this project alone doesn't have everything you need to execute eCQMs. For example:

As I noted in a previous answer, the cql-exec-examples shows how to use this project as a dependency instead -- and also shows how to use cql-exec-fhir for a FHIR-based PatientSource and cql-exec-vsac for a CodeService that use's NLM's VSAC as a terminology server.

If you're interested in executing CMS-based quality measures that use QDM, then you may want to check out the cqm-execution project, which is based on this project, but fine-tuned for executing QDM-based eCQMs.

Last, if you're using FHIR-based eCQMs, and if you're more familiar with Java than Node.js/CoffeeScript, then you may want to check out the Java CQL execution projects here: https://github.com/DBCG (and, in particular, cqf-ruler).

ramanathanga commented 5 years ago

Thank you for the responses Chris. We are reviewing the links. Meanwhile, regarding the execution process,

We see in the Github article that CQL is to be converted in to ELM. And then ELM (coffeescript or JSON?) is converted (build) to JS and executed using nodejs. Also, the patient source data is provided in the coffeescript file. Can we by-pass the CQL to ELM conversion step and directly use JSON files (provided by NCQA) and build them to JS and execute? Also, can we pass source context data here in JSON format? Is ELM (coffeescript) and JSON same?

cmoesel commented 5 years ago

We see in the Github article that CQL is to be converted in to ELM. And then ELM (coffeescript or JSON?) is converted (build) to JS and executed using nodejs.

CQL is the author-friendly representation of the clinical logic. ELM is the machine-friendly translation of the CQL. There is a Java project that can translate CQL to ELM. ELM is typically represented as JSON or XML. In this project we sometimes store it in a .coffee file, but even then it is just JSON embedded and exported in a .coffee file. For your purposes, I think the standard JSON representation will work. The cql-execution library accepts the ELM JSON and executes directly on it.

Also, the patient source data is provided in the coffeescript file.

In some of our examples and tests, we put fake patient data into .coffee files because it's easier to load it as static data that way. But I don't recommend using the patient source libraries that are in cql-execution. They are for testing and proof-of-concept purposes only. In the real world, depending on what data model your CQL uses and how you store your own data, you'll need to either use one of the existing PatientSource implementations (outside of cql-execution) or create one of your own. In my links above you'll find PatientSource implementations for FHIR and for QDM.

Can we by-pass the CQL to ELM conversion step and directly use JSON files (provided by NCQA) and build them to JS and execute?

Yes, if you already have JSON ELM from NCQA, you should be able to just use that with the CQL execution engine. The author-friendly CQL representation is not used by the CQL execution engine (although you might find it helpful just to get a better understanding of what logic the ELM represents).

Also, can we pass source context data here in JSON format?

I'm not sure what you mean by "source context data".

Is ELM (coffeescript) and JSON same?

They're very similar. ELM CoffeeScript is just a wrapper around the JSON that exposes it as a library whose static value is the ELM JSON. You really should not need ELM CoffeeScript at all.

ramanathanga commented 5 years ago

Thanks for your responses Chris.

1) Is there a way to convert QDM-based eCQMs to FHIR-based eCQMs. We have access to 6 measures that was released by NCQA but they seem to be QDM based. Code snippet below for reference.

A code snippet of first few lines from AdultImmunizationStatus-0.0.016.cql

library AdultImmunizationStatus version '0.0.016'

using QDM version '5.3'

include NCQA_Common version '3.9.000' called Common

2) Would you be able to tell us what's the preferred standard QDM or FHIR?

3) We are looking in to examples, but would you be able to guide us on how to pass a JSON data as a external file to the age-exec.coffee instead of inline data?

p9g commented 5 years ago

See http://build.fhir.org/ig/cqframework/qi-core/qdm-to-qicore.html and some examples done manually at https://github.com/cqframework/draft-measures/tree/master/pages/cql

cmoesel commented 5 years ago

Thanks @p9g for the excellent links. Those are really helpful resources!

@ramanathanga, I'll try to answer your questions one-by-one below:

  1. Is there a way to convert QDM-based eCQMs to FHIR-based eCQMs. We have access to 6 measures that was released by NCQA but they seem to be QDM based.

I'm not aware of any automated approach to converting QDM measures to FHIR measures, but you can use the first link that @p9g posted to translate them manually. It's also possible that some of the NCQA measures already have draft conversions to FHIR; so you should check the 2nd link that @p9g posted too.

That said, you should probably confirm w/ NCQA that it's OK to use FHIR versions of the measures rather than process the QDM ones.

If you have the patient data as FHIR, but need to support the QDM measures directly, I suppose another option would be to develop your own QDM-based data model implementation that has code that does the translation from the QDM data model to FHIR using that first link above. But that might be pretty difficult.

  1. Would you be able to tell us what's the preferred standard QDM or FHIR?

I guess that probably depends on who you ask! It also depends on how/why you're doing measures in the first place. If you need to support CMS's quality reporting and/or value-based purchasing programs, then those measures are currently specified using QDM-based CQL. See the eCQI Resource Center for more information.

If you're building your own measures, then you can choose either QDM or FHIR-based CQL depending on what you're more comfortable with.

If you're interested in Clinical Decision Support (CDS), most CQL-based CDS logic is written using the FHIR data model.

  1. We are looking in to examples, but would you be able to guide us on how to pass a JSON data as a external file to the age-exec.coffee instead of inline data?

I'm not sure if we have any examples in coffeescript, but one approach would be to simply put the JSON patient data into a patient-data.json file, and then require it (e.g., patientData = require './patient-data'). Once you do that, you could pass the patientData variable into the cq.PatientSource constructor.

If you don't want to use require, you could use the Node.js fs module and JSON.parse(...) to read and parse the file as JSON.

The cql-exec-examples project I pointed you to before also has some examples of loading patient data from files for use with the cql-exec-fhir data source. For example: https://github.com/cqframework/cql-exec-examples/blob/master/diabetic-foot-exam/runner.js#L43-L52

Hope that helps!

ramanathanga commented 5 years ago

Thanks for the responses Chris and Paul.

We were successfully able to pass data from a file instead of inline and were able to successfully obtain output creating and running age-exec.js. We understand that age-exec-js is based on QUICK/FHIR based input. As a next step we are trying to execute AdultImmunizationStatus-0.0.016.cql (AIS Measure) using an example patient. Since AIS Measure cql (and other released NCQA measures) are based on QDM (not FHIR), 1) We are trying to get a QDM based Patient data sample that would work with AIS Measure CQL, can you pls. share if any. 2) Is there a CQL execution github project based on QDM (since this GitHub CQL execution framework project is FHIR based).

Snippet of coffee script to execute the AIS measure:

[s01@server src]$ cat AIS-exec.coffee
#!/usr/bin/env coffee

cql = require './cql'
measure = require './AdultImmunizationStatus-0.0.016'
fs = require 'fs'

lib = new cql.Library(measure)
executor = new cql.Executor(lib)
psource = new cql.PatientSource(JSON.parse(fs.readFileSync('/midnas01/userhomedir/s01/node_modules/cqm-execution/spec/fixtures/json/patients/CMS107v6/IPPFail_LOS=121Days.json')))
result = executor.exec(psource)
console.log JSON.stringify(result, undefined, 2) 

Below is the Snippet of error we are seeing because CQL libraries expect FHIR bundles:

[s01@server lib]$ node AIS-exec.js
/midnas01/userhomedir/s01/cql-execution-master/lib/cql-patient.js:126
    filtered = this.entry().filter(function(e) {
                           ^

TypeError: Cannot read property 'filter' of undefined
    at Bundle.FHIR.Bundle.findRecords (/midnas01/userhomedir/s01/cql-execution-master/lib/cql-patient.js:126:28)
    at Bundle.FHIR.Bundle.findRecord (/midnas01/userhomedir/s01/cql-execution-master/lib/cql-patient.js:141:17)
    at PatientSource.nextPatient (/midnas01/userhomedir/s01/cql-execution-master/lib/cql-patient.js:239:79)
    at new PatientSource (/midnas01/userhomedir/s01/cql-execution-master/lib/cql-patient.js:228:12)
    at Object.<anonymous> (/midnas01/userhomedir/s01/cql-execution-master/lib/AIS-exec.js:15:13)
    at Object.<anonymous> (/midnas01/userhomedir/s01/cql-execution-master/lib/AIS-exec.js:21:4)
    at Module._compile (module.js:653:30)
    at Object.Module._extensions..js (module.js:664:10)
    at Module.load (module.js:566:32)
    at tryModuleLoad (module.js:506:12) 

Thanks.

cmoesel commented 5 years ago

Hi @ramanathanga. I don't have any examples of QDM-based patients, but I recommend you check out the cqm-execution project: https://github.com/projecttacoma/cqm-execution

The cqm-execution project is based on cql-execution, but specialized for executing QDM-based eCQMs. If you look in their specs folder, it has example measures and patients. The README also shows how to execute one of those test measures with test patients.

cmoesel commented 3 years ago

Closing as "answered".