From f63c2bebe092a5f91b76190d81e469f5c5ba6f11 Mon Sep 17 00:00:00 2001 From: Phil Pluckthun Date: Fri, 14 Oct 2022 11:07:57 +0200 Subject: [PATCH] fix(graphcache): Fix partial optimistic mutation results --- .changeset/lovely-monkeys-wink.md | 5 +++ exchanges/graphcache/src/operations/write.ts | 4 +- exchanges/graphcache/src/store/store.test.ts | 40 ++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 .changeset/lovely-monkeys-wink.md diff --git a/.changeset/lovely-monkeys-wink.md b/.changeset/lovely-monkeys-wink.md new file mode 100644 index 0000000000..490beadc71 --- /dev/null +++ b/.changeset/lovely-monkeys-wink.md @@ -0,0 +1,5 @@ +--- +'@urql/exchange-graphcache': patch +--- + +Fix optimistic mutations containing partial results (`undefined` fields), which previously actually caused a hidden cache miss, which may then affect a subsequent non-optimistic mutation result. diff --git a/exchanges/graphcache/src/operations/write.ts b/exchanges/graphcache/src/operations/write.ts index ccc05f8ee1..f3073a0b6d 100644 --- a/exchanges/graphcache/src/operations/write.ts +++ b/exchanges/graphcache/src/operations/write.ts @@ -259,7 +259,9 @@ const writeSelection = ( // Skip typename fields and assume they've already been written above fieldName === '__typename' || // Fields marked as deferred that aren't defined must be skipped - (fieldValue === undefined && deferRef.current) + // Otherwise, we also ignore undefined values in optimistic updaters + (fieldValue === undefined && + (deferRef.current || (ctx.optimistic && !isRoot))) ) { continue; } diff --git a/exchanges/graphcache/src/store/store.test.ts b/exchanges/graphcache/src/store/store.test.ts index 2c86bc2e69..2f3c8d3506 100644 --- a/exchanges/graphcache/src/store/store.test.ts +++ b/exchanges/graphcache/src/store/store.test.ts @@ -784,6 +784,46 @@ describe('Store with OptimisticMutationConfig', () => { }); }); + it('should be able to optimistically mutate with partial data', () => { + const { dependencies } = writeOptimistic( + store, + { + query: gql` + mutation { + addTodo(id: "0", complete: true, __typename: "Todo") { + id + text + complete + __typename + } + } + `, + }, + 1 + ); + expect(dependencies).toEqual(new Set(['Todo:0'])); + let { data } = query(store, { query: Todos }); + expect(data).toEqual({ + __typename: 'Query', + todos: [ + { + ...todosData.todos[0], + complete: true, + }, + todosData.todos[1], + todosData.todos[2], + ], + }); + + InMemoryData.noopDataState(store.data, 1); + + ({ data } = query(store, { query: Todos })); + expect(data).toEqual({ + __typename: 'Query', + todos: todosData.todos, + }); + }); + describe('Invalidating an entity', () => { it('removes an entity from a list.', () => { store.invalidate(todosData.todos[1]);