esearch.ts 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import axios from 'axios'
  2. import genbankParser from 'genbank-parser'
  3. import { XMLParser } from 'fast-xml-parser'
  4. import { JSONPath } from 'jsonpath-plus';
  5. import jsonata from 'jsonata';
  6. import { log } from 'console';
  7. const simpleJSON = (json:any):any => {
  8. if (Array.isArray(json)) {
  9. if (json.length === 1) { return simpleJSON(json[0]) }
  10. else { return json }
  11. } else if (typeof json === 'object') {
  12. if (Object.keys(json).length === 1 && typeof json[Object.keys(json)[0]] === 'object') { return simpleJSON(json[Object.keys(json)[0]]) }
  13. else { return json }
  14. } else {
  15. return json
  16. }
  17. }
  18. const renameKeys = (json:any):any => {
  19. if(Array.isArray(json)) {
  20. return json.map(e => renameKeys(e))
  21. } else if (typeof json === 'object') {
  22. const newObj:any = {}
  23. Object.keys(json).map(key => {
  24. let tmp
  25. if(typeof json[key] === 'object') {
  26. tmp = renameKeys(json[key])
  27. } else {
  28. tmp = json[key]
  29. }
  30. newObj[key.replace(/-/g,"_")] = tmp
  31. })
  32. return newObj
  33. } else {
  34. return json
  35. }
  36. }
  37. const getEsearch = async (params: any) => {
  38. const endpoint = params?.endpoint ? params.endpoint : 'https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi'
  39. const queries = Array.isArray(params?.query) ? params?.query : [params?.query]
  40. params.id = Array.isArray(params?.id) ? params.id.join(',') : params.id
  41. let allowedParams: string[]
  42. let connType: string = 'get'
  43. if (endpoint.match('esearch')) {
  44. allowedParams = ['db', 'term', 'retmax', 'retstart', 'api_key']
  45. params = {...params, retmax: 100000, retmode: 'xml'}
  46. } else if (endpoint.match('efetch')) {
  47. connType = 'get'
  48. allowedParams = ['id', 'db', 'retmode', 'rettype', 'retmax', 'api_key']
  49. const retmode = params?.rettype === 'fasta' || params?.rettype === 'gb'? 'txt' : 'xml'
  50. params = {...params, retmax: 10000, retmode}
  51. } else if (endpoint.match('esummary')) {
  52. allowedParams = ['id', 'db', 'retmode', 'rettype', 'retstart', 'version', 'api_key']
  53. params = {...params, retmax: 10000, retmode: 'xml', version: '2.0'}
  54. }
  55. let response:any = ''
  56. switch (connType) {
  57. case 'post':
  58. let postParam:any = {}
  59. Object.keys(params).flatMap(k => allowedParams.includes(k) ? postParam[k] = params[k] : [])
  60. response = await axios.post(endpoint, postParam)
  61. break;
  62. case 'get':
  63. const q = `${endpoint}?${Object.keys(params).flatMap(k => allowedParams.includes(k) ? k + '=' + params[k] : []).join('&')}`
  64. console.log(q);
  65. let block = 0
  66. let ctrl = true
  67. while(ctrl && block <= 5) {
  68. try {
  69. response = await axios.get(q)
  70. ctrl = false
  71. } catch (error) {}
  72. block++
  73. if(block === 6) {
  74. console.log("Dropping !!! ", q);
  75. }
  76. }
  77. default:
  78. break;
  79. }
  80. let json = Array.isArray(response.data) ? response.data.join('') : response.data
  81. if (params?.retmode) {
  82. switch (params.retmode) {
  83. case 'xml':
  84. const parser = new XMLParser({
  85. ignoreAttributes: false,
  86. alwaysCreateTextNode: false,
  87. attributeNamePrefix: "",
  88. textNodeName: "value",
  89. allowBooleanAttributes: true,
  90. })
  91. json = parser.parse(json)
  92. break;
  93. case 'gb':
  94. json = genbankParser(json)
  95. break;
  96. default:
  97. break;
  98. }
  99. }
  100. json = renameKeys(json)
  101. const results = []
  102. for (const query of queries) {
  103. // https://www.npmjs.com/package/jsonpath-plus
  104. let result:any
  105. if (query !== '') {
  106. result = {query, value: jsonata(query).evaluate(json)/*simpleJSON(JSONPath({path: query, json})) */}
  107. } else {
  108. result = ''
  109. }
  110. results.push(result)
  111. }
  112. return simpleJSON(results)
  113. }
  114. module.exports = async (params:any) => await getEsearch(params)