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 / RelayQuery.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 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 _Object$freeze = require('babel-runtime/core-js/object/freeze')['default'];

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

var RelayConnectionInterface = require('./RelayConnectionInterface');
var RelayFragmentReference = require('./RelayFragmentReference');

var RelayMetaRoute = require('./RelayMetaRoute');
var RelayProfiler = require('./RelayProfiler');
var RelayRouteFragment = require('./RelayRouteFragment');

var areEqual = require('fbjs/lib/areEqual');
var callsFromGraphQL = require('./callsFromGraphQL');
var callsToGraphQL = require('./callsToGraphQL');
var generateRQLFieldAlias = require('./generateRQLFieldAlias');
var invariant = require('fbjs/lib/invariant');
var serializeRelayQueryCall = require('./serializeRelayQueryCall');
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 SKIP = 'skip';
var INCLUDE = 'include';

var _nextFragmentID = 0;
var _nextQueryID = 0;

var DEFAULT_FRAGMENT_METADATA = {
  isDeferred: false,
  isContainerFragment: false
};
var EMPTY_DIRECTIVES = [];
var EMPTY_CALLS = [];

if (process.env.NODE_ENV !== 'production') {
  _Object$freeze(EMPTY_CALLS);
  _Object$freeze(EMPTY_DIRECTIVES);
}

/**
 * @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 GraphQL fragment, mutation, or query.') : invariant(false) : undefined;
    return node;
  };

  /**
   * @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;
  }

  /**
   * @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 field `%s`.', this instanceof RelayQueryField ? this.getSchemaName() : null) : 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) {
      (function () {
        var nextChildren = [];
        var concreteChildren = _this.__concreteNode__.children;
        if (concreteChildren) {
          concreteChildren.forEach(function (concreteChild) {
            if (concreteChild == null) {
              return;
            }
            var node = createNode(concreteChild, _this.__route__, _this.__variables__);
            if (node && node.isIncluded()) {
              nextChildren.push(node);
            }
          });
        }
        _this.__children__ = nextChildren;
        children = nextChildren;
      })();
    }
    return children;
  };

  RelayQueryNode.prototype.isIncluded = function isIncluded() {
    // Bail out early since most nodes won't have directives
    if (!this.__concreteNode__.directives) {
      return true;
    }
    return this.getDirectives().every(function (directive) {
      if (directive.name === SKIP) {
        return !directive.arguments.some(function (arg) {
          return arg.name === IF && !!arg.value;
        });
      } else if (directive.name === INCLUDE) {
        return !directive.arguments.some(function (arg) {
          return arg.name === IF && !arg.value;
        });
      }
      return true;
    });
  };

  RelayQueryNode.prototype.getDirectives = function getDirectives() {
    var _this2 = this;

    var concreteDirectives = this.__concreteNode__.directives;
    if (concreteDirectives) {
      return this.__concreteNode__.directives.map(function (directive) {
        return {
          name: directive.name,
          arguments: callsFromGraphQL(directive.arguments, _this2.__variables__)
        };
      });
    }
    return EMPTY_DIRECTIVES;
  };

  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.getType = function getType() {
    return this.__concreteNode__.type;
  };

  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.isAbstract = function isAbstract() {
    throw new Error('RelayQueryNode: Abstract function cannot be called.');
  };

  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() {
    return this.__concreteNode__;
  };

  return RelayQueryNode;
})();

var RelayQueryRoot = (function (_RelayQueryNode) {
  _inherits(RelayQueryRoot, _RelayQueryNode);

  /**
   * Helper to construct a new root query with the given attributes and 'empty'
   * route/variables.
   */

  RelayQueryRoot.build = function build(name, fieldName, value, children, metadata, type) {
    var nextChildren = children ? children.filter(function (child) {
      return !!child;
    }) : [];
    var batchCallVariable = QueryBuilder.getBatchCallVariable(value);
    var identifyingArgValue = undefined;
    if (batchCallVariable) {
      identifyingArgValue = batchCallVariable;
    } else if (Array.isArray(value)) {
      identifyingArgValue = value.map(QueryBuilder.createCallValue);
    } else if (value) {
      identifyingArgValue = QueryBuilder.createCallValue(value);
    }
    var concreteRoot = QueryBuilder.createQuery({
      fieldName: fieldName,
      identifyingArgValue: identifyingArgValue,
      metadata: metadata,
      name: name,
      type: type
    });
    var root = new RelayQueryRoot(concreteRoot, RelayMetaRoute.get('$RelayQuery'), {});
    root.__children__ = nextChildren;
    return root;
  };

  RelayQueryRoot.create = function create(concreteNode, route, variables) {
    var query = QueryBuilder.getQuery(concreteNode);
    !query ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQueryRoot.create(): Expected a GraphQL `query { ... }`, got: %s', concreteNode) : invariant(false) : undefined;
    return new RelayQueryRoot(query, route, variables);
  };

  function RelayQueryRoot(concreteNode, route, variables) {
    _classCallCheck(this, RelayQueryRoot);

    _RelayQueryNode.call(this, concreteNode, route, variables);
    this.__batchCall__ = undefined;
    this.__id__ = undefined;
    this.__identifyingArg__ = undefined;
    this.__storageKey__ = 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 = 'q' + _nextQueryID++;
      this.__id__ = id;
    }
    return id;
  };

  RelayQueryRoot.prototype.getBatchCall = function getBatchCall() {
    var batchCall = this.__batchCall__;
    if (batchCall === undefined) {
      var concreteCalls = this.__concreteNode__.calls;
      if (concreteCalls) {
        var callArg = concreteCalls[0] && concreteCalls[0].value;
        if (callArg != null && !Array.isArray(callArg) && callArg.kind === 'BatchCallVariable') {
          batchCall = {
            refParamName: 'ref_' + callArg.sourceQueryID,
            sourceQueryID: callArg.sourceQueryID,
            sourceQueryPath: callArg.jsonPath
          };
        }
      }
      batchCall = batchCall || null;
      this.__batchCall__ = batchCall;
    }
    return batchCall;
  };

  RelayQueryRoot.prototype.getCallsWithValues = function getCallsWithValues() {
    var calls = this.__calls__;
    if (!calls) {
      var concreteCalls = this.__concreteNode__.calls;
      if (concreteCalls) {
        calls = callsFromGraphQL(concreteCalls, this.__variables__);
      } else {
        calls = EMPTY_CALLS;
      }
      this.__calls__ = calls;
    }
    return calls;
  };

  RelayQueryRoot.prototype.getFieldName = function getFieldName() {
    return this.__concreteNode__.fieldName;
  };

  RelayQueryRoot.prototype.getIdentifyingArg = function getIdentifyingArg() {
    var _this3 = this;

    var identifyingArg = this.__identifyingArg__;
    if (!identifyingArg) {
      (function () {
        var metadata = _this3.__concreteNode__.metadata;
        var identifyingArgName = metadata.identifyingArgName;
        if (identifyingArgName != null) {
          identifyingArg = _this3.getCallsWithValues().find(function (c) {
            return c.name === identifyingArgName;
          });
          if (identifyingArg && metadata.identifyingArgType != null) {
            identifyingArg.type = metadata.identifyingArgType;
          }
          _this3.__identifyingArg__ = identifyingArg;
        }
      })();
    }
    return identifyingArg;
  };

  RelayQueryRoot.prototype.getStorageKey = function getStorageKey() {
    var _this4 = this;

    var storageKey = this.__storageKey__;
    if (!storageKey) {
      (function () {
        var args = _this4.getCallsWithValues();
        var identifyingArg = _this4.getIdentifyingArg();
        if (identifyingArg) {
          args = args.filter(function (arg) {
            return arg !== identifyingArg;
          });
        }
        var field = RelayQueryField.build({
          fieldName: _this4.getFieldName(),
          calls: args,
          type: _this4.getType()
        });
        storageKey = field.getStorageKey();
        _this4.__storageKey__ = storageKey;
      })();
    }
    return storageKey;
  };

  RelayQueryRoot.prototype.hasDeferredDescendant = function hasDeferredDescendant() {
    return this.isDeferred() || _RelayQueryNode.prototype.hasDeferredDescendant.call(this);
  };

  RelayQueryRoot.prototype.isAbstract = function isAbstract() {
    return !!this.__concreteNode__.metadata.isAbstract;
  };

  RelayQueryRoot.prototype.isDeferred = function isDeferred() {
    return !!this.__concreteNode__.isDeferred;
  };

  RelayQueryRoot.prototype.isPlural = function isPlural() {
    return !!this.__concreteNode__.metadata.isPlural;
  };

  RelayQueryRoot.prototype.equals = function equals(that) {
    if (this === that) {
      return true;
    }
    if (!(that instanceof RelayQueryRoot)) {
      return false;
    }
    if (!areEqual(this.getBatchCall(), that.getBatchCall())) {
      return false;
    }
    if (this.getFieldName() !== that.getFieldName() || !areEqual(this.getCallsWithValues(), that.getCallsWithValues())) {
      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.getType = function getType() {
    return this.getResponseType();
  };

  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;
      if (concreteCalls) {
        calls = callsFromGraphQL(concreteCalls, this.__variables__);
      } else {
        calls = EMPTY_CALLS;
      }
      this.__calls__ = calls;
    }
    return calls[0];
  };

  RelayQueryOperation.prototype.getCallVariableName = function getCallVariableName() {
    if (!this.__callVariableName__) {
      var concreteCalls = this.__concreteNode__.calls;
      var callVariable = concreteCalls && QueryBuilder.getCallVariable(concreteCalls[0].value);
      !callVariable ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQuery: Expected mutation to have a single argument.') : invariant(false) : undefined;
      this.__callVariableName__ = callVariable.callVariableName;
    }
    return this.__callVariableName__;
  };

  /**
   * Mutations and subscriptions must have a concrete type due to the need for
   * requisite top-level fields.
   */

  RelayQueryOperation.prototype.isAbstract = function isAbstract() {
    return false;
  };

  return RelayQueryOperation;
})(RelayQueryNode);

var RelayQueryMutation = (function (_RelayQueryOperation) {
  _inherits(RelayQueryMutation, _RelayQueryOperation);

  function RelayQueryMutation() {
    _classCallCheck(this, RelayQueryMutation);

    _RelayQueryOperation.apply(this, arguments);
  }

  /**
   * @internal
   *
   * Represents a GraphQL subscription.
   */

  /**
   * Helper to construct a new mutation with the given attributes and 'empty'
   * route/variables.
   */

  RelayQueryMutation.build = function build(name, responseType, callName, callValue, children, metadata) {
    var nextChildren = children ? children.filter(function (child) {
      return !!child;
    }) : [];
    var concreteMutation = QueryBuilder.createMutation({
      calls: [QueryBuilder.createCall(callName, QueryBuilder.createCallVariable('input'))],
      metadata: metadata,
      name: name,
      responseType: responseType
    });
    var mutation = new RelayQueryMutation(concreteMutation, RelayMetaRoute.get('$RelayQuery'), { input: callValue || '' });
    mutation.__children__ = nextChildren;
    return mutation;
  };

  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.
   */

  RelayQuerySubscription.create = function create(concreteNode, route, variables) {
    var subscription = QueryBuilder.getSubscription(concreteNode);
    !subscription ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQuerySubscription.create(): ' + 'Expected a GraphQL `subscription { ... }`, got: %s', concreteNode) : invariant(false) : undefined;
    return new RelayQuerySubscription(concreteNode, route, variables);
  };

  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);

  /**
   * Helper to construct a new fragment with the given attributes and 'empty'
   * route/variables.
   */

  RelayQueryFragment.build = function build(name, type, children, metadata) {
    var nextChildren = children ? children.filter(function (child) {
      return !!child;
    }) : [];
    var concreteFragment = QueryBuilder.createFragment({
      name: name,
      type: type,
      metadata: metadata
    });
    var fragment = new RelayQueryFragment(concreteFragment, RelayMetaRoute.get('$RelayQuery'), {}, {
      isDeferred: !!(metadata && metadata.isDeferred),
      isContainerFragment: !!(metadata && metadata.isContainerFragment)
    });
    fragment.__children__ = nextChildren;
    return fragment;
  };

  RelayQueryFragment.create = function create(concreteNode, route, variables, metadata) {
    var fragment = QueryBuilder.getFragment(concreteNode);
    !fragment ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQueryFragment.create(): ' + 'Expected a GraphQL `fragment { ... }`, got: %s', concreteNode) : invariant(false) : undefined;
    return createMemoizedFragment(fragment, route, variables, metadata || DEFAULT_FRAGMENT_METADATA);
  };

  function RelayQueryFragment(concreteNode, route, variables, metadata) {
    _classCallCheck(this, RelayQueryFragment);

    _RelayQueryNode3.call(this, concreteNode, route, variables);
    this.__compositeHash__ = null;
    this.__isCloned__ = false;
    this.__metadata__ = metadata || DEFAULT_FRAGMENT_METADATA;
  }

  /**
   * @internal
   *
   * Wraps access to query fields.
   */

  RelayQueryFragment.prototype.getDebugName = function getDebugName() {
    return this.__concreteNode__.name;
  };

  /**
   * Checks whether a fragment has been cloned such that the concrete node is no
   * longer representative of this instance. This will return true for fragments
   * that are the result of cloning with new children.
   */

  RelayQueryFragment.prototype.isCloned = function isCloned() {
    return this.__isCloned__;
  };

  /**
   * The "concrete node hash" of a fragment uniquely identifies the instance of
   * the concrete node. This method should be used with `isCloned()` if you may
   * be dealing with fragments that have been cloned with new children.
   *
   * This hash may change between runtime sessions (e.g. client and server).
   */

  RelayQueryFragment.prototype.getConcreteNodeHash = function getConcreteNodeHash() {
    var instanceHash = this.__concreteNode__.__instanceHash__;
    if (instanceHash == null) {
      instanceHash = (_nextFragmentID++).toString();
      this.__concreteNode__.__instanceHash__ = instanceHash;
    }
    return instanceHash;
  };

  /**
   * The "composite hash" is similar to the concrete instance hash, but is also
   * uniquely differentiates between varying variable values or route names. It
   * should also be used with `isCloned()`.
   *
   * The composite hash is used to identify fragment pointers in records. It is
   * also used to store the status of fetching deferred fragments.
   */

  RelayQueryFragment.prototype.getCompositeHash = function getCompositeHash() {
    var compositeHash = this.__compositeHash__;
    if (!compositeHash) {
      // TODO: Simplify this hash function, #9599170.
      compositeHash = generateRQLFieldAlias(this.getConcreteNodeHash() + '.' + this.__route__.name + '.' + stableStringify(this.__variables__));
      this.__compositeHash__ = compositeHash;
    }
    return compositeHash;
  };

  RelayQueryFragment.prototype.isAbstract = function isAbstract() {
    return !!this.__concreteNode__.metadata.isAbstract;
  };

  RelayQueryFragment.prototype.isDeferred = function isDeferred() {
    return this.__metadata__.isDeferred;
  };

  RelayQueryFragment.prototype.isPlural = function isPlural() {
    var metadata = this.__concreteNode__.metadata;
    return !!(metadata.isPlural || // FB Printer
    metadata.plural) // OSS Printer from `@relay`
    ;
  };

  RelayQueryFragment.prototype.cloneAsPlainFragment = function cloneAsPlainFragment() {
    return createMemoizedFragment(this.__concreteNode__, this.__route__, this.__variables__, DEFAULT_FRAGMENT_METADATA);
  };

  RelayQueryFragment.prototype.isContainerFragment = function isContainerFragment() {
    return this.__metadata__.isContainerFragment;
  };

  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 !== this && clone instanceof RelayQueryFragment) {
      clone.__isCloned__ = true;
      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);

  RelayQueryField.create = function create(concreteNode, route, variables) {
    var field = QueryBuilder.getField(concreteNode);
    !field ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQueryField.create(): Expected a GraphQL field, got: %s', concreteNode) : invariant(false) : undefined;
    return new RelayQueryField(field, route, variables);
  };

  /**
   * Helper to construct a new field with the given attributes and 'empty'
   * route/variables.
   */

  RelayQueryField.build = function build(_ref) {
    var alias = _ref.alias;
    var calls = _ref.calls;
    var children = _ref.children;
    var fieldName = _ref.fieldName;
    var metadata = _ref.metadata;
    var type = _ref.type;
    return (function () {
      var nextChildren = children ? children.filter(function (child) {
        return !!child;
      }) : [];
      var concreteField = QueryBuilder.createField({
        alias: alias,
        calls: calls ? callsToGraphQL(calls) : null,
        fieldName: fieldName,
        metadata: metadata,
        type: type
      });
      var field = new RelayQueryField(concreteField, RelayMetaRoute.get('$RelayQuery'), {});
      field.__children__ = nextChildren;
      return field;
    })();
  };

  function RelayQueryField(concreteNode, route, variables) {
    _classCallCheck(this, RelayQueryField);

    _RelayQueryNode4.call(this, concreteNode, route, variables);
    this.__debugName__ = undefined;
    this.__isRefQueryDependency__ = false;
    this.__rangeBehaviorKey__ = undefined;
    this.__shallowHash__ = undefined;
  }

  RelayQueryField.prototype.isAbstract = function isAbstract() {
    return !!this.__concreteNode__.metadata.isAbstract;
  };

  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.isRequisite = function isRequisite() {
    return !!this.__concreteNode__.metadata.isRequisite;
  };

  RelayQueryField.prototype.isScalar = function isScalar() {
    var concreteChildren = this.__concreteNode__.children;
    return (!this.__children__ || this.__children__.length === 0) && (!concreteChildren || concreteChildren.length === 0);
  };

  RelayQueryField.prototype.getDebugName = function getDebugName() {
    var _this5 = this;

    var debugName = this.__debugName__;
    if (!debugName) {
      (function () {
        debugName = _this5.getSchemaName();
        var printedCoreArgs = undefined;
        _this5.getCallsWithValues().forEach(function (arg) {
          if (_this5._isCoreArg(arg)) {
            printedCoreArgs = printedCoreArgs || [];
            printedCoreArgs.push(serializeRelayQueryCall(arg));
          }
        });
        if (printedCoreArgs) {
          debugName += printedCoreArgs.sort().join('');
        }
        _this5.__debugName__ = debugName;
      })();
    }
    return debugName;
  };

  /**
   * The canonical name for the referenced field in the schema.
   */

  RelayQueryField.prototype.getSchemaName = function getSchemaName() {
    return this.__concreteNode__.fieldName;
  };

  /**
   * A string representing the range behavior eligible arguments associated with
   * this field. Arguments will be sorted.
   *
   * Non-core arguments (like connection and identifying arguments) are dropped.
   *   `field(first: 10, foo: "bar", baz: "bat")` => `'baz(bat).foo(bar)'`
   *   `username(name: "steve")`                  => `''`
   */

  RelayQueryField.prototype.getRangeBehaviorKey = function getRangeBehaviorKey() {
    var _this6 = this;

    !this.isConnection() ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQueryField: Range behavior keys are associated exclusively with ' + 'connection fields. `getRangeBehaviorKey()` was called on the ' + 'non-connection field `%s`.', this.getSchemaName()) : invariant(false) : undefined;
    var rangeBehaviorKey = this.__rangeBehaviorKey__;
    if (rangeBehaviorKey == null) {
      (function () {
        var printedCoreArgs = [];
        _this6.getCallsWithValues().forEach(function (arg) {
          if (_this6._isCoreArg(arg)) {
            printedCoreArgs.push(serializeRelayQueryCall(arg));
          }
        });
        rangeBehaviorKey = printedCoreArgs.sort().join('').slice(1);
        _this6.__rangeBehaviorKey__ = rangeBehaviorKey;
      })();
    }
    return rangeBehaviorKey;
  };

  /**
   * 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
   *   `field(first: 10, foo: "bar", baz: "bat")`, or
   *   `field(baz: "bat", foo: "bar", first: 10)`
   *
   * ...the following serialization key will be produced:
   *   `generateRQLFieldAlias('field.bar(bat).first(10).foo(bar)')`
   */

  RelayQueryField.prototype.getSerializationKey = function getSerializationKey() {
    var serializationKey = this.__serializationKey__;
    if (!serializationKey) {
      serializationKey = generateRQLFieldAlias(this.getSchemaName() + this.getCallsWithValues().map(serializeRelayQueryCall).sort().join(''));
      this.__serializationKey__ = serializationKey;
    }
    return serializationKey;
  };

  /**
   * Returns a hash of the field name and all argument values.
   */

  RelayQueryField.prototype.getShallowHash = function getShallowHash() {
    var shallowHash = this.__shallowHash__;
    if (!shallowHash) {
      this.__shallowHash__ = shallowHash = this.getSchemaName() + serializeCalls(this.getCallsWithValues());
    }
    return shallowHash;
  };

  /**
   * The name which Relay internals can use to reference this field, without
   * collisions.
   *
   * Given the GraphQL
   *   `field(first: 10, foo: "bar", baz: "bat")`, or
   *   `field(baz: "bat", foo: "bar", first: 10)`
   *
   * ...the following storage key will be produced:
   *   `'field{bar:"bat",foo:"bar"}'`
   */

  RelayQueryField.prototype.getStorageKey = function getStorageKey() {
    var _this7 = this;

    var storageKey = this.__storageKey__;
    if (!storageKey) {
      this.__storageKey__ = storageKey = this.getSchemaName() + serializeCalls(this.getCallsWithValues().filter(function (call) {
        return _this7._isCoreArg(call);
      }));
    }
    return storageKey;
  };

  /**
   * The name by which this field's results should be made available to the
   * application.
   */

  RelayQueryField.prototype.getApplicationName = function getApplicationName() {
    var concreteNode = this.__concreteNode__;
    return concreteNode.alias || 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;
      if (concreteCalls) {
        calls = callsFromGraphQL(concreteCalls, this.__variables__);
      } else {
        calls = EMPTY_CALLS;
      }
      this.__calls__ = calls;
    }
    return calls;
  };

  RelayQueryField.prototype.getCallType = function getCallType(callName) {
    var concreteCalls = this.__concreteNode__.calls;
    var concreteCall = concreteCalls && concreteCalls.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;
  };

  /**
   * The following types of arguments are non-core:
   * - Range calls such as `first` or `find` on connections.
   * - Conditionals when the field is present.
   */

  RelayQueryField.prototype._isCoreArg = function _isCoreArg(arg) {
    return(
      // `name(if:true)`, `name(unless:false)`, and `name` are equivalent.
      !(arg.name === IF && String(arg.value) === TRUE) && !(arg.name === UNLESS && String(arg.value) === FALSE) &&
      // Connection arguments can be stripped out.
      !(this.isConnection() && RelayConnectionInterface.isConnectionCall(arg))
    );
  };

  return RelayQueryField;
})(RelayQueryNode);

function createNode(_x, _x2, _x3) {
  var _again = true;

  _function: while (_again) {
    var concreteNode = _x,
        route = _x2,
        variables = _x3;
    _again = false;

    !(typeof concreteNode === 'object' && concreteNode !== null) ? process.env.NODE_ENV !== 'production' ? invariant(false, 'RelayQueryNode: Expected a GraphQL object created with `Relay.QL`, got' + '`%s`.', concreteNode) : invariant(false) : undefined;
    var kind = concreteNode.kind;
    var type = RelayQueryNode;
    if (kind === 'Field') {
      type = RelayQueryField;
    } else if (kind === 'Fragment') {
      type = RelayQueryFragment;
    } else if (kind === 'FragmentReference') {
      type = RelayQueryFragment;
      var fragment = QueryBuilder.getFragment(concreteNode.fragment);
      // TODO #9171213: Reference directives should override fragment directives
      if (fragment) {
        return createMemoizedFragment(fragment, route, {}, {
          isDeferred: false,
          isContainerFragment: true
        });
      }
    } else if (kind === 'Query') {
      type = RelayQueryRoot;
    } else if (kind === 'Mutation') {
      type = RelayQueryMutation;
    } else if (kind === 'Subscription') {
      type = RelayQuerySubscription;
    } else if (concreteNode instanceof RelayRouteFragment) {
      var fragment = concreteNode.getFragmentForRoute(route);
      if (fragment) {
        // may be null if no value was defined for this route.
        _x = fragment;
        _x2 = route;
        _x3 = variables;
        _again = true;
        kind = type = fragment = fragment = undefined;
        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.
        return createMemoizedFragment(fragment, route, fragmentVariables, {
          isDeferred: concreteNode.isDeferred(),
          isContainerFragment: concreteNode.isContainerFragment()
        });
      }
      return null;
    } else {}
    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;
  }
}

/**
 * Creates an opaque serialization of calls.
 */
function serializeCalls(calls) {
  if (calls.length) {
    var _ret6 = (function () {
      var callMap = {};
      calls.forEach(function (call) {
        callMap[call.name] = call.value;
      });
      return {
        v: stableStringify(callMap)
      };
    })();

    if (typeof _ret6 === 'object') return _ret6.v;
  } else {
    return '';
  }
}

RelayProfiler.instrumentMethods(RelayQueryNode.prototype, {
  clone: '@RelayQueryNode.prototype.clone',
  equals: '@RelayQueryNode.prototype.equals',
  getChildren: '@RelayQueryNode.prototype.getChildren',
  getDirectives: '@RelayQueryNode.prototype.getDirectives',
  hasDeferredDescendant: '@RelayQueryNode.prototype.hasDeferredDescendant',
  getFieldByStorageKey: '@RelayQueryNode.prototype.getFieldByStorageKey'
});

RelayProfiler.instrumentMethods(RelayQueryField.prototype, {
  getStorageKey: '@RelayQueryField.prototype.getStorageKey',
  getSerializationKey: '@RelayQueryField.prototype.getSerializationKey'
});

module.exports = {
  Field: RelayQueryField,
  Fragment: RelayQueryFragment,
  Mutation: RelayQueryMutation,
  Node: RelayQueryNode,
  Operation: RelayQueryOperation,
  Root: RelayQueryRoot,
  Subscription: RelayQuerySubscription
};
// for flow