@graphql-tools/delegate 12.0.11 → 12.0.12-alpha-bcdf6a1333a84f3ead114d676e66e609c350e084

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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # @graphql-tools/delegate
2
2
 
3
+ ## 12.0.12-alpha-bcdf6a1333a84f3ead114d676e66e609c350e084
4
+ ### Patch Changes
5
+
6
+
7
+
8
+ - [#2106](https://github.com/graphql-hive/gateway/pull/2106) [`bcdf6a1`](https://github.com/graphql-hive/gateway/commit/bcdf6a1333a84f3ead114d676e66e609c350e084) Thanks [@ardatan](https://github.com/ardatan)! - - Optimizations to select ONLY required fields when fetching the missing fields from other subgraphs
9
+ - Do not try to resolve types from the subschemas which only have the stub types, for example if a subgraph only has `id` field as a stub, do not use that subgraph as a target subgraph for resolving the type, because it will not have any other fields than `id`.
10
+
3
11
  ## 12.0.11
4
12
  ### Patch Changes
5
13
 
package/dist/index.cjs CHANGED
@@ -598,6 +598,9 @@ function finalizeGatewayDocument(targetSchema, fragments, operations, onOverlapp
598
598
  const validFragments = [];
599
599
  const validFragmentsWithType = /* @__PURE__ */ Object.create(null);
600
600
  for (const fragment of fragments) {
601
+ if (fragment.selectionSet.selections.length === 0) {
602
+ continue;
603
+ }
601
604
  const typeName = fragment.typeCondition.name.value;
602
605
  const type = targetSchema.getType(typeName);
603
606
  if (type != null) {
@@ -1206,6 +1209,12 @@ function prepareGatewayDocument(originalDocument, transformedSchema, returnType,
1206
1209
  kind: graphql.Kind.DOCUMENT,
1207
1210
  definitions: [...operations, ...fragments, ...expandedFragments]
1208
1211
  };
1212
+ const fragmentMap = /* @__PURE__ */ Object.create(null);
1213
+ for (const fragment of expandedDocument.definitions) {
1214
+ if (fragment.kind === graphql.Kind.FRAGMENT_DEFINITION) {
1215
+ fragmentMap[fragment.name.value] = fragment;
1216
+ }
1217
+ }
1209
1218
  const visitorKeyMap = {
1210
1219
  Document: ["definitions"],
1211
1220
  OperationDefinition: ["selectionSet"],
@@ -1229,7 +1238,8 @@ function prepareGatewayDocument(originalDocument, transformedSchema, returnType,
1229
1238
  fieldNodesByField,
1230
1239
  dynamicSelectionSetsByField,
1231
1240
  infoSchema,
1232
- visitedSelections
1241
+ visitedSelections,
1242
+ fragmentMap
1233
1243
  )
1234
1244
  }),
1235
1245
  // visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
@@ -1267,11 +1277,19 @@ const getExtraPossibleTypesFn = utils.memoize2(function getExtraPossibleTypes(tr
1267
1277
  return extraTypesForSubschema;
1268
1278
  };
1269
1279
  });
1270
- function visitSelectionSet(node, fragmentReplacements, transformedSchema, typeInfo, possibleTypesMap, reversePossibleTypesMap2, interfaceExtensionsMap, fieldNodesByType, fieldNodesByField, dynamicSelectionSetsByField, infoSchema, visitedSelections) {
1280
+ function visitSelectionSet(node, fragmentReplacements, transformedSchema, typeInfo, possibleTypesMap, reversePossibleTypesMap2, interfaceExtensionsMap, fieldNodesByType, fieldNodesByField, dynamicSelectionSetsByField, infoSchema, visitedSelections, fragmentMap) {
1271
1281
  const newSelections = /* @__PURE__ */ new Set();
1272
1282
  const maybeType = typeInfo.getParentType();
1273
1283
  if (maybeType != null) {
1274
1284
  const parentType = graphql.getNamedType(maybeType);
1285
+ if (isSelectionSetSatisfiedBySchema(
1286
+ transformedSchema,
1287
+ parentType,
1288
+ node,
1289
+ fragmentMap
1290
+ )) {
1291
+ return node;
1292
+ }
1275
1293
  const parentTypeName = parentType.name;
1276
1294
  const fieldNodes = fieldNodesByType[parentTypeName];
1277
1295
  if (fieldNodes) {
@@ -1461,6 +1479,91 @@ function isFieldNodeSatisfiedBySelections(fieldNode, existing) {
1461
1479
  }
1462
1480
  return false;
1463
1481
  }
1482
+ function isSelectionSetSatisfiedBySchema(schema, type, selectionSet, fragmentsMap) {
1483
+ const namedType = graphql.getNamedType(type);
1484
+ if (graphql.isLeafType(namedType)) {
1485
+ return true;
1486
+ }
1487
+ for (const selection of selectionSet.selections) {
1488
+ if (selection.kind === graphql.Kind.FIELD) {
1489
+ if (graphql.isAbstractType(namedType)) {
1490
+ return false;
1491
+ }
1492
+ const fieldName = selection.name.value;
1493
+ if (fieldName === "__typename") {
1494
+ continue;
1495
+ }
1496
+ if (graphql.isObjectType(namedType) || graphql.isInterfaceType(namedType)) {
1497
+ const field = namedType.getFields()[fieldName];
1498
+ if (!field) {
1499
+ return false;
1500
+ }
1501
+ if (selection.selectionSet) {
1502
+ const fieldType = graphql.getNamedType(field.type);
1503
+ const satisfied = isSelectionSetSatisfiedBySchema(
1504
+ schema,
1505
+ fieldType,
1506
+ selection.selectionSet,
1507
+ fragmentsMap
1508
+ );
1509
+ if (!satisfied) {
1510
+ return false;
1511
+ }
1512
+ }
1513
+ } else {
1514
+ return false;
1515
+ }
1516
+ } else if (selection.kind === graphql.Kind.INLINE_FRAGMENT) {
1517
+ if (selection.typeCondition) {
1518
+ const typeConditionName = selection.typeCondition.name.value;
1519
+ const typeCondition = schema.getType(typeConditionName);
1520
+ if (!typeCondition) {
1521
+ return false;
1522
+ }
1523
+ const satisfied = isSelectionSetSatisfiedBySchema(
1524
+ schema,
1525
+ typeCondition,
1526
+ selection.selectionSet,
1527
+ fragmentsMap
1528
+ );
1529
+ if (!satisfied) {
1530
+ return false;
1531
+ }
1532
+ } else {
1533
+ const satisfied = isSelectionSetSatisfiedBySchema(
1534
+ schema,
1535
+ type,
1536
+ selection.selectionSet,
1537
+ fragmentsMap
1538
+ );
1539
+ if (!satisfied) {
1540
+ return false;
1541
+ }
1542
+ }
1543
+ } else if (selection.kind === graphql.Kind.FRAGMENT_SPREAD) {
1544
+ const fragmentName = selection.name.value;
1545
+ const fragment = fragmentsMap[fragmentName];
1546
+ if (!fragment) {
1547
+ return false;
1548
+ }
1549
+ const typeConditionName = fragment.typeCondition.name.value;
1550
+ const typeCondition = schema.getType(typeConditionName);
1551
+ if (!typeCondition) {
1552
+ return false;
1553
+ }
1554
+ const satisfied = isSelectionSetSatisfiedBySchema(
1555
+ schema,
1556
+ typeCondition,
1557
+ fragment.selectionSet,
1558
+ fragmentsMap
1559
+ );
1560
+ if (!satisfied) {
1561
+ return false;
1562
+ }
1563
+ }
1564
+ }
1565
+ return true;
1566
+ }
1464
1567
  function isSelectionSetSatisfied({
1465
1568
  incoming,
1466
1569
  existing
package/dist/index.js CHANGED
@@ -598,6 +598,9 @@ function finalizeGatewayDocument(targetSchema, fragments, operations, onOverlapp
598
598
  const validFragments = [];
599
599
  const validFragmentsWithType = /* @__PURE__ */ Object.create(null);
600
600
  for (const fragment of fragments) {
601
+ if (fragment.selectionSet.selections.length === 0) {
602
+ continue;
603
+ }
601
604
  const typeName = fragment.typeCondition.name.value;
602
605
  const type = targetSchema.getType(typeName);
603
606
  if (type != null) {
@@ -1206,6 +1209,12 @@ function prepareGatewayDocument(originalDocument, transformedSchema, returnType,
1206
1209
  kind: Kind.DOCUMENT,
1207
1210
  definitions: [...operations, ...fragments, ...expandedFragments]
1208
1211
  };
1212
+ const fragmentMap = /* @__PURE__ */ Object.create(null);
1213
+ for (const fragment of expandedDocument.definitions) {
1214
+ if (fragment.kind === Kind.FRAGMENT_DEFINITION) {
1215
+ fragmentMap[fragment.name.value] = fragment;
1216
+ }
1217
+ }
1209
1218
  const visitorKeyMap = {
1210
1219
  Document: ["definitions"],
1211
1220
  OperationDefinition: ["selectionSet"],
@@ -1229,7 +1238,8 @@ function prepareGatewayDocument(originalDocument, transformedSchema, returnType,
1229
1238
  fieldNodesByField,
1230
1239
  dynamicSelectionSetsByField,
1231
1240
  infoSchema,
1232
- visitedSelections
1241
+ visitedSelections,
1242
+ fragmentMap
1233
1243
  )
1234
1244
  }),
1235
1245
  // visitorKeys argument usage a la https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby-source-graphql/src/batching/merge-queries.js
@@ -1267,11 +1277,19 @@ const getExtraPossibleTypesFn = memoize2(function getExtraPossibleTypes(transfor
1267
1277
  return extraTypesForSubschema;
1268
1278
  };
1269
1279
  });
1270
- function visitSelectionSet(node, fragmentReplacements, transformedSchema, typeInfo, possibleTypesMap, reversePossibleTypesMap2, interfaceExtensionsMap, fieldNodesByType, fieldNodesByField, dynamicSelectionSetsByField, infoSchema, visitedSelections) {
1280
+ function visitSelectionSet(node, fragmentReplacements, transformedSchema, typeInfo, possibleTypesMap, reversePossibleTypesMap2, interfaceExtensionsMap, fieldNodesByType, fieldNodesByField, dynamicSelectionSetsByField, infoSchema, visitedSelections, fragmentMap) {
1271
1281
  const newSelections = /* @__PURE__ */ new Set();
1272
1282
  const maybeType = typeInfo.getParentType();
1273
1283
  if (maybeType != null) {
1274
1284
  const parentType = getNamedType(maybeType);
1285
+ if (isSelectionSetSatisfiedBySchema(
1286
+ transformedSchema,
1287
+ parentType,
1288
+ node,
1289
+ fragmentMap
1290
+ )) {
1291
+ return node;
1292
+ }
1275
1293
  const parentTypeName = parentType.name;
1276
1294
  const fieldNodes = fieldNodesByType[parentTypeName];
1277
1295
  if (fieldNodes) {
@@ -1461,6 +1479,91 @@ function isFieldNodeSatisfiedBySelections(fieldNode, existing) {
1461
1479
  }
1462
1480
  return false;
1463
1481
  }
1482
+ function isSelectionSetSatisfiedBySchema(schema, type, selectionSet, fragmentsMap) {
1483
+ const namedType = getNamedType(type);
1484
+ if (isLeafType(namedType)) {
1485
+ return true;
1486
+ }
1487
+ for (const selection of selectionSet.selections) {
1488
+ if (selection.kind === Kind.FIELD) {
1489
+ if (isAbstractType(namedType)) {
1490
+ return false;
1491
+ }
1492
+ const fieldName = selection.name.value;
1493
+ if (fieldName === "__typename") {
1494
+ continue;
1495
+ }
1496
+ if (isObjectType(namedType) || isInterfaceType(namedType)) {
1497
+ const field = namedType.getFields()[fieldName];
1498
+ if (!field) {
1499
+ return false;
1500
+ }
1501
+ if (selection.selectionSet) {
1502
+ const fieldType = getNamedType(field.type);
1503
+ const satisfied = isSelectionSetSatisfiedBySchema(
1504
+ schema,
1505
+ fieldType,
1506
+ selection.selectionSet,
1507
+ fragmentsMap
1508
+ );
1509
+ if (!satisfied) {
1510
+ return false;
1511
+ }
1512
+ }
1513
+ } else {
1514
+ return false;
1515
+ }
1516
+ } else if (selection.kind === Kind.INLINE_FRAGMENT) {
1517
+ if (selection.typeCondition) {
1518
+ const typeConditionName = selection.typeCondition.name.value;
1519
+ const typeCondition = schema.getType(typeConditionName);
1520
+ if (!typeCondition) {
1521
+ return false;
1522
+ }
1523
+ const satisfied = isSelectionSetSatisfiedBySchema(
1524
+ schema,
1525
+ typeCondition,
1526
+ selection.selectionSet,
1527
+ fragmentsMap
1528
+ );
1529
+ if (!satisfied) {
1530
+ return false;
1531
+ }
1532
+ } else {
1533
+ const satisfied = isSelectionSetSatisfiedBySchema(
1534
+ schema,
1535
+ type,
1536
+ selection.selectionSet,
1537
+ fragmentsMap
1538
+ );
1539
+ if (!satisfied) {
1540
+ return false;
1541
+ }
1542
+ }
1543
+ } else if (selection.kind === Kind.FRAGMENT_SPREAD) {
1544
+ const fragmentName = selection.name.value;
1545
+ const fragment = fragmentsMap[fragmentName];
1546
+ if (!fragment) {
1547
+ return false;
1548
+ }
1549
+ const typeConditionName = fragment.typeCondition.name.value;
1550
+ const typeCondition = schema.getType(typeConditionName);
1551
+ if (!typeCondition) {
1552
+ return false;
1553
+ }
1554
+ const satisfied = isSelectionSetSatisfiedBySchema(
1555
+ schema,
1556
+ typeCondition,
1557
+ fragment.selectionSet,
1558
+ fragmentsMap
1559
+ );
1560
+ if (!satisfied) {
1561
+ return false;
1562
+ }
1563
+ }
1564
+ }
1565
+ return true;
1566
+ }
1464
1567
  function isSelectionSetSatisfied({
1465
1568
  incoming,
1466
1569
  existing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-tools/delegate",
3
- "version": "12.0.11",
3
+ "version": "12.0.12-alpha-bcdf6a1333a84f3ead114d676e66e609c350e084",
4
4
  "type": "module",
5
5
  "description": "A set of utils for faster development of GraphQL tools",
6
6
  "repository": {