Skip to content

Commit 8cdfaed

Browse files
committed
Merge branch 'issue-15-input-types' into dev
2 parents 8b71038 + 08f89e9 commit 8cdfaed

File tree

5 files changed

+131
-11
lines changed

5 files changed

+131
-11
lines changed

packages/graphql-model-directive/src/ModelDirective.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@ import {
22
defaultFieldResolver,
33
GraphQLBoolean,
44
GraphQLID,
5-
GraphQLInputObjectType,
65
GraphQLList,
76
GraphQLObjectType,
87
} from 'graphql';
98
import { SchemaDirectiveVisitor } from 'graphql-tools';
109
import * as pluralize from 'pluralize';
1110
import {
11+
addInputTypesForObjectType,
1212
generateFieldNames,
13-
omitResolvers,
1413
Store,
1514
} from './';
1615

@@ -70,14 +69,10 @@ export class ModelDirective extends SchemaDirectiveVisitor {
7069
}
7170

7271
private addInputTypes(type: GraphQLObjectType) {
73-
const names = generateFieldNames(type.name);
74-
75-
// Create an input type with identical fields as the current type.
76-
// Since input type fields can't have resolvers we omit them.
77-
this.schema.getTypeMap()[names.input.type] = new GraphQLInputObjectType({
78-
name: names.input.type,
79-
fields: () => omitResolvers(type.getFields()),
80-
});
72+
// Generate corresponding input types for the given type.
73+
// Each field returning GraphQLObjectType in the given type will also
74+
// have input types generated recursively.
75+
addInputTypesForObjectType(type, this.schema);
8176
}
8277

8378
private addMutations(type: GraphQLObjectType) {
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import {
2+
GraphQLInputObjectType,
3+
GraphQLObjectType,
4+
GraphQLSchema,
5+
} from 'graphql';
6+
import {
7+
omitResolvers,
8+
} from './';
9+
10+
export const toInputObjectName = (name: string): string => `${name}InputType`;
11+
12+
export const isObjectType = (object, schema: GraphQLSchema): boolean => {
13+
const type = schema.getType(object.type);
14+
return type instanceof GraphQLObjectType;
15+
};
16+
17+
export const getInputType = (object: any, schema: GraphQLSchema): GraphQLInputObjectType => {
18+
const type = schema.getType(toInputObjectName(object.type.name));
19+
return type as GraphQLInputObjectType;
20+
};
21+
22+
export const addInputTypesForObjectType = (objectType: GraphQLObjectType, schema: GraphQLSchema) => {
23+
// Fields of an input type cannot have resolvers
24+
const fields = omitResolvers(objectType.getFields());
25+
26+
// Create the corresponding input type.
27+
// For example, if given `type Foo` will create `input FooInputType`
28+
let inputObjectType = new GraphQLInputObjectType({
29+
name: toInputObjectName(objectType.name),
30+
fields,
31+
});
32+
33+
// Adds the newly created input type to the type map.
34+
//
35+
// Note: the GraphQLObjectType fields of the input type have not yet been replaced.
36+
// However weneed a reference to the input type added to the type map for lookups during recursion.
37+
schema.getTypeMap()[inputObjectType.name] = inputObjectType;
38+
39+
// Iterate over each field in the input type.
40+
// If the field's type is not a GraphQLObjectType then it is copied as is.
41+
// If the field's type is a GraphQLObjectType
42+
// Find (or create if not found) the corresponding input type
43+
// Replace the field's type with the input type
44+
const inputObjectFields = Object
45+
.keys(fields)
46+
.reduce((res, key) => {
47+
let field = fields[key];
48+
49+
if (isObjectType(field, schema)) {
50+
// Check if the input type already exists
51+
const inputType = getInputType(field, schema);
52+
if (inputType) {
53+
field = {
54+
name: inputType.name,
55+
type: inputType,
56+
};
57+
} else {
58+
// Input type does not exist so we need to create it
59+
const fieldType = schema.getType(field.type.name) as GraphQLObjectType;
60+
const newInputType = addInputTypesForObjectType(fieldType, schema);
61+
field = {
62+
name: newInputType.name,
63+
type: newInputType,
64+
};
65+
}
66+
}
67+
68+
return {
69+
...res,
70+
[key]: field,
71+
};
72+
}, {});
73+
74+
// Replace our original inputObjectType with new one containing the modified fields
75+
76+
inputObjectType = new GraphQLInputObjectType({
77+
name: inputObjectType.name,
78+
fields: inputObjectFields,
79+
});
80+
81+
schema.getTypeMap()[inputObjectType.name] = inputObjectType;
82+
83+
return inputObjectType;
84+
};

packages/graphql-model-directive/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export * from './UniqueDirective';
55
export * from './Store';
66
export * from './generateFieldNames';
77
export * from './omitResolvers';
8+
export * from './addInputTypesForObjectType';
89

910
import { DefaultDirective } from './DefaultDirective';
1011
import { ModelDirective } from './ModelDirective';

packages/graphql-model-directive/test/ModelDirective.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ describe('ModelDirective', () => {
2121
const typeDefs = `
2222
type Foo @model {
2323
name: String
24+
relation: Foo
25+
child: Bar
26+
}
27+
28+
type Bar {
29+
name: String
30+
relation: Foo
31+
child: Dummy
32+
relation: Dummy
33+
}
34+
35+
type Dummy {
36+
name: String
37+
relation: Bar
2438
}
2539
${baseTypeDefs}
2640
`;

packages/graphql-model-directive/test/__snapshots__/ModelDirective.test.ts.snap

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,41 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[`ModelDirective produces the expected schema 1`] = `
4-
"type Foo {
4+
"type Bar {
55
name: String
6+
relation: Dummy
7+
child: Dummy
8+
}
9+
10+
input BarInputType {
11+
name: String
12+
relation: DummyInputType
13+
child: DummyInputType
14+
}
15+
16+
type Dummy {
17+
name: String
18+
relation: Bar
19+
}
20+
21+
input DummyInputType {
22+
name: String
23+
relation: BarInputType
24+
}
25+
26+
type Foo {
27+
name: String
28+
relation: Foo
29+
child: Bar
630
731
\\"\\"\\"Unique ID\\"\\"\\"
832
id: ID
933
}
1034
1135
input FooInputType {
1236
name: String
37+
relation: FooInputType
38+
child: BarInputType
1339
1440
\\"\\"\\"Unique ID\\"\\"\\"
1541
id: ID

0 commit comments

Comments
 (0)