UNPKG

react-relay

Version:

A framework for building data-driven React applications.

224 lines (195 loc) • 6.39 kB
/** * 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 checkRelayQueryData * * @typechecks */ 'use strict'; var _inherits = require('babel-runtime/helpers/inherits')['default']; var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default']; var RelayConnectionInterface = require('./RelayConnectionInterface'); var RelayProfiler = require('./RelayProfiler'); var RelayQueryVisitor = require('./RelayQueryVisitor'); var RelayRecordStatus = require('./RelayRecordStatus'); var forEachRootCallArg = require('./forEachRootCallArg'); var EDGES = RelayConnectionInterface.EDGES; var PAGE_INFO = RelayConnectionInterface.PAGE_INFO; /** * @internal * * Traverses a query and data in the record store to determine whether we have * enough data to satisfy the query. */ function checkRelayQueryData(store, query) { var checker = new RelayQueryChecker(store); var state = { dataID: undefined, rangeInfo: undefined, result: true }; checker.visit(query, state); return state.result; } var RelayQueryChecker = (function (_RelayQueryVisitor) { _inherits(RelayQueryChecker, _RelayQueryVisitor); function RelayQueryChecker(store) { _classCallCheck(this, RelayQueryChecker); _RelayQueryVisitor.call(this); this._store = store; } /** * Skip visiting children if result is already false. */ RelayQueryChecker.prototype.traverse = function traverse(node, state) { var children = node.getChildren(); for (var ii = 0; ii < children.length; ii++) { if (!state.result) { return; } this.visit(children[ii], state); } }; RelayQueryChecker.prototype.visitRoot = function visitRoot(root, state) { var _this = this; var nextState; forEachRootCallArg(root, function (rootCallArg, rootCallName) { var dataID = _this._store.getRootCallID(rootCallName, rootCallArg); if (dataID == null) { state.result = false; } else { nextState = { dataID: dataID, rangeInfo: undefined, result: true }; _this.traverse(root, nextState); state.result = state.result && nextState.result; } }); }; RelayQueryChecker.prototype.visitField = function visitField(field, state) { var dataID = state.dataID; var recordStatus = dataID && this._store.getRecordStatus(dataID); if (recordStatus === RelayRecordStatus.UNKNOWN) { state.result = false; return; } else if (recordStatus === RelayRecordStatus.NONEXISTENT) { return; } var rangeInfo = state.rangeInfo; if (rangeInfo && field.getSchemaName() === EDGES) { this._checkEdges(field, state); } else if (rangeInfo && field.getSchemaName() === PAGE_INFO) { this._checkPageInfo(field, state); } else if (field.isScalar()) { this._checkScalar(field, state); } else if (field.isPlural()) { this._checkPlural(field, state); } else if (field.isConnection()) { this._checkConnection(field, state); } else { this._checkLinkedField(field, state); } }; RelayQueryChecker.prototype._checkScalar = function _checkScalar(field, state) { var fieldData = state.dataID && this._store.getField(state.dataID, field.getStorageKey()); if (fieldData === undefined) { state.result = false; } }; RelayQueryChecker.prototype._checkPlural = function _checkPlural(field, state) { var dataIDs = state.dataID && this._store.getLinkedRecordIDs(state.dataID, field.getStorageKey()); if (dataIDs === undefined) { state.result = false; return; } if (dataIDs) { for (var ii = 0; ii < dataIDs.length; ii++) { if (!state.result) { break; } var nextState = { dataID: dataIDs[ii], rangeInfo: undefined, result: true }; this.traverse(field, nextState); state.result = nextState.result; } } }; RelayQueryChecker.prototype._checkConnection = function _checkConnection(field, state) { var calls = field.getCallsWithValues(); var dataID = state.dataID && this._store.getLinkedRecordID(state.dataID, field.getStorageKey()); if (dataID === undefined) { state.result = false; return; } var nextState = { dataID: dataID, rangeInfo: null, // Flow rejects `undefined` here result: true }; var metadata = this._store.getRangeMetadata(dataID, calls); if (metadata) { nextState.rangeInfo = metadata; } this.traverse(field, nextState); state.result = state.result && nextState.result; }; RelayQueryChecker.prototype._checkEdges = function _checkEdges(field, state) { var rangeInfo = state.rangeInfo; if (!rangeInfo) { state.result = false; return; } if (rangeInfo.diffCalls.length) { state.result = false; return; } var edges = rangeInfo.requestedEdges; for (var ii = 0; ii < edges.length; ii++) { if (!state.result) { break; } var nextState = { dataID: edges[ii].edgeID, rangeInfo: undefined, result: true }; this.traverse(field, nextState); state.result = nextState.result; } }; RelayQueryChecker.prototype._checkPageInfo = function _checkPageInfo(field, state) { var rangeInfo = state.rangeInfo; if (!rangeInfo || !rangeInfo.pageInfo) { state.result = false; return; } }; RelayQueryChecker.prototype._checkLinkedField = function _checkLinkedField(field, state) { var dataID = state.dataID && this._store.getLinkedRecordID(state.dataID, field.getStorageKey()); if (dataID === undefined) { state.result = false; return; } if (dataID) { var nextState = { dataID: dataID, rangeInfo: undefined, result: true }; this.traverse(field, nextState); state.result = state.result && nextState.result; } }; return RelayQueryChecker; })(RelayQueryVisitor); module.exports = RelayProfiler.instrument('checkRelayQueryData', checkRelayQueryData);