@@ -281,17 +281,20 @@ export type PossibleTypesMap = {
281281 [ supertype : string ] : string [ ] ;
282282} ;
283283
284+ type InternalFieldPolicy = {
285+ typename : string ;
286+ keyFn ?: KeyArgsFunction ;
287+ read ?: FieldReadFunction < any > ;
288+ merge ?: FieldMergeFunction < any > ;
289+ } ;
290+
284291export class Policies {
285292 private typePolicies : {
286293 [ __typename : string ] : {
287294 keyFn ?: KeyFieldsFunction ;
288295 merge ?: FieldMergeFunction < any > ;
289296 fields : {
290- [ fieldName : string ] : {
291- keyFn ?: KeyArgsFunction ;
292- read ?: FieldReadFunction < any > ;
293- merge ?: FieldMergeFunction < any > ;
294- } ;
297+ [ fieldName : string ] : InternalFieldPolicy ;
295298 } ;
296299 } ;
297300 } = Object . create ( null ) ;
@@ -440,7 +443,11 @@ export class Policies {
440443 } ) ;
441444 }
442445
443- private updateTypePolicy ( typename : string , incoming : TypePolicy ) {
446+ private updateTypePolicy (
447+ typename : string ,
448+ incoming : TypePolicy ,
449+ existingFieldPolicies : Record < string , InternalFieldPolicy >
450+ ) {
444451 const existing = this . getTypePolicy ( typename ) ;
445452 const { keyFields, fields } = incoming ;
446453
@@ -476,7 +483,17 @@ export class Policies {
476483
477484 if ( fields ) {
478485 Object . keys ( fields ) . forEach ( ( fieldName ) => {
479- const existing = this . getFieldPolicy ( typename , fieldName , true ) ! ;
486+ let existing = existingFieldPolicies [ fieldName ] as
487+ | InternalFieldPolicy
488+ | undefined ;
489+ // Field policy inheritance is atomic/shallow: you can't inherit a
490+ // field policy and then override just its read function, since read
491+ // and merge functions often need to cooperate, so changing only one
492+ // of them would be a recipe for inconsistency.
493+ // So here we avoid merging an inherited field policy with an updated one.
494+ if ( ! existing || existing ?. typename !== typename ) {
495+ existing = existingFieldPolicies [ fieldName ] = { typename } ;
496+ }
480497 const incoming = fields [ fieldName ] ;
481498
482499 if ( typeof incoming === "function" ) {
@@ -623,7 +640,11 @@ export class Policies {
623640 // Merge the pending policies into this.typePolicies, in the order they
624641 // were originally passed to addTypePolicy.
625642 inbox . splice ( 0 ) . forEach ( ( policy ) => {
626- this . updateTypePolicy ( typename , policy ) ;
643+ this . updateTypePolicy (
644+ typename ,
645+ policy ,
646+ this . typePolicies [ typename ] . fields
647+ ) ;
627648 } ) ;
628649 }
629650
@@ -632,21 +653,10 @@ export class Policies {
632653
633654 private getFieldPolicy (
634655 typename : string | undefined ,
635- fieldName : string ,
636- createIfMissing : boolean
637- ) :
638- | {
639- keyFn ?: KeyArgsFunction ;
640- read ?: FieldReadFunction < any > ;
641- merge ?: FieldMergeFunction < any > ;
642- }
643- | undefined {
656+ fieldName : string
657+ ) : InternalFieldPolicy | undefined {
644658 if ( typename ) {
645- const fieldPolicies = this . getTypePolicy ( typename ) . fields ;
646- return (
647- fieldPolicies [ fieldName ] ||
648- ( createIfMissing && ( fieldPolicies [ fieldName ] = Object . create ( null ) ) )
649- ) ;
659+ return this . getTypePolicy ( typename ) . fields [ fieldName ] ;
650660 }
651661 }
652662
@@ -760,13 +770,13 @@ export class Policies {
760770 }
761771
762772 public hasKeyArgs ( typename : string | undefined , fieldName : string ) {
763- const policy = this . getFieldPolicy ( typename , fieldName , false ) ;
773+ const policy = this . getFieldPolicy ( typename , fieldName ) ;
764774 return ! ! ( policy && policy . keyFn ) ;
765775 }
766776
767777 public getStoreFieldName ( fieldSpec : FieldSpecifier ) : string {
768778 const { typename, fieldName } = fieldSpec ;
769- const policy = this . getFieldPolicy ( typename , fieldName , false ) ;
779+ const policy = this . getFieldPolicy ( typename , fieldName ) ;
770780 let storeFieldName : Exclude < ReturnType < KeyArgsFunction > , KeySpecifier > ;
771781
772782 let keyFn = policy && policy . keyFn ;
@@ -835,7 +845,7 @@ export class Policies {
835845 objectOrReference ,
836846 storeFieldName
837847 ) ;
838- const policy = this . getFieldPolicy ( options . typename , fieldName , false ) ;
848+ const policy = this . getFieldPolicy ( options . typename , fieldName ) ;
839849 const read = policy && policy . read ;
840850
841851 if ( read ) {
@@ -866,7 +876,7 @@ export class Policies {
866876 typename : string | undefined ,
867877 fieldName : string
868878 ) : FieldReadFunction | undefined {
869- const policy = this . getFieldPolicy ( typename , fieldName , false ) ;
879+ const policy = this . getFieldPolicy ( typename , fieldName ) ;
870880 return policy && policy . read ;
871881 }
872882
@@ -878,7 +888,7 @@ export class Policies {
878888 let policy :
879889 | Policies [ "typePolicies" ] [ string ]
880890 | Policies [ "typePolicies" ] [ string ] [ "fields" ] [ string ]
881- | undefined = this . getFieldPolicy ( parentTypename , fieldName , false ) ;
891+ | undefined = this . getFieldPolicy ( parentTypename , fieldName ) ;
882892 let merge = policy && policy . merge ;
883893 if ( ! merge && childTypename ) {
884894 policy = this . getTypePolicy ( childTypename ) ;
0 commit comments