Skip to content

Commit 83e7b16

Browse files
committed
Allow skipping suggestions
1 parent a1d22a2 commit 83e7b16

13 files changed

+219
-55
lines changed

src/execution/collectFields.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ interface CollectFieldsContext {
5555
operation: OperationDefinitionNode;
5656
runtimeType: GraphQLObjectType;
5757
visitedFragmentNames: Set<string>;
58+
shouldProvideSuggestions: boolean;
5859
}
5960

6061
/**
@@ -66,12 +67,14 @@ interface CollectFieldsContext {
6667
*
6768
* @internal
6869
*/
70+
// eslint-disable-next-line @typescript-eslint/max-params
6971
export function collectFields(
7072
schema: GraphQLSchema,
7173
fragments: ObjMap<FragmentDetails>,
7274
variableValues: VariableValues,
7375
runtimeType: GraphQLObjectType,
7476
operation: OperationDefinitionNode,
77+
shouldProvideSuggestions: boolean,
7578
): {
7679
groupedFieldSet: GroupedFieldSet;
7780
newDeferUsages: ReadonlyArray<DeferUsage>;
@@ -85,6 +88,7 @@ export function collectFields(
8588
runtimeType,
8689
operation,
8790
visitedFragmentNames: new Set(),
91+
shouldProvideSuggestions,
8892
};
8993

9094
collectFieldsImpl(
@@ -114,6 +118,7 @@ export function collectSubfields(
114118
operation: OperationDefinitionNode,
115119
returnType: GraphQLObjectType,
116120
fieldGroup: FieldGroup,
121+
shouldProvideSuggestions: boolean,
117122
): {
118123
groupedFieldSet: GroupedFieldSet;
119124
newDeferUsages: ReadonlyArray<DeferUsage>;
@@ -125,6 +130,7 @@ export function collectSubfields(
125130
runtimeType: returnType,
126131
operation,
127132
visitedFragmentNames: new Set(),
133+
shouldProvideSuggestions,
128134
};
129135
const subGroupedFieldSet = new AccumulatorMap<string, FieldDetails>();
130136
const newDeferUsages: Array<DeferUsage> = [];
@@ -172,7 +178,12 @@ function collectFieldsImpl(
172178
switch (selection.kind) {
173179
case Kind.FIELD: {
174180
if (
175-
!shouldIncludeNode(selection, variableValues, fragmentVariableValues)
181+
!shouldIncludeNode(
182+
selection,
183+
variableValues,
184+
fragmentVariableValues,
185+
context.shouldProvideSuggestions,
186+
)
176187
) {
177188
continue;
178189
}
@@ -189,6 +200,7 @@ function collectFieldsImpl(
189200
selection,
190201
variableValues,
191202
fragmentVariableValues,
203+
context.shouldProvideSuggestions,
192204
) ||
193205
!doesFragmentConditionMatch(schema, selection, runtimeType)
194206
) {
@@ -201,6 +213,7 @@ function collectFieldsImpl(
201213
fragmentVariableValues,
202214
selection,
203215
deferUsage,
216+
context.shouldProvideSuggestions,
204217
);
205218

206219
if (!newDeferUsage) {
@@ -235,6 +248,7 @@ function collectFieldsImpl(
235248
fragmentVariableValues,
236249
selection,
237250
deferUsage,
251+
context.shouldProvideSuggestions,
238252
);
239253

240254
if (
@@ -244,6 +258,7 @@ function collectFieldsImpl(
244258
selection,
245259
variableValues,
246260
fragmentVariableValues,
261+
context.shouldProvideSuggestions,
247262
))
248263
) {
249264
continue;
@@ -264,6 +279,7 @@ function collectFieldsImpl(
264279
selection,
265280
fragmentVariableSignatures,
266281
variableValues,
282+
context.shouldProvideSuggestions,
267283
fragmentVariableValues,
268284
);
269285
}
@@ -300,16 +316,19 @@ function collectFieldsImpl(
300316
* deferred based on the experimental flag, defer directive present and
301317
* not disabled by the "if" argument.
302318
*/
319+
// eslint-disable-next-line @typescript-eslint/max-params
303320
function getDeferUsage(
304321
operation: OperationDefinitionNode,
305322
variableValues: VariableValues,
306323
fragmentVariableValues: VariableValues | undefined,
307324
node: FragmentSpreadNode | InlineFragmentNode,
308325
parentDeferUsage: DeferUsage | undefined,
326+
shouldProvideSuggestions: boolean,
309327
): DeferUsage | undefined {
310328
const defer = getDirectiveValues(
311329
GraphQLDeferDirective,
312330
node,
331+
shouldProvideSuggestions,
313332
variableValues,
314333
fragmentVariableValues,
315334
);
@@ -341,10 +360,12 @@ function shouldIncludeNode(
341360
node: FragmentSpreadNode | FieldNode | InlineFragmentNode,
342361
variableValues: VariableValues,
343362
fragmentVariableValues: VariableValues | undefined,
363+
shouldProvideSuggestions: boolean,
344364
): boolean {
345365
const skip = getDirectiveValues(
346366
GraphQLSkipDirective,
347367
node,
368+
shouldProvideSuggestions,
348369
variableValues,
349370
fragmentVariableValues,
350371
);
@@ -355,6 +376,7 @@ function shouldIncludeNode(
355376
const include = getDirectiveValues(
356377
GraphQLIncludeDirective,
357378
node,
379+
shouldProvideSuggestions,
358380
variableValues,
359381
fragmentVariableValues,
360382
);

src/execution/execute.ts

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -98,15 +98,21 @@ const collectSubfields = memoize3(
9898
returnType: GraphQLObjectType,
9999
fieldGroup: FieldGroup,
100100
) => {
101-
const { schema, fragments, operation, variableValues } =
102-
validatedExecutionArgs;
101+
const {
102+
schema,
103+
fragments,
104+
operation,
105+
variableValues,
106+
shouldProvideSuggestions,
107+
} = validatedExecutionArgs;
103108
return _collectSubfields(
104109
schema,
105110
fragments,
106111
variableValues,
107112
operation,
108113
returnType,
109114
fieldGroup,
115+
shouldProvideSuggestions,
110116
);
111117
},
112118
);
@@ -148,6 +154,7 @@ export interface ValidatedExecutionArgs {
148154
typeResolver: GraphQLTypeResolver<any, any>;
149155
subscribeFieldResolver: GraphQLFieldResolver<any, any>;
150156
enableEarlyExecution: boolean;
157+
shouldProvideSuggestions: boolean;
151158
}
152159

153160
export interface ExecutionContext {
@@ -172,6 +179,7 @@ export interface ExecutionArgs {
172179
typeResolver?: Maybe<GraphQLTypeResolver<any, any>>;
173180
subscribeFieldResolver?: Maybe<GraphQLFieldResolver<any, any>>;
174181
enableEarlyExecution?: Maybe<boolean>;
182+
shouldProvideSuggestions?: Maybe<boolean>;
175183
}
176184

177185
export interface StreamUsage {
@@ -280,8 +288,14 @@ function executeOperation(
280288
cancellableStreams: undefined,
281289
};
282290
try {
283-
const { schema, fragments, rootValue, operation, variableValues } =
284-
validatedExecutionArgs;
291+
const {
292+
schema,
293+
fragments,
294+
rootValue,
295+
operation,
296+
variableValues,
297+
shouldProvideSuggestions,
298+
} = validatedExecutionArgs;
285299
const rootType = schema.getRootType(operation.operation);
286300
if (rootType == null) {
287301
throw new GraphQLError(
@@ -296,6 +310,7 @@ function executeOperation(
296310
variableValues,
297311
rootType,
298312
operation,
313+
shouldProvideSuggestions,
299314
);
300315

301316
const { groupedFieldSet, newDeferUsages } = collectedFields;
@@ -472,6 +487,7 @@ export function validateExecutionArgs(
472487
typeResolver,
473488
subscribeFieldResolver,
474489
enableEarlyExecution,
490+
shouldProvideSuggestions,
475491
} = args;
476492

477493
// If the schema used for execution is invalid, throw an error.
@@ -527,7 +543,10 @@ export function validateExecutionArgs(
527543
schema,
528544
variableDefinitions,
529545
rawVariableValues ?? {},
530-
{ maxErrors: 50 },
546+
{
547+
maxErrors: 50,
548+
shouldProvideSuggestions: shouldProvideSuggestions ?? true,
549+
},
531550
);
532551

533552
if (variableValuesOrErrors.errors) {
@@ -545,6 +564,7 @@ export function validateExecutionArgs(
545564
typeResolver: typeResolver ?? defaultTypeResolver,
546565
subscribeFieldResolver: subscribeFieldResolver ?? defaultFieldResolver,
547566
enableEarlyExecution: enableEarlyExecution === true,
567+
shouldProvideSuggestions: shouldProvideSuggestions ?? true,
548568
};
549569
}
550570

@@ -728,7 +748,8 @@ function executeField(
728748
deferMap: ReadonlyMap<DeferUsage, DeferredFragmentRecord> | undefined,
729749
): PromiseOrValue<GraphQLWrappedResult<unknown>> | undefined {
730750
const validatedExecutionArgs = exeContext.validatedExecutionArgs;
731-
const { schema, contextValue, variableValues } = validatedExecutionArgs;
751+
const { schema, contextValue, variableValues, shouldProvideSuggestions } =
752+
validatedExecutionArgs;
732753
const fieldName = fieldGroup[0].node.name.value;
733754
const fieldDef = schema.getField(parentType, fieldName);
734755
if (!fieldDef) {
@@ -755,6 +776,7 @@ function executeField(
755776
fieldGroup[0].node,
756777
fieldDef.args,
757778
variableValues,
779+
shouldProvideSuggestions,
758780
fieldGroup[0].fragmentVariableValues,
759781
);
760782

@@ -1058,12 +1080,14 @@ function getStreamUsage(
10581080
._streamUsage;
10591081
}
10601082

1061-
const { operation, variableValues } = validatedExecutionArgs;
1083+
const { operation, variableValues, shouldProvideSuggestions } =
1084+
validatedExecutionArgs;
10621085
// validation only allows equivalent streams on multiple fields, so it is
10631086
// safe to only check the first fieldNode for the stream directive
10641087
const stream = getDirectiveValues(
10651088
GraphQLStreamDirective,
10661089
fieldGroup[0].node,
1090+
shouldProvideSuggestions,
10671091
variableValues,
10681092
fieldGroup[0].fragmentVariableValues,
10691093
);
@@ -2023,6 +2047,7 @@ function executeSubscription(
20232047
contextValue,
20242048
operation,
20252049
variableValues,
2050+
shouldProvideSuggestions,
20262051
} = validatedExecutionArgs;
20272052

20282053
const rootType = schema.getSubscriptionType();
@@ -2039,6 +2064,7 @@ function executeSubscription(
20392064
variableValues,
20402065
rootType,
20412066
operation,
2067+
shouldProvideSuggestions,
20422068
);
20432069

20442070
const firstRootField = groupedFieldSet.entries().next().value as [
@@ -2072,7 +2098,12 @@ function executeSubscription(
20722098

20732099
// Build a JS object of arguments from the field.arguments AST, using the
20742100
// variables scope to fulfill any variable references.
2075-
const args = getArgumentValues(fieldDef, fieldNodes[0], variableValues);
2101+
const args = getArgumentValues(
2102+
fieldDef,
2103+
fieldNodes[0],
2104+
validatedExecutionArgs.shouldProvideSuggestions,
2105+
variableValues,
2106+
);
20762107

20772108
// Call the `subscribe()` resolver or the default resolver to produce an
20782109
// AsyncIterable yielding raw payloads.

0 commit comments

Comments
 (0)