@graphql-mesh/urql-exchange
Version:
64 lines (63 loc) • 2.6 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';
const ROOT_VALUE = {};
const makeExecuteSource = (operation, options) => {
const operationFn = operation.kind === 'subscription' ? options.subscribe : options.execute;
return make(observer => {
let ended = false;
operationFn(operation.query, operation.variables, operation.context, ROOT_VALUE)
.then((result) => {
if (ended || !result) {
return;
}
else if (!isAsyncIterable(result)) {
observer.next(makeResult(operation, result));
return;
}
const iterator = result[Symbol.asyncIterator]();
let prevResult = null;
function next({ done, value }) {
if (value) {
observer.next((prevResult = prevResult
? mergeResultPatch(prevResult, value)
: makeResult(operation, value)));
}
if (!done && !ended) {
return iterator.next().then(next);
}
if (ended && iterator.return != null) {
return iterator.return();
}
}
return iterator.next().then(next);
})
.then(() => {
observer.complete();
})
.catch(error => {
observer.next(makeErrorResult(operation, error));
observer.complete();
});
return () => {
ended = true;
};
});
};
/** Exchange for executing queries locally on a schema using graphql-js. */
export const meshExchange = (options) => ({ forward }) => {
return ops$ => {
const sharedOps$ = share(ops$);
const executedOps$ = pipe(sharedOps$, filter((operation) => {
return (operation.kind === 'query' ||
operation.kind === 'mutation' ||
operation.kind === 'subscription');
}), mergeMap((operation) => {
const { key } = operation;
const teardown$ = pipe(sharedOps$, filter(op => op.kind === 'teardown' && op.key === key));
return pipe(makeExecuteSource(operation, options), takeUntil(teardown$));
}));
const forwardedOps$ = pipe(sharedOps$, filter(operation => operation.kind === 'teardown'), forward);
return merge([executedOps$, forwardedOps$]);
};
};