@graphql-mesh/fusion-runtime
Version:
Runtime for GraphQL Mesh Fusion Supergraph
138 lines (137 loc) • 7.76 kB
JavaScript
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;
}