@graphql-yoga/nestjs
Version:
GraphQL Yoga driver for NestJS GraphQL.
82 lines (74 loc) • 1.7 kB
text/typescript
export interface Generator<T> {
gen: AsyncGenerator<T, void, T>;
produce(val: T): void;
}
function createGenerator<T>(): Generator<T> {
const pending: T[] = [];
const deferred = {
done: false,
error: null as unknown,
resolve: () => {
// noop
},
};
const gen = (async function* gen() {
for (;;) {
if (!pending.length) {
// only wait if there are no pending messages available
await new Promise<void>(resolve => (deferred.resolve = resolve));
}
// first flush
while (pending.length) {
yield pending.shift()!;
}
// then error
if (deferred.error) {
throw deferred.error;
}
// or complete
if (deferred.done) {
return;
}
}
})();
gen.throw = async err => {
if (!deferred.done) {
deferred.done = true;
deferred.error = err;
deferred.resolve();
}
return { done: true, value: undefined };
};
gen.return = async () => {
if (!deferred.done) {
deferred.done = true;
deferred.resolve();
}
return { done: true, value: undefined };
};
return {
gen,
produce(val) {
pending.push(val);
deferred.resolve();
},
};
}
export function createPubSub<T>() {
const producers: Generator<T>['produce'][] = [];
return {
pub(val: T) {
for (const next of producers) next(val);
},
sub() {
const { gen, produce } = createGenerator<T>();
producers.push(produce);
const origReturn = gen.return;
gen.return = () => {
producers.splice(producers.indexOf(produce), 1);
return origReturn();
};
return gen;
},
};
}