Skip to content

Commit 1bbbbe4

Browse files
authored
Merge pull request #91 from mcode/csv-validation
CSV Validation
2 parents 7243379 + bb59921 commit 1bbbbe4

18 files changed

+298
-63
lines changed

docs/CSV_Templates.xlsx

35 Bytes
Binary file not shown.

src/client/BaseClient.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,37 @@ class BaseClient {
2626

2727
// Given an extractor configuration, initialize all the necessary extractors
2828
initializeExtractors(extractorConfig, commonExtractorArgs) {
29+
let allExtractorsValid = true;
30+
2931
extractorConfig.forEach((curExtractorConfig) => {
3032
const { label, type, constructorArgs } = curExtractorConfig;
3133
logger.debug(`Initializing ${label} extractor with type ${type}`);
3234
const ExtractorClass = this.extractorClasses[type];
35+
3336
try {
3437
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+
3549
this.extractors.push(newExtractor);
3650
} catch (e) {
37-
throw new Error(`Unable to initialize ${label} extractor with type ${type}`);
51+
throw new Error(`Unable to initialize ${label} extractor with type ${type}: ${e.message}`);
3852
}
3953
});
54+
55+
if (allExtractorsValid) {
56+
logger.info('Validation succeeded');
57+
} else {
58+
throw new Error('Error occurred during CSV validation');
59+
}
4060
}
4161

4262
// NOTE: Async because in other clients that extend this, we need async helper functions (ex. auth)

src/extractors/BaseCSVExtractor.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const path = require('path');
2+
const { Extractor } = require('./Extractor');
3+
const { CSVModule } = require('../modules');
4+
const { validateCSV } = require('../helpers/csvValidator');
5+
const logger = require('../helpers/logger');
6+
7+
class BaseCSVExtractor extends Extractor {
8+
constructor({ filePath, csvSchema }) {
9+
super();
10+
this.csvSchema = csvSchema;
11+
this.filePath = path.resolve(filePath);
12+
this.csvModule = new CSVModule(this.filePath);
13+
}
14+
15+
validate() {
16+
if (this.csvSchema) {
17+
logger.info(`Validating CSV file for ${this.filePath}`);
18+
return validateCSV(this.filePath, this.csvSchema, this.csvModule.data);
19+
}
20+
logger.warn(`No CSV schema provided for ${this.filePath}`);
21+
return true;
22+
}
23+
}
24+
25+
module.exports = {
26+
BaseCSVExtractor,
27+
};

src/extractors/CSVAdverseEventExtractor.js

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
const path = require('path');
2-
const { CSVModule } = require('../modules');
1+
const { BaseCSVExtractor } = require('./BaseCSVExtractor');
32
const { generateMcodeResources } = require('../templates');
4-
const { Extractor } = require('./Extractor');
53
const logger = require('../helpers/logger');
64
const { formatDateTime } = require('../helpers/dateUtils');
75

@@ -53,15 +51,14 @@ function formatData(adverseEventData) {
5351
});
5452
}
5553

56-
class CSVAdverseEventExtractor extends Extractor {
54+
class CSVAdverseEventExtractor extends BaseCSVExtractor {
5755
constructor({ filePath }) {
58-
super();
59-
this.CSVModule = new CSVModule(path.resolve(filePath));
56+
super({ filePath });
6057
}
6158

6259
async getAdverseEventData(mrn) {
6360
logger.debug('Getting Adverse Event Data');
64-
return this.CSVModule.get('mrn', mrn);
61+
return this.csvModule.get('mrn', mrn);
6562
}
6663

6764
async get({ mrn }) {

src/extractors/CSVCancerDiseaseStatusExtractor.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
const path = require('path');
2-
const { CSVModule } = require('../modules');
1+
const { BaseCSVExtractor } = require('./BaseCSVExtractor');
32
const { formatDateTime } = require('../helpers/dateUtils');
43
const { getDiseaseStatusDisplay, getDiseaseStatusEvidenceDisplay } = require('../helpers/diseaseStatusUtils');
54
const { generateMcodeResources } = require('../templates');
65
const { getEmptyBundle } = require('../helpers/fhirUtils');
76
const logger = require('../helpers/logger');
7+
const { CSVCancerDiseaseStatusSchema } = require('../helpers/schemas/csv');
88

9-
class CSVCancerDiseaseStatusExtractor {
9+
class CSVCancerDiseaseStatusExtractor extends BaseCSVExtractor {
1010
constructor({ filePath, implementation }) {
11-
this.csvModule = new CSVModule(path.resolve(filePath));
11+
super({ filePath, csvSchema: CSVCancerDiseaseStatusSchema });
1212
this.implementation = implementation;
1313
}
1414

src/extractors/CSVCancerRelatedMedicationExtractor.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
const path = require('path');
2-
const { CSVModule } = require('../modules');
1+
const { BaseCSVExtractor } = require('./BaseCSVExtractor');
32
const { generateMcodeResources } = require('../templates');
4-
const { Extractor } = require('./Extractor');
53
const logger = require('../helpers/logger');
64
const { formatDateTime } = require('../helpers/dateUtils');
75

@@ -35,10 +33,9 @@ function formatData(medicationData) {
3533
});
3634
}
3735

38-
class CSVCancerRelatedMedicationExtractor extends Extractor {
36+
class CSVCancerRelatedMedicationExtractor extends BaseCSVExtractor {
3937
constructor({ filePath }) {
40-
super();
41-
this.csvModule = new CSVModule(path.resolve(filePath));
38+
super({ filePath });
4239
}
4340

4441
async getMedicationData(mrn) {

src/extractors/CSVClinicalTrialInformationExtractor.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
const path = require('path');
2-
const { Extractor } = require('./Extractor');
3-
const { CSVModule } = require('../modules');
1+
const { BaseCSVExtractor } = require('./BaseCSVExtractor');
42
const { firstEntryInBundle, getBundleResourcesByType } = require('../helpers/fhirUtils');
53
const { generateMcodeResources } = require('../templates');
64
const logger = require('../helpers/logger');
5+
const { CSVClinicalTrialInformationSchema } = require('../helpers/schemas/csv');
76

87
function getPatientId(context) {
98
const patientInContext = getBundleResourcesByType(context, 'Patient', {}, true);
@@ -16,10 +15,9 @@ function getPatientId(context) {
1615
return undefined;
1716
}
1817

19-
class CSVClinicalTrialInformationExtractor extends Extractor {
18+
class CSVClinicalTrialInformationExtractor extends BaseCSVExtractor {
2019
constructor({ filePath, clinicalSiteID }) {
21-
super();
22-
this.csvModule = new CSVModule(path.resolve(filePath));
20+
super({ filePath, csvSchema: CSVClinicalTrialInformationSchema });
2321
if (!clinicalSiteID) logger.warn(`${this.constructor.name} expects a value for clinicalSiteID but got ${clinicalSiteID}`);
2422
this.clinicalSiteID = clinicalSiteID;
2523
}

src/extractors/CSVConditionExtractor.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
const path = require('path');
2-
const { CSVModule } = require('../modules');
1+
const { BaseCSVExtractor } = require('./BaseCSVExtractor');
32
const { generateMcodeResources } = require('../templates');
4-
const { Extractor } = require('./Extractor');
53
const logger = require('../helpers/logger');
64
const { formatDateTime } = require('../helpers/dateUtils');
5+
const { CSVConditionSchema } = require('../helpers/schemas/csv');
76

87
// Formats data to be passed into template-friendly format
98
function formatData(conditionData) {
@@ -37,10 +36,9 @@ function formatData(conditionData) {
3736
});
3837
}
3938

40-
class CSVConditionExtractor extends Extractor {
39+
class CSVConditionExtractor extends BaseCSVExtractor {
4140
constructor({ filePath }) {
42-
super();
43-
this.csvModule = new CSVModule(path.resolve(filePath));
41+
super({ filePath, csvSchema: CSVConditionSchema });
4442
}
4543

4644
async getConditionData(mrn) {

src/extractors/CSVObservationExtractor.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
const path = require('path');
2-
const { CSVModule } = require('../modules');
1+
const { BaseCSVExtractor } = require('./BaseCSVExtractor');
32
const { generateMcodeResources } = require('../templates');
4-
const { Extractor } = require('./Extractor');
53
const logger = require('../helpers/logger');
64
const { formatDateTime } = require('../helpers/dateUtils');
75

@@ -32,10 +30,9 @@ function formatData(observationData) {
3230
});
3331
}
3432

35-
class CSVObservationExtractor extends Extractor {
33+
class CSVObservationExtractor extends BaseCSVExtractor {
3634
constructor({ filePath }) {
37-
super();
38-
this.csvModule = new CSVModule(path.resolve(filePath));
35+
super({ filePath });
3936
}
4037

4138
async getObservationData(mrn) {

src/extractors/CSVPatientExtractor.js

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
const path = require('path');
2-
const { CSVModule } = require('../modules');
31
const { generateMcodeResources } = require('../templates');
4-
const { Extractor } = require('./Extractor');
2+
const { BaseCSVExtractor } = require('./BaseCSVExtractor');
53
const { getEthnicityDisplay,
64
getRaceCodesystem,
75
getRaceDisplay } = require('../helpers/patientUtils');
86
const logger = require('../helpers/logger');
7+
const { CSVPatientSchema } = require('../helpers/schemas/csv');
98

109
function joinAndReformatData(patientData) {
1110
logger.debug('Reformatting patient data from CSV into template format');
@@ -39,10 +38,9 @@ function joinAndReformatData(patientData) {
3938
};
4039
}
4140

42-
class CSVPatientExtractor extends Extractor {
41+
class CSVPatientExtractor extends BaseCSVExtractor {
4342
constructor({ filePath }) {
44-
super();
45-
this.csvModule = new CSVModule(path.resolve(filePath));
43+
super({ filePath, csvSchema: CSVPatientSchema });
4644
}
4745

4846
async getPatientData(mrn) {

0 commit comments

Comments
 (0)