UNPKG

@graphql-mesh/transport-mysql

Version:
173 lines (172 loc) • 9.72 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getMySQLExecutor = getMySQLExecutor; 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 utils_1 = require("@graphql-mesh/utils"); const delegate_1 = require("@graphql-tools/delegate"); const utils_2 = 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 }) { const mysqlConnectionByContext = new WeakMap(); subgraph = (0, utils_2.mapSchema)(subgraph, { [utils_2.MapperKind.OBJECT_FIELD](fieldConfig, fieldName) { const directives = (0, utils_1.getDefDirectives)(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_2.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}`); } } } } const mysqlConnection = mysqlConnectionByContext.get(context); if (limit.length) { const selectLimit$ = cross_helpers_1.util.promisify(mysqlConnection.selectLimit.bind(mysqlConnection)); return selectLimit$(table, fields, limit, where, args?.orderBy); } else { const select$ = cross_helpers_1.util.promisify(mysqlConnection.select.bind(mysqlConnection)); return select$(table, fields, where, args?.orderBy); } }; break; } case 'mysqlCount': { const { table } = directive.args; fieldConfig.resolve = function mysqlCountResolver(root, args, context, info) { const mysqlConnection = mysqlConnectionByContext.get(context); const count$ = cross_helpers_1.util.promisify(mysqlConnection.count.bind(mysqlConnection)); return count$(table, args.where); }; break; } case 'mysqlInsert': { const { table, primaryKeys } = directive.args; fieldConfig.resolve = async function mysqlInsertResolver(root, args, context, info) { const mysqlConnection = mysqlConnectionByContext.get(context); const select$ = cross_helpers_1.util.promisify(mysqlConnection.select.bind(mysqlConnection)); const insert$ = cross_helpers_1.util.promisify(mysqlConnection.insert.bind(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 mysqlConnection = mysqlConnectionByContext.get(context); const update$ = cross_helpers_1.util.promisify(mysqlConnection.update.bind(mysqlConnection)); await update$(table, args[table], args.where); const fields = getFieldsFromResolveInfo(info); const select$ = cross_helpers_1.util.promisify(mysqlConnection.select.bind(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 mysqlConnection = mysqlConnectionByContext.get(context); const delete$ = cross_helpers_1.util.promisify(mysqlConnection.delete.bind(mysqlConnection)); const res = await delete$(table, args.where); return !!res.affectedRows; }; break; } } } return fieldConfig; }, }); const transportDirectives = (0, utils_2.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.introspection)(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)); return (0, utils_1.makeAsyncDisposable)(async function mysqlExecutor(executionRequest) { const mysqlConnection = await getConnection$(); mysqlConnectionByContext.set(executionRequest.context, mysqlConnection); try { return await defaultExecutor(executionRequest); } finally { mysqlConnectionByContext.delete(executionRequest.context); mysqlConnection.release(); } }, () => new Promise((resolve, reject) => { pool.end(err => { if (err) { reject(err); } else { resolve(); } }); })); }