Skip to content

Commit 1262c0a

Browse files
committed
refactor: migrate code to graphql-compose@7.0.0
BREAKING CHANGE: required graphql-compose@7.0.0
1 parent dbfe926 commit 1262c0a

File tree

9 files changed

+136
-151
lines changed

9 files changed

+136
-151
lines changed

src/__tests__/composeWithRelay-test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ describe('composeWithRelay', () => {
2929

3030
it('should throw error if ObjectTypeComposer without recordIdFn', () => {
3131
const tc = userTC.clone('AnotherUserType2');
32-
delete tc.gqType._gqcGetRecordIdFn;
32+
delete tc._gqcGetRecordIdFn;
3333
expect(() => composeWithRelay(tc)).toThrowError('should have recordIdFn');
3434
});
3535

@@ -45,8 +45,8 @@ describe('composeWithRelay', () => {
4545
describe('when pass RootQuery type composer', () => {
4646
it('should add `node` field to RootQuery', () => {
4747
const nodeField: any = queryTC.getField('node');
48-
expect(nodeField.type).toBeInstanceOf(GraphQLInterfaceType);
49-
expect(nodeField.type.name).toBe('Node');
48+
expect(nodeField.type.getType()).toBeInstanceOf(GraphQLInterfaceType);
49+
expect(nodeField.type.getTypeName()).toBe('Node');
5050
});
5151
});
5252

src/__tests__/nodeFieldConfig-test.js

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/* @flow */
22

3-
import { GraphQLInterfaceType, GraphQLNonNull } from 'graphql-compose/lib/graphql';
3+
import { schemaComposer, InterfaceTypeComposer } from 'graphql-compose';
44
import { findByIdResolver, userTC } from '../__mocks__/userTC';
55
import { toGlobalId } from '../globalId';
66
import { getNodeFieldConfig } from '../nodeFieldConfig';
7+
import { getNodeInterface } from '../nodeInterface';
78

89
describe('nodeFieldConfig', () => {
910
const typeToFindByIdMap = {
@@ -12,16 +13,16 @@ describe('nodeFieldConfig', () => {
1213
tc: userTC,
1314
},
1415
};
15-
const config = getNodeFieldConfig(typeToFindByIdMap);
16+
const config: any = getNodeFieldConfig(typeToFindByIdMap, getNodeInterface(schemaComposer));
1617

1718
it('should have type GraphQLInterfaceType', () => {
1819
expect(config).toBeTruthy();
19-
expect(config.type).toBeInstanceOf(GraphQLInterfaceType);
20-
expect(config.type.name).toBe('Node');
20+
expect(config.type).toBeInstanceOf(InterfaceTypeComposer);
21+
expect(config.type.getTypeName()).toBe('Node');
2122
});
2223

2324
it('should have args with id', () => {
24-
expect(config.args.id.type).toBeInstanceOf(GraphQLNonNull);
25+
expect(config.args.id.type).toBe('ID!');
2526
});
2627

2728
it('should have resolve function', () => {
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/* @flow */
2+
3+
import { composeWithRelay } from '../composeWithRelay';
4+
import { userTC } from '../__mocks__/userTC';
5+
import { toGlobalId } from '../globalId';
6+
7+
describe('wrapMutationResolver', () => {
8+
composeWithRelay(userTC);
9+
const resolverCreateOne = userTC.getResolver('createOne');
10+
const resolverWithInput = userTC.getResolver('manyArgsWithInput');
11+
const resolverWithoutInput = userTC.getResolver('manyArgsWithoutInput');
12+
13+
describe('args', () => {
14+
it('should add `clientMutationId` field to args.input', () => {
15+
const itc = resolverCreateOne.getArgITC('input');
16+
expect(itc.hasField('clientMutationId')).toBe(true);
17+
expect(itc.getFieldTypeName('clientMutationId')).toBe('String');
18+
});
19+
20+
it('should create required args.input! if not exists', () => {
21+
expect(resolverWithoutInput.hasArg('input')).toBeTruthy();
22+
expect(resolverWithoutInput.isArgNonNull('input')).toBeTruthy();
23+
});
24+
25+
it('should create args.input if not exists and move all args into it', () => {
26+
expect(resolverWithoutInput.hasArg('input')).toBeTruthy();
27+
const itc = resolverWithoutInput.getArgITC('input');
28+
expect(itc.hasField('sort')).toBe(true);
29+
expect(itc.hasField('limit')).toBe(true);
30+
expect(itc.hasField('clientMutationId')).toBe(true);
31+
});
32+
33+
it('should leave other arg untouched if args.input exists', () => {
34+
expect(resolverWithInput.getArgNames()).toEqual(
35+
expect.arrayContaining(['input', 'sort', 'limit'])
36+
);
37+
38+
const itc = resolverWithInput.getArgITC('input');
39+
expect(itc.hasField('sort')).toBe(false);
40+
expect(itc.hasField('limit')).toBe(false);
41+
expect(itc.hasField('clientMutationId')).toBe(true);
42+
});
43+
});
44+
45+
describe('outputType', () => {
46+
it('should add `clientMutationId` field to payload', () => {
47+
const tc = resolverCreateOne.getOTC();
48+
expect(tc.hasField('clientMutationId')).toBe(true);
49+
expect(tc.getFieldTypeName('clientMutationId')).toBe('String');
50+
});
51+
52+
it('should add `nodeId` field to payload', () => {
53+
const tc = resolverCreateOne.getOTC();
54+
expect(tc.hasField('nodeId')).toBe(true);
55+
expect(tc.getFieldTypeName('nodeId')).toBe('ID');
56+
});
57+
});
58+
59+
describe('resolve', () => {
60+
it('should passthru `clientMutationId`', async () => {
61+
const result = await resolverCreateOne.resolve({
62+
args: { input: { clientMutationId: '333' } },
63+
});
64+
expect(result.clientMutationId).toBe('333');
65+
});
66+
67+
it('should return `nodeId` with globalId', async () => {
68+
const result = await resolverCreateOne.resolve({ args: { input: { id: 'newRecord' } } });
69+
expect(result.nodeId).toBe(toGlobalId('User', 'newRecord'));
70+
});
71+
});
72+
});

src/__tests__/wrapMutationResolver.js

Lines changed: 0 additions & 87 deletions
This file was deleted.

src/composeWithRelay.js

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,25 @@
22
/* eslint-disable no-use-before-define */
33

44
import { ObjectTypeComposer } from 'graphql-compose';
5-
import { GraphQLID, GraphQLNonNull } from 'graphql-compose/lib/graphql';
6-
import NodeInterface from './nodeInterface';
75
import wrapMutationResolver from './wrapMutationResolver';
86
import { toGlobalId } from './globalId';
7+
import { getNodeInterface } from './nodeInterface';
98
import { getNodeFieldConfig } from './nodeFieldConfig';
109

1110
// all wrapped typeComposers with Relay, stored in this variable
1211
// for futher type resolving via NodeInterface.resolveType method
1312
export const TypeMapForRelayNode = {};
14-
export const nodeFieldConfig = getNodeFieldConfig(TypeMapForRelayNode);
1513

16-
export function composeWithRelay<T>(typeComposer: T): T {
17-
return (_composeWithRelay((typeComposer: any)): any);
18-
}
19-
20-
export function _composeWithRelay<TSource, TContext>(
14+
export function composeWithRelay<TSource, TContext>(
2115
tc: ObjectTypeComposer<TSource, TContext>
2216
): ObjectTypeComposer<TSource, TContext> {
2317
if (!tc || tc.constructor.name !== 'ObjectTypeComposer') {
2418
throw new Error('You should provide ObjectTypeComposer instance to composeWithRelay method');
2519
}
2620

21+
const nodeInterface = getNodeInterface(tc.schemaComposer);
22+
const nodeFieldConfig = getNodeFieldConfig(TypeMapForRelayNode, nodeInterface);
23+
2724
if (tc.getTypeName() === 'Query' || tc.getTypeName() === 'RootQuery') {
2825
tc.setField('node', nodeFieldConfig);
2926
return tc;
@@ -55,13 +52,13 @@ export function _composeWithRelay<TSource, TContext>(
5552

5653
tc.addFields({
5754
id: {
58-
type: new GraphQLNonNull(GraphQLID),
55+
type: 'ID!',
5956
description: 'The globally unique ID among all types',
6057
resolve: source => toGlobalId(tc.getTypeName(), tc.getRecordId(source)),
6158
},
6259
});
6360

64-
tc.addInterface(NodeInterface);
61+
tc.addInterface(nodeInterface);
6562

6663
tc.getResolvers().forEach((resolver, resolverName) => {
6764
if (resolver.kind === 'mutation') {

src/index.js

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
11
/* @flow */
22

3-
import { composeWithRelay, TypeMapForRelayNode, nodeFieldConfig } from './composeWithRelay';
3+
import { composeWithRelay, TypeMapForRelayNode } from './composeWithRelay';
44
import { fromGlobalId, toGlobalId } from './globalId';
5-
import NodeInterface from './nodeInterface';
5+
import { getNodeInterface } from './nodeInterface';
66

77
export default composeWithRelay;
8-
export {
9-
composeWithRelay,
10-
NodeInterface,
11-
TypeMapForRelayNode,
12-
nodeFieldConfig,
13-
fromGlobalId,
14-
toGlobalId,
15-
};
8+
export { composeWithRelay, getNodeInterface, TypeMapForRelayNode, fromGlobalId, toGlobalId };

src/nodeFieldConfig.js

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
/* @flow */
22
/* eslint-disable no-param-reassign, import/prefer-default-export */
3-
import { getProjectionFromAST } from 'graphql-compose';
4-
import { GraphQLID, GraphQLNonNull, type GraphQLResolveInfo } from 'graphql-compose/lib/graphql';
3+
import {
4+
getProjectionFromAST,
5+
type InterfaceTypeComposer,
6+
type ObjectTypeComposerFieldConfigDefinition,
7+
} from 'graphql-compose';
8+
import type { GraphQLResolveInfo } from 'graphql-compose/lib/graphql';
59
import type { Resolver, ObjectTypeComposer } from 'graphql-compose';
610
import { fromGlobalId } from './globalId';
7-
import NodeInterface from './nodeInterface';
811

912
export type TypeMapForRelayNode<TSource, TContext> = {
1013
[typeName: string]: {
@@ -14,13 +17,16 @@ export type TypeMapForRelayNode<TSource, TContext> = {
1417
};
1518

1619
// this fieldConfig must be set to RootQuery.node field
17-
export function getNodeFieldConfig(typeMapForRelayNode: TypeMapForRelayNode<any, any>) {
20+
export function getNodeFieldConfig(
21+
typeMapForRelayNode: TypeMapForRelayNode<any, any>,
22+
nodeInterface: InterfaceTypeComposer<any, any>
23+
): ObjectTypeComposerFieldConfigDefinition<any, any> {
1824
return {
1925
description: 'Fetches an object that has globally unique ID among all types',
20-
type: NodeInterface,
26+
type: nodeInterface,
2127
args: {
2228
id: {
23-
type: (new GraphQLNonNull(GraphQLID): $FlowFixMe),
29+
type: 'ID!',
2430
description: 'The globally unique ID among all types',
2531
},
2632
},

src/nodeInterface.js

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
/* @flow */
22

3-
import { GraphQLID, GraphQLNonNull, GraphQLInterfaceType } from 'graphql-compose/lib/graphql';
3+
import { InterfaceTypeComposer, type SchemaComposer } from 'graphql-compose';
44

5-
const NodeInterface = new GraphQLInterfaceType({
6-
name: 'Node',
7-
description: 'An object, that can be fetched by the globally unique ID among all types.',
8-
fields: () => ({
9-
id: {
10-
type: new GraphQLNonNull(GraphQLID),
11-
description: 'The globally unique ID among all types.',
5+
export function getNodeInterface<TContex>(
6+
sc: SchemaComposer<TContex>
7+
): InterfaceTypeComposer<any, TContex> {
8+
if (sc.hasInstance('Node', InterfaceTypeComposer)) {
9+
return (sc.get('Node'): any);
10+
}
11+
12+
const NodeInterface = InterfaceTypeComposer.create(
13+
{
14+
name: 'Node',
15+
description: 'An object, that can be fetched by the globally unique ID among all types.',
16+
fields: {
17+
id: {
18+
type: 'ID!',
19+
description: 'The globally unique ID among all types.',
20+
},
21+
},
22+
resolveType: payload => {
23+
// `payload.__nodeType` was added to payload via nodeFieldConfig.resolve
24+
return payload.__nodeType ? payload.__nodeType : null;
25+
},
1226
},
13-
}),
14-
resolveType: payload => {
15-
// `payload.__nodeType` was added to payload via nodeFieldConfig.resolve
16-
return payload.__nodeType ? payload.__nodeType : null;
17-
},
18-
});
27+
sc
28+
);
1929

20-
export default NodeInterface;
30+
return NodeInterface;
31+
}

0 commit comments

Comments
 (0)