@graphql-tools/stitch
Version:
A set of utils for faster development of GraphQL tools
79 lines (78 loc) • 3.33 kB
JavaScript
import { Kind, } from 'graphql';
import { extractUnavailableFields } from '@graphql-tools/delegate';
import { collectSubFields } from '@graphql-tools/utils';
export function getFieldsNotInSubschema(schema, stitchingInfo, gatewayType, subschemaType, fieldNodes, fragments, variableValues) {
const { fields: subFieldNodesByResponseKey } = collectSubFields(schema, fragments, variableValues, gatewayType, fieldNodes);
// TODO: Verify whether it is safe that extensions always exists.
const fieldNodesByField = stitchingInfo?.fieldNodesByField;
const shouldAdd = (fieldType, selection) => !fieldNodesByField?.[fieldType.name]?.[selection.name.value];
const fields = subschemaType.getFields();
const fieldsNotInSchema = new Set();
for (const [, subFieldNodes] of subFieldNodesByResponseKey) {
const fieldName = subFieldNodes[0].name.value;
if (!fields[fieldName]) {
for (const subFieldNode of subFieldNodes) {
fieldsNotInSchema.add(subFieldNode);
}
}
else {
const field = fields[fieldName];
for (const subFieldNode of subFieldNodes) {
const unavailableFields = extractUnavailableFields(schema, field, subFieldNode, shouldAdd);
if (unavailableFields.length) {
fieldsNotInSchema.add({
...subFieldNode,
selectionSet: {
kind: Kind.SELECTION_SET,
selections: unavailableFields,
},
});
}
}
}
let addedSubFieldNodes = false;
const fieldNodesByFieldForType = fieldNodesByField?.[gatewayType.name];
const visitedFieldNames = new Set();
if (fieldNodesByFieldForType) {
addMissingRequiredFields({
fieldName,
fields,
fieldsNotInSchema,
visitedFieldNames,
onAdd: () => {
if (!addedSubFieldNodes) {
for (const subFieldNode of subFieldNodes) {
fieldsNotInSchema.add(subFieldNode);
}
addedSubFieldNodes = true;
}
},
fieldNodesByField: fieldNodesByFieldForType,
});
}
}
return Array.from(fieldsNotInSchema);
}
function addMissingRequiredFields({ fieldName, fields, fieldsNotInSchema, onAdd, fieldNodesByField, visitedFieldNames, }) {
if (visitedFieldNames.has(fieldName)) {
return;
}
visitedFieldNames.add(fieldName);
const fieldNodesForField = fieldNodesByField?.[fieldName];
if (fieldNodesForField) {
for (const fieldNode of fieldNodesForField) {
if (fieldNode.name.value !== '__typename' && !fields[fieldNode.name.value]) {
onAdd();
fieldsNotInSchema.add(fieldNode);
addMissingRequiredFields({
fieldName: fieldNode.name.value,
fields,
fieldsNotInSchema,
onAdd,
fieldNodesByField,
visitedFieldNames,
});
}
}
}
}