1 | ;
|
2 | /// <reference path="../typings/index.d.ts" />
|
3 | Object.defineProperty(exports, "__esModule", { value: true });
|
4 | // TODO use a cache, such as
|
5 | // https://github.com/levelgraph/levelgraph
|
6 | require("source-map-support/register");
|
7 | if (!global.hasOwnProperty("XMLHttpRequest")) {
|
8 | global.XMLHttpRequest = require("xhr2");
|
9 | }
|
10 | var fp_1 = require("lodash/fp");
|
11 | var lodash_1 = require("lodash");
|
12 | var Observable_1 = require("rxjs/Observable");
|
13 | require("rxjs/add/observable/dom/ajax");
|
14 | require("rxjs/add/observable/empty");
|
15 | require("rxjs/add/observable/forkJoin");
|
16 | require("rxjs/add/observable/from");
|
17 | require("rxjs/add/observable/throw");
|
18 | require("rxjs/add/observable/zip");
|
19 | require("rxjs/add/operator/buffer");
|
20 | require("rxjs/add/operator/bufferWhen");
|
21 | require("rxjs/add/operator/catch");
|
22 | require("rxjs/add/operator/concatAll");
|
23 | require("rxjs/add/operator/debounceTime");
|
24 | require("rxjs/add/operator/delay");
|
25 | require("rxjs/add/operator/distinctUntilChanged");
|
26 | require("rxjs/add/operator/do");
|
27 | require("rxjs/add/operator/filter");
|
28 | require("rxjs/add/operator/find");
|
29 | require("rxjs/add/operator/mergeMap");
|
30 | require("rxjs/add/operator/map");
|
31 | require("rxjs/add/operator/multicast");
|
32 | require("rxjs/add/operator/publishReplay");
|
33 | require("rxjs/add/operator/race");
|
34 | require("rxjs/add/operator/reduce");
|
35 | require("rxjs/add/operator/skip");
|
36 | require("rxjs/add/operator/toArray");
|
37 | require("rx-extra/add/operator/throughNodeStream");
|
38 | var Subject_1 = require("rxjs/Subject");
|
39 | var TSVGetter_1 = require("./spinoffs/TSVGetter");
|
40 | var dataTypeParsers_1 = require("./spinoffs/dataTypeParsers");
|
41 | var jsonld_utils_1 = require("./spinoffs/jsonld-utils");
|
42 | var VError = require("verror");
|
43 | var BDB = "http://vocabularies.bridgedb.org/ops#";
|
44 | var BIOPAX = "http://www.biopax.org/release/biopax-level3.owl#";
|
45 | var IDENTIFIERS = "http://identifiers.org/";
|
46 | var OWL = "http://www.w3.org/2002/07/owl#";
|
47 | var RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
|
48 | var 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()
|
51 | var XREF_REQUEST_DEBOUNCE_TIME = 10; // ms
|
52 | var XREF_REQUEST_CHUNK_SIZE = 100;
|
53 | var BRIDGE_DB_REPO_CDN = "https://raw.githubusercontent.com/bridgedb/BridgeDb/";
|
54 | var BRIDGE_DB_COMMIT_HASH = "465f9f944d09cefbb167eceb9c69499a764100a2";
|
55 | exports.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.
|
80 | var DATASOURCE_ID_PROPERTIES = [
|
81 | "id",
|
82 | "miriamUrn",
|
83 | "conventionalName",
|
84 | "preferredPrefix",
|
85 | "systemCode"
|
86 | ];
|
87 | var 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 | };
|
92 | var 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 | */
|
99 | function 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 | */
|
111 | function 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 | }
|
118 | var 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 | }());
|
699 | exports.BridgeDb = BridgeDb;
|
700 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQnJpZGdlRGIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvQnJpZGdlRGIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLDhDQUE4Qzs7QUFFOUMsNEJBQTRCO0FBQzVCLDJDQUEyQztBQUUzQyx1Q0FBcUM7QUFlckMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsZ0JBQWdCLENBQUMsRUFBRTtJQUM1QyxNQUFNLENBQUMsY0FBYyxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztDQUN6QztBQUVELGdDQUFnRDtBQUNoRCxpQ0FjZ0I7QUFDaEIsOENBQTZDO0FBRzdDLHdDQUFzQztBQUN0QyxxQ0FBbUM7QUFDbkMsd0NBQXNDO0FBQ3RDLG9DQUFrQztBQUNsQyxxQ0FBbUM7QUFDbkMsbUNBQWlDO0FBQ2pDLG9DQUFrQztBQUNsQyx3Q0FBc0M7QUFDdEMsbUNBQWlDO0FBQ2pDLHVDQUFxQztBQUNyQywwQ0FBd0M7QUFDeEMsbUNBQWlDO0FBQ2pDLGtEQUFnRDtBQUNoRCxnQ0FBOEI7QUFDOUIsb0NBQWtDO0FBQ2xDLGtDQUFnQztBQUNoQyxzQ0FBb0M7QUFDcEMsaUNBQStCO0FBQy9CLHVDQUFxQztBQUNyQywyQ0FBeUM7QUFDekMsa0NBQWdDO0FBQ2hDLG9DQUFrQztBQUNsQyxrQ0FBZ0M7QUFDaEMscUNBQW1DO0FBQ25DLG1EQUFpRDtBQUNqRCx3Q0FBdUM7QUFDdkMsa0RBQWlEO0FBQ2pELDhEQUE2RDtBQUM3RCx3REFBNkQ7QUFDN0QsSUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0FBRWpDLElBQU0sR0FBRyxHQUFHLHVDQUF1QyxDQUFDO0FBQ3BELElBQU0sTUFBTSxHQUFHLGtEQUFrRCxDQUFDO0FBQ2xFLElBQU0sV0FBVyxHQUFHLHlCQUF5QixDQUFDO0FBQzlDLElBQU0sR0FBRyxHQUFHLGdDQUFnQyxDQUFDO0FBQzdDLElBQU0sR0FBRyxHQUFHLDZDQUE2QyxDQUFDO0FBRTFE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 |
\ | No newline at end of file |