Source: xref.js

/* @module Xref */

var _ = require('lodash');
var csv = require('csv-streamify');
var highland = require('highland');
var httpErrors = require('./http-errors.js');
var hyperquest = require('hyperquest');
var RxNode = require('rx-node');

var csvOptions = {objectMode: true, delimiter: '\t'};

/**
 * Used internally to create a new Xref instance
 * @class
 * @protected
 * @memberof BridgeDb
 * @param {Object} instance
 */
var Xref = function(instance) {
  'use strict';

  /**
   * Get all xrefs available from BridgeDb for the provided entity reference.
   * Currently limited to biopax:UnificationXrefs and biopax:RelationshipXrefs.
   *
   * @param {String|Object|Stream} input
   * @return {Stream<EntityReference>} entityReferenceStream Stream of enriched
   *                              {@link EntityReference|EntityReferences}.
   */
  function get(input, options) {
    // TODO this seems bad to be polluting the instance namespace like this.
    var inputStream;
    if (_.isString(input) || _.isPlainObject(input)) {
      inputStream = highland([input]);
    } else if (_.isArray(input)) {
      inputStream = highland(input);
    } else if (highland.isStream(input)) {
      inputStream = input;
    }

    return inputStream.pipe(createStream());
  }

  /**
   * @private
   *
   * Create a Node.js/Highland stream through which entity references
   * can be piped to return all the xrefs available for each entity reference.
   *
   * @return {Stream} entityReferenceToXrefsSetTransformationStream
   */
  function createStream() {
    return highland.pipeline(function(sourceStream) {
      var options = instance.options || {};
      var specifiedEntityReference;
      // normalize the provided entity reference
      return highland(sourceStream)
        .flatMap(instance.entityReference.enrich)
        // get the BridgeDb path to get xrefs for the entity reference
        .map(function(normalizedEntityReference) {
          // TODO this method of setting the specified entity reference seems wrong.
          // Check whether it's correct.
          specifiedEntityReference = normalizedEntityReference;
          return normalizedEntityReference;
        })
        // The rest of this function enriches and formats the xrefs
        .flatMap(function(normalizedEntityReference) {
          var source =
              _getBridgeDbIriByEntityReference(normalizedEntityReference);

          return highland(
            hyperquest(source, {
              withCredentials: false
            })
            .pipe(csv(csvOptions))
          );
        })
        .errors(function(err, push) {
          console.error('in bridgedb.xref.createStream()');
          push(err);
          // TODO what happens if BridgeDb webservices are down?
          // We should just return the data the user provided.
          //return specifiedEntityReference;
          //return push(specifiedEntityReference);
        })
        .map(function(array) {
          return {
            identifier: array[0],
            bridgeDbDataSourceName: array[1]
          };
        })
        // Strange that we need to do this collect/sequence, but
        // if we don't, the stream never ends, meaning we can't
        // do the collect after the enrich step.
        .collect()
        .sequence()
        .flatMap(instance.entityReference.enrich)
        .collect()
        .map(function(entityReferences) {
          if (_.isEmpty(entityReferences)) {
            entityReferences = [specifiedEntityReference];
          }
          return entityReferences;
        })
        .sequence()
        .flatMap(instance.addContext);
    });
  }

  /**
   * @private
   *
   * @param {EntityReference} entityReference
   * @param {String} entityReference.identifier
   * @param {Organism} entityReference.organism
   * @param {Object} entityReference.organism.nameLanguageMap
   * @param {String} entityReference.organism.nameLanguageMap.la
   * @param {Dataset} entityReference.isDataItemIn
   * @param {String} entityReference.isDataItemIn.bridgeDbSystemCode
   * @return {String} iri IRI (URL) for getting Xrefs from BridgeDb webservices
   */
  function _getBridgeDbIriByEntityReference(entityReference) {
    var bridgeDbSystemCode = entityReference.isDataItemIn.bridgeDbSystemCode;
    var path = encodeURIComponent(entityReference.organism.nameLanguageMap.la) +
      '/xrefs/' + encodeURIComponent(bridgeDbSystemCode) + '/' +
      encodeURIComponent(entityReference.identifier);
    return instance.config.baseIri + path;
  }

  return {
    createStream: createStream,
    _getBridgeDbIriByEntityReference: _getBridgeDbIriByEntityReference,
    get: get
  };
};

exports = module.exports = Xref;
comments powered by Disqus