@graphql-codegen/typescript-react-query 3.1.2-alpha-2113b7d34.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/config.d.ts CHANGED
@@ -72,4 +72,9 @@ export interface ReactQueryRawPluginConfig extends Omit<RawClientSideBasePluginC
72
72
  * @description Changes the default "TError" generic type.
73
73
  */
74
74
  errorType?: string;
75
+ /**
76
+ * @default false
77
+ * @description Adds an Infinite Query along side the standard one
78
+ */
79
+ addInfiniteQuery?: boolean;
75
80
  }
@@ -1,7 +1,7 @@
1
+ import { CustomFetch } from './config';
2
+ import { FetcherRenderer } from './fetcher';
1
3
  import { OperationDefinitionNode } from 'graphql';
2
4
  import { ReactQueryVisitor } from './visitor';
3
- import { FetcherRenderer } from './fetcher';
4
- import { CustomFetch } from './config';
5
5
  export declare class CustomMapperFetcher implements FetcherRenderer {
6
6
  private visitor;
7
7
  private _mapper;
@@ -9,6 +9,7 @@ export declare class CustomMapperFetcher implements FetcherRenderer {
9
9
  constructor(visitor: ReactQueryVisitor, customFetcher: CustomFetch);
10
10
  private getFetcherFnName;
11
11
  generateFetcherImplementaion(): string;
12
+ generateInfiniteQueryHook(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
12
13
  generateQueryHook(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
13
14
  generateMutationHook(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
14
15
  generateFetcherFetch(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
@@ -1,7 +1,7 @@
1
- import { OperationDefinitionNode } from 'graphql';
2
- import { ReactQueryVisitor } from './visitor';
3
1
  import { FetcherRenderer } from './fetcher';
4
2
  import { HardcodedFetch } from './config';
3
+ import { OperationDefinitionNode } from 'graphql';
4
+ import { ReactQueryVisitor } from './visitor';
5
5
  export declare class HardcodedFetchFetcher implements FetcherRenderer {
6
6
  private visitor;
7
7
  private config;
@@ -9,6 +9,7 @@ export declare class HardcodedFetchFetcher implements FetcherRenderer {
9
9
  private getEndpoint;
10
10
  private getFetchParams;
11
11
  generateFetcherImplementaion(): string;
12
+ generateInfiniteQueryHook(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
12
13
  generateQueryHook(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
13
14
  generateMutationHook(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
14
15
  generateFetcherFetch(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
@@ -1,10 +1,11 @@
1
+ import { FetcherRenderer } from './fetcher';
1
2
  import { OperationDefinitionNode } from 'graphql';
2
3
  import { ReactQueryVisitor } from './visitor';
3
- import { FetcherRenderer } from './fetcher';
4
4
  export declare class FetchFetcher implements FetcherRenderer {
5
5
  private visitor;
6
6
  constructor(visitor: ReactQueryVisitor);
7
7
  generateFetcherImplementaion(): string;
8
+ generateInfiniteQueryHook(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
8
9
  generateQueryHook(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
9
10
  generateMutationHook(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
10
11
  generateFetcherFetch(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
@@ -1,10 +1,11 @@
1
+ import { FetcherRenderer } from './fetcher';
1
2
  import { OperationDefinitionNode } from 'graphql';
2
3
  import { ReactQueryVisitor } from './visitor';
3
- import { FetcherRenderer } from './fetcher';
4
4
  export declare class GraphQLRequestClientFetcher implements FetcherRenderer {
5
5
  private visitor;
6
6
  constructor(visitor: ReactQueryVisitor);
7
7
  generateFetcherImplementaion(): string;
8
+ generateInfiniteQueryHook(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
8
9
  generateQueryHook(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
9
10
  generateMutationHook(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
10
11
  generateFetcherFetch(node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
package/fetcher.d.ts CHANGED
@@ -2,6 +2,7 @@ import { OperationDefinitionNode } from 'graphql';
2
2
  export interface FetcherRenderer {
3
3
  generateFetcherImplementaion: () => string;
4
4
  generateQueryHook: (node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean) => string;
5
+ generateInfiniteQueryHook: (node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean) => string;
5
6
  generateMutationHook: (node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean) => string;
6
7
  generateFetcherFetch: (node: OperationDefinitionNode, documentVariableName: string, operationName: string, operationResultType: string, operationVariablesTypes: string, hasRequiredVariables: boolean) => string;
7
8
  }
package/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { Types, PluginValidateFn, PluginFunction } from '@graphql-codegen/plugin-helpers';
2
- import { ReactQueryVisitor } from './visitor';
1
+ import { PluginFunction, PluginValidateFn, Types } from '@graphql-codegen/plugin-helpers';
3
2
  import { ReactQueryRawPluginConfig } from './config';
3
+ import { ReactQueryVisitor } from './visitor';
4
4
  export declare const plugin: PluginFunction<ReactQueryRawPluginConfig, Types.ComplexPluginOutput>;
5
5
  export declare const validate: PluginValidateFn<any>;
6
6
  export { ReactQueryVisitor };
package/index.js CHANGED
@@ -4,8 +4,8 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
6
 
7
- const pluginHelpers = require('@graphql-codegen/plugin-helpers');
8
7
  const graphql = require('graphql');
8
+ const pluginHelpers = require('@graphql-codegen/plugin-helpers');
9
9
  const visitorPluginCommon = require('@graphql-codegen/visitor-plugin-common');
10
10
  const autoBind = _interopDefault(require('auto-bind'));
11
11
  const changeCaseAll = require('change-case-all');
@@ -14,6 +14,11 @@ const path = require('path');
14
14
  function generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes) {
15
15
  return `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
16
16
  }
17
+ function generateInfiniteQueryKey(node, hasRequiredVariables) {
18
+ if (hasRequiredVariables)
19
+ return `['${node.name.value}.infinite', variables]`;
20
+ return `variables === undefined ? ['${node.name.value}.infinite'] : ['${node.name.value}.infinite', variables]`;
21
+ }
17
22
  function generateQueryKey(node, hasRequiredVariables) {
18
23
  if (hasRequiredVariables)
19
24
  return `['${node.name.value}', variables]`;
@@ -30,49 +35,72 @@ function generateMutationKeyMaker(node, operationName) {
30
35
  return `\nuse${operationName}.getKey = () => ${generateMutationKey(node)}};\n`;
31
36
  }
32
37
 
33
- class FetchFetcher {
34
- constructor(visitor) {
38
+ class CustomMapperFetcher {
39
+ constructor(visitor, customFetcher) {
35
40
  this.visitor = visitor;
41
+ if (typeof customFetcher === 'string') {
42
+ customFetcher = { func: customFetcher };
43
+ }
44
+ this._mapper = visitorPluginCommon.parseMapper(customFetcher.func);
45
+ this._isReactHook = customFetcher.isReactHook;
46
+ }
47
+ getFetcherFnName(operationResultType, operationVariablesTypes) {
48
+ return `${this._mapper.type}<${operationResultType}, ${operationVariablesTypes}>`;
36
49
  }
37
50
  generateFetcherImplementaion() {
38
- return `
39
- function fetcher<TData, TVariables>(endpoint: string, requestInit: RequestInit, query: string, variables?: TVariables) {
40
- return async (): Promise<TData> => {
41
- const res = await fetch(endpoint, {
42
- method: 'POST',
43
- ...requestInit,
44
- body: JSON.stringify({ query, variables }),
45
- });
46
-
47
- const json = await res.json();
48
-
49
- if (json.errors) {
50
- const { message } = json.errors[0];
51
-
52
- throw new Error(message);
51
+ if (this._mapper.isExternal) {
52
+ return visitorPluginCommon.buildMapperImport(this._mapper.source, [
53
+ {
54
+ identifier: this._mapper.type,
55
+ asDefault: this._mapper.default,
56
+ },
57
+ ], this.visitor.config.useTypeImports);
58
+ }
59
+ return null;
53
60
  }
54
-
55
- return json.data;
56
- }
57
- }`;
61
+ generateInfiniteQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
62
+ const variables = `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
63
+ const hookConfig = this.visitor.queryMethodMap;
64
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.hook);
65
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.options);
66
+ const options = `options?: ${hookConfig.infiniteQuery.options}<${operationResultType}, TError, TData>`;
67
+ const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
68
+ const impl = this._isReactHook
69
+ ? `(metaData) => ${typedFetcher}(${documentVariableName}).bind(null, {...variables, ...(metaData.pageParam ?? {})})()`
70
+ : `(metaData) => ${typedFetcher}(${documentVariableName}, {...variables, ...(metaData.pageParam ?? {})})()`;
71
+ return `export const useInfinite${operationName} = <
72
+ TData = ${operationResultType},
73
+ TError = ${this.visitor.config.errorType}
74
+ >(
75
+ ${variables},
76
+ ${options}
77
+ ) =>
78
+ ${hookConfig.infiniteQuery.hook}<${operationResultType}, TError, TData>(
79
+ ${generateInfiniteQueryKey(node, hasRequiredVariables)},
80
+ ${impl},
81
+ options
82
+ );`;
58
83
  }
59
84
  generateQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
60
- const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
85
+ const variables = `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
61
86
  const hookConfig = this.visitor.queryMethodMap;
62
87
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.query.hook);
63
88
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.query.options);
64
89
  const options = `options?: ${hookConfig.query.options}<${operationResultType}, TError, TData>`;
90
+ const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
91
+ const impl = this._isReactHook
92
+ ? `${typedFetcher}(${documentVariableName}).bind(null, variables)`
93
+ : `${typedFetcher}(${documentVariableName}, variables)`;
65
94
  return `export const use${operationName} = <
66
95
  TData = ${operationResultType},
67
96
  TError = ${this.visitor.config.errorType}
68
97
  >(
69
- dataSource: { endpoint: string, fetchParams?: RequestInit },
70
98
  ${variables},
71
99
  ${options}
72
100
  ) =>
73
101
  ${hookConfig.query.hook}<${operationResultType}, TError, TData>(
74
102
  ${generateQueryKey(node, hasRequiredVariables)},
75
- fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, variables),
103
+ ${impl},
76
104
  options
77
105
  );`;
78
106
  }
@@ -82,52 +110,43 @@ function fetcher<TData, TVariables>(endpoint: string, requestInit: RequestInit,
82
110
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.mutation.hook);
83
111
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.mutation.options);
84
112
  const options = `options?: ${hookConfig.mutation.options}<${operationResultType}, TError, ${operationVariablesTypes}, TContext>`;
113
+ const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
114
+ const impl = this._isReactHook
115
+ ? `${typedFetcher}(${documentVariableName})`
116
+ : `(${variables}) => ${typedFetcher}(${documentVariableName}, variables)()`;
85
117
  return `export const use${operationName} = <
86
118
  TError = ${this.visitor.config.errorType},
87
119
  TContext = unknown
88
- >(
89
- dataSource: { endpoint: string, fetchParams?: RequestInit },
90
- ${options}
91
- ) =>
120
+ >(${options}) =>
92
121
  ${hookConfig.mutation.hook}<${operationResultType}, TError, ${operationVariablesTypes}, TContext>(
93
122
  ${generateMutationKey(node)},
94
- (${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, variables)(),
123
+ ${impl},
95
124
  options
96
125
  );`;
97
126
  }
98
127
  generateFetcherFetch(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
99
- const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
100
- return `\nuse${operationName}.fetcher = (dataSource: { endpoint: string, fetchParams?: RequestInit }, ${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, variables);`;
128
+ // We can't generate a fetcher field since we can't call react hooks outside of a React Fucntion Component
129
+ // Related: https://reactjs.org/docs/hooks-rules.html
130
+ if (this._isReactHook)
131
+ return '';
132
+ const variables = `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
133
+ const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
134
+ const impl = `${typedFetcher}(${documentVariableName}, variables)`;
135
+ return `\nuse${operationName}.fetcher = (${variables}) => ${impl};`;
101
136
  }
102
137
  }
103
138
 
104
- class HardcodedFetchFetcher {
105
- constructor(visitor, config) {
139
+ class FetchFetcher {
140
+ constructor(visitor) {
106
141
  this.visitor = visitor;
107
- this.config = config;
108
- }
109
- getEndpoint() {
110
- try {
111
- new URL(this.config.endpoint);
112
- return JSON.stringify(this.config.endpoint);
113
- }
114
- catch (e) {
115
- return `${this.config.endpoint} as string`;
116
- }
117
- }
118
- getFetchParams() {
119
- let fetchParamsPartial = '';
120
- if (this.config.fetchParams) {
121
- fetchParamsPartial = `\n ...(${this.config.fetchParams}),`;
122
- }
123
- return ` method: "POST",${fetchParamsPartial}`;
124
142
  }
125
143
  generateFetcherImplementaion() {
126
144
  return `
127
- function fetcher<TData, TVariables>(query: string, variables?: TVariables) {
145
+ function fetcher<TData, TVariables>(endpoint: string, requestInit: RequestInit, query: string, variables?: TVariables) {
128
146
  return async (): Promise<TData> => {
129
- const res = await fetch(${this.getEndpoint()}, {
130
- ${this.getFetchParams()}
147
+ const res = await fetch(endpoint, {
148
+ method: 'POST',
149
+ ...requestInit,
131
150
  body: JSON.stringify({ query, variables }),
132
151
  });
133
152
 
@@ -142,6 +161,27 @@ ${this.getFetchParams()}
142
161
  return json.data;
143
162
  }
144
163
  }`;
164
+ }
165
+ generateInfiniteQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
166
+ const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
167
+ const hookConfig = this.visitor.queryMethodMap;
168
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.hook);
169
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.options);
170
+ const options = `options?: ${hookConfig.query.options}<${operationResultType}, TError, TData>`;
171
+ return `export const useInfinite${operationName} = <
172
+ TData = ${operationResultType},
173
+ TError = ${this.visitor.config.errorType}
174
+ >(
175
+ dataSource: { endpoint: string, fetchParams?: RequestInit },
176
+ pageParamKey: keyof ${operationVariablesTypes},
177
+ ${variables},
178
+ ${options}
179
+ ) =>
180
+ ${hookConfig.infiniteQuery.hook}<${operationResultType}, TError, TData>(
181
+ ${generateInfiniteQueryKey(node, hasRequiredVariables)},
182
+ (metaData) => fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, {...variables, ...(metaData.pageParam ?? {})})(),
183
+ options
184
+ );`;
145
185
  }
146
186
  generateQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
147
187
  const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
@@ -153,12 +193,13 @@ ${this.getFetchParams()}
153
193
  TData = ${operationResultType},
154
194
  TError = ${this.visitor.config.errorType}
155
195
  >(
196
+ dataSource: { endpoint: string, fetchParams?: RequestInit },
156
197
  ${variables},
157
198
  ${options}
158
199
  ) =>
159
200
  ${hookConfig.query.hook}<${operationResultType}, TError, TData>(
160
201
  ${generateQueryKey(node, hasRequiredVariables)},
161
- fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, variables),
202
+ fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, variables),
162
203
  options
163
204
  );`;
164
205
  }
@@ -171,16 +212,19 @@ ${this.getFetchParams()}
171
212
  return `export const use${operationName} = <
172
213
  TError = ${this.visitor.config.errorType},
173
214
  TContext = unknown
174
- >(${options}) =>
215
+ >(
216
+ dataSource: { endpoint: string, fetchParams?: RequestInit },
217
+ ${options}
218
+ ) =>
175
219
  ${hookConfig.mutation.hook}<${operationResultType}, TError, ${operationVariablesTypes}, TContext>(
176
220
  ${generateMutationKey(node)},
177
- (${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, variables)(),
221
+ (${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, variables)(),
178
222
  options
179
223
  );`;
180
224
  }
181
225
  generateFetcherFetch(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
182
226
  const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
183
- return `\nuse${operationName}.fetcher = (${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, variables);`;
227
+ return `\nuse${operationName}.fetcher = (dataSource: { endpoint: string, fetchParams?: RequestInit }, ${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, variables);`;
184
228
  }
185
229
  }
186
230
 
@@ -193,6 +237,31 @@ class GraphQLRequestClientFetcher {
193
237
  function fetcher<TData, TVariables>(client: GraphQLClient, query: string, variables?: TVariables, headers?: RequestInit['headers']) {
194
238
  return async (): Promise<TData> => client.request<TData, TVariables>(query, variables, headers);
195
239
  }`;
240
+ }
241
+ generateInfiniteQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
242
+ const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
243
+ const typeImport = this.visitor.config.useTypeImports ? 'import type' : 'import';
244
+ this.visitor.imports.add(`${typeImport} { GraphQLClient } from 'graphql-request';`);
245
+ this.visitor.imports.add(`${typeImport} { RequestInit } from 'graphql-request/dist/types.dom';`);
246
+ const hookConfig = this.visitor.queryMethodMap;
247
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.hook);
248
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.options);
249
+ const options = `options?: ${hookConfig.infiniteQuery.options}<${operationResultType}, TError, TData>`;
250
+ return `export const useInfinite${operationName} = <
251
+ TData = ${operationResultType},
252
+ TError = ${this.visitor.config.errorType}
253
+ >(
254
+ pageParamKey: keyof ${operationVariablesTypes},
255
+ client: GraphQLClient,
256
+ ${variables},
257
+ ${options},
258
+ headers?: RequestInit['headers']
259
+ ) =>
260
+ ${hookConfig.infiniteQuery.hook}<${operationResultType}, TError, TData>(
261
+ ${generateInfiniteQueryKey(node, hasRequiredVariables)},
262
+ (metaData) => fetcher<${operationResultType}, ${operationVariablesTypes}>(client, ${documentVariableName}, {...variables, ...(metaData.pageParam ?? {})}, headers)(),
263
+ options
264
+ );`;
196
265
  }
197
266
  generateQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
198
267
  const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
@@ -245,39 +314,74 @@ function fetcher<TData, TVariables>(client: GraphQLClient, query: string, variab
245
314
  }
246
315
  }
247
316
 
248
- class CustomMapperFetcher {
249
- constructor(visitor, customFetcher) {
317
+ class HardcodedFetchFetcher {
318
+ constructor(visitor, config) {
250
319
  this.visitor = visitor;
251
- if (typeof customFetcher === 'string') {
252
- customFetcher = { func: customFetcher };
320
+ this.config = config;
321
+ }
322
+ getEndpoint() {
323
+ try {
324
+ new URL(this.config.endpoint);
325
+ return JSON.stringify(this.config.endpoint);
326
+ }
327
+ catch (e) {
328
+ return `${this.config.endpoint} as string`;
253
329
  }
254
- this._mapper = visitorPluginCommon.parseMapper(customFetcher.func);
255
- this._isReactHook = customFetcher.isReactHook;
256
330
  }
257
- getFetcherFnName(operationResultType, operationVariablesTypes) {
258
- return `${this._mapper.type}<${operationResultType}, ${operationVariablesTypes}>`;
331
+ getFetchParams() {
332
+ let fetchParamsPartial = '';
333
+ if (this.config.fetchParams) {
334
+ fetchParamsPartial = `\n ...(${this.config.fetchParams}),`;
335
+ }
336
+ return ` method: "POST",${fetchParamsPartial}`;
259
337
  }
260
338
  generateFetcherImplementaion() {
261
- if (this._mapper.isExternal) {
262
- return visitorPluginCommon.buildMapperImport(this._mapper.source, [
263
- {
264
- identifier: this._mapper.type,
265
- asDefault: this._mapper.default,
266
- },
267
- ], this.visitor.config.useTypeImports);
268
- }
269
- return null;
339
+ return `
340
+ function fetcher<TData, TVariables>(query: string, variables?: TVariables) {
341
+ return async (): Promise<TData> => {
342
+ const res = await fetch(${this.getEndpoint()}, {
343
+ ${this.getFetchParams()}
344
+ body: JSON.stringify({ query, variables }),
345
+ });
346
+
347
+ const json = await res.json();
348
+
349
+ if (json.errors) {
350
+ const { message } = json.errors[0];
351
+
352
+ throw new Error(message);
353
+ }
354
+
355
+ return json.data;
356
+ }
357
+ }`;
358
+ }
359
+ generateInfiniteQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
360
+ const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
361
+ const hookConfig = this.visitor.queryMethodMap;
362
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.hook);
363
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.options);
364
+ const options = `options?: ${hookConfig.infiniteQuery.options}<${operationResultType}, TError, TData>`;
365
+ return `export const useInfinite${operationName} = <
366
+ TData = ${operationResultType},
367
+ TError = ${this.visitor.config.errorType}
368
+ >(
369
+ pageParamKey: keyof ${operationVariablesTypes},
370
+ ${variables},
371
+ ${options}
372
+ ) =>
373
+ ${hookConfig.infiniteQuery.hook}<${operationResultType}, TError, TData>(
374
+ ${generateInfiniteQueryKey(node, hasRequiredVariables)},
375
+ (metaData) => fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, {...variables, ...(metaData.pageParam ?? {})})(),
376
+ options
377
+ );`;
270
378
  }
271
379
  generateQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
272
- const variables = `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
380
+ const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
273
381
  const hookConfig = this.visitor.queryMethodMap;
274
382
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.query.hook);
275
383
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.query.options);
276
384
  const options = `options?: ${hookConfig.query.options}<${operationResultType}, TError, TData>`;
277
- const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
278
- const impl = this._isReactHook
279
- ? `${typedFetcher}(${documentVariableName}).bind(null, variables)`
280
- : `${typedFetcher}(${documentVariableName}, variables)`;
281
385
  return `export const use${operationName} = <
282
386
  TData = ${operationResultType},
283
387
  TError = ${this.visitor.config.errorType}
@@ -287,7 +391,7 @@ class CustomMapperFetcher {
287
391
  ) =>
288
392
  ${hookConfig.query.hook}<${operationResultType}, TError, TData>(
289
393
  ${generateQueryKey(node, hasRequiredVariables)},
290
- ${impl},
394
+ fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, variables),
291
395
  options
292
396
  );`;
293
397
  }
@@ -297,29 +401,19 @@ class CustomMapperFetcher {
297
401
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.mutation.hook);
298
402
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.mutation.options);
299
403
  const options = `options?: ${hookConfig.mutation.options}<${operationResultType}, TError, ${operationVariablesTypes}, TContext>`;
300
- const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
301
- const impl = this._isReactHook
302
- ? `${typedFetcher}(${documentVariableName})`
303
- : `(${variables}) => ${typedFetcher}(${documentVariableName}, variables)()`;
304
404
  return `export const use${operationName} = <
305
405
  TError = ${this.visitor.config.errorType},
306
406
  TContext = unknown
307
407
  >(${options}) =>
308
408
  ${hookConfig.mutation.hook}<${operationResultType}, TError, ${operationVariablesTypes}, TContext>(
309
409
  ${generateMutationKey(node)},
310
- ${impl},
410
+ (${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, variables)(),
311
411
  options
312
412
  );`;
313
413
  }
314
414
  generateFetcherFetch(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
315
- // We can't generate a fetcher field since we can't call react hooks outside of a React Fucntion Component
316
- // Related: https://reactjs.org/docs/hooks-rules.html
317
- if (this._isReactHook)
318
- return '';
319
- const variables = `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
320
- const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
321
- const impl = `${typedFetcher}(${documentVariableName}, variables)`;
322
- return `\nuse${operationName}.fetcher = (${variables}) => ${impl};`;
415
+ const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
416
+ return `\nuse${operationName}.fetcher = (${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, variables);`;
323
417
  }
324
418
  }
325
419
 
@@ -332,10 +426,15 @@ class ReactQueryVisitor extends visitorPluginCommon.ClientSideBaseVisitor {
332
426
  exposeQueryKeys: visitorPluginCommon.getConfigValue(rawConfig.exposeQueryKeys, false),
333
427
  exposeMutationKeys: visitorPluginCommon.getConfigValue(rawConfig.exposeMutationKeys, false),
334
428
  exposeFetcher: visitorPluginCommon.getConfigValue(rawConfig.exposeFetcher, false),
429
+ addInfiniteQuery: visitorPluginCommon.getConfigValue(rawConfig.addInfiniteQuery, false),
335
430
  });
336
431
  this.rawConfig = rawConfig;
337
432
  this.reactQueryIdentifiersInUse = new Set();
338
433
  this.queryMethodMap = {
434
+ infiniteQuery: {
435
+ hook: 'useInfiniteQuery',
436
+ options: 'UseInfiniteQueryOptions',
437
+ },
339
438
  query: {
340
439
  hook: 'useQuery',
341
440
  options: 'UseQueryOptions',
@@ -373,6 +472,9 @@ class ReactQueryVisitor extends visitorPluginCommon.ClientSideBaseVisitor {
373
472
  if (!this.hasOperations) {
374
473
  return baseImports;
375
474
  }
475
+ if (this.config.addInfiniteQuery) {
476
+ this.reactQueryIdentifiersInUse.add('QueryFunctionContext');
477
+ }
376
478
  return [...baseImports, `import { ${Array.from(this.reactQueryIdentifiersInUse).join(', ')} } from 'react-query';`];
377
479
  }
378
480
  getFetcherImplementation() {
@@ -407,7 +509,10 @@ class ReactQueryVisitor extends visitorPluginCommon.ClientSideBaseVisitor {
407
509
  query += `\nuse${operationName}.document = ${documentVariableName};\n`;
408
510
  }
409
511
  if (this.config.exposeQueryKeys) {
410
- query += generateQueryKeyMaker(node, operationName, operationVariablesTypes, hasRequiredVariables);
512
+ query += `\n${generateQueryKeyMaker(node, operationName, operationVariablesTypes, hasRequiredVariables)};\n`;
513
+ }
514
+ if (this.config.addInfiniteQuery) {
515
+ query += `\n${this.fetcher.generateInfiniteQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables)}\n`;
411
516
  }
412
517
  // The reason we're looking at the private field of the CustomMapperFetcher to see if it's a react hook
413
518
  // is to prevent calling generateFetcherFetch for each query since all the queries won't be able to generate
package/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { oldVisit } from '@graphql-codegen/plugin-helpers';
2
1
  import { concatAST, Kind } from 'graphql';
2
+ import { oldVisit } from '@graphql-codegen/plugin-helpers';
3
3
  import { parseMapper, buildMapperImport, ClientSideBaseVisitor, DocumentMode, getConfigValue } from '@graphql-codegen/visitor-plugin-common';
4
4
  import autoBind from 'auto-bind';
5
5
  import { pascalCase } from 'change-case-all';
@@ -8,6 +8,11 @@ import { extname } from 'path';
8
8
  function generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes) {
9
9
  return `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
10
10
  }
11
+ function generateInfiniteQueryKey(node, hasRequiredVariables) {
12
+ if (hasRequiredVariables)
13
+ return `['${node.name.value}.infinite', variables]`;
14
+ return `variables === undefined ? ['${node.name.value}.infinite'] : ['${node.name.value}.infinite', variables]`;
15
+ }
11
16
  function generateQueryKey(node, hasRequiredVariables) {
12
17
  if (hasRequiredVariables)
13
18
  return `['${node.name.value}', variables]`;
@@ -24,49 +29,72 @@ function generateMutationKeyMaker(node, operationName) {
24
29
  return `\nuse${operationName}.getKey = () => ${generateMutationKey(node)}};\n`;
25
30
  }
26
31
 
27
- class FetchFetcher {
28
- constructor(visitor) {
32
+ class CustomMapperFetcher {
33
+ constructor(visitor, customFetcher) {
29
34
  this.visitor = visitor;
35
+ if (typeof customFetcher === 'string') {
36
+ customFetcher = { func: customFetcher };
37
+ }
38
+ this._mapper = parseMapper(customFetcher.func);
39
+ this._isReactHook = customFetcher.isReactHook;
40
+ }
41
+ getFetcherFnName(operationResultType, operationVariablesTypes) {
42
+ return `${this._mapper.type}<${operationResultType}, ${operationVariablesTypes}>`;
30
43
  }
31
44
  generateFetcherImplementaion() {
32
- return `
33
- function fetcher<TData, TVariables>(endpoint: string, requestInit: RequestInit, query: string, variables?: TVariables) {
34
- return async (): Promise<TData> => {
35
- const res = await fetch(endpoint, {
36
- method: 'POST',
37
- ...requestInit,
38
- body: JSON.stringify({ query, variables }),
39
- });
40
-
41
- const json = await res.json();
42
-
43
- if (json.errors) {
44
- const { message } = json.errors[0];
45
-
46
- throw new Error(message);
45
+ if (this._mapper.isExternal) {
46
+ return buildMapperImport(this._mapper.source, [
47
+ {
48
+ identifier: this._mapper.type,
49
+ asDefault: this._mapper.default,
50
+ },
51
+ ], this.visitor.config.useTypeImports);
52
+ }
53
+ return null;
47
54
  }
48
-
49
- return json.data;
50
- }
51
- }`;
55
+ generateInfiniteQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
56
+ const variables = `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
57
+ const hookConfig = this.visitor.queryMethodMap;
58
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.hook);
59
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.options);
60
+ const options = `options?: ${hookConfig.infiniteQuery.options}<${operationResultType}, TError, TData>`;
61
+ const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
62
+ const impl = this._isReactHook
63
+ ? `(metaData) => ${typedFetcher}(${documentVariableName}).bind(null, {...variables, ...(metaData.pageParam ?? {})})()`
64
+ : `(metaData) => ${typedFetcher}(${documentVariableName}, {...variables, ...(metaData.pageParam ?? {})})()`;
65
+ return `export const useInfinite${operationName} = <
66
+ TData = ${operationResultType},
67
+ TError = ${this.visitor.config.errorType}
68
+ >(
69
+ ${variables},
70
+ ${options}
71
+ ) =>
72
+ ${hookConfig.infiniteQuery.hook}<${operationResultType}, TError, TData>(
73
+ ${generateInfiniteQueryKey(node, hasRequiredVariables)},
74
+ ${impl},
75
+ options
76
+ );`;
52
77
  }
53
78
  generateQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
54
- const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
79
+ const variables = `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
55
80
  const hookConfig = this.visitor.queryMethodMap;
56
81
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.query.hook);
57
82
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.query.options);
58
83
  const options = `options?: ${hookConfig.query.options}<${operationResultType}, TError, TData>`;
84
+ const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
85
+ const impl = this._isReactHook
86
+ ? `${typedFetcher}(${documentVariableName}).bind(null, variables)`
87
+ : `${typedFetcher}(${documentVariableName}, variables)`;
59
88
  return `export const use${operationName} = <
60
89
  TData = ${operationResultType},
61
90
  TError = ${this.visitor.config.errorType}
62
91
  >(
63
- dataSource: { endpoint: string, fetchParams?: RequestInit },
64
92
  ${variables},
65
93
  ${options}
66
94
  ) =>
67
95
  ${hookConfig.query.hook}<${operationResultType}, TError, TData>(
68
96
  ${generateQueryKey(node, hasRequiredVariables)},
69
- fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, variables),
97
+ ${impl},
70
98
  options
71
99
  );`;
72
100
  }
@@ -76,52 +104,43 @@ function fetcher<TData, TVariables>(endpoint: string, requestInit: RequestInit,
76
104
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.mutation.hook);
77
105
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.mutation.options);
78
106
  const options = `options?: ${hookConfig.mutation.options}<${operationResultType}, TError, ${operationVariablesTypes}, TContext>`;
107
+ const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
108
+ const impl = this._isReactHook
109
+ ? `${typedFetcher}(${documentVariableName})`
110
+ : `(${variables}) => ${typedFetcher}(${documentVariableName}, variables)()`;
79
111
  return `export const use${operationName} = <
80
112
  TError = ${this.visitor.config.errorType},
81
113
  TContext = unknown
82
- >(
83
- dataSource: { endpoint: string, fetchParams?: RequestInit },
84
- ${options}
85
- ) =>
114
+ >(${options}) =>
86
115
  ${hookConfig.mutation.hook}<${operationResultType}, TError, ${operationVariablesTypes}, TContext>(
87
116
  ${generateMutationKey(node)},
88
- (${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, variables)(),
117
+ ${impl},
89
118
  options
90
119
  );`;
91
120
  }
92
121
  generateFetcherFetch(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
93
- const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
94
- return `\nuse${operationName}.fetcher = (dataSource: { endpoint: string, fetchParams?: RequestInit }, ${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, variables);`;
122
+ // We can't generate a fetcher field since we can't call react hooks outside of a React Fucntion Component
123
+ // Related: https://reactjs.org/docs/hooks-rules.html
124
+ if (this._isReactHook)
125
+ return '';
126
+ const variables = `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
127
+ const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
128
+ const impl = `${typedFetcher}(${documentVariableName}, variables)`;
129
+ return `\nuse${operationName}.fetcher = (${variables}) => ${impl};`;
95
130
  }
96
131
  }
97
132
 
98
- class HardcodedFetchFetcher {
99
- constructor(visitor, config) {
133
+ class FetchFetcher {
134
+ constructor(visitor) {
100
135
  this.visitor = visitor;
101
- this.config = config;
102
- }
103
- getEndpoint() {
104
- try {
105
- new URL(this.config.endpoint);
106
- return JSON.stringify(this.config.endpoint);
107
- }
108
- catch (e) {
109
- return `${this.config.endpoint} as string`;
110
- }
111
- }
112
- getFetchParams() {
113
- let fetchParamsPartial = '';
114
- if (this.config.fetchParams) {
115
- fetchParamsPartial = `\n ...(${this.config.fetchParams}),`;
116
- }
117
- return ` method: "POST",${fetchParamsPartial}`;
118
136
  }
119
137
  generateFetcherImplementaion() {
120
138
  return `
121
- function fetcher<TData, TVariables>(query: string, variables?: TVariables) {
139
+ function fetcher<TData, TVariables>(endpoint: string, requestInit: RequestInit, query: string, variables?: TVariables) {
122
140
  return async (): Promise<TData> => {
123
- const res = await fetch(${this.getEndpoint()}, {
124
- ${this.getFetchParams()}
141
+ const res = await fetch(endpoint, {
142
+ method: 'POST',
143
+ ...requestInit,
125
144
  body: JSON.stringify({ query, variables }),
126
145
  });
127
146
 
@@ -136,6 +155,27 @@ ${this.getFetchParams()}
136
155
  return json.data;
137
156
  }
138
157
  }`;
158
+ }
159
+ generateInfiniteQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
160
+ const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
161
+ const hookConfig = this.visitor.queryMethodMap;
162
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.hook);
163
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.options);
164
+ const options = `options?: ${hookConfig.query.options}<${operationResultType}, TError, TData>`;
165
+ return `export const useInfinite${operationName} = <
166
+ TData = ${operationResultType},
167
+ TError = ${this.visitor.config.errorType}
168
+ >(
169
+ dataSource: { endpoint: string, fetchParams?: RequestInit },
170
+ pageParamKey: keyof ${operationVariablesTypes},
171
+ ${variables},
172
+ ${options}
173
+ ) =>
174
+ ${hookConfig.infiniteQuery.hook}<${operationResultType}, TError, TData>(
175
+ ${generateInfiniteQueryKey(node, hasRequiredVariables)},
176
+ (metaData) => fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, {...variables, ...(metaData.pageParam ?? {})})(),
177
+ options
178
+ );`;
139
179
  }
140
180
  generateQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
141
181
  const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
@@ -147,12 +187,13 @@ ${this.getFetchParams()}
147
187
  TData = ${operationResultType},
148
188
  TError = ${this.visitor.config.errorType}
149
189
  >(
190
+ dataSource: { endpoint: string, fetchParams?: RequestInit },
150
191
  ${variables},
151
192
  ${options}
152
193
  ) =>
153
194
  ${hookConfig.query.hook}<${operationResultType}, TError, TData>(
154
195
  ${generateQueryKey(node, hasRequiredVariables)},
155
- fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, variables),
196
+ fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, variables),
156
197
  options
157
198
  );`;
158
199
  }
@@ -165,16 +206,19 @@ ${this.getFetchParams()}
165
206
  return `export const use${operationName} = <
166
207
  TError = ${this.visitor.config.errorType},
167
208
  TContext = unknown
168
- >(${options}) =>
209
+ >(
210
+ dataSource: { endpoint: string, fetchParams?: RequestInit },
211
+ ${options}
212
+ ) =>
169
213
  ${hookConfig.mutation.hook}<${operationResultType}, TError, ${operationVariablesTypes}, TContext>(
170
214
  ${generateMutationKey(node)},
171
- (${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, variables)(),
215
+ (${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, variables)(),
172
216
  options
173
217
  );`;
174
218
  }
175
219
  generateFetcherFetch(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
176
220
  const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
177
- return `\nuse${operationName}.fetcher = (${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, variables);`;
221
+ return `\nuse${operationName}.fetcher = (dataSource: { endpoint: string, fetchParams?: RequestInit }, ${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(dataSource.endpoint, dataSource.fetchParams || {}, ${documentVariableName}, variables);`;
178
222
  }
179
223
  }
180
224
 
@@ -187,6 +231,31 @@ class GraphQLRequestClientFetcher {
187
231
  function fetcher<TData, TVariables>(client: GraphQLClient, query: string, variables?: TVariables, headers?: RequestInit['headers']) {
188
232
  return async (): Promise<TData> => client.request<TData, TVariables>(query, variables, headers);
189
233
  }`;
234
+ }
235
+ generateInfiniteQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
236
+ const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
237
+ const typeImport = this.visitor.config.useTypeImports ? 'import type' : 'import';
238
+ this.visitor.imports.add(`${typeImport} { GraphQLClient } from 'graphql-request';`);
239
+ this.visitor.imports.add(`${typeImport} { RequestInit } from 'graphql-request/dist/types.dom';`);
240
+ const hookConfig = this.visitor.queryMethodMap;
241
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.hook);
242
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.options);
243
+ const options = `options?: ${hookConfig.infiniteQuery.options}<${operationResultType}, TError, TData>`;
244
+ return `export const useInfinite${operationName} = <
245
+ TData = ${operationResultType},
246
+ TError = ${this.visitor.config.errorType}
247
+ >(
248
+ pageParamKey: keyof ${operationVariablesTypes},
249
+ client: GraphQLClient,
250
+ ${variables},
251
+ ${options},
252
+ headers?: RequestInit['headers']
253
+ ) =>
254
+ ${hookConfig.infiniteQuery.hook}<${operationResultType}, TError, TData>(
255
+ ${generateInfiniteQueryKey(node, hasRequiredVariables)},
256
+ (metaData) => fetcher<${operationResultType}, ${operationVariablesTypes}>(client, ${documentVariableName}, {...variables, ...(metaData.pageParam ?? {})}, headers)(),
257
+ options
258
+ );`;
190
259
  }
191
260
  generateQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
192
261
  const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
@@ -239,39 +308,74 @@ function fetcher<TData, TVariables>(client: GraphQLClient, query: string, variab
239
308
  }
240
309
  }
241
310
 
242
- class CustomMapperFetcher {
243
- constructor(visitor, customFetcher) {
311
+ class HardcodedFetchFetcher {
312
+ constructor(visitor, config) {
244
313
  this.visitor = visitor;
245
- if (typeof customFetcher === 'string') {
246
- customFetcher = { func: customFetcher };
314
+ this.config = config;
315
+ }
316
+ getEndpoint() {
317
+ try {
318
+ new URL(this.config.endpoint);
319
+ return JSON.stringify(this.config.endpoint);
320
+ }
321
+ catch (e) {
322
+ return `${this.config.endpoint} as string`;
247
323
  }
248
- this._mapper = parseMapper(customFetcher.func);
249
- this._isReactHook = customFetcher.isReactHook;
250
324
  }
251
- getFetcherFnName(operationResultType, operationVariablesTypes) {
252
- return `${this._mapper.type}<${operationResultType}, ${operationVariablesTypes}>`;
325
+ getFetchParams() {
326
+ let fetchParamsPartial = '';
327
+ if (this.config.fetchParams) {
328
+ fetchParamsPartial = `\n ...(${this.config.fetchParams}),`;
329
+ }
330
+ return ` method: "POST",${fetchParamsPartial}`;
253
331
  }
254
332
  generateFetcherImplementaion() {
255
- if (this._mapper.isExternal) {
256
- return buildMapperImport(this._mapper.source, [
257
- {
258
- identifier: this._mapper.type,
259
- asDefault: this._mapper.default,
260
- },
261
- ], this.visitor.config.useTypeImports);
262
- }
263
- return null;
333
+ return `
334
+ function fetcher<TData, TVariables>(query: string, variables?: TVariables) {
335
+ return async (): Promise<TData> => {
336
+ const res = await fetch(${this.getEndpoint()}, {
337
+ ${this.getFetchParams()}
338
+ body: JSON.stringify({ query, variables }),
339
+ });
340
+
341
+ const json = await res.json();
342
+
343
+ if (json.errors) {
344
+ const { message } = json.errors[0];
345
+
346
+ throw new Error(message);
347
+ }
348
+
349
+ return json.data;
350
+ }
351
+ }`;
352
+ }
353
+ generateInfiniteQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
354
+ const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
355
+ const hookConfig = this.visitor.queryMethodMap;
356
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.hook);
357
+ this.visitor.reactQueryIdentifiersInUse.add(hookConfig.infiniteQuery.options);
358
+ const options = `options?: ${hookConfig.infiniteQuery.options}<${operationResultType}, TError, TData>`;
359
+ return `export const useInfinite${operationName} = <
360
+ TData = ${operationResultType},
361
+ TError = ${this.visitor.config.errorType}
362
+ >(
363
+ pageParamKey: keyof ${operationVariablesTypes},
364
+ ${variables},
365
+ ${options}
366
+ ) =>
367
+ ${hookConfig.infiniteQuery.hook}<${operationResultType}, TError, TData>(
368
+ ${generateInfiniteQueryKey(node, hasRequiredVariables)},
369
+ (metaData) => fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, {...variables, ...(metaData.pageParam ?? {})})(),
370
+ options
371
+ );`;
264
372
  }
265
373
  generateQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
266
- const variables = `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
374
+ const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
267
375
  const hookConfig = this.visitor.queryMethodMap;
268
376
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.query.hook);
269
377
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.query.options);
270
378
  const options = `options?: ${hookConfig.query.options}<${operationResultType}, TError, TData>`;
271
- const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
272
- const impl = this._isReactHook
273
- ? `${typedFetcher}(${documentVariableName}).bind(null, variables)`
274
- : `${typedFetcher}(${documentVariableName}, variables)`;
275
379
  return `export const use${operationName} = <
276
380
  TData = ${operationResultType},
277
381
  TError = ${this.visitor.config.errorType}
@@ -281,7 +385,7 @@ class CustomMapperFetcher {
281
385
  ) =>
282
386
  ${hookConfig.query.hook}<${operationResultType}, TError, TData>(
283
387
  ${generateQueryKey(node, hasRequiredVariables)},
284
- ${impl},
388
+ fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, variables),
285
389
  options
286
390
  );`;
287
391
  }
@@ -291,29 +395,19 @@ class CustomMapperFetcher {
291
395
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.mutation.hook);
292
396
  this.visitor.reactQueryIdentifiersInUse.add(hookConfig.mutation.options);
293
397
  const options = `options?: ${hookConfig.mutation.options}<${operationResultType}, TError, ${operationVariablesTypes}, TContext>`;
294
- const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
295
- const impl = this._isReactHook
296
- ? `${typedFetcher}(${documentVariableName})`
297
- : `(${variables}) => ${typedFetcher}(${documentVariableName}, variables)()`;
298
398
  return `export const use${operationName} = <
299
399
  TError = ${this.visitor.config.errorType},
300
400
  TContext = unknown
301
401
  >(${options}) =>
302
402
  ${hookConfig.mutation.hook}<${operationResultType}, TError, ${operationVariablesTypes}, TContext>(
303
403
  ${generateMutationKey(node)},
304
- ${impl},
404
+ (${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, variables)(),
305
405
  options
306
406
  );`;
307
407
  }
308
408
  generateFetcherFetch(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables) {
309
- // We can't generate a fetcher field since we can't call react hooks outside of a React Fucntion Component
310
- // Related: https://reactjs.org/docs/hooks-rules.html
311
- if (this._isReactHook)
312
- return '';
313
- const variables = `variables${hasRequiredVariables ? '' : '?'}: ${operationVariablesTypes}`;
314
- const typedFetcher = this.getFetcherFnName(operationResultType, operationVariablesTypes);
315
- const impl = `${typedFetcher}(${documentVariableName}, variables)`;
316
- return `\nuse${operationName}.fetcher = (${variables}) => ${impl};`;
409
+ const variables = generateQueryVariablesSignature(hasRequiredVariables, operationVariablesTypes);
410
+ return `\nuse${operationName}.fetcher = (${variables}) => fetcher<${operationResultType}, ${operationVariablesTypes}>(${documentVariableName}, variables);`;
317
411
  }
318
412
  }
319
413
 
@@ -326,10 +420,15 @@ class ReactQueryVisitor extends ClientSideBaseVisitor {
326
420
  exposeQueryKeys: getConfigValue(rawConfig.exposeQueryKeys, false),
327
421
  exposeMutationKeys: getConfigValue(rawConfig.exposeMutationKeys, false),
328
422
  exposeFetcher: getConfigValue(rawConfig.exposeFetcher, false),
423
+ addInfiniteQuery: getConfigValue(rawConfig.addInfiniteQuery, false),
329
424
  });
330
425
  this.rawConfig = rawConfig;
331
426
  this.reactQueryIdentifiersInUse = new Set();
332
427
  this.queryMethodMap = {
428
+ infiniteQuery: {
429
+ hook: 'useInfiniteQuery',
430
+ options: 'UseInfiniteQueryOptions',
431
+ },
333
432
  query: {
334
433
  hook: 'useQuery',
335
434
  options: 'UseQueryOptions',
@@ -367,6 +466,9 @@ class ReactQueryVisitor extends ClientSideBaseVisitor {
367
466
  if (!this.hasOperations) {
368
467
  return baseImports;
369
468
  }
469
+ if (this.config.addInfiniteQuery) {
470
+ this.reactQueryIdentifiersInUse.add('QueryFunctionContext');
471
+ }
370
472
  return [...baseImports, `import { ${Array.from(this.reactQueryIdentifiersInUse).join(', ')} } from 'react-query';`];
371
473
  }
372
474
  getFetcherImplementation() {
@@ -401,7 +503,10 @@ class ReactQueryVisitor extends ClientSideBaseVisitor {
401
503
  query += `\nuse${operationName}.document = ${documentVariableName};\n`;
402
504
  }
403
505
  if (this.config.exposeQueryKeys) {
404
- query += generateQueryKeyMaker(node, operationName, operationVariablesTypes, hasRequiredVariables);
506
+ query += `\n${generateQueryKeyMaker(node, operationName, operationVariablesTypes, hasRequiredVariables)};\n`;
507
+ }
508
+ if (this.config.addInfiniteQuery) {
509
+ query += `\n${this.fetcher.generateInfiniteQueryHook(node, documentVariableName, operationName, operationResultType, operationVariablesTypes, hasRequiredVariables)}\n`;
405
510
  }
406
511
  // The reason we're looking at the private field of the CustomMapperFetcher to see if it's a react hook
407
512
  // is to prevent calling generateFetcherFetch for each query since all the queries won't be able to generate
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphql-codegen/typescript-react-query",
3
- "version": "3.1.2-alpha-2113b7d34.0",
3
+ "version": "3.2.1",
4
4
  "description": "GraphQL Code Generator plugin for generating a ready-to-use React-Query Hooks based on GraphQL operations",
5
5
  "peerDependencies": {
6
6
  "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0",
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "dependencies": {
10
10
  "@graphql-codegen/plugin-helpers": "^2.3.0",
11
- "@graphql-codegen/visitor-plugin-common": "2.5.1-alpha-2113b7d34.0",
11
+ "@graphql-codegen/visitor-plugin-common": "2.5.1",
12
12
  "auto-bind": "~4.0.0",
13
13
  "change-case-all": "1.0.14",
14
14
  "tslib": "~2.3.0"
@@ -1,5 +1,6 @@
1
1
  import { OperationDefinitionNode } from 'graphql';
2
2
  export declare function generateQueryVariablesSignature(hasRequiredVariables: boolean, operationVariablesTypes: string): string;
3
+ export declare function generateInfiniteQueryKey(node: OperationDefinitionNode, hasRequiredVariables: boolean): string;
3
4
  export declare function generateQueryKey(node: OperationDefinitionNode, hasRequiredVariables: boolean): string;
4
5
  export declare function generateQueryKeyMaker(node: OperationDefinitionNode, operationName: string, operationVariablesTypes: string, hasRequiredVariables: boolean): string;
5
6
  export declare function generateMutationKey(node: OperationDefinitionNode): string;
package/visitor.d.ts CHANGED
@@ -1,16 +1,21 @@
1
- import { ClientSideBaseVisitor, ClientSideBasePluginConfig, LoadedFragment } from '@graphql-codegen/visitor-plugin-common';
1
+ import { ClientSideBasePluginConfig, ClientSideBaseVisitor, LoadedFragment } from '@graphql-codegen/visitor-plugin-common';
2
+ import { GraphQLSchema, OperationDefinitionNode } from 'graphql';
3
+ import { FetcherRenderer } from './fetcher';
2
4
  import { ReactQueryRawPluginConfig } from './config';
3
- import { OperationDefinitionNode, GraphQLSchema } from 'graphql';
4
5
  import { Types } from '@graphql-codegen/plugin-helpers';
5
- import { FetcherRenderer } from './fetcher';
6
6
  export interface ReactQueryPluginConfig extends ClientSideBasePluginConfig {
7
7
  errorType: string;
8
8
  exposeDocument: boolean;
9
9
  exposeQueryKeys: boolean;
10
10
  exposeMutationKeys: boolean;
11
11
  exposeFetcher: boolean;
12
+ addInfiniteQuery: boolean;
12
13
  }
13
14
  export interface ReactQueryMethodMap {
15
+ infiniteQuery: {
16
+ hook: string;
17
+ options: string;
18
+ };
14
19
  query: {
15
20
  hook: string;
16
21
  options: string;