graphql-join
Version:
Join types together in your schema declaratively with SDL.
165 lines • 8.25 kB
JavaScript
;
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