react-relay
Version:
A framework for building data-driven React applications.
1,006 lines (852 loc) • 34 kB
JavaScript
/**
* 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 RelayQuery
*
* @typechecks
*/
'use strict';
var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default'];
var _inherits = require('babel-runtime/helpers/inherits')['default'];
var _extends = require('babel-runtime/helpers/extends')['default'];
var GraphQL = require('./GraphQL');
var RelayConnectionInterface = require('./RelayConnectionInterface');
var RelayFragmentReference = require('./RelayFragmentReference');
var RelayMetaRoute = require('./RelayMetaRoute');
var RelayRouteFragment = require('./RelayRouteFragment');
var areEqual = require('fbjs/lib/areEqual');
var callsFromGraphQL = require('./callsFromGraphQL');
var callsToGraphQL = require('./callsToGraphQL');
var generateRQLFieldAlias = require('./generateRQLFieldAlias');
var getWeakIdForObject = require('./getWeakIdForObject');
var invariant = require('fbjs/lib/invariant');
var printRelayQueryCall = require('./printRelayQueryCall');
var shallowEqual = require('fbjs/lib/shallowEqual');
var stableStringify = require('./stableStringify');
// TODO: replace once #6525923 is resolved
// conditional field calls/values
var IF = 'if';
var UNLESS = 'unless';
var TRUE = 'true';
var FALSE = 'false';
var QUERY_ID_PREFIX = 'q';
var REF_PARAM_PREFIX = 'ref_';
var _nextQueryID = 0;
var DEFAULT_FRAGMENT_METADATA = {
isDeferred: false,
isReferenceFragment: false,
isTypeConditional: false
};
/**
* @internal
*
* Queries in Relay are represented as trees. Possible nodes include the root,
* fields, and fragments. Fields can have children, or they can be leaf nodes.
* Root and fragment nodes must always have children.
*
* `RelayQueryNode` provides access to information such as the field name,
* generated alias, sub-fields, and call values.
*
* Nodes are immutable; query modification is supported via `clone`:
*
* ```
* var next = prev.clone(prev.getChildren().filter(f => ...));
* ```
*
* Note: Mediating access to actual query nodes is necessary so that we can
* replace the current mutable GraphQL nodes with an immutable query
* representation. This class *must not* mutate the underlying `concreteNode`.
* Instead, use an instance variable (see `clone()`).
*
* TODO (#6937314): RelayQueryNode support for toJSON/fromJSON
*/
var RelayQueryNode = (function () {
RelayQueryNode.create = function create(concreteNode, route, variables) {
var node = createNode(concreteNode, route, variables);
!(node instanceof RelayQueryNode) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQueryNode.create(): Expected a node.') : invariant(false) : undefined;
return node;
};
/**
* Helper to construct a new root query with the given attributes and 'empty'
* route/variables.
*/
RelayQueryNode.buildRoot = function buildRoot(rootCall, rootCallValue, children, metadata, name) {
var nextChildren = children ? children.filter(function (child) {
return !!child;
}) : [];
var concreteRoot = new GraphQL.Query(rootCall, rootCallValue || null, null, null, metadata, name);
var root = new RelayQueryRoot(concreteRoot, RelayMetaRoute.get('$RelayQuery'), {});
root.__children__ = nextChildren;
return root;
};
/**
* Helper to construct a new fragment with the given attributes and 'empty'
* route/variables.
*/
RelayQueryNode.buildFragment = function buildFragment(name, type, children, metadata) {
var nextChildren = children ? children.filter(function (child) {
return !!child;
}) : [];
var concreteFragment = new GraphQL.QueryFragment(name, type, null, null, metadata);
var fragment = new RelayQueryFragment(concreteFragment, RelayMetaRoute.get('$RelayQuery'), {}, {
isDeferred: !!(metadata && metadata.isDeferred),
isReferenceFragment: !!(metadata && metadata.isReferenceFragment),
isTypeConditional: !!(metadata && metadata.isTypeConditional)
});
fragment.__children__ = nextChildren;
return fragment;
};
/**
* Helper to construct a new field with the given attributes and 'empty'
* route/variables.
*/
RelayQueryNode.buildField = function buildField(fieldName, calls, children, metadata, alias) {
var nextChildren = children ? children.filter(function (child) {
return !!child;
}) : [];
var concreteField = new GraphQL.Field(fieldName, null, null, calls ? callsToGraphQL(calls) : null, alias, null, metadata);
var field = new RelayQueryField(concreteField, RelayMetaRoute.get('$RelayQuery'), {});
field.__children__ = nextChildren;
return field;
};
/**
* Helper to construct a new mutation with the given attributes and 'empty'
* route/variables.
*/
RelayQueryNode.buildMutation = function buildMutation(mutationName, responseType, callName, callValue, children, metadata) {
var nextChildren = children ? children.filter(function (child) {
return !!child;
}) : [];
var concreteMutation = new GraphQL.Mutation(mutationName, responseType, new GraphQL.Callv(callName, new GraphQL.CallVariable('input')), null, null, metadata);
var mutation = new RelayQueryMutation(concreteMutation, RelayMetaRoute.get('$RelayQuery'), { input: callValue || '' });
mutation.__children__ = nextChildren;
return mutation;
};
RelayQueryNode.createFragment = function createFragment(concreteNode, route, variables, metadata) {
!GraphQL.isFragment(concreteNode) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQuery.createQuery(): Expected a concrete query fragment, got: %s', concreteNode) : invariant(false) : undefined;
return createMemoizedFragment(concreteNode, route, variables, metadata || DEFAULT_FRAGMENT_METADATA);
};
RelayQueryNode.createQuery = function createQuery(concreteNode, route, variables) {
!GraphQL.isQuery(concreteNode) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQuery.createQuery(): Expected a concrete query, got: %s', concreteNode) : invariant(false) : undefined;
return new RelayQueryRoot(concreteNode, route, variables);
};
/**
* @private
*
* Base class for all node types, must not be directly instantiated.
*/
function RelayQueryNode(concreteNode, route, variables) {
_classCallCheck(this, RelayQueryNode);
!(this.constructor.name !== 'RelayQueryNode') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQueryNode: Abstract class cannot be instantiated.') : invariant(false) : undefined;
this.__concreteNode__ = concreteNode;
this.__route__ = route;
this.__variables__ = variables;
// lazily computed properties
this.__calls__ = null;
this.__children__ = null;
this.__fieldMap__ = null;
this.__hasDeferredDescendant__ = null;
this.__hasValidatedConnectionCalls__ = null;
this.__serializationKey__ = null;
this.__storageKey__ = null;
// TODO(#7161070) Remove this once `toGraphQL` is no longer needed.
this.__isConcreteNodeCached__ = false;
}
/**
* @internal
*
* Wraps access to query root nodes.
*/
RelayQueryNode.prototype.isGenerated = function isGenerated() {
return false;
};
RelayQueryNode.prototype.isRefQueryDependency = function isRefQueryDependency() {
return false;
};
RelayQueryNode.prototype.isScalar = function isScalar() {
return false;
};
RelayQueryNode.prototype.clone = function clone(children) {
if (this.isScalar()) {
// Compact new children *after* this check, for consistency.
!(children.length === 0) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQueryNode: Cannot add children to scalar fields.') : invariant(false) : undefined;
return this;
}
var prevChildren = this.getChildren();
var nextChildren = cloneChildren(prevChildren, children);
if (!nextChildren.length) {
return null;
} else if (nextChildren === prevChildren) {
return this;
}
var clone = RelayQueryNode.create(this.__concreteNode__, this.__route__, this.__variables__);
clone.__children__ = nextChildren;
clone.__calls__ = this.__calls__;
clone.__serializationKey__ = this.__serializationKey__;
clone.__storageKey__ = this.__storageKey__;
return clone;
};
RelayQueryNode.prototype.getChildren = function getChildren() {
var _this = this;
var children = this.__children__;
if (!children) {
var nextChildren = [];
this.__concreteNode__.children.forEach(function (concreteChild) {
var node = createNode(concreteChild, _this.__route__, _this.__variables__);
if (node) {
nextChildren.push(node);
}
});
this.__children__ = nextChildren;
children = nextChildren;
}
return children;
};
RelayQueryNode.prototype.getField = function getField(field) {
return this.getFieldByStorageKey(field.getStorageKey());
};
RelayQueryNode.prototype.getFieldByStorageKey = function getFieldByStorageKey(storageKey) {
var fieldMap = this.__fieldMap__;
if (!fieldMap) {
fieldMap = {};
var child;
var children = this.getChildren();
for (var ii = 0; ii < children.length; ii++) {
child = children[ii];
if (child instanceof RelayQueryField) {
fieldMap[child.getStorageKey()] = child;
}
}
this.__fieldMap__ = fieldMap;
}
return fieldMap[storageKey];
};
RelayQueryNode.prototype.getRoute = function getRoute() {
return this.__route__;
};
RelayQueryNode.prototype.getVariables = function getVariables() {
return this.__variables__;
};
RelayQueryNode.prototype.hasDeferredDescendant = function hasDeferredDescendant() {
var hasDeferredDescendant = this.__hasDeferredDescendant__;
if (hasDeferredDescendant == null) {
hasDeferredDescendant = !this.isScalar() && this.getChildren().some(function (child) {
return child.hasDeferredDescendant();
});
this.__hasDeferredDescendant__ = hasDeferredDescendant;
}
return hasDeferredDescendant;
};
RelayQueryNode.prototype.isRequisite = function isRequisite() {
return false;
};
/**
* Determine if `this` and `that` are deeply equal.
*/
RelayQueryNode.prototype.equals = function equals(that) {
var thisChildren = this.getChildren();
var thatChildren = that.getChildren();
return thisChildren === thatChildren || thisChildren.length === thatChildren.length && thisChildren.every(function (c, ii) {
return c.equals(thatChildren[ii]);
});
};
/**
* Performs a fast comparison of whether `this` and `that` represent identical
* query nodes. Returns true only if the concrete nodes, routes, and variables
* are all the same.
*
* Note that it is possible that this method can return false in cases where
* `equals` would return true. This can happen when the concrete nodes are
* different but structurally identical, or when the route/variables are
* different but do not have an effect on the structure of the query.
*/
RelayQueryNode.prototype.isEquivalent = function isEquivalent(that) {
return this.__concreteNode__ === that.__concreteNode__ && this.__route__ === that.__route__ && shallowEqual(this.__variables__, that.__variables__);
};
RelayQueryNode.prototype.createNode = function createNode(concreteNode) {
return RelayQueryNode.create(concreteNode, this.__route__, this.__variables__);
};
RelayQueryNode.prototype.getConcreteQueryNode = function getConcreteQueryNode(onCacheMiss) {
if (!this.__isConcreteNodeCached__) {
this.__concreteNode__ = onCacheMiss();
this.__isConcreteNodeCached__ = true;
}
return this.__concreteNode__;
};
return RelayQueryNode;
})();
var RelayQueryRoot = (function (_RelayQueryNode) {
_inherits(RelayQueryRoot, _RelayQueryNode);
function RelayQueryRoot(concreteNode, route, variables) {
_classCallCheck(this, RelayQueryRoot);
_RelayQueryNode.call(this, concreteNode, route, variables);
this.__batchCall__ = undefined;
this.__deferredFragmentNames__ = undefined;
this.__id__ = undefined;
// Ensure IDs are generated in the order that queries are created
this.getID();
}
/**
* @internal
*
* Abstract base class for mutations and subscriptions.
*/
RelayQueryRoot.prototype.getName = function getName() {
var name = this.__concreteNode__.name;
if (!name) {
name = this.getID();
this.__concreteNode__.name = name;
}
return name;
};
RelayQueryRoot.prototype.getID = function getID() {
var id = this.__id__;
if (id == null) {
id = QUERY_ID_PREFIX + _nextQueryID++;
this.__id__ = id;
}
return id;
};
RelayQueryRoot.prototype.getBatchCall = function getBatchCall() {
var batchCall = this.__batchCall__;
if (batchCall === undefined) {
var concreteCalls = this.__concreteNode__.calls;
var callArg = concreteCalls[0].value;
if (GraphQL.isBatchCallVariable(callArg)) {
batchCall = {
refParamName: REF_PARAM_PREFIX + callArg.sourceQueryID,
sourceQueryID: callArg.sourceQueryID,
sourceQueryPath: callArg.jsonPath
};
} else {
batchCall = null;
}
this.__batchCall__ = batchCall;
}
return batchCall;
};
RelayQueryRoot.prototype.getRootCall = function getRootCall() {
var calls = this.__calls__;
if (!calls) {
var concreteCalls = this.__concreteNode__.calls;
calls = callsFromGraphQL(concreteCalls, this.__variables__);
this.__calls__ = calls;
}
return calls[0];
};
RelayQueryRoot.prototype.getCallType = function getCallType() {
if (this.__concreteNode__.calls.length > 0) {
return this.__concreteNode__.metadata.rootCallType;
}
};
RelayQueryRoot.prototype.getRootCallArgument = function getRootCallArgument() {
return this.__concreteNode__.metadata.rootArg;
};
RelayQueryRoot.prototype.hasDeferredDescendant = function hasDeferredDescendant() {
return this.isDeferred() || _RelayQueryNode.prototype.hasDeferredDescendant.call(this);
};
RelayQueryRoot.prototype.isDeferred = function isDeferred() {
return this.__concreteNode__.isDeferred;
};
RelayQueryRoot.prototype.getDeferredFragmentNames = function getDeferredFragmentNames() {
var fragmentNames = this.__deferredFragmentNames__;
if (!fragmentNames) {
fragmentNames = {};
getDeferredFragmentNamesForField(this, fragmentNames);
this.__deferredFragmentNames__ = fragmentNames;
}
return fragmentNames;
};
RelayQueryRoot.prototype.equals = function equals(that) {
if (this === that) {
return true;
}
if (!(that instanceof RelayQueryRoot)) {
return false;
}
if (!areEqual(this.getRootCall(), that.getRootCall())) {
return false;
}
if (!areEqual(this.getBatchCall(), that.getBatchCall())) {
return false;
}
if (this.getRootCallArgument() !== that.getRootCallArgument()) {
return false;
}
return _RelayQueryNode.prototype.equals.call(this, that);
};
return RelayQueryRoot;
})(RelayQueryNode);
var RelayQueryOperation = (function (_RelayQueryNode2) {
_inherits(RelayQueryOperation, _RelayQueryNode2);
function RelayQueryOperation(concreteNode, route, variables) {
_classCallCheck(this, RelayQueryOperation);
_RelayQueryNode2.call(this, concreteNode, route, variables);
!(this.constructor.name !== 'RelayQueryOperation') ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQueryOperation: Abstract class cannot be instantiated.') : invariant(false) : undefined;
}
/**
* @internal
*
* Represents a GraphQL mutation.
*/
RelayQueryOperation.prototype.getName = function getName() {
return this.__concreteNode__.name;
};
RelayQueryOperation.prototype.getResponseType = function getResponseType() {
return this.__concreteNode__.responseType;
};
RelayQueryOperation.prototype.getInputType = function getInputType() {
var inputType = this.__concreteNode__.metadata.inputType;
!inputType ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQuery: Expected operation `%s` to be annotated with the type of ' + 'its argument. Either the babel transform was configured incorrectly, ' + 'or the schema failed to define an argument for this mutation.', this.getCall().name) : invariant(false) : undefined;
return inputType;
};
RelayQueryOperation.prototype.getCall = function getCall() {
var calls = this.__calls__;
if (!calls) {
var concreteCalls = this.__concreteNode__.calls;
calls = callsFromGraphQL(concreteCalls, this.__variables__);
this.__calls__ = calls;
}
return calls[0];
};
RelayQueryOperation.prototype.getCallVariableName = function getCallVariableName() {
if (!this.__callVariableName__) {
var concreteCalls = this.__concreteNode__.calls;
var callArg = concreteCalls[0].value;
!GraphQL.isCallVariable(callArg) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQuery: Expected mutation to have a single argument.') : invariant(false) : undefined;
this.__callVariableName__ = callArg.callVariableName;
}
return this.__callVariableName__;
};
return RelayQueryOperation;
})(RelayQueryNode);
var RelayQueryMutation = (function (_RelayQueryOperation) {
_inherits(RelayQueryMutation, _RelayQueryOperation);
function RelayQueryMutation() {
_classCallCheck(this, RelayQueryMutation);
_RelayQueryOperation.apply(this, arguments);
}
/**
* @internal
*
* Represents a GraphQL subscription.
*/
RelayQueryMutation.prototype.equals = function equals(that) {
if (this === that) {
return true;
}
if (!(that instanceof RelayQueryMutation)) {
return false;
}
if (!areEqual(this.getResponseType(), that.getResponseType())) {
return false;
}
if (!areEqual(this.getCall(), that.getCall())) {
return false;
}
return _RelayQueryOperation.prototype.equals.call(this, that);
};
return RelayQueryMutation;
})(RelayQueryOperation);
var RelayQuerySubscription = (function (_RelayQueryOperation2) {
_inherits(RelayQuerySubscription, _RelayQueryOperation2);
function RelayQuerySubscription() {
_classCallCheck(this, RelayQuerySubscription);
_RelayQueryOperation2.apply(this, arguments);
}
/**
* @internal
*
* Wraps access to query fragments.
*
* Note: place proxy methods for `GraphQL.QueryFragment` here.
*/
RelayQuerySubscription.prototype.getPublishedPayloadType = function getPublishedPayloadType() {
return this.getResponseType();
};
RelayQuerySubscription.prototype.equals = function equals(that) {
if (this === that) {
return true;
}
if (!(that instanceof RelayQuerySubscription)) {
return false;
}
if (!areEqual(this.getPublishedPayloadType(), that.getPublishedPayloadType())) {
return false;
}
if (!areEqual(this.getCall(), that.getCall())) {
return false;
}
return _RelayQueryOperation2.prototype.equals.call(this, that);
};
return RelayQuerySubscription;
})(RelayQueryOperation);
var RelayQueryFragment = (function (_RelayQueryNode3) {
_inherits(RelayQueryFragment, _RelayQueryNode3);
function RelayQueryFragment(concreteNode, route, variables, metadata) {
_classCallCheck(this, RelayQueryFragment);
_RelayQueryNode3.call(this, concreteNode, route, variables);
this.__fragmentID__ = null;
this.__metadata__ = metadata || DEFAULT_FRAGMENT_METADATA;
}
/**
* @internal
*
* Wraps access to query fields.
*
* Note: place proxy methods for `GraphQL.Field` here.
*/
RelayQueryFragment.prototype.getDebugName = function getDebugName() {
return this.__concreteNode__.name;
};
/**
* Returns the weak ID for the concrete fragment. Unlike `getFragmentID`,
* this value is identical for any `RelayQueryFragment` with the same concrete
* fragment, regardless of params/route.
*/
RelayQueryFragment.prototype.getConcreteFragmentID = function getConcreteFragmentID() {
return getWeakIdForObject(this.__concreteNode__);
};
/**
* Returns an identifier for a fragment that is unique for any combination of
* concrete fragment, route name, and variables.
*/
RelayQueryFragment.prototype.getFragmentID = function getFragmentID() {
var fragmentID = this.__fragmentID__;
if (!fragmentID) {
fragmentID = generateRQLFieldAlias(this.getConcreteFragmentID() + '.' + this.__route__.name + '.' + stableStringify(this.__variables__));
this.__fragmentID__ = fragmentID;
}
return fragmentID;
};
RelayQueryFragment.prototype.getType = function getType() {
return this.__concreteNode__.type;
};
RelayQueryFragment.prototype.isDeferred = function isDeferred() {
return this.__metadata__.isDeferred;
};
RelayQueryFragment.prototype.isPlural = function isPlural() {
return !!(this.__concreteNode__.isPlural || // RQLPrinter
this.__concreteNode__.metadata.plural);
};
// GraphQLPrinter
RelayQueryFragment.prototype.isReferenceFragment = function isReferenceFragment() {
return this.__metadata__.isReferenceFragment;
};
RelayQueryFragment.prototype.isTypeConditional = function isTypeConditional() {
return this.__metadata__.isTypeConditional;
};
RelayQueryFragment.prototype.hasDeferredDescendant = function hasDeferredDescendant() {
return this.isDeferred() || _RelayQueryNode3.prototype.hasDeferredDescendant.call(this);
};
RelayQueryFragment.prototype.clone = function clone(children) {
var clone = _RelayQueryNode3.prototype.clone.call(this, children);
if (clone instanceof RelayQueryFragment) {
clone.__metadata__ = _extends({}, this.__metadata__);
}
return clone;
};
RelayQueryFragment.prototype.equals = function equals(that) {
if (this === that) {
return true;
}
if (!(that instanceof RelayQueryFragment)) {
return false;
}
if (this.getType() !== that.getType()) {
return false;
}
return _RelayQueryNode3.prototype.equals.call(this, that);
};
return RelayQueryFragment;
})(RelayQueryNode);
var RelayQueryField = (function (_RelayQueryNode4) {
_inherits(RelayQueryField, _RelayQueryNode4);
function RelayQueryField(concreteNode, route, variables) {
_classCallCheck(this, RelayQueryField);
_RelayQueryNode4.call(this, concreteNode, route, variables);
this.__isRefQueryDependency__ = false;
}
RelayQueryField.prototype.isRequisite = function isRequisite() {
return this.__concreteNode__.metadata.isRequisite;
};
RelayQueryField.prototype.isFindable = function isFindable() {
return this.__concreteNode__.metadata.isFindable;
};
RelayQueryField.prototype.isGenerated = function isGenerated() {
return this.__concreteNode__.metadata.isGenerated;
};
RelayQueryField.prototype.isConnection = function isConnection() {
return this.__concreteNode__.metadata.isConnection;
};
RelayQueryField.prototype.isPlural = function isPlural() {
return this.__concreteNode__.metadata.isPlural;
};
RelayQueryField.prototype.isRefQueryDependency = function isRefQueryDependency() {
return this.__isRefQueryDependency__;
};
RelayQueryField.prototype.isScalar = function isScalar() {
return (!this.__children__ || this.__children__.length === 0) && this.__concreteNode__.children.length === 0;
};
RelayQueryField.prototype.isUnionOrInterface = function isUnionOrInterface() {
return this.__concreteNode__.metadata.isUnionOrInterface;
};
RelayQueryField.prototype.getParentType = function getParentType() {
var parentType = this.__concreteNode__.metadata.parentType;
!parentType ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQueryField(): Expected field `%s` to be annotated with the ' + 'type of the parent field.', this.getSchemaName()) : invariant(false) : undefined;
return parentType;
};
/**
* The canonical name for the referenced field in the schema.
*/
RelayQueryField.prototype.getSchemaName = function getSchemaName() {
return this.__concreteNode__.fieldName;
};
/**
* The name for the field when serializing the query or interpreting query
* responses from the server. The serialization key is derived from
* all calls/values and hashed for compactness.
*
* Given the graphql
* `news_feed.first(10).orderby(TOP_STORIES)`
*
* the serialization key is
* `generateRQLFieldAlias('news_feed.first(10).orderby(TOP_STORIES')`
*/
RelayQueryField.prototype.getSerializationKey = function getSerializationKey() {
var serializationKey = this.__serializationKey__;
if (!serializationKey) {
serializationKey = this.getSchemaName();
var calls = this.getCallsWithValues();
for (var ii = 0; ii < calls.length; ii++) {
serializationKey += printRelayQueryCall(calls[ii]);
}
serializationKey = generateRQLFieldAlias(serializationKey);
this.__serializationKey__ = serializationKey;
}
return serializationKey;
};
/**
* The name which Relay internals can use to reference this field, without
* collisions. The storage key is derived from arguments with the following
* exclusions:
*
* - Range calls such as `first` or `find` on connections.
* - Conditionals when the field is present.
*
* Given the graphql
* `news_feed.first(10).orderby(TOP_STORIES).if(true)`
*
* the storage key is
* `'news_feed.orderby(TOP_STORIES)'`
*/
RelayQueryField.prototype.getStorageKey = function getStorageKey() {
var storageKey = this.__storageKey__;
if (!storageKey) {
var isConnection = this.isConnection();
storageKey = this.getSchemaName();
var calls = this.getCallsWithValues();
for (var ii = 0; ii < calls.length; ii++) {
var call = calls[ii];
if (isConnection && RelayConnectionInterface.isConnectionCall(call)) {
continue;
} else if (call.name === IF && String(call.value) === TRUE || call.name === UNLESS && String(call.value) === FALSE) {
// `name.if(true)`, `name.unless(false)`, and `name` are all
// equivalent fields.
continue;
}
storageKey += printRelayQueryCall(call);
}
this.__storageKey__ = storageKey;
}
return storageKey;
};
/**
* The name by which this field's results should be made available to the
* application.
*/
RelayQueryField.prototype.getApplicationName = function getApplicationName() {
return this.__concreteNode__.alias || this.__concreteNode__.fieldName;
};
RelayQueryField.prototype.getInferredRootCallName = function getInferredRootCallName() {
return this.__concreteNode__.metadata.inferredRootCallName;
};
RelayQueryField.prototype.getInferredPrimaryKey = function getInferredPrimaryKey() {
return this.__concreteNode__.metadata.inferredPrimaryKey;
};
RelayQueryField.prototype.getCallsWithValues = function getCallsWithValues() {
var calls = this.__calls__;
if (!calls) {
var concreteCalls = this.__concreteNode__.calls;
calls = callsFromGraphQL(concreteCalls, this.__variables__);
this.__calls__ = calls;
}
return calls;
};
RelayQueryField.prototype.getCallType = function getCallType(callName) {
var concreteCall = this.__concreteNode__.calls.filter(function (call) {
return call.name === callName;
})[0];
if (concreteCall) {
return concreteCall.metadata.type;
}
};
RelayQueryField.prototype.equals = function equals(that) {
if (this === that) {
return true;
}
if (!(that instanceof RelayQueryField)) {
return false;
}
if (this.getSchemaName() !== that.getSchemaName() || this.getApplicationName() !== that.getApplicationName() || !areEqual(this.getCallsWithValues(), that.getCallsWithValues())) {
return false;
}
return _RelayQueryNode4.prototype.equals.call(this, that);
};
RelayQueryField.prototype.cloneAsRefQueryDependency = function cloneAsRefQueryDependency() {
var field = new RelayQueryField(this.__concreteNode__, this.__route__, this.__variables__);
field.__children__ = [];
field.__isRefQueryDependency__ = true;
return field;
};
RelayQueryField.prototype.cloneFieldWithCalls = function cloneFieldWithCalls(children, calls) {
if (this.isScalar()) {
// Compact new children *after* this check, for consistency.
!(children.length === 0) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQueryField: Cannot add children to scalar fields.') : invariant(false) : undefined;
}
// use `clone()` if call values do not change
if (areEqual(this.getCallsWithValues(), calls)) {
var clone = this.clone(children);
return clone;
}
var nextChildren = cloneChildren(this.getChildren(), children);
if (!nextChildren.length) {
return null;
}
var field = new RelayQueryField(this.__concreteNode__, this.__route__, this.__variables__);
field.__children__ = nextChildren;
field.__calls__ = calls;
return field;
};
return RelayQueryField;
})(RelayQueryNode);
function createNode(_x, _x2, _x3) {
var _again = true;
_function: while (_again) {
var concreteNode = _x,
route = _x2,
variables = _x3;
type = routeFragment = fragment = fragmentVariables = undefined;
_again = false;
// unused default value keeps flow happy
var type = RelayQueryNode;
if (GraphQL.isField(concreteNode)) {
type = RelayQueryField;
} else if (GraphQL.isFragment(concreteNode)) {
type = RelayQueryFragment;
} else if (GraphQL.isQuery(concreteNode)) {
type = RelayQueryRoot;
} else if (GraphQL.isQueryWithValues(concreteNode)) {
concreteNode = concreteNode.query;
type = RelayQueryRoot;
} else if (GraphQL.isMutation(concreteNode)) {
type = RelayQueryMutation;
} else if (GraphQL.isSubscription(concreteNode)) {
type = RelayQuerySubscription;
} else if (concreteNode instanceof RelayRouteFragment) {
var routeFragment = concreteNode.getFragmentForRoute(route);
if (routeFragment) {
// may be null if no value was defined for this route.
_x = routeFragment;
_x2 = route;
_x3 = variables;
_again = true;
continue _function;
}
return null;
} else if (concreteNode instanceof RelayFragmentReference) {
var fragment = concreteNode.getFragment(variables);
var fragmentVariables = concreteNode.getVariables(route, variables);
if (fragment) {
// the fragment may be null when `if` or `unless` conditions are not met.
!GraphQL.isFragment(fragment) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQuery: Invalid fragment reference, expected query fragment.') : invariant(false) : undefined;
return createMemoizedFragment(fragment, route, fragmentVariables, {
isDeferred: concreteNode.isDeferred(),
isReferenceFragment: true,
isTypeConditional: concreteNode.isTypeConditional()
});
}
return null;
} else {
!false ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQueryNode: Invalid concrete node.') : invariant(false) : undefined;
}
return new type(concreteNode, route, variables);
}
}
/**
* Memoizes the `RelayQueryFragment` equivalent of a given `GraphQL` fragment
* for the given route, variables, and deferred status.
*/
function createMemoizedFragment(concreteFragment, route, variables, metadata) {
var cacheKey = route.name + ':' + stableStringify(variables) + ':' + stableStringify(metadata);
var fragment = concreteFragment.__cachedFragment__;
var fragmentCacheKey = concreteFragment.__cacheKey__;
if (!fragment || fragmentCacheKey !== cacheKey) {
fragment = new RelayQueryFragment(concreteFragment, route, variables, metadata);
concreteFragment.__cachedFragment__ = fragment;
concreteFragment.__cacheKey__ = cacheKey;
}
return fragment;
}
/**
* Compacts new children and compares them to the previous children.
* - If all items are equal, returns previous array
* - If any items differ, returns new array
*/
function cloneChildren(prevChildren, nextChildren) {
var children = [];
var isSameChildren = true;
var prevIndex = 0;
for (var ii = 0; ii < nextChildren.length; ii++) {
var child = nextChildren[ii];
if (child) {
children.push(child);
isSameChildren = isSameChildren && child === prevChildren[prevIndex++];
}
}
if (isSameChildren && children.length === prevChildren.length) {
return prevChildren;
} else {
return children;
}
}
/**
* Returns the names of the deferred fragments in the query. Does not return
* nested deferred fragment names.
*/
function getDeferredFragmentNamesForField(node, fragmentNames) {
if (node instanceof RelayQueryFragment && node.isDeferred()) {
var fragmentID = node.getFragmentID();
fragmentNames[fragmentID] = fragmentID;
return;
}
node.getChildren().forEach(function (child) {
return getDeferredFragmentNamesForField(child, fragmentNames);
});
}
module.exports = {
Field: RelayQueryField,
Fragment: RelayQueryFragment,
Mutation: RelayQueryMutation,
Node: RelayQueryNode,
Operation: RelayQueryOperation,
Root: RelayQueryRoot,
Subscription: RelayQuerySubscription
};
// for flow
// TODO(#7161070) Remove this once `toGraphQL` is no longer needed.