@graphql-mesh/utils
Version:
110 lines (109 loc) • 4.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.containsSelectionSet = containsSelectionSet;
exports.selectionSetOfData = selectionSetOfData;
/* eslint-disable no-labels */
const graphql_1 = require("graphql");
/**
* Checks recursively whether all of the fields of {@link requiredSelSet} exist in {@link selSet}
*/
function containsSelectionSet(requiredSelSet, selSet) {
ReqLoop: for (const reqSel of requiredSelSet.selections) {
switch (reqSel.kind) {
case graphql_1.Kind.FIELD: {
for (const sel of selSet.selections) {
// required field exists in the selection set
if (sel.kind === graphql_1.Kind.FIELD && sel.name.value === reqSel.name.value) {
if (!reqSel.selectionSet && !sel.selectionSet) {
// they're both scalar fields, continue to next required field
continue ReqLoop;
}
if (reqSel.selectionSet && !sel.selectionSet) {
// required field is an object, but the selection under the same name is scalar
return false;
}
if (!reqSel.selectionSet && sel.selectionSet) {
// required field is a scalar, but the selection under the same name is object
return false;
}
// they're both objects
if (containsSelectionSet(reqSel.selectionSet, sel.selectionSet)) {
// and they recursively contain all required fields
continue ReqLoop;
}
}
}
// no matches found
return false;
}
case graphql_1.Kind.INLINE_FRAGMENT: {
for (const sel of selSet.selections) {
if (sel.kind !== graphql_1.Kind.INLINE_FRAGMENT) {
continue;
}
if (sel.typeCondition?.name.value &&
reqSel.typeCondition?.name.value &&
sel.typeCondition.name.value === reqSel.typeCondition.name.value) {
// both have matching type conditions
if (containsSelectionSet(reqSel.selectionSet, sel.selectionSet)) {
// and they recursively contain all required fields
continue ReqLoop;
}
}
if (!sel.typeCondition?.name.value && !reqSel.typeCondition?.name.value) {
// neither have a type condition, just check the selection sets
if (containsSelectionSet(reqSel.selectionSet, sel.selectionSet)) {
// and they recursively contain all required fields
continue ReqLoop;
}
}
}
return false;
}
default:
// no other field kind is supported, like fragment spreads or definitions
return false;
}
}
// all fields matched
return true;
}
function selectionSetOfData(data) {
const selSet = {
kind: graphql_1.Kind.SELECTION_SET,
selections: [],
};
for (const fieldName of Object.keys(data)) {
const fieldValue = data[fieldName];
const selNode = {
kind: graphql_1.Kind.FIELD,
name: { kind: graphql_1.Kind.NAME, value: fieldName },
};
if (fieldValue && typeof fieldValue === 'object') {
if (Array.isArray(fieldValue)) {
// we assume that all items in the array are of the same shape, so we look at the first one
const firstItem = fieldValue[0];
if (firstItem && typeof firstItem === 'object') {
selSet.selections.push({
...selNode,
selectionSet: selectionSetOfData(firstItem),
});
}
else {
// is an array of scalars
selSet.selections.push(selNode);
}
}
else {
selSet.selections.push({
...selNode,
selectionSet: selectionSetOfData(fieldValue),
});
}
}
else {
selSet.selections.push(selNode);
}
}
return selSet;
}