@graphql-tools/executor-urql-exchange
Version:
84 lines (83 loc) • 3.71 kB
JavaScript
import { filter, make, merge, mergeMap, pipe, share, takeUntil } from 'wonka';
import { isAsyncIterable } from '@graphql-tools/utils';
import { makeErrorResult, makeResult, mergeResultPatch, } from '@urql/core';
import { handleMaybePromise } from '@whatwg-node/promise-helpers';
export function executorExchange(executor) {
function makeYogaSource(operation) {
const extraFetchOptions = typeof operation.context.fetchOptions === 'function'
? operation.context.fetchOptions()
: operation.context.fetchOptions;
const executionRequest = {
document: operation.query,
operationType: operation.kind,
variables: operation.variables,
context: operation.context,
extensions: {
endpoint: operation.context.url,
fetch: operation.context.fetch,
useGETForQueries: operation.context.preferGetMethod,
headers: extraFetchOptions?.headers,
method: extraFetchOptions?.method,
},
};
return make(observer => {
let ended = false;
let iterator;
handleMaybePromise(() => executor(executionRequest), result => {
if (ended || !result) {
return;
}
if (!isAsyncIterable(result)) {
observer.next(makeResult(operation, result));
observer.complete();
}
else {
let prevResult = null;
iterator = result[Symbol.asyncIterator]();
function iterate() {
if (ended) {
return;
}
return iterator.next().then(({ value, done }) => {
if (done) {
return;
}
if (value) {
if (prevResult && value.incremental) {
prevResult = mergeResultPatch(prevResult, value);
}
else {
prevResult = makeResult(operation, value);
}
observer.next(prevResult);
}
return iterate();
});
}
return handleMaybePromise(() => iterate(), () => observer.complete());
}
}, error => {
observer.next(makeErrorResult(operation, error));
ended = true;
observer.complete();
});
return () => {
iterator?.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$]);
};
};
}