Skip to content

Commit

Permalink
fix(graphcache): mutation would cause dependent operations and reexec…
Browse files Browse the repository at this point in the history
…uting operations become the same set (#3665)
  • Loading branch information
xuanduc987 authored Sep 9, 2024
1 parent 76ef485 commit 31d161a
Show file tree
Hide file tree
Showing 3 changed files with 149 additions and 1 deletion.
5 changes: 5 additions & 0 deletions .changeset/tidy-spies-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@urql/exchange-graphcache': patch
---

fix bug that mutation would cause dependent operations and reexecuting operations to become the same set
142 changes: 142 additions & 0 deletions exchanges/graphcache/src/cacheExchange.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -913,6 +913,148 @@ describe('data dependencies', () => {
expect(reexecuteOperation).toHaveBeenCalledTimes(0);
expect(result.mock.calls[0][0]).toHaveProperty('data.author', null);
});

it('mutation does not change number of reexecute request after a query', () => {
const client = createClient({
url: 'http://0.0.0.0',
exchanges: [],
});

const { source: ops$, next: nextOp } = makeSubject<Operation>();

const reexec = vi
.spyOn(client, 'reexecuteOperation')
.mockImplementation(nextOp);

const mutation = gql`
mutation {
updateNode {
__typename
id
}
}
`;

const normalQuery = gql`
{
__typename
item {
__typename
id
}
}
`;

const extendedQuery = gql`
{
__typename
item {
__typename
extended: id
extra @_optional
}
}
`;

const mutationOp = client.createRequestOperation('mutation', {
key: 0,
query: mutation,
variables: undefined,
});

const normalOp = client.createRequestOperation(
'query',
{
key: 1,
query: normalQuery,
variables: undefined,
},
{
requestPolicy: 'cache-and-network',
}
);

const extendedOp = client.createRequestOperation(
'query',
{
key: 2,
query: extendedQuery,
variables: undefined,
},
{
requestPolicy: 'cache-only',
}
);

const response = vi.fn((forwardOp: Operation): OperationResult => {
if (forwardOp.key === 0) {
return {
operation: mutationOp,
data: {
__typename: 'Mutation',
updateNode: {
__typename: 'Node',
id: 'id',
},
},
stale: false,
hasNext: false,
};
} else if (forwardOp.key === 1) {
return {
operation: normalOp,
data: {
__typename: 'Query',
item: {
__typename: 'Node',
id: 'id',
},
},
stale: false,
hasNext: false,
};
} else if (forwardOp.key === 2) {
return {
operation: extendedOp,
data: {
__typename: 'Query',
item: {
__typename: 'Node',
extended: 'id',
extra: 'extra',
},
},
stale: false,
hasNext: false,
};
}

return undefined as any;
});

const forward = (ops$: Source<Operation>): Source<OperationResult> =>
pipe(ops$, map(response), share);

pipe(cacheExchange()({ forward, client, dispatchDebug })(ops$), publish);

nextOp(normalOp);
expect(reexec).toHaveBeenCalledTimes(0);

nextOp(extendedOp);
expect(reexec).toHaveBeenCalledTimes(0);

// re-execute first operation
reexec.mockClear();
nextOp(normalOp);
expect(reexec).toHaveBeenCalledTimes(4);

nextOp(mutationOp);

// re-execute first operation after mutation
reexec.mockClear();
nextOp(normalOp);
expect(reexec).toHaveBeenCalledTimes(4);
});
});

describe('directives', () => {
Expand Down
3 changes: 2 additions & 1 deletion exchanges/graphcache/src/cacheExchange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,9 @@ export const cacheExchange =
// Upon completion, all dependent operations become reexecuting operations, preventing
// them from reexecuting prior operations again, causing infinite loops
const _reexecutingOperations = reexecutingOperations;
reexecutingOperations = dependentOperations;
if (operation.kind === 'query') {
(reexecutingOperations = dependentOperations).add(operation.key);
reexecutingOperations.add(operation.key);
}
(dependentOperations = _reexecutingOperations).clear();
}
Expand Down

0 comments on commit 31d161a

Please sign in to comment.