Skip to main content
Glama
codesystemimport.test.ts13.2 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { ContentType } from '@medplum/core'; import type { CodeSystem, Parameters } from '@medplum/fhirtypes'; import express from 'express'; import request from 'supertest'; import { initApp, shutdownApp } from '../../app'; import { loadTestConfig } from '../../config/loader'; import { DatabaseMode, getDatabasePool } from '../../database'; import { createTestProject, initTestAuth } from '../../test.setup'; import { Column, Condition, SelectQuery } from '../sql'; import { selectCoding } from './utils/terminology'; const app = express(); export const snomedJSON: CodeSystem = { resourceType: 'CodeSystem', url: 'http://snomed.info/sct', name: 'SNOMEDCT_US', title: 'SNOMED CT (US Edition)', status: 'active', experimental: false, hierarchyMeaning: 'is-a', versionNeeded: false, content: 'not-present', property: [ { code: 'parent', uri: 'http://hl7.org/fhir/concept-properties#parent', description: 'A SNOMED CT concept id that has the target of a direct is-a relationship from the concept', type: 'code', }, ], }; describe('CodeSystem $import', () => { let accessToken: string; let snomed: CodeSystem; beforeAll(async () => { const config = await loadTestConfig(); await initApp(app, config); }); beforeEach(async () => { accessToken = await initTestAuth({ superAdmin: true }); expect(accessToken).toBeDefined(); const resS = await request(app) .get(`/fhir/R4/CodeSystem?url=${snomedJSON.url}`) .set('Authorization', 'Bearer ' + accessToken) .send(); expect(resS.status).toStrictEqual(200); if (resS.body.entry.length > 0) { for (const entry of resS.body.entry) { const resD = await request(app) .delete(`/fhir/R4/CodeSystem/${entry.resource.id}`) .set('Authorization', 'Bearer ' + accessToken) .send(); expect(resD.status).toStrictEqual(200); } } const res = await request(app) .post(`/fhir/R4/CodeSystem`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send(snomedJSON); expect(res.status).toStrictEqual(201); snomed = res.body as CodeSystem; }); afterAll(async () => { await shutdownApp(); }); test('Imports concepts and properties separately', async () => { const res = await request(app) .post(`/fhir/R4/CodeSystem/$import`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'system', valueUri: snomed.url }, { name: 'concept', valueCoding: { code: '37931006', display: 'Auscultation (procedure)' } }, { name: 'concept', valueCoding: { code: '315306007', display: 'Examination by method (procedure)' } }, ], }); expect(res.status).toStrictEqual(200); const res2 = await request(app) .post(`/fhir/R4/CodeSystem/$import`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'system', valueUri: snomed.url }, { name: 'property', part: [ { name: 'code', valueCode: '37931006' }, { name: 'property', valueCode: 'parent' }, { name: 'value', valueString: '315306007' }, ], }, ], }); expect(res2.status).toStrictEqual(200); const coding = await assertCodeExists(snomed.id, '37931006'); expect(coding.isSynonym).toBe(false); await assertCodeExists(snomed.id, '315306007'); await assertPropertyExists(snomed.id, '37931006', 'parent', '315306007'); }); test('Imports concepts and associated relationships', async () => { const res = await request(app) .post(`/fhir/R4/CodeSystem/$import`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'system', valueUri: snomed.url }, { name: 'concept', valueCoding: { code: '184598004', display: 'Needle biopsy of brain (procedure)' } }, { name: 'concept', valueCoding: { code: '702707005', display: 'Biopsy of head (procedure)' } }, { name: 'concept', valueCoding: { code: '118690002', display: 'Procedure on head (procedure)' } }, { name: 'concept', valueCoding: { code: '71388002', display: 'Procedure (procedure)' } }, { name: 'property', part: [ { name: 'code', valueCode: '184598004' }, { name: 'property', valueCode: 'parent' }, { name: 'value', valueString: '702707005' }, ], }, { name: 'property', part: [ { name: 'code', valueCode: '702707005' }, { name: 'property', valueCode: 'parent' }, { name: 'value', valueString: '118690002' }, ], }, { name: 'property', part: [ { name: 'code', valueCode: '118690002' }, { name: 'property', valueCode: 'parent' }, { name: 'value', valueString: '71388002' }, ], }, ], } as Parameters); expect(res.status).toBe(200); await assertCodeExists(snomed.id, '702707005'); const target = await assertCodeExists(snomed.id, '118690002'); const relationship = await assertPropertyExists(snomed.id, '702707005', 'parent', '118690002'); expect(relationship.target).toStrictEqual(target.id); }); test('Returns error on unknown code system', async () => { const res = await request(app) .post(`/fhir/R4/CodeSystem/$import`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'system', valueUri: 'http://example.com/unknown' }, { name: 'concept', valueCoding: { code: '1', display: 'Aspirin' } }, ], }); expect(res.status).toStrictEqual(400); expect(res.body.issue[0].code).toStrictEqual('invalid'); }); test('Returns error on unknown code for property', async () => { const res2 = await request(app) .post(`/fhir/R4/CodeSystem/$import`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'system', valueUri: snomed.url }, { name: 'property', part: [ { name: 'code', valueCode: 'not a real code' }, { name: 'property', valueCode: 'parent' }, { name: 'value', valueString: '71388002' }, ], }, ], }); expect(res2.status).toStrictEqual(400); expect(res2.body.issue[0].code).toStrictEqual('invalid'); }); test('Returns error on unknown property', async () => { const res2 = await request(app) .post(`/fhir/R4/CodeSystem/$import`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'system', valueUri: snomed.url }, { name: 'concept', valueCoding: { code: '184598004', display: 'Needle biopsy of brain (procedure)' } }, { name: 'property', part: [ { name: 'code', valueCode: '184598004' }, { name: 'property', valueCode: 'not a real property' }, { name: 'value', valueString: '71388002' }, ], }, ], }); expect(res2.status).toStrictEqual(400); expect(res2.body.issue[0].code).toStrictEqual('invalid'); }); test('Returns error on non-SuperAdmin user', async () => { const regularAccessToken = await initTestAuth({ superAdmin: false }); const res2 = await request(app) .post(`/fhir/R4/CodeSystem/$import`) .set('Authorization', 'Bearer ' + regularAccessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'system', valueUri: snomed.url }, { name: 'concept', valueCoding: { code: '184598004', display: 'Needle biopsy of brain (procedure)' } }, ], }); expect(res2.status).toStrictEqual(403); expect(res2.body.issue[0].code).toStrictEqual('forbidden'); }); test('Allows access by Project admin', async () => { const { accessToken } = await createTestProject({ project: { superAdmin: false }, membership: { admin: true }, withAccessToken: true, }); // Project Admin must have access to write to CodeSystem resource const res = await request(app) .post('/fhir/R4/CodeSystem') .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send(snomedJSON); expect(res.status).toStrictEqual(201); const res2 = await request(app) .post(`/fhir/R4/CodeSystem/$import`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'system', valueUri: snomed.url }, { name: 'concept', valueCoding: { code: '184598004', display: 'Needle biopsy of brain (procedure)' } }, ], }); expect(res2.status).toStrictEqual(200); await assertCodeExists(res.body.id, '184598004'); }); test('Prevents writes by Project admin to linked Project systems', async () => { const { accessToken } = await createTestProject({ project: { superAdmin: false }, membership: { admin: true }, withAccessToken: true, }); const res2 = await request(app) .post(`/fhir/R4/CodeSystem/$import`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'system', valueUri: 'http://terminology.hl7.org/CodeSystem/v3-RoleCode' }, { name: 'concept', valueCoding: { code: 'NIBL', display: 'nibling' } }, ], }); expect(res2.status).toStrictEqual(400); }); test('Imports concepts and synonym designations', async () => { const res = await request(app) .post(`/fhir/R4/CodeSystem/$import`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'system', valueUri: snomed.url }, { name: 'concept', valueCoding: { code: '37931006', display: 'Auscultation (procedure)' } }, { name: 'designation', part: [ { name: 'code', valueCode: '37931006' }, { name: 'value', valueString: 'Listening' }, ], }, { name: 'designation', part: [ { name: 'code', valueCode: '37931006' }, { name: 'language', valueCode: 'fr' }, { name: 'value', valueString: 'auscultation (intervention)' }, ], }, ], }); expect(res.status).toStrictEqual(200); const coding = await assertCodeExists(snomed.id, '37931006'); expect(coding.isSynonym).toBe(false); }); }); async function assertCodeExists(system: string | undefined, code: string): Promise<any> { const db = getDatabasePool(DatabaseMode.READER); const coding = await selectCoding(system as string, code) .column('isSynonym') .where('synonymOf', '=', null) .execute(db); expect(coding).toHaveLength(1); return coding[0]; } async function assertPropertyExists( system: string | undefined, code: string, property: string, value: string ): Promise<any> { const db = getDatabasePool(DatabaseMode.READER); const query = new SelectQuery('Coding_Property'); const codingTable = query.getNextJoinAlias(); query.join( 'INNER JOIN', 'Coding', codingTable, new Condition(new Column('Coding_Property', 'coding'), '=', new Column(codingTable, 'id')) ); const propertyTable = query.getNextJoinAlias(); query.join( 'INNER JOIN', 'CodeSystem_Property', propertyTable, new Condition(new Column('Coding_Property', 'property'), '=', new Column(propertyTable, 'id')) ); const results = await query .column('value') .column('target') .where(new Column(codingTable, 'system'), '=', system) .where(new Column(codingTable, 'code'), '=', code) .where(new Column(propertyTable, 'code'), '=', property) .execute(db); for (const row of results) { if (row.value === value) { return row; } } throw new Error(`Expected code ${code} to have property ${property}: ${value}`); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server