Fetching additional referenced resources after processing.
fixing hospitalization key. Tweaking the cerner client to use USCore resources, and then adding additional cerner specific resources.
This commit is contained in:
parent
4bc62135ea
commit
aa479fd655
|
@ -9,6 +9,8 @@ import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import * as FHIR401Client_ProcessBundle from './fixtures/FHIR401Client_ProcessBundle.json';
|
import * as FHIR401Client_ProcessBundle from './fixtures/FHIR401Client_ProcessBundle.json';
|
||||||
|
// @ts-ignore
|
||||||
|
import * as FHIR401Client_ExtractResourceReference from './fixtures/FHIR401Client_ExtractResourceReference.json';
|
||||||
import {IDatabaseRepository} from '../../../database/interface';
|
import {IDatabaseRepository} from '../../../database/interface';
|
||||||
import {PouchdbCrypto} from '../../../database/plugins/crypto';
|
import {PouchdbCrypto} from '../../../database/plugins/crypto';
|
||||||
import {ClientConfig} from '../../../models/client/client-config';
|
import {ClientConfig} from '../../../models/client/client-config';
|
||||||
|
@ -101,4 +103,17 @@ describe('FHIR401Client', () => {
|
||||||
}, 10000);
|
}, 10000);
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('ExtractResourceReference', () => {
|
||||||
|
it('should correctly extract resource identifier from raw resources', async () => {
|
||||||
|
|
||||||
|
//setup
|
||||||
|
|
||||||
|
//test
|
||||||
|
const resp = await client.ExtractResourceReference("CarePlan", FHIR401Client_ExtractResourceReference)
|
||||||
|
//expect
|
||||||
|
expect(resp.length).toEqual(2);
|
||||||
|
expect(resp).toEqual(['Encounter/97961321', 'Practitioner/12763770']);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {IClient, IResourceBundleRaw, IResourceRaw} from '../../interface';
|
import {IClient, IResourceBundleEntryRaw, IResourceBundleRaw, IResourceRaw} from '../../interface';
|
||||||
import {BaseClient} from './base_client';
|
import {BaseClient} from './base_client';
|
||||||
import {Source} from '../../../models/database/source';
|
import {Source} from '../../../models/database/source';
|
||||||
import {IDatabaseRepository} from '../../../database/interface';
|
import {IDatabaseRepository} from '../../../database/interface';
|
||||||
|
@ -88,8 +88,29 @@ export class FHIR401Client extends BaseClient implements IClient {
|
||||||
let bundle = await this.GetResourceBundlePaginated(`${resourceType}?patient=${this.source.patient}`)
|
let bundle = await this.GetResourceBundlePaginated(`${resourceType}?patient=${this.source.patient}`)
|
||||||
let wrappedResourceModels = await this.ProcessBundle(bundle)
|
let wrappedResourceModels = await this.ProcessBundle(bundle)
|
||||||
let resourceUpsertSummary = await db.UpsertResources(wrappedResourceModels)
|
let resourceUpsertSummary = await db.UpsertResources(wrappedResourceModels)
|
||||||
|
|
||||||
upsertSummary.updatedResources = upsertSummary.updatedResources.concat(resourceUpsertSummary.updatedResources)
|
upsertSummary.updatedResources = upsertSummary.updatedResources.concat(resourceUpsertSummary.updatedResources)
|
||||||
upsertSummary.totalResources += resourceUpsertSummary.totalResources
|
upsertSummary.totalResources += resourceUpsertSummary.totalResources
|
||||||
|
|
||||||
|
|
||||||
|
// check if theres any "extracted" resource references that we should sync as well
|
||||||
|
let extractedResourceReferences = []
|
||||||
|
extractedResourceReferences = wrappedResourceModels.reduce((previousVal, wrappedResource) => {
|
||||||
|
return previousVal.concat(this.ExtractResourceReference(wrappedResource.source_resource_type, wrappedResource.resource_raw))
|
||||||
|
}, extractedResourceReferences)
|
||||||
|
|
||||||
|
|
||||||
|
if(extractedResourceReferences.length > 0 ){
|
||||||
|
console.log("Extracted Resource References", extractedResourceReferences)
|
||||||
|
|
||||||
|
let extractedResourceBundle = await this.GenerateResourceBundleFromResourceIds(extractedResourceReferences)
|
||||||
|
let wrappedExtractedResourceBundle = await this.ProcessBundle(extractedResourceBundle)
|
||||||
|
let extractedResourceUpsertSummary = await db.UpsertResources(wrappedExtractedResourceBundle)
|
||||||
|
|
||||||
|
upsertSummary.updatedResources = upsertSummary.updatedResources.concat(extractedResourceUpsertSummary.updatedResources)
|
||||||
|
upsertSummary.totalResources += extractedResourceUpsertSummary.totalResources
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
console.error(`An error occurred while processing ${resourceType} bundle ${this.source.patient}`)
|
console.error(`An error occurred while processing ${resourceType} bundle ${this.source.patient}`)
|
||||||
|
@ -109,7 +130,7 @@ export class FHIR401Client extends BaseClient implements IClient {
|
||||||
* @param resourceRaw
|
* @param resourceRaw
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
public async ExtractResourceReference(sourceResourceType: string, resourceRaw): Promise<string[]> {
|
public ExtractResourceReference(sourceResourceType: string, resourceRaw): string[] {
|
||||||
let resourceRefs = []
|
let resourceRefs = []
|
||||||
|
|
||||||
switch (sourceResourceType) {
|
switch (sourceResourceType) {
|
||||||
|
@ -258,16 +279,15 @@ export class FHIR401Client extends BaseClient implements IClient {
|
||||||
resourceRefs.push(reasonReference.reference)
|
resourceRefs.push(reasonReference.reference)
|
||||||
})
|
})
|
||||||
|
|
||||||
//hospitalization[x].origin can contain
|
//hospitalization.origin can contain
|
||||||
//- Location
|
//- Location
|
||||||
//- Organization
|
//- Organization
|
||||||
//hospitalization[x].destination can contain
|
resourceRefs.push(resourceRaw.hospitalization?.origin?.reference)
|
||||||
|
|
||||||
|
//hospitalization.destination can contain
|
||||||
//- Location
|
//- Location
|
||||||
//- Organization
|
//- Organization
|
||||||
resourceRaw.hospitalization?.map((hospitalization) => {
|
resourceRefs.push(resourceRaw.hospitalization?.destination?.reference)
|
||||||
resourceRefs.push(hospitalization.origin?.reference)
|
|
||||||
resourceRefs.push(hospitalization.destination?.reference)
|
|
||||||
})
|
|
||||||
|
|
||||||
//location[x].location can contain
|
//location[x].location can contain
|
||||||
//- Location
|
//- Location
|
||||||
|
@ -440,7 +460,6 @@ export class FHIR401Client extends BaseClient implements IClient {
|
||||||
// remove all null values, remove all duplicates
|
// remove all null values, remove all duplicates
|
||||||
let cleanResourceRefs = resourceRefs.filter(i => !(typeof i === 'undefined' || i === null));
|
let cleanResourceRefs = resourceRefs.filter(i => !(typeof i === 'undefined' || i === null));
|
||||||
cleanResourceRefs = [...new Set(cleanResourceRefs)]
|
cleanResourceRefs = [...new Set(cleanResourceRefs)]
|
||||||
|
|
||||||
return cleanResourceRefs
|
return cleanResourceRefs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -504,6 +523,24 @@ export class FHIR401Client extends BaseClient implements IClient {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a list of resource ids (Patient/xxx, Observation/yyyy), request these resources and generate a pseudo-bundle file
|
||||||
|
* @param resourceIds
|
||||||
|
* @constructor
|
||||||
|
* @protected
|
||||||
|
*/
|
||||||
|
protected async GenerateResourceBundleFromResourceIds(resourceIds: string[]): Promise<IResourceBundleRaw>{
|
||||||
|
|
||||||
|
resourceIds = [...new Set(resourceIds)] //make sure they are unique references.
|
||||||
|
let rawResourceRefs = await Promise.all(resourceIds.map(async (extractedResourceRef) => {
|
||||||
|
return {
|
||||||
|
resource: await this.GetRequest(extractedResourceRef) as IResourceRaw
|
||||||
|
} as IResourceBundleEntryRaw
|
||||||
|
}))
|
||||||
|
|
||||||
|
return {resourceType: "Bundle", entry: rawResourceRefs}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve a resource bundle. While "next" link is present in response, continue to request urls and append BundleEntries
|
* Retrieve a resource bundle. While "next" link is present in response, continue to request urls and append BundleEntries
|
||||||
* @param relativeResourcePath
|
* @param relativeResourcePath
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"resourceType": "CarePlan",
|
||||||
|
"id": "197543976",
|
||||||
|
"meta": {
|
||||||
|
"versionId": "1",
|
||||||
|
"lastUpdated": "2021-10-04T14:46:33.000Z"
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"status": "additional",
|
||||||
|
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\"><p><b>Care Plan</b></p><p><b>Patient</b>: SMART, NANCYU NHA EEEEEE</p><p><b>Title</b>: Comorbidities found via Retrieve Dx</p><p><b>Description</b>: Malnutrition:Severe --- Inputs [Height: 165.1, Weight: 25, BMI (Calculated): 9.171615976368047]\n\nAnoxic Brain Injury\n\n</p><p><b>Status</b>: Active</p><p><b>Intent</b>: Plan</p><p><b>Category</b>: Assessment and Plan of Treatment</p><p><b>Author</b>: P., MD, Cardio</p><p><b>Effective Period</b>: Oct 4, 2021 2:46 P.M. UTC</p></div>"
|
||||||
|
},
|
||||||
|
"status": "active",
|
||||||
|
"intent": "plan",
|
||||||
|
"category": [
|
||||||
|
{
|
||||||
|
"coding": [
|
||||||
|
{
|
||||||
|
"system": "http://hl7.org/fhir/us/core/CodeSystem/careplan-category",
|
||||||
|
"code": "assess-plan",
|
||||||
|
"display": "Assessment and Plan of Treatment"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"text": "Assessment and Plan of Treatment"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"title": "Comorbidities found via Retrieve Dx",
|
||||||
|
"subject": {
|
||||||
|
"reference": "Patient/12724066",
|
||||||
|
"display": "SMART, NANCYU NHA EEEEEE"
|
||||||
|
},
|
||||||
|
"encounter": {
|
||||||
|
"reference": "Encounter/97961321"
|
||||||
|
},
|
||||||
|
"period": {
|
||||||
|
"start": "2021-10-04T14:46:33.000Z"
|
||||||
|
},
|
||||||
|
"author": {
|
||||||
|
"reference": "Practitioner/12763770",
|
||||||
|
"display": "P., MD, Cardio"
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,23 +18,15 @@ export class CernerClient extends FHIR401Client implements IClient {
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
async SyncAll(db: IDatabaseRepository): Promise<UpsertSummary> {
|
async SyncAll(db: IDatabaseRepository): Promise<UpsertSummary> {
|
||||||
const supportedResources: string[] = [
|
const supportedResources: string[] = this.usCoreResources.concat([
|
||||||
"AllergyIntolerance",
|
"Account",
|
||||||
"CarePlan",
|
"Appointment",
|
||||||
"CareTeam",
|
|
||||||
"Condition",
|
|
||||||
"Consent",
|
"Consent",
|
||||||
"Device",
|
|
||||||
"Encounter",
|
|
||||||
"FamilyMemberHistory",
|
"FamilyMemberHistory",
|
||||||
"Goal",
|
|
||||||
"Immunization",
|
|
||||||
"InsurancePlan",
|
"InsurancePlan",
|
||||||
"MedicationRequest",
|
"MedicationRequest",
|
||||||
"NutritionOrder",
|
"NutritionOrder",
|
||||||
"Observation",
|
|
||||||
"Person",
|
"Person",
|
||||||
"Procedure",
|
|
||||||
"Provenance",
|
"Provenance",
|
||||||
"Questionnaire",
|
"Questionnaire",
|
||||||
"QuestionnaireResponse",
|
"QuestionnaireResponse",
|
||||||
|
@ -42,7 +34,7 @@ export class CernerClient extends FHIR401Client implements IClient {
|
||||||
"Schedule",
|
"Schedule",
|
||||||
"ServiceRequest",
|
"ServiceRequest",
|
||||||
"Slot",
|
"Slot",
|
||||||
]
|
])
|
||||||
|
|
||||||
return this.SyncAllByResourceName(db, supportedResources)
|
return this.SyncAllByResourceName(db, supportedResources)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue