@graphql-tools/resolvers-composition
Version:
Common package containing utils and types for GraphQL tools
93 lines (92 loc) • 3.79 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.composeResolvers = void 0;
const tslib_1 = require("tslib");
const lodash_1 = tslib_1.__importDefault(require("lodash"));
const micromatch_1 = tslib_1.__importDefault(require("micromatch"));
const utils_1 = require("@graphql-tools/utils");
const chain_functions_js_1 = require("./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_1.default.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_1.default.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
*/
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] = (0, utils_1.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] = (0, utils_1.asArray)(composeFns);
}
}
}
}
for (const path in mappingResult) {
const fns = (0, chain_functions_js_1.chainFunctions)([...(0, utils_1.asArray)(mappingResult[path]), () => lodash_1.default.get(resolvers, path)]);
lodash_1.default.set(resolvers, path, fns());
}
return resolvers;
}
exports.composeResolvers = composeResolvers;