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

fix(afs): Allow multiple subscribers by using share, closes #1191 #1192

Merged
merged 7 commits into from
Oct 5, 2017

Conversation

jamesdaniels
Copy link
Member

Checklist

Description

Subscribing to AFS collection multiple times causes duplicate data to show up. This is due to events replaying in fromRef#combineChange.

Adding share() to collection#snapshotChange fixes this issue as the side-effects will only occur the once.

@jamesdaniels jamesdaniels requested a review from davideast October 4, 2017 00:57
@jamesdaniels jamesdaniels changed the title fix(afs): Allow multiple subscribers by using share fix(afs): Allow multiple subscribers by using share, closes #1191 Oct 4, 2017
Copy link
Member

@davideast davideast left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work, @jamesdaniels! Just a few things :)


const changes = stocks.valueChanges();

const subA = changes.subscribe(data => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nest these subscriptions to test that one happens after another. I did this locally:

it('should handle multiple subscriptions', async (done) => {
      const ITEMS = 4;
      const { randomCollectionName, ref, stocks, names } = await collectionHarness(afs, ITEMS);
      const obs = stocks.valueChanges();
      const sub1 = obs.subscribe(values1 => {
        const sub2 = obs.subscribe(values2 => {
          expect(values1.length).toEqual(values2.length);
          deleteThemAll(names, ref).then(done).catch(done.fail);
        });
      });
    });

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah good point.

@@ -89,7 +90,7 @@ export class AngularFirestoreCollection<T> {
*/
snapshotChanges(events?: firebase.firestore.DocumentChangeType[]): Observable<DocumentChangeAction[]> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need the .share() operator further down in fromRef.ts. That way each observable method benefits from a "shared" source.

export function fromRef<R>(ref: firebase.firestore.DocumentReference | firebase.firestore.Query) {
  return _fromRef<typeof ref, R>(ref).share();
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM, but as a optimization.
As mentioned, we need the share on sortedChanges (which I'll bump up to the definition) to make the side effects (combineChanges) occur only the once.

@jamesdaniels
Copy link
Member Author

@davideast found a couple more hairy problems here, spent the evening hacking work arounds together but couldn't find anything more elegant then firing next(undefined) before onSnapshot to indicate a reset. It might not be pretty but it will solve the problem cases I defined in the tests.

@@ -28,7 +29,8 @@ export function sortedChanges(query: firebase.firestore.Query, events: firebase.
return fromCollectionRef(query)
.map(changes => changes.payload.docChanges)
.scan((current, changes) => combineChanges(current, changes, events), [])
.map(changes => changes.map(c => ({ type: c.type, payload: c })));
.map(changes => changes.map(c => ({ type: c.type, payload: c })))
.shareReplay(1);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need .share() since .shareReplay() caches the data.

@jamesdaniels
Copy link
Member Author

One of my fixes introduced in 28aef60 (passing undefined) no longer works against master, since we are no longer filtering out null sets (eb71edc). I made that test pending while I think on a new, hopefully more elegant, solution.

This should handle most cases though.

@jamesdaniels
Copy link
Member Author

Ok I found the troubles, another commit coming in shortly.

@jamesdaniels jamesdaniels merged commit 21522ab into master Oct 5, 2017
@jamesdaniels jamesdaniels deleted the handle_multiple_collection_subscribers branch October 5, 2017 22:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants