Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

pfchangs / react-relay   js

Repository URL to install this package:

Version: 0.7.1-ccinternal 

/ lib / findRelayQueryLeaves.js

/**
 * Copyright 2013-2015, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule findRelayQueryLeaves
 * 
 * @typechecks
 */

'use strict';

var _inherits = require('babel-runtime/helpers/inherits')['default'];

var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default'];

Object.defineProperty(exports, '__esModule', {
  value: true
});
var RelayConnectionInterface = require('./RelayConnectionInterface');

var RelayQueryVisitor = require('./RelayQueryVisitor');
var RelayRecordState = require('./RelayRecordState');

var isCompatibleRelayFragmentType = require('./isCompatibleRelayFragmentType');

var EDGES = RelayConnectionInterface.EDGES;
var PAGE_INFO = RelayConnectionInterface.PAGE_INFO;

/**
 * @internal
 *
 * Traverses a query and data in the record store to determine if there are
 * additional nodes that needs to be read from disk cache. If it  ncounters
 * a node that is not in `cachedRecords`, it will queued that node by adding it
 * into the `pendingNodes` list. If it encounters a node that was already read
 * but still missing data, then it will short circuit the evaluation since
 * there is no way for us to satisfy this query even with additional data from
 * disk cache and resturn
 */
function findRelayQueryLeaves(store, cachedRecords, queryNode, dataID, path, rangeCalls) {
  var finder = new RelayQueryLeavesFinder(store, cachedRecords);

  var state = {
    dataID: dataID,
    missingData: false,
    path: path,
    rangeCalls: rangeCalls,
    rangeInfo: undefined
  };
  finder.visit(queryNode, state);
  return {
    missingData: state.missingData,
    pendingNodes: finder.getPendingNodes()
  };
}

var RelayQueryLeavesFinder = (function (_RelayQueryVisitor) {
  _inherits(RelayQueryLeavesFinder, _RelayQueryVisitor);

  function RelayQueryLeavesFinder(store) {
    var cachedRecords = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];

    _classCallCheck(this, RelayQueryLeavesFinder);

    _RelayQueryVisitor.call(this);
    this._store = store;
    this._cachedRecords = cachedRecords;
    this._pendingNodes = {};
  }

  RelayQueryLeavesFinder.prototype.getPendingNodes = function getPendingNodes() {
    return this._pendingNodes;
  };

  /**
   * Skip visiting children if missingData is already false.
   */

  RelayQueryLeavesFinder.prototype.traverse = function traverse(node, state) {
    var children = node.getChildren();
    for (var ii = 0; ii < children.length; ii++) {
      if (state.missingData) {
        return;
      }
      this.visit(children[ii], state);
    }
  };

  RelayQueryLeavesFinder.prototype.visitFragment = function visitFragment(fragment, state) {
    var dataID = state.dataID;
    var recordState = this._store.getRecordState(dataID);
    if (recordState === RelayRecordState.UNKNOWN) {
      this._handleMissingData(fragment, state);
      return;
    } else if (recordState === RelayRecordState.NONEXISTENT) {
      return;
    }

    if (isCompatibleRelayFragmentType(fragment, this._store.getType(dataID))) {
      this.traverse(fragment, state);
    }
  };

  RelayQueryLeavesFinder.prototype.visitField = function visitField(field, state) {
    var dataID = state.dataID;
    var recordState = this._store.getRecordState(dataID);
    if (recordState === RelayRecordState.UNKNOWN) {
      this._handleMissingData(field, state);
      return;
    } else if (recordState === RelayRecordState.NONEXISTENT) {
      return;
    }

    if (state.rangeCalls && !state.rangeInfo) {
      var metadata = this._store.getRangeMetadata(dataID, state.rangeCalls);
      if (metadata) {
        state.rangeInfo = metadata;
      }
    }
    var rangeInfo = state.rangeInfo;
    if (rangeInfo && field.getSchemaName() === EDGES) {
      this._visitEdges(field, state);
    } else if (rangeInfo && field.getSchemaName() === PAGE_INFO) {
      this._visitPageInfo(field, state);
    } else if (field.isScalar()) {
      this._visitScalar(field, state);
    } else if (field.isPlural()) {
      this._visitPlural(field, state);
    } else if (field.isConnection()) {
      this._visitConnection(field, state);
    } else {
      this._visitLinkedField(field, state);
    }
  };

  RelayQueryLeavesFinder.prototype._visitScalar = function _visitScalar(field, state) {
    var fieldData = this._store.getField(state.dataID, field.getStorageKey());
    if (fieldData === undefined) {
      this._handleMissingData(field, state);
    }
  };

  RelayQueryLeavesFinder.prototype._visitPlural = function _visitPlural(field, state) {
    var dataIDs = this._store.getLinkedRecordIDs(state.dataID, field.getStorageKey());
    if (dataIDs === undefined) {
      this._handleMissingData(field, state);
      return;
    }
    if (dataIDs) {
      for (var ii = 0; ii < dataIDs.length; ii++) {
        if (state.missingData) {
          break;
        }
        var nextState = {
          dataID: dataIDs[ii],
          missingData: false,
          path: state.path.getPath(field, dataIDs[ii]),
          rangeCalls: undefined,
          rangeInfo: undefined
        };
        this.traverse(field, nextState);
        state.missingData = nextState.missingData;
      }
    }
  };

  RelayQueryLeavesFinder.prototype._visitConnection = function _visitConnection(field, state) {
    var calls = field.getCallsWithValues();
    var dataID = this._store.getLinkedRecordID(state.dataID, field.getStorageKey());
    if (dataID === undefined) {
      this._handleMissingData(field, state);
      return;
    }
    if (dataID) {
      var nextState = {
        dataID: dataID,
        missingData: false,
        path: state.path.getPath(field, dataID),
        rangeCalls: calls,
        rangeInfo: null
      };
      var metadata = this._store.getRangeMetadata(dataID, calls);
      if (metadata) {
        nextState.rangeInfo = metadata;
      }
      this.traverse(field, nextState);
      state.missingData = state.missingData || nextState.missingData;
    }
  };

  RelayQueryLeavesFinder.prototype._visitEdges = function _visitEdges(field, state) {
    var rangeInfo = state.rangeInfo;
    // Doesn't have  `__range__` loaded
    if (!rangeInfo) {
      this._handleMissingData(field, state);
      return;
    }
    if (rangeInfo.diffCalls.length) {
      state.missingData = true;
      return;
    }
    var edgeIDs = rangeInfo.requestedEdgeIDs;
    for (var ii = 0; ii < edgeIDs.length; ii++) {
      if (state.missingData) {
        break;
      }
      var nextState = {
        dataID: edgeIDs[ii],
        missingData: false,
        path: state.path.getPath(field, edgeIDs[ii]),
        rangeCalls: undefined,
        rangeInfo: undefined
      };
      this.traverse(field, nextState);
      state.missingData = state.missingData || nextState.missingData;
    }
  };

  RelayQueryLeavesFinder.prototype._visitPageInfo = function _visitPageInfo(field, state) {
    var rangeInfo = state.rangeInfo;

    if (!rangeInfo || !rangeInfo.pageInfo) {
      this._handleMissingData(field, state);
      return;
    }
  };

  RelayQueryLeavesFinder.prototype._visitLinkedField = function _visitLinkedField(field, state) {
    var dataID = this._store.getLinkedRecordID(state.dataID, field.getStorageKey());
    if (dataID === undefined) {
      this._handleMissingData(field, state);
      return;
    }
    if (dataID) {
      var nextState = {
        dataID: dataID,
        missingData: false,
        path: state.path.getPath(field, dataID),
        rangeCalls: undefined,
        rangeInfo: undefined
      };
      this.traverse(field, nextState);
      state.missingData = state.missingData || nextState.missingData;
    }
  };

  RelayQueryLeavesFinder.prototype._handleMissingData = function _handleMissingData(node, state) {
    var dataID = state.dataID;
    if (this._cachedRecords.hasOwnProperty(dataID)) {
      // We have read data for this `dataID` from disk, but
      // we still don't have data for the relevant field.
      state.missingData = true;
    } else {
      // Store node in `pendingNodes` because we have not read data for
      // this `dataID` from disk.
      this._pendingNodes[dataID] = this._pendingNodes[dataID] || [];
      this._pendingNodes[dataID].push({
        node: node,
        path: state.path,
        rangeCalls: state.rangeCalls
      });
    }
  };

  return RelayQueryLeavesFinder;
})(RelayQueryVisitor);

module.exports = findRelayQueryLeaves;