UNPKG

graphql-join

Version:

Join types together in your schema declaratively with SDL.

165 lines 8.25 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.mapChildrenToParents = exports.createArgsFromKeysFunction = exports.createChildSelectionSet = exports.createParentSelectionSet = void 0; const graphql_1 = require("graphql"); const batch_delegate_1 = require("@graphql-tools/batch-delegate"); const delegate_1 = require("@graphql-tools/delegate"); const stitch_1 = require("@graphql-tools/stitch"); const wrap_1 = require("@graphql-tools/wrap"); const lodash_1 = __importDefault(require("lodash")); const validate_1 = require("./validate"); class GraphQLJoinTransform { constructor(config) { this.config = config.config || config; } transformSchema(originalSchema) { var _a; return (((_a = this.config.graphqlTools) === null || _a === void 0 ? void 0 : _a.stitchSchemas) || stitch_1.stitchSchemas)({ subschemas: [originalSchema], typeDefs: this.config.typeDefs, resolvers: this.getResolvers(originalSchema), }); } getResolvers(originalSchema) { return lodash_1.default.mapValues(this.config.resolvers, (typeConfig, typeName) => lodash_1.default.mapValues(typeConfig, (fieldConfig, fieldName) => { const { queryFieldNode, isUnbatched } = validate_1.validateFieldConfig(fieldConfig, typeName, fieldName, this.config.typeDefs, originalSchema); return isUnbatched ? this.createUnbatchedFieldResolver(queryFieldNode, originalSchema) : this.createBatchedFieldResolver(queryFieldNode, originalSchema); })); } createUnbatchedFieldResolver(queryFieldNode, schema) { return { selectionSet: createParentSelectionSet(queryFieldNode), resolve: (parent, args, context, info) => { var _a; return (((_a = this.config.graphqlTools) === null || _a === void 0 ? void 0 : _a.delegateToSchema) || delegate_1.delegateToSchema)({ schema, operation: 'query', fieldName: queryFieldNode.name.value, context, info, args: createArgsFromKeysFunction(queryFieldNode, args, false)([parent]), }); }, }; } createBatchedFieldResolver(queryFieldNode, schema) { const childSelectionSetTransform = new wrap_1.WrapQuery([queryFieldNode.name.value], selectionSet => ({ ...selectionSet, selections: selectionSet.selections.concat(createChildSelectionSet(queryFieldNode)), }), result => result); return { selectionSet: createParentSelectionSet(queryFieldNode), resolve: (parent, args, context, info) => { var _a; return (((_a = this.config.graphqlTools) === null || _a === void 0 ? void 0 : _a.batchDelegateToSchema) || batch_delegate_1.batchDelegateToSchema)({ schema, operation: 'query', fieldName: queryFieldNode.name.value, key: parent, context, info, transforms: [childSelectionSetTransform], argsFromKeys: createArgsFromKeysFunction(queryFieldNode, args, true), valuesFromResults: (results, keys) => mapChildrenToParents(results, keys, queryFieldNode, graphql_1.isListType(info.returnType) || (graphql_1.isNonNullType(info.returnType) && graphql_1.isListType(info.returnType.ofType))), }); }, }; } } exports.default = GraphQLJoinTransform; function createParentSelectionSet(queryFieldNode) { const fields = new Set(); graphql_1.visit(queryFieldNode, { Variable: node => { fields.add(node.name.value); }, Field: (node, key, parent) => { var _a; parent && fields.add(((_a = node.alias) === null || _a === void 0 ? void 0 : _a.value) || node.name.value); }, }); return fields.size > 0 ? `{ ${Array.from(fields).join(' ')} }` : undefined; } exports.createParentSelectionSet = createParentSelectionSet; function createChildSelectionSet(queryFieldNode) { return graphql_1.visit(queryFieldNode, { Field: node => ({ ...node, alias: undefined }), }).selectionSet.selections; } exports.createChildSelectionSet = createChildSelectionSet; const scalarSymbol = Symbol('Scalar'); function createArgsFromKeysFunction(queryFieldNode, userArgs, batched) { const getValue = (node) => node.value.kind === scalarSymbol ? node.value.value : node.value; return (parents) => { const args = graphql_1.visit(queryFieldNode, { leave: { IntValue: node => ({ kind: scalarSymbol, value: parseInt(node.value) }), FloatValue: node => ({ kind: scalarSymbol, value: Number(node.value) }), StringValue: node => ({ kind: scalarSymbol, value: node.value }), EnumValue: node => ({ kind: scalarSymbol, value: node.value }), BooleanValue: node => ({ kind: scalarSymbol, value: node.value }), NullValue: () => ({ kind: scalarSymbol, value: null }), Argument: node => ({ [node.name.value]: getValue(node) }), ListValue: node => node.values.map(value => getValue({ value })), ObjectValue: node => lodash_1.default(node.fields) .keyBy(field => field.name.value) .mapValues(getValue) .value(), Variable: node => userArgs[node.name.value] || (batched ? lodash_1.default(parents) .flatMap(parent => lodash_1.default.get(parent, node.name.value)) .filter(elt => elt !== null && elt !== undefined) .uniq() .value() : lodash_1.default.get(parents[0], node.name.value)), }, }).arguments; return lodash_1.default.merge({}, ...args); }; } exports.createArgsFromKeysFunction = createArgsFromKeysFunction; function mapChildrenToParents(children, parents, queryFieldNode, toManyRelation) { const childKeyFields = []; const parentKeyFields = []; graphql_1.visit(queryFieldNode, { Field: (node, key, parent) => { var _a; parent && childKeyFields.push(node.name.value); parent && parentKeyFields.push(((_a = node.alias) === null || _a === void 0 ? void 0 : _a.value) || node.name.value); }, }); if (childKeyFields.length === 1) { const childrenByKey = lodash_1.default(children) .flatMap(child => lodash_1.default([child[childKeyFields[0]]]) .flatten() .map(key => ({ key, child })) .value()) .groupBy(pair => pair.key) .mapValues(pairs => pairs.map(pair => pair.child)) .value(); return parents .map(parent => lodash_1.default([parent[parentKeyFields[0]]]) .flatten() .flatMap(key => (key === null ? [] : childrenByKey[key] || [])) .uniq() .value()) .map(group => { var _a; return (toManyRelation ? group || [] : (_a = group === null || group === void 0 ? void 0 : group[0]) !== null && _a !== void 0 ? _a : null); }); } else { const childrenByKey = lodash_1.default.groupBy(children, child => JSON.stringify(lodash_1.default.at(child, childKeyFields))); return parents .map(prnt => childrenByKey[JSON.stringify(lodash_1.default.at(prnt, parentKeyFields))]) .map(group => { var _a; return (toManyRelation ? group || [] : (_a = group === null || group === void 0 ? void 0 : group[0]) !== null && _a !== void 0 ? _a : null); }); } } exports.mapChildrenToParents = mapChildrenToParents; //# sourceMappingURL=index.js.map