|
urql version & exchanges: Steps to reproduce We are using GraphCache with an However, if the mutation also requests any of those fields, URQL returns a null response for those fields. For example, with the mutation: mutation MyMutation {
updateUserStatus() {
viewer {
statusObj { someField }
}
}
}and the cache exchange: return urqlCacheExchange({
schema: schema as unknown as IntrospectionQuery,
keys: { StatusObjType: () => null },
updates: { Mutation: { updateUserStatus: invalidateStatus } },
});
function invalidateStatus(_data, _variables, cache, info) {
if (!info.optimistic) {
cache.invalidate(getViewerKey(cache), 'statusObj');
}
}
function getViewerKey(cache: Cache): string {
return cache.resolve({ __typename: 'RootQueryType' }, 'viewer') as string;
}...will produce the result Expected behavior While we want to invalidate Put another way, cache-invalidations should only apply to future queries. Actual behavior If a mutation's update configuration invalidates a field returned by that same mutation, the field will is not included in the mutation's response. In a sense, I can rationalize the current behavior – the response is reflective of the current state of the cache. However, my use-case also doesn't seem like it's particularly unique or far-fetched. I want to perform a wide-ranging cache-invalidation after my mutation, but I also still want to know the results of that mutation. (Also, the above explanation only really justifies why As I see it, I can see a few ways that this could be addressed.
|
Replies: 7 comments
|
Noot having a reproduction here makes this a little difficult, but my current suspicion is that both your mutation and queries are referring to a user entity, correct? The problem here seems to me not that the result is changing, which it must consistently according to your schema and config. What I don't understand here is the purpose though of this invalidated field and entity. If you're invalidating it it must either be refetched or is missing, so I'm not sure if invalidating here is the wreong choice? In other words, since I don't understand the meaning and intent of your schema, mutation, and scenario just by looking at the snippet it's hard to reconcile what yoour schema looks like, what the expected behaviour is, and what an alternative may be, if any apply
that's basically the problem I have. If your mutation invalidates this field and also delivers this field, how is that consistent with what's expected? If your mutation is both changing it but also making "its own data invalid" then I don't see how it could deliver the value 😅 Edit: I just wanted to follow up on one statement so we're on one page ✌️
The thing that doesn't make sense to us is two-fold. We only have one target entity here that's being modified and presumably occurs in both the mutation and query. Inherently, to be consistent we may only modify one and the same identity of the entity. I think what I then struggle to understand is, if your mutation has just given you this field, why are you invalidating it? The mutation already delivers it and then you're trying to immediately refetch it? |
|
It seems like I'm having a similar issue, so please don't hesitate to tell me if I need to create my own. I have the following schema provided by strapi graphql, basically notes containing tags. userNotes(
filters: UserNoteFiltersInput
): UserNoteEntityResponseCollection
type UserNoteEntityResponseCollection {
data: [UserNoteEntity!]!
}
type UserNoteEntity {
id: ID
attributes: UserNote
}
type UserNote {
user_tags(...): UserTagRelationResponseCollection
content: String!
}
type UserTagRelationResponseCollection {
data: [UserTagEntity!]!
}
type UserTagEntity {
id: ID
attributes: UserTag
}
type UserTag {
name: String!
description: String
}
and the following query: export const GET_USER_NOTES = gql`
query userNotes {
userNotes {
data {
__typename
id
attributes {
content
user_tags {
data {
id
attributes {
name
}
}
}
}
}
}
}
`
While in a note, I can delete a tag, and I want it to be deleted in every note. deleteUserTag: (result, args, cache, info) => {
cache.invalidate({
__typename: 'UserTagEntity',
id: args.id,
})
},So let's say I'm on note 73, and I delete a tag, the whole user_tags object get deleted for the other notes. {
"userNotes": {
"data": [
{
"__typename": "UserNoteEntity",
"id": "73",
"attributes": {
"content": "super test",
"user_tags": {
"data": [
{
"id": "67",
"attributes": {
"name": "tag_one",
"__typename": "UserTag"
},
"__typename": "UserTagEntity"
},
// correctly deleted
],
"__typename": "UserTagRelationResponseCollection"
},
"__typename": "UserNote"
}
},
{
"__typename": "UserNoteEntity",
"id": "74",
"attributes": {
"content": "Lorem ipsum",
"user_tags": null, // Whole object gets deleted
"__typename": "UserNote"
}
},
{
"__typename": "UserNoteEntity",
"id": "75",
"attributes": {
"content": "Popo",
"user_tags": null, // Whole object gets deleted
"__typename": "UserNote"
}
},
],
"__typename": "UserNoteEntityResponseCollection"
}
} |
|
@bulby97 the whole object didn't get deleted, the If you want to completely evict the entity from an array it will probably be easier to use |
|
@JoviDeCroock thanks for your answer, Is this because I'm using
And ironically, if I disable Using |
|
TBH, I've found partial results to be pretty bothersome to work with. You basically need to assume that any field in your schema could suddenly become nullable at any time, independent of everything else. |
|
You don't have to use Graphcache's schema awareness in that case, but the important bit here is: if you mark an object as nullable, you'll have to expect it to become nullable, no matter whether you use Graphcache or not, since they also represent optional data and error boundaries for resolvers. That said, there's also a proposal for nullability operator for this purpose |
|
I realize this is an old discussion, but I'm having the identical problem as @schmod. As he said, this is a pretty common use-case (update the DB and then return whatever the update was so the client can be informed of the changes). While I can understand conceptually why I'm currently working around this by doing a second fetch to get the updated information but that's more of a work-around when the mutation returns the data we want and isn't an efficient solution. This was marked as the answer but it doesn't provide a path forward on how to fix or adjust the use of |
Noot having a reproduction here makes this a little difficult, but my current suspicion is that both your mutation and queries are referring to a user entity, correct?
The problem here seems to me not that the result is changing, which it must consistently according to your schema and config. What I don't understand here is the purpose though of this invalidated field and entity. If you're invalidating it it must either be refetched or is missing, so I'm not sure if invalidating here is the wreong choice?
In other words, since I don't understand the meaning and intent of your schema, mutation, and scenario just by looking at the snippet it's hard to reconcile what yoour schema looks like,…