Skip to content

Commit 03e4093

Browse files
Merge pull request #68 from mcode/value-set-systems
Code System matching in Value Set searches
2 parents 63c3fc3 + 473abc4 commit 03e4093

29 files changed

+176
-124
lines changed

docs/CSV_Templates.xlsx

34 Bytes
Binary file not shown.

docs/staging.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
mrn,conditionId,stageGroup,t,n,m,type,stagingSystem,effectiveDate
2-
mrn-1,example-condition-id,3C,cT3,cN3,cM0,Clinical,443830009,2020-01-01
1+
mrn,conditionId,stageGroup,t,n,m,type,stagingSystem,stagingCodeSystem,effectiveDate
2+
mrn-1,example-condition-id,3C,cT3,cN3,cM0,Clinical,443830009,http://snomed.info/sct,2020-01-01

src/extractors/CSVStagingExtractor.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ function formatTNMCategoryData(stagingData) {
1010
logger.debug('Reformatting TNM Category data into template format');
1111
const formattedData = [];
1212
const {
13-
mrn, conditionId, t, n, m, type, stagingSystem, effectiveDate,
13+
mrn, conditionId, t, n, m, type, stagingSystem, stagingCodeSystem, effectiveDate,
1414
} = stagingData;
1515

1616
if (!mrn || !conditionId || !effectiveDate) {
@@ -23,6 +23,7 @@ function formatTNMCategoryData(stagingData) {
2323
effectiveDateTime: formatDateTime(effectiveDate),
2424
stageType: type,
2525
stagingSystem,
26+
stagingCodeSystem,
2627
subjectId: mrn,
2728
};
2829

@@ -35,7 +36,7 @@ function formatTNMCategoryData(stagingData) {
3536

3637
function formatStagingData(stagingData, categoryIds) {
3738
const {
38-
mrn, conditionId, type, stageGroup, stagingSystem, effectiveDate,
39+
mrn, conditionId, type, stageGroup, stagingSystem, stagingCodeSystem, effectiveDate,
3940
} = stagingData;
4041

4142
return {
@@ -44,6 +45,7 @@ function formatStagingData(stagingData, categoryIds) {
4445
type,
4546
stageGroup,
4647
stagingSystem,
48+
stagingCodeSystem,
4749
effectiveDateTime: formatDateTime(effectiveDate),
4850
categoryIds,
4951
};

src/extractors/MCODERadiationProcedureExtractor.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ function getMCODERadiationProcedures(fhirProcedures) {
99
const radiationProcedureVSFilepath = path.resolve(__dirname, '..', 'helpers', 'valueSets', 'ValueSet-mcode-cancer-related-radiation-procedure-vs.json');
1010
return fhirProcedures.filter((procedure) => {
1111
const coding = procedure.resource.code ? procedure.resource.code.coding : [];
12-
// NOTE: Update when checkCodeInVS checks code and system (might be able to pass in the full Coding)
13-
return coding.some((c) => checkCodeInVs(c.code, radiationProcedureVSFilepath));
12+
return coding.some((c) => checkCodeInVs(c.code, c.system, radiationProcedureVSFilepath));
1413
});
1514
}
1615

src/extractors/MCODESurgicalProcedureExtractor.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ function getMCODESurgicalProcedures(fhirProcedures) {
99
const surgicalProcedureVSFilepath = path.resolve(__dirname, '..', 'helpers', 'valueSets', 'ValueSet-mcode-cancer-related-surgical-procedure-vs.json');
1010
return fhirProcedures.filter((procedure) => {
1111
const coding = procedure.resource.code ? procedure.resource.code.coding : [];
12-
// NOTE: Update when checkCodeInVS checks code and system (might be able to pass in the full Coding)
13-
return coding.some((c) => checkCodeInVs(c.code, surgicalProcedureVSFilepath));
12+
return coding.some((c) => checkCodeInVs(c.code, c.system, surgicalProcedureVSFilepath));
1413
});
1514
}
1615

src/helpers/cancerStagingUtils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
const path = require('path');
22
const { checkCodeInVs } = require('./valueSetUtils');
33

4-
function isCancerStagingSystem(code) {
4+
function isCancerStagingSystem(code, system) {
55
const cancerStagingSystemVSPath = path.resolve(__dirname, 'valueSets', 'ValueSet-mcode-cancer-staging-system-vs.json');
6-
return checkCodeInVs(code, cancerStagingSystemVSPath);
6+
return checkCodeInVs(code, system, cancerStagingSystemVSPath);
77
}
88

99
module.exports = {

src/helpers/conditionUtils.js

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
const path = require('path');
22
const { checkCodeInVs } = require('./valueSetUtils');
33

4+
const systemLookup = {
5+
'urn:oid:2.16.840.1.113883.6.90': 'http://hl7.org/fhir/sid/icd-10-cm',
6+
};
7+
48

59
/**
610
* Checks for ICD-10 code
@@ -20,22 +24,28 @@ function getICD10Code(condition) {
2024

2125
/**
2226
* Checks if a condition code is a primary cancer condition
23-
* @param code ICD code, string
27+
* @param {string} code ICD code
28+
* @param {string} system Code system to which th code belongs
2429
* @return {boolean} if primary cancer condition
2530
*/
26-
function isConditionCodePrimary(code) {
31+
/* eslint-disable no-prototype-builtins */
32+
function isConditionCodePrimary(code, system) {
2733
const primaryCancerConditionVSFilepath = path.resolve(__dirname, 'valueSets', 'ValueSet-mcode-primary-or-uncertain-behavior-cancer-disorder-vs.json');
28-
return checkCodeInVs(code, primaryCancerConditionVSFilepath);
34+
const searchSystem = systemLookup.hasOwnProperty(system) ? systemLookup[system] : system;
35+
return checkCodeInVs(code, searchSystem, primaryCancerConditionVSFilepath);
2936
}
3037

3138
/**
3239
* Checks if a condition code is a secondary cancer condition
33-
* @param code ICD code, string
40+
* @param {string} code ICD code
41+
* @param {string} system Code system to which th code belongs
3442
* @return {boolean} if secondary cancer condition
3543
*/
36-
function isConditionCodeSecondary(code) {
44+
/* eslint-disable no-prototype-builtins */
45+
function isConditionCodeSecondary(code, system) {
3746
const secondaryCancerConditionVSFilepath = path.resolve(__dirname, 'valueSets', 'ValueSet-mcode-secondary-cancer-disorder-vs.json');
38-
return checkCodeInVs(code, secondaryCancerConditionVSFilepath);
47+
const searchSystem = systemLookup.hasOwnProperty(system) ? systemLookup[system] : system;
48+
return checkCodeInVs(code, searchSystem, secondaryCancerConditionVSFilepath);
3949
}
4050

4151
/**
@@ -45,7 +55,7 @@ function isConditionCodeSecondary(code) {
4555
*/
4656
function isConditionPrimary(condition) {
4757
const icd10Code = getICD10Code(condition);
48-
return icd10Code && isConditionCodePrimary(icd10Code.code);
58+
return icd10Code && isConditionCodePrimary(icd10Code.code, icd10Code.system);
4959
}
5060

5161
/**
@@ -55,16 +65,17 @@ function isConditionPrimary(condition) {
5565
*/
5666
function isConditionSecondary(condition) {
5767
const icd10Code = getICD10Code(condition);
58-
return icd10Code && isConditionCodeSecondary(icd10Code.code);
68+
return icd10Code && isConditionCodeSecondary(icd10Code.code, icd10Code.system);
5969
}
6070

6171
/**
6272
* Checks if a condition code is a cancer condition we recognize
63-
* @param code ICD code, string
73+
* @param {string} code ICD code
74+
* @param {string} system Code system to which th code belongs
6475
* @return {boolean} if primary or secondary cancer condition
6576
*/
66-
function isConditionCodeCancer(code) {
67-
return isConditionCodePrimary(code) || isConditionCodeSecondary(code);
77+
function isConditionCodeCancer(code, system) {
78+
return isConditionCodePrimary(code, system) || isConditionCodeSecondary(code, system);
6879
}
6980

7081
/**

src/helpers/observationUtils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ const vitalSignsCodeToTextLookup = {
1919
};
2020

2121

22-
function isTumorMarker(code) {
22+
function isTumorMarker(code, system) {
2323
const tumorMarkerTestVSPath = path.resolve(__dirname, 'valueSets', 'ValueSet-mcode-tumor-marker-test-vs.json');
24-
return checkCodeInVs(code, tumorMarkerTestVSPath);
24+
return checkCodeInVs(code, system, tumorMarkerTestVSPath);
2525
}
2626

2727
function isVitalSign(code) {

src/helpers/valueSetUtils.js

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,28 +38,26 @@ function loadVs(absoluteFilepath, typeOfVS) {
3838
/**
3939
* Check if code is in value set
4040
* @param {string} code value to look for in a valueset
41-
* @param {object} valueSet contains list of codes included in value set
41+
* @param {string} codeSystem the system to which the code value belongs
42+
* @param {string} valueSetFilePath the file path of the value set to be searched
43+
* @param {string} typeOfVS the file type of the value set to be searched
4244
* @return {boolean} true if condition is in valueSet's compose block or expansion block
4345
*/
44-
const checkCodeInVs = (code, valueSetFilePath, typeOfVS = vsTypes.json) => {
46+
const checkCodeInVs = (code, codeSystem, valueSetFilePath, typeOfVS = vsTypes.json) => {
4547
const valueSet = loadVs(valueSetFilePath, typeOfVS);
4648
let inVSExpansion = false;
4749
let inVSCompose = false;
4850
if (valueSet.expansion) {
4951
// If valueSet has expansion, we only need to check these codes
5052
inVSExpansion = valueSet.expansion.contains.some((containsItem) => {
51-
if (!code || !containsItem) return false;
52-
// NOTE: This is a technically incorrect interpretation of ValueSets;
53-
// this matching ought to check both code and system
54-
return code === containsItem.code;
53+
if (!code || !codeSystem || !containsItem || !containsItem.system) return false;
54+
return code === containsItem.code && codeSystem === containsItem.system;
5555
});
5656
} else {
5757
// Checks if code is in any of the valueSet.compose.include arrays
5858
inVSCompose = valueSet.compose.include.some((includeItem) => {
59-
if (!code || !includeItem || !includeItem.concept) return false;
60-
// NOTE: This is a technically incorrect interpretation of ValueSets;
61-
// this matching ought to check both code and system
62-
return includeItem.concept.map((concept) => concept.code).includes(code);
59+
if (!code || !codeSystem || !includeItem || !includeItem.system || !includeItem.concept) return false;
60+
return includeItem.system === codeSystem && includeItem.concept.map((concept) => concept.code).includes(code);
6361
});
6462
}
6563
return inVSCompose || inVSExpansion;

src/templates/ConditionTemplate.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ function individualCategoryTemplate(category) {
4343

4444
function categoryArrayTemplate(array, code) {
4545
const category = array.map(individualCategoryTemplate);
46-
const codeValue = `${code}`;
47-
if (isConditionCodeCancer(codeValue)) {
46+
const codeValue = `${code.code}`;
47+
const codeSystem = `${code.system}`;
48+
if (isConditionCodeCancer(codeValue, codeSystem)) {
4849
// On cancer conditions, include the fixed value for the disease category
4950
category.push({
5051
coding: [coding({
@@ -125,7 +126,7 @@ function conditionTemplate({
125126
),
126127
...ifAllArgsObj(clinicalStatusTemplate)({ clinicalStatus }),
127128
...ifAllArgsObj(verificationStatusTemplate)({ verificationStatus }),
128-
...categoryArrayTemplate(category, code.code),
129+
...categoryArrayTemplate(category, code),
129130
...codingTemplate({ code }),
130131
...ifAllArgsObj(bodySiteTemplate)({ bodySite, laterality }),
131132
...subjectTemplate({ subject }),

0 commit comments

Comments
 (0)