diff --git a/src/core/ObservableQuery.ts b/src/core/ObservableQuery.ts index 271cc691736..b27fc663f64 100644 --- a/src/core/ObservableQuery.ts +++ b/src/core/ObservableQuery.ts @@ -275,6 +275,8 @@ export class ObservableQuery extends Observable> { }; } + // Note: if the query is not active (there are no subscribers), the promise + // will return null immediately. public setOptions(opts: ModifiableWatchQueryOptions): Promise> { const oldOptions = this.options; this.options = { @@ -289,12 +291,10 @@ export class ObservableQuery extends Observable> { } // If forceFetch went from false to true or noFetch went from true to false - if ((!oldOptions.forceFetch && opts.forceFetch) || (oldOptions.noFetch && !opts.noFetch)) { - return this.queryManager.fetchQuery(this.queryId, this.options) - .then(result => this.queryManager.transformResult(result)); - } + const tryFetch: boolean = (!oldOptions.forceFetch && opts.forceFetch) + || (oldOptions.noFetch && !opts.noFetch); - return this.setVariables(this.options.variables); + return this.setVariables(this.options.variables, tryFetch); } /** @@ -304,19 +304,41 @@ export class ObservableQuery extends Observable> { * Note: if the variables have not changed, the promise will return the old * results immediately, and the `next` callback will *not* fire. * + * Note: if the query is not active (there are no subscribers), the promise + * will return null immediately. + * * @param variables: The new set of variables. If there are missing variables, * the previous values of those variables will be used. + * + * @param tryFetch: Try and fetch new results even if the variables haven't + * changed (we may still just hit the store, but if there's nothing in there + * this will refetch) */ - public setVariables(variables: any): Promise> { + public setVariables(variables: any, tryFetch: boolean = false): Promise> { const newVariables = { ...this.variables, ...variables, }; - if (isEqual(newVariables, this.variables)) { + const nullPromise = new Promise((resolve) => resolve(null)); + + if (isEqual(newVariables, this.variables) && !tryFetch) { + // If we have no observers, then we don't actually want to make a network + // request. As soon as someone observes the query, the request will kick + // off. For now, we just store any changes. (See #1077) + if (this.observers.length === 0) { + return nullPromise; + } + return this.result(); } else { this.variables = newVariables; + + // See comment above + if (this.observers.length === 0) { + return nullPromise; + } + // Use the same options as before, but with new variables return this.queryManager.fetchQuery(this.queryId, { ...this.options, diff --git a/test/ObservableQuery.ts b/test/ObservableQuery.ts index cca7ff2b892..edaf66fb149 100644 --- a/test/ObservableQuery.ts +++ b/test/ObservableQuery.ts @@ -378,6 +378,14 @@ describe('ObservableQuery', () => { }); }); + it('does not perform a query when unsubscribed if variables change', () => { + // Note: no responses, will throw if a query is made + const queryManager = mockQueryManager(); + const observable = queryManager.watchQuery({ query, variables }); + + return observable.setVariables(differentVariables); + }); + it('sets networkStatus to `setVariables` when fetching', (done) => { const mockedResponses = [{ request: { query, variables },