From daed81bf820a5acb976cf0a1ad1e9fc4f2407c8c Mon Sep 17 00:00:00 2001 From: Daniel Rearden Date: Thu, 23 Apr 2020 05:00:23 -0400 Subject: [PATCH] Fix visitEnumValue to allow modifying the enum value (#1391) --- CHANGELOG.md | 3 +++ src/test/directives.test.ts | 35 +++++++++++++++++++++++++++++++++++ src/utils/visitSchema.ts | 37 +++++++++++++++++++++++++++++++++---- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b1fdec3be07..04bf1077700 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ### Next +- Fix visitEnumValue to allow modifying the enum value
+ [@danielrearden](https://github.com/danielrearden) in [#1003](https://github.com/ardatan/graphql-tools/pull/1391) + ### 5.0.0 That is a major release where we went through all issues and PRs and got the library back into great shape. diff --git a/src/test/directives.test.ts b/src/test/directives.test.ts index e4010618f16..9cd4e6d39e2 100644 --- a/src/test/directives.test.ts +++ b/src/test/directives.test.ts @@ -1358,6 +1358,41 @@ describe('@directives', () => { ]); }); + test("can modify enum value's value", () => { + const schema = makeExecutableSchema({ + typeDefs: ` + directive @value(new: String!) on ENUM_VALUE + + type Query { + device: Device + } + + enum Device { + PHONE + TABLET + LAPTOP @value(new: "COMPUTER") + }`, + + schemaDirectives: { + value: class extends SchemaDirectiveVisitor { + public visitEnumValue(value: GraphQLEnumValue): GraphQLEnumValue { + return { + ...value, + value: this.args.new, + }; + } + }, + }, + }); + + const Device = schema.getType('Device') as GraphQLEnumType; + expect(Device.getValues().map((value) => value.value)).toEqual([ + 'PHONE', + 'TABLET', + 'COMPUTER', + ]); + }); + test('can swap names of GraphQLNamedType objects', () => { const schema = makeExecutableSchema({ typeDefs: ` diff --git a/src/utils/visitSchema.ts b/src/utils/visitSchema.ts index 282bc684aa0..ffb219eb839 100644 --- a/src/utils/visitSchema.ts +++ b/src/utils/visitSchema.ts @@ -14,6 +14,8 @@ import { isUnionType, isEnumType, isInputType, + GraphQLEnumValue, + GraphQLEnumType, } from 'graphql'; import { @@ -24,6 +26,7 @@ import { SchemaVisitorMap, } from '../Interfaces'; import updateEachKey from '../esUtils/updateEachKey'; +import keyValMap from '../esUtils/keyValMap'; import { healSchema } from './heal'; import { SchemaVisitor } from './SchemaVisitor'; @@ -193,14 +196,40 @@ export function visitSchema( } if (isEnumType(type)) { - const newEnum = callMethod('visitEnum', type); + let newEnum = callMethod('visitEnum', type); if (newEnum != null) { - updateEachKey(newEnum.getValues(), (value) => - callMethod('visitEnumValue', value, { + const newValues: Array = []; + + updateEachKey(newEnum.getValues(), (value) => { + const newValue = callMethod('visitEnumValue', value, { enumType: newEnum, - }), + }); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (newValue) { + newValues.push(newValue); + } + }); + + // Recreate the enum type if any of the values changed + const valuesUpdated = newValues.some( + (value, index) => value !== newEnum.getValues()[index], ); + if (valuesUpdated) { + newEnum = new GraphQLEnumType({ + ...(newEnum as GraphQLEnumType).toConfig(), + values: keyValMap( + newValues, + (value) => value.name, + (value) => ({ + value: value.value, + deprecationReason: value.deprecationReason, + description: value.description, + astNode: value.astNode, + }), + ), + }) as GraphQLEnumType & T; + } } return newEnum;