diff --git a/core/term/controller/snomed.controller.ts b/core/term/controller/snomed.controller.ts index 8ad0d109e3..22fd83475b 100644 --- a/core/term/controller/snomed.controller.ts +++ b/core/term/controller/snomed.controller.ts @@ -24,20 +24,25 @@ export interface ISnomedController { * Busca un array de conceptos SNOMED. */ - getConcepts(conceptsIds: String[]); + getConcepts(conceptsIds: String[], form?: String); /** * Busca conceptos por un texto. * Para el buscador de RUP. */ - searchTerms(text: String, options: { semanticTags?: String[]; languageCode?: 'es' | 'en'; expression?: string }); + searchTerms(text: String, options: { semanticTags?: String[]; languageCode?: 'es' | 'en'; expression?: string; form?: String }); /** * Busca valores concretos por relaciones entre conceptos */ getValuesByRelationships(expression: String, type: string); + + /** + * Busca conceptos por expresión utilizando browser (trae relaciones) + */ + searchTermWithRelationship(options: { text: String; languageCode?: 'es' | 'en'; expression?: String; semanticTags?: String[] }); } export const SnomedCtr: ISnomedController = SnomedSnowstorm as any; diff --git a/core/term/controller/snomed.snowstorm.ts b/core/term/controller/snomed.snowstorm.ts index a1d4dff63f..5b13a14910 100644 --- a/core/term/controller/snomed.snowstorm.ts +++ b/core/term/controller/snomed.snowstorm.ts @@ -115,7 +115,7 @@ export async function getChildren(sctid, { all = false, completed = true, leaf = return null; } -export async function getConcepts(conceptsIds: string[]) { +export async function getConcepts(conceptsIds: string[], form = 'stated') { const response = await httpGetSnowstorm(`${snomed.snowstormBranch}/concepts`, { limit: 1000, conceptIds: conceptsIds @@ -123,7 +123,7 @@ export async function getConcepts(conceptsIds: string[]) { if (response) { const items = response.items; const ps = items.map(async (concept) => { - const parents = await httpGetSnowstorm(`browser/${snomed.snowstormBranch}/concepts/${concept.conceptId}/parents`, { limit: 1000, form: 'stated' }); + const parents = await httpGetSnowstorm(`browser/${snomed.snowstormBranch}/concepts/${concept.conceptId}/parents`, { limit: 1000, form }); if (parents) { concept.relationships = parents; concept.relationships = filterRelationships(concept, { parent: true }); @@ -204,6 +204,7 @@ async function searchByExpression({ text, languageCode, expression, semanticTags ecl: expression }; const response = await httpGetSnowstorm(`${snomed.snowstormBranch}/concepts`, qs, languageCode); + if (response) { let { items } = response; items = items.map(cpt => { @@ -222,8 +223,54 @@ async function searchByExpression({ text, languageCode, expression, semanticTags return []; } +export async function searchTermWithRelationship({ text, languageCode, expression, semanticTags }) { + const qs: any = { + term: text, + activeFilter: true, + termActive: true, + language: languageCode, + limit: 20, + ecl: expression + }; + const response = await httpGetSnowstorm(`${snomed.snowstormBranch}/concepts`, qs, languageCode); + + if (response) { + let items = []; + if (response.items) { + const conceptIds = response.items.map(c => c.conceptId); + if (conceptIds.length > 0) { + const qsConcepts = { conceptIds }; + const concepts = await httpGetSnowstorm(`browser/${snomed.snowstormBranch}/concepts`, qsConcepts, languageCode); + items = concepts.items.map(cpt => { + const relationships = cpt.relationships ? cpt.relationships.filter(rel => rel.active && rel.typeId === IsASct && rel.target).map(rel => { + return { + conceptId: rel.target.conceptId, + term: rel.target.pt?.term || rel.target.fsn?.term, + fsn: rel.target.fsn?.term, + type: rel.characteristicType === 'INFERRED_RELATIONSHIP' ? 'inferred' : 'stated' + }; + }) : []; + + return { + conceptId: cpt.conceptId, + term: cpt.pt?.term || cpt.fsn?.term, + fsn: cpt.fsn?.term, + semanticTag: cpt.fsn?.term ? getSemanticTagFromFsn(cpt.fsn.term) : '', + relationships + }; + }); + } + } + if (semanticTags) { + items = items.filter(concept => semanticTags.includes(concept.semanticTag)); + } + return items; + } + return []; +} + export async function getValuesByRelationships(expression: string, type: string) { - const response = await searchTerms(null, { semanticTags:null, languageCode: 'es',expression }); + const response = await searchTerms(null, { semanticTags: null, languageCode: 'es', expression }); if (response) { const ps = response.map(async (concept) => { const concreteValues = await httpGetSnowstorm(`${snomed.snowstormBranch}/relationships?active=true&source=${concept.conceptId}&type=${type}`, { limit: 1000 }); diff --git a/core/term/routes/snomed.ts b/core/term/routes/snomed.ts index 7da4bcabe4..32a601622f 100644 --- a/core/term/routes/snomed.ts +++ b/core/term/routes/snomed.ts @@ -3,8 +3,8 @@ import * as express from 'express'; import * as utils from '../../../utils/utils'; import * as cie10 from '../schemas/cie10'; import { SnomedCIE10Mapping } from './../controller/mapping'; - import { SnomedCtr } from '../controller/snomed.controller'; +import { ECLQueriesCtr } from './../../../core/tm/eclqueries.routes'; const router = express.Router(); @@ -37,6 +37,26 @@ router.get('/snomed', async (req, res, next) => { } }); +/** * Busca medicamentos genéricos y comerciales por termino */ +router.get('/snomed/medicamentos', async (req, res, next) => { + const term = req.query.term as string; + if (!term) { + return res.json([]); + } + try { + const ecl = await ECLQueriesCtr.findOne({ key: 'receta:buscarTerminos' }); + const expression = ecl.valor; + const results = await SnomedCtr.searchTermWithRelationship({ text: term, expression, languageCode: 'es', semanticTags: ['fármaco de uso clínico', 'fármaco de uso clínico comercial'] }); + + if (results.length > 0) { + return res.json(results); + } + + return res.json([]); + } catch (e) { + return next(e); + } +}); /** * Mapea un concepto de snomed * diff --git a/core/term/routes/snomedv2.ts b/core/term/routes/snomedv2.ts index bb0a28efb9..abf656eabb 100644 --- a/core/term/routes/snomedv2.ts +++ b/core/term/routes/snomedv2.ts @@ -107,4 +107,46 @@ router.get('/snomed/relationships', async (req, res, next) => { } }); +/** + * Busca medicamentos por nombre comercial y devuelve el concepto con sus padres (genéricos) + */ +router.get('/snomed/medicamentos/comercial', async (req, res, next) => { + const term = req.query.term as string; + if (!term) { + return res.json([]); + } + try { + const results = await SnomedCtr.searchTerms(term, { expression: '<<373873005', languageCode: 'es' }); + const ids = results.slice(0, 20).map(r => r.conceptId); + if (ids.length > 0) { + const concepts = await SnomedCtr.getConcepts(ids); + return res.json(concepts); + } + return res.json([]); + } catch (e) { + return next(e); + } +}); + +/** + * Busca el concepto genérico asociado a un concepto comercial + */ +router.get('/snomed/medicamentos/comercial/:sctid/generico', async (req, res, next) => { + const sctid = req.params.sctid; + try { + const concepts = await SnomedCtr.getConcepts([sctid], 'inferred'); + if (concepts && concepts.length > 0) { + const concept = concepts[0]; + if (concept.relationships && concept.relationships.length > 0) { + const parentIds = concept.relationships.map(r => r.conceptId); + const generics = await SnomedCtr.getConcepts(parentIds, 'inferred'); + return res.json(generics); + } + } + return res.json([]); + } catch (e) { + return next(e); + } +}); + export = router;