UNPKG

@graphql-tools/batch-execute

Version:

A set of utils for faster development of GraphQL tools

47 lines (46 loc) 2.07 kB
import DataLoader from 'dataloader'; import { ValueOrPromise } from 'value-or-promise'; import { getOperationASTFromRequest, isAsyncIterable, } from '@graphql-tools/utils'; import { mergeRequests } from './mergeRequests.js'; import { splitResult } from './splitResult.js'; export function createBatchingExecutor(executor, dataLoaderOptions, extensionsReducer = defaultExtensionsReducer) { const loadFn = createLoadFn(executor, extensionsReducer); const queryLoader = new DataLoader(loadFn, dataLoaderOptions); const mutationLoader = new DataLoader(loadFn, dataLoaderOptions); return function batchingExecutor(request) { const operationType = request.operationType ?? getOperationASTFromRequest(request)?.operation; switch (operationType) { case 'query': return queryLoader.load(request); case 'mutation': return mutationLoader.load(request); case 'subscription': return executor(request); default: throw new Error(`Invalid operation type "${operationType}"`); } }; } function createLoadFn(executor, extensionsReducer) { return function batchExecuteLoadFn(requests) { if (requests.length === 1) { return new ValueOrPromise(() => executor(requests[0])) .then((result) => [result]) .catch((err) => [err]); } const mergedRequests = mergeRequests(requests, extensionsReducer); return new ValueOrPromise(() => executor(mergedRequests)).then(resultBatches => { if (isAsyncIterable(resultBatches)) { throw new Error('Executor must not return incremental results for batching'); } return splitResult(resultBatches, requests.length); }); }; } function defaultExtensionsReducer(mergedExtensions, request) { const newExtensions = request.extensions; if (newExtensions != null) { Object.assign(mergedExtensions, newExtensions); } return mergedExtensions; }