@graphql-tools/batch-execute
Version:
A set of utils for faster development of GraphQL tools
47 lines (46 loc) • 2.07 kB
JavaScript
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;
}