@graphql-tools/federation 4.4.2 → 4.4.3-alpha-12654e24df4f034d8c7112f5052f1b37674985ae
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 +21 -0
- package/dist/index.cjs +172 -26
- package/dist/index.js +172 -26
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @graphql-tools/federation
|
|
2
2
|
|
|
3
|
+
## 4.4.3-alpha-12654e24df4f034d8c7112f5052f1b37674985ae
|
|
4
|
+
### Patch Changes
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
- [#2346](https://github.com/graphql-hive/gateway/pull/2346) [`16fd346`](https://github.com/graphql-hive/gateway/commit/16fd346a18fd77e1094fe4ac2f7a6c2d8923bd68) Thanks [@copilot-swe-agent](https://github.com/apps/copilot-swe-agent)! - Fix `@requires` argument conflict when multiple computed fields in a federation subgraph require the same external field with different argument values (e.g. `price(currency: "USD")` vs `price(currency: "EUR")`).
|
|
9
|
+
|
|
10
|
+
Previously, all `@requires` selections for computed fields in a subgraph were merged into a single entity representation. When two computed fields needed the same external field but with different argument values, the stitching engine would alias each field differently — but both aliases ended up in the same representation object. The second field would overwrite the first, so one of the computed fields would always receive the wrong value.
|
|
11
|
+
|
|
12
|
+
**What changed:**
|
|
13
|
+
|
|
14
|
+
- **Computed field conflict detection** — when building subschema merge configs from the supergraph SDL, the federation stitching layer now detects conflicts: two computed fields conflict when they produce the same top-level aliased field name in their `@requires` selections but with different aliases (i.e. the same external field required with different argument values).
|
|
15
|
+
|
|
16
|
+
- **Conflict group isolation** — conflicting computed fields are separated into independent "conflict groups". Each group gets its own `SubschemaConfig` (sharing the same underlying executor/endpoint) with only its own computed fields and a deduplicated entity representation that carries only the aliased fields it actually needs. This ensures each group sends the correct representation to the subgraph and receives the right data back.
|
|
17
|
+
|
|
18
|
+
- **Schema scoping per group** — the main `SubschemaConfig`'s schema is filtered (via `mapSchema`) to remove computed fields that were moved to a conflict group, preventing the stitching engine from incorrectly routing those fields back to the main subschema. Each conflict group's `SubschemaConfig` is likewise scoped to expose only its own computed fields.
|
|
19
|
+
|
|
20
|
+
- **`getMergedTypeConfigFromKey` extended** — accepts an optional `keysExtraKeys` parameter so each conflict group can inject its own `extraKeys` set when building entity key functions, keeping key generation independent per group.
|
|
21
|
+
|
|
22
|
+
- **Federation audit test enabled** — the `requires-with-argument-conflict` case in the federation compatibility test suite was previously skipped for stitching (marked `it.todo`). It now passes and the skip has been removed.
|
|
23
|
+
|
|
3
24
|
## 4.4.2
|
|
4
25
|
### Patch Changes
|
|
5
26
|
|
package/dist/index.cjs
CHANGED
|
@@ -1272,14 +1272,15 @@ function getStitchingOptionsFromSupergraphSdl(opts) {
|
|
|
1272
1272
|
const mergeConfig = {};
|
|
1273
1273
|
const typeNameKeyMap = typeNameKeysBySubgraphMap.get(subgraphName);
|
|
1274
1274
|
const unionTypeNodes = [];
|
|
1275
|
+
const pendingConflictSubschemaConfigs = [];
|
|
1275
1276
|
if (typeNameKeyMap) {
|
|
1276
1277
|
const typeNameFieldsKeyMap = typeNameFieldsKeyBySubgraphMap.get(subgraphName);
|
|
1277
1278
|
for (const [typeName, keys] of typeNameKeyMap) {
|
|
1278
|
-
let getMergedTypeConfigFromKey2 = function(key) {
|
|
1279
|
+
let getMergedTypeConfigFromKey2 = function(key, keysExtraKeys = extraKeys) {
|
|
1279
1280
|
return {
|
|
1280
1281
|
selectionSet: `{ ${key} }`,
|
|
1281
1282
|
argsFromKeys: getArgsFromKeysForFederation,
|
|
1282
|
-
key: getKeyFnForFederation(typeName, [key, ...
|
|
1283
|
+
key: getKeyFnForFederation(typeName, [key, ...keysExtraKeys]),
|
|
1283
1284
|
fieldName: `_entities`,
|
|
1284
1285
|
dataLoaderOptions: {
|
|
1285
1286
|
cacheKeyFn: getCacheKeyFnFromKey(key),
|
|
@@ -1291,38 +1292,93 @@ function getStitchingOptionsFromSupergraphSdl(opts) {
|
|
|
1291
1292
|
const fieldsKeyMap = typeNameFieldsKeyMap?.get(typeName);
|
|
1292
1293
|
const extraKeys = /* @__PURE__ */ new Set();
|
|
1293
1294
|
if (fieldsKeyMap) {
|
|
1294
|
-
|
|
1295
|
+
let aliasFieldsWithArgs2 = function(selectionSetNode) {
|
|
1296
|
+
for (const selection of selectionSetNode.selections) {
|
|
1297
|
+
if (selection.kind === graphql.Kind.FIELD && selection.arguments?.length) {
|
|
1298
|
+
const argsHash = selection.arguments.map(
|
|
1299
|
+
(arg) => arg.name.value + // TODO: slow? faster hash?
|
|
1300
|
+
memoizedASTPrint(arg.value).replace(/[^a-zA-Z0-9]/g, "")
|
|
1301
|
+
).join("");
|
|
1302
|
+
selection.alias = {
|
|
1303
|
+
kind: graphql.Kind.NAME,
|
|
1304
|
+
value: "_" + selection.name.value + "_" + argsHash
|
|
1305
|
+
};
|
|
1306
|
+
}
|
|
1307
|
+
if ("selectionSet" in selection && selection.selectionSet) {
|
|
1308
|
+
aliasFieldsWithArgs2(selection.selectionSet);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
};
|
|
1312
|
+
const mainFieldsConfig = mergedTypeConfig.fields = {};
|
|
1313
|
+
const groups = [
|
|
1314
|
+
{
|
|
1315
|
+
extraKeys,
|
|
1316
|
+
fieldsConfig: mainFieldsConfig,
|
|
1317
|
+
aliasedFields: /* @__PURE__ */ new Map()
|
|
1318
|
+
}
|
|
1319
|
+
];
|
|
1295
1320
|
for (const [fieldName, fieldNameKey] of fieldsKeyMap) {
|
|
1296
1321
|
const selectionSetNode = utils.parseSelectionSet(`{${fieldNameKey}}`);
|
|
1297
|
-
(
|
|
1298
|
-
for (const selection of selectionSetNode2.selections) {
|
|
1299
|
-
if (selection.kind === graphql.Kind.FIELD && selection.arguments?.length) {
|
|
1300
|
-
const argsHash = selection.arguments.map(
|
|
1301
|
-
(arg) => arg.name.value + // TODO: slow? faster hash?
|
|
1302
|
-
memoizedASTPrint(arg.value).replace(
|
|
1303
|
-
/[^a-zA-Z0-9]/g,
|
|
1304
|
-
""
|
|
1305
|
-
)
|
|
1306
|
-
).join("");
|
|
1307
|
-
selection.alias = {
|
|
1308
|
-
kind: graphql.Kind.NAME,
|
|
1309
|
-
value: "_" + selection.name.value + "_" + argsHash
|
|
1310
|
-
};
|
|
1311
|
-
}
|
|
1312
|
-
if ("selectionSet" in selection && selection.selectionSet) {
|
|
1313
|
-
aliasFieldsWithArgs(selection.selectionSet);
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
})(selectionSetNode);
|
|
1322
|
+
aliasFieldsWithArgs2(selectionSetNode);
|
|
1317
1323
|
const selectionSet = graphql.print(selectionSetNode).replaceAll(/\n/g, " ").replaceAll(/\s+/g, " ");
|
|
1318
|
-
|
|
1324
|
+
const extraKey = (
|
|
1319
1325
|
// remove first and last characters (curly braces)
|
|
1320
1326
|
selectionSet.slice(1, -1)
|
|
1321
1327
|
);
|
|
1322
|
-
|
|
1328
|
+
const fieldAliasedNames = /* @__PURE__ */ new Map();
|
|
1329
|
+
for (const sel of selectionSetNode.selections) {
|
|
1330
|
+
if (sel.kind === graphql.Kind.FIELD && sel.alias) {
|
|
1331
|
+
fieldAliasedNames.set(sel.name.value, sel.alias.value);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
let targetGroup;
|
|
1335
|
+
for (const group of groups) {
|
|
1336
|
+
let hasConflict = false;
|
|
1337
|
+
for (const [origName, aliasName] of fieldAliasedNames) {
|
|
1338
|
+
const existingAlias = group.aliasedFields.get(origName);
|
|
1339
|
+
if (existingAlias !== void 0 && existingAlias !== aliasName) {
|
|
1340
|
+
hasConflict = true;
|
|
1341
|
+
break;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
if (!hasConflict) {
|
|
1345
|
+
targetGroup = group;
|
|
1346
|
+
break;
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
if (!targetGroup) {
|
|
1350
|
+
const newExtraKeys = /* @__PURE__ */ new Set();
|
|
1351
|
+
const newFieldsConfig = {};
|
|
1352
|
+
targetGroup = {
|
|
1353
|
+
extraKeys: newExtraKeys,
|
|
1354
|
+
fieldsConfig: newFieldsConfig,
|
|
1355
|
+
aliasedFields: /* @__PURE__ */ new Map()
|
|
1356
|
+
};
|
|
1357
|
+
groups.push(targetGroup);
|
|
1358
|
+
}
|
|
1359
|
+
targetGroup.extraKeys.add(extraKey);
|
|
1360
|
+
targetGroup.fieldsConfig[fieldName] = {
|
|
1323
1361
|
selectionSet,
|
|
1324
1362
|
computed: true
|
|
1325
1363
|
};
|
|
1364
|
+
for (const [origName, aliasName] of fieldAliasedNames) {
|
|
1365
|
+
targetGroup.aliasedFields.set(origName, aliasName);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
for (const group of groups.slice(1)) {
|
|
1369
|
+
const additionalMergeTypeConfig = {
|
|
1370
|
+
fields: group.fieldsConfig
|
|
1371
|
+
};
|
|
1372
|
+
if (typeNameCanonicalMap.get(typeName) === subgraphName) {
|
|
1373
|
+
additionalMergeTypeConfig.canonical = true;
|
|
1374
|
+
}
|
|
1375
|
+
pendingConflictSubschemaConfigs.push({
|
|
1376
|
+
typeName,
|
|
1377
|
+
// Store closure-captured values for later SubschemaConfig creation
|
|
1378
|
+
// by borrowing getMergedTypeConfigFromKey with the group's extraKeys.
|
|
1379
|
+
mergeTypeConfig: additionalMergeTypeConfig,
|
|
1380
|
+
groupExtraKeys: group.extraKeys
|
|
1381
|
+
});
|
|
1326
1382
|
}
|
|
1327
1383
|
}
|
|
1328
1384
|
if (typeNameCanonicalMap.get(typeName) === subgraphName) {
|
|
@@ -1341,6 +1397,21 @@ function getStitchingOptionsFromSupergraphSdl(opts) {
|
|
|
1341
1397
|
);
|
|
1342
1398
|
mergedTypeConfig.entryPoints = entryPoints;
|
|
1343
1399
|
}
|
|
1400
|
+
for (const pending of pendingConflictSubschemaConfigs) {
|
|
1401
|
+
if (pending.typeName === typeName && !("selectionSet" in pending.mergeTypeConfig) && !("entryPoints" in pending.mergeTypeConfig)) {
|
|
1402
|
+
const groupExtraKeys = pending.groupExtraKeys;
|
|
1403
|
+
if (keysArr.length === 1 && keysArr[0]) {
|
|
1404
|
+
Object.assign(
|
|
1405
|
+
pending.mergeTypeConfig,
|
|
1406
|
+
getMergedTypeConfigFromKey2(keysArr[0], groupExtraKeys)
|
|
1407
|
+
);
|
|
1408
|
+
} else if (keysArr.length > 1) {
|
|
1409
|
+
pending.mergeTypeConfig.entryPoints = keysArr.map(
|
|
1410
|
+
(key) => getMergedTypeConfigFromKey2(key, groupExtraKeys)
|
|
1411
|
+
);
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1344
1415
|
unionTypeNodes.push({
|
|
1345
1416
|
kind: graphql.Kind.NAMED_TYPE,
|
|
1346
1417
|
name: {
|
|
@@ -1731,10 +1802,55 @@ function getStitchingOptionsFromSupergraphSdl(opts) {
|
|
|
1731
1802
|
}
|
|
1732
1803
|
}
|
|
1733
1804
|
}
|
|
1805
|
+
let mainSchema = schema;
|
|
1806
|
+
const additionalGroupFieldsByType = /* @__PURE__ */ new Map();
|
|
1807
|
+
for (const {
|
|
1808
|
+
typeName,
|
|
1809
|
+
mergeTypeConfig
|
|
1810
|
+
} of pendingConflictSubschemaConfigs) {
|
|
1811
|
+
for (const [fieldName, fieldConfig] of Object.entries(
|
|
1812
|
+
mergeTypeConfig.fields ?? {}
|
|
1813
|
+
)) {
|
|
1814
|
+
if (!fieldConfig?.computed) continue;
|
|
1815
|
+
let set = additionalGroupFieldsByType.get(typeName);
|
|
1816
|
+
if (!set) {
|
|
1817
|
+
set = /* @__PURE__ */ new Set();
|
|
1818
|
+
additionalGroupFieldsByType.set(typeName, set);
|
|
1819
|
+
}
|
|
1820
|
+
set.add(fieldName);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
if (additionalGroupFieldsByType.size > 0) {
|
|
1824
|
+
mainSchema = utils.mapSchema(schema, {
|
|
1825
|
+
[utils.MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName, typeName) => {
|
|
1826
|
+
if (additionalGroupFieldsByType.get(typeName)?.has(fieldName)) {
|
|
1827
|
+
return null;
|
|
1828
|
+
}
|
|
1829
|
+
return fieldConfig;
|
|
1830
|
+
}
|
|
1831
|
+
});
|
|
1832
|
+
}
|
|
1833
|
+
const allComputedFieldsByType = new Map(
|
|
1834
|
+
Array.from(additionalGroupFieldsByType, ([t, s]) => [t, new Set(s)])
|
|
1835
|
+
);
|
|
1836
|
+
for (const [typeName, typeConfig] of Object.entries(mergeConfig)) {
|
|
1837
|
+
if (!typeConfig?.fields) continue;
|
|
1838
|
+
for (const [fieldName, fieldConfig] of Object.entries(
|
|
1839
|
+
typeConfig.fields
|
|
1840
|
+
)) {
|
|
1841
|
+
if (!fieldConfig?.computed) continue;
|
|
1842
|
+
let set = allComputedFieldsByType.get(typeName);
|
|
1843
|
+
if (!set) {
|
|
1844
|
+
set = /* @__PURE__ */ new Set();
|
|
1845
|
+
allComputedFieldsByType.set(typeName, set);
|
|
1846
|
+
}
|
|
1847
|
+
set.add(fieldName);
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1734
1850
|
const subschemaConfig = {
|
|
1735
1851
|
name: subgraphName,
|
|
1736
1852
|
endpoint,
|
|
1737
|
-
schema,
|
|
1853
|
+
schema: mainSchema,
|
|
1738
1854
|
executor: executor$1,
|
|
1739
1855
|
merge: mergeConfig,
|
|
1740
1856
|
transforms,
|
|
@@ -1742,6 +1858,36 @@ function getStitchingOptionsFromSupergraphSdl(opts) {
|
|
|
1742
1858
|
batchingOptions: opts.batchingOptions
|
|
1743
1859
|
};
|
|
1744
1860
|
subschemas.push(subschemaConfig);
|
|
1861
|
+
for (const {
|
|
1862
|
+
typeName,
|
|
1863
|
+
mergeTypeConfig
|
|
1864
|
+
} of pendingConflictSubschemaConfigs) {
|
|
1865
|
+
const groupOwnFields = new Set(
|
|
1866
|
+
Object.entries(mergeTypeConfig.fields ?? {}).filter(([, fc]) => fc?.computed).map(([fn]) => fn)
|
|
1867
|
+
);
|
|
1868
|
+
const allComputedForType = allComputedFieldsByType.get(typeName) ?? /* @__PURE__ */ new Set();
|
|
1869
|
+
const fieldsToRemove = new Set(
|
|
1870
|
+
[...allComputedForType].filter((f) => !groupOwnFields.has(f))
|
|
1871
|
+
);
|
|
1872
|
+
const groupSchema = fieldsToRemove.size > 0 ? utils.mapSchema(schema, {
|
|
1873
|
+
[utils.MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName, type) => {
|
|
1874
|
+
if (type === typeName && fieldsToRemove.has(fieldName)) {
|
|
1875
|
+
return null;
|
|
1876
|
+
}
|
|
1877
|
+
return fieldConfig;
|
|
1878
|
+
}
|
|
1879
|
+
}) : schema;
|
|
1880
|
+
subschemas.push({
|
|
1881
|
+
name: subgraphName,
|
|
1882
|
+
endpoint,
|
|
1883
|
+
schema: groupSchema,
|
|
1884
|
+
executor: executor$1,
|
|
1885
|
+
merge: { [typeName]: mergeTypeConfig },
|
|
1886
|
+
transforms,
|
|
1887
|
+
batch: opts.batch,
|
|
1888
|
+
batchingOptions: opts.batchingOptions
|
|
1889
|
+
});
|
|
1890
|
+
}
|
|
1745
1891
|
}
|
|
1746
1892
|
const defaultMerger = stitch.getDefaultFieldConfigMerger(true);
|
|
1747
1893
|
const fieldConfigMerger = function(candidates) {
|
package/dist/index.js
CHANGED
|
@@ -1270,14 +1270,15 @@ function getStitchingOptionsFromSupergraphSdl(opts) {
|
|
|
1270
1270
|
const mergeConfig = {};
|
|
1271
1271
|
const typeNameKeyMap = typeNameKeysBySubgraphMap.get(subgraphName);
|
|
1272
1272
|
const unionTypeNodes = [];
|
|
1273
|
+
const pendingConflictSubschemaConfigs = [];
|
|
1273
1274
|
if (typeNameKeyMap) {
|
|
1274
1275
|
const typeNameFieldsKeyMap = typeNameFieldsKeyBySubgraphMap.get(subgraphName);
|
|
1275
1276
|
for (const [typeName, keys] of typeNameKeyMap) {
|
|
1276
|
-
let getMergedTypeConfigFromKey2 = function(key) {
|
|
1277
|
+
let getMergedTypeConfigFromKey2 = function(key, keysExtraKeys = extraKeys) {
|
|
1277
1278
|
return {
|
|
1278
1279
|
selectionSet: `{ ${key} }`,
|
|
1279
1280
|
argsFromKeys: getArgsFromKeysForFederation,
|
|
1280
|
-
key: getKeyFnForFederation(typeName, [key, ...
|
|
1281
|
+
key: getKeyFnForFederation(typeName, [key, ...keysExtraKeys]),
|
|
1281
1282
|
fieldName: `_entities`,
|
|
1282
1283
|
dataLoaderOptions: {
|
|
1283
1284
|
cacheKeyFn: getCacheKeyFnFromKey(key),
|
|
@@ -1289,38 +1290,93 @@ function getStitchingOptionsFromSupergraphSdl(opts) {
|
|
|
1289
1290
|
const fieldsKeyMap = typeNameFieldsKeyMap?.get(typeName);
|
|
1290
1291
|
const extraKeys = /* @__PURE__ */ new Set();
|
|
1291
1292
|
if (fieldsKeyMap) {
|
|
1292
|
-
|
|
1293
|
+
let aliasFieldsWithArgs2 = function(selectionSetNode) {
|
|
1294
|
+
for (const selection of selectionSetNode.selections) {
|
|
1295
|
+
if (selection.kind === Kind.FIELD && selection.arguments?.length) {
|
|
1296
|
+
const argsHash = selection.arguments.map(
|
|
1297
|
+
(arg) => arg.name.value + // TODO: slow? faster hash?
|
|
1298
|
+
memoizedASTPrint(arg.value).replace(/[^a-zA-Z0-9]/g, "")
|
|
1299
|
+
).join("");
|
|
1300
|
+
selection.alias = {
|
|
1301
|
+
kind: Kind.NAME,
|
|
1302
|
+
value: "_" + selection.name.value + "_" + argsHash
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1305
|
+
if ("selectionSet" in selection && selection.selectionSet) {
|
|
1306
|
+
aliasFieldsWithArgs2(selection.selectionSet);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
};
|
|
1310
|
+
const mainFieldsConfig = mergedTypeConfig.fields = {};
|
|
1311
|
+
const groups = [
|
|
1312
|
+
{
|
|
1313
|
+
extraKeys,
|
|
1314
|
+
fieldsConfig: mainFieldsConfig,
|
|
1315
|
+
aliasedFields: /* @__PURE__ */ new Map()
|
|
1316
|
+
}
|
|
1317
|
+
];
|
|
1293
1318
|
for (const [fieldName, fieldNameKey] of fieldsKeyMap) {
|
|
1294
1319
|
const selectionSetNode = parseSelectionSet(`{${fieldNameKey}}`);
|
|
1295
|
-
(
|
|
1296
|
-
for (const selection of selectionSetNode2.selections) {
|
|
1297
|
-
if (selection.kind === Kind.FIELD && selection.arguments?.length) {
|
|
1298
|
-
const argsHash = selection.arguments.map(
|
|
1299
|
-
(arg) => arg.name.value + // TODO: slow? faster hash?
|
|
1300
|
-
memoizedASTPrint(arg.value).replace(
|
|
1301
|
-
/[^a-zA-Z0-9]/g,
|
|
1302
|
-
""
|
|
1303
|
-
)
|
|
1304
|
-
).join("");
|
|
1305
|
-
selection.alias = {
|
|
1306
|
-
kind: Kind.NAME,
|
|
1307
|
-
value: "_" + selection.name.value + "_" + argsHash
|
|
1308
|
-
};
|
|
1309
|
-
}
|
|
1310
|
-
if ("selectionSet" in selection && selection.selectionSet) {
|
|
1311
|
-
aliasFieldsWithArgs(selection.selectionSet);
|
|
1312
|
-
}
|
|
1313
|
-
}
|
|
1314
|
-
})(selectionSetNode);
|
|
1320
|
+
aliasFieldsWithArgs2(selectionSetNode);
|
|
1315
1321
|
const selectionSet = print(selectionSetNode).replaceAll(/\n/g, " ").replaceAll(/\s+/g, " ");
|
|
1316
|
-
|
|
1322
|
+
const extraKey = (
|
|
1317
1323
|
// remove first and last characters (curly braces)
|
|
1318
1324
|
selectionSet.slice(1, -1)
|
|
1319
1325
|
);
|
|
1320
|
-
|
|
1326
|
+
const fieldAliasedNames = /* @__PURE__ */ new Map();
|
|
1327
|
+
for (const sel of selectionSetNode.selections) {
|
|
1328
|
+
if (sel.kind === Kind.FIELD && sel.alias) {
|
|
1329
|
+
fieldAliasedNames.set(sel.name.value, sel.alias.value);
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
let targetGroup;
|
|
1333
|
+
for (const group of groups) {
|
|
1334
|
+
let hasConflict = false;
|
|
1335
|
+
for (const [origName, aliasName] of fieldAliasedNames) {
|
|
1336
|
+
const existingAlias = group.aliasedFields.get(origName);
|
|
1337
|
+
if (existingAlias !== void 0 && existingAlias !== aliasName) {
|
|
1338
|
+
hasConflict = true;
|
|
1339
|
+
break;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
if (!hasConflict) {
|
|
1343
|
+
targetGroup = group;
|
|
1344
|
+
break;
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
if (!targetGroup) {
|
|
1348
|
+
const newExtraKeys = /* @__PURE__ */ new Set();
|
|
1349
|
+
const newFieldsConfig = {};
|
|
1350
|
+
targetGroup = {
|
|
1351
|
+
extraKeys: newExtraKeys,
|
|
1352
|
+
fieldsConfig: newFieldsConfig,
|
|
1353
|
+
aliasedFields: /* @__PURE__ */ new Map()
|
|
1354
|
+
};
|
|
1355
|
+
groups.push(targetGroup);
|
|
1356
|
+
}
|
|
1357
|
+
targetGroup.extraKeys.add(extraKey);
|
|
1358
|
+
targetGroup.fieldsConfig[fieldName] = {
|
|
1321
1359
|
selectionSet,
|
|
1322
1360
|
computed: true
|
|
1323
1361
|
};
|
|
1362
|
+
for (const [origName, aliasName] of fieldAliasedNames) {
|
|
1363
|
+
targetGroup.aliasedFields.set(origName, aliasName);
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
1366
|
+
for (const group of groups.slice(1)) {
|
|
1367
|
+
const additionalMergeTypeConfig = {
|
|
1368
|
+
fields: group.fieldsConfig
|
|
1369
|
+
};
|
|
1370
|
+
if (typeNameCanonicalMap.get(typeName) === subgraphName) {
|
|
1371
|
+
additionalMergeTypeConfig.canonical = true;
|
|
1372
|
+
}
|
|
1373
|
+
pendingConflictSubschemaConfigs.push({
|
|
1374
|
+
typeName,
|
|
1375
|
+
// Store closure-captured values for later SubschemaConfig creation
|
|
1376
|
+
// by borrowing getMergedTypeConfigFromKey with the group's extraKeys.
|
|
1377
|
+
mergeTypeConfig: additionalMergeTypeConfig,
|
|
1378
|
+
groupExtraKeys: group.extraKeys
|
|
1379
|
+
});
|
|
1324
1380
|
}
|
|
1325
1381
|
}
|
|
1326
1382
|
if (typeNameCanonicalMap.get(typeName) === subgraphName) {
|
|
@@ -1339,6 +1395,21 @@ function getStitchingOptionsFromSupergraphSdl(opts) {
|
|
|
1339
1395
|
);
|
|
1340
1396
|
mergedTypeConfig.entryPoints = entryPoints;
|
|
1341
1397
|
}
|
|
1398
|
+
for (const pending of pendingConflictSubschemaConfigs) {
|
|
1399
|
+
if (pending.typeName === typeName && !("selectionSet" in pending.mergeTypeConfig) && !("entryPoints" in pending.mergeTypeConfig)) {
|
|
1400
|
+
const groupExtraKeys = pending.groupExtraKeys;
|
|
1401
|
+
if (keysArr.length === 1 && keysArr[0]) {
|
|
1402
|
+
Object.assign(
|
|
1403
|
+
pending.mergeTypeConfig,
|
|
1404
|
+
getMergedTypeConfigFromKey2(keysArr[0], groupExtraKeys)
|
|
1405
|
+
);
|
|
1406
|
+
} else if (keysArr.length > 1) {
|
|
1407
|
+
pending.mergeTypeConfig.entryPoints = keysArr.map(
|
|
1408
|
+
(key) => getMergedTypeConfigFromKey2(key, groupExtraKeys)
|
|
1409
|
+
);
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1342
1413
|
unionTypeNodes.push({
|
|
1343
1414
|
kind: Kind.NAMED_TYPE,
|
|
1344
1415
|
name: {
|
|
@@ -1729,10 +1800,55 @@ function getStitchingOptionsFromSupergraphSdl(opts) {
|
|
|
1729
1800
|
}
|
|
1730
1801
|
}
|
|
1731
1802
|
}
|
|
1803
|
+
let mainSchema = schema;
|
|
1804
|
+
const additionalGroupFieldsByType = /* @__PURE__ */ new Map();
|
|
1805
|
+
for (const {
|
|
1806
|
+
typeName,
|
|
1807
|
+
mergeTypeConfig
|
|
1808
|
+
} of pendingConflictSubschemaConfigs) {
|
|
1809
|
+
for (const [fieldName, fieldConfig] of Object.entries(
|
|
1810
|
+
mergeTypeConfig.fields ?? {}
|
|
1811
|
+
)) {
|
|
1812
|
+
if (!fieldConfig?.computed) continue;
|
|
1813
|
+
let set = additionalGroupFieldsByType.get(typeName);
|
|
1814
|
+
if (!set) {
|
|
1815
|
+
set = /* @__PURE__ */ new Set();
|
|
1816
|
+
additionalGroupFieldsByType.set(typeName, set);
|
|
1817
|
+
}
|
|
1818
|
+
set.add(fieldName);
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
if (additionalGroupFieldsByType.size > 0) {
|
|
1822
|
+
mainSchema = mapSchema(schema, {
|
|
1823
|
+
[MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName, typeName) => {
|
|
1824
|
+
if (additionalGroupFieldsByType.get(typeName)?.has(fieldName)) {
|
|
1825
|
+
return null;
|
|
1826
|
+
}
|
|
1827
|
+
return fieldConfig;
|
|
1828
|
+
}
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
const allComputedFieldsByType = new Map(
|
|
1832
|
+
Array.from(additionalGroupFieldsByType, ([t, s]) => [t, new Set(s)])
|
|
1833
|
+
);
|
|
1834
|
+
for (const [typeName, typeConfig] of Object.entries(mergeConfig)) {
|
|
1835
|
+
if (!typeConfig?.fields) continue;
|
|
1836
|
+
for (const [fieldName, fieldConfig] of Object.entries(
|
|
1837
|
+
typeConfig.fields
|
|
1838
|
+
)) {
|
|
1839
|
+
if (!fieldConfig?.computed) continue;
|
|
1840
|
+
let set = allComputedFieldsByType.get(typeName);
|
|
1841
|
+
if (!set) {
|
|
1842
|
+
set = /* @__PURE__ */ new Set();
|
|
1843
|
+
allComputedFieldsByType.set(typeName, set);
|
|
1844
|
+
}
|
|
1845
|
+
set.add(fieldName);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1732
1848
|
const subschemaConfig = {
|
|
1733
1849
|
name: subgraphName,
|
|
1734
1850
|
endpoint,
|
|
1735
|
-
schema,
|
|
1851
|
+
schema: mainSchema,
|
|
1736
1852
|
executor,
|
|
1737
1853
|
merge: mergeConfig,
|
|
1738
1854
|
transforms,
|
|
@@ -1740,6 +1856,36 @@ function getStitchingOptionsFromSupergraphSdl(opts) {
|
|
|
1740
1856
|
batchingOptions: opts.batchingOptions
|
|
1741
1857
|
};
|
|
1742
1858
|
subschemas.push(subschemaConfig);
|
|
1859
|
+
for (const {
|
|
1860
|
+
typeName,
|
|
1861
|
+
mergeTypeConfig
|
|
1862
|
+
} of pendingConflictSubschemaConfigs) {
|
|
1863
|
+
const groupOwnFields = new Set(
|
|
1864
|
+
Object.entries(mergeTypeConfig.fields ?? {}).filter(([, fc]) => fc?.computed).map(([fn]) => fn)
|
|
1865
|
+
);
|
|
1866
|
+
const allComputedForType = allComputedFieldsByType.get(typeName) ?? /* @__PURE__ */ new Set();
|
|
1867
|
+
const fieldsToRemove = new Set(
|
|
1868
|
+
[...allComputedForType].filter((f) => !groupOwnFields.has(f))
|
|
1869
|
+
);
|
|
1870
|
+
const groupSchema = fieldsToRemove.size > 0 ? mapSchema(schema, {
|
|
1871
|
+
[MapperKind.OBJECT_FIELD]: (fieldConfig, fieldName, type) => {
|
|
1872
|
+
if (type === typeName && fieldsToRemove.has(fieldName)) {
|
|
1873
|
+
return null;
|
|
1874
|
+
}
|
|
1875
|
+
return fieldConfig;
|
|
1876
|
+
}
|
|
1877
|
+
}) : schema;
|
|
1878
|
+
subschemas.push({
|
|
1879
|
+
name: subgraphName,
|
|
1880
|
+
endpoint,
|
|
1881
|
+
schema: groupSchema,
|
|
1882
|
+
executor,
|
|
1883
|
+
merge: { [typeName]: mergeTypeConfig },
|
|
1884
|
+
transforms,
|
|
1885
|
+
batch: opts.batch,
|
|
1886
|
+
batchingOptions: opts.batchingOptions
|
|
1887
|
+
});
|
|
1888
|
+
}
|
|
1743
1889
|
}
|
|
1744
1890
|
const defaultMerger = getDefaultFieldConfigMerger(true);
|
|
1745
1891
|
const fieldConfigMerger = function(candidates) {
|
package/package.json
CHANGED