UNPKG

@graphql-tools/stitch

Version:

A set of utils for faster development of GraphQL tools

159 lines (158 loc) • 7.22 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isolateComputedFieldsTransformer = void 0; const graphql_1 = require("graphql"); const utils_1 = require("@graphql-tools/utils"); const wrap_1 = require("@graphql-tools/wrap"); function isolateComputedFieldsTransformer(subschemaConfig) { if (subschemaConfig.merge == null) { return [subschemaConfig]; } const baseSchemaTypes = Object.create(null); const isolatedSchemaTypes = Object.create(null); for (const typeName in subschemaConfig.merge) { const mergedTypeConfig = subschemaConfig.merge[typeName]; baseSchemaTypes[typeName] = mergedTypeConfig; if (mergedTypeConfig.fields) { const baseFields = Object.create(null); const isolatedFields = Object.create(null); for (const fieldName in mergedTypeConfig.fields) { const mergedFieldConfig = mergedTypeConfig.fields[fieldName]; if (mergedFieldConfig.computed && mergedFieldConfig.selectionSet) { isolatedFields[fieldName] = mergedFieldConfig; } else if (mergedFieldConfig.computed) { throw new Error(`A selectionSet is required for computed field "${typeName}.${fieldName}"`); } else { baseFields[fieldName] = mergedFieldConfig; } } const isolatedFieldCount = Object.keys(isolatedFields).length; const objectType = subschemaConfig.schema.getType(typeName); if (isolatedFieldCount && isolatedFieldCount !== Object.keys(objectType.getFields()).length) { baseSchemaTypes[typeName] = { ...mergedTypeConfig, fields: baseFields, }; isolatedSchemaTypes[typeName] = { ...mergedTypeConfig, fields: isolatedFields, canonical: undefined, }; } } } if (Object.keys(isolatedSchemaTypes).length) { return [ filterBaseSubschema({ ...subschemaConfig, merge: baseSchemaTypes }, isolatedSchemaTypes), filterIsolatedSubschema({ ...subschemaConfig, merge: isolatedSchemaTypes }), ]; } return [subschemaConfig]; } exports.isolateComputedFieldsTransformer = isolateComputedFieldsTransformer; function filterBaseSubschema(subschemaConfig, isolatedSchemaTypes) { const schema = subschemaConfig.schema; const typesForInterface = {}; const filteredSchema = (0, utils_1.filterSchema)({ schema, objectFieldFilter: (typeName, fieldName) => !isolatedSchemaTypes[typeName]?.fields?.[fieldName], interfaceFieldFilter: (typeName, fieldName) => { if (!typesForInterface[typeName]) { typesForInterface[typeName] = (0, utils_1.getImplementingTypes)(typeName, schema); } return !typesForInterface[typeName].some(implementingTypeName => isolatedSchemaTypes[implementingTypeName]?.fields?.[fieldName]); }, }); const filteredFields = {}; for (const typeName in filteredSchema.getTypeMap()) { const type = filteredSchema.getType(typeName); if ((0, graphql_1.isObjectType)(type) || (0, graphql_1.isInterfaceType)(type)) { filteredFields[typeName] = { __typename: true }; const fieldMap = type.getFields(); for (const fieldName in fieldMap) { filteredFields[typeName][fieldName] = true; } } } const filteredSubschema = { ...subschemaConfig, merge: subschemaConfig.merge ? { ...subschemaConfig.merge, } : undefined, transforms: (subschemaConfig.transforms ?? []).concat([ new wrap_1.TransformCompositeFields((typeName, fieldName) => (filteredFields[typeName]?.[fieldName] ? undefined : null), (typeName, fieldName) => (filteredFields[typeName]?.[fieldName] ? undefined : null)), ]), }; const remainingTypes = filteredSchema.getTypeMap(); const mergeConfig = filteredSubschema.merge; if (mergeConfig) { for (const mergeType in mergeConfig) { if (!remainingTypes[mergeType]) { delete mergeConfig[mergeType]; } } if (!Object.keys(mergeConfig).length) { delete filteredSubschema.merge; } } return filteredSubschema; } function filterIsolatedSubschema(subschemaConfig) { const rootFields = {}; for (const typeName in subschemaConfig.merge) { const mergedTypeConfig = subschemaConfig.merge[typeName]; const entryPoints = mergedTypeConfig.entryPoints ?? [mergedTypeConfig]; for (const entryPoint of entryPoints) { if (entryPoint.fieldName != null) { rootFields[entryPoint.fieldName] = true; } } } const interfaceFields = {}; for (const typeName in subschemaConfig.merge) { const type = subschemaConfig.schema.getType(typeName); if (!type || !('getInterfaces' in type)) { throw new Error(`${typeName} expected to have 'getInterfaces' method`); } for (const int of type.getInterfaces()) { const intType = subschemaConfig.schema.getType(int.name); if (!intType || !('getFields' in intType)) { throw new Error(`${int.name} expected to have 'getFields' method`); } for (const intFieldName in intType.getFields()) { if (subschemaConfig.merge[typeName].fields?.[intFieldName]) { interfaceFields[int.name] = interfaceFields[int.name] || {}; interfaceFields[int.name][intFieldName] = true; } } } } const filteredSchema = (0, utils_1.filterSchema)({ schema: subschemaConfig.schema, rootFieldFilter: (operation, fieldName) => operation === 'Query' && rootFields[fieldName] != null, objectFieldFilter: (typeName, fieldName) => subschemaConfig.merge[typeName]?.fields?.[fieldName] != null, interfaceFieldFilter: (typeName, fieldName) => interfaceFields[typeName]?.[fieldName] != null, }); const filteredFields = {}; for (const typeName in filteredSchema.getTypeMap()) { const type = filteredSchema.getType(typeName); if ((0, graphql_1.isObjectType)(type) || (0, graphql_1.isInterfaceType)(type)) { filteredFields[typeName] = { __typename: true }; const fieldMap = type.getFields(); for (const fieldName in fieldMap) { filteredFields[typeName][fieldName] = true; } } } const filteredSubschema = { ...subschemaConfig, transforms: (subschemaConfig.transforms ?? []).concat([ new wrap_1.TransformCompositeFields((typeName, fieldName) => (filteredFields[typeName]?.[fieldName] ? undefined : null), (typeName, fieldName) => (filteredFields[typeName]?.[fieldName] ? undefined : null)), ]), }; return filteredSubschema; }