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

fqm-e bump to 1.3.1 and update Docker setup #140

Merged
merged 10 commits into from
Sep 13, 2023
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
connectathon
ecqm-content-r4-2021
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:14
FROM node:16

# Create app directory
WORKDIR /usr/src/app
Expand Down
4 changes: 2 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ services:
NDJSON_WORKERS: 2
REDIS_HOST: redis
REDIS_PORT: 6379
VALIDATE: "false"
VALIDATE: 'false'
VALIDATOR_HOST: validator
VALIDATOR_PORT: 4567
ports:
Expand All @@ -31,7 +31,7 @@ services:
tty: true

mongo:
image: mongo:4.4.4
image: mongo:6.0
ports:
- '27017'
volumes:
Expand Down
6,390 changes: 3,488 additions & 2,902 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"cql-exec-fhir-mongo": "git+https://[email protected]/projecttacoma/cql-exec-fhir-mongo",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"fqm-execution": "^1.0.5",
"fqm-execution": "^1.3.1",
"lodash": "^4.17.21",
"mongodb": "^4.1.3",
"uuid": "^8.3.2",
Expand All @@ -54,4 +54,4 @@
"./test/globalSetup.js"
]
}
}
}
8 changes: 7 additions & 1 deletion src/queue/execQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,18 @@ class ScaledCalculation {
}

this._measureBundle = measureBundle;
const measureEntry = measureBundle.entry.find(e => e.resource.resourceType === 'Measure');
if (measureEntry) {
this._measure = measureEntry.resource;
} else {
throw new Error('Measure resource was not found in bundle.');
}
this._periodStart = periodStart;
this._periodEnd = periodEnd;

// Prepare the fqm-execution measure report builder
try {
this._mrBuilder = new MeasureReportBuilder(this._measureBundle, {
this._mrBuilder = new MeasureReportBuilder(this._measure, {
measurementPeriodStart: this._periodStart,
measurementPeriodEnd: this._periodEnd,
reportType: 'summary'
Expand Down
15 changes: 13 additions & 2 deletions src/scripts/uploadPremadeBundles.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const fs = require('fs');
const path = require('path');
const mongoUtil = require('../database/connection');
const { createResource } = require('../database/dbOperations');
const { randomUUID } = require('crypto');

const ecqmContentR4Path = path.resolve(path.join(__dirname, '../../ecqm-content-r4-2021/bundles/measure/'));

Expand Down Expand Up @@ -84,7 +85,7 @@ async function main() {
} else {
try {
if (!searchPattern) {
searchPattern = /^[A-Z].*-bundle.json$/;
searchPattern = /^[A-Z].*.json$/;
elsaperelli marked this conversation as resolved.
Show resolved Hide resolved
}
console.log(`Finding bundles in ecqm-content-r4-2021 repo at ${ecqmContentR4Path}.`);
getEcqmBundleFiles(ecqmContentR4Path, searchPattern);
Expand All @@ -100,11 +101,21 @@ async function main() {
// 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);
if (bundle.resourceType !== 'Bundle') {
console.log(`Skipping ${filePath.split('/').slice(-1)} NOT A BUNDLE`);
continue;
}
//console.log(`Uploading ${filePath.split('/').slice(-1)}...`);

// retrieve each resource and insert into database
const uploads = bundle.entry.map(async res => {
try {
// If there is no ID... make one probably MADiE Bundle Measure
if (!res.resource.id) {
res.resource.id = filePath.split('/').slice(-1)[0].split('-')[0] || randomUUID();
hossenlopp marked this conversation as resolved.
Show resolved Hide resolved
console.log(`Gave ${res.resource.resourceType} an ID of ${res.resource.id}`);
}
await createResource(res.resource, res.resource.resourceType);
resourcesUploaded += 1;
} catch (e) {
Expand Down
2 changes: 1 addition & 1 deletion src/services/measure.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ const evaluateMeasure = async (args, { req }) => {
const { reportType, subject } = req.query;

// If reportType is not specified, default to 'subject', but
// only if the 'subject' parameter is also specificed
// only if the 'subject' parameter is also specified
if (reportType === 'subject' || (reportType == null && subject != null)) {
logger.debug('Evaluating measure for individual');
return evaluateMeasureForIndividual(args, { req });
Expand Down
14 changes: 9 additions & 5 deletions src/util/bundleUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,12 @@ async function getDependentValueSets(lib) {
}

const depValueSetUrls = lib.relatedArtifact
.filter(ra => ra.type === 'depends-on' && ra.resource.includes('ValueSet'))
.map(ra => ra.resource);
.filter(
ra =>
ra.type === 'depends-on' &&
((ra.resource && ra.resource.includes('ValueSet')) || (ra.url && ra.url.includes('ValueSet')))
hossenlopp marked this conversation as resolved.
Show resolved Hide resolved
)
.map(ra => ra.resource || ra.url);

const valueSetGets = depValueSetUrls.map(async url => {
const vsQuery = getQueryFromReference(url);
Expand Down Expand Up @@ -180,10 +184,10 @@ async function getAllDependentLibraries(lib) {
.filter(
ra =>
ra.type === 'depends-on' &&
ra.resource.includes('Library') &&
(ra.resource?.includes('Library') || ra.url?.includes('Library')) &&
hossenlopp marked this conversation as resolved.
Show resolved Hide resolved
ra.resource !== 'http://fhir.org/guides/cqf/common/Library/FHIR-ModelInfo|4.0.1'
) // exclude modelinfo dependency
.map(ra => ra.resource);
.map(ra => ra.resource || ra.url);
// Obtain all libraries referenced in the related artifact, and recurse on their dependencies
const libraryGets = depLibUrls.map(async url => {
// Quick fix for invalid connectathon url references
Expand Down Expand Up @@ -225,7 +229,7 @@ function replaceReferences(entries) {
// Add metadata for old IDs and newly created ones of POST entries
entries.forEach(e => {
logger.debug(`Replacing resourceIds for entry: ${JSON.stringify(e)}`);
if (e.request.method === 'POST') {
if (!e.request || e.request.method === 'POST') {
hossenlopp marked this conversation as resolved.
Show resolved Hide resolved
e.isPost = true;
e.oldId = e.resource.id;
e.newId = uuidv4();
Expand Down
2 changes: 1 addition & 1 deletion test/queue/execQueue.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ describe('execQueue', () => {
'2019-01-01',
'2019-12-31'
);
}).toThrow('Could not prepare report builder:');
}).toThrow('Measure resource was not found in bundle.');
});

test('Throws an error if scaled calculation is disabled', () => {
Expand Down
5 changes: 3 additions & 2 deletions test/services/base.service.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ describe('base.service', () => {
url: expect.stringMatching(/\/4_0_1\/Patient\?page=1$/)
}
]);
expect(response.body.entry[0].resource.id).toEqual(testPatient.id);
expect(response.body.entry[0].resource.resourceType).toEqual('Patient');
const testPatientEntry = response.body.entry.find(e => e.resource.id === testPatient.id);
expect(testPatientEntry).toBeDefined();
expect(testPatientEntry.resource.resourceType).toEqual('Patient');
});
});

Expand Down
Loading