@graphql-mesh/transport-mysql
Version:
175 lines (174 loc) • 9.46 kB
JavaScript
"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;