UNPKG

@graphql-tools/executor-urql-exchange

Version:
72 lines (71 loc) 3.25 kB
import { pipe, share, filter, takeUntil, mergeMap, merge, make } from 'wonka'; import { makeResult, makeErrorResult, mergeResultPatch, getOperationName, } from '@urql/core'; import { isAsyncIterable } from '@graphql-tools/utils'; export function executorExchange(executor) { function makeYogaSource(operation) { const operationName = getOperationName(operation.query); const extraFetchOptions = typeof operation.context.fetchOptions === 'function' ? operation.context.fetchOptions() : operation.context.fetchOptions; const executionRequest = { document: operation.query, operationName, operationType: operation.kind, variables: operation.variables, context: operation.context, extensions: { endpoint: operation.context.url, fetch: operation.context.fetch, useGETForQueries: operation.context.preferGetMethod, headers: extraFetchOptions === null || extraFetchOptions === void 0 ? void 0 : extraFetchOptions.headers, method: extraFetchOptions === null || extraFetchOptions === void 0 ? void 0 : extraFetchOptions.method, }, }; return make(observer => { let ended = false; Promise.resolve(executor(executionRequest)) .then(async (result) => { if (ended || !result) { return; } if (!isAsyncIterable(result)) { observer.next(makeResult(operation, result)); } else { let prevResult = null; for await (const value of result) { if (value) { prevResult = prevResult ? mergeResultPatch(prevResult, value) : makeResult(operation, value); observer.next(prevResult); } if (ended) { break; } } } observer.complete(); }) .catch(error => { observer.next(makeErrorResult(operation, error)); }) .finally(() => { ended = true; observer.complete(); }); return () => { ended = true; }; }); } return function executorExchangeFn({ forward }) { return function executorExchangeIO(ops$) { const sharedOps$ = share(ops$); const executedOps$ = pipe(sharedOps$, filter(operation => operation.kind === 'query' || operation.kind === 'mutation' || operation.kind === 'subscription'), mergeMap(operation => { const teardown$ = pipe(sharedOps$, filter(op => op.kind === 'teardown' && op.key === operation.key)); return pipe(makeYogaSource(operation), takeUntil(teardown$)); })); const forwardedOps$ = pipe(sharedOps$, filter(operation => operation.kind === 'teardown'), forward); return merge([executedOps$, forwardedOps$]); }; }; }