Repository: apollographql/apollo-client

Problem statement:
Refetch query with new variables at runtime
Hey @stubailo @jbaxleyiii 

Relay provides an option in the component called [setvariables](https://facebook.github.io/relay/docs/api-reference-relay-container.html#setvariables) to change the variables on runtime. Does apollo client support this yet? I see `refetch` function, but it works like refresh button, which wouldn't be helpful if someone wants to change the variables and then refetch the query. I think this option could be super useful for things like infinite scroll pagination or filtering - one can set the variable on runtime and fetch the updated data to update the store with new data. 



Hints:
If you want to pass new variables you can just unsubscribe from the previous query and start a new one.

`react-apollo` makes this really convenient: You can easily pass in a prop from outside, or put your state in Redux. The `mapQueriesToProps` option takes in `ownProps` and `state`, which can be used as variables in your query.

See this example (this is using data from `Meteor.userId()` but you could put other stuff in there):

https://github.com/apollostack/meteor-starter-kit/blob/3950b23ee39be144168a3f4d9f56ebeafb912533/imports/ui/App.js#L21-L44

However since we already have the `refetch` helper method, it would be pretty simple to have that take in a new set of variables.

Hi @stubailo I did the same thing for passing variables for this demo app: https://github.com/gauravtiwari/apollo_on_rails/blob/master/app/assets/javascripts/components/posts/show.es6.js#L41, but I think to utilise `refetch()` with new variables would be much more clear and easy to use. 

`For example:` In infinite scroll pagination, we could just change the number of new records to fetch and page offset and it would fetch the new data.

``` javascript
variables: {
  first: 20,
}
```

Later for refetching: 

``` javascript
this.refetch({
  variables: {first: 40, page: 2}
});
```

@johnthepink would your pagination for the app do something similar if present?

Based on how refetch works right now I think it would be trivial to build!

@stubailo thoughts on passing just an object of variables vs passing a QueryOptions object? 

Hmm lets keep variables only for now until someone has a need for the other stuff?

@jbaxleyiii I think for a component, the query mostly revolves around variables (if any), so mutating just the variable object and then have some kinda of observer to detect that the variable changed and refetch (I guess that's how refetch works right now, but with variables)

@jbaxleyiii it totally could. I'm just updating redux and letting it unsubscribe and start over (mixed with `shouldComponentUpdate`). I think I like the refetch idea better though, because the unsubscribe currently removes the data from the store and then adds it back. Which, if you are trying to render components based off the store is a little wonky.

Cool, I'll see about knocking this out now


Patch:
diff --git a/src/QueryManager.ts b/src/QueryManager.ts
--- a/src/QueryManager.ts
+++ b/src/QueryManager.ts
@@ -67,7 +67,7 @@ export class ObservableQuery extends Observable<GraphQLResult> {
 }
 
 export interface QuerySubscription extends Subscription {
-  refetch();
+  refetch(variables?: any): void;
 }
 
 export interface WatchQueryOptions {
@@ -197,8 +197,8 @@ export class QueryManager {
         unsubscribe: () => {
           this.stopQuery(queryId);
         },
-        refetch: () => {
-          this.fetchQuery(queryId, assign(options, { forceFetch: true }) as WatchQueryOptions);
+        refetch: (variables: any): void => {
+          this.fetchQuery(queryId, assign(options, { forceFetch: true, variables }) as WatchQueryOptions);
         },
       };
     });


Test patch:
diff --git a/test/QueryManager.ts b/test/QueryManager.ts
--- a/test/QueryManager.ts
+++ b/test/QueryManager.ts
@@ -301,6 +301,82 @@ describe('QueryManager', () => {
     });
   });
 
+  it('allows you to refetch queries with new variables', (done) => {
+    const query = `
+      {
+        people_one(id: 1) {
+          name
+        }
+      }
+    `;
+
+    const data1 = {
+      people_one: {
+        name: 'Luke Skywalker',
+      },
+    };
+
+    const data2 = {
+      people_one: {
+        name: 'Luke Skywalker has a new name',
+      },
+    };
+
+    const data3 = {
+      people_one: {
+        name: 'Luke Skywalker has a new name',
+      },
+    };
+
+    const variables = {
+      test: 'I am your father',
+    };
+
+    const networkInterface = mockNetworkInterface(
+      {
+        request: { query: query },
+        result: { data: data1 },
+      },
+      {
+        request: { query: query },
+        result: { data: data2 },
+      },
+      {
+        request: { query: query, variables },
+        result: { data: data2 },
+      }
+    );
+
+    const queryManager = new QueryManager({
+      networkInterface,
+      store: createApolloStore(),
+      reduxRootKey: 'apollo',
+    });
+
+    let handleCount = 0;
+
+    const handle = queryManager.watchQuery({
+      query: query,
+    });
+
+    const subscription = handle.subscribe({
+      next(result) {
+        handleCount++;
+
+        if (handleCount === 1) {
+          assert.deepEqual(result.data, data1);
+          subscription.refetch();
+        } else if (handleCount === 2) {
+          assert.deepEqual(result.data, data2);
+          subscription.refetch(variables);
+        } else if (handleCount === 3) {
+          assert.deepEqual(result.data, data3);
+          done();
+        }
+      },
+    });
+  });
+
   it('doesn\'t explode if you refetch before first fetch is done with query diffing', (done) => {
     const primeQuery = `
       {