import axios from 'axios' import genbankParser from 'genbank-parser' import { XMLParser } from 'fast-xml-parser' import jsonata from 'jsonata'; const simpleJSON = (json:any):any => { if (Array.isArray(json)) { if (json.length === 1) { return simpleJSON(json[0]) } else { return json } } else if (typeof json === 'object') { if (Object.keys(json).length === 1 && typeof json[Object.keys(json)[0]] === 'object') { return simpleJSON(json[Object.keys(json)[0]]) } else { return json } } else { return json } } const renameKeys = (json:any):any => { if(Array.isArray(json)) { return json.map(e => renameKeys(e)) } else if (typeof json === 'object') { const newObj:any = {} Object.keys(json).map(key => { let tmp if(typeof json[key] === 'object') { tmp = renameKeys(json[key]) } else { tmp = json[key] } newObj[key.replace(/-/g,"_")] = tmp }) return newObj } else { return json } } const getEsearch = async (params: any) => { const endpoint = params?.endpoint ? params.endpoint : 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi' const queries = Array.isArray(params?.query) ? params?.query : [params?.query] params.id = Array.isArray(params?.id) ? params.id.join(',') : params.id let allowedParams: string[] let connType: string = 'get' if (endpoint.match('esearch')) { allowedParams = ['db', 'term', 'retmax', 'retstart', 'api_key'] params = {...params, retmax: 100000, retmode: 'xml'} } else if (endpoint.match('efetch')) { connType = 'get' allowedParams = ['id', 'db', 'retmode', 'rettype', 'retmax', 'api_key'] const retmode = params?.rettype === 'fasta' || params?.rettype === 'gb'? 'txt' : 'xml' params = {...params, retmax: 10000, retmode} } else if (endpoint.match('esummary')) { allowedParams = ['id', 'db', 'retmode', 'rettype', 'retstart', 'version', 'api_key'] params = {...params, retmax: 10000, retmode: 'xml', version: '2.0'} } let response:any = '' switch (connType) { case 'post': let postParam:any = {} Object.keys(params).flatMap(k => allowedParams.includes(k) ? postParam[k] = params[k] : []) response = await axios.post(endpoint, postParam) break; case 'get': const q = `${endpoint}?${Object.keys(params).flatMap(k => allowedParams.includes(k) ? k + '=' + params[k] : []).join('&')}` console.log(q); let block = 0 let ctrl = true while(ctrl && block <= 5) { try { response = await axios.get(q) ctrl = false } catch (error) {} block++ if(block === 6) { console.log("Dropping !!! ", q); } } default: break; } let json = Array.isArray(response.data) ? response.data.join('') : response.data if (params?.retmode) { switch (params.retmode) { case 'xml': const parser = new XMLParser({ ignoreAttributes: false, alwaysCreateTextNode: false, attributeNamePrefix: "", textNodeName: "value", allowBooleanAttributes: true, }) json = parser.parse(json) break; case 'gb': json = genbankParser(json) break; default: break; } } json = renameKeys(json) const results = [] for (const query of queries) { let result:any if (query !== '') { result = {query, value: jsonata(query).evaluate(json)/*simpleJSON(JSONPath({path: query, json})) */} } else { result = '' } results.push(result) } return simpleJSON(results) } module.exports = async (params:any) => await getEsearch(params)