DOCUMENT_REGISTRY_FILTER_TYPE_LOCALLY, when enabled, skips the `type` query param on GET /DocumentReference to the document registry and filters the resulting searchset by type client-side instead, matching the same system|code / |code / code token semantics used elsewhere. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
183 lines
7.2 KiB
JavaScript
183 lines
7.2 KiB
JavaScript
const config = require('../config');
|
|
const { createBusRequest } = require('../utils/busAuth');
|
|
const { default: axios } = require('axios');
|
|
|
|
|
|
const INDICE_ATENCION_URL = config.bus.documentRegistryUrl;
|
|
|
|
const LOCAL_URL = "https://federador.qa-bus-interoperabilidad.svc.cluster.local:8080/fhir/DocumentReference";
|
|
|
|
function maskPrivateURL(patientId) {
|
|
return patientId.replace(LOCAL_URL, INDICE_ATENCION_URL);
|
|
}
|
|
|
|
|
|
|
|
async function findDocumentReferenceById(token, id) {
|
|
const request = createBusRequest(token);
|
|
const response = await request.get(
|
|
URL.parse(`${INDICE_ATENCION_URL}/${id}`)
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
|
|
async function findDocumentReferenceByUrl(token, id) {
|
|
const request = createBusRequest(token);
|
|
const response = await request.get(
|
|
URL.parse(id, INDICE_ATENCION_URL)
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
/**
|
|
* Posts a DocumentReference to the document registry
|
|
* (POST /fhir/DocumentReference).
|
|
* @param {string} documentRegistryUrl - Base URL of the document registry service.
|
|
* @param {string} token - Bearer access token.
|
|
* @param {object} documentReference - FHIR DocumentReference resource to register.
|
|
* @returns {Promise<object>} The created DocumentReference resource returned by the registry.
|
|
* @todo Agregar system http://federador.msal.gob.ar/uri para armar el identificador del custodian: http://federador.msal.gob.ar/uri|<custodianId>
|
|
*/
|
|
async function createDocumentReference(token, documentReference) {
|
|
const request = createBusRequest(token);
|
|
const response = await request.post(
|
|
URL.parse(INDICE_ATENCION_URL),
|
|
documentReference
|
|
);
|
|
const location = maskPrivateURL(response.headers['location']);
|
|
return findDocumentReferenceByUrl(token, location);
|
|
}
|
|
/**
|
|
* Searches DocumentReferences in the document registry by patient subject identifier
|
|
* (GET /fhir/DocumentReference?subject=system|value).
|
|
* @param {string} documentRegistryUrl - Base URL of the document registry service.
|
|
* @param {string} token - Bearer access token.
|
|
* @param {string} subjectSystem - Identifier system of the patient.
|
|
* @param {string} subjectValue - Identifier value of the patient.
|
|
* @returns {Promise<object>} FHIR Bundle (searchset) with matching DocumentReferences.
|
|
*/
|
|
async function findDocumentReferenceBySubject(token, subjectSystem, subjectValue) {
|
|
const request = createBusRequest(token);
|
|
const response = await request.get(
|
|
URL.parse(INDICE_ATENCION_URL),
|
|
{
|
|
params: { subject: `${subjectSystem}|${subjectValue}` },
|
|
}
|
|
);
|
|
return response.data;
|
|
}
|
|
|
|
/**
|
|
* Parses a FHIR token search value (`system|code`, `|code` o `code`) into its parts.
|
|
* `system === null` indica la forma `|code` (exige coding sin system).
|
|
* `system === undefined` indica la forma `code` (sin restricción de system).
|
|
* @param {string} token
|
|
* @returns {{ system: string|null|undefined, code: string }}
|
|
*/
|
|
function parseTypeToken(token) {
|
|
const pipeIndex = token.indexOf('|');
|
|
if (pipeIndex === -1) {
|
|
return { system: undefined, code: token };
|
|
}
|
|
const system = token.slice(0, pipeIndex);
|
|
return { system: system === '' ? null : system, code: token.slice(pipeIndex + 1) };
|
|
}
|
|
|
|
/**
|
|
* Indica si el CodeableConcept `type` de un DocumentReference matchea el token FHIR dado,
|
|
* replicando la semántica estándar de búsqueda por token (`system|code`, `|code` o `code`)
|
|
* que el índice de documentos aplicaría del lado del servidor.
|
|
* @param {object} resource - DocumentReference resource.
|
|
* @param {string} token - Token FHIR de DocumentReference.type.
|
|
* @returns {boolean}
|
|
*/
|
|
function matchesTypeToken(resource, token) {
|
|
const { system, code } = parseTypeToken(token);
|
|
const codings = resource?.type?.coding ?? [];
|
|
return codings.some(coding => {
|
|
if (system === null) {
|
|
return !coding.system && coding.code === code;
|
|
}
|
|
if (system !== undefined) {
|
|
return coding.system === system && coding.code === code;
|
|
}
|
|
return coding.code === code;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Filtra las entries de un Bundle searchset de DocumentReference por type,
|
|
* ajustando `total` a la cantidad de entries resultantes.
|
|
* @param {object} bundle - FHIR Bundle (searchset).
|
|
* @param {string} type - Token FHIR de DocumentReference.type.
|
|
* @returns {object} Bundle filtrado.
|
|
*/
|
|
function filterBundleByType(bundle, type) {
|
|
if (!bundle || !Array.isArray(bundle.entry)) {
|
|
return bundle;
|
|
}
|
|
const entry = bundle.entry.filter(e => matchesTypeToken(e.resource, type));
|
|
return { ...bundle, entry, total: entry.length };
|
|
}
|
|
|
|
/**
|
|
* Searches DocumentReferences in the document registry by patient internal ID,
|
|
* opcionalmente filtrando por tipo de documento
|
|
* (GET /fhir/DocumentReference?patient=value[&type=system|code]).
|
|
*
|
|
* Si `config.bus.filterDocumentTypeLocally` está activo y se pidió `type`, el parámetro
|
|
* `type` no se envía al índice de documentos: se piden todos los DocumentReference del
|
|
* subject y el filtrado por tipo se hace localmente sobre el Bundle resultante.
|
|
* @param {string} documentRegistryUrl - Base URL of the document registry service.
|
|
* @param {string} token - Bearer access token.
|
|
* @param {string} patientId - Internal patient ID in the document registry.
|
|
* @param {string} [type] - Token FHIR (`system|code` o `code`) de DocumentReference.type, ej: `http://loinc.org|60591-5`.
|
|
* @returns {Promise<object>} FHIR Bundle (searchset) with matching DocumentReferences.
|
|
*/
|
|
async function findDocumentReferenceByPatient(token, patientId, type) {
|
|
const request = createBusRequest(token);
|
|
const filterLocally = Boolean(type) && config.bus.filterDocumentTypeLocally;
|
|
const params = { subject: patientId };
|
|
if (type && !filterLocally) {
|
|
params.type = type;
|
|
}
|
|
const response = await request.get(
|
|
URL.parse(INDICE_ATENCION_URL),
|
|
{ params }
|
|
);
|
|
return filterLocally ? filterBundleByType(response.data, type) : response.data;
|
|
}
|
|
|
|
/**
|
|
* Searches DocumentReferences in the document registry filtered by subject, custodian and type
|
|
* (GET /fhir/DocumentReference?subject=...&custodian=...&type=...).
|
|
* @param {string} documentRegistryUrl - Base URL of the document registry service.
|
|
* @param {string} token - Bearer access token.
|
|
* @param {{ system: string, value: string }} subject - Patient identifier (TokenParam).
|
|
* @param {{ system: string, value: string }} custodian - Custodian identifier (TokenParam).
|
|
* @param {{ system: string, value: string }} type - Document type (TokenParam, e.g. { system: 'http://loinc.org', value: '60591-5' }).
|
|
* @returns {Promise<object>} FHIR Bundle (searchset) with matching DocumentReferences.
|
|
*/
|
|
async function searchDocumentReference(token, subject, custodian, type) {
|
|
const request = createBusRequest(token);
|
|
const response = await request.get(
|
|
URL.parse(INDICE_ATENCION_URL),
|
|
{
|
|
params: {
|
|
subject: `${subject.system}|${subject.value}`,
|
|
custodian: `${custodian.system}|${custodian.value}`,
|
|
type: `${type.system}|${type.value}`,
|
|
},
|
|
});
|
|
return response.data;
|
|
}
|
|
|
|
module.exports = {
|
|
findDocumentReferenceById,
|
|
createDocumentReference,
|
|
findDocumentReferenceBySubject,
|
|
findDocumentReferenceByPatient,
|
|
searchDocumentReference
|
|
};
|