@graphql-tools/federation
Version:
Useful tools to create and manipulate GraphQL schemas.
153 lines (152 loc) • 6.06 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getNamedTypeNode = exports.filterInternalFieldsAndTypes = exports.getCacheKeyFnFromKey = exports.getKeyFnForFederation = exports.projectDataSelectionSet = exports.getKeyForFederation = exports.getArgsFromKeysForFederation = void 0;
const graphql_1 = require("graphql");
const utils_1 = require("@graphql-tools/utils");
function getArgsFromKeysForFederation(representations) {
return { representations };
}
exports.getArgsFromKeysForFederation = getArgsFromKeysForFederation;
function getKeyForFederation(root) {
return root;
}
exports.getKeyForFederation = getKeyForFederation;
function projectDataSelectionSet(data, selectionSet) {
if (data == null || selectionSet == null) {
return data;
}
if (Array.isArray(data)) {
return data.map(entry => projectDataSelectionSet(entry, selectionSet));
}
const projectedData = {
__typename: data.__typename,
};
for (const selection of selectionSet.selections) {
if (selection.kind === graphql_1.Kind.FIELD) {
const key = selection.name.value;
if (data.hasOwnProperty(key)) {
const projectedKeyData = projectDataSelectionSet(data[key], selection.selectionSet);
if (projectedData[key]) {
projectedData[key] = (0, utils_1.mergeDeep)([projectedData[key], projectedKeyData]);
}
else {
projectedData[key] = projectDataSelectionSet(data[key], selection.selectionSet);
}
}
}
else if (selection.kind === graphql_1.Kind.INLINE_FRAGMENT) {
if (selection.typeCondition &&
projectedData['__typename'] != null &&
projectedData['__typename'] !== selection.typeCondition.name.value) {
continue;
}
Object.assign(projectedData, (0, utils_1.mergeDeep)([projectedData, projectDataSelectionSet(data, selection.selectionSet)]));
}
}
return projectedData;
}
exports.projectDataSelectionSet = projectDataSelectionSet;
function getKeyFnForFederation(typeName, keys) {
if (keys.some(key => key.includes('{'))) {
const parsedSelectionSet = (0, utils_1.parseSelectionSet)(`{${keys.join(' ')}}`, { noLocation: true });
return function keyFn(root) {
return projectDataSelectionSet({
__typename: typeName,
...root,
}, parsedSelectionSet);
};
}
const allKeyProps = keys.flatMap(key => key.split(' ')).map(key => key.trim());
if (allKeyProps.length > 1) {
return function keyFn(root) {
return allKeyProps.reduce((prev, key) => {
if (key !== '__typename') {
prev[key] = root[key];
}
return prev;
}, { __typename: typeName });
};
}
const keyProp = allKeyProps[0];
return function keyFn(root) {
return {
__typename: typeName,
[keyProp]: root[keyProp],
};
};
}
exports.getKeyFnForFederation = getKeyFnForFederation;
function getCacheKeyFnFromKey(key) {
if (key.includes('{')) {
const parsedSelectionSet = (0, utils_1.parseSelectionSet)(`{${key}}`, { noLocation: true });
return function cacheKeyFn(root) {
return JSON.stringify(projectDataSelectionSet(root, parsedSelectionSet));
};
}
const keyTrimmed = key.trim();
const keys = keyTrimmed.split(' ').map(key => key.trim());
if (keys.length > 1) {
return function cacheKeyFn(root) {
return keys.map(key => root[key]).join(' ');
};
}
return function cacheKeyFn(root) {
return root[keyTrimmed];
};
}
exports.getCacheKeyFnFromKey = getCacheKeyFnFromKey;
const internalTypeNames = ['_Entity', '_Any', '_FieldSet', '_Service', 'link', 'inaccessible'];
function filterInternalFieldsAndTypes(finalSchema) {
return (0, utils_1.mapSchema)(finalSchema, {
[utils_1.MapperKind.DIRECTIVE]: directive => {
if (internalTypeNames.includes(directive.name) ||
directive.name.startsWith('link__') ||
directive.name.startsWith('join__') ||
directive.name.startsWith('core__')) {
return null;
}
return directive;
},
[utils_1.MapperKind.TYPE]: type => {
if (internalTypeNames.includes(type.name) ||
type.name.startsWith('link__') ||
type.name.startsWith('join__') ||
type.name.startsWith('core__') ||
type.astNode?.directives?.some(d => d.name.value === 'inaccessible')) {
return null;
}
return type;
},
[utils_1.MapperKind.COMPOSITE_FIELD]: fieldConfig => {
if (fieldConfig.astNode?.directives?.some(d => d.name.value === 'inaccessible')) {
return null;
}
return fieldConfig;
},
[utils_1.MapperKind.QUERY_ROOT_FIELD]: (fieldConfig, fieldName) => {
if (fieldName === '_entities') {
return null;
}
return fieldConfig;
},
[utils_1.MapperKind.ENUM_VALUE]: valueConfig => {
if (valueConfig.astNode?.directives?.some(d => d.name.value === 'inaccessible')) {
return null;
}
},
[utils_1.MapperKind.ARGUMENT]: argConfig => {
if (argConfig.astNode?.directives?.some(d => d.name.value === 'inaccessible')) {
return null;
}
return argConfig;
},
});
}
exports.filterInternalFieldsAndTypes = filterInternalFieldsAndTypes;
function getNamedTypeNode(typeNode) {
if (typeNode.kind !== graphql_1.Kind.NAMED_TYPE) {
return getNamedTypeNode(typeNode.type);
}
return typeNode;
}
exports.getNamedTypeNode = getNamedTypeNode;