@@ -281,17 +281,20 @@ export type PossibleTypesMap = {
281
281
[ supertype : string ] : string [ ] ;
282
282
} ;
283
283
284
+ type InternalFieldPolicy = {
285
+ typename : string ;
286
+ keyFn ?: KeyArgsFunction ;
287
+ read ?: FieldReadFunction < any > ;
288
+ merge ?: FieldMergeFunction < any > ;
289
+ } ;
290
+
284
291
export class Policies {
285
292
private typePolicies : {
286
293
[ __typename : string ] : {
287
294
keyFn ?: KeyFieldsFunction ;
288
295
merge ?: FieldMergeFunction < any > ;
289
296
fields : {
290
- [ fieldName : string ] : {
291
- keyFn ?: KeyArgsFunction ;
292
- read ?: FieldReadFunction < any > ;
293
- merge ?: FieldMergeFunction < any > ;
294
- } ;
297
+ [ fieldName : string ] : InternalFieldPolicy ;
295
298
} ;
296
299
} ;
297
300
} = Object . create ( null ) ;
@@ -440,7 +443,11 @@ export class Policies {
440
443
} ) ;
441
444
}
442
445
443
- private updateTypePolicy ( typename : string , incoming : TypePolicy ) {
446
+ private updateTypePolicy (
447
+ typename : string ,
448
+ incoming : TypePolicy ,
449
+ existingFieldPolicies : Record < string , InternalFieldPolicy >
450
+ ) {
444
451
const existing = this . getTypePolicy ( typename ) ;
445
452
const { keyFields, fields } = incoming ;
446
453
@@ -476,7 +483,17 @@ export class Policies {
476
483
477
484
if ( fields ) {
478
485
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
+ }
480
497
const incoming = fields [ fieldName ] ;
481
498
482
499
if ( typeof incoming === "function" ) {
@@ -623,7 +640,11 @@ export class Policies {
623
640
// Merge the pending policies into this.typePolicies, in the order they
624
641
// were originally passed to addTypePolicy.
625
642
inbox . splice ( 0 ) . forEach ( ( policy ) => {
626
- this . updateTypePolicy ( typename , policy ) ;
643
+ this . updateTypePolicy (
644
+ typename ,
645
+ policy ,
646
+ this . typePolicies [ typename ] . fields
647
+ ) ;
627
648
} ) ;
628
649
}
629
650
@@ -632,21 +653,10 @@ export class Policies {
632
653
633
654
private getFieldPolicy (
634
655
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 {
644
658
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 ] ;
650
660
}
651
661
}
652
662
@@ -760,13 +770,13 @@ export class Policies {
760
770
}
761
771
762
772
public hasKeyArgs ( typename : string | undefined , fieldName : string ) {
763
- const policy = this . getFieldPolicy ( typename , fieldName , false ) ;
773
+ const policy = this . getFieldPolicy ( typename , fieldName ) ;
764
774
return ! ! ( policy && policy . keyFn ) ;
765
775
}
766
776
767
777
public getStoreFieldName ( fieldSpec : FieldSpecifier ) : string {
768
778
const { typename, fieldName } = fieldSpec ;
769
- const policy = this . getFieldPolicy ( typename , fieldName , false ) ;
779
+ const policy = this . getFieldPolicy ( typename , fieldName ) ;
770
780
let storeFieldName : Exclude < ReturnType < KeyArgsFunction > , KeySpecifier > ;
771
781
772
782
let keyFn = policy && policy . keyFn ;
@@ -835,7 +845,7 @@ export class Policies {
835
845
objectOrReference ,
836
846
storeFieldName
837
847
) ;
838
- const policy = this . getFieldPolicy ( options . typename , fieldName , false ) ;
848
+ const policy = this . getFieldPolicy ( options . typename , fieldName ) ;
839
849
const read = policy && policy . read ;
840
850
841
851
if ( read ) {
@@ -866,7 +876,7 @@ export class Policies {
866
876
typename : string | undefined ,
867
877
fieldName : string
868
878
) : FieldReadFunction | undefined {
869
- const policy = this . getFieldPolicy ( typename , fieldName , false ) ;
879
+ const policy = this . getFieldPolicy ( typename , fieldName ) ;
870
880
return policy && policy . read ;
871
881
}
872
882
@@ -878,7 +888,7 @@ export class Policies {
878
888
let policy :
879
889
| Policies [ "typePolicies" ] [ string ]
880
890
| Policies [ "typePolicies" ] [ string ] [ "fields" ] [ string ]
881
- | undefined = this . getFieldPolicy ( parentTypename , fieldName , false ) ;
891
+ | undefined = this . getFieldPolicy ( parentTypename , fieldName ) ;
882
892
let merge = policy && policy . merge ;
883
893
if ( ! merge && childTypename ) {
884
894
policy = this . getTypePolicy ( childTypename ) ;
0 commit comments