First up, thanks for all your hard work on this repo!
Now my issue.
apollo.mutate and apollo.query seem like they are Observables, but they are not rxjs observables and do not work correctly with pipe operators like flatMap.
apollo.watchQuery is an rxjs compatible observable.
I have samples code for this ready to play with in the apollo branch of this repo if you are interested.
https://github.com/vespertilian/wallaby-angular-node-yarn-workspaces/tree/apollo
My issue is I wanted to run a mutation then run another mutation.
Something like this:
const multiplyMutation = gql`
mutation Multiply($number: Int!) {
multiply(number: $number) {
value
}
}
`;
this.apollo.mutate({mutation: multiplyMutation, variables: {number: 2}})
.pipe(
flatMap(({data}: any) => {
this.addToResult(data.multiply.value, 'd');
// this does not work :(
return this.apollo.mutate({mutation: multiplyMutation, variables: {number: 8}});
})
)
.subscribe(({data}) => {
// never get here
this.addToResult(data.multiply.value, 'd');
});
You can get around the issue by using from(.toPromise)
Like this:
from(this.apollo.mutate({mutation: multiplyMutation, variables: {number: 6}}).toPromise())
.pipe(
flatMap(({data}: any) => {
this.addToResult(data.multiply.value, 'e');
return from(this.apollo.mutate({mutation: multiplyMutation, variables: {number: 9}}).toPromise());
})
)
.subscribe(({data}) => {
this.addToResult(data.multiply.value, 'e');
});
Full code samples here:
https://github.com/vespertilian/wallaby-angular-node-yarn-workspaces/blob/apollo/angular-app/src/app/apollo-test/apollo-test.component.ts
After some digging I am assuming this is because Apollo does not use RxJS. It took me a while to track this issue down and it might be worth mentioning this in the docs that the Observables returned from apollo.mutate and apollo.query are not compatible with all RxJS operators.
It mentioned in the apollo.mutate.valueChanges docs that this function is compatible with RxJS, it's just not mentioned that apollo.mutate and apollo.query is not compatible.
From the docs on mutation: "As you can see, mutate method returns an Observable that resolves with ApolloQueryResult. It is the same result we get when we fetch queries." - to me this implied it was an Observable and I assumed it would be compatible with RxJS.
The extra issue with mutations is we currently don't have a .valueChanges method that emits a valid RxJS observable.
The real fix would be to be able to use RxJS as the Observable library for Apollo, as these different observables are very confusing to work with in Angular.
This issue here seems to do that.
https://github.com/apollographql/apollo-link/pull/380
I will bump that issue with this thread, hopefully the sample repo included does a good job of highlighting this issue and why having RxJS as a native (peer) dependency would make Apollo and Angular much better friends.
Is there anything else specific I can do to help you push this issue forward?
apollo-link package has nothing to do with your issue. It could even use Promises or iterables, it doesn't matter. That's because the observable created in apollo-link is never used in Apollo Angular. It's used by apollo-client and the library creates a Promise that apollo-angular uses to create RxJS Observable.
Here's the same what you did. flatMap is an alias for mergeMap.
https://stackblitz.com/edit/simple-apollo-angular-example-z6qx3a?file=app%2Fupvoter.component.ts
It has RxJS as peer dependency too.
@kamilkisiela Thank you for you quick reply, for the background on Apollo link, and the sample repo.
When I first looked at it, it did seem to work, I was thinking dammit my config is wrong, checking my repo against yours they looked the same.
Digging into it a bit more the reason your code looks like it works, is because both mutations are sent over the network, and the updates to your view is being driven separately by watchQuery.
Your second mutation however does not complete the .subscribe() block never gets executed, which you can see with a simple console.log().
https://stackblitz.com/edit/simple-apollo-angular-example-jpjmig?file=app/upvoter.component.ts
console.log("About to mutate")
mutation.pipe(mergeMap(() => {
console.log("We make it here")
return mutation
})).subscribe(() => {
console.log("This never completes :(")
})
My sample code highlighted this issue as I am using the result of the mutation from the second query call.
const mutation = this.apollo.mutate({mutation: multiplyMutation, variables: {number: 2}});
mutation
.pipe(
mergeMap(({data}: any) => {
this.addToResult(data.multiply.value, 'd');
// this does not work
return mutation;
})
)
.subscribe(({data}) => {
// we never get here so we cannot add the second mutation to our restuls
this.addToResult(data.multiply.value, 'd');
});
Thoughts?
@vespertilian Actually, it works: https://github.com/kamilkisiela/apollo-angular-services/blob/ae3fe822d14b477e2a3394cdab5d37e2290d9e0d/src/app/upvoter.component.ts#L18-L35
Maybe some indirect dependency was causing the issue. Update dependencies in the stackblitz example by clicking the "update" button in "dependencies" section to see that it works.
Closing but if it's still an issue, please @mention me
@kamilkisiela
RxJS was the issue, I assumed incorrectly the Angular Apollo library was the issue, as I had other RxJS mutations working within Angular and this was the new code I had introduced.
6.3.2 broken
6.3.3 fixed
https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md
Thanks for you help. If you are ever in Australia, hit me up and I will buy you a coffee!
An alternative is to wrap the ObservableQuery:
function fromObservableQuery<T = any>(observableQuery: ObservableQuery<T>): Observable<ApolloCurrentResult<T>> {
return new Observable((subscriber) => {
const subscription: ZenObservable.Subscription = observableQuery.subscribe(
(value) => subscriber.next(value),
(error) => subscriber.error(error),
() => subscriber.complete());
return () => {
subscription.unsubscribe();
};
});
}
@Xample how is that related to the issue?
apollo.query is not an rxjs observable, it is a ZenObservable.
// This does not work
this.apollo.watchQuery(aQuery).pipe(...)
Wrapping the ZenObservable into a rxjs observable will do the job
// This works
fromObservableQuery(this.apollo.watchQuery(aQuery)).pipe(...)
@Xample but everything that Apollo Angular exposes is RxJS Observable.
@kamilkisiela maybe now, but due to ionic 3, I am stuck with an older version and therefore had to wrap it using the code above. I suspect the author of this question to have had the same problem.
The issue was with RxJS
https://github.com/apollographql/apollo-angular/issues/835#issuecomment-425619596

I am stuck with ionic 3 which is using angular 5 which is using rxjs 5.5
I do not want to try upgrading rxjs as it is too risky, we will probably do the clean up when upgrading to ionic 4
thats weird that I am facing this issue with rxjs 6.3.3 and 6.4.0. I even tried to get rid of all the rxjs-compat and remove it from the deps completely.
valueChanges from apollo-angular 1.5.0 is returning rxjs Observable which fails to prove being zen-observable-Observable where it ends called by apollo-angular-link-http next
fromObservableQuery approach does not seem to help either...
all good, my bad ;)
in a custom pass-through ApolloLink in one case was returning rxjs of() observable instead of apollo-link/zen-observable one. Got suggested by similar symptoms.
also to @Xample - what I did in ionic 3 was to upgrade rxjs to 6.2.2 and relay on rxjs-compat most of the time. Do not remember all the process yet was not very painful.
@kamilkisiela It's also an issue trying to use rxjs outside of Apollo Angular
Most helpful comment
apollo.query is not an
rxjs observable, it is aZenObservable.Wrapping the ZenObservable into a rxjs observable will do the job