-
Notifications
You must be signed in to change notification settings - Fork 5
User Guide
The CQFramework Clinical Quality Language VSCode Extension adds syntax highlighting, semantic (error) highlighting, and local execution for HL7 Clinical Quality Language (CQL) to Visual Studio Code
To install Visual Studio Code, visit https://code.visualstudio.com and follow the download instructions appropriate for your platform.
The cqframework.cql extension has been published to the VS Code Marketplace, so the installation is simple. Just search for "Clinical Quality Language" in the marketplace and install the extension:
The extension will be activated once you open any file with the .cql
extension in the editor. Note that the extension will download the CQL Language Server, which may take a while. During the download, the status is displayed in the lower-right corner of the VSCode environment.
In addition, this extension requires Java to be installed. It'll prompt you to install Java if required.
Download and unzip vscodeTest.zip to a local drive. In VSCode, use 'Open Folder', open the /vscodeTest directory. This should also open a panel on the left hand side called 'Explorer'. Select the /input/cql/HelloWorld.cql file, which should display on the right hand side. Select the CQL file on right, right mouse click, 'Execute CQL' option. This should cause a new HelloWorld.txt file to be generated, which should contain "HelloWorld=Your CQL extension works if you see this text in the output HelloWorld.TXT file". If you see that output being generated your CQL extension has been installed correctly and is up and working.
If not: please ensure you have the latest version of VSCode and Java. Please check your PATH environment variables. Should these not correctly refer to the \Java\javapath directory the CQL extension won't work.
The plugin provides syntax highlighting for CQL:
To see the result type of any expression, hover over the expression with the mouse:
Errors in the CQL are highlighted using a red underline. To see the error message, hover over the underlined CQL and the error message will display:
Warnings in the CQL (i.e. messages that indicate something may be wrong or unexpected with the CQL but doesn't necessarily mean an error) are highlighted using a yellow underline. Again, to see the warning message, hover over the underlined CQL and the warning message will display:
The plugin supports execution of CQL, right-click anywhere in the CQL editor and select Execute CQL
from the menu:
Note that the plugin relies on the name of the library, so the filename and CQL library declaration name must match. In the above example, the file is named Simple.cql
and the library name is Simple
.
Executing the CQL will open a new editor on a file with the library name and a .txt
extension, logging the results of the evaluation. Every top-level expression in the library is evaluated and the results are added to the evaluation log:
In addition, any messages generated by the execution are output to the log. Note that not all messages are errors, the evaluation may result in information, warning, and other messages that don't necessarily mean the evaluation failed. Check for the keyword ERROR:
at the beginning of the message to make sure an error has occurred, rather than just a warning or informational message produced by the evaluation.
The plugin also supports vocabulary and data access as part of execution, see the Adding Vocabulary and Adding Test Data topics below for more information on these features.
CQL is translated into a machine-friendly format called Expression Logical Model or ELM. Most engines that run CQL are processing ELM to perform the actual evaluation. To see the ELM output for a given CQL file, right-click anywhere in the CQL editor and select View ELM
:
The plugin will open a new editor with the ELM output as XML:
This feature is useful mainly as a tool for helping understand what an engine is doing or when debugging an unexpected result or error.
The translation and execution capabilities in the plugin expect CQL files to be in the following directories, by convention:
input/cql
input/tests
input/tests/<cql-library-name>
input/tests/<cql-library-name>/<patient-id>
input/tests/<cql-library-name>/<patient-id>/<resource-type-name>/<resource files> // flexible structure
input/vocabulary/codesystem
input/vocabulary/valueset
Within the tests folder, there is a folder for each CQL library, by name (note that the name of the file must match the name of the library in order for the evaluator to properly execute the CQL). Note also that the evaluator is a separate subsystem from the translator, so it will read whatever is current on disk, so be sure to save before executing.
Within the library folder, there is a folder for each "test case", in the form of a Patient (the execution only supports patient context execution at this point). The folder must have the same id as the patient (that's how the evaluator knows what the patient id is).
Within each test case folder are the resources for that specific test case. The resource files can be provided either directly in this folder, or they can be organized into folders by resource type name. Whether they are in the test folder or in subfolders, resources can be provided as bundles (included nested bundles), or as separate files, and in either XML or JSON format. If a Patient is provided, the id element of the Patient resource must match the name of the test case folder. Resource file names are expected to follow the convention <id>.(json|xml)
(when in a resource-specific folder) or <ResourceType>-<id>.(json|xml)
, for example Patient-123.json
.
NOTE: As of the 0.7.3 release of the VSCode plugin, test case resources can no longer be provided as bundles, each resource must be in a separate file in order for it to be recognized by the plugin. This change was made to accommodate future capabilities for supporting test case authoring and updating, making it easier for the plugin to identify where resource contents should be updated.
Refer to the Adding a Test Case topic below for more information.
NOTE: The plugin will actually search any subfolders of the
input/tests
folder, looking for the first match of a folder with the library name being tested. This allows for flexible organization of tests to match intent, for example, there may belibrary
tests organized under a library folder, andmeasure
tests organized under a measure folder. However, when this feature is used, the plugin will use the first folder it finds that matches the library name, regardless of how nested the folder structure is.
The plugin can make use of an options file to support setting compiler and run-time options for the plugin. These options are read from a file named cql-options.json
in the input/cql
folder. Here is an example cql-options file with typical defaults for common options:
{
"options":[
"EnableAnnotations",
"EnableLocators",
"DisableListDemotion",
"DisableListPromotion"
],
"formats":[
"XML",
"JSON"
],
"validateUnits":true,
"verifyOnly":false,
"errorLevel":"Info",
"signatureLevel":"None",
"analyzeDataRequirements":false,
"collapseDataRequirements":true
}
For a complete description of the available options, refer to the Usage topic in the CQL-to-ELM translator documentation.
To support collaboration among multiple authors, Visual Studio Code has built-in support for using Github. To use Github, you will need a Github account, it's free and can be associated with your favorite identity provider if you want. Once you have a github account, go to the Source Control tab in Visual Studio Code and select "Clone a repository":
In the popup that displays select Clone from github
:
Type in the Github organization and repository you want to clone (e.g. cqframework/cqf-ccc
), then select the repository in the dropdown:
Choose a folder locally where you want to clone the repository and click Select a Repository Destination
:
VSCode will prompt you whether you want to open the newly cloned repository:
VSCode will then prompt for whether you trust the authors of the repository. Select Yes, I trust the authors
. You can optionally select the checkbox to Trust the authors of all files in the parent folder
, that way other repositories you clone from this same organization will already be trusted.
You are now taken to the main VSCode folder explorer interface. On the left-hand side you will see a listing of the files and folders in the repository:
In the explorer view, navigate to the input/cql
folder to see all the CQL files in the repository. Click on the CQL file you want to open:
Make some changes to the CQL library (in this case we've added a comment to the expression). Then save the changes and the editor will indicate where the changed lines are in the file, and the explorer will indicate that the file is modified:
These changes are only in your local clone of the repository at this point, so they are visible only to you.
To commit these changes back to the github repository, select the Source Control icon on the left side of VSCode:
Provide a message describing the changes, and select the +
icon next to the list of changes to Stage All Changes
:
Once the changes you want to commit back to the repository are staged, pull down the arrow on the Commit button and select Commit and Push
:
This will commit the changes directly back to the main branch of the repository.
NOTE: This process requires write access to the repository. Contact the repository administrator to ensure you have privileges to write.
NOTE: Many repositories require the use of a Pull Request to commit changes to the main branch of the repository. There is an extension (github.vscode-pull-request-github) that enables the use of pull requests in VSCode.
To pull changes from the github repository (i.e. get the latest changes that other users have committed), click the Source Control icon on the left side of VSCode, and open the Source Control menu by clicking the ellipses. On the Source Control menu, select Pull:
The plugin can use locally available value sets in the form of FHIR ValueSet resources. The plugin looks in the input/vocabulary/valueset folder (and any sub-folders recursively) and loads any files it finds and tries to interpret them as FHIR ValueSet resources. This means that the value set files can be FHIR Bundles or FHIR ValueSet resources in both XML and JSON format.
For example, given the following declaration in a CQL library:
valueset "Active Condition": 'http://fhir.org/guides/cqf/common/ValueSet/active-condition'
The plugin will look in the input/vocabulary
folder for a FHIR ValueSet resource with this url:
{
"resourceType" : "ValueSet",
"id" : "active-condition",
...
"url" : "http://fhir.org/guides/cqf/common/ValueSet/active-condition",
"version" : "4.0.1",
"name" : "CQFActiveCondition",
"title" : "CQF Active Condition",
...
Note that the id
doesn't matter, only the url
element is used to find the value set.
Note also that if the value set is a simple extensional value set (i.e. it is defined only in terms of a list of specific codes from a code system) then the plugin will compute the expansion. When this happens, a WARNING is issued by the evaluator indicating that the plugin performed the expansion and it may not be correct (because it does not use the code system to compute the expansion so it may include codes that should not be included based on the expansion rules that a full terminology server would follow).
...
"status" : "active",
"experimental" : false,
"date" : "2019-07-21",
"publisher" : "Alphora",
...
"compose" : {
"include" : [
{
"system" : "http://terminology.hl7.org/CodeSystem/condition-clinical",
"concept" : [
{
"code" : "active",
"display" : "Active"
},
{
"code" : "recurrence",
"display" : "Recurrence"
},
{
"code" : "relapse",
"display" : "Relapse"
}
]
}
]
}
}
Because of this possibility, best practice is to use ValueSet resources that have an expansion
element already computed, rather than relying on the plugin to perform the computation. In addition, any ValueSets that are more complex than simple extensional definitions will not be able to be expanded by the plugin and must have an expansion element present in order to be used.
NOTE: Because the structure of CQL projects is an extension to the FHIR IG publisher project structure, it is best practice to use an
external
sub-folder to contain value sets that are copied from other locations and not actually defined as part of the content IG. Future enhancements to the plugin will be able to make use of value sets distributed in dependent IGs, but for now, all terminology dependencies need to be copied localy in order for the plugin to make use of them.
Once you have added any required terminology, use the same process above for committing those changes back to the repository.
The plugin is also capable of making use of locally available FHIR resources for test data. The plugin looks in the input/tests
folder (and any sub-folders, recursively) for a folder with the same name as the library being tested. For example, when running the ColorectalCancerElements
library, the plugin will look in the input/cql/library/ColorectalCancerElements
folder.
The evaluation log lists the directory that the plugin is using to find test data:
Executing CQL...
CQL path: c:\Users\Bryn\Documents\Src\Github\CQFramework\cqf-ccc\input\cql
Data path: c:\Users\Bryn\Documents\Src\Github\CQFramework\cqf-ccc\input\tests\library\ColorectalCancerElements
Terminology path: c:\Users\Bryn\Documents\Src\Github\CQFramework\cqf-ccc\input\vocabulary\valueset
The plugin supports defining any number of Test Cases, where each test case is a separate folder in the test folder. In this case, the plugin finds two folders:
- denom-EXM130
- numer-EXM130
Each of these folders contains JSON files with the FHIR resources representing the test case. The name of the test case is the name of the folder and is used as the patient id for the test case. This means that all the FHIR data in the folder must use this patient id:
{
"resourceType": "Patient",
"id": "denom-EXM130",
...
}
{
"resourceType": "Encounter",
"id": "denom-EXM130-1",
"subject": {
"reference": "Patient/denom-EXM130"
},
...
}
To create a new test case, add a new folder and place the resource files corresponding to the test case in the folder. As with the terminology, the plugin will search for any files in the folder and any sub-folders, recursively, attempting to load any files and interpret them as FHIR resources, so the files can be in XML or JSON format and can be either Bundles or individual resources, and organized in whatever folder structure makes the most sense for your team.
As with changes to the CQL and Vocabulary, once you have made changes and want to commit them back to the repository, follow the same process for committing and pushing changes described above.
Once you have defined your test cases, right click anywhere in the library and select Execute CQL
to run the library. The plugin will find the test cases and run the library for each test case, outputting the result of evaluating each expression definition in the library to the evaluation log:
Executing CQL...
CQL path: c:\Users\Bryn\Documents\Src\Github\CQFramework\cqf-ccc\input\cql
Data path: c:\Users\Bryn\Documents\Src\Github\CQFramework\cqf-ccc\input\tests\library\ColorectalCancerElements
Terminology path: c:\Users\Bryn\Documents\Src\Github\CQFramework\cqf-ccc\input\vocabulary\valueset
Patient=Patient(id=denom-EXM130)
AsOf=2023-09-28T11:59:30.162
...
Has Appropriate Colorectal Cancer Screening=false
Has History of Appropriate Colorectal Cancer Screening=false
Patient=Patient(id=numer-EXM130)
AsOf=2023-09-28T11:59:30.624
...
Has Appropriate Colorectal Cancer Screening=true
Has History of Appropriate Colorectal Cancer Screening=false
NOTE: The plugin reads what is on disk, so make sure to save any changes in the editor before running your tests