-
Notifications
You must be signed in to change notification settings - Fork 10.3k
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
Share union type instances #9052
Share union type instances #9052
Conversation
Field names are not necessary, since createTypeName is used
type = new GraphQLUnionType({ | ||
name: createTypeName( | ||
`Union_${key}_${fields | ||
type = unionTypes.find(type => |
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.
let's make unionTypes
an object/map so we don't need to find type in array.
map keys could be name of type, so first thing here is to generate typeName:
const typeName = `Union_${key}_${fields.map(f => f.name).sort().join(`__`)
check if that typeName is already in our map and return it of it is
if it's not create type and set our new type in our map
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've made unionTypes
an object, so union type instances can be shared on a per-key basis. The value still needs to be an array though (and we still need to use .find
on it), because of this use-case:
- A node type contains a union type on the field with the key
content
; - Another node type also contains a union type on the
content
field, but it contains different node types for the children.
In this case, we do not want to share the union type. We want to verify that it actually contains the same node types.
In case you hadn't already noticed, I've changed the name of the union type to exclude all fields names. This way the union type name doesn't change when you the data structure for the children change (in case of WordPress: adding or removing an ACF layout).
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.
Right, that's why object/map key would need to include field type names and not just field key
.
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've been thinking about this, but I think there's an issue with using the field type names as a key. The reason behind this, is that the schema is updated when bootstrapping Gatsby. On bootstrap, the schema is re-created.
If we are using the field names as a key, the same union type instance that is created during initial schema creation, is also used when the schema is updated. The problem here is that the union type defines which child node types it has, which are in turn registered as fields during schema creation (in GraphQLSchema
).
Since the 'old' union type (and its child node types) are used, the schema tries to create the child node type for both the old union type and the new child node type during schema creation. Since GraphQL's JS implementation checks for type names being the exact same type (and compares the object itself instead of just the names), this error would be thrown.
This is why comparing the objects using _.isEqual
does work, since they are not equal and a new union type is actually created when updating the schema (which it should). I think we have two options:
- Resetting the
unionTypes
map when starting to construct schema (as you proposed forseenNames
) - Keep comparing types using
.find
and_.isEqual
Do you have any other ideas? Which option has your preference?
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.
We can clear that map when we start (re)building schema (in schema/index.js
)
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.
Thanks for your reply. I've updated the PR and converted to a Map
for ease of clearing the union types map.
I think this is very valid. Let's start with problem of adding |
Thanks for your feedback. I think you're right about the It might be worth noting that this PR will also break the use of union types in the same way, but they currently already break whenever the data structure is updated or whenever another type is unnecessarily created for a different node type (incrementing If you agree with the key-based approach, I think the only part left is to create a test for this change. |
@pieh Sorry for pinging you again, but if you have any tips on how to approach the test (preferably with multiple node types I think), I could do some work on that. |
@haroldangenent Please, ping me whenever you need answers/help! (it's just sometimes hard for me to keep up with multiple open PRs, so definitely my bad) this is very basic test that we can add - haroldangenent#1 additional tests would be good to check if same union type is being used if keys in field/field2 would be different would be different |
add basic test for reusing union type
@pieh Thanks for your response and PR. Your test really helped me to get going, I've added tests for several cases, including consistent naming of the union type to ensure it doesn't break on a future (minor) release. In order to do test this properly, I've converted the Let me know what you think! |
Yeah, we will definitely change that for next major release (as it will be breaking change) - in general a lot plans around schema improvements, but need to keep it as is for now :( I think this looks good, will give it more thorough review tomorrow |
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.
Thanks @haroldangenent!
Holy buckets, @haroldangenent — we just merged your PR to Gatsby! 💪💜 Gatsby is built by awesome people like you. Let us say “thanks” in two ways:
If there’s anything we can do to help, please don’t hesitate to reach out to us: tweet at @gatsbyjs and we’ll come a-runnin’. Thanks again! |
Hello, Gatsby team 👋
I hope to get some feedback on this PR. Let's dive in. Currently, union types are named as follows:
createTypeName
).This causes union types to not be very reliable for usage in GraphQL queries (and not pretty, such as
unionContentPostNodeWordPressAcfImageWordPressAcfText_2
for a WordPress flexible content field).This issue is mentioned in #4074 (comment) and is the root of the cause of this problem: #8615. This PR takes a first shot at naming union types more consistently.
createTypeName
and updated schema: BecausecreateTypeName
is used (that stores all seen names in memory), the field name still gets incremented. This ensures a unique union type, when the same key is used for different child-node types. However, because schema is updated during bootstrap (for theSitePage
node), all fields usingcreateTypeName
end on_2
. While this never changes, this makes it seem less reliable for developers trying to use the field. Maybe this is out of scope, but would there be a way to fix this issue? If you have any pointers on where to start, that would be great.listNode
is queried).Thanks!