UNPKG

apollo-schema-extend

Version:

Extends your Apollo Server Express based graphql server with an external graphql source

156 lines (155 loc) 7.08 kB
"use strict"; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getFilteredDefinition = void 0; const graphql_1 = require("graphql"); const ast_1 = require("../ast"); const definition_1 = require("../definition"); /** * Filters the given operation based on the provided schema. * @param operation The operation to be filtered. * @param fragments Available fragments of the query * @param schema The schema to be used for the filtering */ const getFilteredDefinition = (operation, resolveInfo, schema, remapRules) => { const fragments = Object.entries(resolveInfo.fragments).reduce((total, next) => { if (next[1]) { const filteredFragment = getFilteredFragment(next[1], schema, remapRules, resolveInfo); if (filteredFragment) { total[next[0]] = filteredFragment; } } return total; }, {}); const filteredOperation = getFilteredOperation(operation, fragments, schema, remapRules, resolveInfo); return { operation: filteredOperation, fragments }; }; exports.getFilteredDefinition = getFilteredDefinition; const getFilteredOperation = (operation, fragments, schema, remapRules, resolveInfo) => { const currentType = operation.operation === 'query' ? schema.getQueryType() : schema.getMutationType(); if (!currentType) { throw new Error(`operation ${operation.operation} is not supported by the schema`); } return filterNode(operation, { currentType, schema, fragments, remapRules, resolveInfo }); }; const getFilteredFragment = (fragment, schema, remapRules, resolveInfo) => { const currentType = schema.getType(fragment.typeCondition.name.value); if (!currentType) { return null; } return filterNode(fragment, { currentType, schema, fragments: resolveInfo.fragments, remapRules, resolveInfo }); }; const filterNode = (node, _a) => { var { currentType } = _a, context = __rest(_a, ["currentType"]); let filteredNode = node; if ((0, graphql_1.isObjectType)(currentType) || (0, graphql_1.isInterfaceType)(currentType)) { filteredNode = filterObjectLikeType(node, Object.assign({ currentType }, context)); } else if ((0, graphql_1.isUnionType)(currentType)) { filteredNode = filterUnionType(node, Object.assign({ currentType }, context)); } if ((0, ast_1.isFieldNode)(node)) { const remapRule = context.remapRules[currentType.name]; if (remapRule) { filteredNode = remapRule(filteredNode, { unfilteredNode: node, resolveInfo: context.resolveInfo, }); } } return filteredNode; }; const typeNameKey = '__typename'; const isFragmentSpread = (0, ast_1.isNodeKind)(graphql_1.Kind.FRAGMENT_SPREAD); const filterObjectLikeType = (node, _a) => { var { currentType } = _a, context = __rest(_a, ["currentType"]); if ((0, ast_1.hasSelectionSet)(node)) { const fields = currentType.getFields(); const selections = []; node.selectionSet.selections.forEach(selection => { if ((0, ast_1.isFieldNode)(selection)) { const field = fields[selection.name.value]; const selectionType = field && (0, definition_1.toNamedType)(field.type); if (selectionType && isValidFieldSelection(selection, selectionType)) { selections.push(filterNode(selection, Object.assign(Object.assign({}, context), { currentType: selectionType }))); } else if (selection.name.value === typeNameKey) { selections.push(selection); } } else { const filteredFragment = filterFragmentNode(selection, Object.assign({ currentType }, context)); if (filteredFragment) { selections.push(filteredFragment); } } }); if ((0, graphql_1.isInterfaceType)(currentType) || !selections.length) { ensureTypename(selections); } return (0, ast_1.withSelections)(node, selections); } return node; }; const isValidFieldSelection = (selection, selectionType) => selectionType instanceof graphql_1.GraphQLScalarType || selectionType instanceof graphql_1.GraphQLEnumType ? !selection.selectionSet : !!selection.selectionSet; const filterUnionType = (node, _a) => { var { currentType } = _a, context = __rest(_a, ["currentType"]); if ((0, ast_1.hasSelectionSet)(node)) { const selections = []; node.selectionSet.selections.forEach(selection => { if ((0, ast_1.isFieldNode)(selection)) { if (selection.name.value === typeNameKey) { selections.push(selection); } } else { const filteredFragment = filterFragmentNode(selection, Object.assign({ currentType }, context)); if (filteredFragment) { selections.push(selection); } } }); ensureTypename(selections); return (0, ast_1.withSelections)(node, selections); } return node; }; const filterFragmentNode = (node, _a) => { var { currentType } = _a, context = __rest(_a, ["currentType"]); if (isFragmentSpread(node)) { const fragment = context.fragments[node.name.value]; return fragment && isFragmentAllowed(fragment, currentType, context.schema) ? node : null; } if (isFragmentAllowed(node, currentType, context.schema)) { const fragmentType = context.schema.getType(node.typeCondition.name.value); const filteredNode = filterNode(node, Object.assign({ currentType: fragmentType }, context)); return filteredNode.selectionSet.selections.length ? filteredNode : null; } return null; }; const isFragmentAllowed = (fragment, currentType, schema) => { const fragmentType = fragment.typeCondition && schema.getType(fragment.typeCondition.name.value); if (!fragmentType) { return false; } return (currentType.name === fragmentType.name || ((0, graphql_1.isAbstractType)(currentType) && schema.isSubType(currentType, fragmentType)) || ((0, graphql_1.isAbstractType)(fragmentType) && schema.isSubType(fragmentType, currentType))); }; const ensureTypename = (selections) => { if (!selections.some(selection => (0, ast_1.isFieldNode)(selection) && selection.name.value === typeNameKey)) { selections.push((0, ast_1.createField)(typeNameKey)); } };