graphql
Version:
A Query Language and Runtime which can target any service.
694 lines (614 loc) • 19.4 kB
JavaScript
/* @flow */
/**
* Copyright (c) 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.
*/
'use strict';
/**
* These are all of the possible kinds of types.
*/
// Predicates
/**
* These types may be used as input types for arguments and directives.
*/
var _createClass = require('babel-runtime/helpers/create-class')['default'];
var _classCallCheck = require('babel-runtime/helpers/class-call-check')['default'];
var _Object$defineProperty = require('babel-runtime/core-js/object/define-property')['default'];
var _Object$keys = require('babel-runtime/core-js/object/keys')['default'];
var _Map = require('babel-runtime/core-js/map')['default'];
var _interopRequireDefault = require('babel-runtime/helpers/interop-require-default')['default'];
_Object$defineProperty(exports, '__esModule', {
value: true
});
exports.isInputType = isInputType;
/**
* These types may be used as output types as the result of fields.
*/
exports.isOutputType = isOutputType;
/**
* These types may describe types which may be leaf values.
*/
exports.isLeafType = isLeafType;
/**
* These types may describe the parent context of a selection set.
*/
exports.isCompositeType = isCompositeType;
/**
* These types may describe the parent context of a selection set.
*/
exports.isAbstractType = isAbstractType;
/**
* These types can all accept null as a value.
*/
exports.getNullableType = getNullableType;
/**
* These types have no modifiers like List or NonNull.
*/
exports.getUnmodifiedType = getUnmodifiedType;
var _utilsInvariant = require('../utils/invariant');
var _utilsInvariant2 = _interopRequireDefault(_utilsInvariant);
var _languageKinds = require('../language/kinds');
function isInputType(type) {
var nakedType = getUnmodifiedType(type);
return nakedType instanceof GraphQLScalarType || nakedType instanceof GraphQLEnumType || nakedType instanceof GraphQLInputObjectType;
}
function isOutputType(type) {
var nakedType = getUnmodifiedType(type);
return nakedType instanceof GraphQLScalarType || nakedType instanceof GraphQLObjectType || nakedType instanceof GraphQLInterfaceType || nakedType instanceof GraphQLUnionType || nakedType instanceof GraphQLEnumType;
}
function isLeafType(type) {
var nakedType = getUnmodifiedType(type);
return nakedType instanceof GraphQLScalarType || nakedType instanceof GraphQLEnumType;
}
function isCompositeType(type) {
return type instanceof GraphQLObjectType || type instanceof GraphQLInterfaceType || type instanceof GraphQLUnionType;
}
function isAbstractType(type) {
return type instanceof GraphQLInterfaceType || type instanceof GraphQLUnionType;
}
function getNullableType(type) {
return type instanceof GraphQLNonNull ? type.ofType : type;
}
function getUnmodifiedType(type) {
var unmodifiedType = type;
while (unmodifiedType instanceof GraphQLList || unmodifiedType instanceof GraphQLNonNull) {
unmodifiedType = unmodifiedType.ofType;
}
return unmodifiedType;
}
/**
* Scalar Type Definition
*
* The leaf values of any request and input values to arguments are
* Scalars (or Enums) and are defined with a name and a series of coercion
* functions used to ensure validity.
*
* Example:
*
* var OddType = new GraphQLScalarType({
* name: 'Odd',
* coerce(value) {
* return value % 2 === 1 ? value : null;
* }
* });
*
*/
var GraphQLScalarType = (function () {
function GraphQLScalarType(config) {
_classCallCheck(this, GraphQLScalarType);
(0, _utilsInvariant2['default'])(config.name, 'Type must be named.');
this.name = config.name;
this.description = config.description;
this._scalarConfig = config;
}
_createClass(GraphQLScalarType, [{
key: 'coerce',
value: function coerce(value) /*T*/{
var coercer = this._scalarConfig.coerce;
return coercer(value);
}
}, {
key: 'coerceLiteral',
value: function coerceLiteral(value) /*T*/{
var coercer = this._scalarConfig.coerceLiteral;
return coercer ? coercer(value) : null;
}
}, {
key: 'toString',
value: function toString() {
return this.name;
}
}]);
return GraphQLScalarType;
})();
exports.GraphQLScalarType = GraphQLScalarType;
/**
* Object Type Definition
*
* Almost all of the GraphQL types you define will be object types. Object types
* have a name, but most importantly describe their fields.
*
* Example:
*
* var AddressType = new GraphQLObjectType({
* name: 'Address',
* fields: {
* street: { type: GraphQLString },
* number: { type: GraphQLInt },
* formatted: {
* type: GraphQLString,
* resolve(obj) {
* return obj.number + ' ' + obj.street
* }
* }
* }
* });
*
* When two types need to refer to each other, or a type needs to refer to
* itself in a field, you can use a function expression (aka a closure or a
* thunk) to supply the fields lazily.
*
* Example:
*
* var PersonType = new GraphQLObjectType({
* name: 'Person',
* fields: () => ({
* name: { type: GraphQLString },
* bestFriend: { type: PersonType },
* })
* });
*
*/
var GraphQLObjectType = (function () {
function GraphQLObjectType(config) {
_classCallCheck(this, GraphQLObjectType);
(0, _utilsInvariant2['default'])(config.name, 'Type must be named.');
this.name = config.name;
this.description = config.description;
this._typeConfig = config;
addImplementationToInterfaces(this);
}
_createClass(GraphQLObjectType, [{
key: 'getFields',
value: function getFields() {
return this._fields || (this._fields = defineFieldMap(this._typeConfig.fields));
}
}, {
key: 'getInterfaces',
value: function getInterfaces() {
return this._typeConfig.interfaces || [];
}
}, {
key: 'isTypeOf',
value: function isTypeOf(value) {
var predicate = this._typeConfig.isTypeOf;
if (predicate) {
return predicate(value);
}
}
}, {
key: 'toString',
value: function toString() {
return this.name;
}
}]);
return GraphQLObjectType;
})();
exports.GraphQLObjectType = GraphQLObjectType;
function defineFieldMap(fields) {
var fieldMap = typeof fields === 'function' ? fields() : fields;
_Object$keys(fieldMap).forEach(function (fieldName) {
var field = fieldMap[fieldName];
field.name = fieldName;
if (!field.args) {
field.args = [];
} else {
field.args = _Object$keys(field.args).map(function (argName) {
var arg = field.args[argName];
(0, _utilsInvariant2['default'])(arg.type, 'Arg must supply type. ' + fieldName + '.' + argName);
return {
name: argName,
type: arg.type,
defaultValue: arg.defaultValue === undefined ? null : arg.defaultValue
};
});
}
});
return fieldMap;
}
/**
* Update the interfaces to know about this implementation.
* This is an rare and unfortunate use of mutation in the type definition
* implementations, but avoids an expensive "getPossibleTypes"
* implementation for Interface types.
*/
function addImplementationToInterfaces(impl) {
impl.getInterfaces().forEach(function (type) {
type._implementations.push(impl);
});
}
/**
* Interface Type Definition
*
* When a field can return one of a heterogeneous set of types, a Interface type
* is used to describe what types are possible, what fields are in common across
* all types, as well as a function to determine which type is actually used
* when the field is resolved.
*
* Example:
*
* var EntityType = new GraphQLInterfaceType({
* name: 'Entity',
* fields: {
* name: { type: GraphQLString }
* }
* });
*
*/
var GraphQLInterfaceType = (function () {
function GraphQLInterfaceType(config) {
_classCallCheck(this, GraphQLInterfaceType);
(0, _utilsInvariant2['default'])(config.name, 'Type must be named.');
this.name = config.name;
this.description = config.description;
this._typeConfig = config;
this._implementations = [];
}
_createClass(GraphQLInterfaceType, [{
key: 'getFields',
value: function getFields() {
return this._fields || (this._fields = defineFieldMap(this._typeConfig.fields));
}
}, {
key: 'getPossibleTypes',
value: function getPossibleTypes() {
return this._implementations;
}
}, {
key: 'isPossibleType',
value: function isPossibleType(type) {
var possibleTypeNames = this._possibleTypeNames;
if (!possibleTypeNames) {
this._possibleTypeNames = possibleTypeNames = this.getPossibleTypes().reduce(function (map, possibleType) {
return (map[possibleType.name] = true, map);
}, {});
}
return possibleTypeNames[type.name] === true;
}
}, {
key: 'resolveType',
value: function resolveType(value) {
var resolver = this._typeConfig.resolveType;
return resolver ? resolver(value) : getTypeOf(value, this);
}
}, {
key: 'toString',
value: function toString() {
return this.name;
}
}]);
return GraphQLInterfaceType;
})();
exports.GraphQLInterfaceType = GraphQLInterfaceType;
function getTypeOf(value, abstractType) {
var possibleTypes = abstractType.getPossibleTypes();
for (var i = 0; i < possibleTypes.length; i++) {
var type = possibleTypes[i];
var isTypeOf = type.isTypeOf(value);
if (isTypeOf === undefined) {
// TODO: move this to a JS impl specific type system validation step
// so the error can be found before execution.
throw new Error('Non-Object Type ' + abstractType.name + ' does not implement ' + 'resolveType and Object Type ' + type.name + ' does not implement ' + 'isTypeOf. There is no way to determine if a value is of this type.');
}
if (isTypeOf) {
return type;
}
}
}
/**
* Union Type Definition
*
* When a field can return one of a heterogeneous set of types, a Union type
* is used to describe what types are possible as well as providing a function
* to determine which type is actually used when the field is resolved.
*
* Example:
*
* var PetType = new GraphQLUnionType({
* name: 'Pet',
* types: [ DogType, CatType ],
* resolveType(value) {
* if (value instanceof Dog) {
* return DogType;
* }
* if (value instanceof Cat) {
* return CatType;
* }
* }
* });
*
*/
var GraphQLUnionType = (function () {
function GraphQLUnionType(config) {
_classCallCheck(this, GraphQLUnionType);
(0, _utilsInvariant2['default'])(config.name, 'Type must be named.');
this.name = config.name;
this.description = config.description;
(0, _utilsInvariant2['default'])(config.types && config.types.length, 'Must provide types for Union ' + config.name + '.');
if (!config.types.every(function (x) {
return x instanceof GraphQLObjectType;
})) {
var nonObjectTypes = config.types.filter(function (x) {
return !(x instanceof GraphQLObjectType);
});
throw new Error('Union ' + config.name + ' may only contain object types, it cannot ' + ('contain: ' + nonObjectTypes.join(', ') + '.'));
}
this._types = config.types;
this._typeConfig = config;
}
_createClass(GraphQLUnionType, [{
key: 'getPossibleTypes',
value: function getPossibleTypes() {
return this._types;
}
}, {
key: 'isPossibleType',
value: function isPossibleType(type) {
var possibleTypeNames = this._possibleTypeNames;
if (!possibleTypeNames) {
this._possibleTypeNames = possibleTypeNames = this.getPossibleTypes().reduce(function (map, possibleType) {
return (map[possibleType.name] = true, map);
}, {});
}
return possibleTypeNames[type.name] === true;
}
}, {
key: 'resolveType',
value: function resolveType(value) {
var resolver = this._typeConfig.resolveType;
return resolver ? resolver(value) : getTypeOf(value, this);
}
}, {
key: 'toString',
value: function toString() {
return this.name;
}
}]);
return GraphQLUnionType;
})();
exports.GraphQLUnionType = GraphQLUnionType;
/**
* Enum Type Definition
*
* Some leaf values of requests and input values are Enums. GraphQL serializes
* Enum values as strings, however internally Enums can be represented by any
* kind of type, often integers.
*
* Example:
*
* var RGBType = new GraphQLEnumType({
* name: 'RGB',
* values: {
* RED: { value: 0 },
* GREEN: { value: 1 },
* BLUE: { value: 2 }
* }
* });
*
* Note: If a value is not provided in a definition, the name of the enum value
* will be used as it's internal value.
*/
var GraphQLEnumType = (function () {
function GraphQLEnumType(config) {
_classCallCheck(this, GraphQLEnumType);
this.name = config.name;
this.description = config.description;
this._enumConfig = config;
}
_createClass(GraphQLEnumType, [{
key: 'getValues',
value: function getValues() /*<T>*/{
return this._values || (this._values = this._defineValueMap());
}
}, {
key: 'coerce',
value: function coerce(value) {
var enumValue = this._getValueLookup().get(value);
return enumValue ? enumValue.name : null;
}
}, {
key: 'coerceLiteral',
value: function coerceLiteral(value) /*T*/{
if (value.kind === _languageKinds.ENUM) {
var enumValue = this._getNameLookup().get(value.value);
if (enumValue) {
return enumValue.value;
}
}
}
}, {
key: '_defineValueMap',
value: function _defineValueMap() /*<T>*/{
var valueMap = this._enumConfig.values;
_Object$keys(valueMap).forEach(function (valueName) {
var value = valueMap[valueName];
value.name = valueName;
if (!value.hasOwnProperty('value')) {
value.value = valueName;
}
});
return valueMap;
}
}, {
key: '_getValueLookup',
value: function _getValueLookup() {
if (!this._valueLookup) {
var lookup = new _Map();
var values = this.getValues();
_Object$keys(values).forEach(function (valueName) {
var value = values[valueName];
lookup.set(value.value, value);
});
this._valueLookup = lookup;
}
return this._valueLookup;
}
}, {
key: '_getNameLookup',
value: function _getNameLookup() {
if (!this._nameLookup) {
var lookup = new _Map();
var values = this.getValues();
_Object$keys(values).forEach(function (valueName) {
var value = values[valueName];
lookup.set(value.name, value);
});
this._nameLookup = lookup;
}
return this._nameLookup;
}
}, {
key: 'toString',
value: function toString() {
return this.name;
}
}]);
return GraphQLEnumType;
})();
exports.GraphQLEnumType = GraphQLEnumType;
/**
* Input Object Type Definition
*
* An input object defines a structured collection of fields which may be
* supplied to a field argument.
*
* Using `NonNull` will ensure that a value must be provided by the query
*
* Example:
*
* var GeoPoint = new GraphQLInputObjectType({
* name: 'GeoPoint',
* fields: {
* lat: { type: new GraphQLNonNull(GraphQLFloat) },
* lon: { type: new GraphQLNonNull(GraphQLFloat) },
* alt: { type: GraphQLFloat, defaultValue: 0 },
* }
* });
*
*/
var GraphQLInputObjectType = (function () {
function GraphQLInputObjectType(config) {
_classCallCheck(this, GraphQLInputObjectType);
(0, _utilsInvariant2['default'])(config.name, 'Type must be named.');
this.name = config.name;
this.description = config.description;
this._typeConfig = config;
}
_createClass(GraphQLInputObjectType, [{
key: 'getFields',
value: function getFields() {
return this._fields || (this._fields = this._defineFieldMap());
}
}, {
key: '_defineFieldMap',
value: function _defineFieldMap() {
var fields = this._typeConfig.fields;
var fieldMap = typeof fields === 'function' ? fields() : fields;
_Object$keys(fieldMap).forEach(function (fieldName) {
var field = fieldMap[fieldName];
field.name = fieldName;
});
return fieldMap;
}
}, {
key: 'toString',
value: function toString() {
return this.name;
}
}]);
return GraphQLInputObjectType;
})();
exports.GraphQLInputObjectType = GraphQLInputObjectType;
/**
* List Modifier
*
* A list is a kind of type marker, a wrapping type which points to another
* type. Lists are often created within the context of defining the fields of
* an object type.
*
* Example:
*
* var PersonType = new GraphQLObjectType({
* name: 'Person',
* fields: () => ({
* parents: { type: new GraphQLList(Person) },
* children: { type: new GraphQLList(Person) },
* })
* })
*
*/
var GraphQLList = (function () {
function GraphQLList(type) {
_classCallCheck(this, GraphQLList);
this.ofType = type;
}
_createClass(GraphQLList, [{
key: 'toString',
value: function toString() {
return '[' + this.ofType.toString() + ']';
}
}]);
return GraphQLList;
})();
exports.GraphQLList = GraphQLList;
/**
* Non-Null Modifier
*
* A non-null is a kind of type marker, a wrapping type which points to another
* type. Non-null types enforce that their values are never null and can ensure
* an error is raised if this ever occurs during a request. It is useful for
* fields which you can make a strong guarantee on non-nullability, for example
* usually the id field of a database row will never be null.
*
* Example:
*
* var RowType = new GraphQLObjectType({
* name: 'Row',
* fields: () => ({
* id: { type: new GraphQLNonNull(String) },
* })
* })
*
* Note: the enforcement of non-nullability occurs within the executor.
*/
var GraphQLNonNull = (function () {
function GraphQLNonNull(type) {
_classCallCheck(this, GraphQLNonNull);
(0, _utilsInvariant2['default'])(!(type instanceof GraphQLNonNull), 'Cannot nest NonNull inside NonNull.');
this.ofType = type;
}
_createClass(GraphQLNonNull, [{
key: 'toString',
value: function toString() {
return this.ofType.toString() + '!';
}
}]);
return GraphQLNonNull;
})();
exports.GraphQLNonNull = GraphQLNonNull;
/*<T>*/ /*<T>*/ /*<T>*/ /*<T>*/ /*T*/ /*T*/
/**
* Optionally provide a custom type resolver function. If one is not provided,
* the default implemenation will call `isTypeOf` on each implementing
* Object type.
*/
/**
* Optionally provide a custom type resolver function. If one is not provided,
* the default implemenation will call `isTypeOf` on each implementing
* Object type.
*/
/*<T>*/ /*<T>*/ /*<T>*/ /*T*/ /*<T>*/ /*T*/ /*T*/ /*<T>*/ /*<T>*/ /*<T>*/ /*<T>*/ /*<T>*/ /*T*/ /*<T>*/ /*<T>*/ /*<T>*/ /*T*/