Repository: FormidableLabs/urql
Pull request #397 (2019-08-20 11:36:19)

Add pollInterval support to client.executeQuery
Improvement of #396 


Patch:
diff --git a/docs/api.md b/docs/api.md
index 00c3bb69..7aaa576e 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -12,6 +12,7 @@ interface UseQueryArgs {
   variables?: any;
   requestPolicy?: RequestPolicy;
   pause?: boolean;
+  pollInterval?: number;
   context?: Partial<OperationContext>;
 }
 ```
@@ -109,6 +110,7 @@ interface UseSubscriptionState<T> {
 | context       | `?object`                  | The GraphQL request's context                                                                         |
 | requestPolicy | `?RequestPolicy`           | An optional request policy that should be used                                                        |
 | pause         | `?boolean`                 | A boolean flag instructing `Query` to pause execution of the subsequent query operation               |
+| pollInterval  | `?number`                  | Every `pollInterval` milliseconds the query will be refetched                                         |
 | children      | `RenderProps => ReactNode` | A function that follows the typical render props pattern. The shape of the render props is as follows |
 
 #### Render Props
diff --git a/src/client.ts b/src/client.ts
index 23e354c2..970d3d74 100755
--- a/src/client.ts
+++ b/src/client.ts
@@ -8,6 +8,10 @@ import {
   share,
   Source,
   take,
+  merge,
+  interval,
+  fromValue,
+  switchMap,
 } from 'wonka';
 
 import {
@@ -197,7 +201,17 @@ export class Client {
     opts?: Partial<OperationContext>
   ): Source<OperationResult> => {
     const operation = this.createRequestOperation('query', query, opts);
-    return this.executeRequestOperation(operation);
+    const response$ = this.executeRequestOperation(operation);
+    const { pollInterval } = operation.context;
+
+    if (pollInterval) {
+      return pipe(
+        merge([fromValue(0), interval(pollInterval)]),
+        switchMap(() => response$)
+      );
+    } else {
+      return response$;
+    }
   };
 
   executeSubscription = (
diff --git a/src/hooks/useQuery.ts b/src/hooks/useQuery.ts
index 767247be..ddd80b4e 100644
--- a/src/hooks/useQuery.ts
+++ b/src/hooks/useQuery.ts
@@ -13,6 +13,7 @@ export interface UseQueryArgs<V> {
   query: string | DocumentNode;
   variables?: V;
   requestPolicy?: RequestPolicy;
+  pollInterval?: number;
   context?: Partial<OperationContext>;
   pause?: boolean;
 }
@@ -58,6 +59,7 @@ export const useQuery = <T = any, V = object>(
       [unsubscribe.current] = pipe(
         client.executeQuery(request, {
           requestPolicy: args.requestPolicy,
+          pollInterval: args.pollInterval,
           ...args.context,
           ...opts,
           ...devtoolsContext,
@@ -70,6 +72,7 @@ export const useQuery = <T = any, V = object>(
     [
       args.context,
       args.requestPolicy,
+      args.pollInterval,
       client,
       devtoolsContext,
       request,
diff --git a/src/types.ts b/src/types.ts
index 2a8da684..8cd61b5f 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -42,6 +42,7 @@ export interface OperationContext {
   fetchOptions?: RequestInit | (() => RequestInit);
   requestPolicy: RequestPolicy;
   url: string;
+  pollInterval?: number;
   meta?: OperationDebugMeta;
 }
 


Test patch:
diff --git a/src/client.test.ts b/src/client.test.ts
index 7552c29f..6bc46e00 100755
--- a/src/client.test.ts
+++ b/src/client.test.ts
@@ -125,6 +125,21 @@ describe('executeQuery', () => {
 
     expect(receivedOps[0]).toHaveProperty('context.url', url);
   });
+
+  it('polls when pollInterval is specified', () => {
+    jest.useFakeTimers();
+    pipe(
+      client.executeQuery(query, { pollInterval: 10000 }),
+      subscribe(x => x)
+    );
+
+    expect(receivedOps.length).toEqual(1);
+    jest.runOnlyPendingTimers();
+    expect(receivedOps.length).toEqual(3);
+    expect(receivedOps[0].operationName).toEqual('query');
+    expect(receivedOps[1].operationName).toEqual('teardown');
+    expect(receivedOps[2].operationName).toEqual('query');
+  });
 });
 
 describe('executeMutation', () => {