-
Notifications
You must be signed in to change notification settings - Fork 1.4k
[resolvers][federation] Fix fields or types being wrong generated when marked with @external #10287
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: federation-fixes
Are you sure you want to change the base?
Conversation
🦋 Changeset detectedLatest commit: 78bbdb9 The changes in this PR will be included in the next version bump. This PR includes changesets to release 10 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
// A ObjectTypeDefinitionNode's directive looks like `{ kind: 'Directive', name: 'external', arguments: [] }` | ||
// However, other directives looks like `{ kind: 'Directive', name: { kind: 'Name', value: 'external' }, arguments: [] }` | ||
// Therefore, we need to check for both `d.name.value` and d.name | ||
return d.name.value === name || (d.name as unknown as string) === name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an observation from running unit tests. I'm not sure right now if this is a bug in graphql
lib or we did something in our plugins that caused this. Either way, I'm putting this in first to unblock this PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ddfa8e3
to
fbab7d6
Compare
b0b7e86
to
0b0c9bf
Compare
1a64f6d
to
6a2bca7
Compare
fbab7d6
to
7949e63
Compare
f1a4aab
to
b03b692
Compare
6a2bca7
to
30ac893
Compare
b03b692
to
9d6c170
Compare
packages/plugins/other/visitor-plugin-common/src/base-resolvers-visitor.ts
Show resolved
Hide resolved
@@ -62,7 +62,6 @@ describe('customDirectives.sematicNonNull', () => { | |||
nonNullableListWithNonNullableItemLevel0?: Resolver<Array<ResolversTypes['String']>, ParentType, ContextType>; | |||
nonNullableListWithNonNullableItemLevel1?: Resolver<Array<ResolversTypes['String']>, ParentType, ContextType>; | |||
nonNullableListWithNonNullableItemBothLevels?: Resolver<Array<ResolversTypes['String']>, ParentType, ContextType>; | |||
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a new test from master
.
__isTypeOf
is not required here after this PR in the feature branch: #10283
// FIXME: `CompanyResolvers` should only have taxCode resolver because it is part of the `@provides` directive in `Book.editor`, even if the whole `Company` type is marked with @external | ||
// expect(content).toBeSimilarStringTo(` | ||
// export type CompanyResolvers<ContextType = any, ParentType extends ResolversParentTypes['Company'] = ResolversParentTypes['Company']> = { | ||
// taxCode?: Resolver<ResolversTypes['String'], ParentType, ContextType>; | ||
// }; | ||
// `); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel this edge case is quite hard to implement, will come back in another PR, or maybe after the major version bump.
return getDirectivesByName('external', node).length > 0; | ||
} | ||
|
||
private hasProvides(objectType: ObjectTypeDefinitionNode | GraphQLObjectType, node: FieldDefinitionNode): boolean { | ||
const fields = this.providesMap[isObjectType(objectType) ? objectType.name : objectType.name.value]; | ||
private hasProvides(node: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode, fieldName: string): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note for the future: I find allowing both types (e.g. GraphQLObjectType
) and nodes (e.g. ObjectTypeDefinitionNode
) can get confusing very quickly.
Maybe we should just only accept nodes in the future?
@@ -410,7 +443,7 @@ export class ApolloFederation { | |||
for (const field of Object.values(objectType.getFields())) { | |||
const provides = getDirectivesByName('provides', field.astNode) | |||
.map(extractReferenceSelectionSet) | |||
.reduce((prev, curr) => [...prev, ...Object.keys(curr)], []); | |||
.reduce((prev, curr) => [...prev, ...Object.keys(curr)], []); // FIXME: this is not taking into account nested selection sets e.g. `company { taxCode }` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is for this test here: https://github.com/dotansimha/graphql-code-generator/pull/10287/files#r2084481189
// FIXME: this Name method causes a lot of type inconsistencies | ||
// because the type of nodes no longer matches the `graphql-js` types | ||
// So, we should update this and remove any relevant `as any as string` or `as unknown as string` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drive-by put a FIXME here, so we remember why we need to do as any as string
in a lot of places, so we can fix it later.
const hasArguments = node.arguments && node.arguments.length > 0; | ||
const declarationKind = 'type'; | ||
|
||
return (parentName, avoidResolverOptionals) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is used to print field definition. We need more details when we handle fields.
So, this now returns the original node, etc. as part of the result object. We might return more things in the future.
Description
When a field or type is marked with
@external
, the resolver should not be generated (unless part of@provides
). This PR takes care of the following scenarios:@external
, do not generate it@external
, the object type's resolvers signature must still useParentType
for its first param@external
, do not generate the type@external
, do not generate the type@external
, but the object type itself is marked with@external
, what happens? (PlaceOfBirth
in the test setup)User.placeOfBirth
points to the basePlaceOfBirth
, i.e. we don't need to generatePlaceOfBirthResolvers
because it is unused.@provides
in play? (Company
in the test setup)@provides
Related #10206
Type of change
Please delete options that are not relevant.
How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration