postgraphile-plugin-atomic-mutations
Version:
Postgraphile plugin to enable mutation atomicty with GraphQL requests containing multiple mutations
88 lines (87 loc) • 3.88 kB
JavaScript
;
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');
}
}
}
});