Skip to content

Commit

Permalink
Merge pull request #704 from CMSgov/feat/QPPA-7860
Browse files Browse the repository at this point in the history
QPPA-7860: Add new benchmark build script
  • Loading branch information
ckawell-sb authored Aug 21, 2023
2 parents 243e87f + ec7b966 commit 1dfddd0
Show file tree
Hide file tree
Showing 12 changed files with 94 additions and 928 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@
"update:measures": "scripts/measures/update-measures",
"build:measures": "scripts/measures/build-measures",
"build:benchmarks": "scripts/benchmarks/archive/build-benchmarks",
"update:benchmarks": "scripts/benchmarks/build-benchmarks",
"build:clinical-clusters": "scripts/clinical-clusters/build-clinical-clusters",
"update:mvp": "scripts/mvp/update-mvp",
"parse:mvp": "scripts/mvp/parse-mvp-data",
"export:measures": "scripts/measures/export-measures",
"pretest": "eslint test util scripts index.js",
"pretest": "eslint test scripts index.js",
"pre-commit": "tools/pre-commit.sh",
"jest:cov": "TS_NODE_FILES=true NODE_OPTIONS='--max-old-space-size=3072' jest --coverage --coverage-prodivder=v8 --runInBand"
},
Expand Down
2 changes: 1 addition & 1 deletion scripts/benchmarks/archive/format-benchmark-record.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// Libraries
const keyBy = require('lodash/keyBy');
// Data
const isInverseBenchmarkRecord = require('../../../util/benchmarks/is-inverse-benchmark-record');
const isInverseBenchmarkRecord = require('./is-inverse-benchmark-record');

const Constants = require('../../../constants.js');

Expand Down
8 changes: 4 additions & 4 deletions scripts/benchmarks/benchmarks.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,10 @@ export enum Method {
}

export type Benchmark = {
measureId?: string,
benchmarkYear?: number,
performanceYear?: number,
submissionMethod?: string,
measureId: string,
benchmarkYear: number,
performanceYear: number,
submissionMethod: string,
isToppedOut?: boolean,
isHighPriority?: boolean,
isInverse?: boolean,
Expand Down
60 changes: 60 additions & 0 deletions scripts/benchmarks/build-benchmarks
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env bash

currentPerformanceYear=$(($1))
maxPerformanceYear=2023

Red='\033[0;31m'
Green='\033[0;32m'
bold=$(tput bold)

# checks the exit code of the last command and exits if not successful code 0.
function exitOnFailure () {
if (( $? != 0 )); then
echo -e "${Red}\n${bold}Update failed."
exit
fi
}

# This script is not made to work for years prior to 2023.
if (( $currentPerformanceYear >= 2023 )) && (( $currentPerformanceYear <= $maxPerformanceYear )); then

echo -e "Compiling Typescript..."
tsc -p .


# Convert all CSV benchmark files to JSON.
for FILE in staging/$currentPerformanceYear/benchmarks/*; do
re='^(.+\/)*(.+)\.(.+)$'
if [[ $FILE =~ $re ]]; then
echo -e "Converting $FILE.csv to JSON..."
node dist/scripts/benchmarks/csv-json-converter.js \
staging/$currentPerformanceYear/benchmarks/${BASH_REMATCH[2]}.csv $currentPerformanceYear \
> staging/$currentPerformanceYear/benchmarks/json/${BASH_REMATCH[2]}.json

# validate the JSON files before combining
node dist/scripts/benchmarks/validation.business.js \
${BASH_REMATCH[2]}.json $currentPerformanceYear

exitOnFailure
fi
done


# merge all benchmark files into one.
echo -e "Merging individual JSON files..."
node dist/scripts/benchmarks/merge-benchmark-files.js \
staging/$currentPerformanceYear/benchmarks/json/ \
> ./benchmarks/$currentPerformanceYear.json


# Validate benchmarks.
echo -e "Validating new benchmarks JSON."
cat benchmarks/$currentPerformanceYear.json | node scripts/validate-data.js benchmarks $currentPerformanceYear
exitOnFailure

echo -e "${Green}\n${bold}Update complete."
exit

else
echo -e "${Red}${bold}Performance year ${currentPerformanceYear} not valid."
fi
6 changes: 5 additions & 1 deletion scripts/benchmarks/merge-benchmark-files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import fs from 'fs';
import path from 'path';
import appRoot from 'app-root-path';

import { Benchmark } from './csv-json-converter';
import { Benchmark } from './benchmarks.types';

// command to use this file:
// node ./dist/benchmarks/merge-benchmark-files.js ./util/2023/benchmarks/json/ > ./benchmarks/2023.json
Expand All @@ -17,6 +17,10 @@ function mergeBenchmarkFiles(benchmarksPath: string) {
const jsonFile = JSON.parse(
fs.readFileSync(path.join(appRoot + '', `${benchmarksPath}${fileName}`), 'utf8')
);
//remove the deciles column (which is still sometimes included in 3rd party files)
jsonFile.forEach(measure => {
delete measure.deciles;
});
combinedBenchmarks.push(...jsonFile);
});

Expand Down
6 changes: 3 additions & 3 deletions scripts/benchmarks/validation.business.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import mockFS from 'mock-fs';
import * as logger from '../logger'

import { benchmarkBusinessValidation } from './validation.business';
import { BaseMeasure, Benchmark, BenchmarkList, MeasureList } from './benchmarks.types';
import { BaseMeasure, Benchmark } from './benchmarks.types';

const measuresJson: BaseMeasure[] = JSON.parse(
fs.readFileSync(path.join(appRoot + '', 'measures/2023/measures-data.json'), 'utf8')
Expand Down Expand Up @@ -49,7 +49,7 @@ describe('validation.business', () => {
modifiedBenchmarks,
volatileBenchmarksCahps
);
benchmarkBusinessValidation(2023);
benchmarkBusinessValidation('benchmarks.json', 2023);

expect('').toBe('No error thrown when one expected');
} catch (errors: any) {
Expand All @@ -76,7 +76,7 @@ describe('validation.business', () => {
});

it('validates 2023 benchmarks data', () => {
const result = benchmarkBusinessValidation(2023);
const result = benchmarkBusinessValidation('benchmarks.json', 2023);

expect(logSpy).not.toBeCalled();
expect(result).toBeFalsy();
Expand Down
38 changes: 17 additions & 21 deletions scripts/benchmarks/validation.business.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,39 @@
import _ from 'lodash';
import { Benchmark, BenchmarkList, QualityMeasure } from './benchmarks.types';
import {
import {
BaseMeasure,
MeasureList,
} from './benchmarks.types';
import path from 'path';
import appRoot from 'app-root-path';
import fs from 'fs';

function readStagingJSONFile (fileName: string, performanceYear: number) {
function readStagingJSONFile(fileName: string, performanceYear: number) {
const benchmarksStagingJSONDirectory = appRoot + `/staging/${performanceYear}/benchmarks/json`

return JSON.parse(
fs.readFileSync(path.join(benchmarksStagingJSONDirectory + '', fileName), 'utf8')
) as BenchmarkList;
}

export function benchmarkBusinessValidation(performanceYear: number, input?: BenchmarkList) {
let rawInput, rawInputCahps;
export function benchmarkBusinessValidation(jsonName: string, performanceYear: number) {
let errors: Error[] = [];
let indexedBenchmarks: BenchmarkList;

if (!input) {
rawInputCahps = readStagingJSONFile('benchmarks_cahps.json', performanceYear);
rawInput = readStagingJSONFile('benchmarks.json', performanceYear);

rawInput = rawInput.concat(rawInputCahps);
indexedBenchmarks = readStagingJSONFile(jsonName, performanceYear);
indexedBenchmarks = _.mapKeys(indexedBenchmarks, ((benchmark: Benchmark) => {
if (!benchmark.measureId) {
errors.push(new Error(`no MeasureId provided for benchmark: ${JSON.stringify(benchmark)}`));
return;
}

input = _.mapKeys(rawInput, ((benchmark: Benchmark) => {
if (!benchmark.measureId) {
errors.push(new Error(`no MeasureId provided for benchmark: ${JSON.stringify(benchmark)}`));
return;
}

return benchmark.measureId;
})
)
}
return benchmark.measureId;
}));

if (errors.length > 0) {
throw errors;
}

const indexedBenchmarks: BenchmarkList = input;

const measures: BaseMeasure[] = JSON.parse(
fs.readFileSync(path.join(appRoot + '', `measures/${performanceYear}/measures-data.json`), 'utf8')
Expand Down Expand Up @@ -92,4 +84,8 @@ export function benchmarkBusinessValidation(performanceYear: number, input?: Ben
if (errors.length > 0) {
throw errors;
}
}
}

/* istanbul ignore next */
if (process.argv[2] && process.argv[2] !== '--coverage')
benchmarkBusinessValidation(process.argv[2], parseInt(process.argv[3]));
2 changes: 1 addition & 1 deletion staging/2023/benchmarks/benchmarks_cahps.csv
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
measureName,qualityId,submissionMethod,measureType,benchmark,standardDeviation,average,decile1,decile2,decile3,decile4,decile5,decile6,decile7,decile8,decile9,decile10,isToppedOut,isToppedOutByProgram,percentile1,percentile10,percentile20,percentile30,percentile40,percentile50,percentile60,percentile70,percentile80,percentile90,percentile99,isHighPriority,isInverse,metricType
measureName,measureId,submissionMethod,measureType,benchmark,standardDeviation,average,decile1,decile2,decile3,decile4,decile5,decile6,decile7,decile8,decile9,decile10,isToppedOut,isToppedOutByProgram,percentile1,percentile10,percentile20,percentile30,percentile40,percentile50,percentile60,percentile70,percentile80,percentile90,percentile99,isHighPriority,isInverse,metricType
CAHPS for MIPS SSM: Stewardship of Patient Resources,CAHPS_11,CAHPS Survey Vendor,Patient Engagement/Experience,Y,,,<18.60,18.60 - 20.18,20.19 - 21.75,21.76 - 23.13,23.14 - 24.42,24.43 - 25.47,25.48 - 26.68,26.69 - 28.26,28.27 - 30.13,>= 30.14,N,,,,,,,,,,,,,Y,,cahps
CAHPS for MIPS SSM: Patient’s Rating of Provider,CAHPS_3,CAHPS Survey Vendor,Patient Engagement/Experience,Y,,,<89.93,89.93 - 90.81,90.82 - 91.45,91.46 - 91.79,91.80 - 92.23,92.24 - 92.61,92.62 - 93.00,93.01 - 93.42,93.43 - 93.98,>= 93.99,N,,,,,,,,,,,,,Y,,cahps
"CAHPS for MIPS SSM: Getting Timely Care, Appointments and Information",CAHPS_1,CAHPS Survey Vendor,Patient Engagement/Experience,Y,,,<79.09,79.09 - 81.41,81.42 - 82.74,82.75 - 83.95,83.96 - 84.83,84.84 - 85.69,85.70 - 86.43,86.44 - 87.46,87.47 - 88.60,>= 88.61,N,,,,,,,,,,,,,Y,,cahps
Expand Down
2 changes: 1 addition & 1 deletion test/util/benchmarks/is-inverse-benchmark-record-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
const chai = require('chai');
const assert = chai.assert;
// Utils
const isInverseBenchmarkRecord = require('./../../../util/benchmarks/is-inverse-benchmark-record');
const isInverseBenchmarkRecord = require('../../../scripts/benchmarks/archive/is-inverse-benchmark-record');

describe('isInverseBenchmarkRecord', function() {
it('should default to false', function() {
Expand Down
Loading

0 comments on commit 1dfddd0

Please sign in to comment.