Skip to content

Commit

Permalink
Merged in vsac-cache-updater (pull request #13)
Browse files Browse the repository at this point in the history
Vsac cache updater

Approved-by: David Winters <dwinters@mitre.org>
Approved-by: Tom Read <tread@mitre.org>
Approved-by: Noranda Brown <noranda@norandabrown.com>
  • Loading branch information
cmoesel authored and noranda committed Feb 26, 2020
2 parents 5a25887 + c9b9a5d commit 1af2094
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 54 deletions.
2 changes: 1 addition & 1 deletion .node-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8.11.3
10.13.0
19 changes: 11 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ The Pain Management Summary SMART on FHIR application was developed to support t

The Pain Management Summary SMART on FHIR application was piloted during Summer 2018. Local modifications and development were needed to fully support this application in the pilot environment. For example, custom development was needed to expose pain assessments via the FHIR API. See the pilot reports for more information.

This application was originally piloted with support for FHIR DSTU2. The app has been updated since the pilot to also support FHIR R4, although pilot R4 support has not been piloted in a clinical setting.
This application was originally piloted with support for FHIR DSTU2. The app has been updated since the pilot to also support FHIR R4, although pilot R4 support has not been piloted in a clinical setting. In addition, value sets and standardized codes have been updated since the pilot. See the comments in the bundled CQL for details.

This prototype application is part of the [CDS Connect](https://cds.ahrq.gov/cdsconnect) project, sponsored by the [Agency for Healthcare Research and Quality](https://www.ahrq.gov/) (AHRQ), and developed under contract with AHRQ by [MITRE's CAMH](https://www.mitre.org/centers/cms-alliances-to-modernize-healthcare/who-we-are) FFRDC.

Expand All @@ -28,11 +28,6 @@ This CDS logic queries for several concepts that do not yet have standardized co

| Code | System | Display |
| --- | --- | --- |
| PEGASSESSMENT | http://cds.ahrq.gov/cdsconnect/pms | Pain Enjoyment General Activity (PEG) Assessment |
| PEGPAIN | http://cds.ahrq.gov/cdsconnect/pms | Pain |
| PEGENJOYMENT | http://cds.ahrq.gov/cdsconnect/pms | Enjoyment of life |
| PEGGENERALACTIVITY | http://cds.ahrq.gov/cdsconnect/pms | General activity |
| STARTBACK | http://cds.ahrq.gov/cdsconnect/pms | STarT Back Screening Tool |
| SQETOHUSE | http://cds.ahrq.gov/cdsconnect/pms | Single question r/t ETOH use |
| SQDRUGUSE | http://cds.ahrq.gov/cdsconnect/pms | Single question r/t drug use |
| MME | http://cds.ahrq.gov/cdsconnect/pms | Morphine Milligram Equivalent (MME) |
Expand All @@ -41,7 +36,7 @@ Systems integrating the Pain Management Summary will need to expose the correspo

### To build and run in development:

1. Install [Node.js](https://nodejs.org/en/download/) (LTS edition, currently 8.x)
1. Install [Node.js](https://nodejs.org/en/download/) (LTS edition, currently 12.x)
2. Install [Yarn](https://yarnpkg.com/en/docs/install) (1.3.x or above)
3. Install dependencies by executing `yarn` from the project's root directory
4. If you have a SMART-on-FHIR client ID, edit `public/launch-context.json` to specify it
Expand All @@ -53,7 +48,7 @@ Systems integrating the Pain Management Summary will need to expose the correspo

The Pain Management Summary can be deployed as static web resources on any HTTP server. There are several customizations, however, that need to be made based on the site where it is deployed.

1. Install [Node.js](https://nodejs.org/en/download/) (LTS edition, currently 8.x)
1. Install [Node.js](https://nodejs.org/en/download/) (LTS edition, currently 12.x)
2. Install [Yarn](https://yarnpkg.com/en/docs/install) (1.3.x or above)
3. Install dependencies by executing `yarn` from the project's root directory
4. Modify the `homepage` value in `package.json` to reflect the path (after the hostname) at which it will be deployed
Expand All @@ -69,6 +64,14 @@ The Pain Management Summary can be deployed as static web resources on any HTTP

Optionally to step 9, you can run the static build contents in a simple Node http-server via the command: `yarn start-static`.

### To update the valueset-db.json file

The value set content used by the CQL is cached in a file named `valueset-db.json`. If the CQL has been modified to add or remove value sets, or if the value sets themselves have been updated, you may wish to update the valueset-db.json with the latest codes. To do this, you will need a [UMLS Terminology Services account](https://uts.nlm.nih.gov//license.html).

To update the `valueset-db.json` file:

1. Run `node src/utils/updateValueSetDB.js UMLS_USER_NAME UMLS_PASSWORD` _(replacing UMLS\_USER\_NAME and UMLS\_PASSWORD with your username and password)_

### To run the unit tests

To execute the unit tests:
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "pain-management-factors",
"version": "0.3.0",
"version": "0.3.1",
"description": "Pain Management Factors SMART-on-FHIR App",
"homepage": "https://ahrq-cds.github.io/AHRQ-CDS-Connect-PAIN-MANAGEMENT-SUMMARY",
"license": "Apache-2.0",
Expand Down Expand Up @@ -31,13 +31,15 @@
"@rescripts/cli": "^0.0.13",
"@rescripts/utilities": "^0.0.6",
"cors": "^2.8.5",
"cql-exec-vsac": "^1.0.4",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"express": "^4.17.1",
"gh-pages": "^2.2.0",
"jest-enzyme": "^7.1.2",
"mock-local-storage": "^1.1.11",
"react-router-test-context": "^0.1.0",
"temp": "^0.9.1",
"typescript": "^3.7.5"
},
"resolutions": {
Expand Down Expand Up @@ -66,7 +68,6 @@
"eject": "rescripts eject",
"predeploy": "npm run build",
"deploy": "gh-pages -d build",
"fix-vs-db": "node ./src/utils/fixVsDb",
"upload-test-patients": "node ./src/utils/uploadTestPatients",
"lint": "eslint ."
}
Expand Down
2 changes: 1 addition & 1 deletion src/utils/executeELM.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function getLibrary(release) {
}));
case 4:
return new cql.Library(r4FactorsELM, new cql.Repository({
CDS_Connect_Commons_for_FHIRv102: r4CommonsELM,
CDS_Connect_Commons_for_FHIRv400: r4CommonsELM,
FHIRHelpers: r4HelpersELM
}));
default:
Expand Down
37 changes: 0 additions & 37 deletions src/utils/fixVsDb.js

This file was deleted.

88 changes: 88 additions & 0 deletions src/utils/updateValueSetDB.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// This script updates the valueset-db.json file with any changes from the CQL
// library and/or changes in the value set definitions in VSAC. It should be
// called with the UMLS Username and Password as arguments.
const fs = require('fs');
const path = require('path');
const temp = require('temp');
const { Library, Repository } = require('cql-execution');
const { CodeService } = require('cql-exec-vsac');
const dstu2FactorsELM = require('../cql/dstu2/Factors_to_Consider_in_Managing_Chronic_Pain.json');
const dstu2CommonsELM = require('../cql/dstu2/CDS_Connect_Commons_for_FHIRv102.json');
const dstu2HelpersELM = require('../cql/dstu2/FHIRHelpers.json');
const r4FactorsELM = require('../cql/r4/Factors_to_Consider_in_Managing_Chronic_Pain_FHIRv400.json');
const r4CommonsELM = require('../cql/r4/CDS_Connect_Commons_for_FHIRv400.json');
const r4HelpersELM = require('../cql/r4/FHIRHelpers.json');

// First ensure a username and password are provided
const [user, password] = process.argv.slice(2);
if (user == null || password == null) {
console.error('The UMLS username and password must be passed in as arguments');
process.exit(1);
}

// Then initialize the cql-exec-vsac CodeService, pointing to a temporary
// folder to dump the valueset cache files.
temp.track(); // track temporary files and delete them when the process exits
const tempFolder = temp.mkdirSync('vsac-cache');
const codeService = new CodeService(tempFolder);

console.log(`Using temp folder: ${tempFolder}`);

// Then setup the CQL libraries that we need to analyze to extract the
// valuesets from. In theory, the DSTU2 and R4 libraries should use the
// same valuesets, but in case they don't we go ahead and load both of
// them.
const dstu2Lib = new Library(dstu2FactorsELM, new Repository({
CDS_Connect_Commons_for_FHIRv102: dstu2CommonsELM,
FHIRHelpers: dstu2HelpersELM
}));
const r4Lib = new Library(r4FactorsELM, new Repository({
CDS_Connect_Commons_for_FHIRv400: r4CommonsELM,
FHIRHelpers: r4HelpersELM
}));

// Then use the ensureValueSetsInLibrary function to analyze the Pain
// Management Summary CQL, request all the value sets from VSAC, and store
// their data in the temporary folder. The second argument (true)
// indicates to also look at dependency libraries. This has no affect
// for the current CQL, but may be helpful for people who extend it.
console.log(`Loading value sets from VSAC using account: ${user}`);
codeService.ensureValueSetsInLibrary(dstu2Lib, true, user, password)
.then(() => codeService.ensureValueSetsInLibrary(r4Lib, true, user, password))
.then(() => {
// The valueset-db.json that the codeService produces isn't exactly the
// format that the Pain Management Summary wants, so now we must reformat
// it into the desired format.
const tempDBFile = path.join(tempFolder, 'valueset-db.json');
const original = JSON.parse(fs.readFileSync(tempDBFile, 'utf8'));
let oidKeys = Object.keys(original).sort();
console.log(`Loaded ${oidKeys.length} value sets`);
console.log('Translating JSON to expected format')
const fixed = {};
for (const oid of oidKeys) {
fixed[oid] = {};
for (const version of Object.keys(original[oid])) {
fixed[oid][version] = original[oid][version]['codes'].sort((a, b) => {
if (a.code < b.code) return -1;
else if (a.code > b.code) return 1;
return 0;
});
}
}

// And finally write the result to the real locations of the valueset-db.json.
const dbPath = path.join(__dirname, '..', 'cql', 'valueset-db.json');
fs.writeFileSync(dbPath, JSON.stringify(fixed, null, 2), 'utf8');
console.log('Updated:', dbPath);
})
.catch((error) => {
let message = error.message;
if (error.statusCode === 401) {
// The default 401 message isn't helpful at all
message = 'invalid password or unauthorized access'
}
console.error('Error updating valueset-db.json:', message);
process.exit(1);
});


59 changes: 54 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3335,6 +3335,17 @@ cql-exec-fhir@^1.3.1:
dependencies:
xml2js "~0.4.19"

cql-exec-vsac@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/cql-exec-vsac/-/cql-exec-vsac-1.0.4.tgz#3359f62c2eb96fa8dcf5cd28acc28de6a437d0d8"
integrity sha512-ZnHGqt7baLmw7abiAgK7Z9MCAi2ZGZPt+J6avVTshSBY1s3rOCQUDoppOQTvN7QlUSM+Y7mNI8oP7BzJ4NR8dA==
dependencies:
debug "^4.1.1"
mkdirp "^1.0.3"
request "^2.88.2"
request-promise-native "^1.0.8"
xml2js "^0.4.23"

cql-execution@^1.3.7:
version "1.3.7"
resolved "https://registry.yarnpkg.com/cql-execution/-/cql-execution-1.3.7.tgz#bf302da698c6ed626fe37af62b93431a95ce64c2"
Expand Down Expand Up @@ -5306,7 +5317,7 @@ har-schema@^2.0.0:
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=

har-validator@~5.1.0:
har-validator@~5.1.0, har-validator@~5.1.3:
version "5.1.3"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
Expand Down Expand Up @@ -7517,6 +7528,11 @@ mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1:
dependencies:
minimist "0.0.8"

mkdirp@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.3.tgz#4cf2e30ad45959dddea53ad97d518b6c8205e1ea"
integrity sha512-6uCP4Qc0sWsgMLy1EOqqS/3rjDHOEnsStVr/4vtAIK2Y5i2kA7lFFejYrpIyiN9w0pYf4ckeCYT9f1r1P9KX5g==

mock-local-storage@^1.1.11:
version "1.1.11"
resolved "https://registry.yarnpkg.com/mock-local-storage/-/mock-local-storage-1.1.11.tgz#2a36faeb30f76ef3c5005460b6bbf12f19555811"
Expand Down Expand Up @@ -9977,7 +9993,7 @@ request-promise-core@1.1.3:
dependencies:
lodash "^4.17.15"

request-promise-native@^1.0.5:
request-promise-native@^1.0.5, request-promise-native@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36"
integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==
Expand Down Expand Up @@ -10012,6 +10028,32 @@ request@^2.87.0, request@^2.88.0:
tunnel-agent "^0.6.0"
uuid "^3.3.2"

request@^2.88.2:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
dependencies:
aws-sign2 "~0.7.0"
aws4 "^1.8.0"
caseless "~0.12.0"
combined-stream "~1.0.6"
extend "~3.0.2"
forever-agent "~0.6.1"
form-data "~2.3.2"
har-validator "~5.1.3"
http-signature "~1.2.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.19"
oauth-sign "~0.9.0"
performance-now "^2.1.0"
qs "~6.5.2"
safe-buffer "^5.1.2"
tough-cookie "~2.5.0"
tunnel-agent "^0.6.0"
uuid "^3.3.2"

require-directory@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
Expand Down Expand Up @@ -10150,7 +10192,7 @@ rimraf@2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3, rimraf@^2.7.1:
dependencies:
glob "^7.1.3"

rimraf@2.6.3:
rimraf@2.6.3, rimraf@~2.6.2:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
Expand Down Expand Up @@ -11112,6 +11154,13 @@ tar@^4:
safe-buffer "^5.1.2"
yallist "^3.0.3"

temp@^0.9.1:
version "0.9.1"
resolved "https://registry.yarnpkg.com/temp/-/temp-0.9.1.tgz#2d666114fafa26966cd4065996d7ceedd4dd4697"
integrity sha512-WMuOgiua1xb5R56lE0eH6ivpVmg/lq2OHm4+LtT/xtEtPQ+sz6N3bBM6WZ5FvO1lO4IKIOb43qnhoc4qxP5OeA==
dependencies:
rimraf "~2.6.2"

terser-webpack-plugin@2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-2.2.1.tgz#5569e6c7d8be79e5e43d6da23acc3b6ba77d22bd"
Expand Down Expand Up @@ -11267,7 +11316,7 @@ toidentifier@1.0.0:
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==

tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@^2.5.0:
tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@^2.5.0, tough-cookie@~2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
Expand Down Expand Up @@ -12069,7 +12118,7 @@ xml-name-validator@^3.0.0:
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==

xml2js@~0.4.19:
xml2js@^0.4.23, xml2js@~0.4.19:
version "0.4.23"
resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
Expand Down

0 comments on commit 1af2094

Please sign in to comment.