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.

refactor(graphcache): Refactor internal state and data utilities (#3166)

authored by

Phil Pluckthun and committed by
GitHub
06189b5b 6031d913

+69 -96
+4 -3
exchanges/graphcache/src/cacheExchange.ts
··· 24 24 import { _write } from './operations/write'; 25 25 import { addMetadata, toRequestPolicy } from './helpers/operation'; 26 26 import { filterVariables, getMainOperation } from './ast'; 27 + import { Store } from './store/store'; 28 + import { Data, Dependencies, CacheExchangeOpts } from './types'; 29 + 27 30 import { 28 - Store, 29 31 initDataState, 30 32 clearDataState, 31 33 noopDataState, 32 34 hydrateData, 33 35 reserveLayer, 34 - } from './store'; 35 - import { Data, Dependencies, CacheExchangeOpts } from './types'; 36 + } from './store/data'; 36 37 37 38 interface OperationResultWithMeta extends Partial<OperationResult> { 38 39 operation: Operation;
+1 -1
exchanges/graphcache/src/extras/relayPagination.test.ts
··· 2 2 import { it, expect } from 'vitest'; 3 3 import { __initAnd_query as query } from '../operations/query'; 4 4 import { __initAnd_write as write } from '../operations/write'; 5 - import { Store } from '../store'; 5 + import { Store } from '../store/store'; 6 6 import { relayPagination } from './relayPagination'; 7 7 8 8 function itemNode(numItem: number) {
+1 -1
exchanges/graphcache/src/extras/simplePagination.test.ts
··· 2 2 import { it, expect } from 'vitest'; 3 3 import { __initAnd_query as query } from '../operations/query'; 4 4 import { __initAnd_write as write } from '../operations/write'; 5 - import { Store } from '../store'; 5 + import { Store } from '../store/store'; 6 6 import { simplePagination } from './simplePagination'; 7 7 8 8 it('works with forward pagination', () => {
+1 -1
exchanges/graphcache/src/index.ts
··· 1 1 export * from './types'; 2 - export type { Store } from './store'; 2 + export { Store } from './store/store'; 3 3 export { cacheExchange } from './cacheExchange'; 4 4 export { offlineExchange } from './offlineExchange';
+1 -1
exchanges/graphcache/src/operations/invalidate.ts
··· 1 1 import * as InMemoryData from '../store/data'; 2 + import { keyOfField } from '../store/keys'; 2 3 import { FieldArgs } from '../types'; 3 - import { keyOfField } from '../store'; 4 4 5 5 interface PartialFieldInfo { 6 6 fieldKey: string;
+1 -1
exchanges/graphcache/src/operations/query.test.ts
··· 4 4 import { minifyIntrospectionQuery } from '@urql/introspection'; 5 5 import { describe, it, beforeEach, beforeAll, expect } from 'vitest'; 6 6 7 - import { Store } from '../store'; 7 + import { Store } from '../store/store'; 8 8 import { __initAnd_write as write } from './write'; 9 9 import { __initAnd_query as query } from './query'; 10 10
+34 -29
exchanges/graphcache/src/operations/query.ts
··· 27 27 Dependencies, 28 28 } from '../types'; 29 29 30 - import { 31 - Store, 32 - getCurrentOperation, 33 - getCurrentDependencies, 34 - initDataState, 35 - clearDataState, 36 - joinKeys, 37 - keyOfField, 38 - makeData, 39 - ownsData, 40 - } from '../store'; 41 - 30 + import { joinKeys, keyOfField } from '../store/keys'; 31 + import { Store } from '../store/store'; 42 32 import * as InMemoryData from '../store/data'; 43 33 import { warn, pushDebugNode, popDebugNode } from '../helpers/help'; 44 34 ··· 75 65 error?: CombinedError | undefined, 76 66 key?: number 77 67 ): QueryResult => { 78 - initDataState('read', store.data, key); 68 + InMemoryData.initDataState('read', store.data, key); 79 69 const result = _query(store, request, data, error); 80 - clearDataState(); 70 + InMemoryData.clearDataState(); 81 71 return result; 82 72 }; 83 73 ··· 100 90 getFragments(request.query), 101 91 rootKey, 102 92 rootKey, 103 - false, 104 93 error 105 94 ); 106 95 ··· 114 103 // scratch 115 104 const data = 116 105 rootKey !== ctx.store.rootFields['query'] 117 - ? readRoot(ctx, rootKey, rootSelect, input || makeData()) 118 - : readSelection(ctx, rootKey, rootSelect, input || makeData()); 106 + ? readRoot(ctx, rootKey, rootSelect, input || InMemoryData.makeData()) 107 + : readSelection( 108 + ctx, 109 + rootKey, 110 + rootSelect, 111 + input || InMemoryData.makeData() 112 + ); 119 113 120 114 if (process.env.NODE_ENV !== 'production') { 121 115 popDebugNode(); 116 + InMemoryData.getCurrentDependencies(); 122 117 } 123 118 124 119 return { 125 - dependencies: getCurrentDependencies(), 120 + dependencies: InMemoryData.currentDependencies!, 126 121 partial: ctx.partial || !data, 127 122 hasNext: ctx.hasNext, 128 123 data: data || null, ··· 146 141 147 142 let node: FieldNode | void; 148 143 let hasChanged = InMemoryData.currentForeignData; 149 - const output = makeData(input); 144 + const output = InMemoryData.makeData(input); 150 145 while ((node = iterate())) { 151 146 const fieldAlias = getFieldAlias(node); 152 147 const fieldValue = input[fieldAlias]; ··· 274 269 variables || {}, 275 270 fragments, 276 271 typename, 277 - entityKey 272 + entityKey, 273 + undefined 278 274 ); 279 275 280 276 const result = 281 - readSelection(ctx, entityKey, getSelectionSet(fragment), makeData()) || 282 - null; 277 + readSelection( 278 + ctx, 279 + entityKey, 280 + getSelectionSet(fragment), 281 + InMemoryData.makeData() 282 + ) || null; 283 283 284 284 if (process.env.NODE_ENV !== 'production') { 285 285 popDebugNode(); ··· 341 341 let hasNext = false; 342 342 let hasChanged = InMemoryData.currentForeignData; 343 343 let node: FieldNode | void; 344 - const output = makeData(input); 344 + const output = InMemoryData.makeData(input); 345 345 while ((node = iterate()) !== undefined) { 346 346 // Derive the needed data from our node. 347 347 const fieldName = getName(node); ··· 369 369 // The field is a scalar and can be retrieved directly from the result 370 370 dataFieldValue = resultValue; 371 371 } else if ( 372 - getCurrentOperation() === 'read' && 372 + InMemoryData.currentOperation === 'read' && 373 373 resolvers && 374 374 resolvers[fieldName] 375 375 ) { ··· 403 403 ? output[fieldAlias] 404 404 : input[fieldAlias]) as Data, 405 405 dataFieldValue, 406 - ownsData(input) 406 + InMemoryData.ownsData(input) 407 407 ); 408 408 } 409 409 ··· 431 431 ? output[fieldAlias] 432 432 : input[fieldAlias]) as Data, 433 433 resultValue, 434 - ownsData(input) 434 + InMemoryData.ownsData(input) 435 435 ); 436 436 } else { 437 437 // Otherwise we attempt to get the missing field from the cache ··· 447 447 (output[fieldAlias] !== undefined 448 448 ? output[fieldAlias] 449 449 : input[fieldAlias]) as Data, 450 - ownsData(input) 450 + InMemoryData.ownsData(input) 451 451 ); 452 452 } else if (typeof fieldValue === 'object' && fieldValue !== null) { 453 453 // The entity on the field was invalid but can still be recovered ··· 549 549 } else if (!isOwnedData && prevData === null) { 550 550 return null; 551 551 } else if (isDataOrKey(result)) { 552 - const data = (prevData || makeData()) as Data; 552 + const data = (prevData || InMemoryData.makeData()) as Data; 553 553 return typeof result === 'string' 554 554 ? readSelection(ctx, result, select, data) 555 555 : readSelection(ctx, key, select, data, result); ··· 616 616 return null; 617 617 } 618 618 619 - return readSelection(ctx, link, select, (prevData || makeData()) as Data); 619 + return readSelection( 620 + ctx, 621 + link, 622 + select, 623 + (prevData || InMemoryData.makeData()) as Data 624 + ); 620 625 }; 621 626 622 627 const isDataOrKey = (x: any): x is string | Data =>
+6 -6
exchanges/graphcache/src/operations/shared.ts
··· 17 17 } from '../ast'; 18 18 19 19 import { warn, pushDebugNode, popDebugNode } from '../helpers/help'; 20 - import { hasField, isWriting } from '../store/data'; 21 - import { Store, keyOfField } from '../store'; 20 + import { hasField, currentOperation, currentOptimistic } from '../store/data'; 21 + import { keyOfField } from '../store/keys'; 22 + import { Store } from '../store/store'; 22 23 23 24 import { getFieldArguments, shouldInclude, isInterfaceOfType } from '../ast'; 24 25 ··· 66 67 fragments: Fragments, 67 68 typename: string, 68 69 entityKey: string, 69 - optimistic?: boolean, 70 - error?: CombinedError | undefined 70 + error: CombinedError | undefined 71 71 ): Context => { 72 72 const ctx: Context = { 73 73 store, ··· 81 81 error: undefined, 82 82 partial: false, 83 83 hasNext: false, 84 - optimistic: !!optimistic, 84 + optimistic: currentOptimistic, 85 85 __internal: { 86 86 path: [], 87 87 errorMap: undefined, ··· 144 144 ); 145 145 146 146 return ( 147 - isWriting() || 147 + currentOperation === 'write' || 148 148 !getSelectionSet(node).some(node => { 149 149 if (!isFieldNode(node)) return false; 150 150 const fieldKey = keyOfField(getName(node), getFieldArguments(node, vars));
+1 -1
exchanges/graphcache/src/operations/write.test.ts
··· 6 6 7 7 import { __initAnd_write as write } from './write'; 8 8 import * as InMemoryData from '../store/data'; 9 - import { Store } from '../store'; 9 + import { Store } from '../store/store'; 10 10 11 11 const TODO_QUERY = gql` 12 12 query todos {
+12 -17
exchanges/graphcache/src/operations/write.ts
··· 32 32 OptimisticMutationResolver, 33 33 } from '../types'; 34 34 35 - import { 36 - Store, 37 - getCurrentDependencies, 38 - initDataState, 39 - clearDataState, 40 - joinKeys, 41 - keyOfField, 42 - makeData, 43 - } from '../store'; 44 - 35 + import { joinKeys, keyOfField } from '../store/keys'; 36 + import { Store } from '../store/store'; 45 37 import * as InMemoryData from '../store/data'; 46 38 47 39 import { ··· 69 61 error?: CombinedError | undefined, 70 62 key?: number 71 63 ): WriteResult => { 72 - initDataState('write', store.data, key || null); 64 + InMemoryData.initDataState('write', store.data, key || null); 73 65 const result = _write(store, request, data, error); 74 - clearDataState(); 66 + InMemoryData.clearDataState(); 75 67 return result; 76 68 }; 77 69 ··· 89 81 ); 90 82 } 91 83 92 - initDataState('write', store.data, key, true); 84 + InMemoryData.initDataState('write', store.data, key, true); 93 85 const result = _write(store, request, {} as Data, undefined); 94 - clearDataState(); 86 + InMemoryData.clearDataState(); 95 87 return result; 96 88 }; 97 89 ··· 101 93 data?: Data, 102 94 error?: CombinedError | undefined 103 95 ) => { 96 + if (process.env.NODE_ENV !== 'production') { 97 + InMemoryData.getCurrentDependencies(); 98 + } 99 + 104 100 const operation = getMainOperation(request.query); 105 101 const result: WriteResult = { 106 - data: data || makeData(), 107 - dependencies: getCurrentDependencies(), 102 + data: data || InMemoryData.makeData(), 103 + dependencies: InMemoryData.currentDependencies!, 108 104 }; 109 105 const kind = store.rootFields[operation.operation]; 110 106 ··· 114 110 getFragments(request.query), 115 111 kind, 116 112 kind, 117 - InMemoryData.currentOptimistic, 118 113 error 119 114 ); 120 115
+2 -16
exchanges/graphcache/src/store/data.ts
··· 59 59 60 60 let currentOwnership: null | WeakSet<Data> = null; 61 61 let currentDataMapping: null | WeakMap<Data, Data> = null; 62 - let currentOperation: null | OperationType = null; 63 62 let currentData: null | InMemoryData = null; 64 - let currentDependencies: null | Dependencies = null; 65 63 let currentOptimisticKey: null | number = null; 64 + export let currentOperation: null | OperationType = null; 65 + export let currentDependencies: null | Dependencies = null; 66 66 export let currentForeignData = false; 67 67 export let currentOptimistic = false; 68 68 ··· 80 80 currentOwnership!.add(newData); 81 81 return newData; 82 82 }; 83 - 84 - export const isWriting = (): boolean => currentOperation === 'write'; 85 83 86 84 export const ownsData = (data?: Data): boolean => 87 85 !!data && currentOwnership!.has(data); ··· 203 201 if (layerKey && !isOptimistic) data.deferredKeys.delete(layerKey); 204 202 initDataState('write', data, layerKey, isOptimistic); 205 203 clearDataState(); 206 - }; 207 - 208 - export const getCurrentOperation = (): OperationType => { 209 - invariant( 210 - currentOperation !== null, 211 - 'Invalid Cache call: The cache may only be accessed or mutated during' + 212 - 'operations like write or query, or as part of its resolvers, updaters, ' + 213 - 'or optimistic configs.', 214 - 2 215 - ); 216 - 217 - return currentOperation; 218 204 }; 219 205 220 206 /** As we're writing, we keep around all the records and links we've read or have written to */
-14
exchanges/graphcache/src/store/index.ts
··· 1 - export { 2 - initDataState, 3 - clearDataState, 4 - noopDataState, 5 - makeData, 6 - ownsData, 7 - reserveLayer, 8 - getCurrentOperation, 9 - getCurrentDependencies, 10 - hydrateData, 11 - } from './data'; 12 - 13 - export * from './keys'; 14 - export * from './store';
+1 -1
exchanges/graphcache/src/store/store.test.ts
··· 382 382 }, 383 383 }); 384 384 385 - context = makeContext(store, {}, {}, 'Query', 'Query'); 385 + context = makeContext(store, {}, {}, 'Query', 'Query', undefined); 386 386 write(store, { query: Todos }, todosData); 387 387 InMemoryData.initDataState('read', store.data, null); 388 388 });
+1 -1
exchanges/graphcache/src/test-utils/examples-1.test.ts
··· 6 6 __initAnd_writeOptimistic as writeOptimistic, 7 7 } from '../operations/write'; 8 8 import * as InMemoryData from '../store/data'; 9 - import { Store } from '../store'; 9 + import { Store } from '../store/store'; 10 10 import { Data } from '../types'; 11 11 12 12 const Todos = gql`
+1 -1
exchanges/graphcache/src/test-utils/examples-2.test.ts
··· 2 2 import { it, afterEach, expect } from 'vitest'; 3 3 import { __initAnd_query as query } from '../operations/query'; 4 4 import { __initAnd_write as write } from '../operations/write'; 5 - import { Store } from '../store'; 5 + import { Store } from '../store/store'; 6 6 7 7 const Item = gql` 8 8 {
+1 -1
exchanges/graphcache/src/test-utils/examples-3.test.ts
··· 2 2 import { it, afterEach, expect } from 'vitest'; 3 3 import { __initAnd_query as query } from '../operations/query'; 4 4 import { __initAnd_write as write } from '../operations/write'; 5 - import { Store } from '../store'; 5 + import { Store } from '../store/store'; 6 6 7 7 afterEach(() => { 8 8 expect(console.warn).not.toHaveBeenCalled();
+1 -1
exchanges/graphcache/src/test-utils/suite.test.ts
··· 3 3 import { it, expect } from 'vitest'; 4 4 import { __initAnd_query as query } from '../operations/query'; 5 5 import { __initAnd_write as write } from '../operations/write'; 6 - import { Store } from '../store'; 6 + import { Store } from '../store/store'; 7 7 8 8 interface TestCase { 9 9 query: DocumentNode;