Skip to content

Commit

Permalink
Merge branch 'master' into greenkeeper-tslint-4.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Sashko Stubailo committed Jan 5, 2017
2 parents 0015570 + 6997b7b commit e54f49c
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 103 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Expand Up @@ -4,6 +4,10 @@

* ...

### v0.9.0

* Migrate from `typed-graphql` to `@types/graphql`. [PR #249](https://github.com/apollostack/graphql-tools/pull/249)

### v0.8.4

* `addSchemaLevelResolveFunction` resolves once per operation type and not once globally. [#220](https://github.com/apollostack/graphql-tools/pull/220)
Expand Down
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -96,6 +96,7 @@ At the end, the schema and resolvers are combined using `makeExecutableSchema`:
```js
import schema from './data/schema.js';
import resolverMap from './data/resolvers';
import { makeExecutableSchema } from 'graphql-tools';

const executableSchema = makeExecutableSchema({
typeDefs: schema,
Expand Down
4 changes: 2 additions & 2 deletions package.json
@@ -1,6 +1,6 @@
{
"name": "graphql-tools",
"version": "0.8.4",
"version": "0.9.0",
"description": "A set of useful tools for GraphQL",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
Expand Down Expand Up @@ -55,7 +55,7 @@
"graphql": "^0.5.0 || ^0.6.0 || ^0.7.0 || ^0.8.0"
},
"optionalDependencies": {
"typed-graphql": "^1.0.2"
"@types/graphql": "^0.8.5"
},
"devDependencies": {
"@types/bluebird": "^3.0.32",
Expand Down
24 changes: 12 additions & 12 deletions src/Interfaces.ts
@@ -1,11 +1,11 @@
import {
GraphQLSchema,
GraphQLFieldDefinition,
GraphQLResult,
GraphQLField,
ExecutionResult,
GraphQLType,
GraphQLFieldResolveFn,
GraphQLFieldResolver,
GraphQLIsTypeOfFn,
GraphQLTypeResolveFn,
GraphQLTypeResolver,
GraphQLScalarType,
} from 'graphql';

Expand All @@ -18,14 +18,14 @@ export interface IResolverValidationOptions {
}

export interface IResolverOptions {
resolve?: GraphQLFieldResolveFn;
__resolveType?: GraphQLTypeResolveFn;
__isTypeOf?: GraphQLIsTypeOfFn;
resolve?: GraphQLFieldResolver<any, any>;
__resolveType?: GraphQLTypeResolver<any, any>;
__isTypeOf?: GraphQLIsTypeOfFn<any, any>;
};

export type ITypedef = (() => ITypedef[]) | string;
export type ITypeDefinitions = ITypedef | ITypedef[];
export type IResolverObject = { [key: string]: GraphQLFieldResolveFn | IResolverOptions };
export type IResolverObject = { [key: string]: GraphQLFieldResolver<any, any> | IResolverOptions };
export interface IResolvers {
[key: string]: (() => any) | IResolverObject | GraphQLScalarType;
};
Expand All @@ -50,12 +50,12 @@ export interface IExecutableSchemaDefinition {
resolverValidationOptions?: IResolverValidationOptions;
}

export type IFieldIteratorFn = (fieldDef: GraphQLFieldDefinition, typeName: string, fieldName: string) => void;
export type IFieldIteratorFn = (fieldDef: GraphQLField<any, any>, typeName: string, fieldName: string) => void;

/* XXX on mocks, args are optional, Not sure if a bug. */
export type IMockFn = GraphQLFieldResolveFn;
export type IMockFn = GraphQLFieldResolver<any, any>;
export type IMocks = { [key: string]: IMockFn };
export type IMockTypeFn = (type: GraphQLType, typeName?: string, fieldName?: string) => GraphQLFieldResolveFn;
export type IMockTypeFn = (type: GraphQLType, typeName?: string, fieldName?: string) => GraphQLFieldResolver<any, any>;

export interface IMockOptions {
schema: GraphQLSchema;
Expand All @@ -64,5 +64,5 @@ export interface IMockOptions {
}

export interface IMockServer {
query: (query: string, vars?: { [key: string]: any }) => Promise<GraphQLResult>;
query: (query: string, vars?: { [key: string]: any }) => Promise<ExecutionResult>;
}
3 changes: 1 addition & 2 deletions src/autopublish.ts
@@ -1,6 +1,5 @@
import {
GraphQLSchema,
GraphQLFieldDefinition,
GraphQLResolveInfo,
} from 'graphql';
import { PubSub } from 'graphql-subscriptions';
Expand All @@ -10,7 +9,7 @@ export function autopublishMutationResults(schema: GraphQLSchema, pubsub: PubSub
// decorate the mutations with your thingy
const mutationFields = schema.getMutationType().getFields();
Object.keys(mutationFields).forEach( fieldName => {
const field = mutationFields[fieldName] as GraphQLFieldDefinition;
const field = mutationFields[fieldName];

// define the function
const publishMutatedValue = (
Expand Down
22 changes: 11 additions & 11 deletions src/mock.ts
Expand Up @@ -6,12 +6,12 @@ import {
GraphQLInterfaceType,
GraphQLList,
GraphQLType,
GraphQLFieldDefinition,
GraphQLField,
GraphQLResolveInfo,
getNullableType,
getNamedType,
GraphQLNamedType,
GraphQLFieldResolveFn,
GraphQLFieldResolver,
} from 'graphql';
import { graphql } from 'graphql';
import * as uuid from 'uuid';
Expand Down Expand Up @@ -140,7 +140,7 @@ function addMockFunctionsToSchema({ schema, mocks = {}, preserveResolvers = fals
}
}

const mockType = function mockType(type: GraphQLType, typeName?: string, fieldName?: string): GraphQLFieldResolveFn {
const mockType = function mockType(type: GraphQLType, typeName?: string, fieldName?: string): GraphQLFieldResolver<any, any> {
// order of precendence for mocking:
// 1. if the object passed in already has fieldName, just use that
// --> if it's a function, that becomes your resolver
Expand All @@ -160,7 +160,7 @@ function addMockFunctionsToSchema({ schema, mocks = {}, preserveResolvers = fals
if (typeof root[fieldName] === 'function') {
result = root[fieldName](root, args, context, info);
if (result instanceof MockList) {
result = result.mock(root, args, context, info, fieldType as GraphQLList, mockType);
result = result.mock(root, args, context, info, fieldType as GraphQLList<any>, mockType);
}
} else {
result = root[fieldName];
Expand Down Expand Up @@ -217,13 +217,13 @@ function addMockFunctionsToSchema({ schema, mocks = {}, preserveResolvers = fals
};
};

forEachField(schema, (field: GraphQLFieldDefinition, typeName: string, fieldName: string) => {
forEachField(schema, (field: GraphQLField<any, any>, typeName: string, fieldName: string) => {
assignResolveType(field.type);
let mockResolver: GraphQLFieldResolveFn;
let mockResolver: GraphQLFieldResolver<any, any>;

// we have to handle the root mutation and root query types differently,
// because no resolver is called at the root.
/* istanbul ignore next: Must provide schema definition with query type or a type named Query. */
/* istanbul ignore next: Must provide schema DefinitionNode with query type or a type named Query. */
const isOnQueryType: boolean = schema.getQueryType() ? (schema.getQueryType().name === typeName) : false;
const isOnMutationType: boolean = schema.getMutationType() ? (schema.getMutationType().name === typeName) : false;

Expand Down Expand Up @@ -285,10 +285,10 @@ function addMockFunctionsToSchema({ schema, mocks = {}, preserveResolvers = fals

class MockList {
private len: number | number[];
private wrappedFunction: GraphQLFieldResolveFn;
private wrappedFunction: GraphQLFieldResolver<any, any>;

// wrappedFunction can return another MockList or a value
constructor(len: number | number[], wrappedFunction?: GraphQLFieldResolveFn) {
constructor(len: number | number[], wrappedFunction?: GraphQLFieldResolver<any, any>) {
this.len = len;
if (typeof wrappedFunction !== 'undefined') {
if (typeof wrappedFunction !== 'function') {
Expand All @@ -302,7 +302,7 @@ class MockList {
args: { [key: string]: any },
context: any,
info: GraphQLResolveInfo,
fieldType: GraphQLList,
fieldType: GraphQLList<any>,
mockTypeFunc: IMockTypeFn) {
let arr: any[];
if (Array.isArray(this.len)) {
Expand All @@ -315,7 +315,7 @@ class MockList {
if (typeof this.wrappedFunction === 'function') {
const res = this.wrappedFunction(root, args, context, info);
if (res instanceof MockList) {
const nullableType = getNullableType(fieldType.ofType) as GraphQLList;
const nullableType = getNullableType(fieldType.ofType) as GraphQLList<any>;
arr[i] = res.mock(root, args, context, info, nullableType, mockTypeFunc);
} else {
arr[i] = res;
Expand Down
76 changes: 40 additions & 36 deletions src/schemaGenerator.ts
Expand Up @@ -6,7 +6,7 @@
// TODO: we should refactor this file, rename it to makeExecutableSchema, and move
// a bunch of utility functions into a separate utitlities folder, one file per function.

import { Document, parse, Kind, Definition } from 'graphql';
import { DocumentNode, parse, Kind, DefinitionNode } from 'graphql';
import { uniq } from 'lodash';
import { buildASTSchema, extendSchema } from 'graphql';
import {
Expand All @@ -15,11 +15,11 @@ import {
GraphQLObjectType,
GraphQLSchema,
GraphQLResolveInfo,
GraphQLFieldDefinition,
GraphQLFieldResolveFn,
GraphQLField,
GraphQLFieldResolver,
GraphQLType,
GraphQLInterfaceType,
GraphQLFieldDefinitionMap,
GraphQLFieldMap,
} from 'graphql';
import {
IExecutableSchemaDefinition ,
Expand Down Expand Up @@ -100,7 +100,7 @@ function makeExecutableSchema({
if (typeof resolvers['__schema'] === 'function') {
// TODO a bit of a hack now, better rewrite generateSchema to attach it there.
// not doing that now, because I'd have to rewrite a lot of tests.
addSchemaLevelResolveFunction(jsSchema, resolvers['__schema'] as GraphQLFieldResolveFn);
addSchemaLevelResolveFunction(jsSchema, resolvers['__schema'] as GraphQLFieldResolver<any, any>);
}
if (connectors) {
// connectors are optional, at least for now. That means you can just import them in the resolve
Expand Down Expand Up @@ -141,7 +141,7 @@ function buildSchemaFromTypeDefinitions(typeDefinitions: ITypeDefinitions): Grap
myDefinitions = concatenateTypeDefs(myDefinitions);
}

const astDocument: Document = parse(myDefinitions);
const astDocument: DocumentNode = parse(myDefinitions);
let schema: GraphQLSchema = buildASTSchema(astDocument);

const extensionsAst = extractExtensionDefinitions(astDocument);
Expand All @@ -152,9 +152,9 @@ function buildSchemaFromTypeDefinitions(typeDefinitions: ITypeDefinitions): Grap
return schema;
}

function extractExtensionDefinitions(ast: Document) {
function extractExtensionDefinitions(ast: DocumentNode) {
const extensionDefs =
ast.definitions.filter((def: Definition) => def.kind === Kind.TYPE_EXTENSION_DEFINITION);
ast.definitions.filter((def: DefinitionNode) => def.kind === Kind.TYPE_EXTENSION_DEFINITION);

return Object.assign({}, ast, {
definitions: extensionDefs,
Expand Down Expand Up @@ -212,32 +212,33 @@ const attachConnectorsToContext = deprecated<Function>({
throw new Error('Connectors already attached to context, cannot attach more than once');
}
schema['_apolloConnectorsAttached'] = true;
const attachconnectorFn: GraphQLFieldResolveFn = (root: any, args: { [key: string]: any }, ctx: any) => {
if (typeof ctx !== 'object') {
// if in any way possible, we should throw an error when the attachconnectors
// function is called, not when a query is executed.
const contextType = typeof ctx;
throw new Error(`Cannot attach connector because context is not an object: ${contextType}`);
}
if (typeof ctx.connectors === 'undefined') {
ctx.connectors = {};
}
Object.keys(connectors).forEach((connectorName) => {
let connector: IConnector = connectors[connectorName];
if ( !!connector.prototype ) {
ctx.connectors[connectorName] = new (<IConnectorCls> connector)(ctx);
} else {
throw new Error(`Connector must be a function or an class`);
const attachconnectorFn: GraphQLFieldResolver<any, any> =
(root: any, args: { [key: string]: any }, ctx: any) => {
if (typeof ctx !== 'object') {
// if in any way possible, we should throw an error when the attachconnectors
// function is called, not when a query is executed.
const contextType = typeof ctx;
throw new Error(`Cannot attach connector because context is not an object: ${contextType}`);
}
});
return root;
};
if (typeof ctx.connectors === 'undefined') {
ctx.connectors = {};
}
Object.keys(connectors).forEach((connectorName) => {
let connector: IConnector = connectors[connectorName];
if ( !!connector.prototype ) {
ctx.connectors[connectorName] = new (<IConnectorCls> connector)(ctx);
} else {
throw new Error(`Connector must be a function or an class`);
}
});
return root;
};
addSchemaLevelResolveFunction(schema, attachconnectorFn);
});

// wraps all resolve functions of query, mutation or subscription fields
// with the provided function to simulate a root schema level resolve funciton
function addSchemaLevelResolveFunction(schema: GraphQLSchema, fn: GraphQLFieldResolveFn): void {
function addSchemaLevelResolveFunction(schema: GraphQLSchema, fn: GraphQLFieldResolver<any, any>): void {
// TODO test that schema is a schema, fn is a function
const rootTypes = ([
schema.getQueryType(),
Expand All @@ -261,7 +262,7 @@ function addSchemaLevelResolveFunction(schema: GraphQLSchema, fn: GraphQLFieldRe
});
}

function getFieldsForType(type: GraphQLType): GraphQLFieldDefinitionMap {
function getFieldsForType(type: GraphQLType): GraphQLFieldMap<any, any> {
if ((type instanceof GraphQLObjectType) ||
(type instanceof GraphQLInterfaceType)) {
return type.getFields();
Expand Down Expand Up @@ -319,7 +320,7 @@ function addResolveFunctionsToSchema(schema: GraphQLSchema, resolveFunctions: IR
});
}

function setFieldProperties(field: GraphQLFieldDefinition, propertiesObj: Object) {
function setFieldProperties(field: GraphQLField<any, any>, propertiesObj: Object) {
Object.keys(propertiesObj).forEach((propertyName) => {
field[propertyName] = propertiesObj[propertyName];
});
Expand Down Expand Up @@ -358,7 +359,7 @@ function assertResolveFunctionsPresent(schema: GraphQLSchema, resolverValidation
});
}

function expectResolveFunction(field: GraphQLFieldDefinition, typeName: string, fieldName: string) {
function expectResolveFunction(field: GraphQLField<any, any>, typeName: string, fieldName: string) {
if (!field.resolve) {
// tslint:disable-next-line: max-line-length
console.warn(`Resolve function missing for "${typeName}.${fieldName}". To disable this warning check https://github.com/apollostack/graphql-tools/issues/131`);
Expand All @@ -383,7 +384,10 @@ function addErrorLoggingToSchema(schema: GraphQLSchema, logger: ILogger): void {
}

// XXX badly named function. this doesn't really wrap, it just chains resolvers...
function wrapResolver(innerResolver: GraphQLFieldResolveFn | undefined, outerResolver: GraphQLFieldResolveFn): GraphQLFieldResolveFn {
function wrapResolver(
innerResolver: GraphQLFieldResolver<any, any> | undefined,
outerResolver: GraphQLFieldResolver<any, any>,
): GraphQLFieldResolver<any, any> {
return (obj, args, ctx, info) => {
return Promise.resolve(outerResolver(obj, args, ctx, info)).then(root => {
if (innerResolver) {
Expand All @@ -394,7 +398,7 @@ function wrapResolver(innerResolver: GraphQLFieldResolveFn | undefined, outerRes
};
}

function chainResolvers(resolvers: GraphQLFieldResolveFn[]) {
function chainResolvers(resolvers: GraphQLFieldResolver<any, any>[]) {
return (root: any, args: {[argName: string]: any}, ctx: any, info: GraphQLResolveInfo) => {
return resolvers.reduce(
(prev, curResolver) => {
Expand All @@ -414,7 +418,7 @@ function chainResolvers(resolvers: GraphQLFieldResolveFn[]) {
* logger: an object instance of type Logger
* hint: an optional hint to add to the error's message
*/
function decorateWithLogger(fn: GraphQLFieldResolveFn | undefined, logger: ILogger, hint: string): GraphQLFieldResolveFn {
function decorateWithLogger(fn: GraphQLFieldResolver<any, any> | undefined, logger: ILogger, hint: string): GraphQLFieldResolver<any, any> {
if (typeof fn === 'undefined') {
fn = defaultResolveFn;
}
Expand Down Expand Up @@ -445,7 +449,7 @@ function addCatchUndefinedToSchema(schema: GraphQLSchema): void {
});
}

function decorateToCatchUndefined(fn: GraphQLFieldResolveFn, hint: string): GraphQLFieldResolveFn {
function decorateToCatchUndefined(fn: GraphQLFieldResolver<any, any>, hint: string): GraphQLFieldResolver<any, any> {
if (typeof fn === 'undefined') {
fn = defaultResolveFn;
}
Expand All @@ -464,7 +468,7 @@ function decorateToCatchUndefined(fn: GraphQLFieldResolveFn, hint: string): Grap
// if people don't actually cache the operation.
// if they do cache the operation, they will have to
// manually remove the __runAtMostOnce before every request.
function runAtMostOncePerRequest(fn: GraphQLFieldResolveFn): GraphQLFieldResolveFn {
function runAtMostOncePerRequest(fn: GraphQLFieldResolver<any, any>): GraphQLFieldResolver<any, any> {
let value: any;
const randomNumber = Math.random();
return (root, args, ctx, info) => {
Expand Down

0 comments on commit e54f49c

Please sign in to comment.