Ecodev / natural

Angular Material components and various utilities

Home Page:https://ecodev.github.io/natural

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Limit the use of intermediate observables

PowerKiKi opened this issue · comments

We have code using temporary observable looking like:

const observable = new Subject<Tcreate>();

this.apollo.mutate<Tcreate, Vcreate>({
    mutation: query,
    variables: variables,
}).subscribe(result => {
    this.apollo.getClient().reFetchObservableQueries();
    const newObject = this.mapCreation(result);
    observable.next(mergeWith(object, newObject, NaturalAbstractModelService.mergeOverrideArray));
    observable.complete();
});

return observable;

If an error is thrown by the internal observable it will never be seen by the returned observable. That make it impossible to use finalize() operator in our projects.

Instead it can be rewritten like this without losing anything with a code that is simpler to read and more performant:

return this.apollo.mutate<Tcreate, Vcreate>({
    mutation: query,
    variables: variables,
}).pipe(map(result => {
    this.apollo.getClient().reFetchObservableQueries();
    const newObject = this.mapCreation(result);

    return mergeWith(object, newObject, NaturalAbstractModelService.mergeOverrideArray);
}));

We should look for other similar usage and simplify them too.

Apollo only sends the query when we subscribe to it. Pipe does not subscribe.

I don't remember when/where this was problematic but I have something like that in mind. If we change that we have to triple check everywhere if everything still works as expected.

As alternative we could implement some error relay mecanism... It would uglify the method for sure...

After further investigation, I guess I was thinking about some .get/watchOne/All function.

For mutation, your changes seem legit.

Indeed my solution was only meant for mutations. But we should still think about what we could/should do for queries too.

Also, the suggested solution changes the existing behavior. Multiple subscribe to external observable will result in multiple XHR. We need to make a decision and keep the whole class as consistent as possible.

  • Should XHR be sent as soon as calling the class method, like service.create({foo}); or should XHR be sent only after a (first) subscribeservice.create({foo}).subscribe(); ?
  • Should multiple subscribes emit multiple XHR or not ?

I'd vote to be as close as possible to rxjs standard behavior, so one subscribe() is required to emit XHR, and a second subscribe() would emit a second XHR.

createOrUpdate() is doing a few internal tricks, but whatever happen in there could be updated to be compatible with whatever we choose to do. It should not be used a the primary factor to make a decision.

PS: I just checked create() and update() are always called with a .subscribe() in our project. So moving to standard rxjs behavior would most likely work out of the box.

A usfeul operator for this would the be the shareReplay() as used with success in 3e90418