Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(graphcache): mutation would cause dependent operations and reexecuting operations become the same set (#3665)

authored by

Duc Nghiem Xuan and committed by
GitHub
31d161a5 76ef485c

+149 -1
+5
.changeset/tidy-spies-turn.md
··· 1 + --- 2 + '@urql/exchange-graphcache': patch 3 + --- 4 + 5 + fix bug that mutation would cause dependent operations and reexecuting operations to become the same set
+142
exchanges/graphcache/src/cacheExchange.test.ts
··· 913 913 expect(reexecuteOperation).toHaveBeenCalledTimes(0); 914 914 expect(result.mock.calls[0][0]).toHaveProperty('data.author', null); 915 915 }); 916 + 917 + it('mutation does not change number of reexecute request after a query', () => { 918 + const client = createClient({ 919 + url: 'http://0.0.0.0', 920 + exchanges: [], 921 + }); 922 + 923 + const { source: ops$, next: nextOp } = makeSubject<Operation>(); 924 + 925 + const reexec = vi 926 + .spyOn(client, 'reexecuteOperation') 927 + .mockImplementation(nextOp); 928 + 929 + const mutation = gql` 930 + mutation { 931 + updateNode { 932 + __typename 933 + id 934 + } 935 + } 936 + `; 937 + 938 + const normalQuery = gql` 939 + { 940 + __typename 941 + item { 942 + __typename 943 + id 944 + } 945 + } 946 + `; 947 + 948 + const extendedQuery = gql` 949 + { 950 + __typename 951 + item { 952 + __typename 953 + extended: id 954 + extra @_optional 955 + } 956 + } 957 + `; 958 + 959 + const mutationOp = client.createRequestOperation('mutation', { 960 + key: 0, 961 + query: mutation, 962 + variables: undefined, 963 + }); 964 + 965 + const normalOp = client.createRequestOperation( 966 + 'query', 967 + { 968 + key: 1, 969 + query: normalQuery, 970 + variables: undefined, 971 + }, 972 + { 973 + requestPolicy: 'cache-and-network', 974 + } 975 + ); 976 + 977 + const extendedOp = client.createRequestOperation( 978 + 'query', 979 + { 980 + key: 2, 981 + query: extendedQuery, 982 + variables: undefined, 983 + }, 984 + { 985 + requestPolicy: 'cache-only', 986 + } 987 + ); 988 + 989 + const response = vi.fn((forwardOp: Operation): OperationResult => { 990 + if (forwardOp.key === 0) { 991 + return { 992 + operation: mutationOp, 993 + data: { 994 + __typename: 'Mutation', 995 + updateNode: { 996 + __typename: 'Node', 997 + id: 'id', 998 + }, 999 + }, 1000 + stale: false, 1001 + hasNext: false, 1002 + }; 1003 + } else if (forwardOp.key === 1) { 1004 + return { 1005 + operation: normalOp, 1006 + data: { 1007 + __typename: 'Query', 1008 + item: { 1009 + __typename: 'Node', 1010 + id: 'id', 1011 + }, 1012 + }, 1013 + stale: false, 1014 + hasNext: false, 1015 + }; 1016 + } else if (forwardOp.key === 2) { 1017 + return { 1018 + operation: extendedOp, 1019 + data: { 1020 + __typename: 'Query', 1021 + item: { 1022 + __typename: 'Node', 1023 + extended: 'id', 1024 + extra: 'extra', 1025 + }, 1026 + }, 1027 + stale: false, 1028 + hasNext: false, 1029 + }; 1030 + } 1031 + 1032 + return undefined as any; 1033 + }); 1034 + 1035 + const forward = (ops$: Source<Operation>): Source<OperationResult> => 1036 + pipe(ops$, map(response), share); 1037 + 1038 + pipe(cacheExchange()({ forward, client, dispatchDebug })(ops$), publish); 1039 + 1040 + nextOp(normalOp); 1041 + expect(reexec).toHaveBeenCalledTimes(0); 1042 + 1043 + nextOp(extendedOp); 1044 + expect(reexec).toHaveBeenCalledTimes(0); 1045 + 1046 + // re-execute first operation 1047 + reexec.mockClear(); 1048 + nextOp(normalOp); 1049 + expect(reexec).toHaveBeenCalledTimes(4); 1050 + 1051 + nextOp(mutationOp); 1052 + 1053 + // re-execute first operation after mutation 1054 + reexec.mockClear(); 1055 + nextOp(normalOp); 1056 + expect(reexec).toHaveBeenCalledTimes(4); 1057 + }); 916 1058 }); 917 1059 918 1060 describe('directives', () => {
+2 -1
exchanges/graphcache/src/cacheExchange.ts
··· 136 136 // Upon completion, all dependent operations become reexecuting operations, preventing 137 137 // them from reexecuting prior operations again, causing infinite loops 138 138 const _reexecutingOperations = reexecutingOperations; 139 + reexecutingOperations = dependentOperations; 139 140 if (operation.kind === 'query') { 140 - (reexecutingOperations = dependentOperations).add(operation.key); 141 + reexecutingOperations.add(operation.key); 141 142 } 142 143 (dependentOperations = _reexecutingOperations).clear(); 143 144 }