-
As part of making our app offline-first, we're adding optimistic functionality to all mutations. I'm confused how to handle delivering an optimistic update when both the input arguments and the result are dynamic Consider the following mutation: gql`
mutation UpdateItem($id: ID!, $name: String, $amount: Int) {
updateItem(id: $id, name: $name, amount: $amount) {
id
name
amount
}
}
`; The consumer may choose to only update the const graphcache = cacheExchange({
optimistic: {
updateItem: (parent, { id, name, amount }, cache) => {
const existingItem = cache.readFragment(
gql`
fragment _ on Item {
id
name
amount
}
`,
{ __typename: 'Item', id }
);
return {
__typename: 'Item',
id,
name: name ?? existingItem?.name,
amount: amount ?? existingItem?.amount,
};
},
},
}); The API is not super convenient, but so far so good. Now what happens if a consumer executes this mutation: gql`
mutation UpdateItem2($id: ID!, $name: String, $amount: Int) {
updateItem(id: $id, name: $name, amount: $amount) {
id
name
amount
store {
id
itemCount
warehouse {
id
itemCount
}
}
and {
tons {
of {
nested {
fields {
wow
}
}
}
}
}
}
}
`; It seems impossible to write an optimistic updater that Just Works? You'd have to have an intimate (and brittle) knowledge of every field your consumer might ask for, as well as traverse your entire graph with lots of The optimistic updater page in the docs is very simplistic, and doesn't talk about this problem. Am I misunderstanding something? Initially, I thought this problem would be easily solved by composing all the consumer's fragments, like: const graphcache = cacheExchange({
optimistic: {
updateItem: (parent, { id, name, amount }, cache) => {
const existingItem = cache.readFragment(
gql`
fragment _ on Item {
...UpdateItem1Fragment
...UpdateItem2Fragment
}
`,
{ __typename: 'Item', id }
);
return {
...existingItem,
__typename: 'Item',
id,
name: name ?? existingItem?.name,
amount: amount ?? existingItem?.amount,
};
},
},
}); However, this also falls apart when you get into modifying relationships, let's expand on our mutation even more and add gql`
mutation UpdateItem3($id: ID!, $name: String, $amount: Int, $storeIds: [ID!]) {
updateItem(id: $id, name: $name, amount: $amount) {
id
name
amount
store {
id
itemCount
warehouse {
id
itemCount
}
}
and {
tons {
of {
nested {
fields {
wow
}
}
}
}
}
}
}
`; now our optimistic updater looks like:
I'm actually not sure how to write this. I guess you'd have to query every With schema-awareness, the cache already knows all relationships of an const graphcache = cacheExchange({
optimistic: {
updateItem: (parent, { id, name, amount }, cache) => {
const existingItemWithAllKnownRelationships = cache.Item.get(id);
return {
...existingItemWithAllKnownRelationships,
name: name ?? existingItemWithAllKnownRelationships?.name ?? '',
amount: amount ?? existingItemWithAllKnownRelationships?.amount ?? 0,
};
},
},
}); As it stands, I'm not really sure how to go about writing complex optimistic updaters. Any advice? |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 1 reply
-
There's a bit of a missing piece here, which I wanted to address a while ago. There should indeed be two things in the optimistic API that we currently don't support:
So, long story short, currently you do need a lot of knowledge if you want to return a complete result. However, it's actually completely safe to leave out fields that aren't part of your keyable fields. We just warn you about this field once and then skip it, but it doesn't necessarily break anything |
Beta Was this translation helpful? Give feedback.
-
@kitten is this true even if the field is marked as nullable? Won't an optimistic response that's missing an already-cached nullable field end up erroneously setting that field to null? |
Beta Was this translation helpful? Give feedback.
There's a bit of a missing piece here, which I wanted to address a while ago. There should indeed be two things in the optimistic API that we currently don't support:
So, long story short, currently you do need a lot of knowledge if you want to return a complete result. However, it's actually completely saf…