Skip to content

Commit

Permalink
fix: make getFieldTC to return *TypeComposer for any type (#181)
Browse files Browse the repository at this point in the history
* Make getFieldTC return TypeComposer for any type
* Fix typescript
  • Loading branch information
freiksenet authored and nodkz committed Apr 1, 2019
1 parent 457f668 commit e299fa3
Show file tree
Hide file tree
Showing 14 changed files with 309 additions and 138 deletions.
7 changes: 6 additions & 1 deletion src/InputTypeComposer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,12 @@ export class InputTypeComposer<TContext = any> {

public getFieldType(fieldName: string): GraphQLInputType;

public getFieldTC(fieldName: string): InputTypeComposer<TContext>;
public getFieldTC(
fieldName: string,
):
| InputTypeComposer<TContext>
| EnumTypeComposer<TContext>
| ScalarTypeComposer<TContext>;

public makeFieldNonNull(fieldNameOrArray: string | string[]): this;

Expand Down
21 changes: 15 additions & 6 deletions src/InputTypeComposer.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,9 @@ export class InputTypeComposer<TContext> {
} else {
childTC = this.getFieldTC(name);
}
childTC.addNestedFields({ [names.join('.')]: fc });
if (childTC instanceof InputTypeComposer) {
childTC.addNestedFields({ [names.join('.')]: fc });
}
}
});

Expand Down Expand Up @@ -353,15 +355,22 @@ export class InputTypeComposer<TContext> {
return this.getFieldConfig(fieldName).type;
}

getFieldTC(fieldName: string): InputTypeComposer<TContext> {
getFieldTC(
fieldName: string
): InputTypeComposer<TContext> | EnumTypeComposer<TContext> | ScalarTypeComposer<TContext> {
const fieldType = getNamedType(this.getFieldType(fieldName));
if (!(fieldType instanceof GraphQLInputObjectType)) {
const tc = this.schemaComposer.createTempTC(fieldType);
if (
tc instanceof InputTypeComposer ||
tc instanceof EnumTypeComposer ||
tc instanceof ScalarTypeComposer
) {
return tc;
} else {
throw new Error(
`Cannot get InputTypeComposer for field '${fieldName}' in type ${this.getTypeName()}. ` +
`This field should be InputObjectType, but it has type '${fieldType.constructor.name}'`
`Type ${this.getTypeName()} has invalid field ${fieldName} which is not of an input type.`
);
}
return InputTypeComposer.createTemp(fieldType, this.schemaComposer);
}

makeFieldNonNull(fieldNameOrArray: string | string[]): InputTypeComposer<TContext> {
Expand Down
13 changes: 12 additions & 1 deletion src/InterfaceTypeComposer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import {
ComposeFieldConfigAsObject,
ObjectTypeComposer,
} from './ObjectTypeComposer';
import { EnumTypeComposer } from './EnumTypeComposer';
import { UnionTypeComposer } from './UnionTypeComposer';
import { ScalarTypeComposer } from './ScalarTypeComposer';
import { TypeAsString } from './TypeMapper';
import { Thunk, MaybePromise, Extensions } from './utils/definitions';

Expand Down Expand Up @@ -119,7 +122,15 @@ export class InterfaceTypeComposer<TSource = any, TContext = any> {

public getFieldType(fieldName: string): GraphQLOutputType;

public getFieldTC(fieldName: string): ObjectTypeComposer<any, TContext>;
public getFieldTC(
fieldName: string,
):
| ObjectTypeComposer<TSource, TContext>
| InputTypeComposer<TContext>
| EnumTypeComposer<TContext>
| InterfaceTypeComposer<TSource, TContext>
| UnionTypeComposer<TSource, TContext>
| ScalarTypeComposer<TContext>;

public makeFieldNonNull(fieldNameOrArray: string | string[]): this;

Expand Down
21 changes: 13 additions & 8 deletions src/InterfaceTypeComposer.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ import type {
GraphQLTypeResolver,
} from './graphql';
import type { InputTypeComposer } from './InputTypeComposer';
import type { EnumTypeComposer } from './EnumTypeComposer';
import type { UnionTypeComposer } from './UnionTypeComposer';
import type { ScalarTypeComposer } from './ScalarTypeComposer';
import type { TypeAsString } from './TypeMapper';
import { SchemaComposer } from './SchemaComposer';
import type {
Expand Down Expand Up @@ -315,15 +318,17 @@ export class InterfaceTypeComposer<TSource, TContext> {
return this.getFieldConfig(fieldName).type;
}

getFieldTC(fieldName: string): ObjectTypeComposer<any, TContext> {
getFieldTC(
fieldName: string
):
| ObjectTypeComposer<TSource, TContext>
| InputTypeComposer<TContext>
| EnumTypeComposer<TContext>
| InterfaceTypeComposer<TSource, TContext>
| UnionTypeComposer<TSource, TContext>
| ScalarTypeComposer<TContext> {
const fieldType = getNamedType(this.getFieldType(fieldName));
if (!(fieldType instanceof GraphQLObjectType)) {
throw new Error(
`Cannot get ObjectTypeComposer for field '${fieldName}' in type ${this.getTypeName()}. ` +
`This field should be ObjectType, but it has type '${fieldType.constructor.name}'`
);
}
return ObjectTypeComposer.createTemp(fieldType, this.schemaComposer);
return this.schemaComposer.createTempTC(fieldType);
}

makeFieldNonNull(fieldNameOrArray: string | string[]): InterfaceTypeComposer<TSource, TContext> {
Expand Down
10 changes: 9 additions & 1 deletion src/ObjectTypeComposer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,15 @@ export class ObjectTypeComposer<TSource = any, TContext = any> {

public getFieldType(fieldName: string): GraphQLOutputType;

public getFieldTC(fieldName: string): ObjectTypeComposer<TSource, TContext>;
public getFieldTC(
fieldName: string,
):
| ObjectTypeComposer<TSource, TContext>
| InputTypeComposer<TContext>
| EnumTypeComposer<TContext>
| InterfaceTypeComposer<TSource, TContext>
| UnionTypeComposer<TSource, TContext>
| ScalarTypeComposer<TContext>;

public makeFieldNonNull(fieldNameOrArray: string | string[]): this;

Expand Down
22 changes: 13 additions & 9 deletions src/ObjectTypeComposer.js
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,9 @@ export class ObjectTypeComposer<TSource, TContext> {
} else {
childTC = this.getFieldTC(name);
}
childTC.addNestedFields({ [names.join('.')]: fc });
if (childTC instanceof ObjectTypeComposer) {
childTC.addNestedFields({ [names.join('.')]: fc });
}
}
});

Expand Down Expand Up @@ -486,15 +488,17 @@ export class ObjectTypeComposer<TSource, TContext> {
return this.getFieldConfig(fieldName).type;
}

getFieldTC(fieldName: string): ObjectTypeComposer<TSource, TContext> {
getFieldTC(
fieldName: string
):
| ObjectTypeComposer<TSource, TContext>
| InputTypeComposer<TContext>
| EnumTypeComposer<TContext>
| InterfaceTypeComposer<TSource, TContext>
| UnionTypeComposer<TSource, TContext>
| ScalarTypeComposer<TContext> {
const fieldType = getNamedType(this.getFieldType(fieldName));
if (!(fieldType instanceof GraphQLObjectType)) {
throw new Error(
`Cannot get ObjectTypeComposer for field '${fieldName}' in type ${this.getTypeName()}. ` +
`This field should be ObjectType, but it has type '${fieldType.constructor.name}'`
);
}
return ObjectTypeComposer.createTemp(fieldType, this.schemaComposer);
return this.schemaComposer.createTempTC(fieldType);
}

makeFieldNonNull(fieldNameOrArray: string | string[]): ObjectTypeComposer<TSource, TContext> {
Expand Down
10 changes: 10 additions & 0 deletions src/SchemaComposer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,16 @@ export class SchemaComposer<TContext> extends TypeStorage<any, any> {

public add(typeOrSDL: any): string | null;

public createTempTC(
typeOrSDL: any,
):
| ObjectTypeComposer<any, TContext>
| InputTypeComposer<TContext>
| EnumTypeComposer<TContext>
| InterfaceTypeComposer<any, TContext>
| UnionTypeComposer<any, TContext>
| ScalarTypeComposer<TContext>;

public addAsComposer(typeOrSDL: any): string;

public addTypeDefs(typeDefs: string): TypeStorage<string, GraphQLNamedType>;
Expand Down
32 changes: 22 additions & 10 deletions src/SchemaComposer.js
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,15 @@ export class SchemaComposer<TContext> extends TypeStorage<any, any> {
}
}

addAsComposer(typeOrSDL: mixed): string {
createTempTC(
typeOrSDL: mixed
):
| ObjectTypeComposer<any, TContext>
| InputTypeComposer<TContext>
| EnumTypeComposer<TContext>
| InterfaceTypeComposer<any, TContext>
| UnionTypeComposer<any, TContext>
| ScalarTypeComposer<TContext> {
let type;
if (typeof typeOrSDL === 'string') {
type = this.typeMapper.createType(typeOrSDL);
Expand All @@ -429,26 +437,30 @@ export class SchemaComposer<TContext> extends TypeStorage<any, any> {
type instanceof InterfaceTypeComposer ||
type instanceof UnionTypeComposer
) {
const name = type.getTypeName();
this.set(name, type);
return name;
return type;
} else if (type instanceof GraphQLObjectType) {
return ObjectTypeComposer.create(type, this).getTypeName();
return ObjectTypeComposer.createTemp(type, this);
} else if (type instanceof GraphQLInputObjectType) {
return InputTypeComposer.create(type, this).getTypeName();
return InputTypeComposer.createTemp(type, this);
} else if (type instanceof GraphQLScalarType) {
return ScalarTypeComposer.create(type, this).getTypeName();
return ScalarTypeComposer.createTemp(type, this);
} else if (type instanceof GraphQLEnumType) {
return EnumTypeComposer.create(type, this).getTypeName();
return EnumTypeComposer.createTemp(type, this);
} else if (type instanceof GraphQLInterfaceType) {
return InterfaceTypeComposer.create(type, this).getTypeName();
return InterfaceTypeComposer.createTemp(type, this);
} else if (type instanceof GraphQLUnionType) {
return UnionTypeComposer.create(type, this).getTypeName();
return UnionTypeComposer.createTemp(type, this);
}

throw new Error(`Cannot add as Composer type following value: ${inspect(type)}.`);
}

addAsComposer(typeOrSDL: mixed): string {
const composer = this.createTempTC(typeOrSDL);
this.set(composer.getTypeName(), composer);
return composer.getTypeName();
}

addTypeDefs(typeDefs: string): TypeStorage<string, GraphQLNamedType> {
const types = this.typeMapper.parseTypesFromString(typeDefs);
types.forEach((type: any) => {
Expand Down
58 changes: 37 additions & 21 deletions src/__tests__/InputTypeComposer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
} from '../graphql';
import { schemaComposer } from '..';
import { InputTypeComposer } from '../InputTypeComposer';
import { ScalarTypeComposer } from '../ScalarTypeComposer';
import { EnumTypeComposer } from '../EnumTypeComposer';
import { graphqlVersion } from '../utils/graphqlVersion';

beforeEach(() => {
Expand Down Expand Up @@ -120,13 +122,16 @@ describe('InputTypeComposer', () => {

expect(itc.getFieldType('fieldNested1')).toBeInstanceOf(GraphQLInputObjectType);
const fieldTC = itc.getFieldTC('fieldNested1');
expect(fieldTC.getTypeName()).toBe('InputTypeFieldNested1');
expect(fieldTC.getFieldType('f1')).toBe(GraphQLString);
expect(fieldTC.getFieldType('f2')).toBeInstanceOf(GraphQLNonNull);
expect((fieldTC.getFieldType('f2'): any).ofType).toBe(GraphQLBoolean);
expect(fieldTC).toBeInstanceOf(InputTypeComposer);
if (fieldTC instanceof InputTypeComposer) {
expect(fieldTC.getTypeName()).toBe('InputTypeFieldNested1');
expect(fieldTC.getFieldType('f1')).toBe(GraphQLString);
expect(fieldTC.getFieldType('f2')).toBeInstanceOf(GraphQLNonNull);
expect((fieldTC.getFieldType('f2'): any).ofType).toBe(GraphQLBoolean);

expect(itc.getFieldType('fieldNested2')).toBeInstanceOf(GraphQLList);
expect((itc.getFieldType('fieldNested2'): any).ofType).toBe(GraphQLInt);
expect(itc.getFieldType('fieldNested2')).toBeInstanceOf(GraphQLList);
expect((itc.getFieldType('fieldNested2'): any).ofType).toBe(GraphQLInt);
}
});

it('removeField()', () => {
Expand Down Expand Up @@ -453,28 +458,39 @@ describe('InputTypeComposer', () => {
myITC.addFields({
scalar: 'String',
list: '[Int]',
obj: schemaComposer.createInputTC(`input ICustomObjInputType { name: String }`),
objArr: [schemaComposer.createInputTC(`input ICustomObjInputType2 { name: String }`)],
obj: schemaComposer.createInputTC(`input MyInputType { name: String }`),
objArr: [schemaComposer.createInputTC(`input MyInputType2 { name: String }`)],
enum: EnumTypeComposer.create(`enum MyEnumType { FOO BAR }`, schemaComposer),
});

it('should return InputTypeComposer for object field', () => {
const objTC = myITC.getFieldTC('obj');
expect(objTC.getTypeName()).toBe('ICustomObjInputType');
it('should return TypeComposer for object field', () => {
const tco = myITC.getFieldTC('obj');
expect(tco).toBeInstanceOf(InputTypeComposer);
expect(tco.getTypeName()).toBe('MyInputType');
});

it('should return InputTypeComposer for wrapped object field', () => {
const objTC = myITC.getFieldTC('objArr');
expect(objTC.getTypeName()).toBe('ICustomObjInputType2');
it('should return TypeComposer for wrapped object field', () => {
const tco = myITC.getFieldTC('objArr');
expect(tco).toBeInstanceOf(InputTypeComposer);
expect(tco.getTypeName()).toBe('MyInputType2');
});

it('should throw error for non-object fields', () => {
expect(() => {
myITC.getFieldTC('scalar');
}).toThrow('field should be InputObjectType');
it('should return TypeComposer for scalar fields', () => {
const tco = myITC.getFieldTC('scalar');
expect(tco).toBeInstanceOf(ScalarTypeComposer);
expect(tco.getTypeName()).toBe('String');
});

it('should return TypeComposer for scalar list fields', () => {
const tco = myITC.getFieldTC('list');
expect(tco).toBeInstanceOf(ScalarTypeComposer);
expect(tco.getTypeName()).toBe('Int');
});

expect(() => {
myITC.getFieldTC('list');
}).toThrow('field should be InputObjectType');
it('should return TypeComposer for interface list fields', () => {
const tco = myITC.getFieldTC('enum');
expect(tco).toBeInstanceOf(EnumTypeComposer);
expect(tco.getTypeName()).toBe('MyEnumType');
});
});
});

0 comments on commit e299fa3

Please sign in to comment.