From 97add34fbf7353413751069153bd3696b3f0b71d Mon Sep 17 00:00:00 2001 From: adipaul1981 Date: Mon, 31 Jan 2022 09:30:12 -0500 Subject: [PATCH] add include project for download (#46) * add include project for download * incorporate review comments --- package-lock.json | 85 +++++--- package.json | 4 +- src/env.ts | 3 + src/reports/biospecimen-data/configInclude.ts | 45 ++++ .../{config.ts => configKf.ts} | 0 src/reports/biospecimen-data/index.ts | 7 +- src/reports/clinical-data/configInclude.ts | 201 ++++++++++++++++++ .../clinical-data/{config.ts => configKf.ts} | 0 src/reports/clinical-data/index.ts | 7 +- .../family-clinical-data/configInclude.ts | 120 +++++++++++ .../{config.ts => configKf.ts} | 0 .../generateFamilySqon.ts | 2 +- src/reports/family-clinical-data/index.ts | 7 +- src/reports/generateReport.ts | 2 +- src/reports/types.ts | 13 +- src/status/index.ts | 9 +- src/utils/esUtils.ts | 2 +- 17 files changed, 455 insertions(+), 52 deletions(-) create mode 100644 src/reports/biospecimen-data/configInclude.ts rename src/reports/biospecimen-data/{config.ts => configKf.ts} (100%) create mode 100644 src/reports/clinical-data/configInclude.ts rename src/reports/clinical-data/{config.ts => configKf.ts} (100%) create mode 100644 src/reports/family-clinical-data/configInclude.ts rename src/reports/family-clinical-data/{config.ts => configKf.ts} (100%) diff --git a/package-lock.json b/package-lock.json index ff71203..8baa69a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,8 +9,8 @@ "version": "1.2.3", "license": "Apache-2.0", "dependencies": { + "@arranger/middleware": "2.16.1", "@elastic/elasticsearch": "^7.4.0", - "@kfarranger/middleware": "1.5.2", "cors": "^2.8.5", "dotenv": "^8.1.0", "excel4node": "^1.7.2", @@ -40,6 +40,23 @@ "typescript": "^4.3.5" } }, + "node_modules/@arranger/middleware": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@arranger/middleware/-/middleware-2.16.1.tgz", + "integrity": "sha512-IIovu6mDvQ2ADLvTp5HWNwBOJbTb0ocyhVVOBgZ5Pi8+NDabYHsInm4HBhJc7loKjuFkTXtZz/W3xrcsysMkeA==", + "dependencies": { + "body-parser": "^1.18.2", + "cors": "^2.8.4", + "date-fns": "^1.29.0", + "express": "^4.16.3", + "kind-of": "^6.0.3", + "lodash": "^4.17.20", + "minimist": "^1.2.5", + "morgan": "^1.9.0", + "utf8": "^3.0.0", + "winston": "^2.4.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -666,21 +683,6 @@ "node": ">=8" } }, - "node_modules/@kfarranger/middleware": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@kfarranger/middleware/-/middleware-1.5.2.tgz", - "integrity": "sha512-y1SoE8UOcCyYG1g3x22YZZUYibUjNjWPO0RfWPNZ7/uxYkXlTtHz0KEvf2Axyet03CMpMxQUBQ8ZiuCZ7vMpaQ==", - "dependencies": { - "body-parser": "^1.18.2", - "cors": "^2.8.4", - "date-fns": "^1.29.0", - "express": "^4.16.2", - "lodash": "^4.17.15", - "morgan": "^1.9.0", - "utf8": "^3.0.0", - "winston": "^2.4.0" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -4203,6 +4205,14 @@ "json-buffer": "3.0.0" } }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -4520,8 +4530,7 @@ "node_modules/minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "node_modules/mocha": { "version": "9.0.2", @@ -7079,6 +7088,23 @@ } }, "dependencies": { + "@arranger/middleware": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@arranger/middleware/-/middleware-2.16.1.tgz", + "integrity": "sha512-IIovu6mDvQ2ADLvTp5HWNwBOJbTb0ocyhVVOBgZ5Pi8+NDabYHsInm4HBhJc7loKjuFkTXtZz/W3xrcsysMkeA==", + "requires": { + "body-parser": "^1.18.2", + "cors": "^2.8.4", + "date-fns": "^1.29.0", + "express": "^4.16.3", + "kind-of": "^6.0.3", + "lodash": "^4.17.20", + "minimist": "^1.2.5", + "morgan": "^1.9.0", + "utf8": "^3.0.0", + "winston": "^2.4.0" + } + }, "@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -7569,21 +7595,6 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, - "@kfarranger/middleware": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@kfarranger/middleware/-/middleware-1.5.2.tgz", - "integrity": "sha512-y1SoE8UOcCyYG1g3x22YZZUYibUjNjWPO0RfWPNZ7/uxYkXlTtHz0KEvf2Axyet03CMpMxQUBQ8ZiuCZ7vMpaQ==", - "requires": { - "body-parser": "^1.18.2", - "cors": "^2.8.4", - "date-fns": "^1.29.0", - "express": "^4.16.2", - "lodash": "^4.17.15", - "morgan": "^1.9.0", - "utf8": "^3.0.0", - "winston": "^2.4.0" - } - }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -10268,6 +10279,11 @@ "json-buffer": "3.0.0" } }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, "latest-version": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", @@ -10514,8 +10530,7 @@ "minimist": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" }, "mocha": { "version": "9.0.2", diff --git a/package.json b/package.json index 276a400..d22181e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "kf-api-portal-reports", "version": "1.2.3", - "description": "The Kids First Download Clinical Data API offers an endpoint to generate a report of clinical data based on a query built using the Kids First Portal.", + "description": "The Download Clinical Data API offers an endpoint to generate a report of clinical data based on a query built using the:", "main": "index.js", "scripts": { "start": "node ./dist/index.js", @@ -44,7 +44,7 @@ }, "dependencies": { "@elastic/elasticsearch": "^7.4.0", - "@kfarranger/middleware": "1.5.2", + "@arranger/middleware": "2.16.1", "cors": "^2.8.5", "dotenv": "^8.1.0", "excel4node": "^1.7.2", diff --git a/src/env.ts b/src/env.ts index ced9d28..8360e44 100644 --- a/src/env.ts +++ b/src/env.ts @@ -10,6 +10,9 @@ export const ES_HOST = process.env.ES_HOST || 'kf-arranger-es-prd.kids-first.io: // ElasticSearch queries parameters export const ES_PAGESIZE: number = Number(process.env.ES_PAGESIZE) || 1000; +// Project +export const PROJECT: string = process.env.PROJECT || 'kids-first'; + // Keycloak configs export const KEYCLOAK_URL = process.env.KEYCLOAK_URL || 'https://kf-keycloak-qa.kf-strides.org/auth'; export const KEYCLOAK_REALM = process.env.KEYCLOAK_REALM || 'kidsfirstdrc'; diff --git a/src/reports/biospecimen-data/configInclude.ts b/src/reports/biospecimen-data/configInclude.ts new file mode 100644 index 0000000..d84af57 --- /dev/null +++ b/src/reports/biospecimen-data/configInclude.ts @@ -0,0 +1,45 @@ +import { QueryConfig, ReportConfig, SheetConfig } from '../types'; + +const biospecimens: SheetConfig = { + sheetName: 'Biospecimens', + root: 'biospecimens', + columns: [ + { field: 'fhir_id' }, + { field: 'external_id' }, + { field: 'files.biospecimens.biospecimen_id', header: 'Biospecimens Biospecimens Id' }, + { + field: 'files.biospecimens.age_at_biospecimen_collection', + header: 'Biospecimens Age At Biospecimen Collection', + }, + { field: 'files.biospecimens.bio_repository', header: 'Biospecimens Bio Repository' }, + { field: 'files.biospecimens.biospecimen_type', header: 'Biospecimens Biospecimen Type' }, + { field: 'files.biospecimens.derived_sample_id', header: 'Biospecimens Derived Sample Id' }, + { field: 'files.biospecimens.derived_sample_type', header: 'Biospecimens Derived Sample Type' }, + { field: 'files.biospecimens.ncit_id_tissue_type', header: 'Biospecimens NCIT Id Tissue Type' }, + { field: 'files.biospecimens.sample_id', header: 'Biospecimens Sample Id' }, + { field: 'files.biospecimens.sample_type', header: 'Biospecimens Sample Type' }, + ], + sort: [ + { + 'files.biospecimens.biospecimen_id': { + order: 'asc', + }, + }, + { + fhir_id: { + order: 'asc', + }, + }, + ], +}; + +const queryConfigs: QueryConfig = { + indexName: 'participant', + alias: 'participant_centric', +}; + +const sheetConfigs: SheetConfig[] = [biospecimens]; + +const reportConfig: ReportConfig = { queryConfigs, sheetConfigs }; + +export default reportConfig; diff --git a/src/reports/biospecimen-data/config.ts b/src/reports/biospecimen-data/configKf.ts similarity index 100% rename from src/reports/biospecimen-data/config.ts rename to src/reports/biospecimen-data/configKf.ts diff --git a/src/reports/biospecimen-data/index.ts b/src/reports/biospecimen-data/index.ts index 2bdb2fe..9021549 100644 --- a/src/reports/biospecimen-data/index.ts +++ b/src/reports/biospecimen-data/index.ts @@ -1,10 +1,13 @@ import { Request, Response } from 'express'; import { Client } from '@elastic/elasticsearch'; import generateReport from '../generateReport'; -import reportConfig from './config'; +import configKf from './configKf'; +import configInclude from './configInclude'; +import { PROJECT } from '../../env'; import { normalizeConfigs } from '../../utils/configUtils'; import ExtendedReportConfigs from '../../utils/extendedReportConfigs'; import { reportGenerationErrorHandler } from '../../errors'; +import { ProjectType } from '../types'; const clinicalDataReport = (esHost: string) => async (req: Request, res: Response) => { console.time('biospecimen-data'); @@ -13,6 +16,8 @@ const clinicalDataReport = (esHost: string) => async (req: Request, res: Respons const userId = req['kauth']?.grant?.access_token?.content?.sub; const accessToken = req.headers.authorization; + const reportConfig = PROJECT.toLowerCase().trim() === ProjectType.kidsFirst ? configKf : configInclude; + let es = null; try { // prepare the ES client diff --git a/src/reports/clinical-data/configInclude.ts b/src/reports/clinical-data/configInclude.ts new file mode 100644 index 0000000..2550df2 --- /dev/null +++ b/src/reports/clinical-data/configInclude.ts @@ -0,0 +1,201 @@ +import { QueryConfig, ReportConfig, SheetConfig } from '../types'; + +const participants: SheetConfig = { + sheetName: 'Participants', + root: null, + columns: [ + { field: 'fhir_id' }, + { field: 'external_id' }, + { field: 'families_id' }, + { field: 'family_type' }, + { field: 'is_proband' }, + { field: 'study.study_name' }, + { field: 'families.family_members.exploded_member_entity' }, + { field: 'sex' }, + { field: 'race' }, + { field: 'ethnicity' }, + { field: 'karyotype' }, + { field: 'down_syndrome_diagnosis' }, + // { field: 'outcomes.vital_status' }, //TODO TBD + // { + // field: 'outcomes.age_at_event_days', + // header: 'Age at the Last Vital Status (Days)', + // }, //TODO TBD + // { field: 'outcome.disease_related' }, //TODO TBD + // { field: 'affected_status' }, //TODO TBD + ], + sort: [ + { + fhir_id: { + order: 'asc', + }, + }, + { + 'diagnosis.age_at_event_days': { + order: 'desc', + }, + }, + ], +}; + +const phenotypes: SheetConfig = { + sheetName: 'Phenotypes', + root: 'phenotype', + columns: [ + { field: 'fhir_id' }, + { field: 'external_id' }, + { field: 'is_proband' }, + { + field: 'phenotype.observed', + additionalFields: ['phenotype.hpo_phenotype_observed', 'phenotype.hpo_phenotype_not_observed'], + header: 'Phenotype (HPO)', + transform: (observed, row) => { + if (!row.phenotype) { + return; + } + return observed ? row.phenotype.hpo_phenotype_observed : row.phenotype.hpo_phenotype_not_observed; + }, + }, + // { + // field: 'phenotype.observed', + // additionalFields: ['phenotype.snomed_phenotype_observed', 'phenotype.snomed_phenotype_not_observed'], + // header: 'Phenotype (SNOMED)', + // transform: (observed, row) => { + // if (!row.phenotype) { + // return; + // } + // return observed ? row.phenotype.snomed_phenotype_observed : row.phenotype.snomed_phenotype_not_observed; + // }, + // }, //TODO TBD + { field: 'phenotype.source_text_phenotype' }, + { + field: 'phenotype.observed', + additionalFields: ['phenotype.hpo_phenotype_observed_text', 'phenotype.hpo_phenotype_not_observed_text'], + header: 'Phenotype Source Text', + transform: (observed, row) => { + if (!row.phenotype) { + return; + } + return observed + ? row.phenotype.hpo_phenotype_observed_text + : row.phenotype.hpo_phenotype_not_observed_text; + }, + }, + { + field: 'phenotype.observed', + header: 'Interpretation', + transform: (value, row) => (value ? 'Observed' : 'Not Observed'), + }, + { + field: 'phenotype.age_at_event_days', + header: 'Age at Phenotype Assignment (Days)', + }, + ], + sort: [{ fhir_id: 'asc' }], +}; + +const diagnoses: SheetConfig = { + sheetName: 'Diagnoses', + root: 'diagnoses', + columns: [ + { field: 'fhir_id' }, + { field: 'external_id' }, + { field: 'is_proband' }, + { + field: 'fhir_id', + header: 'Diagnosis Type', + transform: () => 'Clinical', + }, + { field: 'diagnosis.mondo_id_diagnosis' }, + { field: 'diagnosis.ncit_id_diagnosis' }, + { field: 'diagnosis.icd_id_diagnosis' }, + { field: 'diagnosis.source_text' }, + { + field: 'diagnosis.age_at_event_days', + header: 'Age at Diagnosis (Days)', + }, + { field: 'diagnosis.source_text_tumor_location' }, + ], + sort: [{ fhir_id: 'asc' }], +}; + +const histologicalDiagnoses: SheetConfig = { + sheetName: 'Histological Diagnoses', + root: 'biospecimens.diagnoses', + columns: [ + { field: 'fhir_id' }, + { field: 'external_id' }, //TODO TBD biospecimen fields + // { field: 'biospecimens.kf_id' }, + // { field: 'biospecimens.external_sample_id' }, + // { field: 'biospecimens.external_aliquot_id' }, + // { field: 'is_proband' }, + // { + // // This allows to do a cell with a static value. + // // The value will be formatted like the value of `field` would have. + // field: 'kf_id', + // header: 'Diagnosis Type', + // transform: () => 'Histological', + // }, + // { field: 'biospecimens.diagnoses.diagnosis_category' }, + // { field: 'biospecimens.diagnoses.mondo_id_diagnosis' }, + // { field: 'biospecimens.diagnoses.ncit_id_diagnosis' }, + // { field: 'biospecimens.diagnoses.source_text_diagnosis' }, + // { + // field: 'biospecimens.diagnoses.age_at_event_days', + // header: 'Age at Diagnosis (Days)', + // }, + // { field: 'biospecimens.diagnoses.source_text_tumor_location' }, + // { field: 'biospecimens.source_text_anatomical_site' }, + // { field: 'biospecimens.ncit_id_tissue_type' }, + // { field: 'biospecimens.source_text_tissue_type' }, + // { field: 'biospecimens.composition' }, + // { field: 'biospecimens.method_of_sample_procurement' }, + // { field: 'biospecimens.analyte_type' }, + ], + sort: [ + { fhir_id: 'asc' }, + { + 'biospecimens.diagnoses.age_at_event_days': { + order: 'desc', + nested: { + path: 'biospecimens', + nested: { + path: 'biospecimens.diagnoses', + }, + }, + }, + }, + ], +}; + +const familyRelationship: SheetConfig = { + sheetName: 'Family Relationship', + root: 'families', + columns: [ + { field: 'fhir_id' }, + { field: 'family.family_members_id' }, + // { + // field: 'family.family_compositions.family_members.relationship', + // header: 'Relationship', + // transform: value => value || 'self', + // }, //TODO TBD + ], + sort: [{ fhir_id: 'asc' }], +}; + +export const queryConfigs: QueryConfig = { + indexName: 'participant', + alias: 'participant_centric', +}; + +export const sheetConfigs: SheetConfig[] = [ + participants, + phenotypes, + diagnoses, + // histologicalDiagnoses, //TODO TBD missing biospecimen + familyRelationship, +]; + +const reportConfig: ReportConfig = { queryConfigs, sheetConfigs }; + +export default reportConfig; diff --git a/src/reports/clinical-data/config.ts b/src/reports/clinical-data/configKf.ts similarity index 100% rename from src/reports/clinical-data/config.ts rename to src/reports/clinical-data/configKf.ts diff --git a/src/reports/clinical-data/index.ts b/src/reports/clinical-data/index.ts index 2a9f6f5..69c0d7a 100644 --- a/src/reports/clinical-data/index.ts +++ b/src/reports/clinical-data/index.ts @@ -1,9 +1,12 @@ import { Request, Response } from 'express'; import { Client } from '@elastic/elasticsearch'; import generateReport from '../generateReport'; -import reportConfig from './config'; +import configKf from './configKf'; +import configInclude from './configInclude'; import { normalizeConfigs } from '../../utils/configUtils'; import { reportGenerationErrorHandler } from '../../errors'; +import { PROJECT } from '../../env'; +import { ProjectType } from '../types'; const clinicalDataReport = (esHost: string) => async (req: Request, res: Response) => { console.time('clinical-data'); @@ -12,6 +15,8 @@ const clinicalDataReport = (esHost: string) => async (req: Request, res: Respons const userId = req['kauth']?.grant?.access_token?.content?.sub; const accessToken = req.headers.authorization; + const reportConfig = PROJECT.toLowerCase().trim() === ProjectType.kidsFirst ? configKf : configInclude; + let es = null; try { // prepare the ES client diff --git a/src/reports/family-clinical-data/configInclude.ts b/src/reports/family-clinical-data/configInclude.ts new file mode 100644 index 0000000..b68501a --- /dev/null +++ b/src/reports/family-clinical-data/configInclude.ts @@ -0,0 +1,120 @@ +import { QueryConfig, ReportConfig, SheetConfig } from '../types'; + +const participants: SheetConfig = { + sheetName: 'Participants', + root: null, + columns: [ + { field: 'fhir_id' }, + { field: 'external_id' }, + { field: 'families_id' }, + { field: 'is_proband' }, + { field: 'study.study_name' }, + // { field: 'family.family_compositions.composition' }, //TODO TBD + { field: 'sex' }, + { field: 'race' }, + { field: 'ethnicity' }, + { field: 'down_syndrome_diagnosis' }, + { field: 'karyotype' }, + // { field: 'outcome.vital_status' }, //TODO TBD + // { + // field: 'outcome.age_at_event_days', + // header: 'Age at the Last Vital Status (Days)', + // }, //TODO TBD + // { field: 'outcome.disease_related' }, //TODO TBD + // { field: 'affected_status' }, //TODO TBD + ], + sort: [ + { + fhir_id: { + order: 'asc', + }, + }, + { + 'diagnosis.age_at_event_days': { + order: 'desc', + }, + }, + ], +}; + +const phenotypes: SheetConfig = { + sheetName: 'Phenotypes', + root: 'phenotype', + columns: [ + { field: 'fhir_id' }, + { field: 'external_id' }, + { field: 'families_id' }, + { field: 'is_proband' }, + { + field: 'phenotype.hpo_phenotype_observed_text', + header: 'Phenotype (HPO)', + }, + // { + // field: 'phenotype.observed', + // additionalFields: ['phenotype.snomed_phenotype_observed', 'phenotype.snomed_phenotype_not_observed'], + // header: 'Phenotype (SNOMED)', + // transform: (observed, row) => { + // if (!row.phenotype) { + // return; + // } + // return observed ? row.phenotype.snomed_phenotype_observed : row.phenotype.snomed_phenotype_not_observed; + // }, + // }, //TODO TBD + { + field: 'phenotype.observed', + additionalFields: ['phenotype.hpo_phenotype_observed_text', 'phenotype.hpo_phenotype_not_observed_text'], + header: 'Source Text Phenotype', + transform: (observed, row) => { + if (!row.phenotype) { + return; + } + return observed + ? row.phenotype.hpo_phenotype_observed_text + : row.phenotype.hpo_phenotype_not_observed_text; + }, + }, + { + field: 'phenotype.observed', + header: 'Interpretation', + transform: (value, row) => (value ? 'Observed' : 'Not Observed'), + }, + { field: 'phenotype.age_at_event_days', header: 'Age at Phenotype Assignment (Days)' }, + ], + sort: [{ families_id: 'asc' }, { fhir_id: 'asc' }], +}; + +const diagnoses: SheetConfig = { + sheetName: 'Diagnoses', + root: 'diagnoses', + columns: [ + { field: 'fhir_id' }, + { field: 'external_id' }, + { field: 'families_id' }, + { field: 'is_proband' }, + { + field: 'fhir_id', + header: 'Diagnosis Type', + transform: () => 'Clinical', + }, + { field: 'diagnoses.mondo_id_diagnosis' }, + { field: 'diagnoses.ncit_id_diagnosis' }, + { field: 'diagnoses.source_text' }, + { + field: 'diagnoses.age_at_event_days', + header: 'Age at Diagnosis (Days)', + }, + { field: 'diagnoses.source_text_tumor_location' }, + ], + sort: [{ families_id: 'asc' }, { fhir_id: 'asc' }], +}; + +export const queryConfigs: QueryConfig = { + indexName: 'participant', + alias: 'participant_centric', +}; + +export const sheetConfigs: SheetConfig[] = [participants, phenotypes, diagnoses]; + +const reportConfig: ReportConfig = { queryConfigs, sheetConfigs }; + +export default reportConfig; diff --git a/src/reports/family-clinical-data/config.ts b/src/reports/family-clinical-data/configKf.ts similarity index 100% rename from src/reports/family-clinical-data/config.ts rename to src/reports/family-clinical-data/configKf.ts diff --git a/src/reports/family-clinical-data/generateFamilySqon.ts b/src/reports/family-clinical-data/generateFamilySqon.ts index cac04f3..c1eb8c5 100644 --- a/src/reports/family-clinical-data/generateFamilySqon.ts +++ b/src/reports/family-clinical-data/generateFamilySqon.ts @@ -1,5 +1,5 @@ import get from 'lodash/get'; -import { buildQuery } from '@kfarranger/middleware'; +import { buildQuery } from '@arranger/middleware'; import { getExtendedConfigs, getNestedFields } from '../../utils/arrangerUtils'; import { executeSearch } from '../../utils/esUtils'; diff --git a/src/reports/family-clinical-data/index.ts b/src/reports/family-clinical-data/index.ts index 6e89ccb..f121af4 100644 --- a/src/reports/family-clinical-data/index.ts +++ b/src/reports/family-clinical-data/index.ts @@ -1,11 +1,14 @@ import { Client } from '@elastic/elasticsearch'; import { Request, Response } from 'express'; import generateReport from '../generateReport'; -import reportConfig from './config'; +import configKf from './configKf'; +import configInclude from './configInclude'; import { normalizeConfigs } from '../../utils/configUtils'; import generateFamilySqon from './generateFamilySqon'; import { reportGenerationErrorHandler } from '../../errors'; +import { PROJECT } from '../../env'; +import { ProjectType } from '../types'; const clinicalDataReport = (esHost: string) => async (req: Request, res: Response) => { console.time('family-clinical-data'); @@ -14,6 +17,8 @@ const clinicalDataReport = (esHost: string) => async (req: Request, res: Respons const userId = req['kauth']?.grant?.access_token?.content?.sub; const accessToken = req.headers.authorization; + const reportConfig = PROJECT.toLowerCase().trim() === ProjectType.kidsFirst ? configKf : configInclude; + let es = null; try { // prepare the ES client diff --git a/src/reports/generateReport.ts b/src/reports/generateReport.ts index a7f05f2..c86f984 100644 --- a/src/reports/generateReport.ts +++ b/src/reports/generateReport.ts @@ -1,5 +1,5 @@ import { Client } from '@elastic/elasticsearch'; -import { buildQuery } from '@kfarranger/middleware'; +import { buildQuery } from '@arranger/middleware'; import xl from 'excel4node'; import { Response } from 'express'; import flattenDeep from 'lodash/flattenDeep'; diff --git a/src/reports/types.ts b/src/reports/types.ts index 858ad73..536aa25 100644 --- a/src/reports/types.ts +++ b/src/reports/types.ts @@ -7,7 +7,7 @@ export type ColumnConfig = { field: string; header?: string; additionalFields?: string[]; - transform?:any + transform?: any; }; export type SheetConfig = { @@ -15,9 +15,14 @@ export type SheetConfig = { root: string; columns: ColumnConfig[]; sort: object[]; -} +}; export type ReportConfig = { queryConfigs: QueryConfig; - sheetConfigs: SheetConfig[] -} \ No newline at end of file + sheetConfigs: SheetConfig[]; +}; + +export enum ProjectType { + kidsFirst = 'kids-first', + include = 'include', +} diff --git a/src/status/index.ts b/src/status/index.ts index c93fdd6..7069fe2 100644 --- a/src/status/index.ts +++ b/src/status/index.ts @@ -1,13 +1,12 @@ import { Request, Response } from 'express'; import { version, name, description } from '../../package.json'; -import { ES_HOST } from '../env'; +import { ES_HOST, PROJECT } from '../env'; -export default (_req: Request, res: Response) => { - return res.send({ +export default (_req: Request, res: Response) => + res.send({ name, version, - description, + description: `${description} ${PROJECT} portal.`, elasticsearch: ES_HOST, }); -}; diff --git a/src/utils/esUtils.ts b/src/utils/esUtils.ts index 296dfdf..02d59f1 100644 --- a/src/utils/esUtils.ts +++ b/src/utils/esUtils.ts @@ -1,7 +1,7 @@ import { Client } from '@elastic/elasticsearch'; import noop from 'lodash/noop'; import defaults from 'lodash/defaults'; -import esToSafeJsInt from '@kfarranger/middleware/dist/utils/esToSafeJsInt'; +import esToSafeJsInt from '@arranger/middleware/dist/utils/esToSafeJsInt'; type SearchOpts = { onPageFetched(data: object[], page: number): void;