UNPKG

postgraphile-plugin-atomic-mutations

Version:

Postgraphile plugin to enable mutation atomicty with GraphQL requests containing multiple mutations

88 lines (87 loc) 3.88 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const graphql_1 = require("graphql"); const postgraphile_1 = require("postgraphile"); exports.MutationAtomicityHeaderName = 'x-mutation-atomicity'; var MutationAtomicityHeaderValue; (function (MutationAtomicityHeaderValue) { MutationAtomicityHeaderValue["ON"] = "on"; MutationAtomicityHeaderValue["OFF"] = "off"; })(MutationAtomicityHeaderValue = exports.MutationAtomicityHeaderValue || (exports.MutationAtomicityHeaderValue = {})); exports.getMutationAtomicityContext = (req, enablePluginByDefault = false) => { const body = req.body; const paramsList = typeof body === 'string' ? { query: body } : body; if (Array.isArray(paramsList) && paramsList.length > 1) { throw Error('AtomicMutationsPlugin does not support GraphQL query batching'); } if (!paramsList) { return undefined; } const { query, operationName } = paramsList; const parsedQuery = graphql_1.parse(query); const [executedDefinition] = parsedQuery.definitions.filter((definition) => (definition.name === undefined && (operationName === undefined || operationName === null)) || definition.name.value === operationName); if (executedDefinition && executedDefinition.operation === 'mutation' && ((req.headers[exports.MutationAtomicityHeaderName] && req.headers[exports.MutationAtomicityHeaderName].toLowerCase() === MutationAtomicityHeaderValue.ON) || (req.headers[exports.MutationAtomicityHeaderName] === undefined && enablePluginByDefault))) { req.headers[exports.MutationAtomicityHeaderName] = MutationAtomicityHeaderValue.ON; const totalMutations = executedDefinition.selectionSet.selections.filter((selection) => selection.name.value !== '__typename').length; req.mutationAtomicityContext = { totalMutations, executedMutations: [], }; } else { req.headers[exports.MutationAtomicityHeaderName] = MutationAtomicityHeaderValue.OFF; } if (req.headers[exports.MutationAtomicityHeaderName] === MutationAtomicityHeaderValue.ON) { return req.mutationAtomicityContext; } else { return undefined; } }; exports.AtomicMutationsPlugin = postgraphile_1.makeWrapResolversPlugin((context) => { if (context.scope.isRootMutation) { return { scope: context.scope }; } else { return null; } }, () => async (resolver, source, args, context, resolveInfo) => { const { mutationAtomicityContext, pgClient, } = context; try { if (mutationAtomicityContext && mutationAtomicityContext.executedMutations.length === 0) { await pgClient.query('SAVEPOINT atomic_mutations_tx_start'); } const result = await resolver(source, args, context, resolveInfo); if (mutationAtomicityContext) { mutationAtomicityContext.executedMutations.push({ hasErrors: false }); } return result; } catch (error) { if (mutationAtomicityContext) { mutationAtomicityContext.executedMutations.push({ hasErrors: true }); } throw error; } finally { if (mutationAtomicityContext && mutationAtomicityContext.executedMutations.length === mutationAtomicityContext.totalMutations) { if (mutationAtomicityContext.executedMutations.filter((mutation) => mutation.hasErrors === true).length) { await pgClient.query(`ROLLBACK TO SAVEPOINT atomic_mutations_tx_start`); } else { await pgClient.query('RELEASE SAVEPOINT atomic_mutations_tx_start'); } } } });