diff --git a/README.md b/README.md index 493bae5..46327c0 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,13 @@ This project establishes a VSAC-enabled code service module for use with the CQL Execution Engine. This allows the CQL Execution Engine to execute CQL containing references to Value Sets that are published in the National Library of -Medicine's (NLM) Value Set Authority Center (VSAC). Value Set references should be defined using OIDS. For example: +Medicine's (NLM) Value Set Authority Center (VSAC). Value Set references can be defined using a valid VSAC +identifying URL for the value set, a URN, or the oid itself. For example: ``` -valueset "Diabetes": '2.16.840.1.113883.3.464.1003.103.12.1001' +valueset "Diabetes": 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.103.12.1001' +// or valueset "Diabetes": 'urn:oid:2.16.840.1.113883.3.464.1003.103.12.1001' +// or valueset "Diabetes": '2.16.840.1.113883.3.464.1003.103.12.1001' ``` This library requires that the credentials of a valid UMLS account be provided to it. If you do not have an UMLS @@ -41,13 +44,15 @@ provided via `UMLS_USER_NAME` and `UMLS_PASSWORD` environment variables. ## Downloading Value Set Definitions -The `ensureValueSets` function is the only function that attempts to download value sets from VSAC. Before it makes -a request to VSAC, it will check the cache. If the value set is already in the cache, it will not make a request to -VSAC. Otherwise, it will use VSAC's SVS2 API to download the expanded codes from the value set. +The `ensureValueSets` and `ensureValueSetsInLibrary` functions are the only functions that attempt to download value +sets from VSAC. Before they make a request to VSAC, they will check the cache. If the value set is already in the +cache, they will not make a request to VSAC. Otherwise, they will use VSAC's SVS2 API to download the expanded codes +from the value set. -The `findValueSetsByOID` and `findValueSet` functions do not reach out to VSAC, so implementations should call -`ensureValueSets` with the value set OIDs / versions first, before attempting to execute CQL. Usually an implementor -will extract the list of value set OIDs / versions from the ELM to pass them into `ensureValueSets`. +The `findValueSet` and `findValueSets` functions (including the legacy `findValueSetsByOid` function) do not reach out +to VSAC, so implementations should call `ensureValueSetsInLibrary` or `ensureValueSets` before attempting to execute +CQL. If `ensureValueSets` is used, the implementor is responsible for passing in the OIDs / versions that will be +needed. ## Example @@ -60,17 +65,10 @@ const vsac = require('cql-exec-vsac'); // Code setting up the CQL library, patient source, parameters, etc // ... -// Extract the value sets from the ELM -let valueSets = []; -const json = JSON.parse(fs.readFileSync('/path/to/cdsELM.json', 'utf8')); -if (json.library && json.library.valueSets && json.library.valueSets.def) { - valueSets = json.library.valueSets.def; -} - // Set up the code service, loading from the cache if it exists const codeService = new vsac.CodeService('/path/to/vsac_cache', true); -// Ensure value sets, downloading any missing value sets -codeService.ensureValueSets(valueSets, 'myUMLSUserName', 'myUMLSPassword') +// Ensure value sets in the library and its dependencies, downloading any missing value sets +codeService.ensureValueSetsInLibrary(library, true, 'myUMLSUserName', 'myUMLSPassword') .then(() => { // Value sets are loaded, so execute! const executor = new cql.Executor(lib, codeService, parameters); diff --git a/lib/CodeService.js b/lib/CodeService.js index b2b11b4..1047eed 100644 --- a/lib/CodeService.js +++ b/lib/CodeService.js @@ -4,6 +4,7 @@ const proc = require('process'); const env = proc.env; const path = require('path'); const {downloadFromVSAC} = require('./download-vsac'); +const extractOidAndVersion = require('./extractOidAndVersion'); /** * Constructs a code service with functions for downloading codes from the National Library of Medicine's @@ -98,39 +99,65 @@ class CodeService { return this.ensureValueSets(Array.from(valueSets), umlsUserName, umlsPassword, caching); } + /** + * The findValueSetsByOid function is kept for backwards compatibility (and since cql-execution + * calls it), but now it just calls the more appropriately named findValuesets. + * @param {string} oid - the OID to lookup the VS by (note: this now also support URN and URL) + * @returns {Array} a list of the matching value sets + */ findValueSetsByOid(oid) { + return this.findValueSets(oid); + } + + /** + * Returns a list of value sets matching the passed in identifier. If version is passed in, it will also filter + * by version (resulting in a list of, at most, 1 item). If no version is passed in, all versions are returned. + * Note that this does not do any network calls -- it operated only on the cached value sets. + * @param {string} id - the identifier for the value set (may be OID, URN, or VSAC FHIR URL) + * @param {string} version - the optional version; if blank, returns all versions + * @returns {Array} a list of the matching value sets + */ + findValueSets(id, version) { const result = []; + const [oid, embeddedVersion] = extractOidAndVersion(id); + if (version == null && embeddedVersion != null) { + version = embeddedVersion; + } const vs = this.valueSets[oid]; - for (let version in vs) { - result.push(vs[version]); + if (vs) { + for (let foundVersion in vs) { + if (version == null || foundVersion === version) { + result.push(vs[foundVersion]); + } + } } return result; } - findValueSet(oid, version) { - if (version != null) { - const vsObj = this.valueSets[oid]; - if (typeof vsObj !== 'undefined') { - return vsObj[version]; - } else { - return; - } - } - else { - const results = this.findValueSetsByOid(oid); - if (results.length === 0) { - return; - } - else { - return results.reduce(function(a, b) { - if (a.version > b.version) { - return a; - } - else { - return b; - } - }); - } + /** + * Returns the value set matching the passed in identifier and version (if applicable). If no version is + * passed in, and multiple versions are found, it will attempt to return the most recent version using a + * simple string comparison of versions. Note that this does not do any network calls -- it operates only + * on the cached value sets. + * @param {string} id - the identifier for the value set (may be OID, URN, or VSAC FHIR URL) + * @param {string} version - the optional version; if blank, attempts to return the most recent version + * @returns {Object} the matching value set or undefined (if no match is found) + */ + findValueSet(id, version) { + const results = this.findValueSets(id, version); + if (results.length === 0) { + return; + } else if (results.length === 1) { + return results[0]; + } else { + return results.reduce(function(a, b) { + if (a.version > b.version) { + return a; + } + else { + return b; + } + }); } } } diff --git a/lib/download-vsac.js b/lib/download-vsac.js index dd8aef2..5eb5074 100644 --- a/lib/download-vsac.js +++ b/lib/download-vsac.js @@ -3,6 +3,7 @@ const path = require('path'); const rpn = require('request-promise-native'); const mkdirp = require('mkdirp'); const parseVSACXML = require('./parse-vsac'); +const extractOidAndVersion = require('./extractOidAndVersion'); const debug = require('debug')('vsac'); // To turn on DEBUG: $ export DEBUG=vsac function downloadFromVSAC(username, password, input, output, vsDB={}, caching=true) { @@ -12,9 +13,10 @@ function downloadFromVSAC(username, password, input, output, vsDB={}, caching=tr vsJSON = require(input); } else { var keys = Object.keys(input); - keys.forEach(function(val,idx) { - if (!(input[val].id in vsDB)) { - vsJSON[input[val].name] = input[val].id; + keys.forEach(function(val) { + const [oid] = extractOidAndVersion(input[val].id); + if (!(oid in vsDB)) { + vsJSON[input[val].name] = oid; } }); } diff --git a/lib/extractOidAndVersion.js b/lib/extractOidAndVersion.js new file mode 100644 index 0000000..af48575 --- /dev/null +++ b/lib/extractOidAndVersion.js @@ -0,0 +1,23 @@ +/** + * Extracts just the oid from a urn, url, or oid. If it is not a valid urn or VSAC URL, + * it is assumed to be an oid and returned as-is. + * @param {string} id - the urn, url, or oid + * @returns {string} the oid + */ +function extractOidAndVersion(id) { + if (id == null) return []; + + // first check for VSAC FHIR URL (ideally https is preferred but support http just in case) + // if there is a | at the end, it indicates that a version string follows + let m = id.match(/^https?:\/\/cts\.nlm\.nih\.gov\/fhir\/ValueSet\/([^|]+)(\|(.+))?$/); + if (m) return m[3] == null ? [m[1]] : [m[1], m[3]]; + + // then check for urn:oid + m = id.match(/^urn:oid:(.+)$/); + if (m) return [m[1]]; + + // finally just return as-is + return [id]; +} + +module.exports = extractOidAndVersion; \ No newline at end of file diff --git a/test/fixtures/valueset-db.json b/test/fixtures/valueset-db.json index ce39ded..1bedc22 100644 --- a/test/fixtures/valueset-db.json +++ b/test/fixtures/valueset-db.json @@ -38,6 +38,17 @@ "version": "2.58" } ] + }, + "20200401": { + "oid": "2.16.840.1.113883.3.464.1003.104.12.1013", + "version": "20200401", + "codes": [ + { + "code": "48620-9", + "system": "http://loinc.org", + "version": "2.58" + } + ] } } } \ No newline at end of file diff --git a/test/test.js b/test/test.js index 8613469..7329267 100644 --- a/test/test.js +++ b/test/test.js @@ -70,11 +70,14 @@ describe('CodeService', function() { it('should find loaded value set', function() { const oid = '2.16.840.1.113883.3.464.1003.104.12.1013'; const results = service.findValueSetsByOid(oid); - results.should.have.length(1); + results.should.have.length(2); results[0].should.eql(new ValueSet(oid, '20170320', [ new Code('2093-3', 'http://loinc.org', '2.58'), new Code('48620-9', 'http://loinc.org', '2.58') ])); + results[1].should.eql(new ValueSet(oid, '20200401', [ + new Code('48620-9', 'http://loinc.org', '2.58') + ])); }); it('should not find invalid value set', function() { @@ -83,12 +86,140 @@ describe('CodeService', function() { }); }); + describe('#findValueSets', function() { + it('should find loaded values set by OID', function() { + const oid = '2.16.840.1.113883.3.464.1003.104.12.1013'; + const results = service.findValueSets(oid); + results.should.have.length(2); + results[0].should.eql(new ValueSet(oid, '20170320', [ + new Code('2093-3', 'http://loinc.org', '2.58'), + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + results[1].should.eql(new ValueSet(oid, '20200401', [ + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should find loaded values set by URN', function() { + const urn = 'urn:oid:2.16.840.1.113883.3.464.1003.104.12.1013'; + const results = service.findValueSets(urn); + results.should.have.length(2); + results[0].should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20170320', [ + new Code('2093-3', 'http://loinc.org', '2.58'), + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + results[1].should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20200401', [ + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + + it('should find loaded values set by https URL', function() { + const urn = 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013'; + const results = service.findValueSets(urn); + results.should.have.length(2); + results[0].should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20170320', [ + new Code('2093-3', 'http://loinc.org', '2.58'), + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + results[1].should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20200401', [ + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should find loaded values set by http URL', function() { + const urn = 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013'; + const results = service.findValueSets(urn); + results.should.have.length(2); + results[0].should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20170320', [ + new Code('2093-3', 'http://loinc.org', '2.58'), + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + results[1].should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20200401', [ + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should find loaded value set by https URL with version', function() { + const urn = 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013|20170320'; + const results = service.findValueSets(urn); + results.should.have.length(1); + results[0].should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20170320', [ + new Code('2093-3', 'http://loinc.org', '2.58'), + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should find loaded value set by http URL with version', function() { + const urn = 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013|20170320'; + const results = service.findValueSets(urn); + results.should.have.length(1); + results[0].should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20170320', [ + new Code('2093-3', 'http://loinc.org', '2.58'), + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should not find invalid value set by OID', function() { + const results = service.findValueSets('FOO'); + results.should.be.empty; + }); + + it('should not find invalid value set by URN', function() { + const results = service.findValueSets('urn:oid:FOO'); + results.should.be.empty; + }); + + it('should not find invalid value set by https URL', function() { + const results = service.findValueSets('https://cts.nlm.nih.gov/fhir/ValueSet/FOO'); + results.should.be.empty; + }); + + it('should not find invalid value set by http URL', function() { + const results = service.findValueSets('http://cts.nlm.nih.gov/fhir/ValueSet/FOO'); + results.should.be.empty; + }); + + it('should not find value set by https URL with invalid version', function() { + const results = service.findValueSets('https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013|20180320'); + results.should.be.empty; + }); + + it('should not find value set by http URL with invalid version', function() { + const results = service.findValueSets('http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013|20180320'); + results.should.be.empty; + }); + }); + describe('#findValueSet', function() { it('should find loaded value set by OID only', function() { const oid = '2.16.840.1.113883.3.464.1003.104.12.1013'; const result = service.findValueSet(oid); - result.should.eql(new ValueSet(oid, '20170320', [ - new Code('2093-3', 'http://loinc.org', '2.58'), + result.should.eql(new ValueSet(oid, '20200401', [ + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should find loaded value set by URN only', function() { + const urn = 'urn:oid:2.16.840.1.113883.3.464.1003.104.12.1013'; + const result = service.findValueSet(urn); + result.should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20200401', [ + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should find loaded value set by https URL only', function() { + const urn = 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013'; + const result = service.findValueSet(urn); + result.should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20200401', [ + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should find loaded value set by http URL only', function() { + const urn = 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013'; + const result = service.findValueSet(urn); + result.should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20200401', [ new Code('48620-9', 'http://loinc.org', '2.58') ])); }); @@ -103,6 +234,71 @@ describe('CodeService', function() { ])); }); + it('should find loaded value set by URN and version', function() { + const urn = 'urn:oid:2.16.840.1.113883.3.464.1003.104.12.1013'; + const version = '20170320'; + const result = service.findValueSet(urn, version); + result.should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', version, [ + new Code('2093-3', 'http://loinc.org', '2.58'), + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should find loaded value set by https URL and version', function() { + const url = 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013'; + const version = '20170320'; + const result = service.findValueSet(url, version); + result.should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', version, [ + new Code('2093-3', 'http://loinc.org', '2.58'), + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should find loaded value set by http URL and version', function() { + const url = 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013'; + const version = '20170320'; + const result = service.findValueSet(url, version); + result.should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', version, [ + new Code('2093-3', 'http://loinc.org', '2.58'), + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should find loaded value set by https URL and embedded version', function() { + const url = 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013|20170320'; + const result = service.findValueSet(url); + result.should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20170320', [ + new Code('2093-3', 'http://loinc.org', '2.58'), + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should find loaded value set by http URL and embedded version', function() { + const url = 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013|20170320'; + const result = service.findValueSet(url); + result.should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', '20170320', [ + new Code('2093-3', 'http://loinc.org', '2.58'), + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + + it('should prefer passed in version over url-embedded version', function() { + const url = 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013|20200401'; + const version = '20170320'; + const result = service.findValueSet(url, version); + result.should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', version, [ + new Code('2093-3', 'http://loinc.org', '2.58'), + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + + const url2 = 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013|20170320'; + const version2 = '20200401'; + const result2 = service.findValueSet(url2, version2); + result2.should.eql(new ValueSet('2.16.840.1.113883.3.464.1003.104.12.1013', version2, [ + new Code('48620-9', 'http://loinc.org', '2.58') + ])); + }); + it('should not find value set with invalid OID', function() { const result = service.findValueSet('FOO'); should.not.exist(result); @@ -115,54 +311,119 @@ describe('CodeService', function() { }); describe('#ensureValueSets', function() { - it('should not attempt downloads for value sets it already has', function() { + it('should not attempt downloads for value sets it already has (by OID)', function() { const vsList = [ {name: 'HDL Cholesterol', id: '2.16.840.1.113883.3.464.1003.104.12.1013', version: '20170320'} ]; return service.ensureValueSets(vsList).should.be.fulfilled; }); - it('should download value sets it does not have', function() { - // Just to be sure, check length is only 2 (as expected) - Object.keys(service.valueSets).should.have.length(2); + it('should not attempt downloads for value sets it already has (by URN)', function() { + const vsList = [ + {name: 'HDL Cholesterol', id: 'urn:oid:2.16.840.1.113883.3.464.1003.104.12.1013', version: '20170320'} + ]; + return service.ensureValueSets(vsList).should.be.fulfilled; + }); - nock('https://vsac.nlm.nih.gov') - // Ticket granting ticket - .post('/vsac/ws/Ticket', { username, password }) - .reply(200, 'TGT-TEST') - // Service ticket and VS retrieval #1 - .post('/vsac/ws/Ticket/TGT-TEST', { service: 'http://umlsks.nlm.nih.gov' }) - .reply(200, 'ST-TEST-1') - .get('/vsac/svs/RetrieveValueSet') - .query({ id: '2.16.840.1.113883.3.526.3.1032', ticket: 'ST-TEST-1' }) - .replyWithFile(200, path.join(__dirname, 'fixtures', '2.16.840.1.113883.3.526.3.1032.xml')) - // Service ticket and VS retrieval #2 - .post('/vsac/ws/Ticket/TGT-TEST', { service: 'http://umlsks.nlm.nih.gov' }) - .reply(200, 'ST-TEST-2') - .get('/vsac/svs/RetrieveValueSet') - .query({ id: '2.16.840.1.113883.3.600.2390', ticket: 'ST-TEST-2' }) - .replyWithFile(200, path.join(__dirname, 'fixtures', '2.16.840.1.113883.3.600.2390.xml')); + it('should not attempt downloads for value sets it already has (by https URL)', function() { + const vsList = [ + {name: 'HDL Cholesterol', id: 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013', version: '20170320'} + ]; + return service.ensureValueSets(vsList).should.be.fulfilled; + }); + + it('should not attempt downloads for value sets it already has (by http URL)', function() { + const vsList = [ + {name: 'HDL Cholesterol', id: 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013', version: '20170320'} + ]; + return service.ensureValueSets(vsList).should.be.fulfilled; + }); + it('should not attempt downloads for value sets it already has (by https URL with embedded version)', function() { const vsList = [ + {name: 'HDL Cholesterol', id: 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013|20170320'} + ]; + return service.ensureValueSets(vsList).should.be.fulfilled; + }); + + it('should not attempt downloads for value sets it already has (by http URL with embedded version)', function() { + const vsList = [ + {name: 'HDL Cholesterol', id: 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.464.1003.104.12.1013|20170320'} + ]; + return service.ensureValueSets(vsList).should.be.fulfilled; + }); + + it('should download value sets it does not have (by OID)', function() { + return doDownloadTest([ {name: 'Systolic Blood Pressure', id: '2.16.840.1.113883.3.526.3.1032', version: '20170320'}, {name: 'Current Tobacco Smoker', id: '2.16.840.1.113883.3.600.2390', version: '20170320'} - ]; + ]); + }); - return service.ensureValueSets(vsList, username, password).then(function() { - // Test that the value sets were properly loaded into memory - service.valueSets.should.not.be.empty; - Object.keys(service.valueSets).should.have.length(4); - const vs1 = service.findValueSet('2.16.840.1.113883.3.526.3.1032', '20170320'); - vs1.codes.should.have.length(1); - const vs2 = service.findValueSet('2.16.840.1.113883.3.600.2390', '20170418'); - vs2.codes.should.have.length(24); - // Test that the value sets were properly written to the cache - const cached = require(path.join(tmpCache, 'valueset-db.json')); - JSON.parse(JSON.stringify(service.valueSets)).should.eql(cached); - }); + it('should download value sets it does not have (by URN)', function() { + return doDownloadTest([ + {name: 'Systolic Blood Pressure', id: 'urn:oid:2.16.840.1.113883.3.526.3.1032', version: '20170320'}, + {name: 'Current Tobacco Smoker', id: 'urn:oid:2.16.840.1.113883.3.600.2390', version: '20170320'} + ]); + }); + + it('should download value sets it does not have (by https URL)', function() { + return doDownloadTest([ + {name: 'Systolic Blood Pressure', id: 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.526.3.1032', version: '20170320'}, + {name: 'Current Tobacco Smoker', id: 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.600.2390', version: '20170320'} + ]); }); - it('should download value sets it does not have when no version is supplied', function() { + it('should download value sets it does not have (by http URL)', function() { + return doDownloadTest([ + {name: 'Systolic Blood Pressure', id: 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.526.3.1032', version: '20170320'}, + {name: 'Current Tobacco Smoker', id: 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.600.2390', version: '20170320'} + ]); + }); + + it('should download value sets it does not have (by https URL with embedded version)', function() { + return doDownloadTest([ + {name: 'Systolic Blood Pressure', id: 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.526.3.1032|20170320'}, + {name: 'Current Tobacco Smoker', id: 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.600.2390|20170320'} + ]); + }); + + it('should download value sets it does not have (by http URL with embedded version)', function() { + return doDownloadTest([ + {name: 'Systolic Blood Pressure', id: 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.526.3.1032|20170320'}, + {name: 'Current Tobacco Smoker', id: 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.600.2390|20170320'} + ]); + }); + + it('should download value sets it does not have when no version is supplied (by OID)', function() { + return doDownloadTest([ + {name: 'Systolic Blood Pressure', id: '2.16.840.1.113883.3.526.3.1032'}, + {name: 'Current Tobacco Smoker', id: '2.16.840.1.113883.3.600.2390'} + ]); + }); + + it('should download value sets it does not have when no version is supplied (by URN)', function() { + return doDownloadTest([ + {name: 'Systolic Blood Pressure', id: 'urn:oid:2.16.840.1.113883.3.526.3.1032'}, + {name: 'Current Tobacco Smoker', id: 'urn:oid:2.16.840.1.113883.3.600.2390'} + ]); + }); + + it('should download value sets it does not have when no version is supplied (by https URL)', function() { + return doDownloadTest([ + {name: 'Systolic Blood Pressure', id: 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.526.3.1032'}, + {name: 'Current Tobacco Smoker', id: 'https://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.600.2390'} + ]); + }); + + it('should download value sets it does not have when no version is supplied (by http URL)', function() { + return doDownloadTest([ + {name: 'Systolic Blood Pressure', id: 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.526.3.1032'}, + {name: 'Current Tobacco Smoker', id: 'http://cts.nlm.nih.gov/fhir/ValueSet/2.16.840.1.113883.3.600.2390'} + ]); + }); + + const doDownloadTest = (vsList) => { // Just to be sure, check length is only 2 (as expected) Object.keys(service.valueSets).should.have.length(2); @@ -183,24 +444,19 @@ describe('CodeService', function() { .query({ id: '2.16.840.1.113883.3.600.2390', ticket: 'ST-TEST-2' }) .replyWithFile(200, path.join(__dirname, 'fixtures', '2.16.840.1.113883.3.600.2390.xml')); - const vsList = [ - {name: 'Systolic Blood Pressure', id: '2.16.840.1.113883.3.526.3.1032'}, - {name: 'Current Tobacco Smoker', id: '2.16.840.1.113883.3.600.2390'} - ]; - return service.ensureValueSets(vsList, username, password).then(function() { // Test that the value sets were properly loaded into memory service.valueSets.should.not.be.empty; Object.keys(service.valueSets).should.have.length(4); - const vs1 = service.findValueSet('2.16.840.1.113883.3.526.3.1032'); + const vs1 = service.findValueSet('2.16.840.1.113883.3.526.3.1032', '20170320'); vs1.codes.should.have.length(1); - const vs2 = service.findValueSet('2.16.840.1.113883.3.600.2390'); + const vs2 = service.findValueSet('2.16.840.1.113883.3.600.2390', '20170418'); vs2.codes.should.have.length(24); // Test that the value sets were properly written to the cache const cached = require(path.join(tmpCache, 'valueset-db.json')); JSON.parse(JSON.stringify(service.valueSets)).should.eql(cached); - }); - }); + }).catch((err) => console.log(err)); + }; it('should download and cache successful value sets before throwing error', function() { // Just to be sure, check length is only 2 (as expected)