Skip to content

Commit

Permalink
Merge pull request #826 from CMSgov/QPPA-9422-refactor-index
Browse files Browse the repository at this point in the history
QPPA-9422: refactor mvp helper functions
  • Loading branch information
chetanmunegowda authored Aug 26, 2024
2 parents d2b9e07 + ffb64d7 commit 10d2b66
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 83 deletions.
11 changes: 6 additions & 5 deletions index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import YAML from 'yaml';

import * as index from './index';
import { Constants } from './constants';
import * as mvpDataUtils from './util/mvp-data-utils';

const mvpJson = [
{
Expand Down Expand Up @@ -405,7 +406,7 @@ describe('index', () => {
describe('getMVPData', () => {
let createMvpFileSpy: jest.SpyInstance;
beforeEach(() => {
createMvpFileSpy = jest.spyOn(index, 'createMVPDataFile').mockImplementation(() => mvpJson);
createMvpFileSpy = jest.spyOn(mvpDataUtils, 'createMVPDataFile').mockImplementation(() => mvpJson);
});

it('finds and returns the mvp-enriched json file for the specified performance year.', () => {
Expand Down Expand Up @@ -479,7 +480,7 @@ describe('index', () => {
let getSpy: jest.SpyInstance;
beforeEach(() => {
writeSpy = jest.spyOn(fse, 'writeFileSync').mockImplementation(jest.fn());
populateSpy = jest.spyOn(index, 'populateMeasuresforMVPs').mockImplementation(jest.fn());
populateSpy = jest.spyOn(mvpDataUtils, 'populateMeasuresforMVPs').mockImplementation(jest.fn());
getSpy = jest.spyOn(index, 'getMeasuresData').mockReturnValue([
{
measureId: '001',
Expand Down Expand Up @@ -541,7 +542,7 @@ describe('index', () => {
});

it('creates and returns enriched mvp data, updating the mvp-enriched and measures-data files.', () => {
expect(index.createMVPDataFile(2024)).toStrictEqual([
expect(mvpDataUtils.createMVPDataFile(2024)).toStrictEqual([
{
mvpId: 'G0053',
clinicalTopic: 'Stroke Care and Prevention',
Expand Down Expand Up @@ -590,7 +591,7 @@ describe('index', () => {
'mvp/2024': {},
});

expect(index.createMVPDataFile(2024)).toStrictEqual([]);
expect(mvpDataUtils.createMVPDataFile(2024)).toStrictEqual([]);
expect(logSpy).toBeCalled();
expect(writeSpy).not.toBeCalled();
expect(populateSpy).not.toBeCalled();
Expand Down Expand Up @@ -623,7 +624,7 @@ describe('index', () => {

it('successfully populates the mvp', () => {
const testMvp = { ...mvpJson[0], qualityMeasureIds: ['001', '321'], qualityMeasures: [] };
index.populateMeasuresforMVPs(testMvp, mvpJson, testMeasuresData, 'qualityMeasureIds', 'qualityMeasures');
mvpDataUtils.populateMeasuresforMVPs(testMvp, mvpJson, testMeasuresData, 'qualityMeasureIds', 'qualityMeasures');

expect(testMvp).toStrictEqual({
mvpId: 'G0053',
Expand Down
81 changes: 3 additions & 78 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
import * as fse from 'fs-extra';
import * as path from 'path';
import * as YAML from 'yaml';
import * as _ from 'lodash';
import { Constants } from './constants';
import { createMVPDataFile } from './util/mvp-data-utils';


const yearRegEx = /^[0-9]{4}/;
const benchmarkJsonFileRegEx = /^[0-9]{4}\.json$/;
Expand Down Expand Up @@ -175,7 +176,7 @@ export function getMVPData(performanceYear: number = 2023, mvpIds: string[] = []
if (fse.existsSync(filePath)) {
mvpData = JSON.parse(fse.readFileSync(filePath, 'utf8'));
} else {
mvpData = exports.createMVPDataFile(performanceYear);
mvpData = createMVPDataFile(performanceYear);
}

if (mvpIds.length) {
Expand All @@ -185,82 +186,6 @@ export function getMVPData(performanceYear: number = 2023, mvpIds: string[] = []
return mvpData;
}

/**
* @return {any}
*/
export function createMVPDataFile(performanceYear: number): any {
const mvpFilePath = path.join(__dirname, 'mvp', performanceYear.toString(), 'mvp-enriched.json');
const measureFilePath = path.join(__dirname, 'measures', performanceYear.toString(), 'measures-data.json');

let mvpData: any[] = [];
let measuresData: any[] = [];
try {
mvpData = JSON.parse(
fse.readFileSync(path.join(__dirname, 'mvp', performanceYear.toString(), 'mvp.json'), 'utf8'));
measuresData = exports.getMeasuresData(performanceYear);
} catch (e) {
console.log('QPP mvp / measures data not found for year: ' + performanceYear + ' --> ' + e);
return [];
}

const mvpIds: any[] = [];
mvpData.forEach(mvpDataItem => {
if (mvpDataItem.mvpId !== 'app1') {
mvpIds.push(mvpDataItem.mvpId);
}
});

// Reset the allowedPrograms to remove any MVP ID program names (we will add them back later in the process)
// This allows for removal of a measure from an MVP data item
measuresData.forEach(measure => {
measure.allowedPrograms = measure.allowedPrograms ? measure.allowedPrograms.filter(program => !mvpIds.includes(program)) : [];
});

// Hydrate measures
mvpData.forEach(mvp => {
Constants.mvpMeasuresHelper.forEach(item => {
mvp[item.enrichedMeasureKey] = [];
exports.populateMeasuresforMVPs(mvp, mvpData, measuresData, item.measureIdKey, item.enrichedMeasureKey);
});

mvp.hasOutcomeAdminClaims = !_.isEmpty(mvp.administrativeClaimsMeasureIds);
});

mvpData.forEach(mvp => {
Constants.mvpMeasuresHelper.forEach(item => {
delete mvp[item.measureIdKey];
});
});

fse.writeFileSync(mvpFilePath, JSON.stringify(mvpData, null, 2));
fse.writeFileSync(measureFilePath, JSON.stringify(measuresData, null, 2));

return mvpData;
}

export function populateMeasuresforMVPs(currentMvp: any, allMvps: any[], measuresData: any[], measureIdKey: string, enrichedMeasureKey: string): void {
currentMvp[measureIdKey].forEach((measureId: string) => {
const measure = measuresData.find(measure => measure.measureId === measureId);

if (measure) {
allMvps.forEach(mvp => {
// update measuresData with MVP programNames.
if (mvp[measureIdKey].includes(measureId)) {
measure.allowedPrograms.push(mvp.mvpId);
}
});
measure.allowedPrograms = _.uniq(measure.allowedPrograms);

if (measure.measureId === '321') {
currentMvp.hasCahps = true;
}

// update mvp-data with measures.
currentMvp[enrichedMeasureKey].push(measure);
}
});
}

/**
* @return {any} - Object representation of the MVP Schema
*/
Expand Down
85 changes: 85 additions & 0 deletions util/mvp-data-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import * as fse from 'fs-extra';
import * as path from 'path';
import * as _ from 'lodash';
import { Constants } from '../constants';
import { getMeasuresData } from '../index';

export function createMVPDataFile(performanceYear: number): any {
const basePath = path.resolve(__dirname, '..');
const mvpFilePath = path.join(basePath, 'mvp', performanceYear.toString(), 'mvp-enriched.json');
const measureFilePath = path.join(basePath, 'measures', performanceYear.toString(), 'measures-data.json');

let mvpData: any[] = [];
let measuresData: any[] = [];
try {
mvpData = JSON.parse(
fse.readFileSync(path.join(basePath, 'mvp', performanceYear.toString(), 'mvp.json'), 'utf8'));
measuresData = getMeasuresData(performanceYear);
} catch (e) {
console.log('QPP mvp / measures data not found for year: ' + performanceYear + ' --> ' + e);
return [];
}

const mvpIds: any[] = [];
mvpData.forEach(mvpDataItem => {
if (mvpDataItem.mvpId !== 'app1') {
mvpIds.push(mvpDataItem.mvpId);
}
});

// Reset the allowedPrograms to remove any MVP ID program names (we will add them back later in the process)
// This allows for removal of a measure from an MVP data item
measuresData.forEach(measure => {
measure.allowedPrograms = measure.allowedPrograms ? measure.allowedPrograms.filter(program => !mvpIds.includes(program)) : [];
});

// Hydrate measures
mvpData.forEach(mvp => {
Constants.mvpMeasuresHelper.forEach(item => {
mvp[item.enrichedMeasureKey] = [];
exports.populateMeasuresforMVPs(mvp, mvpData, measuresData, item.measureIdKey, item.enrichedMeasureKey);
});

mvp.hasOutcomeAdminClaims = !_.isEmpty(mvp.administrativeClaimsMeasureIds);
});

mvpData.forEach(mvp => {
Constants.mvpMeasuresHelper.forEach(item => {
delete mvp[item.measureIdKey];
});
});

fse.writeFileSync(mvpFilePath, JSON.stringify(mvpData, null, 2));
fse.writeFileSync(measureFilePath, JSON.stringify(measuresData, null, 2));

return mvpData;
}

export function populateMeasuresforMVPs(
currentMvp: any,
allMvps: any[],
measuresData: any[],
measureIdKey: string,
enrichedMeasureKey: string
): void {
currentMvp[measureIdKey].forEach((measureId: string) => {
const measure = measuresData.find(measure => measure.measureId === measureId);

if (measure) {
allMvps.forEach(mvp => {
// update measuresData with MVP programNames.
if (mvp[measureIdKey].includes(measureId)) {
measure.allowedPrograms.push(mvp.mvpId);
}
});
measure.allowedPrograms = _.uniq(measure.allowedPrograms);

if (measure.measureId === '321') {
currentMvp.hasCahps = true;
}

// update mvp-data with measures.
currentMvp[enrichedMeasureKey].push(measure);
}
});
}

0 comments on commit 10d2b66

Please sign in to comment.