-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuploadPremadeBundles.js
More file actions
140 lines (133 loc) · 5.11 KB
/
Copy pathuploadPremadeBundles.js
File metadata and controls
140 lines (133 loc) · 5.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
const fs = require('fs');
const path = require('path');
const mongoUtil = require('../util/mongo');
const { createResource } = require('../util/mongo.controller');
const { createPatientGroupsPerMeasure } = require('../util/groupUtils');
const ecqmContentR4Path = path.resolve(path.join(__dirname, '../../ecqm-content-qicore-2025/bundles/measure/'));
// files containing EXM bundles of interest from specified directory
const bundleFiles = [];
/**
* Retrieves all measure bundle files from the passed in directory that match the passed in regex
* Uses recursion to parse through all available subdirectories.
* @param {string} directory - directory path to start at
* @param {string} searchPattern - regex to match potential measure bundle files against
* @returns {Array} array of string paths that represent the bundle files of interest
*/
const getEcqmBundleFiles = (directory, searchPattern) => {
const fileNameRegExp = new RegExp(searchPattern);
const filesInDirectory = fs.readdirSync(directory);
filesInDirectory.forEach(file => {
const absolute = path.join(directory, file);
if (fs.statSync(absolute).isDirectory()) {
getEcqmBundleFiles(absolute, searchPattern);
} else if (fileNameRegExp.test(file)) {
bundleFiles.push(absolute);
}
});
};
/**
* Retrieves bundle files from arbitrary folder using a regular expression.
* Uses recursion to parse through all available subdirectories.
* @param {string} directory - directory path to start a
* @param {string} searchPattern - regex to match potential measure bundle files against
* @returns {Array} array of string paths that represent the bundle files of interest
*/
const getBundleFiles = (directory, searchPattern) => {
const fileNameRegExp = new RegExp(searchPattern);
const filesInDirectory = fs.readdirSync(directory);
filesInDirectory.forEach(file => {
const absolute = path.join(directory, file);
if (fs.statSync(absolute).isDirectory()) {
getBundleFiles(absolute, searchPattern);
} else if (
fileNameRegExp.test(file) &&
!file.endsWith('MeasureReport.json') &&
!file.endsWith('measure-report.json')
) {
bundleFiles.push(absolute);
}
});
};
/**
* Uploads all the resources from the specified directory into the
* database.
*
* TODO: Currently configured for ecqm-content-qicore-2025 measure bundles,
* but may want to expand to other measure bundle providers in the future.
*/
async function main() {
await mongoUtil.client.connect();
console.log('Connected successfully to server');
let searchPattern;
if (process.argv[3]) {
searchPattern = process.argv[3];
}
if (process.argv[2]) {
// if a path is provided
const bundlePath = path.resolve(process.argv[2]);
try {
if (!searchPattern) {
searchPattern = /.json$/;
}
console.log(`Finding bundles in ${bundlePath}.`);
getBundleFiles(bundlePath, searchPattern);
} catch {
throw new Error('Provided directory not found.');
}
// otherwise load from ecqm-content-qicore-2025
} else {
try {
if (!searchPattern) {
// default searchPattern to retrieve all filenames that begin with a capital letter and end with -bundle.json
searchPattern = /^[A-Z].*-bundle.json$/;
}
console.log(`Finding bundles in ecqm-content-qicore-2025 repo at ${ecqmContentR4Path}.`);
getEcqmBundleFiles(ecqmContentR4Path, searchPattern);
} catch {
throw new Error(
'ecqm-content-qicore-2025 directory not found. Git clone the ecqm-content-qicore-2025 repo into the root directory and run script again'
);
}
}
let filesUploaded = 0;
let resourcesUploaded = 0;
const measureToPatientsMap = {};
for (const filePath of bundleFiles) {
// read each EXM bundle file
const data = fs.readFileSync(filePath, 'utf8');
if (data) {
console.log(`Uploading ${filePath.split('/').slice(-1)}...`);
const bundle = JSON.parse(data);
// retrieve each resource and insert into database
const measureId = bundle.entry.find(e => e.resource.resourceType === 'Measure').resource.id;
measureToPatientsMap[measureId] = [];
for (const res of bundle.entry) {
try {
if (res.resource.resourceType === 'Patient') {
measureToPatientsMap[measureId].push(res.resource.id);
}
await createResource(res.resource, res.resource.resourceType);
resourcesUploaded += 1;
} catch (e) {
// ignore duplicate key errors for Libraries, ValueSets
if (e.code !== 11000 || res.resource.resourceType === 'Measure') {
console.log(e.message);
}
}
}
filesUploaded += 1;
}
}
let groupsCreated = 0;
for (const [measureId, patientIds] of Object.entries(measureToPatientsMap)) {
const success = await createPatientGroupsPerMeasure(measureId, patientIds);
if (success) {
groupsCreated += 1;
}
}
return `${resourcesUploaded} resources uploaded from ${filesUploaded} Bundle files. ${groupsCreated} Groups created.`;
}
main()
.then(console.log)
.catch(console.error)
.finally(async () => await mongoUtil.client.close());