UNPKG

react-relay

Version:

A framework for building data-driven React applications.

140 lines (117 loc) 4.68 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 intersectRelayQuery * @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 RelayQuery = require('./RelayQuery'); var RelayQueryTransform = require('./RelayQueryTransform'); var invariant = require('fbjs/lib/invariant'); /** * @internal * * `intersectRelayQuery(subjectNode, patternNode)` returns a node with fields in * `subjectNode` that also exist in `patternNode`. `patternNode` is expected to * be flattened (and not contain fragments). * * If any field in `patternNode` is unterminated (i.e. has no sub-fields), we * treat the field as though it contains every descendant sub-field. * * If `filterUnterminatedRange` is supplied, it will be invoked with any fields * from `subjectNode` that are connections and unterminated in `patternNode`. If * it returns true, the `edges` and `page_info` fields will be filtered out. */ function intersectRelayQuery(subjectNode, patternNode, filterUnterminatedRange) { filterUnterminatedRange = filterUnterminatedRange || returnsFalse; var visitor = new RelayQueryIntersector(filterUnterminatedRange); return visitor.traverse(subjectNode, patternNode); } var RelayQueryIntersector = (function (_RelayQueryTransform) { _inherits(RelayQueryIntersector, _RelayQueryTransform); function RelayQueryIntersector(filterUnterminatedRange) { _classCallCheck(this, RelayQueryIntersector); _RelayQueryTransform.call(this); this._filterUnterminatedRange = filterUnterminatedRange; } /** * @private */ RelayQueryIntersector.prototype.traverse = function traverse(subjectNode, patternNode) { var _this = this; if (subjectNode.isScalar()) { // Since `patternNode` exists, `subjectNode` must be in the intersection. return subjectNode; } if (!hasChildren(patternNode)) { if (subjectNode instanceof RelayQuery.Field && subjectNode.isConnection() && this._filterUnterminatedRange(subjectNode)) { return filterRangeFields(subjectNode); } // Unterminated `patternNode` is the same as containing every descendant // sub-field, so `subjectNode` must be in the intersection. return subjectNode; } return subjectNode.clone(subjectNode.getChildren().map(function (subjectChild) { if (subjectChild instanceof RelayQuery.Fragment) { return _this.visit(subjectChild, patternNode); } if (subjectChild instanceof RelayQuery.Field) { var schemaName = subjectChild.getSchemaName(); var patternChild; var patternChildren = patternNode.getChildren(); for (var ii = 0; ii < patternChildren.length; ii++) { var child = patternChildren[ii]; !(child instanceof RelayQuery.Field) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'intersectRelayQuery(): Nodes in `patternNode` must be fields.') : invariant(false) : undefined; if (child.getSchemaName() === schemaName) { patternChild = child; break; } } if (patternChild) { return _this.visit(subjectChild, patternChild); } } return null; })); }; return RelayQueryIntersector; })(RelayQueryTransform); var RelayQueryRangeFilter = (function (_RelayQueryTransform2) { _inherits(RelayQueryRangeFilter, _RelayQueryTransform2); function RelayQueryRangeFilter() { _classCallCheck(this, RelayQueryRangeFilter); _RelayQueryTransform2.apply(this, arguments); } RelayQueryRangeFilter.prototype.visitField = function visitField(node) { var schemaName = node.getSchemaName(); if (schemaName === RelayConnectionInterface.EDGES || schemaName === RelayConnectionInterface.PAGE_INFO) { return null; } else { return node; } }; return RelayQueryRangeFilter; })(RelayQueryTransform); var rangeFilter = new RelayQueryRangeFilter(); function filterRangeFields(node) { return rangeFilter.traverse(node, undefined); } function returnsFalse() { return false; } function hasChildren(node) { return !node.getChildren().every(isGenerated); } function isGenerated(node) { return node.isGenerated(); } module.exports = intersectRelayQuery;