11const { fetch } = require ( '../../../util' ) ;
22const _ = require ( 'lodash' ) ;
3- const qs = require ( 'query-string' ) ;
43const QuickLRU = require ( 'quick-lru' ) ;
54
6- const cleanUpEntrez = require ( './clean-up-entrez' ) ;
75const { GPROFILER_URL } = require ( '../../../config' ) ;
86const logger = require ( '../../logger' ) ;
97const { cachePromise } = require ( '../../cache' ) ;
108
11- const GPROFILER_GOST_URL = GPROFILER_URL + 'index.cgi' ;
9+ const toJSON = res => res . json ( ) ;
10+
11+ // See https://biit.cs.ut.ee/gprofiler/page/apis
12+ const GPROFILER_GOST_URL = GPROFILER_URL + 'api/gost/profile/' ;
1213const GPROFILER_DEFAULT_OPTS = {
13- output : 'mini' ,
1414 organism : 'hsapiens' ,
15- significant : 0 ,
16- sort_by_structure : 1 ,
17- ordered_query : 0 ,
18- as_ranges : 0 ,
19- no_iea : 1 ,
20- underrep : 0 ,
21- hierfiltering : 'none' ,
22- user_thr : 0.05 ,
23- min_set_size : 5 ,
24- max_set_size : 200 ,
25- threshold_algo : 'analytical' ,
26- domain_size_type : 'annotated' ,
27- custbg : [ ] ,
28- 'sf_GO:BP' : 1 ,
29- sf_REAC : 1 ,
30- prefix : 'ENTREZGENE_ACC'
15+ sources : [ 'GO:BP' , 'REAC' ] ,
16+ user_threshold : 0.05 ,
17+ all_results : false ,
18+ ordered : false ,
19+ combined : false ,
20+ measure_underrepresentation : false ,
21+ no_iea : true ,
22+ domain_scope : 'annotated' ,
23+ numeric_ns : 'ENTREZGENE_ACC' ,
24+ significance_threshold_method : 'g_SCS' ,
25+ background : [ ] ,
26+ no_evidences : true
3127} ;
3228
33- // parseGProfilerResponse(gProfilerResponse) takes the text response
34- // from gProfiler gProfilerResponse and parses it into JSON format
35- const parseGProfilerResponse = gProfilerResponse => {
36- let lines = gProfilerResponse . split ( '\n' ) . map ( line => {
37- if ( line . substring ( 0 , 1 ) === '#' ) { return '' ; }
38- return line ;
39- } ) ;
40-
41- let elements = _ . compact ( lines ) . map ( line => line . split ( '\t' ) ) ;
29+ const DEFAULT_FILTER_OPTS = {
30+ minSetSize : 5 ,
31+ maxSetSize : 200
32+ } ;
4233
34+ const parseGProfilerResponse = ( json , opts ) => {
4335 let pathways = [ ] ;
44- let P_VALUE_INDEX = 2 ;
45- let PATHWAY_ID_INDEX = 8 ;
46- let DESCRIPTION_INDEX = 11 ;
47- let GENE_INTERSECTION_LIST_INDEX = 13 ;
48-
49-
50- elements . forEach ( ele => {
51- let pathwayId = ele [ PATHWAY_ID_INDEX ] ;
52- let pValue = ele [ P_VALUE_INDEX ] ;
53- let description = ele [ DESCRIPTION_INDEX ] . trim ( ) ;
54- let geneIntersectionList = ele [ GENE_INTERSECTION_LIST_INDEX ] . split ( ',' ) . map ( gene => cleanUpEntrez ( gene ) ) ;
55-
36+ const {
37+ minSetSize = DEFAULT_FILTER_OPTS . minSetSize ,
38+ maxSetSize = DEFAULT_FILTER_OPTS . maxSetSize
39+ } = opts ;
40+ const pathwayInfoList = _ . get ( json , [ 'result' ] ) ;
41+ pathwayInfoList . forEach ( pathwayInfo => {
42+ let { native : id , name, p_value, term_size } = pathwayInfo ;
43+ if ( term_size < minSetSize || term_size > maxSetSize ) return ;
5644 pathways . push ( {
57- id : pathwayId ,
58- data : {
59- name : description ,
60- p_value : pValue ,
61- intersection : geneIntersectionList
62- }
45+ id,
46+ data : { name, p_value }
6347 } ) ;
6448 } ) ;
6549
6650 return { pathways } ;
6751} ;
6852
6953
54+ const validateParams = ( query , opts ) => {
55+ let error = null ,
56+ message = '' ;
57+ const { minSetSize, maxSetSize } = opts ;
58+
59+ if ( ! Array . isArray ( query ) ) message = 'ERROR: query must be an array' ;
60+ if ( minSetSize && ( typeof ( minSetSize ) != 'number' || minSetSize < 0 ) ) message = 'ERROR: minSetSize must be a positive number' ;
61+ if ( maxSetSize && ( typeof ( maxSetSize ) != 'number' || maxSetSize < 0 ) ) message = 'ERROR: maxSetSize must be a positive number' ;
62+ if ( ( minSetSize && maxSetSize ) && ( maxSetSize < minSetSize ) ) message = 'ERROR: minSetSize must be less than maxSetSize' ;
63+
64+ if ( ! _ . isEmpty ( message ) ) error = new Error ( message ) ;
65+ return error ;
66+ } ;
67+
68+ const getGProfilerOpts = query => _ . assign ( { } , GPROFILER_DEFAULT_OPTS , { query } ) ;
69+
7070// enrichmemt(query, opts) takes a list of gene identifiers query
7171// and an object of user settings opts
7272// and extracts enrichment information
7373// from g:Profiler for the query list based on userSetting
74- const rawEnrichment = ( query , opts ) => {
75- return new Promise ( ( resolve , reject ) => {
76- let {
77- minSetSize = GPROFILER_DEFAULT_OPTS . min_set_size ,
78- maxSetSize = GPROFILER_DEFAULT_OPTS . max_set_size ,
79- background = [ ]
80- } = opts ;
81-
82- if ( ! Array . isArray ( query ) ) {
83- reject ( new Error ( 'ERROR: genes should be an array' ) ) ;
84- }
85- if ( typeof ( minSetSize ) != 'number' ) {
86- reject ( new Error ( 'ERROR: minSetSize should be a number' ) ) ;
87- }
88- if ( minSetSize < 0 ) {
89- reject ( new Error ( 'ERROR: minSetSize should be >= 0' ) ) ;
90- }
91- if ( typeof ( maxSetSize ) != 'number' ) {
92- reject ( new Error ( 'ERROR: maxSetSize should be a number' ) ) ;
93- }
94- if ( maxSetSize < minSetSize ) {
95- reject ( new Error ( 'ERROR: maxSetSize should be >= minSetSize' ) ) ;
96- }
97- if ( ! Array . isArray ( background ) ) {
98- reject ( new Error ( 'ERROR: backgroundGenes should be an array' ) ) ;
99- }
100-
101- let gProfilerOpts = _ . assign ( { } , GPROFILER_DEFAULT_OPTS , {
102- query : query . sort ( ) . join ( ' ' ) ,
103- min_set_size : minSetSize ,
104- max_set_size : maxSetSize ,
105- custbg : background . join ( ' ' )
106- } ) ;
107-
108-
109- fetch ( GPROFILER_GOST_URL , { method : 'post' , body : qs . stringify ( gProfilerOpts ) } )
110- . then ( res => res . text ( ) )
111- . then ( gprofilerRes => parseGProfilerResponse ( gprofilerRes ) )
112- . then ( pathwayInfo => resolve ( pathwayInfo ) )
113- . catch ( err => {
114- logger . error ( `Error in rawEnrichment - ${ err . message } ` ) ;
115- throw err ;
116- } ) ;
117- } ) ;
74+ const rawEnrichment = ( query , opts ) => {
75+ const gProfilerOpts = getGProfilerOpts ( query , opts ) ;
76+
77+ return fetch ( GPROFILER_GOST_URL , {
78+ method : 'post' ,
79+ body : JSON . stringify ( gProfilerOpts ) ,
80+ headers : { 'Content-Type' : 'application/json' }
81+ } )
82+ . then ( toJSON )
83+ . then ( gprofilerRes => parseGProfilerResponse ( gprofilerRes , opts ) )
84+ . catch ( err => {
85+ logger . error ( `Error in rawEnrichment - ${ err . message } ` ) ;
86+ throw err ;
87+ } ) ;
11888} ;
11989
90+
12091const lruCache = new QuickLRU ( { maxSize : 100 } ) ;
12192
122- const enrichment = cachePromise ( rawEnrichment , lruCache ) ;
93+ const enrichmentWrapper = cachePromise ( rawEnrichment , lruCache ) ;
12394
95+ const enrichment = async ( query , opts ) => {
96+ const paramError = validateParams ( query , opts ) ;
97+ if ( paramError ) throw paramError ;
12498
99+ return enrichmentWrapper ( query . sort ( ) , opts ) ;
100+ } ;
125101
126102module . exports = { enrichment, parseGProfilerResponse } ;
0 commit comments