"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createBatchingExecutor = void 0;
const tslib_1 = require("tslib");
const dataloader_1 = tslib_1.__importDefault(require("dataloader"));
const value_or_promise_1 = require("value-or-promise");
const utils_1 = require("@graphql-tools/utils");
const mergeRequests_js_1 = require("./mergeRequests.js");
const splitResult_js_1 = require("./splitResult.js");
function createBatchingExecutor(executor, dataLoaderOptions, extensionsReducer = defaultExtensionsReducer) {
    const loadFn = createLoadFn(executor, extensionsReducer);
    const queryLoader = new dataloader_1.default(loadFn, dataLoaderOptions);
    const mutationLoader = new dataloader_1.default(loadFn, dataLoaderOptions);
    return function batchingExecutor(request) {
        const operationType = request.operationType ?? (0, utils_1.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}"`);
        }
    };
}
exports.createBatchingExecutor = createBatchingExecutor;
function createLoadFn(executor, extensionsReducer) {
    return function batchExecuteLoadFn(requests) {
        if (requests.length === 1) {
            return new value_or_promise_1.ValueOrPromise(() => executor(requests[0]))
                .then((result) => [result])
                .catch((err) => [err]);
        }
        const mergedRequests = (0, mergeRequests_js_1.mergeRequests)(requests, extensionsReducer);
        return new value_or_promise_1.ValueOrPromise(() => executor(mergedRequests)).then(resultBatches => {
            if ((0, utils_1.isAsyncIterable)(resultBatches)) {
                throw new Error('Executor must not return incremental results for batching');
            }
            return (0, splitResult_js_1.splitResult)(resultBatches, requests.length);
        });
    };
}
function defaultExtensionsReducer(mergedExtensions, request) {
    const newExtensions = request.extensions;
    if (newExtensions != null) {
        Object.assign(mergedExtensions, newExtensions);
    }
    return mergedExtensions;
}
