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.

feat(graphcache): add possibleTypes config for deterministic fragment matching (#3805)

authored by

Duc Nghiem Xuan and committed by
GitHub
038c2c04 b0a0f32a

+57 -10
+5
.changeset/unlucky-apes-change.md
··· 1 + --- 2 + '@urql/exchange-graphcache': minor 3 + --- 4 + 5 + Add possibleTypes config for deterministic fragment matching
+29 -10
exchanges/graphcache/src/operations/shared.ts
··· 234 234 fragment, 235 235 this.typename 236 236 ) 237 - : (currentOperation === 'read' && 238 - isFragmentMatching( 237 + : this.ctx.store.possibleTypeMap 238 + ? isSuperType( 239 + this.ctx.store.possibleTypeMap, 239 240 fragment.typeCondition.name.value, 240 241 this.typename 241 - )) || 242 - isFragmentHeuristicallyMatching( 243 - fragment, 244 - this.typename, 245 - this.entityKey, 246 - this.ctx.variables, 247 - this.ctx.store.logger 248 - )); 242 + ) 243 + : (currentOperation === 'read' && 244 + isFragmentMatching( 245 + fragment.typeCondition.name.value, 246 + this.typename 247 + )) || 248 + isFragmentHeuristicallyMatching( 249 + fragment, 250 + this.typename, 251 + this.entityKey, 252 + this.ctx.variables, 253 + this.ctx.store.logger 254 + )); 249 255 if ( 250 256 isMatching || 251 257 (currentOperation === 'write' && !this.ctx.store.schema) ··· 289 295 return undefined; 290 296 } 291 297 } 298 + 299 + const isSuperType = ( 300 + possibleTypeMap: Map<string, Set<string>>, 301 + typeCondition: string, 302 + typename: string | void 303 + ) => { 304 + if (!typename) return false; 305 + if (typeCondition === typename) return true; 306 + 307 + const concreteTypes = possibleTypeMap.get(typeCondition); 308 + 309 + return concreteTypes && concreteTypes.has(typename); 310 + }; 292 311 293 312 const isFragmentMatching = (typeCondition: string, typename: string | void) => { 294 313 if (!typename) return false;
+9
exchanges/graphcache/src/store/store.ts
··· 57 57 keys: KeyingConfig; 58 58 globalIDs: Set<string> | boolean; 59 59 schema?: SchemaIntrospector; 60 + possibleTypeMap?: Map<string, Set<string>>; 60 61 61 62 rootFields: { query: string; mutation: string; subscription: string }; 62 63 rootNames: { [name: string]: RootField | void }; ··· 84 85 subscriptionName = schema.subscription || subscriptionName; 85 86 // Only add schema introspector if it has types info 86 87 if (schema.types) this.schema = schema; 88 + } 89 + 90 + if (!this.schema && opts.possibleTypes) { 91 + this.possibleTypeMap = new Map(); 92 + for (const entry of Object.entries(opts.possibleTypes)) { 93 + const [abstractType, concreteTypes] = entry; 94 + this.possibleTypeMap.set(abstractType, new Set(concreteTypes)); 95 + } 87 96 } 88 97 89 98 this.updates = opts.updates || {};
+14
exchanges/graphcache/src/types.ts
··· 618 618 * type names may be passed instead. 619 619 */ 620 620 globalIDs?: string[] | boolean; 621 + /** Configures abstract to concrete types mapping for GraphQL types. 622 + * 623 + * @remarks 624 + * This will disable heuristic fragment matching, allowing Graphcache to match 625 + * fragment deterministically. 626 + * 627 + * When both `possibleTypes` and `schema` is set, `possibleTypes` value will be 628 + * ignored. 629 + */ 630 + possibleTypes?: PossibleTypesConfig; 621 631 /** Configures Graphcache with Schema Introspection data. 622 632 * 623 633 * @remarks ··· 930 940 */ 931 941 export type KeyingConfig = { 932 942 [typename: string]: KeyGenerator; 943 + }; 944 + 945 + export type PossibleTypesConfig = { 946 + [abstractType: string]: string[]; 933 947 }; 934 948 935 949 /** Serialized normalized caching data. */