Skip to content

Commit a1c04d9

Browse files
committed
[validation] Allow safe divergence
As pointed out in graphql-go#53, our validation is more conservative than it needs to be in some cases. Particularly, two fields which could not overlap are still treated as a potential conflict. This change loosens this rule, allowing fields which can never both apply in a frame of execution to diverge. Commit: d71e063fdd1d4c376b4948147e54438b6f1e13de [d71e063] Parents: 228215a704 Author: Lee Byron <[email protected]> Date: 13 November 2015 at 9:39:54 AM SGT Commit Date: 13 November 2015 at 10:01:11 AM SGT
1 parent 0058fcd commit a1c04d9

File tree

2 files changed

+250
-94
lines changed

2 files changed

+250
-94
lines changed

rules.go

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,8 +1078,9 @@ func NoUnusedVariablesRule(context *ValidationContext) *ValidationRuleInstance {
10781078
}
10791079

10801080
type fieldDefPair struct {
1081-
Field *ast.Field
1082-
FieldDef *FieldDefinition
1081+
ParentType Composite
1082+
Field *ast.Field
1083+
FieldDef *FieldDefinition
10831084
}
10841085

10851086
func collectFieldASTsAndDefs(context *ValidationContext, parentType Named, selectionSet *ast.SelectionSet, visitedFragmentNames map[string]bool, astAndDefs map[string][]*fieldDefPair) map[string][]*fieldDefPair {
@@ -1116,10 +1117,18 @@ func collectFieldASTsAndDefs(context *ValidationContext, parentType Named, selec
11161117
if !ok {
11171118
astAndDefs[responseName] = []*fieldDefPair{}
11181119
}
1119-
astAndDefs[responseName] = append(astAndDefs[responseName], &fieldDefPair{
1120-
Field: selection,
1121-
FieldDef: fieldDef,
1122-
})
1120+
if parentType, ok := parentType.(Composite); ok {
1121+
astAndDefs[responseName] = append(astAndDefs[responseName], &fieldDefPair{
1122+
ParentType: parentType,
1123+
Field: selection,
1124+
FieldDef: fieldDef,
1125+
})
1126+
} else {
1127+
astAndDefs[responseName] = append(astAndDefs[responseName], &fieldDefPair{
1128+
Field: selection,
1129+
FieldDef: fieldDef,
1130+
})
1131+
}
11231132
case *ast.InlineFragment:
11241133
inlineFragmentType := parentType
11251134
if selection.TypeCondition != nil {
@@ -1279,6 +1288,10 @@ func sameValue(value1 ast.Value, value2 ast.Value) bool {
12791288
return val1 == val2
12801289
}
12811290

1291+
func sameType(typeA, typeB Type) bool {
1292+
return fmt.Sprintf("%v", typeA) == fmt.Sprintf("%v", typeB)
1293+
}
1294+
12821295
/**
12831296
* OverlappingFieldsCanBeMergedRule
12841297
* Overlapping fields can be merged
@@ -1291,15 +1304,38 @@ func OverlappingFieldsCanBeMergedRule(context *ValidationContext) *ValidationRul
12911304

12921305
comparedSet := newPairSet()
12931306
var findConflicts func(fieldMap map[string][]*fieldDefPair) (conflicts []*conflict)
1294-
findConflict := func(responseName string, pair *fieldDefPair, pair2 *fieldDefPair) *conflict {
1307+
findConflict := func(responseName string, field *fieldDefPair, field2 *fieldDefPair) *conflict {
12951308

1296-
ast1 := pair.Field
1297-
def1 := pair.FieldDef
1309+
parentType1 := field.ParentType
1310+
ast1 := field.Field
1311+
def1 := field.FieldDef
12981312

1299-
ast2 := pair2.Field
1300-
def2 := pair2.FieldDef
1313+
parentType2 := field2.ParentType
1314+
ast2 := field2.Field
1315+
def2 := field2.FieldDef
1316+
1317+
// Not a pair.
1318+
if ast1 == ast2 {
1319+
return nil
1320+
}
1321+
1322+
// If the statically known parent types could not possibly apply at the same
1323+
// time, then it is safe to permit them to diverge as they will not present
1324+
// any ambiguity by differing.
1325+
// It is known that two parent types could never overlap if they are
1326+
// different Object types. Interface or Union types might overlap - if not
1327+
// in the current state of the schema, then perhaps in some future version,
1328+
// thus may not safely diverge.
1329+
if parentType1 != parentType2 {
1330+
_, ok1 := parentType1.(*Object)
1331+
_, ok2 := parentType2.(*Object)
1332+
if ok1 && ok2 {
1333+
return nil
1334+
}
1335+
}
13011336

1302-
if ast1 == ast2 || comparedSet.Has(ast1, ast2) {
1337+
// Memoize, do not report the same issue twice.
1338+
if comparedSet.Has(ast1, ast2) {
13031339
return nil
13041340
}
13051341
comparedSet.Add(ast1, ast2)
@@ -1332,7 +1368,7 @@ func OverlappingFieldsCanBeMergedRule(context *ValidationContext) *ValidationRul
13321368
type2 = def2.Type
13331369
}
13341370

1335-
if type1 != nil && type2 != nil && !isEqualType(type1, type2) {
1371+
if type1 != nil && type2 != nil && !sameType(type1, type2) {
13361372
return &conflict{
13371373
Reason: conflictReason{
13381374
Name: responseName,

0 commit comments

Comments
 (0)