graphql-modules
Version:
Create reusable, maintainable, testable and extendable GraphQL modules
78 lines (77 loc) • 3.25 kB
JavaScript
import { wrapSchema } from '@graphql-tools/wrap';
import { execute } from 'graphql';
import { uniqueId } from '../shared/utils';
const CONTEXT_ID = Symbol.for('context-id');
export function apolloExecutorCreator({ createExecution, }) {
return function createApolloExecutor(options) {
const executor = createExecution(options);
return async function executorAdapter(requestContext) {
return executor({
schema: requestContext.schema,
document: requestContext.document,
operationName: requestContext.operationName,
variableValues: requestContext.request.variables,
contextValue: requestContext.context,
});
};
};
}
export function apolloSchemaCreator({ createSubscription, contextBuilder, schema, }) {
const createApolloSchema = () => {
const sessions = {};
const subscription = createSubscription();
function getSession(ctx, { context, ɵdestroy: destroy }) {
if (!ctx[CONTEXT_ID]) {
ctx[CONTEXT_ID] = uniqueId((id) => !sessions[id]);
sessions[ctx[CONTEXT_ID]] = {
count: 0,
session: {
context,
destroy() {
if (--sessions[ctx[CONTEXT_ID]].count === 0) {
destroy();
delete sessions[ctx[CONTEXT_ID]];
delete ctx[CONTEXT_ID];
}
},
},
};
}
sessions[ctx[CONTEXT_ID]].count++;
return sessions[ctx[CONTEXT_ID]].session;
}
return wrapSchema({
schema,
batch: true,
executor(input) {
if (input.operationType === 'subscription') {
return subscription({
schema,
document: input.document,
variableValues: input.variables,
contextValue: input.context,
rootValue: input.rootValue,
operationName: input.operationName,
});
}
// Create an execution context and run within it
return contextBuilder(input.context).runWithContext((env) => {
const { context, destroy } = getSession(input.context, env);
// It's important to wrap the executeFn within a promise
// so we can easily control the end of execution (with finally)
return Promise.resolve()
.then(() => execute({
schema,
document: input.document,
contextValue: context,
variableValues: input.variables,
rootValue: input.rootValue,
operationName: input.operationName,
}))
.finally(destroy);
});
},
});
};
return createApolloSchema;
}