Skip to content

Commit

Permalink
Add configuration to support including both uri and oid when parsing …
Browse files Browse the repository at this point in the history
…valuesets (#31)

Squashed commits from PR #31:

* feat: add initial support for oid and url

* fix: refactor the logic

* fix: spelling mistake

* fix: remove unused option for fhir

* style: fix lint

* fix: update to a better option name and value

* fix: default option should be url when empty options passed

---------

Co-authored-by: Tyler J Cvetan <[email protected]>
  • Loading branch information
SomethingSexy and Tyler J Cvetan authored Apr 16, 2024
1 parent 7e3de6b commit 884bd4e
Show file tree
Hide file tree
Showing 8 changed files with 683 additions and 17 deletions.
10 changes: 6 additions & 4 deletions src/CodeService.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ class CodeService {
async ensureValueSetsWithAPIKey(
valueSetList = [],
umlsAPIKey = env['UMLS_API_KEY'],
caching = true
caching = true,
options = { svsCodeSystemType: 'url' }
) {
// First, filter out the value sets we already have
const filteredVSList = valueSetList.filter(vs => {
Expand Down Expand Up @@ -112,7 +113,7 @@ class CodeService {
// Catch errors and convert to resolutions returning an error. This ensures Promise.all waits for all promises.
// See: http://stackoverflow.com/questions/31424561/wait-until-all-es6-promises-complete-even-rejected-promises
return this.api
.downloadValueSet(umlsAPIKey, oid, version, output, this.valueSets, caching)
.downloadValueSet(umlsAPIKey, oid, version, output, this.valueSets, caching, options)
.catch(err => {
debug(
`Error downloading valueset ${oid}${version != null ? ` version ${version}` : ''}`,
Expand Down Expand Up @@ -151,10 +152,11 @@ class CodeService {
library,
checkIncluded = true,
umlsAPIKey = env['UMLS_API_KEY'],
caching = true
caching = true,
options = { svsCodeSystemType: 'url' }
) {
const valueSets = extractSetOfValueSetsFromLibrary(library, checkIncluded);
return this.ensureValueSetsWithAPIKey(Array.from(valueSets), umlsAPIKey, caching);
return this.ensureValueSetsWithAPIKey(Array.from(valueSets), umlsAPIKey, caching, options);
}

/**
Expand Down
12 changes: 11 additions & 1 deletion src/fhir.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,17 @@ const fetch = require('node-fetch');
const debug = require('debug')('vsac'); // To turn on DEBUG: $ export DEBUG=vsac
const { Code, ValueSet } = require('cql-execution');

async function downloadValueSet(apiKey, oid, version, output, vsDB = {}, caching = true) {
async function downloadValueSet(
apiKey,
oid,
version,
output,
vsDB = {},
caching = true,
options = {
/* reserved for future use */
}
) {
const pages = await getValueSetPages(apiKey, oid, version);
if (pages == null || pages.length === 0) {
return;
Expand Down
58 changes: 46 additions & 12 deletions src/svs.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,56 @@ const debug = require('debug')('vsac'); // To turn on DEBUG: $ export DEBUG=vsac
const { Code, ValueSet } = require('cql-execution');
const vsacCS = require('./vsac-code-systems');

async function downloadValueSet(apiKey, oid, version, output, vsDB = {}, caching = true) {
async function downloadValueSet(
apiKey,
oid,
version,
output,
vsDB = {},
caching = true,
options = { svsCodeSystemType: 'url' }
) {
debug(`Getting ValueSet: ${oid}${version != null ? ` version ${version}` : ''}`);
const params = new URLSearchParams({ id: oid });
if (version != null) {
params.append('version', version);
}
const options = {
const requestOptions = {
headers: {
Authorization: `Basic ${Buffer.from(`apikey:${apiKey}`).toString('base64')}`
}
};
const response = await fetch(
`https://vsac.nlm.nih.gov/vsac/svs/RetrieveValueSet?${params}`,
options
requestOptions
);
if (!response.ok) {
throw new Error(response.status);
}
const data = await response.text();
parseVSACXML(data, vsDB);
parseVSACXML(data, vsDB, options);
if (caching) {
const file = path.join(output, `${oid}.xml`);
await fs.writeFile(file, data);
return file;
}
}

function getVSACCodeSystem(codeSystems, system) {
if (
typeof codeSystems[system] !== 'undefined' &&
typeof codeSystems[system].uri !== 'undefined'
) {
return codeSystems[system];
}

return null;
}

// Take in a string containing a string of the XML response from a VSAC SVS
// response and parse it into a vsDB object. This code makes strong
// assumptions about the structure of the message. See code below.
function parseVSACXML(xmlString, vsDB = {}) {
function parseVSACXML(xmlString, vsDB = {}, options = { svsCodeSystemType: 'url' }) {
if (typeof xmlString === 'undefined' || xmlString == null || xmlString.trim().length == 0) {
return;
}
Expand All @@ -59,16 +78,31 @@ function parseVSACXML(xmlString, vsDB = {}) {
// Loop over the codes and build the JSON.
const codeList = [];
for (let concept in conceptList) {
let system;
const systemOID = conceptList[concept]['$']['codeSystem'];
if (typeof vsacCS[systemOID] !== 'undefined' && typeof vsacCS[systemOID].uri !== 'undefined') {
system = vsacCS[systemOID].uri;
let system = conceptList[concept]['$']['codeSystem'];
const code = conceptList[concept]['$']['code'];
const version = conceptList[concept]['$']['codeSystemVersion'];
const systemOid = `urn:oid:${system}`;
const systemUri = getVSACCodeSystem(vsacCS, system);

if (options.svsCodeSystemType === 'oid') {
// Keep the oid system as is
system = systemOid;
} else if (options.svsCodeSystemType === 'both') {
// Optionally include both if they exist
if (systemUri !== null) {
codeList.push({ code, system: systemUri.uri, version });
}
// Include the standard oid system
system = systemOid;
} else {
system = `urn:oid:${systemOID}`;
// Replace oid system with the url system, if one exists
if (systemUri !== null) {
system = systemUri.uri;
} else {
system = systemOid;
}
}

const code = conceptList[concept]['$']['code'];
const version = conceptList[concept]['$']['codeSystemVersion'];
codeList.push({ code, system, version });
}

Expand Down
20 changes: 20 additions & 0 deletions test/fixtures/2.16.840.1.113883.3.526.3.1032-oid-uri-vsdb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"2.16.840.1.113883.3.526.3.1032": {
"20170504": {
"oid": "2.16.840.1.113883.3.526.3.1032",
"version": "20170504",
"codes": [
{
"code": "8480-6",
"system": "http://loinc.org",
"version": "2.74"
},
{
"code": "8480-6",
"system": "urn:oid:2.16.840.1.113883.6.1",
"version": "2.74"
}
]
}
}
}
15 changes: 15 additions & 0 deletions test/fixtures/2.16.840.1.113883.3.526.3.1032-oid-vsdb.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"2.16.840.1.113883.3.526.3.1032": {
"20170504": {
"oid": "2.16.840.1.113883.3.526.3.1032",
"version": "20170504",
"codes": [
{
"code": "8480-6",
"system": "urn:oid:2.16.840.1.113883.6.1",
"version": "2.74"
}
]
}
}
}
Loading

0 comments on commit 884bd4e

Please sign in to comment.