Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNOMED Hydrating, Filtering, Special MR Generation #1648

Draft
wants to merge 19 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat(snomed): conditions and procedures duplications
Refs: #1442
  • Loading branch information
jonahkaye committed Mar 27, 2024
commit 0033587808813ea90764b5aaeebb70c7a1bf3386
56 changes: 44 additions & 12 deletions packages/utils/src/terminology-server/snomed-dedup-and-filter.ts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add documentation explaining what it does and how to use it, please.

Original file line number Diff line number Diff line change
Expand Up @@ -52,40 +52,72 @@ async function computeHashTable(filePath: string, hashTable: Record<string, Hash

async function processFileEntries(filePath: string, hashTable: Record<string, HashTableEntry>) {
const data = JSON.parse(fs.readFileSync(filePath, "utf8"));
const encounteredCodes = new Set();
const entries = data.bundle ? data.bundle.entry : data.entry;

for (let i = entries.length - 1; i >= 0; i--) {
const entry = entries[i];
const resource = entry.resource;
if (resource && resource.resourceType === "Condition") {
const codings = resource.code?.coding || [];
let hasSnomedCode = false;

for (const coding of codings) {
if (coding.system === "http:https://snomed.info/sct") {
if (encounteredCodes.has(coding.code)) {
hasSnomedCode = true;
if (hashTable[coding.code] && hashTable[coding.code].inserted) {
console.log(`Removing duplicate code ${coding.code} from ${path.basename(filePath)}`);
entries.splice(i, 1);
break;
} else if (hashTable[coding.code] && !hashTable[coding.code].root) {
console.log(`Removing non-root code ${coding.code} from ${path.basename(filePath)}`);
entries.splice(i, 1);
break;
} else {
encounteredCodes.add(coding.code);
hashTable[coding.code].inserted = true;
const codeDetails = await getCodeDetails(coding.code, "SNOMEDCT_US");
if (codeDetails && codeDetails.display) {
if (codeDetails.category == "disorder") {
// console.log(`Identified disorder for ${coding.code}`);
if (codeDetails) {
if (codeDetails.category !== "disorder") {
console.log(
`Removing non-disorder code ${coding.code} from ${path.basename(filePath)}`
);
entries.splice(i, 1);
break;
} else {
const updatedText = `${codeDetails.display} (${codeDetails.category})`;
resource.code.text = updatedText;
coding.text = updatedText;
}
const updatedText = `${codeDetails.display} (${codeDetails.category})`;
resource.code.text = updatedText;
coding.text = updatedText;
}
}
}
}
if (!hasSnomedCode) {
console.log(`Removing entry without SNOMED codes from ${path.basename(filePath)}`);
entries.splice(i, 1);
}
} else if (resource && resource.resourceType === "Procedure") {
const codings = resource.code?.coding || [];
let hasValidCptCode = false;

for (const coding of codings) {
if (coding.system === "http:https://www.ama-assn.org/go/cpt") {
const cptCode = parseInt(coding.code, 10);
if (cptCode >= 10004 && cptCode <= 69990) {
hasValidCptCode = true;
break;
}
}
}
if (!hasValidCptCode) {
console.log(
`Removing procedure entry with invalid or missing CPT code from ${path.basename(
filePath
)}`
);
entries.splice(i, 1);
}
}
}

// Write the updated data back to the same file
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf8");
}

Expand All @@ -96,7 +128,7 @@ async function main() {
process.exit(1);
}
const hashTable: Record<string, HashTableEntry> = {};
// call compute hash table and then after thats done call process file entries

await processDirectoryOrFile(directoryPath, async filePath => {
await computeHashTable(filePath, hashTable);
});
Expand Down
11 changes: 10 additions & 1 deletion packages/utils/src/terminology-server/snomed-heirarchies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export type HashTableEntry = {
children: Set<string>;
parents: Set<string>;
root: boolean;
inserted: boolean;
};

export type CodeDetailsResponse = {
Expand Down Expand Up @@ -44,7 +45,13 @@ export async function populateHashTableFromCodeDetails(
hashTable[queriedCode] = { ...hashTable[queriedCode], found: true, root: false };
}
} else {
hashTable[queriedCode] = { found: true, parents: new Set(), children: new Set(), root: true };
hashTable[queriedCode] = {
found: true,
parents: new Set(),
children: new Set(),
root: true,
inserted: false,
};
codeDetails.parameter.forEach(param => {
if (param.name === "property") {
const valuePart = param.part.find(part => part.name === "value");
Expand All @@ -61,6 +68,7 @@ export async function populateHashTableFromCodeDetails(
parents: new Set(),
children: new Set(),
root: false,
inserted: false,
};
hashTable[queriedCode].parents.add(value);
// having children indicates your a parent node
Expand All @@ -75,6 +83,7 @@ export async function populateHashTableFromCodeDetails(
parents: new Set(),
children: new Set(),
root: false,
inserted: false,
};
hashTable[queriedCode].children.add(value);
// having parents indicates your a chilld node
Expand Down
Loading