UNPKG

graphql

Version:

A Query Language and Runtime which can target any service.

694 lines (614 loc) 19.4 kB
/* @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*/