From c9320446817e4c17168a351242e95be8f48c0c6d Mon Sep 17 00:00:00 2001 From: Eddy Nguyen Date: Mon, 16 Dec 2024 19:33:31 +1100 Subject: [PATCH] Remove extraneous UnwrappedObject type --- .../plugins/typescript/resolvers/src/index.ts | 7 - .../typescript/resolvers/src/visitor.ts | 16 +- .../__snapshots__/ts-resolvers.spec.ts.snap | 3 + .../tests/ts-resolvers.federation.spec.ts | 143 ++++++------------ .../utils/plugins-helpers/src/federation.ts | 36 ++--- 5 files changed, 73 insertions(+), 132 deletions(-) diff --git a/packages/plugins/typescript/resolvers/src/index.ts b/packages/plugins/typescript/resolvers/src/index.ts index e949ae972a2..692622a72bb 100644 --- a/packages/plugins/typescript/resolvers/src/index.ts +++ b/packages/plugins/typescript/resolvers/src/index.ts @@ -106,13 +106,6 @@ export type ResolverWithResolve = { const stitchingResolverUsage = `StitchingResolver`; if (visitor.hasFederation()) { - if (visitor.config.wrapFieldDefinitions) { - defsToInclude.push(`export type UnwrappedObject = { - [P in keyof T]: T[P] extends infer R | Promise | (() => infer R2 | Promise) - ? R & R2 : T[P] - };`); - } - defsToInclude.push( `export type ReferenceResolver = ( reference: TReference, diff --git a/packages/plugins/typescript/resolvers/src/visitor.ts b/packages/plugins/typescript/resolvers/src/visitor.ts index a587e67b550..ea4434dfa7e 100644 --- a/packages/plugins/typescript/resolvers/src/visitor.ts +++ b/packages/plugins/typescript/resolvers/src/visitor.ts @@ -7,14 +7,7 @@ import { ParsedResolversConfig, } from '@graphql-codegen/visitor-plugin-common'; import autoBind from 'auto-bind'; -import { - EnumTypeDefinitionNode, - FieldDefinitionNode, - GraphQLSchema, - ListTypeNode, - NamedTypeNode, - NonNullTypeNode, -} from 'graphql'; +import { EnumTypeDefinitionNode, GraphQLSchema, ListTypeNode, NamedTypeNode, NonNullTypeNode } from 'graphql'; import { TypeScriptResolversPluginConfig } from './config.js'; export const ENUM_RESOLVERS_SIGNATURE = @@ -96,13 +89,6 @@ export class TypeScriptResolversVisitor extends BaseResolversVisitor< return `${this.config.immutableTypes ? 'ReadonlyArray' : 'Array'}<${str}>`; } - protected getParentTypeForSignature(node: FieldDefinitionNode) { - if (this._federation.isResolveReferenceField(node) && this.config.wrapFieldDefinitions) { - return 'UnwrappedObject'; - } - return 'ParentType'; - } - NamedType(node: NamedTypeNode): string { return `Maybe<${super.NamedType(node)}>`; } diff --git a/packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap b/packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap index 8783aac2cb1..0e3228d4016 100644 --- a/packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap +++ b/packages/plugins/typescript/resolvers/tests/__snapshots__/ts-resolvers.spec.ts.snap @@ -166,6 +166,7 @@ export type DirectiveResolverFn TResult | Promise; + /** Mapping of union types */ export type ResolversUnionTypes<_RefType extends Record> = ResolversObject<{ ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyOtherType ); @@ -425,6 +426,7 @@ export type DirectiveResolverFn TResult | Promise; + /** Mapping of union types */ export type ResolversUnionTypes<_RefType extends Record> = ResolversObject<{ ChildUnion: ( Omit & { parent?: Types.Maybe<_RefType['MyType']> } ) | ( Types.MyOtherType ); @@ -770,6 +772,7 @@ export type DirectiveResolverFn TResult | Promise; + /** Mapping of union types */ export type ResolversUnionTypes<_RefType extends Record> = ResolversObject<{ ChildUnion: ( Omit & { parent?: Maybe<_RefType['MyType']> } ) | ( MyOtherType ); diff --git a/packages/plugins/typescript/resolvers/tests/ts-resolvers.federation.spec.ts b/packages/plugins/typescript/resolvers/tests/ts-resolvers.federation.spec.ts index 7aae74ee79c..d6f97f1e515 100644 --- a/packages/plugins/typescript/resolvers/tests/ts-resolvers.federation.spec.ts +++ b/packages/plugins/typescript/resolvers/tests/ts-resolvers.federation.spec.ts @@ -85,8 +85,8 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { }); expect(content).toBeSimilarStringTo(` - export type UserResolvers = { - __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; + export type UserResolvers = { + __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; id?: Resolver; name?: Resolver, ParentType, ContextType>; username?: Resolver, ParentType, ContextType>; @@ -95,24 +95,24 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { `); expect(content).toBeSimilarStringTo(` - export type SingleResolvableResolvers = { - __resolveReference?: ReferenceResolver, { __typename: 'SingleResolvable' } & GraphQLRecursivePick, ContextType>; + export type SingleResolvableResolvers = { + __resolveReference?: ReferenceResolver, { __typename: 'SingleResolvable' } & GraphQLRecursivePick, ContextType>; id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(content).toBeSimilarStringTo(` - export type SingleNonResolvableResolvers = { - __resolveReference?: ReferenceResolver, ParentType, ContextType>; + export type SingleNonResolvableResolvers = { + __resolveReference?: ReferenceResolver, FederationType, ContextType>; id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; `); expect(content).toBeSimilarStringTo(` - export type AtLeastOneResolvableResolvers = { - __resolveReference?: ReferenceResolver, { __typename: 'AtLeastOneResolvable' } & GraphQLRecursivePick, ContextType>; + export type AtLeastOneResolvableResolvers = { + __resolveReference?: ReferenceResolver, { __typename: 'AtLeastOneResolvable' } & GraphQLRecursivePick, ContextType>; id?: Resolver; id2?: Resolver; id3?: Resolver; @@ -121,8 +121,8 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { `); expect(content).toBeSimilarStringTo(` - export type MixedResolvableResolvers = { - __resolveReference?: ReferenceResolver, { __typename: 'MixedResolvable' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + export type MixedResolvableResolvers = { + __resolveReference?: ReferenceResolver, { __typename: 'MixedResolvable' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; id?: Resolver; id2?: Resolver; id3?: Resolver; @@ -131,8 +131,8 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { `); expect(content).toBeSimilarStringTo(` - export type MultipleNonResolvableResolvers = { - __resolveReference?: ReferenceResolver, ParentType, ContextType>; + export type MultipleNonResolvableResolvers = { + __resolveReference?: ReferenceResolver, FederationType, ContextType>; id?: Resolver; id2?: Resolver; id3?: Resolver; @@ -211,8 +211,8 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { // User should have __resolveReference because it has resolvable @key (by default) expect(content).toBeSimilarStringTo(` - export type UserResolvers = { - __resolveReference: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; + export type UserResolvers = { + __resolveReference: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; id?: Resolver; name?: Resolver, ParentType, ContextType>; username?: Resolver, ParentType, ContextType>; @@ -222,8 +222,8 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { // SingleResolvable has __resolveReference because it has resolvable: true expect(content).toBeSimilarStringTo(` - export type SingleResolvableResolvers = { - __resolveReference: ReferenceResolver, { __typename: 'SingleResolvable' } & GraphQLRecursivePick, ContextType>; + export type SingleResolvableResolvers = { + __resolveReference: ReferenceResolver, { __typename: 'SingleResolvable' } & GraphQLRecursivePick, ContextType>; id?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; @@ -239,8 +239,8 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { // AtLeastOneResolvable has __resolveReference because it at least one resolvable expect(content).toBeSimilarStringTo(` - export type AtLeastOneResolvableResolvers = { - __resolveReference: ReferenceResolver, { __typename: 'AtLeastOneResolvable' } & GraphQLRecursivePick, ContextType>; + export type AtLeastOneResolvableResolvers = { + __resolveReference: ReferenceResolver, { __typename: 'AtLeastOneResolvable' } & GraphQLRecursivePick, ContextType>; id?: Resolver; id2?: Resolver; id3?: Resolver; @@ -250,8 +250,8 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { // MixedResolvable has __resolveReference and references for resolvable keys expect(content).toBeSimilarStringTo(` - export type MixedResolvableResolvers = { - __resolveReference: ReferenceResolver, { __typename: 'MixedResolvable' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + export type MixedResolvableResolvers = { + __resolveReference: ReferenceResolver, { __typename: 'MixedResolvable' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; id?: Resolver; id2?: Resolver; id3?: Resolver; @@ -305,11 +305,11 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { // User should have it expect(content).toBeSimilarStringTo(` - __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; + __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; `); // Foo shouldn't because it doesn't have @key expect(content).not.toBeSimilarStringTo(` - __resolveReference?: ReferenceResolver, { __typename: 'Book' } & GraphQLRecursivePick, ContextType>; + __resolveReference?: ReferenceResolver, { __typename: 'Book' } & GraphQLRecursivePick, ContextType>; `); }); @@ -345,19 +345,19 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { }); expect(content).toBeSimilarStringTo(` - export type UserResolvers = { - __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; - id?: Resolver, ContextType>; - name?: Resolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; + export type UserResolvers = { + __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; + id?: Resolver, ContextType>; + name?: Resolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; __isTypeOf?: IsTypeOfResolverFn; } `); expect(content).toBeSimilarStringTo(` - export type NameResolvers = { - __resolveReference?: ReferenceResolver, { __typename: 'Name' } & GraphQLRecursivePick, ContextType>; - first?: Resolver, ContextType>; - last?: Resolver, ContextType>; + export type NameResolvers = { + __resolveReference?: ReferenceResolver, { __typename: 'Name' } & GraphQLRecursivePick, ContextType>; + first?: Resolver, ContextType>; + last?: Resolver, ContextType>; __isTypeOf?: IsTypeOfResolverFn; } `); @@ -386,10 +386,10 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { // User should have it expect(content).toBeSimilarStringTo(` - export type UserResolvers = { - __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; - id?: Resolver, ContextType>; - username?: Resolver, { __typename: 'User' } & GraphQLRecursivePick & GraphQLRecursivePick, ContextType>; + export type UserResolvers = { + __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; + id?: Resolver, ContextType>; + username?: Resolver, { __typename: 'User' } & GraphQLRecursivePick & GraphQLRecursivePick, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); @@ -423,9 +423,9 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { }); expect(content).toBeSimilarStringTo(` - export type UserResolvers = { - __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; - username?: Resolver, { __typename: 'User' } & GraphQLRecursivePick & GraphQLRecursivePick, ContextType>; + export type UserResolvers = { + __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; + username?: Resolver, { __typename: 'User' } & GraphQLRecursivePick & GraphQLRecursivePick, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); @@ -456,9 +456,9 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { }); expect(content).toBeSimilarStringTo(` - export type UserResolvers = { - __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; - username?: Resolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; + export type UserResolvers = { + __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; + username?: Resolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); @@ -489,8 +489,8 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { }); expect(content).toBeSimilarStringTo(` - export type UserResolvers = { - __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; + export type UserResolvers = { + __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; name?: Resolver; username?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; @@ -568,10 +568,10 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { // UserResolver should not have a resolver function of name field expect(content).toBeSimilarStringTo(` - export type UserResolvers = { - __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; - id?: Resolver, ContextType>; - name?: Resolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; + export type UserResolvers = { + __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; + id?: Resolver, ContextType>; + name?: Resolver, { __typename: 'User' } & GraphQLRecursivePick, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); @@ -695,10 +695,10 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { // User should have it expect(content).toBeSimilarStringTo(` - export type UserResolvers = { - __resolveReference?: ReferenceResolver, { __typename: 'User' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; - name?: Resolver, { __typename: 'User' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; - username?: Resolver, { __typename: 'User' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + export type UserResolvers = { + __resolveReference?: ReferenceResolver, { __typename: 'User' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + name?: Resolver, { __typename: 'User' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; + username?: Resolver, { __typename: 'User' } & (GraphQLRecursivePick | GraphQLRecursivePick), ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; `); @@ -763,49 +763,6 @@ describe('TypeScript Resolvers Plugin + Apollo Federation', () => { expect(content).not.toContain('GraphQLScalarType'); }); - describe('When field definition wrapping is enabled', () => { - it('should add the UnwrappedObject type', async () => { - const federatedSchema = /* GraphQL */ ` - type User @key(fields: "id") { - id: ID! - } - `; - - const content = await generate({ - schema: federatedSchema, - config: { - federation: true, - wrapFieldDefinitions: true, - }, - }); - - expect(content).toBeSimilarStringTo(`type UnwrappedObject = {`); - }); - - it('should add UnwrappedObject around ParentType for __resloveReference', async () => { - const federatedSchema = /* GraphQL */ ` - type User @key(fields: "id") { - id: ID! - } - `; - - const content = await generate({ - schema: federatedSchema, - config: { - federation: true, - wrapFieldDefinitions: true, - }, - }); - - // __resolveReference should be unwrapped - expect(content).toBeSimilarStringTo(` - __resolveReference?: ReferenceResolver, { __typename: 'User' } & GraphQLRecursivePick, {"id":true}>, ContextType>; - `); - // but ID should not - expect(content).toBeSimilarStringTo(`id?: Resolver`); - }); - }); - describe('meta - generates federation meta correctly', () => { const federatedSchema = /* GraphQL */ ` scalar _FieldSet diff --git a/packages/utils/plugins-helpers/src/federation.ts b/packages/utils/plugins-helpers/src/federation.ts index 685150e6c10..4da2e33e1c1 100644 --- a/packages/utils/plugins-helpers/src/federation.ts +++ b/packages/utils/plugins-helpers/src/federation.ts @@ -174,30 +174,32 @@ export class ApolloFederation { const { resolvableKeyDirectives } = objectTypeFederationDetails; - if (resolvableKeyDirectives.length) { - const outputs: string[] = [`{ __typename: '${parentType.name}' } &`]; + if (resolvableKeyDirectives.length === 0) { + return federationTypeSignature; + } - // Look for @requires and see what the service needs and gets - const requires = getDirectivesByName('requires', fieldNode).map(this.extractFieldSet); - const requiredFields = this.translateFieldSet(merge({}, ...requires), federationTypeSignature); + const outputs: string[] = [`{ __typename: '${parentType.name}' } &`]; - // @key() @key() - "primary keys" in Federation - const primaryKeys = resolvableKeyDirectives.map(def => { - const fields = this.extractFieldSet(def); - return this.translateFieldSet(fields, federationTypeSignature); - }); + // Look for @requires and see what the service needs and gets + const requires = getDirectivesByName('requires', fieldNode).map(this.extractFieldSet); + const requiredFields = this.translateFieldSet(merge({}, ...requires), federationTypeSignature); - const [open, close] = primaryKeys.length > 1 ? ['(', ')'] : ['', '']; + // @key() @key() - "primary keys" in Federation + const primaryKeys = resolvableKeyDirectives.map(def => { + const fields = this.extractFieldSet(def); + return this.translateFieldSet(fields, federationTypeSignature); + }); - outputs.push([open, primaryKeys.join(' | '), close].join('')); + const [open, close] = primaryKeys.length > 1 ? ['(', ')'] : ['', '']; - // include required fields - if (requires.length) { - outputs.push(`& ${requiredFields}`); - } + outputs.push([open, primaryKeys.join(' | '), close].join('')); - return outputs.join(' '); + // include required fields + if (requires.length) { + outputs.push(`& ${requiredFields}`); } + + return outputs.join(' '); } return parentTypeSignature;