Skip to content

Commit

Permalink
Merge pull request #953 from apollographql/hwillson/issue-945
Browse files Browse the repository at this point in the history
Update to `graphql-js` 14.x
  • Loading branch information
hwillson authored Sep 19, 2018
2 parents bf66e96 + 6c0f429 commit b85137b
Show file tree
Hide file tree
Showing 22 changed files with 327 additions and 407 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
language: node_js
node_js:
- "4"
- "6"
- "8"
- "10"

install:
- npm config set spin=false
Expand All @@ -20,4 +20,4 @@ script:
sudo: false

env:
- GRAPHQL_VERSION='^0.13'
- GRAPHQL_VERSION='^14.0'
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
{
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.rulers": [110],
"editor.rulers": [80],
"editor.wordWrapColumn": 110,
"prettier.semi": true,
"files.trimTrailingWhitespace": true,
Expand Down
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@

### 4.0.0

* Support `graphql` and `@types/graphql` 14.x. <br />
[@hwillson](https://github.com/hwillson) in [#953](https://github.com/apollographql/graphql-tools/pull/953)
* Fix template strings usage in guessSchemaByRootField error message. <br/>
[@nagelflorian](https://github.com/nagelflorian) in [#936](https://github.com/apollographql/graphql-tools/pull/936)
* Update `IFieldResolver` to allow typed input args. <br/>
[@luk3thomas](https://github.com/luk3thomas) in [#932](https://github.com/apollographql/graphql-tools/pull/932)
* Changes to `extractExtensionDefinitions` to properly support `graphql-js` input extensions. <br/>
[@jure](https://github.com/jure) in [#948](https://github.com/apollographql/graphql-tools/pull/948)
* Stop automatically shallow cloning (via object spread syntax) transformed subscription results. Transformed subscription results are not always objects, which means object spreading can lead to invalid results. <br/>
[@ericlewis](https://github.com/ericlewis) in [#928](https://github.com/apollographql/graphql-tools/pull/928)
[@ericlewis](https://github.com/ericlewis) in [#928](https://github.com/apollographql/graphql-tools/pull/928)
* Re-use errors with an `extensions` property to make compatible with Apollo Server and it's built-in errors. <br/>
[@edorsey](https://github.com/edorsey) in [#925](https://github.com/apollographql/graphql-tools/pull/925)
* Documentation updates. <br/>
Expand Down
15 changes: 8 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "graphql-tools",
"version": "3.1.1",
"version": "4.0.0",
"description": "Useful tools to create and manipulate GraphQL schemas.",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
Expand All @@ -20,6 +20,7 @@
"lint": "tslint src/**/*.ts",
"watch": "tsc -w",
"testonly": "mocha --reporter spec --full-trace ./dist/test/tests.js",
"testonly:watch": "mocha -w --reporter spec --full-trace ./dist/test/tests.js",
"coverage": "istanbul cover _mocha -- --reporter dot --full-trace ./dist/test/tests.js",
"postcoverage": "remap-istanbul --input coverage/coverage.json --type lcovonly --output coverage/lcov.info",
"prepublishOnly": "npm run compile",
Expand Down Expand Up @@ -48,19 +49,19 @@
},
"homepage": "https://github.com/apollostack/graphql-tools#readme",
"dependencies": {
"apollo-link": "^1.2.2",
"apollo-link": "^1.2.3",
"apollo-utilities": "^1.0.1",
"deprecated-decorator": "^0.1.6",
"iterall": "^1.1.3",
"uuid": "^3.1.0"
},
"peerDependencies": {
"graphql": "^0.13.0"
"graphql": "^0.13.0 || ^14.0.0"
},
"devDependencies": {
"@types/chai": "4.0.10",
"@types/graphql": "0.12.5",
"@types/dateformat": "^1.0.1",
"@types/graphql": "14.0.0",
"@types/mocha": "^2.2.44",
"@types/node": "^8.0.47",
"@types/uuid": "^3.4.3",
Expand All @@ -69,8 +70,8 @@
"chai": "^4.1.2",
"dateformat": "^3.0.3",
"express": "^4.16.2",
"graphql": "^0.13.0",
"graphql-subscriptions": "^0.5.7",
"graphql": "^14.0.2",
"graphql-subscriptions": "^1.0.0",
"graphql-type-json": "^0.1.4",
"istanbul": "^0.4.5",
"mocha": "^4.0.1",
Expand All @@ -79,6 +80,6 @@
"rimraf": "^2.6.2",
"source-map-support": "^0.5.0",
"tslint": "^5.8.0",
"typescript": "2.6.2"
"typescript": "3.0.3"
}
}
31 changes: 29 additions & 2 deletions src/generate/addResolveFunctionsToSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ import {
IResolverValidationOptions,
IAddResolveFunctionsToSchemaOptions,
} from '../Interfaces';

import { applySchemaTransforms } from '../transforms/transforms';
import { checkForResolveTypeResolver, extendResolversFromInterfaces } from '.';
import ConvertEnumValues from '../transforms/ConvertEnumValues';

function addResolveFunctionsToSchema(
options: IAddResolveFunctionsToSchemaOptions | GraphQLSchema,
Expand Down Expand Up @@ -51,6 +52,10 @@ function addResolveFunctionsToSchema(
? extendResolversFromInterfaces(schema, inputResolvers)
: inputResolvers;

// Used to map the external value of an enum to its internal value, when
// that internal value is provided by a resolver.
const enumValueMap = Object.create(null);

Object.keys(resolvers).forEach(typeName => {
const resolverValue = resolvers[typeName];
const resolverType = typeof resolverValue;
Expand All @@ -63,6 +68,7 @@ function addResolveFunctionsToSchema(
}

const type = schema.getType(typeName);

if (!type && typeName !== '__schema') {
if (allowResolversNotInSchema) {
return;
Expand Down Expand Up @@ -95,7 +101,18 @@ function addResolveFunctionsToSchema(
);
}

type.getValue(fieldName)['value'] = resolverValue[fieldName];
// We've encountered an enum resolver that is being used to provide an
// internal enum value.
// Reference: https://www.apollographql.com/docs/graphql-tools/scalars.html#internal-values
//
// We're storing a map of the current enums external facing value to
// its resolver provided internal value. This map is used to transform
// the current schema to a new schema that includes enums with the new
// internal value.
enumValueMap[type.name] = {
[fieldName]: resolverValue[fieldName],
};

return;
}

Expand Down Expand Up @@ -137,6 +154,16 @@ function addResolveFunctionsToSchema(
});

checkForResolveTypeResolver(schema, requireResolversForResolveType);

// If there are any enum resolver functions (that are used to return
// internal enum values), create a new schema that includes enums with the
// new internal facing values.
const updatedSchema = applySchemaTransforms(
schema,
[new ConvertEnumValues(enumValueMap)],
);

return updatedSchema;
}

function getFieldsForType(type: GraphQLType): GraphQLFieldMap<any, any> {
Expand Down
4 changes: 2 additions & 2 deletions src/makeExecutableSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ export function makeExecutableSchema<TContext = any>({

// Arguments are now validated and cleaned up

const schema = buildSchemaFromTypeDefinitions(typeDefs, parseOptions);
let schema = buildSchemaFromTypeDefinitions(typeDefs, parseOptions);

addResolveFunctionsToSchema({
schema = addResolveFunctionsToSchema({
schema,
resolvers: resolverMap,
resolverValidationOptions,
Expand Down
8 changes: 6 additions & 2 deletions src/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
getNamedType,
GraphQLNamedType,
GraphQLFieldResolver,
GraphQLNonNull,
} from 'graphql';
import * as uuid from 'uuid';
import {
Expand Down Expand Up @@ -140,7 +141,10 @@ function addMockFunctionsToSchema({
return result;
}

if (fieldType instanceof GraphQLList) {
if (
fieldType instanceof GraphQLList ||
fieldType instanceof GraphQLNonNull
) {
return [
mockType(fieldType.ofType)(root, args, context, info),
mockType(fieldType.ofType)(root, args, context, info),
Expand Down Expand Up @@ -297,7 +301,7 @@ function isObject(thing: any) {
}

// returns a random element from that ary
function getRandomElement(ary: any[]) {
function getRandomElement(ary: ReadonlyArray<any>) {
const sample = Math.floor(Math.random() * ary.length);
return ary[sample];
}
Expand Down
16 changes: 8 additions & 8 deletions src/schemaVisitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ export function healSchema(schema: GraphQLSchema) {
});

// Directive declaration argument types can refer to named types.
each(type.getDirectives(), decl => {
each(type.getDirectives(), (decl: GraphQLDirective) => {
if (decl.args) {
each(decl.args, arg => {
arg.type = healType(arg.type);
Expand Down Expand Up @@ -399,11 +399,11 @@ export function healSchema(schema: GraphQLSchema) {
}

function healType<T extends GraphQLType>(type: T): T {
if (type instanceof GraphQLList ||
type instanceof GraphQLNonNull) {
// Unwrap the two known wrapper types:
// https://github.com/graphql/graphql-js/blob/master/src/type/wrappers.js
type.ofType = healType(type.ofType);
// Unwrap the two known wrapper types
if (type instanceof GraphQLList) {
type = new GraphQLList(healType(type.ofType)) as T;
} else if (type instanceof GraphQLNonNull) {
type = new GraphQLNonNull(healType(type.ofType)) as T;
} else if (isNamedType(type)) {
// If a type annotation on a field or an argument or a union member is
// any `GraphQLNamedType` with a `name`, then it must end up identical
Expand Down Expand Up @@ -620,7 +620,7 @@ export class SchemaDirectiveVisitor extends SchemaVisitor {
[directiveName: string]: GraphQLDirective,
} = Object.create(null);

each(schema.getDirectives(), decl => {
each(schema.getDirectives(), (decl: GraphQLDirective) => {
declaredDirectives[decl.name] = decl;
});

Expand Down Expand Up @@ -689,7 +689,7 @@ function directiveLocationToVisitorMethodName(loc: DirectiveLocationEnum) {
});
}

type IndexedObject<V> = { [key: string]: V } | V[];
type IndexedObject<V> = { [key: string]: V } | ReadonlyArray<V>;

function each<V>(
arrayOrObject: IndexedObject<V>,
Expand Down
4 changes: 2 additions & 2 deletions src/stitching/delegateToSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ async function delegateToSchemaImplementation(
function createDocument(
targetField: string,
targetOperation: Operation,
originalSelections: Array<SelectionNode>,
originalSelections: ReadonlyArray<SelectionNode>,
fragments: Array<FragmentDefinitionNode>,
variables: Array<VariableDefinitionNode>,
variables: ReadonlyArray<VariableDefinitionNode>,
operationName: NameNode,
): DocumentNode {
let selections: Array<SelectionNode> = [];
Expand Down
19 changes: 12 additions & 7 deletions src/stitching/errors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { GraphQLResolveInfo, responsePathAsArray, ExecutionResult, GraphQLFormattedError } from 'graphql';
import {
GraphQLResolveInfo,
responsePathAsArray,
ExecutionResult,
GraphQLFormattedError,
GraphQLError,
} from 'graphql';
import { locatedError } from 'graphql/error';
import { getResponseKeyFromInfo } from './getResponseKeyFromInfo';

Expand All @@ -12,7 +18,7 @@ if (
ERROR_SYMBOL = '@@__subSchemaErrors';
}

export function annotateWithChildrenErrors(object: any, childrenErrors: Array<GraphQLFormattedError>): any {
export function annotateWithChildrenErrors(object: any, childrenErrors: ReadonlyArray<GraphQLFormattedError>): any {
if (!childrenErrors || childrenErrors.length === 0) {
// Nothing to see here, move along
return object;
Expand Down Expand Up @@ -79,8 +85,8 @@ export function getErrorsFromParent(
}

class CombinedError extends Error {
public errors: Error[];
constructor(message: string, errors: Error[]) {
public errors: ReadonlyArray<GraphQLError>;
constructor(message: string, errors: ReadonlyArray<GraphQLError>) {
super(message);
this.errors = errors;
}
Expand All @@ -103,18 +109,17 @@ export function checkResultAndHandleErrors(
result.errors.length === 1 && hasResult(result.errors[0])
? result.errors[0]
: new CombinedError(concatErrors(result.errors), result.errors);

throw locatedError(newError, info.fieldNodes, responsePathAsArray(info.path));
}

let resultObject = result.data[responseKey];
if (result.errors) {
resultObject = annotateWithChildrenErrors(resultObject, result.errors as Array<GraphQLFormattedError>);
resultObject = annotateWithChildrenErrors(resultObject, result.errors as ReadonlyArray<GraphQLFormattedError>);
}
return resultObject;
}

function concatErrors(errors: Error[]) {
function concatErrors(errors: ReadonlyArray<GraphQLError>) {
return errors.map(error => error.message).join('\n');
}

Expand Down
2 changes: 1 addition & 1 deletion src/stitching/mergeSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ function mergeSchemasImplementation({
});
});

addResolveFunctionsToSchema({
mergedSchema = addResolveFunctionsToSchema({
schema: mergedSchema,
resolvers: mergeDeep(generatedResolvers, resolvers),
inheritResolversFromInterfaces
Expand Down
3 changes: 2 additions & 1 deletion src/stitching/schemaRecreation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,10 @@ export function recreateType(
const newValues = {};
values.forEach(value => {
newValues[value.name] = {
value: value.name,
value: value.value,
deprecationReason: value.deprecationReason,
description: value.description,
astNode: value.astNode,
};
});
return new GraphQLEnumType({
Expand Down
4 changes: 2 additions & 2 deletions src/stitching/typeFromAST.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ function makeInputObjectType(
});
}

function makeFields(nodes: Array<FieldDefinitionNode>) {
function makeFields(nodes: ReadonlyArray<FieldDefinitionNode>) {
const result = {};
nodes.forEach(node => {
result[node.name.value] = {
Expand All @@ -151,7 +151,7 @@ function makeFields(nodes: Array<FieldDefinitionNode>) {
return result;
}

function makeValues(nodes: Array<InputValueDefinitionNode>) {
function makeValues(nodes: ReadonlyArray<InputValueDefinitionNode>) {
const result = {};
nodes.forEach(node => {
const type = resolveType(node.type, 'input') as GraphQLInputType;
Expand Down
Loading

0 comments on commit b85137b

Please sign in to comment.