Skip to content

Commit 85e8f21

Browse files
JoviDeCroockyaacovCR
authored andcommitted
feat: Allow skipping suggestions (graphql#4214)
1 parent fcb9158 commit 85e8f21

21 files changed

Lines changed: 483 additions & 65 deletions

src/execution/collectFields.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ interface CollectFieldsContext {
4444
variableValues: VariableValues;
4545
runtimeType: GraphQLObjectType;
4646
visitedFragmentNames: Set<string>;
47+
hideSuggestions: boolean;
4748
}
4849

4950
/**
@@ -55,12 +56,14 @@ interface CollectFieldsContext {
5556
*
5657
* @internal
5758
*/
59+
// eslint-disable-next-line @typescript-eslint/max-params
5860
export function collectFields(
5961
schema: GraphQLSchema,
6062
fragments: ObjMap<FragmentDetails>,
6163
variableValues: VariableValues,
6264
runtimeType: GraphQLObjectType,
6365
selectionSet: SelectionSetNode,
66+
hideSuggestions: boolean,
6467
): GroupedFieldSet {
6568
const groupedFieldSet = new AccumulatorMap<string, FieldDetails>();
6669
const context: CollectFieldsContext = {
@@ -69,6 +72,7 @@ export function collectFields(
6972
variableValues,
7073
runtimeType,
7174
visitedFragmentNames: new Set(),
75+
hideSuggestions,
7276
};
7377

7478
collectFieldsImpl(context, selectionSet, groupedFieldSet);
@@ -85,19 +89,22 @@ export function collectFields(
8589
*
8690
* @internal
8791
*/
92+
// eslint-disable-next-line @typescript-eslint/max-params
8893
export function collectSubfields(
8994
schema: GraphQLSchema,
9095
fragments: ObjMap<FragmentDetails>,
9196
variableValues: VariableValues,
9297
returnType: GraphQLObjectType,
9398
fieldDetailsList: FieldDetailsList,
99+
hideSuggestions: boolean,
94100
): GroupedFieldSet {
95101
const context: CollectFieldsContext = {
96102
schema,
97103
fragments,
98104
variableValues,
99105
runtimeType: returnType,
100106
visitedFragmentNames: new Set(),
107+
hideSuggestions,
101108
};
102109
const subGroupedFieldSet = new AccumulatorMap<string, FieldDetails>();
103110

@@ -129,6 +136,7 @@ function collectFieldsImpl(
129136
variableValues,
130137
runtimeType,
131138
visitedFragmentNames,
139+
hideSuggestions,
132140
} = context;
133141

134142
for (const selection of selectionSet.selections) {
@@ -192,6 +200,7 @@ function collectFieldsImpl(
192200
fragmentVariableSignatures,
193201
variableValues,
194202
fragmentVariableValues,
203+
hideSuggestions,
195204
);
196205
}
197206

src/execution/execute.ts

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,15 @@ const collectSubfields = memoize3(
8080
returnType: GraphQLObjectType,
8181
fieldDetailsList: FieldDetailsList,
8282
) => {
83-
const { schema, fragments, variableValues } = validatedExecutionArgs;
83+
const { schema, fragments, variableValues, hideSuggestions } =
84+
validatedExecutionArgs;
8485
return _collectSubfields(
8586
schema,
8687
fragments,
8788
variableValues,
8889
returnType,
8990
fieldDetailsList,
91+
hideSuggestions,
9092
);
9193
},
9294
);
@@ -134,6 +136,7 @@ export interface ValidatedExecutionArgs {
134136
perEventExecutor: (
135137
validatedExecutionArgs: ValidatedExecutionArgs,
136138
) => PromiseOrValue<ExecutionResult>;
139+
hideSuggestions: boolean;
137140
}
138141

139142
export interface ExecutionContext {
@@ -181,6 +184,7 @@ export interface ExecutionArgs {
181184
validatedExecutionArgs: ValidatedExecutionArgs,
182185
) => PromiseOrValue<ExecutionResult>
183186
>;
187+
hideSuggestions?: Maybe<boolean>;
184188
/** Additional execution options. */
185189
options?: {
186190
/** Set the maximum number of errors allowed for coercing (defaults to 50). */
@@ -234,8 +238,14 @@ export function executeQueryOrMutationOrSubscriptionEvent(
234238
errors: [],
235239
};
236240
try {
237-
const { schema, fragments, rootValue, operation, variableValues } =
238-
validatedExecutionArgs;
241+
const {
242+
schema,
243+
fragments,
244+
rootValue,
245+
operation,
246+
variableValues,
247+
hideSuggestions,
248+
} = validatedExecutionArgs;
239249
const rootType = schema.getRootType(operation.operation);
240250
if (rootType == null) {
241251
throw new GraphQLError(
@@ -250,6 +260,7 @@ export function executeQueryOrMutationOrSubscriptionEvent(
250260
variableValues,
251261
rootType,
252262
operation.selectionSet,
263+
hideSuggestions,
253264
);
254265

255266
const result = executeRootGroupedFieldSet(
@@ -380,12 +391,16 @@ export function validateExecutionArgs(
380391
// FIXME: https://github.com/graphql/graphql-js/issues/2203
381392
/* c8 ignore next */
382393
const variableDefinitions = operation.variableDefinitions ?? [];
394+
const hideSuggestions = args.hideSuggestions ?? false;
383395

384396
const variableValuesOrErrors = getVariableValues(
385397
schema,
386398
variableDefinitions,
387399
rawVariableValues ?? {},
388-
{ maxErrors: options?.maxCoercionErrors ?? 50 },
400+
{
401+
maxErrors: options?.maxCoercionErrors ?? 50,
402+
hideSuggestions,
403+
},
389404
);
390405

391406
if (variableValuesOrErrors.errors) {
@@ -404,6 +419,7 @@ export function validateExecutionArgs(
404419
typeResolver: typeResolver ?? defaultTypeResolver,
405420
subscribeFieldResolver: subscribeFieldResolver ?? defaultFieldResolver,
406421
perEventExecutor: perEventExecutor ?? executeSubscriptionEvent,
422+
hideSuggestions,
407423
};
408424
}
409425

@@ -549,7 +565,8 @@ function executeField(
549565
path: Path,
550566
): PromiseOrValue<unknown> {
551567
const validatedExecutionArgs = exeContext.validatedExecutionArgs;
552-
const { schema, contextValue, variableValues } = validatedExecutionArgs;
568+
const { schema, contextValue, variableValues, hideSuggestions } =
569+
validatedExecutionArgs;
553570
const fieldNodes = toNodes(fieldDetailsList);
554571
const firstFieldNode = fieldNodes[0];
555572
const fieldName = firstFieldNode.name.value;
@@ -579,6 +596,7 @@ function executeField(
579596
fieldDef.args,
580597
variableValues,
581598
fieldDetailsList[0].fragmentVariableValues,
599+
hideSuggestions,
582600
);
583601

584602
// The resolve function's optional third argument is a context value that
@@ -1514,6 +1532,7 @@ function executeSubscription(
15141532
contextValue,
15151533
operation,
15161534
variableValues,
1535+
hideSuggestions,
15171536
} = validatedExecutionArgs;
15181537

15191538
const rootType = schema.getSubscriptionType();
@@ -1530,6 +1549,7 @@ function executeSubscription(
15301549
variableValues,
15311550
rootType,
15321551
operation.selectionSet,
1552+
hideSuggestions,
15331553
);
15341554

15351555
const firstRootField = groupedFieldSet.entries().next().value as [
@@ -1563,7 +1583,12 @@ function executeSubscription(
15631583

15641584
// Build a JS object of arguments from the field.arguments AST, using the
15651585
// variables scope to fulfill any variable references.
1566-
const args = getArgumentValues(fieldDef, fieldNodes[0], variableValues);
1586+
const args = getArgumentValues(
1587+
fieldDef,
1588+
fieldNodes[0],
1589+
variableValues,
1590+
hideSuggestions,
1591+
);
15671592

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

src/execution/values.ts

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export function getVariableValues(
5555
schema: GraphQLSchema,
5656
varDefNodes: ReadonlyArray<VariableDefinitionNode>,
5757
inputs: { readonly [variable: string]: unknown },
58-
options?: { maxErrors?: number },
58+
options?: { maxErrors?: number; hideSuggestions?: boolean },
5959
): VariableValuesOrErrors {
6060
const errors: Array<GraphQLError> = [];
6161
const maxErrors = options?.maxErrors;
@@ -72,6 +72,7 @@ export function getVariableValues(
7272
}
7373
errors.push(error);
7474
},
75+
options?.hideSuggestions,
7576
);
7677

7778
if (errors.length === 0) {
@@ -89,6 +90,7 @@ function coerceVariableValues(
8990
varDefNodes: ReadonlyArray<VariableDefinitionNode>,
9091
inputs: { readonly [variable: string]: unknown },
9192
onError: (error: GraphQLError) => void,
93+
hideSuggestions?: Maybe<boolean>,
9294
): VariableValues {
9395
const sources: ObjMap<VariableValueSource> = Object.create(null);
9496
const coerced: ObjMap<unknown> = Object.create(null);
@@ -105,7 +107,11 @@ function coerceVariableValues(
105107
const defaultValue = varSignature.defaultValue;
106108
if (defaultValue) {
107109
sources[varName] = { signature: varSignature };
108-
coerced[varName] = coerceDefaultValue(defaultValue, varType);
110+
coerced[varName] = coerceDefaultValue(
111+
defaultValue,
112+
varType,
113+
hideSuggestions,
114+
);
109115
} else if (isNonNullType(varType)) {
110116
const varTypeStr = inspect(varType);
111117
onError(
@@ -149,6 +155,7 @@ function coerceVariableValues(
149155
}),
150156
);
151157
},
158+
hideSuggestions,
152159
);
153160
}
154161

@@ -160,6 +167,7 @@ export function getFragmentVariableValues(
160167
fragmentSignatures: ReadOnlyObjMap<GraphQLVariableSignature>,
161168
variableValues: VariableValues,
162169
fragmentVariableValues?: Maybe<VariableValues>,
170+
hideSuggestions?: Maybe<boolean>,
163171
): VariableValues {
164172
const varSignatures: Array<GraphQLVariableSignature> = [];
165173
const sources = Object.create(null);
@@ -178,6 +186,7 @@ export function getFragmentVariableValues(
178186
varSignatures,
179187
variableValues,
180188
fragmentVariableValues,
189+
hideSuggestions,
181190
);
182191

183192
return { sources, coerced };
@@ -195,15 +204,23 @@ export function getArgumentValues(
195204
def: GraphQLField<unknown, unknown> | GraphQLDirective,
196205
node: FieldNode | DirectiveNode,
197206
variableValues?: Maybe<VariableValues>,
207+
hideSuggestions?: Maybe<boolean>,
198208
): { [argument: string]: unknown } {
199-
return experimentalGetArgumentValues(node, def.args, variableValues);
209+
return experimentalGetArgumentValues(
210+
node,
211+
def.args,
212+
variableValues,
213+
undefined,
214+
hideSuggestions,
215+
);
200216
}
201217

202218
export function experimentalGetArgumentValues(
203219
node: FieldNode | DirectiveNode | FragmentSpreadNode,
204220
argDefs: ReadonlyArray<GraphQLArgument | GraphQLVariableSignature>,
205221
variableValues: Maybe<VariableValues>,
206222
fragmentVariablesValues?: Maybe<VariableValues>,
223+
hideSuggestions?: Maybe<boolean>,
207224
): { [argument: string]: unknown } {
208225
const coercedValues: { [argument: string]: unknown } = {};
209226

@@ -222,6 +239,7 @@ export function experimentalGetArgumentValues(
222239
coercedValues[name] = coerceDefaultValue(
223240
argDef.defaultValue,
224241
argDef.type,
242+
hideSuggestions,
225243
);
226244
} else if (isNonNullType(argType)) {
227245
throw new GraphQLError(
@@ -251,6 +269,7 @@ export function experimentalGetArgumentValues(
251269
coercedValues[name] = coerceDefaultValue(
252270
argDef.defaultValue,
253271
argDef.type,
272+
hideSuggestions,
254273
);
255274
} else if (isNonNullType(argType)) {
256275
throw new GraphQLError(
@@ -277,6 +296,7 @@ export function experimentalGetArgumentValues(
277296
argType,
278297
variableValues,
279298
fragmentVariablesValues,
299+
hideSuggestions,
280300
);
281301
if (coercedValue === undefined) {
282302
// Note: ValuesOfCorrectTypeRule validation should catch this before
@@ -310,6 +330,7 @@ export function getDirectiveValues(
310330
node: { readonly directives?: ReadonlyArray<DirectiveNode> | undefined },
311331
variableValues?: Maybe<VariableValues>,
312332
fragmentVariableValues?: Maybe<VariableValues>,
333+
hideSuggestions?: Maybe<boolean>,
313334
): undefined | { [argument: string]: unknown } {
314335
const directiveNode = node.directives?.find(
315336
(directive) => directive.name.value === directiveDef.name,
@@ -321,6 +342,7 @@ export function getDirectiveValues(
321342
directiveDef.args,
322343
variableValues,
323344
fragmentVariableValues,
345+
hideSuggestions,
324346
);
325347
}
326348
}

src/graphql.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import { execute } from './execution/execute.js';
5959
export interface GraphQLArgs {
6060
schema: GraphQLSchema;
6161
source: string | Source;
62+
hideSuggestions?: Maybe<boolean>;
6263
rootValue?: unknown;
6364
contextValue?: unknown;
6465
variableValues?: Maybe<{ readonly [variable: string]: unknown }>;
@@ -99,6 +100,7 @@ function graphqlImpl(args: GraphQLArgs): PromiseOrValue<ExecutionResult> {
99100
operationName,
100101
fieldResolver,
101102
typeResolver,
103+
hideSuggestions,
102104
} = args;
103105

104106
// Validate Schema
@@ -116,7 +118,9 @@ function graphqlImpl(args: GraphQLArgs): PromiseOrValue<ExecutionResult> {
116118
}
117119

118120
// Validate
119-
const validationErrors = validate(schema, document);
121+
const validationErrors = validate(schema, document, undefined, {
122+
hideSuggestions,
123+
});
120124
if (validationErrors.length > 0) {
121125
return { errors: validationErrors };
122126
}
@@ -131,5 +135,6 @@ function graphqlImpl(args: GraphQLArgs): PromiseOrValue<ExecutionResult> {
131135
operationName,
132136
fieldResolver,
133137
typeResolver,
138+
hideSuggestions,
134139
});
135140
}

0 commit comments

Comments
 (0)