From 480613c747a00cd5d2a8b869ee5e3aba8beab013 Mon Sep 17 00:00:00 2001 From: Yaacov Rydzinski Date: Thu, 22 Aug 2024 14:04:25 +0300 Subject: [PATCH] introduce internal getVariableSignature utility extracted from my fragment arguments scratch branch --- src/execution/values.ts | 24 ++++------ src/utilities/getVariableSignature.ts | 69 +++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 16 deletions(-) create mode 100644 src/utilities/getVariableSignature.ts diff --git a/src/execution/values.ts b/src/execution/values.ts index 5511911c78..1d5b346381 100644 --- a/src/execution/values.ts +++ b/src/execution/values.ts @@ -14,12 +14,12 @@ import { Kind } from '../language/kinds.js'; import { print } from '../language/printer.js'; import type { GraphQLField } from '../type/definition.js'; -import { isInputType, isNonNullType } from '../type/definition.js'; +import { isNonNullType } from '../type/definition.js'; import type { GraphQLDirective } from '../type/directives.js'; import type { GraphQLSchema } from '../type/schema.js'; import { coerceInputValue } from '../utilities/coerceInputValue.js'; -import { typeFromAST } from '../utilities/typeFromAST.js'; +import { getVariableSignature } from '../utilities/getVariableSignature.js'; import { valueFromAST } from '../utilities/valueFromAST.js'; type CoercedVariableValues = @@ -76,24 +76,16 @@ function coerceVariableValues( ): { [variable: string]: unknown } { const coercedValues: { [variable: string]: unknown } = {}; for (const varDefNode of varDefNodes) { - const varName = varDefNode.variable.name.value; - const varType = typeFromAST(schema, varDefNode.type); - if (!isInputType(varType)) { - // Must use input types for variables. This should be caught during - // validation, however is checked again here for safety. - const varTypeStr = print(varDefNode.type); - onError( - new GraphQLError( - `Variable "$${varName}" expected value of type "${varTypeStr}" which cannot be used as an input type.`, - { nodes: varDefNode.type }, - ), - ); + const varSignature = getVariableSignature(schema, varDefNode); + if (varSignature instanceof GraphQLError) { + onError(varSignature); continue; } + const { name: varName, type: varType } = varSignature; if (!Object.hasOwn(inputs, varName)) { - if (varDefNode.defaultValue) { - coercedValues[varName] = valueFromAST(varDefNode.defaultValue, varType); + if (varSignature.hasDefaultValue) { + coercedValues[varName] = varSignature.getDefaultValue(); } else if (isNonNullType(varType)) { const varTypeStr = inspect(varType); onError( diff --git a/src/utilities/getVariableSignature.ts b/src/utilities/getVariableSignature.ts new file mode 100644 index 0000000000..ec531ce914 --- /dev/null +++ b/src/utilities/getVariableSignature.ts @@ -0,0 +1,69 @@ +import { GraphQLError } from '../error/GraphQLError.js'; + +import { print } from '../language/printer.js'; + +import type { GraphQLInputType, GraphQLSchema } from '../type/index.js'; +import { isInputType } from '../type/index.js'; + +import type { ConstValueNode, VariableDefinitionNode } from '../index.js'; + +import { typeFromAST } from './typeFromAST.js'; +import { valueFromAST } from './valueFromAST.js'; + +/** + * A GraphQLVariableSignature is required to coerce a variable value. + * + * @internal + * */ +export class GraphQLVariableSignature { + name: string; + type: GraphQLInputType; + hasDefaultValue: boolean; + _defaultValue: unknown; + + constructor( + name: string, + type: GraphQLInputType, + defaultValueNode: ConstValueNode | undefined, + ) { + this.name = name; + this.type = type; + if (defaultValueNode) { + this.hasDefaultValue = true; + this._defaultValue = () => valueFromAST(defaultValueNode, type); + } else { + this.hasDefaultValue = false; + } + } + + getDefaultValue(): unknown { + if (typeof this._defaultValue === 'function') { + this._defaultValue = this._defaultValue(); + } + return this._defaultValue; + } +} + +export function getVariableSignature( + schema: GraphQLSchema, + varDefNode: VariableDefinitionNode, +): GraphQLVariableSignature | GraphQLError { + const varName = varDefNode.variable.name.value; + const varType = typeFromAST(schema, varDefNode.type); + + if (!isInputType(varType)) { + // Must use input types for variables. This should be caught during + // validation, however is checked again here for safety. + const varTypeStr = print(varDefNode.type); + return new GraphQLError( + `Variable "$${varName}" expected value of type "${varTypeStr}" which cannot be used as an input type.`, + { nodes: varDefNode.type }, + ); + } + + return new GraphQLVariableSignature( + varName, + varType, + varDefNode.defaultValue, + ); +}