From 18f81bd5af0c9a45b11a27380c156db4e16f7b60 Mon Sep 17 00:00:00 2001 From: Jovi De Croock Date: Wed, 19 Jun 2024 09:58:24 +0200 Subject: [PATCH] fix bug for discovery --- .../OverlappingFieldsCanBeMergedRule-test.ts | 42 ++++++++++ .../rules/OverlappingFieldsCanBeMergedRule.ts | 78 +++++++++---------- 2 files changed, 81 insertions(+), 39 deletions(-) diff --git a/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.ts b/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.ts index 1f9c1764e29..e607cc8b4c6 100644 --- a/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.ts +++ b/src/validation/__tests__/OverlappingFieldsCanBeMergedRule-test.ts @@ -1163,4 +1163,46 @@ describe('Validate: Overlapping fields can be merged', () => { expectErrors(query).toDeepEqual([]); }); + + it('finds conflicts in nested fragments', () => { + const n = 10000; + const fragments = Array.from(Array(n).keys()).reduce( + (acc, next) => + acc.concat(`\n + fragment X${next + 1} on Query { + ...X${next} + } + `), + '', + ); + + const query = ` + query Test { + type: conflict + ...X${n} + } + ${fragments} + fragment X0 on Query { + type: conflict2 + __typename + } + `; + expectErrors(query).toDeepEqual( + [ + { + "locations": [ + { + "column": 9, + "line": 3 + }, + { + "column": 9, + "line": 50008 + } + ], + "message": "Fields \"type\" conflict because \"conflict\" and \"conflict2\" are different fields. Use different aliases on the fields to fetch both if this was intentional." + } + ] + ); + }); }); diff --git a/src/validation/rules/OverlappingFieldsCanBeMergedRule.ts b/src/validation/rules/OverlappingFieldsCanBeMergedRule.ts index 0967071e1bd..87186484e47 100644 --- a/src/validation/rules/OverlappingFieldsCanBeMergedRule.ts +++ b/src/validation/rules/OverlappingFieldsCanBeMergedRule.ts @@ -223,7 +223,7 @@ function findConflictsWithinSelectionSet( comparedFragmentPairs, false, fieldMap, - fragmentName, + referencedFragmentName, discoveredFragments, ); } @@ -439,26 +439,26 @@ function findConflictsBetweenSubSelectionSets( ); } - // (E) Then collect any conflicts between the provided collection of fields - // and any fragment names found in the given fragment. - while (discoveredFragments.length !== 0) { - const item = discoveredFragments.pop(); - if (!item || comparedFragmentPairs.has(item[1], item[0], areMutuallyExclusive)) { - continue; + // (E) Then collect any conflicts between the provided collection of fields + // and any fragment names found in the given fragment. + while (discoveredFragments.length !== 0) { + const item = discoveredFragments.pop(); + if (!item || comparedFragmentPairs.has(item[1], item[0], areMutuallyExclusive)) { + continue; + } + const [fragmentName, referencedFragmentName] = item; + comparedFragmentPairs.add(referencedFragmentName, fragmentName, areMutuallyExclusive); + collectConflictsBetweenFieldsAndFragment( + context, + conflicts, + cachedFieldsAndFragmentNames, + comparedFragmentPairs, + areMutuallyExclusive, + fieldMap1, + referencedFragmentName, + discoveredFragments, + ); } - const [fragmentName, referencedFragmentName] = item; - comparedFragmentPairs.add(referencedFragmentName, fragmentName, areMutuallyExclusive); - collectConflictsBetweenFieldsAndFragment( - context, - conflicts, - cachedFieldsAndFragmentNames, - comparedFragmentPairs, - areMutuallyExclusive, - fieldMap1, - fragmentName, - discoveredFragments, - ); - } // (I) Then collect conflicts between the second collection of fields and // those referenced by each fragment name associated with the first. @@ -475,26 +475,26 @@ function findConflictsBetweenSubSelectionSets( ); } - // (E) Then collect any conflicts between the provided collection of fields - // and any fragment names found in the given fragment. - while (discoveredFragments.length !== 0) { - const item = discoveredFragments.pop(); - if (!item || comparedFragmentPairs.has(item[1], item[0], areMutuallyExclusive)) { - continue; + // (E) Then collect any conflicts between the provided collection of fields + // and any fragment names found in the given fragment. + while (discoveredFragments.length !== 0) { + const item = discoveredFragments.pop(); + if (!item || comparedFragmentPairs.has(item[1], item[0], areMutuallyExclusive)) { + continue; + } + const [fragmentName, referencedFragmentName] = item; + comparedFragmentPairs.add(referencedFragmentName, fragmentName, areMutuallyExclusive); + collectConflictsBetweenFieldsAndFragment( + context, + conflicts, + cachedFieldsAndFragmentNames, + comparedFragmentPairs, + areMutuallyExclusive, + fieldMap2, + referencedFragmentName, + discoveredFragments, + ); } - const [fragmentName, referencedFragmentName] = item; - comparedFragmentPairs.add(referencedFragmentName, fragmentName, areMutuallyExclusive); - collectConflictsBetweenFieldsAndFragment( - context, - conflicts, - cachedFieldsAndFragmentNames, - comparedFragmentPairs, - areMutuallyExclusive, - fieldMap2, - fragmentName, - discoveredFragments, - ); - } // (J) Also collect conflicts between any fragment names by the first and // fragment names by the second. This compares each item in the first set of