From 16705aeb5adcac2ed7c260a28f3355ac08f089e0 Mon Sep 17 00:00:00 2001 From: raskolnikov-rodion <22417165+raskolnikov-rodion@users.noreply.github.com> Date: Thu, 31 Aug 2023 06:37:30 +0100 Subject: [PATCH] refactor(ccdaservice): test and refactor count entities function (#6805) * refactor(ccdaservice): test and refactor single entity function * refactor(ccdaservice): use extracted single entity function * refactor(ccdaservice): rename function countEntities --- ccdaservice/serveccda.js | 79 +++++++++------------- ccdaservice/utils/count-entities/count-entities.js | 14 ++++ .../utils/count-entities/count-entities.spec.js | 43 ++++++++++++ 3 files changed, 88 insertions(+), 48 deletions(-) create mode 100644 ccdaservice/utils/count-entities/count-entities.js create mode 100644 ccdaservice/utils/count-entities/count-entities.spec.js diff --git a/ccdaservice/serveccda.js b/ccdaservice/serveccda.js index 9ca9f1133..b2606b843 100644 --- a/ccdaservice/serveccda.js +++ b/ccdaservice/serveccda.js @@ -16,11 +16,12 @@ const server = net.createServer(); const to_json = require('xmljson').to_json; const bbg = require(__dirname + '/oe-blue-button-generate'); const fs = require('fs'); -const DataStack = require('./data-stack/data-stack').DataStack; -const cleanCode = require('./utils/clean-code/clean-code').cleanCode; -const safeTrim = require('./utils/safe-trim/safe-trim').safeTrim; -const headReplace = require('./utils/head-replace/head-replace').headReplace; +const { DataStack } = require('./data-stack/data-stack'); +const { cleanCode } = require('./utils/clean-code/clean-code'); +const { safeTrim } = require('./utils/safe-trim/safe-trim'); +const { headReplace } = require('./utils/head-replace/head-replace'); const { fDate, templateDate } = require('./utils/date/date'); +const { countEntities } = require('./utils/count-entities/count-entities'); var conn = ''; // make our connection scope global to script var oidFacility = ""; @@ -53,24 +54,6 @@ function populateTimezones(node, tzOffset, depthCheck) { return node; } -function isOne(who) { - try { - if (who !== null && typeof who === 'object') { - return (Object.prototype.hasOwnProperty.call(who, 'npi') - || Object.prototype.hasOwnProperty.call(who, 'code') - || Object.prototype.hasOwnProperty.call(who, 'extension') - || Object.prototype.hasOwnProperty.call(who, 'id') - || Object.prototype.hasOwnProperty.call(who, 'date') - || Object.prototype.hasOwnProperty.call(who, 'use') - || Object.prototype.hasOwnProperty.call(who, 'type') - ) ? 1 : Object.keys(who).length; - } - } catch (e) { - return false; - } - return 0; -} - function fetchPreviousAddresses(pd) { let addressArray = []; let pa = pd.previous_addresses.address; @@ -93,7 +76,7 @@ function fetchPreviousAddresses(pd) { } } }); - let count = isOne(pa); + let count = countEntities(pa); // how do we ever get here where we just have one object? if (count === 1) { streetLine = [pa.street[0]]; @@ -335,7 +318,7 @@ function populateProviders(all) { // primary provider let provider = populateProvider(all.primary_care_provider.provider); providerArray.push(provider); - let count = isOne(all.care_team.provider); + let count = countEntities(all.care_team.provider); if (count === 1) { provider = populateProvider(all.care_team.provider); providerArray.push(provider); @@ -466,7 +449,7 @@ function populateCareTeamMembers(pd) { if (pd.primary_care_provider) { let provider = populateCareTeamMember(pd.primary_care_provider.provider); providerArray.push(provider); - let count = isOne(pd.care_team.provider); + let count = countEntities(pd.care_team.provider); if (count === 1) { provider = populateCareTeamMember(pd.care_team.provider); providerSince = providerSince || fDate(provider.provider_since); @@ -846,7 +829,7 @@ function populateEncounter(pd) { let theone = {}; let count = 0; try { - count = isOne(pd.encounter_problems.problem); + count = countEntities(pd.encounter_problems.problem); } catch (e) { count = 0; } @@ -1395,7 +1378,7 @@ function getResultSet(results) { let count = 0; many.results = []; try { - count = isOne(results.result); + count = countEntities(results.result); } catch (e) { count = 0; } @@ -1739,7 +1722,7 @@ function getHealthConcerns(pd) { let one = true; let issue_uuid; let problems = [], problem = {}; - if (isOne(pd.issues.issue_uuid) !== 0) { + if (countEntities(pd.issues.issue_uuid) !== 0) { for (let key in pd.issues.issue_uuid) { issue_uuid = pd.issues.issue_uuid[key]; if (issue_uuid) { @@ -2658,7 +2641,7 @@ function populateHeader(pd) { let docParticipants = pd.document_participants || {participant: []}; let count = 0; try { - count = isOne(docParticipants.participant); + count = countEntities(docParticipants.participant); } catch (e) { count = 0 } @@ -2672,7 +2655,7 @@ function populateHeader(pd) { head.participants = participants; } - if (isOne(all.encounter_list.encounter) === 1) { + if (countEntities(all.encounter_list.encounter) === 1) { let primary_care_provider = pd.primary_care_provider || {provider: {}}; head.component_of = { "identifiers": [ @@ -2776,7 +2759,7 @@ function generateCcda(pd) { if (pd.author.time.length > 7) { authorDateTime = pd.author.time; } else if (all.encounter_list && all.encounter_list.encounter) { - if (isOne(all.encounter_list.encounter) === 1) { + if (countEntities(all.encounter_list.encounter) === 1) { authorDateTime = all.encounter_list.encounter.date; } else { authorDateTime = all.encounter_list.encounter[0].date; @@ -2796,7 +2779,7 @@ function generateCcda(pd) { let enc = {}; encs.encounters = []; try { - count = isOne(pd.encounter_list.encounter); + count = countEntities(pd.encounter_list.encounter); } catch (e) { count = 0 } @@ -2817,7 +2800,7 @@ function generateCcda(pd) { let vital = {}; vitals.vitals = []; try { - count = isOne(pd.history_physical.vitals_list.vitals); + count = countEntities(pd.history_physical.vitals_list.vitals); } catch (e) { count = 0 } @@ -2838,7 +2821,7 @@ function generateCcda(pd) { let m = {}; meds.medications = []; try { - count = isOne(pd.medications.medication); + count = countEntities(pd.medications.medication); } catch (e) { count = 0 } @@ -2859,7 +2842,7 @@ function generateCcda(pd) { let allergy = {}; allergies.allergies = []; try { - count = isOne(pd.allergies.allergy); + count = countEntities(pd.allergies.allergy); } catch (e) { count = 0 } @@ -2881,7 +2864,7 @@ function generateCcda(pd) { let problem = {}; problems.problems = []; try { - count = isOne(pd.problem_lists.problem); + count = countEntities(pd.problem_lists.problem); } catch (e) { count = 0 } @@ -2902,7 +2885,7 @@ function generateCcda(pd) { theone = {}; many.procedures = []; try { - count = isOne(pd.procedures.procedure); + count = countEntities(pd.procedures.procedure); } catch (e) { count = 0 } @@ -2923,7 +2906,7 @@ function generateCcda(pd) { theone = {}; many.medical_devices = []; try { - count = isOne(pd.medical_devices.device); + count = countEntities(pd.medical_devices.device); } catch (e) { count = 0 } @@ -2959,7 +2942,7 @@ function generateCcda(pd) { theone = {}; many.health_concerns = []; try { - count = isOne(pd.health_concerns.concern); + count = countEntities(pd.health_concerns.concern); } catch (e) { count = 0 } @@ -2983,7 +2966,7 @@ function generateCcda(pd) { theone = {}; many.immunizations = []; try { - count = isOne(pd.immunizations.immunization); + count = countEntities(pd.immunizations.immunization); } catch (e) { count = 0; } @@ -3004,7 +2987,7 @@ function generateCcda(pd) { theone = {}; many.plan_of_care = []; try { - count = isOne(pd.planofcare.item); + count = countEntities(pd.planofcare.item); } catch (e) { count = 0 } @@ -3033,7 +3016,7 @@ function generateCcda(pd) { theone = {}; many.goals = []; try { - count = isOne(pd.goals.item); + count = countEntities(pd.goals.item); } catch (e) { count = 0 } @@ -3054,7 +3037,7 @@ function generateCcda(pd) { theone = {}; many.clinicalNoteAssessments = []; try { - count = isOne(pd.clinical_notes.evaluation_note); + count = countEntities(pd.clinical_notes.evaluation_note); } catch (e) { count = 0 } @@ -3077,7 +3060,7 @@ function generateCcda(pd) { theone = {}; many.functional_status = []; try { - count = isOne(pd.functional_status.item); + count = countEntities(pd.functional_status.item); } catch (e) { count = 0 } @@ -3099,7 +3082,7 @@ function generateCcda(pd) { theone = {}; many.mental_status = []; try { - count = isOne(pd.mental_status.item); + count = countEntities(pd.mental_status.item); } catch (e) { count = 0 } @@ -3121,7 +3104,7 @@ function generateCcda(pd) { theone = {}; many.social_history = []; try { - count = isOne(pd.history_physical.social_history.history_element); + count = countEntities(pd.history_physical.social_history.history_element); } catch (e) { count = 0 } @@ -3170,7 +3153,7 @@ function generateCcda(pd) { continue; } try { - count = isOne(pd.clinical_notes[currentNote]); + count = countEntities(pd.clinical_notes[currentNote]); } catch (e) { count = 0 } @@ -3249,7 +3232,7 @@ function generateUnstructured(pd) { if (pd.author.time.length > 7) { authorDateTime = pd.author.time; } else if (all.encounter_list && all.encounter_list.encounter) { - if (isOne(all.encounter_list.encounter) === 1) { + if (countEntities(all.encounter_list.encounter) === 1) { authorDateTime = all.encounter_list.encounter.date; } else { authorDateTime = all.encounter_list.encounter[0].date; diff --git a/ccdaservice/utils/count-entities/count-entities.js b/ccdaservice/utils/count-entities/count-entities.js new file mode 100644 index 000000000..d9c7a12eb --- /dev/null +++ b/ccdaservice/utils/count-entities/count-entities.js @@ -0,0 +1,14 @@ +'use strict'; + +function hasEntityKey(input) { + return ['npi', 'code', 'extension', 'id', 'date', 'use', 'type'].some( + (key) => Object.prototype.hasOwnProperty.call(input, key) + ); +} + +function countEntities(input) { + if (input === null || typeof input !== 'object') return 0; + return hasEntityKey(input) ? 1 : Object.keys(input).length; +} + +exports.countEntities = countEntities; diff --git a/ccdaservice/utils/count-entities/count-entities.spec.js b/ccdaservice/utils/count-entities/count-entities.spec.js new file mode 100644 index 000000000..ccd3abfdb --- /dev/null +++ b/ccdaservice/utils/count-entities/count-entities.spec.js @@ -0,0 +1,43 @@ +const { countEntities } = require('./count-entities'); + +describe('countEntities', () => { + test.each([ + { description: 'I only have one value!' }, + { npi: '2.16.840.1.113883.4.6', other: true }, + { code: '409073007', other: false }, + { extension: '45665', other: 10 }, + { id: '47', other: null }, + { date: '2023-09-17', other: {} }, + { use: 'work place', other: [] }, + { type: 'primary home', other: () => true }, + ])('should return 1 if the input represents a single entity', (input) => { + expect(countEntities(input)).toEqual(1); + }); + + test.each([ + [[{ a: 1 }, { b: 2 }, { c: 3 }], 3], + [ + { + description: `I have multiple values inside, but none has an entity key!`, + explode: `Why not?`, + }, + 2, + ], + ])( + 'should return the number of enumerable keys in the object if the input does not represent a single entity', + (input, result) => { + expect(countEntities(input)).toEqual(result); + } + ); + + test.each([null, undefined, 10, true, 'OpenEMR', () => {}])( + 'should return zero if the input is %p', + (input) => { + expect(countEntities(input)).toEqual(0); + } + ); + + it('should return zero if the input is an empty array', () => { + expect(countEntities([])).toEqual(0); + }); +}); -- 2.11.4.GIT