UNPKG

@graphql-mesh/fusion-runtime

Version:

Runtime for GraphQL Mesh Fusion Supergraph

138 lines (137 loc) 7.76 kB
import { iterateAsync, mapMaybePromise } from '@graphql-mesh/utils'; import { isAsyncIterable, mapAsyncIterator, } from '@graphql-tools/utils'; export function defaultTransportsOption(transportKind) { return import(`@graphql-mesh/transport-${transportKind}`).catch(err => { console.error(err); throw new Error(`No transport found for ${transportKind}. Please install @graphql-mesh/transport-${transportKind}`); }); } export function createTransportGetter(transports) { if (typeof transports === 'function') { return transports; } return function getTransport(transportKind) { const transport = transports[transportKind]; if (!transport) { throw new Error(`No transport found for ${transportKind}`); } return transport; }; } export function getTransportExecutor(transportGetter, transportContext) { transportContext.logger?.info(`Loading transport ${transportContext.transportEntry?.kind}`); const transport$ = transportGetter(transportContext.transportEntry?.kind); return mapMaybePromise(transport$, transport => transport.getSubgraphExecutor(transportContext)); } export function getOnSubgraphExecute({ fusiongraph, plugins, transports, transportBaseContext, transportEntryMap, subgraphMap, }) { const onSubgraphExecuteHooks = []; if (plugins) { for (const plugin of plugins) { if (plugin.onSubgraphExecute) { onSubgraphExecuteHooks.push(plugin.onSubgraphExecute); } } } const subgraphExecutorMap = {}; const transportGetter = createTransportGetter(transports); function onSubgraphExecute(subgraphName, executionRequest) { let executor = subgraphExecutorMap[subgraphName]; if (executor == null) { transportBaseContext?.logger?.info(`Initializing executor for subgraph ${subgraphName}`); const transportEntry = transportEntryMap[subgraphName]; // eslint-disable-next-line no-inner-declarations function wrapExecutorWithHooks(currentExecutor) { if (onSubgraphExecuteHooks.length) { return function executorWithHooks(executionRequest) { const onSubgraphExecuteDoneHooks = []; const subgraph = subgraphMap.get(subgraphName); const onSubgraphExecuteHooksRes$ = iterateAsync(onSubgraphExecuteHooks, onSubgraphExecuteHook => onSubgraphExecuteHook({ fusiongraph, subgraph, subgraphName, transportEntry, executionRequest, setExecutionRequest(newExecutionRequest) { executionRequest = newExecutionRequest; }, executor: currentExecutor, setExecutor(newExecutor) { currentExecutor = newExecutor; }, }), onSubgraphExecuteDoneHooks); function handleOnSubgraphExecuteHooksResult() { if (onSubgraphExecuteDoneHooks.length) { // eslint-disable-next-line no-inner-declarations function handleExecutorResWithHooks(currentResult) { const executeDoneResults = []; const onSubgraphExecuteDoneHooksRes$ = iterateAsync(onSubgraphExecuteDoneHooks, onSubgraphExecuteDoneHook => onSubgraphExecuteDoneHook({ result: currentResult, setResult(newResult) { currentResult = newResult; }, }), executeDoneResults); function handleExecuteDoneResults(result) { if (!isAsyncIterable(result)) { return result; } if (executeDoneResults.length === 0) { return result; } const onNextHooks = []; const onEndHooks = []; for (const executeDoneResult of executeDoneResults) { if (executeDoneResult.onNext) { onNextHooks.push(executeDoneResult.onNext); } if (executeDoneResult.onEnd) { onEndHooks.push(executeDoneResult.onEnd); } } return mapAsyncIterator(result[Symbol.asyncIterator](), currentResult => { if (onNextHooks.length === 0) { return currentResult; } const $ = iterateAsync(onNextHooks, onNext => onNext({ result: currentResult, setResult: res => { currentResult = res; }, })); return mapMaybePromise($, () => currentResult); }, undefined, () => onEndHooks.length === 0 ? undefined : iterateAsync(onEndHooks, onEnd => onEnd())); } return mapMaybePromise(onSubgraphExecuteDoneHooksRes$, () => handleExecuteDoneResults(currentResult)); } const executorRes$ = currentExecutor(executionRequest); return mapMaybePromise(executorRes$, handleExecutorResWithHooks); } return currentExecutor(executionRequest); } return mapMaybePromise(onSubgraphExecuteHooksRes$, handleOnSubgraphExecuteHooksResult); }; } return currentExecutor; } executor = function lazyExecutor(subgraphExecReq) { const subgraph = subgraphMap.get(subgraphName); const executor$ = getTransportExecutor(transportGetter, transportBaseContext ? { ...transportBaseContext, subgraphName, subgraph, transportEntry, } : { subgraph, transportEntry, subgraphName }); return mapMaybePromise(executor$, executor_ => { executor = wrapExecutorWithHooks(executor_); subgraphExecutorMap[subgraphName] = executor; return executor(subgraphExecReq); }); }; } return executor(executionRequest); } return onSubgraphExecute; }