Skip to content

Commit

Permalink
Ensure @client @export variables in watched queries are updated
Browse files Browse the repository at this point in the history
The changes made in #5946 helped address an issue where queries
with `@client @export` variables were making unnecessary
network requests. While those changes work, they're currently
preventing watched queries using `@client @export` from updating
the `@export`ed variable, as new data is received. This commit
fixes that issue.
  • Loading branch information
hwillson committed Feb 24, 2020
1 parent d345d35 commit e6b17c0
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 11 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,9 @@
- Refined `useLazyQuery` types to help prevent runtime errors. <br/>
[@benmosher](https://github.com/benmosher) in [#5935](https://github.com/apollographql/apollo-client/pull/5935)

- Make sure `@client @export` variables used in watched queries are updated each time the query receives new data that changes the value of the `@export` variable. <br/>
[@hwillson](https://github.com/hwillson) in [#5986](https://github.com/apollographql/apollo-client/pull/5986)

## Apollo Client 2.6.8

### Apollo Client (2.6.8)
Expand Down
64 changes: 62 additions & 2 deletions src/__tests__/local-state/export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -754,8 +754,7 @@ describe('@client @export tests', () => {
});
done();
}

resultCount +=1;
resultCount += 1;
}
});
}
Expand Down Expand Up @@ -904,4 +903,65 @@ describe('@client @export tests', () => {
});
}
);

it(
"should update @client @export variables on each broadcast if they've " +
"changed",
done => {
const cache = new InMemoryCache();

const widgetCountQuery = gql`{ widgetCount @client }`;
cache.writeQuery({
query: widgetCountQuery,
data: {
widgetCount: 100
}
});

const client = new ApolloClient({
cache,
resolvers: {
Query: {
doubleWidgets(_, { widgetCount }) {
return widgetCount ? widgetCount * 2 : 0;
}
}
}
});

const doubleWidgetsQuery = gql`
query DoubleWidgets($widgetCount: Int!) {
widgetCount @client @export(as: "widgetCount")
doubleWidgets(widgetCount: $widgetCount) @client
}
`;

let count = 0;
const obs = client.watchQuery({ query: doubleWidgetsQuery });
obs.subscribe({
next({ data }) {
switch (count) {
case 0:
expect(data.widgetCount).toEqual(100);
expect(data.doubleWidgets).toEqual(200);

client.writeQuery({
query: widgetCountQuery,
data: {
widgetCount: 500
}
});
break;
case 1:
expect(data.widgetCount).toEqual(500);
expect(data.doubleWidgets).toEqual(1000);
done();
break;
default:
}
count += 1;
},
});
}
);
});
13 changes: 4 additions & 9 deletions src/core/ObservableQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -590,10 +590,7 @@ export class ObservableQuery<
iterateObserversSafely(this.observers, 'error', this.lastError = error);
};

const {
hasClientExports,
serverQuery
} = queryManager.transform(this.options.query);
const { hasClientExports } = queryManager.transform(this.options.query);

queryManager.observeQuery<TData>(queryId, this.options, {
next: (result: ApolloQueryResult<TData>) => {
Expand All @@ -605,9 +602,8 @@ export class ObservableQuery<
// Before calling `next` on each observer, we need to first see if
// the query is using `@client @export` directives, and update
// any variables that might have changed. If `@export` variables have
// changed, and the query is requesting both local and remote
// data, `setVariables` is used as a network refetch might be
// needed to pull in new data, using the updated `@export` variables.
// changed, `setVariables` is used to query the cache first, followed
// by the network if needed.
if (hasClientExports) {
queryManager.getLocalState().addExportedVariables(
query,
Expand All @@ -618,11 +614,10 @@ export class ObservableQuery<
!result.loading &&
previousResult &&
fetchPolicy !== 'cache-only' &&
serverQuery &&
!equal(previousVariables, variables)
) {
this.setVariables(variables).then(updatedResult => {
iterateObserversSafely(this.observers, 'next', updatedResult)
iterateObserversSafely(this.observers, 'next', updatedResult);
});
} else {
this.variables = this.options.variables = variables;
Expand Down

0 comments on commit e6b17c0

Please sign in to comment.