diff --git a/src/execution/__tests__/executor-test.ts b/src/execution/__tests__/executor-test.ts index ff366c6631..a283dcbf23 100644 --- a/src/execution/__tests__/executor-test.ts +++ b/src/execution/__tests__/executor-test.ts @@ -22,7 +22,6 @@ import { GraphQLBoolean, GraphQLInt, GraphQLString } from '../../type/scalars'; import { GraphQLSchema } from '../../type/schema'; import { execute, executeSync } from '../execute'; -import { print } from '../../language'; describe('Execute: Handles basic execution tasks', () => { it('throws if no document is provided', () => { @@ -81,7 +80,6 @@ describe('Execute: Handles basic execution tasks', () => { }), }); - const n = 10000; const fragments = Array.from(Array(n).keys()).reduce( (acc, next) => @@ -96,7 +94,6 @@ describe('Execute: Handles basic execution tasks', () => { const document = parse(` query { ...X${n} - __typename } ${fragments} fragment X0 on Query { diff --git a/src/execution/collectFields.ts b/src/execution/collectFields.ts index d0961bfae8..06ade32c5b 100644 --- a/src/execution/collectFields.ts +++ b/src/execution/collectFields.ts @@ -21,6 +21,11 @@ import { typeFromAST } from '../utilities/typeFromAST'; import { getDirectiveValues } from './values'; +interface FragmentEntry { + fragment: FragmentDefinitionNode; + runtimeType: GraphQLObjectType; +} + /** * Given a selectionSet, collects all of the fields and returns them. * @@ -37,7 +42,9 @@ export function collectFields( runtimeType: GraphQLObjectType, selectionSet: SelectionSetNode, ): Map> { + const foundFragments: Array = []; const fields = new Map(); + const visited = new Set(); collectFieldsImpl( schema, fragments, @@ -45,8 +52,24 @@ export function collectFields( runtimeType, selectionSet, fields, - new Set(), + visited, + foundFragments, ); + + let entry; + while ((entry = foundFragments.pop()) !== undefined) { + collectFieldsImpl( + schema, + fragments, + variableValues, + entry.runtimeType, + entry.fragment.selectionSet, + fields, + visited, + foundFragments, + ); + } + return fields; } @@ -68,6 +91,7 @@ export function collectSubfields( fieldNodes: ReadonlyArray, ): Map> { const subFieldNodes = new Map(); + const foundFragments: Array = []; const visitedFragmentNames = new Set(); for (const node of fieldNodes) { if (node.selectionSet) { @@ -79,9 +103,25 @@ export function collectSubfields( node.selectionSet, subFieldNodes, visitedFragmentNames, + foundFragments, ); } } + + let entry; + while ((entry = foundFragments.pop()) !== undefined) { + collectFieldsImpl( + schema, + fragments, + variableValues, + entry.runtimeType, + entry.fragment.selectionSet, + subFieldNodes, + visitedFragmentNames, + foundFragments, + ); + } + return subFieldNodes; } @@ -93,6 +133,7 @@ function collectFieldsImpl( selectionSet: SelectionSetNode, fields: Map>, visitedFragmentNames: Set, + foundFragments: Array, ): void { for (const selection of selectionSet.selections) { switch (selection.kind) { @@ -124,6 +165,7 @@ function collectFieldsImpl( selection.selectionSet, fields, visitedFragmentNames, + foundFragments, ); break; } @@ -143,15 +185,8 @@ function collectFieldsImpl( ) { continue; } - collectFieldsImpl( - schema, - fragments, - variableValues, - runtimeType, - fragment.selectionSet, - fields, - visitedFragmentNames, - ); + + foundFragments.push({ runtimeType, fragment }); break; } }