@apollo/federation-internals 2.4.0 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/coreSpec.js +1 -1
- package/dist/coreSpec.js.map +1 -1
- package/dist/operations.d.ts +92 -1
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +182 -46
- package/dist/operations.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/operations.test.ts +598 -45
- package/src/__tests__/schemaUpgrader.test.ts +1 -1
- package/src/operations.ts +305 -99
- package/tsconfig.tsbuildinfo +1 -1
package/dist/operations.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.operationToDocument = exports.parseSelectionSet = exports.parseOperation = exports.operationFromDocument = exports.FragmentSelection = exports.FieldSelection = exports.selectionOfElement = exports.selectionSetOfElement = exports.selectionSetOf = exports.allFieldDefinitionsInSelectionSet = exports.MutableSelectionSet = exports.SelectionSetUpdates = exports.SelectionSet = exports.NamedFragments = exports.NamedFragmentDefinition = exports.Operation = exports.concatOperationPaths = exports.conditionalDirectivesInOperationPath = exports.sameOperationPaths = exports.operationPathToStringPath = exports.FragmentElement = exports.Field = void 0;
|
|
4
4
|
const graphql_1 = require("graphql");
|
|
5
5
|
const definitions_1 = require("./definitions");
|
|
6
|
+
const federation_1 = require("./federation");
|
|
6
7
|
const error_1 = require("./error");
|
|
7
8
|
const types_1 = require("./types");
|
|
8
9
|
const utils_1 = require("./utils");
|
|
@@ -174,7 +175,8 @@ class Field extends AbstractOperationElement {
|
|
|
174
175
|
canRebaseOn(parentType) {
|
|
175
176
|
const fieldParentType = this.definition.parent;
|
|
176
177
|
return parentType.name === fieldParentType.name
|
|
177
|
-
|| (
|
|
178
|
+
|| (0, definitions_1.isInterfaceType)(fieldParentType)
|
|
179
|
+
|| (0, federation_1.isInterfaceObjectType)(fieldParentType);
|
|
178
180
|
}
|
|
179
181
|
typeIfAddedTo(parentType) {
|
|
180
182
|
var _a, _b;
|
|
@@ -557,8 +559,7 @@ class NamedFragmentDefinition extends definitions_1.DirectiveTargetElement {
|
|
|
557
559
|
};
|
|
558
560
|
}
|
|
559
561
|
canApplyAtType(type) {
|
|
560
|
-
const applyAtType = (0, types_1.sameType)(this.typeCondition, type)
|
|
561
|
-
|| ((0, definitions_1.isAbstractType)(this.typeCondition) && !(0, definitions_1.isUnionType)(type) && (0, types_1.isDirectSubtype)(this.typeCondition, type));
|
|
562
|
+
const applyAtType = (0, types_1.sameType)(type, this.typeCondition) || (0, definitions_1.runtimeTypesIntersects)(type, this.typeCondition);
|
|
562
563
|
return applyAtType
|
|
563
564
|
&& this.validForSchema(type.schema());
|
|
564
565
|
}
|
|
@@ -839,31 +840,67 @@ class SelectionSet {
|
|
|
839
840
|
}
|
|
840
841
|
return true;
|
|
841
842
|
}
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
843
|
+
triviallyNestedSelectionsForKey(parentType, key) {
|
|
844
|
+
const found = [];
|
|
845
|
+
for (const selection of this.selections()) {
|
|
846
|
+
if (selection.isUnecessaryInlineFragment(parentType)) {
|
|
847
|
+
const selectionForKey = selection.selectionSet._keyedSelections.get(key);
|
|
848
|
+
if (selectionForKey) {
|
|
849
|
+
found.push(selectionForKey);
|
|
850
|
+
}
|
|
851
|
+
for (const nestedSelection of selection.selectionSet.triviallyNestedSelectionsForKey(parentType, key)) {
|
|
852
|
+
found.push(nestedSelection);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
return found;
|
|
857
|
+
}
|
|
858
|
+
mergeSameKeySelections(selections) {
|
|
859
|
+
if (selections.length === 0) {
|
|
860
|
+
return undefined;
|
|
861
|
+
}
|
|
862
|
+
const first = selections[0];
|
|
863
|
+
if (!first.selectionSet || (first instanceof FragmentSpreadSelection) || selections.length === 1) {
|
|
864
|
+
return first;
|
|
865
|
+
}
|
|
866
|
+
const mergedSubselections = new SelectionSetUpdates();
|
|
867
|
+
for (const selection of selections) {
|
|
868
|
+
mergedSubselections.add(selection.selectionSet);
|
|
845
869
|
}
|
|
870
|
+
return first.withUpdatedSelectionSet(mergedSubselections.toSelectionSet(first.selectionSet.parentType));
|
|
871
|
+
}
|
|
872
|
+
contains(that) {
|
|
846
873
|
for (const [key, thatSelection] of that._keyedSelections) {
|
|
847
874
|
const thisSelection = this._keyedSelections.get(key);
|
|
848
|
-
|
|
875
|
+
const otherSelections = this.triviallyNestedSelectionsForKey(this.parentType, key);
|
|
876
|
+
const mergedSelection = this.mergeSameKeySelections([thisSelection].concat(otherSelections).filter(utils_1.isDefined));
|
|
877
|
+
if (!(mergedSelection && mergedSelection.contains(thatSelection))
|
|
878
|
+
&& !(thatSelection.isUnecessaryInlineFragment(this.parentType) && this.contains(thatSelection.selectionSet))) {
|
|
849
879
|
return false;
|
|
850
880
|
}
|
|
851
881
|
}
|
|
852
882
|
return true;
|
|
853
883
|
}
|
|
884
|
+
diffIfContains(that) {
|
|
885
|
+
if (this.contains(that)) {
|
|
886
|
+
const diff = this.minus(that);
|
|
887
|
+
return { contains: true, diff: diff.isEmpty() ? undefined : diff };
|
|
888
|
+
}
|
|
889
|
+
return { contains: false };
|
|
890
|
+
}
|
|
854
891
|
minus(that) {
|
|
855
892
|
const updated = new SelectionSetUpdates();
|
|
856
893
|
for (const [key, thisSelection] of this._keyedSelections) {
|
|
857
894
|
const thatSelection = that._keyedSelections.get(key);
|
|
858
|
-
|
|
895
|
+
const otherSelections = that.triviallyNestedSelectionsForKey(this.parentType, key);
|
|
896
|
+
const allSelections = thatSelection ? [thatSelection].concat(otherSelections) : otherSelections;
|
|
897
|
+
if (allSelections.length === 0) {
|
|
859
898
|
updated.add(thisSelection);
|
|
860
899
|
}
|
|
861
900
|
else {
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
updated.add(thisSelection.withUpdatedSelectionSet(updatedSubSelectionSet));
|
|
866
|
-
}
|
|
901
|
+
const selectionDiff = allSelections.reduce((prev, val) => prev === null || prev === void 0 ? void 0 : prev.minus(val), thisSelection);
|
|
902
|
+
if (selectionDiff) {
|
|
903
|
+
updated.add(selectionDiff);
|
|
867
904
|
}
|
|
868
905
|
}
|
|
869
906
|
}
|
|
@@ -1231,6 +1268,39 @@ class AbstractSelection {
|
|
|
1231
1268
|
? this.us()
|
|
1232
1269
|
: this.withUpdatedSelectionSet(updatedSelectionSet);
|
|
1233
1270
|
}
|
|
1271
|
+
minus(that) {
|
|
1272
|
+
if (this.selectionSet && that.selectionSet) {
|
|
1273
|
+
const updatedSubSelectionSet = this.selectionSet.minus(that.selectionSet);
|
|
1274
|
+
if (!updatedSubSelectionSet.isEmpty()) {
|
|
1275
|
+
return this.withUpdatedSelectionSet(updatedSubSelectionSet);
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
return undefined;
|
|
1279
|
+
}
|
|
1280
|
+
tryOptimizeSubselectionOnce(_) {
|
|
1281
|
+
(0, utils_1.assert)(false, `UNSUPPORTED`);
|
|
1282
|
+
}
|
|
1283
|
+
tryOptimizeSubselectionWithFragments({ parentType, subSelection, fragments, fragmentFilter, }) {
|
|
1284
|
+
let candidates = fragments.maybeApplyingAtType(parentType);
|
|
1285
|
+
if (fragmentFilter) {
|
|
1286
|
+
candidates = candidates.filter(fragmentFilter);
|
|
1287
|
+
}
|
|
1288
|
+
let shouldTryAgain;
|
|
1289
|
+
do {
|
|
1290
|
+
const { spread, optimizedSelection, hasDiff } = this.tryOptimizeSubselectionOnce({ parentType, subSelection, candidates, fragments });
|
|
1291
|
+
if (optimizedSelection) {
|
|
1292
|
+
subSelection = optimizedSelection;
|
|
1293
|
+
}
|
|
1294
|
+
else if (spread) {
|
|
1295
|
+
return spread;
|
|
1296
|
+
}
|
|
1297
|
+
shouldTryAgain = !!spread && !!hasDiff;
|
|
1298
|
+
if (shouldTryAgain) {
|
|
1299
|
+
candidates = candidates.filter((c) => c !== (spread === null || spread === void 0 ? void 0 : spread.namedFragment));
|
|
1300
|
+
}
|
|
1301
|
+
} while (shouldTryAgain);
|
|
1302
|
+
return subSelection;
|
|
1303
|
+
}
|
|
1234
1304
|
}
|
|
1235
1305
|
class FieldSelection extends AbstractSelection {
|
|
1236
1306
|
constructor(field, _selectionSet) {
|
|
@@ -1251,20 +1321,36 @@ class FieldSelection extends AbstractSelection {
|
|
|
1251
1321
|
return this.element.key();
|
|
1252
1322
|
}
|
|
1253
1323
|
optimize(fragments) {
|
|
1254
|
-
|
|
1324
|
+
let optimizedSelection = this.selectionSet ? this.selectionSet.optimize(fragments) : undefined;
|
|
1255
1325
|
const fieldBaseType = (0, definitions_1.baseType)(this.element.definition.type);
|
|
1256
1326
|
if ((0, definitions_1.isCompositeType)(fieldBaseType) && optimizedSelection) {
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
}
|
|
1327
|
+
const optimized = this.tryOptimizeSubselectionWithFragments({
|
|
1328
|
+
parentType: fieldBaseType,
|
|
1329
|
+
subSelection: optimizedSelection,
|
|
1330
|
+
fragments,
|
|
1331
|
+
fragmentFilter: (f) => f.appliedDirectives.length === 0,
|
|
1332
|
+
});
|
|
1333
|
+
(0, utils_1.assert)(!(optimized instanceof FragmentSpreadSelection), 'tryOptimizeSubselectionOnce should never return only a spread');
|
|
1334
|
+
optimizedSelection = optimized;
|
|
1263
1335
|
}
|
|
1264
1336
|
return this.selectionSet === optimizedSelection
|
|
1265
1337
|
? this
|
|
1266
1338
|
: new FieldSelection(this.element, optimizedSelection);
|
|
1267
1339
|
}
|
|
1340
|
+
tryOptimizeSubselectionOnce({ parentType, subSelection, candidates, fragments, }) {
|
|
1341
|
+
let optimizedSelection = subSelection;
|
|
1342
|
+
for (const candidate of candidates) {
|
|
1343
|
+
const { contains, diff } = optimizedSelection.diffIfContains(candidate.selectionSet);
|
|
1344
|
+
if (contains) {
|
|
1345
|
+
const spread = new FragmentSpreadSelection(parentType, fragments, candidate, []);
|
|
1346
|
+
optimizedSelection = diff
|
|
1347
|
+
? new SelectionSetUpdates().add(spread).add(diff).toSelectionSet(parentType, fragments)
|
|
1348
|
+
: selectionSetOf(parentType, spread);
|
|
1349
|
+
return { spread, optimizedSelection, hasDiff: !!diff };
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
return {};
|
|
1353
|
+
}
|
|
1268
1354
|
filter(predicate) {
|
|
1269
1355
|
if (!this.selectionSet) {
|
|
1270
1356
|
return predicate(this) ? this : undefined;
|
|
@@ -1378,6 +1464,9 @@ class FieldSelection extends AbstractSelection {
|
|
|
1378
1464
|
}
|
|
1379
1465
|
return !!this.selectionSet && this.selectionSet.contains(that.selectionSet);
|
|
1380
1466
|
}
|
|
1467
|
+
isUnecessaryInlineFragment(_) {
|
|
1468
|
+
return false;
|
|
1469
|
+
}
|
|
1381
1470
|
toString(expandFragments = true, indent) {
|
|
1382
1471
|
return (indent !== null && indent !== void 0 ? indent : '') + this.element + (this.selectionSet ? ' ' + this.selectionSet.toString(expandFragments, true, indent) : '');
|
|
1383
1472
|
}
|
|
@@ -1409,18 +1498,11 @@ class FragmentSelection extends AbstractSelection {
|
|
|
1409
1498
|
hasDefer() {
|
|
1410
1499
|
return this.element.hasDefer() || this.selectionSet.hasDefer();
|
|
1411
1500
|
}
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
&& this.element.equals(that.element)
|
|
1418
|
-
&& this.selectionSet.equals(that.selectionSet);
|
|
1419
|
-
}
|
|
1420
|
-
contains(that) {
|
|
1421
|
-
return (that instanceof FragmentSelection)
|
|
1422
|
-
&& this.element.equals(that.element)
|
|
1423
|
-
&& this.selectionSet.contains(that.selectionSet);
|
|
1501
|
+
isUnecessaryInlineFragment(parentType) {
|
|
1502
|
+
return this.element.appliedDirectives.length === 0
|
|
1503
|
+
&& !!this.element.typeCondition
|
|
1504
|
+
&& (this.element.typeCondition.name === parentType.name
|
|
1505
|
+
|| ((0, definitions_1.isObjectType)(parentType) && (0, definitions_1.possibleRuntimeTypes)(this.element.typeCondition).some((t) => t.name === parentType.name)));
|
|
1424
1506
|
}
|
|
1425
1507
|
}
|
|
1426
1508
|
exports.FragmentSelection = FragmentSelection;
|
|
@@ -1488,28 +1570,49 @@ class InlineFragmentSelection extends FragmentSelection {
|
|
|
1488
1570
|
let optimizedSelection = this.selectionSet.optimize(fragments);
|
|
1489
1571
|
const typeCondition = this.element.typeCondition;
|
|
1490
1572
|
if (typeCondition) {
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1573
|
+
const optimized = this.tryOptimizeSubselectionWithFragments({
|
|
1574
|
+
parentType: typeCondition,
|
|
1575
|
+
subSelection: optimizedSelection,
|
|
1576
|
+
fragments,
|
|
1577
|
+
});
|
|
1578
|
+
if (optimized instanceof FragmentSpreadSelection) {
|
|
1579
|
+
return optimized;
|
|
1580
|
+
}
|
|
1581
|
+
optimizedSelection = optimized;
|
|
1582
|
+
}
|
|
1583
|
+
return this.selectionSet === optimizedSelection
|
|
1584
|
+
? this
|
|
1585
|
+
: new InlineFragmentSelection(this.element, optimizedSelection);
|
|
1586
|
+
}
|
|
1587
|
+
tryOptimizeSubselectionOnce({ parentType, subSelection, candidates, fragments, }) {
|
|
1588
|
+
let optimizedSelection = subSelection;
|
|
1589
|
+
for (const candidate of candidates) {
|
|
1590
|
+
const { contains, diff } = optimizedSelection.diffIfContains(candidate.selectionSet);
|
|
1591
|
+
if (contains) {
|
|
1592
|
+
if (!diff && (0, types_1.sameType)(this.element.typeCondition, candidate.typeCondition)) {
|
|
1593
|
+
let spreadDirectives = this.element.appliedDirectives;
|
|
1594
|
+
if (candidate.appliedDirectives.length > 0) {
|
|
1495
1595
|
const { isSubset, difference } = diffDirectives(this.element.appliedDirectives, candidate.appliedDirectives);
|
|
1496
1596
|
if (!isSubset) {
|
|
1497
1597
|
continue;
|
|
1498
1598
|
}
|
|
1499
1599
|
spreadDirectives = difference;
|
|
1500
1600
|
}
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1601
|
+
return {
|
|
1602
|
+
spread: new FragmentSpreadSelection(this.parentType, fragments, candidate, spreadDirectives),
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1605
|
+
if (candidate.appliedDirectives.length > 0) {
|
|
1606
|
+
continue;
|
|
1507
1607
|
}
|
|
1608
|
+
const spread = new FragmentSpreadSelection(parentType, fragments, candidate, []);
|
|
1609
|
+
optimizedSelection = diff
|
|
1610
|
+
? new SelectionSetUpdates().add(spread).add(diff).toSelectionSet(parentType, fragments)
|
|
1611
|
+
: selectionSetOf(parentType, spread);
|
|
1612
|
+
return { spread, optimizedSelection, hasDiff: !!diff };
|
|
1508
1613
|
}
|
|
1509
1614
|
}
|
|
1510
|
-
return
|
|
1511
|
-
? this
|
|
1512
|
-
: new InlineFragmentSelection(this.element, optimizedSelection);
|
|
1615
|
+
return {};
|
|
1513
1616
|
}
|
|
1514
1617
|
withoutDefer(labelsToRemove) {
|
|
1515
1618
|
const newSelection = this.selectionSet.withoutDefer(labelsToRemove);
|
|
@@ -1543,7 +1646,7 @@ class InlineFragmentSelection extends FragmentSelection {
|
|
|
1543
1646
|
return trimmed.isEmpty() ? undefined : trimmed;
|
|
1544
1647
|
}
|
|
1545
1648
|
if ((0, definitions_1.isObjectType)(currentType)) {
|
|
1546
|
-
if ((0, definitions_1.isObjectType)(thisCondition)) {
|
|
1649
|
+
if ((0, definitions_1.isObjectType)(thisCondition) || !(0, definitions_1.possibleRuntimeTypes)(thisCondition).includes(currentType)) {
|
|
1547
1650
|
return undefined;
|
|
1548
1651
|
}
|
|
1549
1652
|
else {
|
|
@@ -1591,6 +1694,19 @@ class InlineFragmentSelection extends FragmentSelection {
|
|
|
1591
1694
|
expandFragments(names, updatedFragments) {
|
|
1592
1695
|
return this.mapToSelectionSet((s) => s.expandFragments(names, updatedFragments));
|
|
1593
1696
|
}
|
|
1697
|
+
equals(that) {
|
|
1698
|
+
if (this === that) {
|
|
1699
|
+
return true;
|
|
1700
|
+
}
|
|
1701
|
+
return (that instanceof FragmentSelection)
|
|
1702
|
+
&& this.element.equals(that.element)
|
|
1703
|
+
&& this.selectionSet.equals(that.selectionSet);
|
|
1704
|
+
}
|
|
1705
|
+
contains(that) {
|
|
1706
|
+
return (that instanceof FragmentSelection)
|
|
1707
|
+
&& this.element.equals(that.element)
|
|
1708
|
+
&& this.selectionSet.contains(that.selectionSet);
|
|
1709
|
+
}
|
|
1594
1710
|
toString(expandFragments = true, indent) {
|
|
1595
1711
|
return (indent !== null && indent !== void 0 ? indent : '') + this.element + ' ' + this.selectionSet.toString(expandFragments, true, indent);
|
|
1596
1712
|
}
|
|
@@ -1685,6 +1801,26 @@ class FragmentSpreadSelection extends FragmentSelection {
|
|
|
1685
1801
|
withNormalizedDefer(_normalizer) {
|
|
1686
1802
|
(0, utils_1.assert)(false, 'Unsupported, see `Operation.withAllDeferLabelled`');
|
|
1687
1803
|
}
|
|
1804
|
+
minus(that) {
|
|
1805
|
+
(0, utils_1.assert)(this.equals(that), () => `Invalid operation for ${this.toString(false)} and ${that.toString(false)}`);
|
|
1806
|
+
return undefined;
|
|
1807
|
+
}
|
|
1808
|
+
equals(that) {
|
|
1809
|
+
if (this === that) {
|
|
1810
|
+
return true;
|
|
1811
|
+
}
|
|
1812
|
+
return (that instanceof FragmentSpreadSelection)
|
|
1813
|
+
&& this.namedFragment.name === that.namedFragment.name
|
|
1814
|
+
&& (0, definitions_1.sameDirectiveApplications)(this.spreadDirectives, that.spreadDirectives);
|
|
1815
|
+
}
|
|
1816
|
+
contains(that) {
|
|
1817
|
+
if (this.equals(that)) {
|
|
1818
|
+
return true;
|
|
1819
|
+
}
|
|
1820
|
+
return (that instanceof FragmentSelection)
|
|
1821
|
+
&& this.element.equals(that.element)
|
|
1822
|
+
&& this.selectionSet.contains(that.selectionSet);
|
|
1823
|
+
}
|
|
1688
1824
|
toString(expandFragments = true, indent) {
|
|
1689
1825
|
if (expandFragments) {
|
|
1690
1826
|
return (indent !== null && indent !== void 0 ? indent : '') + this.element + ' ' + this.selectionSet.toString(true, true, indent);
|