-
Notifications
You must be signed in to change notification settings - Fork 396
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
fix(graphql): avoid partial field declarations from inherited metadata with cli plugin #3270
fix(graphql): avoid partial field declarations from inherited metadata with cli plugin #3270
Conversation
…a with cli plugin The former logic was accessing the inherited metadata factory, I guess when the current class didn't have one. The parent class could have fields that the plugin cannot determine, and are explicitly declared with `@Field` decorators. The partial info & the type from decorator are merged together for that base type. But here when the subclass was redefining this field it only had partial info, no type. This caused the complication logic to fail, because the `typeFn` would be missing. Instead, we only want to look for the _own_ metadata factory, and ignore if there is none. Just to note: inherited fields are merged elsewhere (in factories), so this doesn't need to try.
packages/graphql/lib/schema-builder/storages/type-metadata.storage.ts
Outdated
Show resolved
Hide resolved
} | ||
seen.add(prototype.constructor); | ||
|
||
const metadata = Object.getOwnPropertyDescriptor( |
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.
question: any specific reason why we use getOwnPropertyDescriptor
now?
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.
Yes this is basically the fix. We only want the metadata factory from the referenced class. Static properties (of ES6 classes) are inherited, and we want to avoid this here.
This could be an Object.hasOwn
check. I used this to do that check and get the own value at the same time so the constant METADATA_FACTORY_NAME
only had to be referenced once.
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 clarified the PR description. The minimal reproduction is still a lot of boilerplate.
I looked at updating tests, but I didn't find a spot where I could using the plugin metadata and instantiate a GraphQLModule
using it.
What would you like me to do?
79c9e56
to
690dfeb
Compare
Bump 🙏 |
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Issue Number: N/A
The former logic was accessing the inherited metadata factory, I guess when the current class didn't have one.
The parent class could have fields that the plugin cannot determine, and are explicitly declared with
@Field
decorators.The partial info & the type from decorator are merged together for that base type.
But here when the subclass was redefining this field it only had partial info, no type.
This caused the complication logic to fail, because the
typeFn
would be missing.Instead, we only want to look for the own metadata factory, and ignore if there is none.
Just to note: inherited fields are merged elsewhere (in factories), so this doesn't need to try.
A minimal reproduction is
With this example,
Person
&Entity
will have metadata loaded /_GRAPHQL_METADATA_FACTORY
property assigned.The problem is that
resolves to
Entity
's_GRAPHQL_METADATA_FACTORY
💥 , but it's registered as theLivingBeingClass
type.⭐ The logic should be to skip because no
_GRAPHQL_METADATA_FACTORY
is declared forLivingBeingClass
.Entity
's metadata is merged with the decorator, so the plugin doesn't provide thetype
, but the decorator does.However,
LivingBeingClass
does not have this field metadata merged since theEntity.id
decorator is not its own (guessing on why).The factories throw because
LivingBeingClass.id
does not have atype
even though its parent class does.The metadata should ignore this field for this intermediate class since it doesn't do anything with it - it just inherits.
What is the new behavior?
Error is avoided. Fields are still merged/inherited as expected.
Does this PR introduce a breaking change?
Other information
I also added a check to avoid merging metadata for common parents.
i.e.
TypeMetadataStorage.addClassFieldMetadata
would previous be called forEntity.id
for every concrete type extendingEntity
. Which is redundant work after the first time.