UNPKG

60.6 kBJavaScriptView Raw
1"use strict";
2/// <reference path="../typings/index.d.ts" />
3Object.defineProperty(exports, "__esModule", { value: true });
4// TODO use a cache, such as
5// https://github.com/levelgraph/levelgraph
6require("source-map-support/register");
7if (!global.hasOwnProperty("XMLHttpRequest")) {
8 global.XMLHttpRequest = require("xhr2");
9}
10var fp_1 = require("lodash/fp");
11var lodash_1 = require("lodash");
12var Observable_1 = require("rxjs/Observable");
13require("rxjs/add/observable/dom/ajax");
14require("rxjs/add/observable/empty");
15require("rxjs/add/observable/forkJoin");
16require("rxjs/add/observable/from");
17require("rxjs/add/observable/throw");
18require("rxjs/add/observable/zip");
19require("rxjs/add/operator/buffer");
20require("rxjs/add/operator/bufferWhen");
21require("rxjs/add/operator/catch");
22require("rxjs/add/operator/concatAll");
23require("rxjs/add/operator/debounceTime");
24require("rxjs/add/operator/delay");
25require("rxjs/add/operator/distinctUntilChanged");
26require("rxjs/add/operator/do");
27require("rxjs/add/operator/filter");
28require("rxjs/add/operator/find");
29require("rxjs/add/operator/mergeMap");
30require("rxjs/add/operator/map");
31require("rxjs/add/operator/multicast");
32require("rxjs/add/operator/publishReplay");
33require("rxjs/add/operator/race");
34require("rxjs/add/operator/reduce");
35require("rxjs/add/operator/skip");
36require("rxjs/add/operator/toArray");
37require("rx-extra/add/operator/throughNodeStream");
38var Subject_1 = require("rxjs/Subject");
39var TSVGetter_1 = require("./spinoffs/TSVGetter");
40var dataTypeParsers_1 = require("./spinoffs/dataTypeParsers");
41var jsonld_utils_1 = require("./spinoffs/jsonld-utils");
42var VError = require("verror");
43var BDB = "http://vocabularies.bridgedb.org/ops#";
44var BIOPAX = "http://www.biopax.org/release/biopax-level3.owl#";
45var IDENTIFIERS = "http://identifiers.org/";
46var OWL = "http://www.w3.org/2002/07/owl#";
47var RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
48var CSV_OPTIONS = { objectMode: true, delimiter: "\t" };
49// time to wait for no new calls to xrefs() before we
50// batch up all calls in the queue and send to xrefsBatch()
51var XREF_REQUEST_DEBOUNCE_TIME = 10; // ms
52var XREF_REQUEST_CHUNK_SIZE = 100;
53var BRIDGE_DB_REPO_CDN = "https://raw.githubusercontent.com/bridgedb/BridgeDb/";
54var BRIDGE_DB_COMMIT_HASH = "465f9f944d09cefbb167eceb9c69499a764100a2";
55exports.CONFIG_DEFAULT = {
56 baseIri: "https://webservice.bridgedb.org/",
57 context: [
58 BRIDGE_DB_REPO_CDN,
59 BRIDGE_DB_COMMIT_HASH,
60 "/org.bridgedb.bio/resources/org/bridgedb/bio/jsonld-context.jsonld"
61 ].join(""),
62 dataSourcesMetadataHeadersIri: [
63 BRIDGE_DB_REPO_CDN,
64 BRIDGE_DB_COMMIT_HASH,
65 "/org.bridgedb.bio/resources/org/bridgedb/bio/datasources_headers.txt"
66 ].join(""),
67 dataSourcesMetadataIri: [
68 BRIDGE_DB_REPO_CDN,
69 BRIDGE_DB_COMMIT_HASH,
70 "/org.bridgedb.bio/resources/org/bridgedb/bio/datasources.txt"
71 ].join(""),
72 http: {
73 timeout: 4 * 1000,
74 retryLimit: 2,
75 retryDelay: 3 * 1000
76 }
77};
78// these properties can be trusted to
79// uniquely identify a data source.
80var DATASOURCE_ID_PROPERTIES = [
81 "id",
82 "miriamUrn",
83 "conventionalName",
84 "preferredPrefix",
85 "systemCode"
86];
87var IRI_TO_NAME = {
88 "http://www.w3.org/1999/02/22-rdf-syntax-ns#about": "id",
89 "http://identifiers.org/idot/preferredPrefix": "preferredPrefix",
90 "http://identifiers.org/miriam.collection/": "miriamUrn"
91};
92var NAME_TO_IRI = lodash_1.invert(IRI_TO_NAME);
93/**
94 * miriamUrnToIdentifiersIri
95 *
96 * @param {string} miriamUrn
97 * @return {string} e.g., "http://identifiers.org/ncbigene/"
98 */
99function miriamUrnToIdentifiersIri(miriamUrn) {
100 var preferredPrefix = miriamUrnToPreferredPrefix(miriamUrn);
101 if (preferredPrefix) {
102 return IDENTIFIERS + preferredPrefix + "/";
103 }
104}
105/**
106 * miriamUrnToPreferredPrefix
107 *
108 * @param {string} uri, e.g., "urn:miriam:ncbigene"
109 * @return {string} preferredPrefix from identifiers.org/Miriam, e.g., "ncbigene"
110 */
111function miriamUrnToPreferredPrefix(miriamUrn) {
112 // Make sure it's actually an identifiers.org namespace,
113 // not a BridgeDb system code:
114 if (miriamUrn.indexOf("urn:miriam:") > -1) {
115 return miriamUrn.substring(11, miriamUrn.length);
116 }
117}
118var BridgeDb = /** @class */ (function () {
119 function BridgeDb(config) {
120 var _this = this;
121 if (config === void 0) { config = exports.CONFIG_DEFAULT; }
122 this.convertXrefDataSourceTo = fp_1.curry(function (targetType, input) {
123 var bridgeDb = _this;
124 return bridgeDb.dataSourceMappings$
125 .map(function (mapping) {
126 return !!mapping[input] && mapping[input][targetType];
127 })
128 .catch(function (err) {
129 throw new VError(err, "calling bridgedb.convertXrefDataSourceTo");
130 });
131 });
132 this.identifyHeaderNameForXrefDataSource = function (input) {
133 var bridgeDb = _this;
134 return bridgeDb.dataSourceMappings$
135 .map(function (mapping) { return mapping[input]; })
136 .filter(fp_1.negate(lodash_1.isEmpty))
137 .map(function (dataSource) {
138 return lodash_1.toPairs(dataSource)
139 .filter(function (_a) {
140 var key = _a[0], value = _a[1];
141 return value === input;
142 })
143 .map(function (_a) {
144 var key = _a[0], value = _a[1];
145 return key;
146 })
147 .reduce(function (acc, key) {
148 // we want to return the IRI, if it's available.
149 return acc.length > key.length ? acc : key;
150 });
151 })
152 .catch(function (err) {
153 throw new VError(err, "calling bridgedb.identifyHeaderNameForXrefDataSource");
154 });
155 };
156 this.dataSourceProperties = function (input) {
157 var bridgeDb = _this;
158 return bridgeDb.dataSourceMappings$
159 .map(function (mapping) { return mapping[input]; })
160 .catch(function (err) {
161 throw new VError(err, "calling bridgedb.dataSourceProperties");
162 });
163 };
164 this.parseXrefRow = function (_a) {
165 var xrefIdentifier = _a[0], dataSourceConventionalName = _a[1], symbol = _a[2];
166 var bridgeDb = _this;
167 if (!xrefIdentifier || !dataSourceConventionalName) {
168 return Observable_1.Observable.empty();
169 }
170 return bridgeDb.dataSourceMappings$
171 .map(function (mapping) { return mapping[dataSourceConventionalName]; })
172 .map(function (dataSource) {
173 var xref = {
174 xrefIdentifier: xrefIdentifier,
175 isDataItemIn: dataSource
176 };
177 if (symbol) {
178 xref.symbol = symbol;
179 }
180 if (dataSource.hasOwnProperty("id")) {
181 xref.id = encodeURI(dataSource.id + xref.xrefIdentifier);
182 }
183 return xref;
184 });
185 };
186 this.xrefsBatch = function (organism, oneOrMoreXrefDataSources, xrefIdentifiers, desiredXrefDataSourceOrSources) {
187 var bridgeDb = _this;
188 var desiredXrefDataSources = jsonld_utils_1.arrayify(desiredXrefDataSourceOrSources);
189 var dataSourceFilterParamSection = desiredXrefDataSources.length === 1
190 ? "?dataSource=" + desiredXrefDataSources[0]
191 : "";
192 var xrefDataSources = lodash_1.isArray(oneOrMoreXrefDataSources)
193 ? oneOrMoreXrefDataSources
194 : lodash_1.fill(new Array(xrefIdentifiers.length), oneOrMoreXrefDataSources);
195 var convertXrefDataSourceToConventionalName = bridgeDb.convertXrefDataSourceTo("conventionalName");
196 var callString = "Called xrefsBatch(\n\t" + organism + ",\n\t" + oneOrMoreXrefDataSources + ",\n\t" + xrefIdentifiers + ",\n\t" + desiredXrefDataSourceOrSources + "\n)";
197 var postURL = bridgeDb.config.baseIri +
198 organism +
199 "/xrefsBatch" +
200 dataSourceFilterParamSection;
201 var inputXrefDataSourceHeaderName$ = Observable_1.Observable.from(xrefDataSources)
202 .mergeMap(function (xrefDataSource) {
203 return bridgeDb.identifyHeaderNameForXrefDataSource(xrefDataSource);
204 })
205 .find(lodash_1.isString);
206 var desiredXrefDataSourceHeaderName$ = lodash_1.isEmpty(desiredXrefDataSources)
207 ? inputXrefDataSourceHeaderName$
208 : Observable_1.Observable.from(desiredXrefDataSources)
209 .mergeMap(function (xrefDataSource) {
210 return bridgeDb.identifyHeaderNameForXrefDataSource(xrefDataSource);
211 })
212 .find(lodash_1.isString);
213 var dataSourceConventionalNames$ = Observable_1.Observable.from(xrefDataSources)
214 .mergeMap(function (xrefDataSource) {
215 return convertXrefDataSourceToConventionalName(xrefDataSource);
216 })
217 .toArray();
218 return Observable_1.Observable.forkJoin(inputXrefDataSourceHeaderName$, desiredXrefDataSourceHeaderName$, dataSourceConventionalNames$).mergeMap(function (_a) {
219 var inputXrefDataSourceHeaderName = _a[0], desiredXrefDataSourceHeaderName = _a[1], dataSourceConventionalNames = _a[2];
220 // TODO: find out how we're getting duplicate rows in the body.
221 // For at least one example, see RefSeqSample.tsv in test dir.
222 // It has duplicates.
223 var body = fp_1.uniq(lodash_1.zip(xrefIdentifiers, dataSourceConventionalNames)
224 .filter(function (pair) { return !!pair[1]; })
225 .map(function (x) { return x.join("\t"); })).join("\n");
226 if (lodash_1.isEmpty(body.replace(/[\ \n\t]/g, ""))) {
227 return Observable_1.Observable.throw(new Error("Error: body is empty. " + callString));
228 }
229 var convertXrefDataSourceToInputFormat = bridgeDb.convertXrefDataSourceTo(inputXrefDataSourceHeaderName);
230 var convertXrefDataSourceToDesiredInputFormat = bridgeDb.convertXrefDataSourceTo(desiredXrefDataSourceHeaderName);
231 return bridgeDb
232 .getTSV(postURL, "POST", body)
233 .mergeMap(function (xrefStringsByInput) {
234 var inputXrefIdentifier = xrefStringsByInput[0];
235 var inputXrefDataSource = xrefStringsByInput[1];
236 var xrefsString = xrefStringsByInput[2];
237 // NOTE: splitting by comma, e.g.:
238 // 'T:GO:0031966,Il:ILMN_1240829' -> ['T:GO:0031966', 'Il:ILMN_1240829']
239 return Observable_1.Observable.from(xrefsString.split(","))
240 .mergeMap(function (xrefString) {
241 if (xrefString === "N/A") {
242 return Observable_1.Observable.empty();
243 }
244 // NOTE: splitting by FIRST colon only, e.g.:
245 // 'T:GO:0031966' -> ['T', 'GO:0031966']
246 var _a = xrefString.split(/:(.+)/), returnedXrefDataSource = _a[0], returnedXrefIdentifier = _a[1];
247 return convertXrefDataSourceToDesiredInputFormat(returnedXrefDataSource).map(function (desiredXrefDataSource) {
248 return {
249 xrefDataSource: desiredXrefDataSource,
250 xrefIdentifier: returnedXrefIdentifier
251 };
252 });
253 })
254 .filter(function (_a) {
255 var xrefDataSource = _a.xrefDataSource;
256 return (!lodash_1.isEmpty(xrefDataSource) &&
257 (desiredXrefDataSources.length === 0 ||
258 desiredXrefDataSources.indexOf(xrefDataSource) > -1));
259 })
260 .toArray()
261 .mergeMap(function (xrefs) {
262 if (desiredXrefDataSources.length > 0) {
263 // Sort xrefs in the order matching the order that the user specified
264 // in desiredXrefDataSource1, desiredXrefDataSource2, ...
265 xrefs.sort(function (a, b) {
266 var aIndex = desiredXrefDataSources.indexOf(a.xrefDataSource);
267 var bIndex = desiredXrefDataSources.indexOf(b.xrefDataSource);
268 if (aIndex < bIndex) {
269 return -1;
270 }
271 else if (aIndex > bIndex) {
272 return 1;
273 }
274 else {
275 return 0;
276 }
277 });
278 }
279 return convertXrefDataSourceToInputFormat(inputXrefDataSource).map(function (inputXrefDataSource) {
280 return {
281 organism: organism,
282 inputXrefDataSource: inputXrefDataSource,
283 inputXrefIdentifier: inputXrefIdentifier,
284 xrefs: xrefs,
285 // NOTE: return desiredXrefDataSources for use in xrefsResponseQueue
286 desiredXrefDataSources: desiredXrefDataSources
287 };
288 });
289 });
290 })
291 .catch(null, function (err) {
292 throw new VError(err, "Error: " + callString);
293 });
294 });
295 };
296 var bridgeDb = this;
297 lodash_1.defaultsDeep(config, exports.CONFIG_DEFAULT);
298 bridgeDb.config = config;
299 var xrefsRequestQueue = (bridgeDb.xrefsRequestQueue = new Subject_1.Subject());
300 var debounceSignel = xrefsRequestQueue.debounceTime(XREF_REQUEST_DEBOUNCE_TIME);
301 bridgeDb.xrefsResponseQueue = xrefsRequestQueue
302 .filter(function (_a) {
303 var organism = _a.organism, xrefDataSource = _a.xrefDataSource, xrefIdentifier = _a.xrefIdentifier;
304 return !lodash_1.isEmpty(organism) &&
305 !lodash_1.isEmpty(xrefDataSource) &&
306 !lodash_1.isEmpty(xrefIdentifier);
307 })
308 /* TODO should we use this? It doesn't seem to work, and we could just use caching.
309 .distinctUntilChanged(function(
310 a: { xrefDataSource; xrefIdentifier },
311 b: { xrefDataSource; xrefIdentifier }
312 ) {
313 return JSON.stringify(a) === JSON.stringify(b);
314 })
315 //*/
316 //.buffer(Observable.race(debounceSignel, xrefsRequestQueue.skip(2000)))
317 .bufferWhen(function () {
318 return Observable_1.Observable.race(debounceSignel, xrefsRequestQueue.skip(2000));
319 })
320 .filter(function (x) { return !lodash_1.isEmpty(x); })
321 .mergeMap(function (inputs) {
322 var firstInput = inputs[0];
323 var organism = firstInput.organism;
324 var xrefDataSources = inputs.map(function (input) { return input.xrefDataSource; });
325 var xrefIdentifiers = inputs.map(function (input) { return input.xrefIdentifier; });
326 var desiredXrefDataSources = firstInput.desiredXrefDataSources;
327 return bridgeDb.xrefsBatch(organism, xrefDataSources, xrefIdentifiers, desiredXrefDataSources);
328 })
329 .multicast(new Subject_1.Subject());
330 // toggle from cold to hot
331 bridgeDb.xrefsResponseQueue.connect();
332 var getTSV = (bridgeDb.getTSV = new TSVGetter_1.TSVGetter(config.http).get);
333 var dataSourcesMetadataHeaders$ = getTSV(config.dataSourcesMetadataHeadersIri).map(function (fields) {
334 var id = fields[4];
335 return {
336 // NOTE: the column number could be confusing, because it's one-based,
337 // so I'll just use the index instead and ignore the column number.
338 //column: parseFloat(fields[0]),
339 header: fields[1],
340 description: fields[2],
341 example_entry: fields[3],
342 id: id,
343 name: IRI_TO_NAME.hasOwnProperty(id)
344 ? IRI_TO_NAME[id]
345 : id.split(/[\/|#]/).pop(),
346 "http://www.w3.org/1999/02/22-rdf-syntax-ns#datatype": fields[5]
347 };
348 });
349 bridgeDb.dataSourceMappings$ = Observable_1.Observable.forkJoin(dataSourcesMetadataHeaders$.toArray(), getTSV(config.dataSourcesMetadataIri).toArray())
350 .mergeMap(function (results) {
351 var metadataByColumnIndex = results[0];
352 var rows = results[1];
353 return Observable_1.Observable.from(rows).map(function (fields) {
354 return fields.reduce(function (acc, field, i) {
355 var metadata = metadataByColumnIndex[i];
356 var id = metadata.id, name = metadata.name;
357 // NOTE: side effects
358 if (!!id && !(id in IRI_TO_NAME)) {
359 IRI_TO_NAME[id] = name;
360 NAME_TO_IRI[name] = id;
361 }
362 acc[name] = dataTypeParsers_1.dataTypeParsers[metadata[RDF + "datatype"]](field);
363 return acc;
364 }, {});
365 });
366 })
367 .map(function (dataSource) {
368 // remove empty properties, ie., properties with these values:
369 // ''
370 // NaN
371 // null
372 // undefined
373 // TODO what about empty plain object {} or array []
374 return lodash_1.omitBy(dataSource, function (value) {
375 return (value === "" || lodash_1.isNaN(value) || lodash_1.isNull(value) || lodash_1.isUndefined(value));
376 });
377 })
378 .map(function (dataSource) {
379 // Kludge to temporarily handle this issue:
380 // https://github.com/bridgedb/BridgeDb/issues/58
381 if (dataSource.id === "Sp") {
382 dataSource.id = "urn:miriam:uniprot";
383 }
384 // If the Miriam URN is unknown or unspecified, datasources.txt uses
385 // the BridgeDb system code as a placeholder value.
386 // So here we make sure "id" is actually a Miriam URN.
387 if (dataSource.hasOwnProperty("id") &&
388 dataSource.id.indexOf("urn:miriam:") > -1) {
389 // switch "id" property from Miriam URN to identifiers.org IRI
390 var miriamUrn = dataSource.id;
391 dataSource.miriamUrn = miriamUrn;
392 var preferredPrefix = miriamUrnToPreferredPrefix(miriamUrn);
393 if (preferredPrefix) {
394 dataSource.preferredPrefix = preferredPrefix;
395 dataSource.sameAs = dataSource.sameAs || [];
396 dataSource.sameAs.push(miriamUrn);
397 var identifiersIri = miriamUrnToIdentifiersIri(miriamUrn);
398 if (identifiersIri) {
399 dataSource.id = dataSource.hasIdentifiersOrgPattern = identifiersIri;
400 }
401 }
402 }
403 else {
404 delete dataSource.id;
405 }
406 return dataSource;
407 })
408 .map(function (dataSource) {
409 var primaryUriPattern = dataSource.hasPrimaryUriPattern;
410 if (!!primaryUriPattern) {
411 var regexXrefIdentifierPattern = dataSource.hasRegexPattern || ".*";
412 dataSource.hasRegexUriPattern = primaryUriPattern.replace("$id",
413 // removing ^ (start) and $ (end) from regexXrefIdentifierPattern
414 "(" + regexXrefIdentifierPattern.replace(/(^\^|\$$)/g, "") + ")");
415 // if '$id' is at the end of the primaryUriPattern
416 var indexOfDollaridWhenAtEnd = primaryUriPattern.length - 3;
417 if (primaryUriPattern.indexOf("$id") === indexOfDollaridWhenAtEnd) {
418 dataSource.sameAs = dataSource.sameAs || [];
419 dataSource.sameAs.push(primaryUriPattern.substr(0, indexOfDollaridWhenAtEnd));
420 }
421 }
422 if (dataSource.type) {
423 dataSource[BDB + "type"] = dataSource.type;
424 }
425 dataSource.type = "Dataset";
426 return dataSource;
427 })
428 .map(function (dataSource) {
429 var bdbType = dataSource[BDB + "type"];
430 if (!!bdbType) {
431 dataSource.subject = [];
432 /* Example of using 'subject' (from the VOID docs <http://www.w3.org/TR/void/#subject>):
433 :Bio2RDF a void:Dataset;
434 dcterms:subject <http://purl.uniprot.org/core/Gene>;
435 .
436
437 The closest concepts from the WP, BioPAX and MESH vocabularies are included below,
438 with the default vocabulary being WP.
439
440 Note that in BioPAX, 'ProteinReference' is to 'Protein' as
441 'Class' is to 'Instance' or
442 'platonic ideal of http://identifiers.org/uniprot/P78527' is to
443 'one specific example of http://identifiers.org/uniprot/P78527'
444 with the same logic applying for Dna, Rna and SmallMolecule. As such, it appears the
445 subject of Uniprot is best described in BioPAX terms as biopax:ProteinReference instead
446 of biopax:Protein.
447
448 It is unclear whether the subject of Entrez Gene is biopax:DnaReference or biopax:Gene,
449 but I'm going with biopax:DnaReference for now because it appears to be analogous to
450 ProteinReference and SmallMoleculeReference.
451 //*/
452 if (bdbType === "gene" ||
453 // TODO should the following two conditions be removed?
454 bdbType === "probe" ||
455 dataSource.preferredPrefix === "go") {
456 dataSource.subject.push("GeneProduct");
457 dataSource.subject.push(BIOPAX + "DnaReference");
458 }
459 else if (bdbType === "rna") {
460 dataSource.subject.push("Rna");
461 dataSource.subject.push(BIOPAX + "RnaReference");
462 }
463 else if (bdbType === "protein") {
464 dataSource.subject.push("Protein");
465 dataSource.subject.push(BIOPAX + "ProteinReference");
466 }
467 else if (bdbType === "metabolite") {
468 dataSource.subject.push("Metabolite");
469 dataSource.subject.push(BIOPAX + "SmallMoleculeReference");
470 }
471 else if (bdbType === "pathway") {
472 // BioPAX does not have a term for pathways that is analogous to
473 // biopax:ProteinReference for proteins.
474 dataSource.subject.push("Pathway");
475 dataSource.subject.push(BIOPAX + "Pathway");
476 }
477 else if (bdbType === "ontology") {
478 dataSource.subject.push(OWL + "Ontology");
479 }
480 else if (bdbType === "interaction") {
481 dataSource.subject.push("Interaction");
482 dataSource.subject.push(BIOPAX + "Interaction");
483 }
484 }
485 dataSource.alternatePrefix = [dataSource.systemCode];
486 return dataSource;
487 })
488 .reduce(function (acc, dataSource) {
489 DATASOURCE_ID_PROPERTIES.forEach(function (propertyName) {
490 var propertyValue = dataSource[propertyName];
491 var propertyId = NAME_TO_IRI[propertyName];
492 dataSource[propertyId] = propertyValue;
493 acc[propertyValue] = dataSource;
494 });
495 return acc;
496 }, {})
497 .catch(function (err) {
498 throw new VError(err, "Setting up dataSourceMappings$ in constructor");
499 })
500 .publishReplay();
501 // toggle from cold to hot
502 bridgeDb.dataSourceMappings$.connect();
503 } // end constructor
504 BridgeDb.prototype.attributes = function (organism, xrefDataSource, xrefIdentifier) {
505 var bridgeDb = this;
506 return bridgeDb
507 .getTSV(bridgeDb.config.baseIri +
508 organism +
509 "/attributes/" +
510 xrefDataSource +
511 "/" +
512 xrefIdentifier)
513 .reduce(function (acc, fields) {
514 var key = lodash_1.camelCase(fields[0]);
515 var value = fields[1];
516 acc[key] = value;
517 return acc;
518 }, {})
519 .catch(function (err) {
520 throw new VError(err, "calling bridgedb.attributes");
521 });
522 };
523 BridgeDb.prototype.attributeSearch = function (organism, query, attrName) {
524 var bridgeDb = this;
525 var attrNameParamSection = attrName ? "?attrName=" + attrName : "";
526 return bridgeDb
527 .getTSV(bridgeDb.config.baseIri +
528 organism +
529 "/attributeSearch/" +
530 query +
531 attrNameParamSection)
532 .mergeMap(bridgeDb.parseXrefRow)
533 .catch(function (err) {
534 throw new VError(err, "calling bridgedb.attributeSearch");
535 });
536 };
537 BridgeDb.prototype.attributeSet = function (organism) {
538 var bridgeDb = this;
539 return bridgeDb
540 .getTSV(bridgeDb.config.baseIri + organism + "/attributeSet")
541 .reduce(function (acc, row) {
542 acc.push(row[0]);
543 return acc;
544 }, [])
545 .catch(function (err) {
546 throw new VError(err, "calling bridgedb.attributeSet");
547 });
548 };
549 BridgeDb.prototype.isFreeSearchSupported = function (organism) {
550 var bridgeDb = this;
551 var ajaxRequest = {
552 url: bridgeDb.config.baseIri + organism + "/isFreeSearchSupported",
553 method: "GET",
554 responseType: "text",
555 timeout: bridgeDb.config.http.timeout,
556 crossDomain: true
557 };
558 return (Observable_1.Observable.ajax(ajaxRequest)
559 .map(function (ajaxResponse) { return ajaxResponse.xhr.response; })
560 // NOTE: must compare with 'true' as a string, because the response is just a string, not a parsed JS boolean.
561 .map(function (res) { return res === "true"; })
562 // TODO is this TS correct?
563 .catch(function (err) {
564 throw new VError(err, "calling bridgedb.isFreeSearchSupported");
565 }));
566 };
567 BridgeDb.prototype.isMappingSupported = function (organism, sourceXrefDataSource, targetXrefDataSource) {
568 var bridgeDb = this;
569 var ajaxRequest = {
570 url: bridgeDb.config.baseIri +
571 organism + "/isMappingSupported/" + sourceXrefDataSource + "/" + targetXrefDataSource,
572 method: "GET",
573 responseType: "text",
574 timeout: bridgeDb.config.http.timeout,
575 crossDomain: true
576 };
577 return (Observable_1.Observable.ajax(ajaxRequest)
578 .map(function (ajaxResponse) { return ajaxResponse.xhr.response; })
579 // NOTE: must compare with 'true' as a string, because the response is just a string, not a parsed JS boolean.
580 .map(function (res) { return res === "true"; })
581 // TODO is this TS correct?
582 .catch(function (err) {
583 throw new VError(err, "calling bridgedb.isMappingSupported");
584 }));
585 };
586 BridgeDb.prototype.organismProperties = function (organism) {
587 var bridgeDb = this;
588 return bridgeDb
589 .getTSV(bridgeDb.config.baseIri + organism + "/properties")
590 .reduce(function (acc, fields) {
591 var key = lodash_1.camelCase(fields[0]);
592 var value = fields[1];
593 acc[key] = value;
594 return acc;
595 }, {})
596 .catch(function (err) {
597 throw new VError(err, "calling bridgedb.organismProperties");
598 });
599 };
600 BridgeDb.prototype.organisms = function () {
601 var bridgeDb = this;
602 return bridgeDb
603 .getTSV(bridgeDb.config.baseIri + "contents")
604 .map(function (fields) {
605 return {
606 en: fields[0],
607 la: fields[1]
608 };
609 })
610 .catch(function (err) {
611 throw new VError(err, "calling bridgedb.organisms");
612 });
613 };
614 BridgeDb.prototype.search = function (organism, query) {
615 var bridgeDb = this;
616 return bridgeDb
617 .getTSV(bridgeDb.config.baseIri + organism + "/search/" + query)
618 .mergeMap(bridgeDb.parseXrefRow)
619 .catch(function (err) {
620 throw new VError(err, "calling bridgedb.search");
621 });
622 };
623 BridgeDb.prototype.sourceDataSources = function (organism) {
624 var bridgeDb = this;
625 return bridgeDb
626 .getTSV(bridgeDb.config.baseIri + organism + "/sourceDataSources")
627 .map(function (fields) {
628 return fields[0];
629 })
630 .mergeMap(bridgeDb.dataSourceProperties)
631 .catch(function (err) {
632 throw new VError(err, "calling bridgedb.sourceDataSources");
633 });
634 };
635 BridgeDb.prototype.targetDataSources = function (organism) {
636 var bridgeDb = this;
637 return bridgeDb
638 .getTSV(bridgeDb.config.baseIri + organism + "/targetDataSources")
639 .map(function (fields) {
640 return fields[0];
641 })
642 .mergeMap(bridgeDb.dataSourceProperties)
643 .catch(function (err) {
644 throw new VError(err, "calling bridgedb.targetDataSources");
645 });
646 };
647 // TODO check whether dataSource exists before calling webservice re:
648 // dataSource AND identifier
649 BridgeDb.prototype.xrefExists = function (organism, xrefDataSource, xrefIdentifier) {
650 var bridgeDb = this;
651 var ajaxRequest = {
652 url: bridgeDb.config.baseIri +
653 organism + "/xrefExists/" + xrefDataSource + "/" + xrefIdentifier,
654 method: "GET",
655 responseType: "text",
656 timeout: bridgeDb.config.http.timeout,
657 crossDomain: true
658 };
659 return (Observable_1.Observable.ajax(ajaxRequest)
660 .map(function (ajaxResponse) { return ajaxResponse.xhr.response; })
661 // NOTE: must compare with 'true' as a string, because the response is just a string, not a parsed JS boolean.
662 .map(function (res) { return res === "true"; })
663 // TODO is this TS correct?
664 .catch(function (err) {
665 throw new VError(err, "calling bridgedb.xrefExists");
666 }));
667 };
668 BridgeDb.prototype.xrefs = function (organism, xrefDataSource, xrefIdentifier, desiredXrefDataSourceOrSources) {
669 var bridgeDb = this;
670 var xrefsRequestQueue = bridgeDb.xrefsRequestQueue;
671 var xrefsResponseQueue = bridgeDb.xrefsResponseQueue;
672 var desiredXrefDataSources = jsonld_utils_1.arrayify(desiredXrefDataSourceOrSources);
673 xrefsRequestQueue.next({
674 organism: organism,
675 xrefDataSource: xrefDataSource,
676 xrefIdentifier: xrefIdentifier,
677 desiredXrefDataSources: desiredXrefDataSources
678 });
679 return (xrefsResponseQueue
680 .find(function (xrefBatchEnvelope) {
681 return (xrefBatchEnvelope.organism === organism &&
682 // NOTE: we are not using the dataSource test in the line below.
683 // Instead, we are matching dataSources in the mergeMap further below.
684 // The reason is that the inputXrefDataSource and the returned dataSource
685 // may not match, e.g., 'L' vs. 'Entrez Gene'.
686 xrefBatchEnvelope.inputXrefDataSource === xrefDataSource &&
687 xrefBatchEnvelope.inputXrefIdentifier === xrefIdentifier &&
688 xrefBatchEnvelope.desiredXrefDataSources.join() ===
689 desiredXrefDataSources.join());
690 })
691 .map(function (x) { return x.xrefs; })
692 //.do(null, xrefsRequestQueue.complete)
693 .catch(function (err) {
694 throw new VError(err, "calling bridgedb.xrefs");
695 }));
696 };
697 return BridgeDb;
698}());
699exports.BridgeDb = BridgeDb;
700//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQnJpZGdlRGIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvQnJpZGdlRGIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLDhDQUE4Qzs7QUFFOUMsNEJBQTRCO0FBQzVCLDJDQUEyQztBQUUzQyx1Q0FBcUM7QUFlckMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsZ0JBQWdCLENBQUMsRUFBRTtJQUM1QyxNQUFNLENBQUMsY0FBYyxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztDQUN6QztBQUVELGdDQUFnRDtBQUNoRCxpQ0FjZ0I7QUFDaEIsOENBQTZDO0FBRzdDLHdDQUFzQztBQUN0QyxxQ0FBbUM7QUFDbkMsd0NBQXNDO0FBQ3RDLG9DQUFrQztBQUNsQyxxQ0FBbUM7QUFDbkMsbUNBQWlDO0FBQ2pDLG9DQUFrQztBQUNsQyx3Q0FBc0M7QUFDdEMsbUNBQWlDO0FBQ2pDLHVDQUFxQztBQUNyQywwQ0FBd0M7QUFDeEMsbUNBQWlDO0FBQ2pDLGtEQUFnRDtBQUNoRCxnQ0FBOEI7QUFDOUIsb0NBQWtDO0FBQ2xDLGtDQUFnQztBQUNoQyxzQ0FBb0M7QUFDcEMsaUNBQStCO0FBQy9CLHVDQUFxQztBQUNyQywyQ0FBeUM7QUFDekMsa0NBQWdDO0FBQ2hDLG9DQUFrQztBQUNsQyxrQ0FBZ0M7QUFDaEMscUNBQW1DO0FBQ25DLG1EQUFpRDtBQUNqRCx3Q0FBdUM7QUFDdkMsa0RBQWlEO0FBQ2pELDhEQUE2RDtBQUM3RCx3REFBNkQ7QUFDN0QsSUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBRWpDLElBQU0sR0FBRyxHQUFHLHVDQUF1QyxDQUFDO0FBQ3BELElBQU0sTUFBTSxHQUFHLGtEQUFrRCxDQUFDO0FBQ2xFLElBQU0sV0FBVyxHQUFHLHlCQUF5QixDQUFDO0FBQzlDLElBQU0sR0FBRyxHQUFHLGdDQUFnQyxDQUFDO0FBQzdDLElBQU0sR0FBRyxHQUFHLDZDQUE2QyxDQUFDO0FBRTFE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
\No newline at end of file