File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 1+ ---
2+ ' @urql/exchange-graphcache ' : minor
3+ ---
4+
5+ Add possibleTypes config for deterministic fragment matching
Original file line number Diff line number Diff line change @@ -234,18 +234,24 @@ export class SelectionIterator {
234234 fragment ,
235235 this . typename
236236 )
237- : ( currentOperation === 'read' &&
238- isFragmentMatching (
237+ : this . ctx . store . possibleTypeMap
238+ ? isSuperType (
239+ this . ctx . store . possibleTypeMap ,
239240 fragment . typeCondition . name . value ,
240241 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+ ) ) ;
249255 if (
250256 isMatching ||
251257 ( currentOperation === 'write' && ! this . ctx . store . schema )
@@ -290,6 +296,19 @@ export class SelectionIterator {
290296 }
291297}
292298
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+ } ;
311+
293312const isFragmentMatching = ( typeCondition : string , typename : string | void ) => {
294313 if ( ! typename ) return false ;
295314 if ( typeCondition === typename ) return true ;
Original file line number Diff line number Diff line change @@ -57,6 +57,7 @@ export class Store<
5757 keys : KeyingConfig ;
5858 globalIDs : Set < string > | boolean ;
5959 schema ?: SchemaIntrospector ;
60+ possibleTypeMap ?: Map < string , Set < string > > ;
6061
6162 rootFields : { query : string ; mutation : string ; subscription : string } ;
6263 rootNames : { [ name : string ] : RootField | void } ;
@@ -86,6 +87,14 @@ export class Store<
8687 if ( schema . types ) this . schema = schema ;
8788 }
8889
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+ }
96+ }
97+
8998 this . updates = opts . updates || { } ;
9099
91100 this . rootFields = {
Original file line number Diff line number Diff line change @@ -618,6 +618,16 @@ export type CacheExchangeOpts = {
618618 * type names may be passed instead.
619619 */
620620 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 ;
621631 /** Configures Graphcache with Schema Introspection data.
622632 *
623633 * @remarks
@@ -932,6 +942,10 @@ export type KeyingConfig = {
932942 [ typename : string ] : KeyGenerator ;
933943} ;
934944
945+ export type PossibleTypesConfig = {
946+ [ abstractType : string ] : string [ ] ;
947+ } ;
948+
935949/** Serialized normalized caching data. */
936950export interface SerializedEntries {
937951 [ key : string ] : string | undefined ;
You can’t perform that action at this time.
0 commit comments