Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: replace iterall with native Symbol.asyncIterator + fix return types #232

Merged
merged 5 commits into from
Nov 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

- Add an optional generic type map to `PubSub`. <br/>
[@cursorsdottsx](https://github.com/cursorsdottsx) in [#245](https://github.com/apollographql/graphql-subscriptions/pull/245)
- Replace `iterall` use with native `Symbol.asyncIterator`. <br/>
[@n1ru4l](https://github.com/n1ru4l) in [#232](https://github.com/apollographql/graphql-subscriptions/pull/232)

### 2.0.1 (not yet released)

Expand Down
4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,7 @@
"type": "git",
"url": "https://github.com/apollostack/graphql-subscriptions.git"
},
"dependencies": {
"iterall": "^1.3.0"
},
"dependencies": {},
"peerDependencies": {
"graphql": "^15.7.2 || ^16.0.0"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { $$asyncIterator } from 'iterall';
import { PubSubEngine } from './pubsub-engine';

/**
Expand Down Expand Up @@ -33,7 +32,7 @@ import { PubSubEngine } from './pubsub-engine';
* @property pubsub @type {PubSubEngine}
* The PubSubEngine whose events will be observed.
*/
export class PubSubAsyncIterator<T> implements AsyncIterator<T> {
export class PubSubAsyncIterableIterator<T> implements AsyncIterableIterator<T> {

private pullQueue: ((value: IteratorResult<T>) => void)[];
private pushQueue: T[];
Expand Down Expand Up @@ -66,7 +65,7 @@ export class PubSubAsyncIterator<T> implements AsyncIterator<T> {
return Promise.reject(error);
}

public [$$asyncIterator]() {
public [Symbol.asyncIterator]() {
return this;
}

Expand Down Expand Up @@ -119,5 +118,4 @@ export class PubSubAsyncIterator<T> implements AsyncIterator<T> {
this.pubsub.unsubscribe(subscriptionId);
}
}

}
6 changes: 3 additions & 3 deletions src/pubsub-engine.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {PubSubAsyncIterator} from './pubsub-async-iterator';
import {PubSubAsyncIterableIterator} from './pubsub-async-iterable-iterator';

export abstract class PubSubEngine {
public abstract publish(triggerName: string, payload: any): Promise<void>;
public abstract subscribe(triggerName: string, onMessage: Function, options: Object): Promise<number>;
public abstract unsubscribe(subId: number);
public asyncIterator<T>(triggers: string | string[]): AsyncIterator<T> {
return new PubSubAsyncIterator<T>(this, triggers);
public asyncIterableIterator<T>(triggers: string | string[]): PubSubAsyncIterableIterator<T> {
return new PubSubAsyncIterableIterator<T>(this, triggers);
}
}
51 changes: 27 additions & 24 deletions src/test/asyncIteratorSubscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ import * as chaiAsPromised from 'chai-as-promised';
import { spy } from 'sinon';
import * as sinonChai from 'sinon-chai';

import { createAsyncIterator, isAsyncIterable } from 'iterall';
import { PubSub } from '../pubsub';
import { withFilter, FilterFn } from '../with-filter';
import { ExecutionResult } from 'graphql';

const isAsyncIterableIterator = (input: unknown): input is AsyncIterableIterator<unknown> => {
return input != null && typeof input[Symbol.asyncIterator] === 'function';
};

chai.use(chaiAsPromised);
chai.use(sinonChai);
const expect = chai.expect;
Expand Down Expand Up @@ -64,14 +67,13 @@ describe('GraphQL-JS asyncIterator', () => {
}
`);
const pubsub = new PubSub();
const origIterator = pubsub.asyncIterator(FIRST_EVENT);
const origIterator = pubsub.asyncIterableIterator(FIRST_EVENT);
const schema = buildSchema(origIterator);


const results = await subscribe({schema, document: query}) as AsyncIterator<ExecutionResult>;
const results = await subscribe({ schema, document: query }) as AsyncIterableIterator<ExecutionResult>;
const payload1 = results.next();

expect(isAsyncIterable(results)).to.be.true;
expect(isAsyncIterableIterator(results)).to.be.true;

const r = payload1.then(res => {
expect(res.value.data.testSubscription).to.equal('FIRST_EVENT');
Expand All @@ -90,13 +92,13 @@ describe('GraphQL-JS asyncIterator', () => {
}
`);
const pubsub = new PubSub();
const origIterator = pubsub.asyncIterator(FIRST_EVENT);
const origIterator = pubsub.asyncIterableIterator(FIRST_EVENT);
const schema = buildSchema(origIterator, () => Promise.resolve(true));

const results = await subscribe({schema, document: query}) as AsyncIterator<ExecutionResult>;
const results = await subscribe({ schema, document: query }) as AsyncIterableIterator<ExecutionResult>;
const payload1 = results.next();

expect(isAsyncIterable(results)).to.be.true;
expect(isAsyncIterableIterator(results)).to.be.true;

const r = payload1.then(res => {
expect(res.value.data.testSubscription).to.equal('FIRST_EVENT');
Expand All @@ -115,7 +117,7 @@ describe('GraphQL-JS asyncIterator', () => {
`);

const pubsub = new PubSub();
const origIterator = pubsub.asyncIterator(FIRST_EVENT);
const origIterator = pubsub.asyncIterableIterator(FIRST_EVENT);

let counter = 0;

Expand All @@ -133,8 +135,8 @@ describe('GraphQL-JS asyncIterator', () => {

const schema = buildSchema(origIterator, filterFn);

subscribe({schema, document: query}).then((results: AsyncGenerator<ExecutionResult, void, void> | ExecutionResult) => {
expect(isAsyncIterable(results)).to.be.true;
Promise.resolve(subscribe({ schema, document: query })).then((results: AsyncIterableIterator<ExecutionResult> | ExecutionResult) => {
expect(isAsyncIterableIterator(results)).to.be.true;

(results as AsyncGenerator<ExecutionResult, void, void>).next();
(results as AsyncGenerator<ExecutionResult, void, void>).return();
Expand All @@ -155,7 +157,7 @@ describe('GraphQL-JS asyncIterator', () => {
`);

const pubsub = new PubSub();
const origIterator = pubsub.asyncIterator(FIRST_EVENT);
const origIterator = pubsub.asyncIterableIterator(FIRST_EVENT);
const returnSpy = spy(origIterator, 'return');
const schema = buildSchema(origIterator);

Expand All @@ -172,20 +174,21 @@ describe('GraphQL-JS asyncIterator', () => {
});
});

describe('withFilter', () => {

it('works properly with finite asyncIterators', async () => {
const isEven = (x: number) => x % 2 === 0;
function isEven(x: number) {
if (x === undefined) {
throw Error('Undefined value passed to filterFn');
}
return x % 2 === 0;
}

const testFiniteAsyncIterator: AsyncIterator<number> = createAsyncIterator([1, 2, 3, 4, 5, 6, 7, 8]);
// Work around https://github.com/leebyron/iterall/issues/48
testFiniteAsyncIterator.throw = function (error) {
return Promise.reject(error);
};
testFiniteAsyncIterator.return = function () {
return Promise.resolve({ value: undefined, done: true });
};
const testFiniteAsyncIterator: AsyncIterableIterator<number> = (async function * () {
for (const value of [1, 2, 3, 4, 5, 6, 7, 8]) {
yield value;
}
})();

describe('withFilter', () => {
it('works properly with finite asyncIterators', async () => {
const filteredAsyncIterator = withFilter(() => testFiniteAsyncIterator, isEven)();

for (let i = 1; i <= 4; i++) {
Expand Down
19 changes: 11 additions & 8 deletions src/test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import * as chaiAsPromised from 'chai-as-promised';
import * as sinonChai from 'sinon-chai';

import { PubSub } from '../pubsub';
import { isAsyncIterable } from 'iterall';

const isAsyncIterableIterator = (input: unknown): input is AsyncIterableIterator<unknown> => {
return input != null && typeof input[Symbol.asyncIterator] === 'function';
};

chai.use(chaiAsPromised);
chai.use(sinonChai);
Expand Down Expand Up @@ -37,15 +40,15 @@ describe('AsyncIterator', () => {
it('should expose valid asyncIterator for a specific event', () => {
const eventName = 'test';
const ps = new PubSub();
const iterator = ps.asyncIterator(eventName);
const iterator = ps.asyncIterableIterator(eventName);
expect(iterator).to.not.be.undefined;
expect(isAsyncIterable(iterator)).to.be.true;
expect(isAsyncIterableIterator(iterator)).to.be.true;
});

it('should trigger event on asyncIterator when published', done => {
const eventName = 'test';
const ps = new PubSub();
const iterator = ps.asyncIterator(eventName);
const iterator = ps.asyncIterableIterator(eventName);

iterator.next().then(result => {
expect(result).to.not.be.undefined;
Expand All @@ -60,7 +63,7 @@ describe('AsyncIterator', () => {
it('should not trigger event on asyncIterator when publishing other event', () => {
const eventName = 'test2';
const ps = new PubSub();
const iterator = ps.asyncIterator('test');
const iterator = ps.asyncIterableIterator('test');
const spy = sinon.spy();

iterator.next().then(spy);
Expand All @@ -71,7 +74,7 @@ describe('AsyncIterator', () => {
it('register to multiple events', done => {
const eventName = 'test2';
const ps = new PubSub();
const iterator = ps.asyncIterator(['test', 'test2']);
const iterator = ps.asyncIterableIterator(['test', 'test2']);
const spy = sinon.spy();

iterator.next().then(() => {
Expand All @@ -85,7 +88,7 @@ describe('AsyncIterator', () => {
it('should not trigger event on asyncIterator already returned', done => {
const eventName = 'test';
const ps = new PubSub();
const iterator = ps.asyncIterator(eventName);
const iterator = ps.asyncIterableIterator(eventName);

iterator.next().then(result => {
expect(result).to.deep.equal({
Expand Down Expand Up @@ -117,7 +120,7 @@ describe('AsyncIterator', () => {
}
}
const ps = new TestPubSub();
ps.asyncIterator(testEventName);
ps.asyncIterableIterator(testEventName);

expect(ps.listenerCount(testEventName)).to.equal(0);
});
Expand Down
7 changes: 3 additions & 4 deletions src/with-filter.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { $$asyncIterator } from 'iterall';

export type FilterFn<TSource = any, TArgs = any, TContext = any> = (rootValue?: TSource, args?: TArgs, context?: TContext, info?: any) => boolean | Promise<boolean>;
export type ResolverFn<TSource = any, TArgs = any, TContext = any> = (rootValue?: TSource, args?: TArgs, context?: TContext, info?: any) => AsyncIterator<any>;

interface IterallAsyncIterator<T> extends AsyncIterator<T> {
[$$asyncIterator](): IterallAsyncIterator<T>;
interface IterallAsyncIterator<T> extends AsyncIterableIterator<T> {
[Symbol.asyncIterator](): IterallAsyncIterator<T>;
}

export type WithFilter<TSource = any, TArgs = any, TContext = any> = (
Expand Down Expand Up @@ -63,7 +62,7 @@ export function withFilter<TSource = any, TArgs = any, TContext = any>(
throw(error) {
return asyncIterator.throw(error);
},
[$$asyncIterator]() {
[Symbol.asyncIterator]() {
return this;
},
};
Expand Down