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): Fix extra variables regression (#3356)

authored by

Phil Pluckthun and committed by
GitHub
ddbc3dc3 344b5441

+136 -22
+5
.changeset/odd-parrots-fix.md
··· 1 + --- 2 + '@urql/exchange-graphcache': patch 3 + --- 4 + 5 + Fix extra variables in mutation results regressing by a change made in [#3317](https://github.com/urql-graphql/urql/pull/3317). The original operation wasn't being preserved anymore.
+111
exchanges/graphcache/src/cacheExchange.test.ts
··· 1260 1260 }); 1261 1261 }); 1262 1262 1263 + describe('extra variables', () => { 1264 + it('allows extra variables to be applied to updates', () => { 1265 + vi.useFakeTimers(); 1266 + 1267 + const mutation = gql` 1268 + mutation TestMutation($test: Boolean) { 1269 + test(test: $test) { 1270 + id 1271 + } 1272 + } 1273 + `; 1274 + 1275 + const mutationData = { 1276 + __typename: 'Mutation', 1277 + test: { 1278 + __typename: 'Author', 1279 + id: '123', 1280 + }, 1281 + }; 1282 + 1283 + const client = createClient({ 1284 + url: 'http://0.0.0.0', 1285 + exchanges: [], 1286 + }); 1287 + 1288 + const { source: ops$, next } = makeSubject<Operation>(); 1289 + 1290 + const opQuery = client.createRequestOperation('query', { 1291 + key: 1, 1292 + query: queryOne, 1293 + variables: undefined, 1294 + }); 1295 + 1296 + const opMutation = client.createRequestOperation('mutation', { 1297 + key: 2, 1298 + query: mutation, 1299 + variables: { 1300 + test: true, 1301 + extra: 'extra', 1302 + }, 1303 + }); 1304 + 1305 + const response = vi.fn((forwardOp: Operation): OperationResult => { 1306 + if (forwardOp.key === 1) { 1307 + return { ...queryResponse, operation: forwardOp, data: queryOneData }; 1308 + } else if (forwardOp.key === 2) { 1309 + return { 1310 + ...queryResponse, 1311 + operation: forwardOp, 1312 + data: mutationData, 1313 + }; 1314 + } 1315 + 1316 + return undefined as any; 1317 + }); 1318 + 1319 + const result = vi.fn(); 1320 + const forward: ExchangeIO = ops$ => 1321 + pipe(ops$, delay(3), map(response), share); 1322 + 1323 + const optimistic = { 1324 + test: vi.fn() as any, 1325 + }; 1326 + 1327 + const updates = { 1328 + Mutation: { 1329 + test: vi.fn() as any, 1330 + }, 1331 + }; 1332 + 1333 + pipe( 1334 + cacheExchange({ optimistic, updates })({ 1335 + forward, 1336 + client, 1337 + dispatchDebug, 1338 + })(ops$), 1339 + filter(x => x.operation.kind === 'mutation'), 1340 + tap(result), 1341 + publish 1342 + ); 1343 + 1344 + next(opQuery); 1345 + vi.runAllTimers(); 1346 + expect(response).toHaveBeenCalledTimes(1); 1347 + expect(result).toHaveBeenCalledTimes(0); 1348 + 1349 + next(opMutation); 1350 + vi.advanceTimersByTime(1); 1351 + 1352 + expect(response).toHaveBeenCalledTimes(1); 1353 + expect(result).toHaveBeenCalledTimes(0); 1354 + expect(optimistic.test).toHaveBeenCalledTimes(1); 1355 + 1356 + expect(optimistic.test.mock.calls[0][2].variables).toEqual({ 1357 + test: true, 1358 + extra: 'extra', 1359 + }); 1360 + 1361 + vi.runAllTimers(); 1362 + 1363 + expect(response).toHaveBeenCalledTimes(2); 1364 + expect(result).toHaveBeenCalledTimes(1); 1365 + expect(updates.Mutation.test).toHaveBeenCalledTimes(2); 1366 + 1367 + expect(updates.Mutation.test.mock.calls[1][3].variables).toEqual({ 1368 + test: true, 1369 + extra: 'extra', 1370 + }); 1371 + }); 1372 + }); 1373 + 1263 1374 describe('custom resolvers', () => { 1264 1375 it('follows resolvers on initial write', () => { 1265 1376 const client = createClient({
+20 -22
exchanges/graphcache/src/cacheExchange.ts
··· 143 143 144 144 // This registers queries with the data layer to ensure commutativity 145 145 const prepareForwardedOperation = (operation: Operation) => { 146 + let optimistic = false; 146 147 if (operation.kind === 'query') { 147 148 // Pre-reserve the position of the result layer 148 149 reserveLayer(store.data, operation.key); ··· 155 156 // Mark operation layer as done 156 157 noopDataState(store.data, operation.key); 157 158 return operation; 158 - } 159 - 160 - const query = formatDocument(operation.query); 161 - operation = makeOperation( 162 - operation.kind, 163 - { 164 - key: operation.key, 165 - query, 166 - variables: operation.variables 167 - ? filterVariables(getMainOperation(query), operation.variables) 168 - : operation.variables, 169 - }, 170 - { ...operation.context } 171 - ); 172 - 173 - if ( 159 + } else if ( 174 160 operation.kind === 'mutation' && 175 161 operation.context.requestPolicy !== 'network-only' 176 162 ) { ··· 187 173 if (dependencies.size) { 188 174 // Update blocked optimistic dependencies 189 175 for (const dep of dependencies.values()) blockedDependencies.add(dep); 190 - 191 176 // Store optimistic dependencies for update 192 177 optimisticKeysToDependencies.set(operation.key, dependencies); 193 - 194 178 // Update related queries 195 179 const pendingOperations: Operations = new Set(); 196 180 collectPendingOperations(pendingOperations, dependencies); 197 181 executePendingOperations(operation, pendingOperations, true); 198 - 199 182 // Mark operation as optimistic 200 - operation.context.optimistic = true; 183 + optimistic = true; 201 184 } 202 185 } 203 186 204 - return operation; 187 + return makeOperation( 188 + operation.kind, 189 + { 190 + key: operation.key, 191 + query: formatDocument(operation.query), 192 + variables: operation.variables 193 + ? filterVariables( 194 + getMainOperation(operation.query), 195 + operation.variables 196 + ) 197 + : operation.variables, 198 + }, 199 + { ...operation.context, optimistic } 200 + ); 205 201 }; 206 202 207 203 // This updates the known dependencies for the passed operation ··· 250 246 result: OperationResult, 251 247 pendingOperations: Operations 252 248 ): OperationResult => { 253 - const { operation } = result; 249 + // Retrieve the original operation to get unfiltered variables 250 + const operation = 251 + operations.get(result.operation.key) || result.operation; 254 252 if (operation.kind === 'mutation') { 255 253 // Collect previous dependencies that have been written for optimistic updates 256 254 const dependencies = optimisticKeysToDependencies.get(operation.key);