UNPKG

@graphql-tools/resolvers-composition

Version:

Common package containing utils and types for GraphQL tools

88 lines (87 loc) 3.42 kB
import _ from 'lodash'; import micromatch from 'micromatch'; import { asArray } from '@graphql-tools/utils'; import { chainFunctions } from './chain-functions.js'; function isScalarTypeConfiguration(config) { return config && 'serialize' in config && 'parseLiteral' in config; } function resolveRelevantMappings(resolvers, path) { if (!resolvers) { return []; } const [typeNameOrGlob, fieldNameOrGlob] = path.split('.'); const isTypeMatch = micromatch.matcher(typeNameOrGlob); let fixedFieldGlob = fieldNameOrGlob; // convert single value OR `{singleField}` to `singleField` as matching will fail otherwise if (fixedFieldGlob.includes('{') && !fixedFieldGlob.includes(',')) { fixedFieldGlob = fieldNameOrGlob.replace('{', '').replace('}', ''); } fixedFieldGlob = fixedFieldGlob.replace(', ', ',').trim(); const isFieldMatch = micromatch.matcher(fixedFieldGlob); const mappings = []; for (const typeName in resolvers) { if (!isTypeMatch(typeName)) { continue; } if (isScalarTypeConfiguration(resolvers[typeName])) { continue; } const fieldMap = resolvers[typeName]; if (!fieldMap) { return []; } for (const field in fieldMap) { if (!isFieldMatch(field)) { continue; } const resolvedPath = `${typeName}.${field}`; if (resolvers[typeName] && resolvers[typeName][field]) { if (resolvers[typeName][field].subscribe) { mappings.push(resolvedPath + '.subscribe'); } if (resolvers[typeName][field].resolve) { mappings.push(resolvedPath + '.resolve'); } if (typeof resolvers[typeName][field] === 'function') { mappings.push(resolvedPath); } } } } return mappings; } /** * Wraps the resolvers object with the resolvers composition objects. * Implemented as a simple and basic middleware mechanism. * * @param resolvers - resolvers object * @param mapping - resolvers composition mapping * @hidden */ export function composeResolvers(resolvers, mapping = {}) { const mappingResult = {}; for (const resolverPath in mapping) { const resolverPathMapping = mapping[resolverPath]; if (resolverPathMapping instanceof Array || typeof resolverPathMapping === 'function') { const composeFns = resolverPathMapping; const relevantFields = resolveRelevantMappings(resolvers, resolverPath); for (const path of relevantFields) { mappingResult[path] = asArray(composeFns); } } else if (resolverPathMapping) { for (const fieldName in resolverPathMapping) { const composeFns = resolverPathMapping[fieldName]; const relevantFields = resolveRelevantMappings(resolvers, resolverPath + '.' + fieldName); for (const path of relevantFields) { mappingResult[path] = asArray(composeFns); } } } } for (const path in mappingResult) { const fns = chainFunctions([...asArray(mappingResult[path]), () => _.get(resolvers, path)]); _.set(resolvers, path, fns()); } return resolvers; }