Skip to content

Commit

Permalink
refactor addition of all possible input types (#131)
Browse files Browse the repository at this point in the history
* refactor addition of all possible input types

this version is more robust as it only adds stricter types to the base type

* add changeset
  • Loading branch information
yaacovCR authored Jan 14, 2022
1 parent 9f6a142 commit 6b97308
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .changeset/witty-guests-explode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'graphql-executor': patch
---

refactor toExecutorSchema to add only necessary input types
37 changes: 35 additions & 2 deletions src/execution/__tests__/toExecutorSchema-test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { expect } from 'chai';
import { describe, it } from 'mocha';

import type { GraphQLNonNull, NamedTypeNode, NonNullTypeNode } from 'graphql';
import type {
GraphQLNonNull,
ListTypeNode,
NamedTypeNode,
NonNullTypeNode,
} from 'graphql';
import {
GraphQLList,
GraphQLInputObjectType,
GraphQLObjectType,
GraphQLSchema,
Expand All @@ -24,14 +30,22 @@ describe('ExecutorSchema:', () => {
const query = new GraphQLObjectType({
name: 'Query',
fields: {
field: {
fieldWithInputArg: {
type: GraphQLString,
args: {
arg: {
type: input,
},
},
},
fieldWithListInputArg: {
type: GraphQLString,
args: {
arg: {
type: new GraphQLList(input),
},
},
},
},
});
const schema = new GraphQLSchema({
Expand Down Expand Up @@ -87,4 +101,23 @@ describe('ExecutorSchema:', () => {
expect(executorSchema.isInputType(type)).to.equal(true);
expect((type as GraphQLNonNull<any>).ofType).to.equal(input);
});

it('allows retrieving list input types defined in schema', () => {
const executorSchema = toExecutorSchema(schema);
const listTypeNode: ListTypeNode = {
kind: Kind.LIST_TYPE,
type: {
kind: Kind.NAMED_TYPE,
name: {
kind: Kind.NAME,
value: 'Input',
},
},
};
const type = executorSchema.getType(listTypeNode);
expect(type).to.not.equal(undefined);
expect(executorSchema.isListType(type)).to.equal(true);
expect(executorSchema.isInputType(type)).to.equal(true);
expect((type as GraphQLList<any>).ofType).to.equal(input);
});
});
97 changes: 83 additions & 14 deletions src/execution/toExecutorSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ import type {
GraphQLInterfaceType,
GraphQLInputObjectType,
GraphQLObjectType,
GraphQLScalarType,
GraphQLSchema,
GraphQLUnionType,
GraphQLNamedInputType,
GraphQLNamedType,
GraphQLInputType,
GraphQLLeafType,
GraphQLType,
GraphQLNullableType,
GraphQLOutputType,
GraphQLScalarType,
OperationTypeNode,
TypeNode,
} from 'graphql';
Expand Down Expand Up @@ -183,25 +184,93 @@ class TypeTree {
}
}

function getPossibleInputTypes(
interface InputTypeInfo {
nonNullListWrappers: Array<boolean>;
nonNull: boolean;
namedType: GraphQLNamedInputType;
}

function getInputTypeInfo(
type: GraphQLInputType,
): Array<GraphQLInputType> {
if (_isListType(type)) {
return [
...getPossibleInputTypes(type.ofType).map(
(possibleType) => new GraphQLList(possibleType),
),
...getPossibleInputTypes(type.ofType).map(
(possibleType) => new GraphQLNonNull(new GraphQLList(possibleType)),
),
];
wrapper?:
| GraphQLNonNull<GraphQLNullableInputType>
| GraphQLList<GraphQLInputType>,
): InputTypeInfo {
if (!_isNonNullType(type) && !_isListType(type)) {
return {
nonNullListWrappers: [],
nonNull: _isNonNullType(wrapper),
namedType: type,
};
}

const inputTypeInfo = getInputTypeInfo(type.ofType, type);
if (_isNonNullType(type)) {
return [...getPossibleInputTypes(type.ofType)];
return inputTypeInfo;
}

inputTypeInfo.nonNullListWrappers.push(_isNonNullType(wrapper));

return inputTypeInfo;
}

function getPossibleSequences(
nonNullListWrappers: Array<boolean>,
): Array<Array<boolean>> {
if (!nonNullListWrappers.length) {
return [[]];
}

const nonNull = nonNullListWrappers.pop();
if (nonNull) {
return getPossibleSequences(nonNullListWrappers).map((sequence) => [
true,
...sequence,
]);
}

return [
...getPossibleSequences(nonNullListWrappers).map((sequence) => [
true,
...sequence,
]),
...getPossibleSequences(nonNullListWrappers).map((sequence) => [
false,
...sequence,
]),
];
}

function inputTypesFromSequences(
sequences: Array<Array<boolean>>,
inputType: GraphQLInputType,
): Array<GraphQLInputType> {
return sequences.map((sequence) =>
sequence.reduce((acc, nonNull) => {
let wrapped = new GraphQLList(acc);
if (nonNull) {
wrapped = new GraphQLNonNull(wrapped);
}
return wrapped;
}, inputType),
);
}

function getPossibleInputTypes(
type: GraphQLInputType,
): Array<GraphQLInputType> {
const { nonNullListWrappers, nonNull, namedType } = getInputTypeInfo(type);
const sequences = getPossibleSequences(nonNullListWrappers);

const wrapped = new GraphQLNonNull(namedType);
if (nonNull) {
return inputTypesFromSequences(sequences, wrapped);
}

return [new GraphQLNonNull(type), type];
return [
...inputTypesFromSequences(sequences, namedType),
...inputTypesFromSequences(sequences, wrapped),
];
}

function _toExecutorSchema(schema: GraphQLSchema): ExecutorSchema {
Expand Down

0 comments on commit 6b97308

Please sign in to comment.