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 teardown operation breaking commutative layers (#588)

* Fix teardown operations destroying commutative order

* Add changeset

* Expand added data test

authored by

Phil Plückthun and committed by
GitHub
890040a8 82566f50

+38 -9
+5
.changeset/two-guests-hide.md
··· 1 + --- 2 + '@urql/exchange-graphcache': patch 3 + --- 4 + 5 + Fix teardown events leading to broken commutativity
+13 -7
exchanges/graphcache/src/cacheExchange.test.ts
··· 10 10 pipe, 11 11 map, 12 12 mergeMap, 13 + filter, 13 14 fromValue, 14 15 makeSubject, 15 16 tap, ··· 1043 1044 data = result.data; 1044 1045 }); 1045 1046 1046 - pipe( 1047 - cacheExchange()({ forward: ops$ => pipe(ops$, mergeMap(result)), client })( 1048 - ops$ 1049 - ), 1050 - tap(output), 1051 - publish 1052 - ); 1047 + const forward = (ops$: Source<Operation>): Source<OperationResult> => 1048 + pipe( 1049 + ops$, 1050 + filter(op => op.operationName !== 'teardown'), 1051 + mergeMap(result) 1052 + ); 1053 + 1054 + pipe(cacheExchange()({ forward, client })(ops$), tap(output), publish); 1053 1055 1054 1056 next(client.createRequestOperation('query', { key: 1, query })); 1055 1057 next(client.createRequestOperation('query', { key: 2, query })); 1058 + 1059 + // This shouldn't have any effect: 1060 + next(client.createRequestOperation('teardown', { key: 2, query })); 1061 + 1056 1062 next(client.createRequestOperation('query', { key: 3, query })); 1057 1063 1058 1064 jest.advanceTimersByTime(5);
+2 -2
exchanges/graphcache/src/cacheExchange.ts
··· 29 29 import { query, write, writeOptimistic } from './operations'; 30 30 import { hydrateData } from './store/data'; 31 31 import { makeDict } from './helpers/dict'; 32 - import { Store, clearLayer, reserveLayer } from './store'; 32 + import { Store, noopDataState, clearLayer, reserveLayer } from './store'; 33 33 34 34 import { 35 35 UpdatesConfig, ··· 174 174 if (operation.operationName === 'query') { 175 175 reserveLayer(store.data, operation.key); 176 176 } else if (operation.operationName === 'teardown') { 177 - clearLayer(store.data, operation.key); 177 + noopDataState(store.data, operation.key); 178 178 } 179 179 }; 180 180
+11
exchanges/graphcache/src/store/data.test.ts
··· 323 323 324 324 expect(data.optimisticOrder).toEqual([]); 325 325 }); 326 + 327 + it('allows noopDataState to clear layers only if necessary', () => { 328 + InMemoryData.reserveLayer(data, 1); 329 + InMemoryData.reserveLayer(data, 2); 330 + 331 + InMemoryData.noopDataState(data, 2); 332 + expect(data.optimisticOrder).toEqual([2, 1]); 333 + 334 + InMemoryData.noopDataState(data, 1); 335 + expect(data.optimisticOrder).toEqual([]); 336 + }); 326 337 });
+6
exchanges/graphcache/src/store/data.ts
··· 135 135 } 136 136 }; 137 137 138 + /** Initialises then resets the data state, which may squash this layer if necessary */ 139 + export const noopDataState = (data: InMemoryData, layerKey: number | null) => { 140 + initDataState(data, layerKey); 141 + clearDataState(); 142 + }; 143 + 138 144 /** As we're writing, we keep around all the records and links we've read or have written to */ 139 145 export const getCurrentDependencies = (): Set<string> => { 140 146 invariant(
+1
exchanges/graphcache/src/store/index.ts
··· 1 1 export { 2 2 initDataState, 3 3 clearDataState, 4 + noopDataState, 4 5 reserveLayer, 5 6 clearLayer, 6 7 getCurrentDependencies,