From 2cd9b9bc9d5cff922329e2f42e0d433446accc37 Mon Sep 17 00:00:00 2001 From: Byron Wall Date: Mon, 5 Feb 2024 11:09:01 -0500 Subject: [PATCH 1/2] fix(graphql drafts): omit __typename field from built graphql draft moddels when isGraphqlDraft option is passed to transformer --- core/src/builder.spec.ts | 43 ++++++++++++++++++++++++++++++++++++++++ core/src/helpers.ts | 28 ++++++++++++++++++++++++++ core/src/transformer.ts | 7 ++++++- core/src/types.ts | 5 +++++ 4 files changed, 82 insertions(+), 1 deletion(-) diff --git a/core/src/builder.spec.ts b/core/src/builder.spec.ts index be4c555ee..33ef012c7 100644 --- a/core/src/builder.spec.ts +++ b/core/src/builder.spec.ts @@ -506,6 +506,49 @@ describe('building', () => { ], }); }); + it('should omit __typename field when building nested builders and isGraphqlDraft is true', () => { + const teamTransformers = { + graphql: Transformer('graphql', { + buildFields: ['users'], + isGraphqlDraft: true, + }), + }; + const userTransformers = { + graphql: Transformer< + TestExpandedUserReference, + TestExpandedUserReferenceGraphql + >('graphql', { + addFields: () => ({ + __typename: 'User', + }), + isGraphqlDraft: true, + }), + }; + const userBuilder1 = Builder({ + transformers: userTransformers, + }).name('My name'); + const userBuilder2 = Builder({ + transformers: userTransformers, + }).name('My other name'); + const built = Builder({ + transformers: teamTransformers, + }) + .id('my-id') + .users([userBuilder1, userBuilder2]) + .buildGraphql(); + + expect(built).toEqual({ + id: 'my-id', + users: [ + { + name: 'My name', + }, + { + name: 'My other name', + }, + ], + }); + }); }); }); }); diff --git a/core/src/helpers.ts b/core/src/helpers.ts index 880465832..01599070c 100644 --- a/core/src/helpers.ts +++ b/core/src/helpers.ts @@ -28,6 +28,33 @@ const upperFirst = (value: string): string => const lowerFirst = (value: string): string => value.charAt(0).toLowerCase() + value.slice(1); +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function deleteKeyFromObject(inputObject: any, keyToDelete: string) { + for (let [currentObjectKey, currentObjectValue] of Object.entries( + inputObject + )) { + if (currentObjectKey === keyToDelete) { + delete inputObject[keyToDelete]; + } else if (Array.isArray(currentObjectValue)) { + deleteKeyFromObjectInArray(currentObjectValue, keyToDelete); + } else if (isObject(currentObjectValue)) { + deleteKeyFromObject(currentObjectValue, keyToDelete); + } + } +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function deleteKeyFromObjectInArray(inputArray: any[], keyToDelete: string) { + for (let currentIndex = 0; currentIndex < inputArray.length; currentIndex++) { + let currentElement = inputArray[currentIndex]; + if (Array.isArray(currentElement)) { + deleteKeyFromObjectInArray(currentElement, keyToDelete); + } else if (isObject(currentElement)) { + deleteKeyFromObject(currentElement, keyToDelete); + } + } +} + const omitOne = (entity: T, prop: K): Omit => { // eslint-disable-next-line @typescript-eslint/no-unused-vars const { [prop]: deleted, ...newState } = entity; @@ -175,6 +202,7 @@ export { isBuilderFunction, upperFirst, lowerFirst, + deleteKeyFromObject, omitMany, pickMany, convertBuiltNameToTransformName, diff --git a/core/src/transformer.ts b/core/src/transformer.ts index 27d130b23..915661762 100644 --- a/core/src/transformer.ts +++ b/core/src/transformer.ts @@ -1,4 +1,4 @@ -import { buildField, buildFields } from './helpers'; +import { buildField, buildFields, deleteKeyFromObject } from './helpers'; import type { TTransformer, TTransformerOptions, @@ -36,6 +36,11 @@ function Transformer( }; } }); + + if (transformOptions?.isGraphqlDraft) { + /**recursively delete '__typename' field from all built fields in graphql draft */ + deleteKeyFromObject(transformedFields, '__typename'); + } } // The default transformer only allows building nested fields to not diff --git a/core/src/types.ts b/core/src/types.ts index 9ff1d3fa5..884d1518f 100644 --- a/core/src/types.ts +++ b/core/src/types.ts @@ -50,6 +50,11 @@ export type TTransformerOptions = { removeFields?: (keyof Model)[]; replaceFields?: (args: { fields: Model }) => TransformedModel; buildFields?: (keyof Model)[]; + /** When transforming fields for GraphQL draft models, + * this flag removes all "__typename" fields from transformed models + * so that the draft can be used with the API + */ + isGraphqlDraft?: Boolean; }; export interface TTransformer { From 5a234a96e6efc648d300b7c61edeb63c47de30c8 Mon Sep 17 00:00:00 2001 From: Byron Wall Date: Mon, 5 Feb 2024 11:15:21 -0500 Subject: [PATCH 2/2] chore(remove typename): add changeset --- .changeset/unlucky-phones-repair.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/unlucky-phones-repair.md diff --git a/.changeset/unlucky-phones-repair.md b/.changeset/unlucky-phones-repair.md new file mode 100644 index 000000000..68517734c --- /dev/null +++ b/.changeset/unlucky-phones-repair.md @@ -0,0 +1,5 @@ +--- +'@commercetools-test-data/core': minor +--- + +"fix(graphql drafts): omit \_\_typename field from built graphql draft models when isGraphqlDraft option is passed to transformer"