Skip to content

Commit 2e4e350

Browse files
authored
Merge pull request #140 from mcode/csv-read-from-url
Csv read from url
2 parents e2f32ee + f8e89de commit 2e4e350

26 files changed

+391
-194
lines changed

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"dependencies": {
2424
"ajv": "^6.12.6",
2525
"antlr4": "4.8.0",
26+
"axios": "^0.21.1",
2627
"commander": "^6.2.0",
2728
"csv-parse": "^4.8.8",
2829
"fhir-crud-client": "^1.2.2",

src/client/BaseClient.js

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -25,32 +25,37 @@ class BaseClient {
2525
}
2626

2727
// Given an extractor configuration, initialize all the necessary extractors
28-
initializeExtractors(extractorConfig, commonExtractorArgs) {
29-
let allExtractorsValid = true;
30-
28+
async initializeExtractors(extractorConfig, commonExtractorArgs) {
29+
// Loop to initialize the extractors
3130
extractorConfig.forEach((curExtractorConfig) => {
3231
const { label, type, constructorArgs } = curExtractorConfig;
3332
logger.debug(`Initializing ${label} extractor with type ${type}`);
3433
const ExtractorClass = this.extractorClasses[type];
35-
3634
try {
3735
const newExtractor = new ExtractorClass({ ...commonExtractorArgs, ...constructorArgs });
38-
39-
if (newExtractor.validate) {
40-
const isExtractorValid = newExtractor.validate();
41-
allExtractorsValid = (allExtractorsValid && isExtractorValid);
42-
if (isExtractorValid) {
43-
logger.debug(`Extractor ${label} PASSED CSV validation`);
44-
} else {
45-
logger.debug(`Extractor ${label} FAILED CSV validation`);
46-
}
47-
}
48-
4936
this.extractors.push(newExtractor);
5037
} catch (e) {
5138
throw new Error(`Unable to initialize ${label} extractor with type ${type}: ${e.message}`);
5239
}
5340
});
41+
// For validation, we are looping over extractors and performing an async operation on each.
42+
// We need to loop without forEach (since forEach is sequential).
43+
// Using Reduce to compute the validity of all extractors
44+
const allExtractorsValid = await this.extractors.reduce(async (curExtractorsValid, curExtractor) => {
45+
const { name } = curExtractor.constructor;
46+
47+
if (curExtractor.validate) {
48+
logger.debug(`Validating ${name}`);
49+
const isExtractorValid = await curExtractor.validate();
50+
if (isExtractorValid) {
51+
logger.debug(`Extractor ${name} PASSED CSV validation`);
52+
} else {
53+
logger.warn(`Extractor ${name} FAILED CSV validation`);
54+
}
55+
return (curExtractorsValid && isExtractorValid);
56+
}
57+
return curExtractorsValid;
58+
}, true);
5459

5560
if (allExtractorsValid) {
5661
logger.info('Validation succeeded');

src/extractors/BaseCSVExtractor.js

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
1-
const path = require('path');
21
const { Extractor } = require('./Extractor');
3-
const { CSVModule } = require('../modules');
4-
const { validateCSV } = require('../helpers/csvValidator');
5-
const logger = require('../helpers/logger');
2+
const { CSVFileModule, CSVURLModule } = require('../modules');
63

74
class BaseCSVExtractor extends Extractor {
8-
constructor({ filePath, csvSchema, unalterableColumns }) {
5+
constructor({ filePath, url, csvSchema, unalterableColumns }) {
96
super();
107
this.unalterableColumns = unalterableColumns || [];
118
this.csvSchema = csvSchema;
12-
this.filePath = path.resolve(filePath);
13-
this.csvModule = new CSVModule(this.filePath, this.unalterableColumns);
9+
if (url) {
10+
this.url = url;
11+
this.csvModule = new CSVURLModule(this.url, this.unalterableColumns);
12+
} else if (filePath) {
13+
this.filePath = filePath;
14+
this.csvModule = new CSVFileModule(this.filePath, this.unalterableColumns);
15+
} else {
16+
throw new Error('Trying to instantiate a CSVExtractor without a filePath or url');
17+
}
1418
}
1519

16-
validate() {
17-
if (this.csvSchema) {
18-
logger.info(`Validating CSV file for ${this.filePath}`);
19-
return validateCSV(this.filePath, this.csvSchema, this.csvModule.data);
20-
}
21-
logger.warn(`No CSV schema provided for ${this.filePath}`);
22-
return true;
20+
async validate() {
21+
return this.csvModule.validate(this.csvSchema);
2322
}
2423
}
2524

src/extractors/CSVAdverseEventExtractor.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ function formatData(adverseEventData, patientId) {
6969
}
7070

7171
class CSVAdverseEventExtractor extends BaseCSVExtractor {
72-
constructor({ filePath }) {
73-
super({ filePath });
72+
constructor({ filePath, url }) {
73+
super({ filePath, url });
7474
}
7575

7676
async getAdverseEventData(mrn) {

src/extractors/CSVCancerDiseaseStatusExtractor.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ const logger = require('../helpers/logger');
88
const { CSVCancerDiseaseStatusSchema } = require('../helpers/schemas/csv');
99

1010
class CSVCancerDiseaseStatusExtractor extends BaseCSVExtractor {
11-
constructor({ filePath, implementation }) {
12-
super({ filePath, csvSchema: CSVCancerDiseaseStatusSchema });
11+
constructor({ filePath, url, implementation }) {
12+
super({ filePath, url, csvSchema: CSVCancerDiseaseStatusSchema });
1313
this.implementation = implementation;
1414
}
1515

src/extractors/CSVCancerRelatedMedicationExtractor.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ function formatData(medicationData, patientId) {
4646
}
4747

4848
class CSVCancerRelatedMedicationExtractor extends BaseCSVExtractor {
49-
constructor({ filePath }) {
50-
super({ filePath });
49+
constructor({ filePath, url }) {
50+
super({ filePath, url });
5151
}
5252

5353
async getMedicationData(mrn) {

src/extractors/CSVClinicalTrialInformationExtractor.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ const { CSVClinicalTrialInformationSchema } = require('../helpers/schemas/csv');
88

99

1010
class CSVClinicalTrialInformationExtractor extends BaseCSVExtractor {
11-
constructor({ filePath, clinicalSiteID, clinicalSiteSystem }) {
12-
super({ filePath, csvSchema: CSVClinicalTrialInformationSchema });
11+
constructor({ filePath, url, clinicalSiteID, clinicalSiteSystem }) {
12+
super({ filePath, url, csvSchema: CSVClinicalTrialInformationSchema });
1313
if (!clinicalSiteID) logger.warn(`${this.constructor.name} expects a value for clinicalSiteID but got ${clinicalSiteID}`);
1414
this.clinicalSiteID = clinicalSiteID;
1515
this.clinicalSiteSystem = clinicalSiteSystem;

src/extractors/CSVConditionExtractor.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ function formatData(conditionData, patientId) {
4949
}
5050

5151
class CSVConditionExtractor extends BaseCSVExtractor {
52-
constructor({ filePath }) {
53-
super({ filePath, csvSchema: CSVConditionSchema });
52+
constructor({ filePath, url }) {
53+
super({ filePath, url, csvSchema: CSVConditionSchema });
5454
}
5555

5656
async getConditionData(mrn) {

src/extractors/CSVObservationExtractor.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ function formatData(observationData, patientId) {
4242
}
4343

4444
class CSVObservationExtractor extends BaseCSVExtractor {
45-
constructor({ filePath }) {
46-
super({ filePath });
45+
constructor({ filePath, url }) {
46+
super({ filePath, url });
4747
}
4848

4949
async getObservationData(mrn) {

0 commit comments

Comments
 (0)