UNPKG

@graphql-mesh/transport-mysql

Version:
175 lines (174 loc) • 9.46 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getMySQLExecutor = void 0; const tslib_1 = require("tslib"); const graphql_1 = require("graphql"); const graphql_fields_1 = tslib_1.__importDefault(require("graphql-fields")); const mysql_1 = require("mysql"); const mysql_utilities_1 = require("mysql-utilities"); const cross_helpers_1 = require("@graphql-mesh/cross-helpers"); const delegate_1 = require("@graphql-tools/delegate"); const utils_1 = require("@graphql-tools/utils"); const parseEndpointUri_js_1 = require("./parseEndpointUri.js"); function getFieldsFromResolveInfo(info) { const fieldMap = (0, graphql_fields_1.default)(info); return Object.keys(fieldMap).filter(fieldName => Object.keys(fieldMap[fieldName]).length === 0 && fieldName !== '__typename'); } function getMySQLExecutor({ subgraph, pool, pubsub, logger, }) { subgraph = (0, utils_1.mapSchema)(subgraph, { [utils_1.MapperKind.OBJECT_FIELD](fieldConfig, fieldName) { const directives = (0, utils_1.getDirectives)(subgraph, fieldConfig); for (const directive of directives) { switch (directive.name) { case 'mysqlSelect': { const { table, columnMap: columnMapEntries } = directive.args; const columnMap = new Map(columnMapEntries); fieldConfig.resolve = function mysqlSelectResolver(root, args, context, info) { const where = { ...args.where, }; columnMap.forEach((foreignColumn, localColumn) => { where[foreignColumn] = root[localColumn]; }); const limit = [args.limit, args.offset].filter(Boolean); const fieldMap = (0, graphql_fields_1.default)(info); const fields = []; for (const fieldName in fieldMap) { if (fieldName !== '__typename') { const subFieldMap = fieldMap[fieldName]; if (Object.keys(subFieldMap).length === 0) { fields.push(fieldName); } else { const returnType = (0, graphql_1.getNamedType)(fieldConfig.type); if ((0, graphql_1.isObjectType)(returnType)) { const returnTypeFields = returnType.getFields(); const foreignField = returnTypeFields[fieldName]; const foreignDirective = (0, utils_1.getDirective)(subgraph, foreignField, 'mysqlTableForeign'); const foreignDirectiveArgs = foreignDirective?.[0]; const columnName = foreignDirectiveArgs?.columnName; if (columnName) { fields.push(columnName); } } else { throw new Error(`Invalid type for field ${fieldName}`); } } } } if (limit.length) { const selectLimit$ = cross_helpers_1.util.promisify(context.mysqlConnection.selectLimit.bind(context.mysqlConnection)); return selectLimit$(table, fields, limit, where, args?.orderBy); } else { const select$ = cross_helpers_1.util.promisify(context.mysqlConnection.select.bind(context.mysqlConnection)); return select$(table, fields, where, args?.orderBy); } }; break; } case 'mysqlCount': { const { table } = directive.args; fieldConfig.resolve = function mysqlCountResolver(root, args, context, info) { const count$ = cross_helpers_1.util.promisify(context.mysqlConnection.count.bind(context.mysqlConnection)); return count$(table, args.where); }; break; } case 'mysqlInsert': { const { table, primaryKeys } = directive.args; fieldConfig.resolve = async function mysqlInsertResolver(root, args, context, info) { const select$ = cross_helpers_1.util.promisify(context.mysqlConnection.select.bind(context.mysqlConnection)); const insert$ = cross_helpers_1.util.promisify(context.mysqlConnection.insert.bind(context.mysqlConnection)); const input = args[table]; const { recordId } = await insert$(table, input); const fields = getFieldsFromResolveInfo(info); const where = {}; for (const primaryColumnName of primaryKeys) { where[primaryColumnName] = input[primaryColumnName] || recordId; } const result = await select$(table, fields, where, {}); return result[0]; }; break; } case 'mysqlUpdate': { const { table } = directive.args; fieldConfig.resolve = async function mysqlUpdateResolver(root, args, context, info) { const update$ = cross_helpers_1.util.promisify(context.mysqlConnection.update.bind(context.mysqlConnection)); await update$(table, args[table], args.where); const fields = getFieldsFromResolveInfo(info); const select$ = cross_helpers_1.util.promisify(context.mysqlConnection.select.bind(context.mysqlConnection)); const result = await select$(table, fields, args.where, {}); return result[0]; }; break; } case 'mysqlDelete': { const { table } = directive.args; fieldConfig.resolve = async function mysqlDeleteResolver(root, args, context, info) { const delete$ = cross_helpers_1.util.promisify(context.mysqlConnection.delete.bind(context.mysqlConnection)); const res = await delete$(table, args.where); return !!res.affectedRows; }; break; } } } return fieldConfig; }, }); const transportDirectives = (0, utils_1.getDirective)(subgraph, subgraph, 'transport'); if (!transportDirectives?.length) { throw new Error(`No transport directives found in the schema`); } const transportDirective = transportDirectives[0]; const { location } = transportDirective; const connectionOpts = (0, parseEndpointUri_js_1.getConnectionOptsFromEndpointUri)(location); const isDebug = globalThis.process?.env?.DEBUG?.includes('mysql') || globalThis.process?.env?.DEBUG?.toString() === '1' || globalThis.process?.env?.DEBUG?.toLowerCase() === 'true'; pool ||= (0, mysql_1.createPool)({ ...connectionOpts, supportBigNumbers: true, bigNumberStrings: true, debug: !!isDebug, trace: !!isDebug, }); pool.on('connection', connection => { (0, mysql_utilities_1.upgrade)(connection); }); const defaultExecutor = (0, delegate_1.createDefaultExecutor)(subgraph); const getConnection$ = cross_helpers_1.util.promisify(pool.getConnection.bind(pool)); if (pubsub) { const id = pubsub.subscribe('destroy', () => { pool.end(err => { if (err) { console.error(err); } pubsub.unsubscribe(id); }); }); } else { logger?.warn(`FIXME: No pubsub provided for mysql executor, so the connection pool will never be closed`); } return async function mysqlExecutor(executionRequest) { const mysqlConnection = await getConnection$(); const mysqlContext = { mysqlConnection, ...executionRequest.context, }; try { return await defaultExecutor({ ...executionRequest, context: mysqlContext, }); } finally { mysqlConnection.release(); } }; } exports.getMySQLExecutor = getMySQLExecutor;