Skip to content

Commit 4be3fb8

Browse files
committed
introduce OrderedPairSet class
1 parent 2d830ca commit 4be3fb8

File tree

1 file changed

+60
-42
lines changed

1 file changed

+60
-42
lines changed

src/validation/rules/OverlappingFieldsCanBeMergedRule.ts

Lines changed: 60 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,11 @@ export function OverlappingFieldsCanBeMergedRule(
6262
// A memoization for when fields and a fragment or two fragments are compared
6363
// "between" each other for conflicts. Comparisons made be made many times,
6464
// so memoizing this can dramatically improve the performance of this validator.
65-
const comparedFieldsAndFragmentPairs = new PairSet<
65+
const comparedFieldsAndFragmentPairs = new OrderedPairSet<
6666
NodeAndDefCollection,
6767
string
68-
>((a, _) => typeof a === 'string');
69-
const comparedFragmentPairs = new PairSet<string, string>((a, b) => a < b);
68+
>();
69+
const comparedFragmentPairs = new PairSet<string>((a, b) => a < b);
7070

7171
// A cache for the "field map" and list of fragment names found in any given
7272
// selection set. Selection sets may be asked for this information multiple
@@ -173,8 +173,8 @@ type FieldsAndFragmentNames = readonly [NodeAndDefCollection, FragmentNames];
173173
function findConflictsWithinSelectionSet(
174174
context: ValidationContext,
175175
cachedFieldsAndFragmentNames: Map<SelectionSetNode, FieldsAndFragmentNames>,
176-
comparedFieldsAndFragmentPairs: PairSet<NodeAndDefCollection, string>,
177-
comparedFragmentPairs: PairSet<string, string>,
176+
comparedFieldsAndFragmentPairs: OrderedPairSet<NodeAndDefCollection, string>,
177+
comparedFragmentPairs: PairSet<string>,
178178
parentType: Maybe<GraphQLNamedType>,
179179
selectionSet: SelectionSetNode,
180180
): Array<Conflict> {
@@ -239,8 +239,8 @@ function collectConflictsBetweenFieldsAndFragment(
239239
context: ValidationContext,
240240
conflicts: Array<Conflict>,
241241
cachedFieldsAndFragmentNames: Map<SelectionSetNode, FieldsAndFragmentNames>,
242-
comparedFieldsAndFragmentPairs: PairSet<NodeAndDefCollection, string>,
243-
comparedFragmentPairs: PairSet<string, string>,
242+
comparedFieldsAndFragmentPairs: OrderedPairSet<NodeAndDefCollection, string>,
243+
comparedFragmentPairs: PairSet<string>,
244244
areMutuallyExclusive: boolean,
245245
fieldMap: NodeAndDefCollection,
246246
fragmentName: string,
@@ -314,8 +314,8 @@ function collectConflictsBetweenFragments(
314314
context: ValidationContext,
315315
conflicts: Array<Conflict>,
316316
cachedFieldsAndFragmentNames: Map<SelectionSetNode, FieldsAndFragmentNames>,
317-
comparedFieldsAndFragmentPairs: PairSet<NodeAndDefCollection, string>,
318-
comparedFragmentPairs: PairSet<string, string>,
317+
comparedFieldsAndFragmentPairs: OrderedPairSet<NodeAndDefCollection, string>,
318+
comparedFragmentPairs: PairSet<string>,
319319
areMutuallyExclusive: boolean,
320320
fragmentName1: string,
321321
fragmentName2: string,
@@ -406,8 +406,8 @@ function collectConflictsBetweenFragments(
406406
function findConflictsBetweenSubSelectionSets(
407407
context: ValidationContext,
408408
cachedFieldsAndFragmentNames: Map<SelectionSetNode, FieldsAndFragmentNames>,
409-
comparedFieldsAndFragmentPairs: PairSet<NodeAndDefCollection, string>,
410-
comparedFragmentPairs: PairSet<string, string>,
409+
comparedFieldsAndFragmentPairs: OrderedPairSet<NodeAndDefCollection, string>,
410+
comparedFragmentPairs: PairSet<string>,
411411
areMutuallyExclusive: boolean,
412412
parentType1: Maybe<GraphQLNamedType>,
413413
selectionSet1: SelectionSetNode,
@@ -496,8 +496,8 @@ function collectConflictsWithin(
496496
context: ValidationContext,
497497
conflicts: Array<Conflict>,
498498
cachedFieldsAndFragmentNames: Map<SelectionSetNode, FieldsAndFragmentNames>,
499-
comparedFieldsAndFragmentPairs: PairSet<NodeAndDefCollection, string>,
500-
comparedFragmentPairs: PairSet<string, string>,
499+
comparedFieldsAndFragmentPairs: OrderedPairSet<NodeAndDefCollection, string>,
500+
comparedFragmentPairs: PairSet<string>,
501501
fieldMap: NodeAndDefCollection,
502502
): void {
503503
// A field map is a keyed collection, where each key represents a response
@@ -539,8 +539,8 @@ function collectConflictsBetween(
539539
context: ValidationContext,
540540
conflicts: Array<Conflict>,
541541
cachedFieldsAndFragmentNames: Map<SelectionSetNode, FieldsAndFragmentNames>,
542-
comparedFieldsAndFragmentPairs: PairSet<NodeAndDefCollection, string>,
543-
comparedFragmentPairs: PairSet<string, string>,
542+
comparedFieldsAndFragmentPairs: OrderedPairSet<NodeAndDefCollection, string>,
543+
comparedFragmentPairs: PairSet<string>,
544544
parentFieldsAreMutuallyExclusive: boolean,
545545
fieldMap1: NodeAndDefCollection,
546546
fieldMap2: NodeAndDefCollection,
@@ -579,8 +579,8 @@ function collectConflictsBetween(
579579
function findConflict(
580580
context: ValidationContext,
581581
cachedFieldsAndFragmentNames: Map<SelectionSetNode, FieldsAndFragmentNames>,
582-
comparedFieldsAndFragmentPairs: PairSet<NodeAndDefCollection, string>,
583-
comparedFragmentPairs: PairSet<string, string>,
582+
comparedFieldsAndFragmentPairs: OrderedPairSet<NodeAndDefCollection, string>,
583+
comparedFragmentPairs: PairSet<string>,
584584
parentFieldsAreMutuallyExclusive: boolean,
585585
responseName: string,
586586
field1: NodeAndDef,
@@ -841,44 +841,62 @@ function subfieldConflicts(
841841
}
842842

843843
/**
844-
* A way to keep track of pairs of things when the ordering of the pair does not matter.
844+
* A way to keep track of pairs of things where the ordering of the pair
845+
* matters.
846+
*
847+
* Provides a third argument for has/set to allow flagging the pair as
848+
* weakly or strongly present within the collection.
845849
*/
846-
class PairSet<T, U> {
847-
_data: Map<T | U, Map<T | U, boolean>>;
848-
_orderer: (a: T | U, b: T | U) => [T | U, T | U];
850+
class OrderedPairSet<T, U> {
851+
_data: Map<T, Map<U, boolean>>;
849852

850-
constructor(comparator: (a: T | U, b: T | U) => boolean) {
853+
constructor() {
851854
this._data = new Map();
852-
this._orderer = (a: T | U, b: T | U) =>
853-
comparator(a, b) ? [a, b] : [b, a];
854855
}
855856

856-
has(a: T, b: U, areMutuallyExclusive: boolean): boolean;
857-
has(a: U, b: T, areMutuallyExclusive: boolean): boolean;
858-
has(a: T | U, b: T | U, areMutuallyExclusive: boolean): boolean {
859-
const [key1, key2] = this._orderer(a, b);
860-
861-
const result = this._data.get(key1)?.get(key2);
857+
has(a: T, b: U, weaklyPresent: boolean): boolean {
858+
const result = this._data.get(a)?.get(b);
862859
if (result === undefined) {
863860
return false;
864861
}
865862

866-
// areMutuallyExclusive being false is a superset of being true, hence if
867-
// we want to know if this PairSet "has" these two with no exclusivity,
868-
// we have to ensure it was added as such.
869-
return areMutuallyExclusive ? true : areMutuallyExclusive === result;
863+
return weaklyPresent ? true : weaklyPresent === result;
870864
}
871865

872-
add(a: T, b: U, areMutuallyExclusive: boolean): void;
873-
add(a: U, b: T, areMutuallyExclusive: boolean): void;
874-
add(a: T | U, b: T | U, areMutuallyExclusive: boolean): void {
875-
const [key1, key2] = this._orderer(a, b);
876-
877-
const map = this._data.get(key1);
866+
add(a: T, b: U, weaklyPresent: boolean): void {
867+
const map = this._data.get(a);
878868
if (map === undefined) {
879-
this._data.set(key1, new Map([[key2, areMutuallyExclusive]]));
869+
this._data.set(a, new Map([[b, weaklyPresent]]));
870+
} else {
871+
map.set(b, weaklyPresent);
872+
}
873+
}
874+
}
875+
876+
/**
877+
* A way to keep track of pairs of similar things when the ordering of the pair
878+
* does not matter.
879+
*/
880+
class PairSet<T> {
881+
_orderedPairSet: OrderedPairSet<T, T>;
882+
_comparator: (a: T, b: T) => boolean;
883+
884+
constructor(comparator: (a: T, b: T) => boolean) {
885+
this._orderedPairSet = new OrderedPairSet();
886+
this._comparator = comparator;
887+
}
888+
889+
has(a: T, b: T, weaklyPresent: boolean): boolean {
890+
return this._comparator(a, b)
891+
? this._orderedPairSet.has(a, b, weaklyPresent)
892+
: this._orderedPairSet.has(b, a, weaklyPresent);
893+
}
894+
895+
add(a: T, b: T, weaklyPresent: boolean): void {
896+
if (this._comparator(a, b)) {
897+
this._orderedPairSet.add(a, b, weaklyPresent);
880898
} else {
881-
map.set(key2, areMutuallyExclusive);
899+
this._orderedPairSet.add(b, a, weaklyPresent);
882900
}
883901
}
884902
}

0 commit comments

Comments
 (0)