Skip to content

Commit 6b97308

Browse files
authored
refactor addition of all possible input types (#131)
* refactor addition of all possible input types this version is more robust as it only adds stricter types to the base type * add changeset
1 parent 9f6a142 commit 6b97308

File tree

3 files changed

+123
-16
lines changed

3 files changed

+123
-16
lines changed

.changeset/witty-guests-explode.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'graphql-executor': patch
3+
---
4+
5+
refactor toExecutorSchema to add only necessary input types

src/execution/__tests__/toExecutorSchema-test.ts

+35-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import { expect } from 'chai';
22
import { describe, it } from 'mocha';
33

4-
import type { GraphQLNonNull, NamedTypeNode, NonNullTypeNode } from 'graphql';
4+
import type {
5+
GraphQLNonNull,
6+
ListTypeNode,
7+
NamedTypeNode,
8+
NonNullTypeNode,
9+
} from 'graphql';
510
import {
11+
GraphQLList,
612
GraphQLInputObjectType,
713
GraphQLObjectType,
814
GraphQLSchema,
@@ -24,14 +30,22 @@ describe('ExecutorSchema:', () => {
2430
const query = new GraphQLObjectType({
2531
name: 'Query',
2632
fields: {
27-
field: {
33+
fieldWithInputArg: {
2834
type: GraphQLString,
2935
args: {
3036
arg: {
3137
type: input,
3238
},
3339
},
3440
},
41+
fieldWithListInputArg: {
42+
type: GraphQLString,
43+
args: {
44+
arg: {
45+
type: new GraphQLList(input),
46+
},
47+
},
48+
},
3549
},
3650
});
3751
const schema = new GraphQLSchema({
@@ -87,4 +101,23 @@ describe('ExecutorSchema:', () => {
87101
expect(executorSchema.isInputType(type)).to.equal(true);
88102
expect((type as GraphQLNonNull<any>).ofType).to.equal(input);
89103
});
104+
105+
it('allows retrieving list input types defined in schema', () => {
106+
const executorSchema = toExecutorSchema(schema);
107+
const listTypeNode: ListTypeNode = {
108+
kind: Kind.LIST_TYPE,
109+
type: {
110+
kind: Kind.NAMED_TYPE,
111+
name: {
112+
kind: Kind.NAME,
113+
value: 'Input',
114+
},
115+
},
116+
};
117+
const type = executorSchema.getType(listTypeNode);
118+
expect(type).to.not.equal(undefined);
119+
expect(executorSchema.isListType(type)).to.equal(true);
120+
expect(executorSchema.isInputType(type)).to.equal(true);
121+
expect((type as GraphQLList<any>).ofType).to.equal(input);
122+
});
90123
});

src/execution/toExecutorSchema.ts

+83-14
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,16 @@ import type {
44
GraphQLInterfaceType,
55
GraphQLInputObjectType,
66
GraphQLObjectType,
7-
GraphQLScalarType,
87
GraphQLSchema,
98
GraphQLUnionType,
9+
GraphQLNamedInputType,
1010
GraphQLNamedType,
1111
GraphQLInputType,
1212
GraphQLLeafType,
1313
GraphQLType,
1414
GraphQLNullableType,
1515
GraphQLOutputType,
16+
GraphQLScalarType,
1617
OperationTypeNode,
1718
TypeNode,
1819
} from 'graphql';
@@ -183,25 +184,93 @@ class TypeTree {
183184
}
184185
}
185186

186-
function getPossibleInputTypes(
187+
interface InputTypeInfo {
188+
nonNullListWrappers: Array<boolean>;
189+
nonNull: boolean;
190+
namedType: GraphQLNamedInputType;
191+
}
192+
193+
function getInputTypeInfo(
187194
type: GraphQLInputType,
188-
): Array<GraphQLInputType> {
189-
if (_isListType(type)) {
190-
return [
191-
...getPossibleInputTypes(type.ofType).map(
192-
(possibleType) => new GraphQLList(possibleType),
193-
),
194-
...getPossibleInputTypes(type.ofType).map(
195-
(possibleType) => new GraphQLNonNull(new GraphQLList(possibleType)),
196-
),
197-
];
195+
wrapper?:
196+
| GraphQLNonNull<GraphQLNullableInputType>
197+
| GraphQLList<GraphQLInputType>,
198+
): InputTypeInfo {
199+
if (!_isNonNullType(type) && !_isListType(type)) {
200+
return {
201+
nonNullListWrappers: [],
202+
nonNull: _isNonNullType(wrapper),
203+
namedType: type,
204+
};
198205
}
199206

207+
const inputTypeInfo = getInputTypeInfo(type.ofType, type);
200208
if (_isNonNullType(type)) {
201-
return [...getPossibleInputTypes(type.ofType)];
209+
return inputTypeInfo;
210+
}
211+
212+
inputTypeInfo.nonNullListWrappers.push(_isNonNullType(wrapper));
213+
214+
return inputTypeInfo;
215+
}
216+
217+
function getPossibleSequences(
218+
nonNullListWrappers: Array<boolean>,
219+
): Array<Array<boolean>> {
220+
if (!nonNullListWrappers.length) {
221+
return [[]];
222+
}
223+
224+
const nonNull = nonNullListWrappers.pop();
225+
if (nonNull) {
226+
return getPossibleSequences(nonNullListWrappers).map((sequence) => [
227+
true,
228+
...sequence,
229+
]);
230+
}
231+
232+
return [
233+
...getPossibleSequences(nonNullListWrappers).map((sequence) => [
234+
true,
235+
...sequence,
236+
]),
237+
...getPossibleSequences(nonNullListWrappers).map((sequence) => [
238+
false,
239+
...sequence,
240+
]),
241+
];
242+
}
243+
244+
function inputTypesFromSequences(
245+
sequences: Array<Array<boolean>>,
246+
inputType: GraphQLInputType,
247+
): Array<GraphQLInputType> {
248+
return sequences.map((sequence) =>
249+
sequence.reduce((acc, nonNull) => {
250+
let wrapped = new GraphQLList(acc);
251+
if (nonNull) {
252+
wrapped = new GraphQLNonNull(wrapped);
253+
}
254+
return wrapped;
255+
}, inputType),
256+
);
257+
}
258+
259+
function getPossibleInputTypes(
260+
type: GraphQLInputType,
261+
): Array<GraphQLInputType> {
262+
const { nonNullListWrappers, nonNull, namedType } = getInputTypeInfo(type);
263+
const sequences = getPossibleSequences(nonNullListWrappers);
264+
265+
const wrapped = new GraphQLNonNull(namedType);
266+
if (nonNull) {
267+
return inputTypesFromSequences(sequences, wrapped);
202268
}
203269

204-
return [new GraphQLNonNull(type), type];
270+
return [
271+
...inputTypesFromSequences(sequences, namedType),
272+
...inputTypesFromSequences(sequences, wrapped),
273+
];
205274
}
206275

207276
function _toExecutorSchema(schema: GraphQLSchema): ExecutorSchema {

0 commit comments

Comments
 (0)