@toktokhan-dev/cli-plugin-gen-api-react-query 0.0.19 → 0.1.0
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/dist/index.d.ts +3 -4
- package/dist/index.js +28 -12
- package/package.json +1 -1
- package/templates/custom-axios/api.eta +77 -60
- package/templates/custom-fetch/api.eta +48 -22
- package/templates/custom-fetch/http-client.eta +4 -3
- package/templates/my/react-query-hook.eta +91 -89
- package/templates/my/react-query-key.eta +1 -1
- package/templates/my/react-query-suspense-hook.eta +175 -0
- package/templates/my/react-query-type.eta +30 -0
package/dist/index.d.ts
CHANGED
|
@@ -38,11 +38,10 @@ interface GenerateSwaggerApiConfig {
|
|
|
38
38
|
swaggerSchemaUrl: string;
|
|
39
39
|
/** 생성될 파일들이 위치할 경로입니다. */
|
|
40
40
|
output: string;
|
|
41
|
-
/** 생성되는 코드의
|
|
42
|
-
* 해당 옵션이 false 일경우 infiniteQuery 를 포함한 모든 Query 가 생성되지 않습니다. */
|
|
41
|
+
/** 생성되는 코드의 useQuery, useInfiniteQuery 포함 여부 입니다. */
|
|
43
42
|
includeReactQuery: boolean;
|
|
44
|
-
/** 생성되는 코드의
|
|
45
|
-
|
|
43
|
+
/** 생성되는 코드의 useSuspenseQuery, useSuspenseInfiniteQuery 포함 여부 입니다. */
|
|
44
|
+
includeReactSuspenseQuery: boolean;
|
|
46
45
|
/** Api 의 axios 혹은 fetch 요청 instance 주소입니다. */
|
|
47
46
|
instancePath: string;
|
|
48
47
|
/** http client 타입입니다. */
|
package/dist/index.js
CHANGED
|
@@ -23,11 +23,12 @@ const GENERATE_SWAGGER_DATA = {
|
|
|
23
23
|
TYPE_FILE: ['react-query-type.ts', 'data-contracts.ts', 'util-types.ts'],
|
|
24
24
|
UTIL_FILE: ['param-serializer-by.ts'],
|
|
25
25
|
QUERY_HOOK_INDICATOR: '@indicator-for-query-hook',
|
|
26
|
+
USE_SUSPENSE_QUERY_HOOK_INDICATOR: '@indicator-for-use-suspense-query-hook',
|
|
26
27
|
AXIOS_DEFAULT_INSTANCE_PATH: '@/configs/axios/instance',
|
|
27
28
|
FETCH_DEFAULT_INSTANCE_PATH: '@/configs/fetch/fetch-extend',
|
|
28
29
|
};
|
|
29
30
|
|
|
30
|
-
const { EXTRA_TEMPLATE_FOLTER, CUSTOM_AXIOS_TEMPLATE_FOLDER, CUSTOM_FETCH_TEMPLATE_FOLDER, QUERY_HOOK_INDICATOR: QUERY_HOOK_INDICATOR$1, } = GENERATE_SWAGGER_DATA;
|
|
31
|
+
const { EXTRA_TEMPLATE_FOLTER, CUSTOM_AXIOS_TEMPLATE_FOLDER, CUSTOM_FETCH_TEMPLATE_FOLDER, QUERY_HOOK_INDICATOR: QUERY_HOOK_INDICATOR$1, USE_SUSPENSE_QUERY_HOOK_INDICATOR: USE_SUSPENSE_QUERY_HOOK_INDICATOR$1, } = GENERATE_SWAGGER_DATA;
|
|
31
32
|
const parseSwagger = (config) => generateApi({
|
|
32
33
|
templates: config.httpClientType === 'axios' ?
|
|
33
34
|
CUSTOM_AXIOS_TEMPLATE_FOLDER
|
|
@@ -62,15 +63,19 @@ const parseSwagger = (config) => generateApi({
|
|
|
62
63
|
onPrepareConfig: (defaultConfig) => {
|
|
63
64
|
return {
|
|
64
65
|
...defaultConfig,
|
|
65
|
-
myConfig: {
|
|
66
|
+
myConfig: {
|
|
67
|
+
QUERY_HOOK_INDICATOR: QUERY_HOOK_INDICATOR$1,
|
|
68
|
+
USE_SUSPENSE_QUERY_HOOK_INDICATOR: USE_SUSPENSE_QUERY_HOOK_INDICATOR$1,
|
|
69
|
+
...config,
|
|
70
|
+
},
|
|
66
71
|
};
|
|
67
72
|
},
|
|
68
73
|
},
|
|
69
74
|
});
|
|
70
75
|
|
|
71
|
-
const { TYPE_FILE, UTIL_FILE, QUERY_HOOK_INDICATOR } = GENERATE_SWAGGER_DATA;
|
|
76
|
+
const { TYPE_FILE, UTIL_FILE, QUERY_HOOK_INDICATOR, USE_SUSPENSE_QUERY_HOOK_INDICATOR, } = GENERATE_SWAGGER_DATA;
|
|
72
77
|
const writeSwaggerApiFile = (params) => {
|
|
73
|
-
const { input, output, spinner } = params;
|
|
78
|
+
const { input, output, spinner, config } = params;
|
|
74
79
|
input.files.forEach(async ({ fileName, fileContent: content, fileExtension }) => {
|
|
75
80
|
const name = fileName + fileExtension;
|
|
76
81
|
try {
|
|
@@ -97,9 +102,14 @@ const writeSwaggerApiFile = (params) => {
|
|
|
97
102
|
return;
|
|
98
103
|
}
|
|
99
104
|
if (isApiFile) {
|
|
100
|
-
const { apiContents,
|
|
101
|
-
|
|
102
|
-
|
|
105
|
+
const { apiContents, hookParts } = splitHookContents(filename, content);
|
|
106
|
+
generatePretty(path.resolve(targetFolder, `${filename}.api.ts`), apiContents);
|
|
107
|
+
if (config.includeReactQuery) {
|
|
108
|
+
generatePretty(path.resolve(targetFolder, `${filename}.query.ts`), hookParts[0]);
|
|
109
|
+
}
|
|
110
|
+
if (config.includeReactSuspenseQuery) {
|
|
111
|
+
generatePretty(path.resolve(targetFolder, `${filename}.suspenseQuery.ts`), hookParts[1]);
|
|
112
|
+
}
|
|
103
113
|
return;
|
|
104
114
|
}
|
|
105
115
|
generate(path.resolve(targetFolder, name), content);
|
|
@@ -109,7 +119,7 @@ const writeSwaggerApiFile = (params) => {
|
|
|
109
119
|
}
|
|
110
120
|
});
|
|
111
121
|
};
|
|
112
|
-
async function
|
|
122
|
+
async function generatePretty(path, contents) {
|
|
113
123
|
const organized = await prettierString(contents, {
|
|
114
124
|
parser: 'babel-ts',
|
|
115
125
|
plugins: ['prettier-plugin-organize-imports'],
|
|
@@ -123,8 +133,9 @@ async function genreatePretty(path, contents) {
|
|
|
123
133
|
function generate(path, contents) {
|
|
124
134
|
fs.writeFileSync(path, contents);
|
|
125
135
|
}
|
|
126
|
-
function
|
|
136
|
+
function splitHookContents(filename, content) {
|
|
127
137
|
const [_apiContent, _hookContent] = content.split(QUERY_HOOK_INDICATOR);
|
|
138
|
+
const _hookParts = _hookContent.split(USE_SUSPENSE_QUERY_HOOK_INDICATOR);
|
|
128
139
|
const lastImport = getLastImportLine(content);
|
|
129
140
|
const lines = content.split('\n');
|
|
130
141
|
const importArea = [
|
|
@@ -133,7 +144,7 @@ function spilitHookContents(filename, content) {
|
|
|
133
144
|
].join('\n');
|
|
134
145
|
return {
|
|
135
146
|
apiContents: _apiContent,
|
|
136
|
-
|
|
147
|
+
hookParts: _hookParts.map((d) => importArea + d),
|
|
137
148
|
};
|
|
138
149
|
}
|
|
139
150
|
function getLastImportLine(content) {
|
|
@@ -155,7 +166,7 @@ const genApi = defineCommand({
|
|
|
155
166
|
swaggerSchemaUrl: '',
|
|
156
167
|
output: 'src/generated/apis',
|
|
157
168
|
includeReactQuery: true,
|
|
158
|
-
|
|
169
|
+
includeReactSuspenseQuery: false,
|
|
159
170
|
httpClientType: 'axios',
|
|
160
171
|
instancePath: GENERATE_SWAGGER_DATA.AXIOS_DEFAULT_INSTANCE_PATH,
|
|
161
172
|
paginationSets: [
|
|
@@ -191,7 +202,12 @@ const genApi = defineCommand({
|
|
|
191
202
|
}
|
|
192
203
|
withLoading('Write Swagger API', //
|
|
193
204
|
covered.output, (spinner) => {
|
|
194
|
-
writeSwaggerApiFile({
|
|
205
|
+
writeSwaggerApiFile({
|
|
206
|
+
input: parsed,
|
|
207
|
+
output: covered.output,
|
|
208
|
+
spinner,
|
|
209
|
+
config,
|
|
210
|
+
});
|
|
195
211
|
});
|
|
196
212
|
},
|
|
197
213
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toktokhan-dev/cli-plugin-gen-api-react-query",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "A CLI plugin for generating API hooks with React Query built by TOKTOKHAN.DEV",
|
|
5
5
|
"author": "TOKTOKHAN.DEV <fe-system@toktokhan.dev>",
|
|
6
6
|
"license": "ISC",
|
|
@@ -6,36 +6,36 @@ const { RESERVED_REQ_PARAMS_ARG_NAMES } = config.constants;
|
|
|
6
6
|
const routes = route.routes;
|
|
7
7
|
const dataContracts = _.map(modelTypes, "name");
|
|
8
8
|
|
|
9
|
-
|
|
10
9
|
const projectRootPath = process.env.PWD;
|
|
11
|
-
const myTemeplatePath = `../my
|
|
12
|
-
const reactQueryTemplatePath = `${myTemeplatePath}/react-query-hook.eta
|
|
13
|
-
const
|
|
10
|
+
const myTemeplatePath = `../my`;
|
|
11
|
+
const reactQueryTemplatePath = `${myTemeplatePath}/react-query-hook.eta`;
|
|
12
|
+
const reactSuspenseQueryTemplatePath = `${myTemeplatePath}/react-query-suspense-hook.eta`;
|
|
13
|
+
const reactQuerKeyTemplatePath = `${myTemeplatePath}/react-query-key.eta`;
|
|
14
14
|
|
|
15
15
|
const apiClassName = classNameCase(route.moduleName) + 'Api';
|
|
16
|
-
const paginationSets = myConfig?.paginationSets
|
|
17
|
-
const instancePath = myConfig?.instancePath
|
|
18
|
-
|
|
19
|
-
const apiInstanceName =route.moduleName + "Api";
|
|
20
|
-
const queryKeyName = "QUERY_KEY_" + _.upperCase(apiClassName).replace(/ /g, '_');
|
|
16
|
+
const paginationSets = myConfig?.paginationSets;
|
|
17
|
+
const instancePath = myConfig?.instancePath;
|
|
21
18
|
|
|
19
|
+
const includeReactQuery = myConfig?.includeReactQuery;
|
|
20
|
+
const includeReactSuspenseQuery = myConfig?.includeReactSuspenseQuery;
|
|
22
21
|
|
|
22
|
+
const apiInstanceName = route.moduleName + "Api";
|
|
23
|
+
const queryKeyName = "QUERY_KEY_" + _.upperCase(apiClassName).replace(/ /g, '_');
|
|
23
24
|
|
|
24
25
|
const hasPaginationKeyword = (queryString, keywords = paginationKeywords ) => {
|
|
25
|
-
if(!
|
|
26
|
+
if(!includeReactQuery && !includeReactSuspenseQuery ) return false;
|
|
26
27
|
const keywordUnion = keywords.map(str => `.*${str}.*`).join("|");
|
|
27
28
|
const rgxSting = keywords.map(str => `(${keywordUnion})`).join("");
|
|
28
29
|
const rgx = new RegExp(rgxSting);
|
|
29
30
|
return rgx.test(queryString);
|
|
30
|
-
}
|
|
31
|
-
|
|
31
|
+
};
|
|
32
32
|
|
|
33
33
|
const upperSnakeCase = (str) => _.upperCase(str).replace(/ /g, '_');
|
|
34
34
|
|
|
35
|
-
const removeModuleName = (str) =>
|
|
35
|
+
const removeModuleName = (str) => str.replace(route.moduleName,'');
|
|
36
36
|
|
|
37
37
|
const getConfigByRoute = (route) => {
|
|
38
|
-
const { specificArgNameResolver } = route
|
|
38
|
+
const { specificArgNameResolver } = route;
|
|
39
39
|
const { parameters, path, method, payload, query, formData, security, requestParams } = route.request;
|
|
40
40
|
const pathParams = _.values(parameters);
|
|
41
41
|
const pathParamsNames = _.map(pathParams, "name");
|
|
@@ -45,7 +45,7 @@ const getConfigByRoute = (route) => {
|
|
|
45
45
|
name: specificArgNameResolver.resolve(RESERVED_REQ_PARAMS_ARG_NAMES),
|
|
46
46
|
optional: true,
|
|
47
47
|
type: "RequestParams",
|
|
48
|
-
}
|
|
48
|
+
};
|
|
49
49
|
|
|
50
50
|
const argToTmpl = ({ name, optional, type, defaultValue }) => `${name}${!defaultValue && optional ? '?' : ''}: ${type}`;
|
|
51
51
|
|
|
@@ -71,30 +71,29 @@ const getConfigByRoute = (route) => {
|
|
|
71
71
|
// Sort by optionality
|
|
72
72
|
.sortBy(rawWrapperArgs, [o => o.optional])
|
|
73
73
|
.map(argToTmpl)
|
|
74
|
-
.join('; ')
|
|
75
|
-
|
|
74
|
+
.join('; ');
|
|
76
75
|
|
|
77
76
|
const functionName = route.routeName.usage;
|
|
78
|
-
const hookVariant = _.upperCase(method) === "GET" ? "Query" : "Mutation"
|
|
77
|
+
const hookVariant = _.upperCase(method) === "GET" ? "Query" : "Mutation";
|
|
79
78
|
const key = upperSnakeCase(functionName);
|
|
80
79
|
const methodKey = upperSnakeCase(removeModuleName(functionName));
|
|
81
|
-
const pagination = paginationSets.find(d => !!query?.type &&
|
|
80
|
+
const pagination = paginationSets.find(d => !!query?.type && hasPaginationKeyword(query?.type.split("\n").join(""), d.keywords));
|
|
82
81
|
|
|
83
82
|
const isQuery = hookVariant === "Query";
|
|
84
83
|
const isMutation = hookVariant === "Mutation";
|
|
85
84
|
const hasPagination = !!pagination;
|
|
86
85
|
|
|
87
|
-
const isOptionalVariables
|
|
88
|
-
// Find optional value
|
|
86
|
+
const isOptionalVariables = _
|
|
89
87
|
.filter(rawWrapperArgs, o => o.optional).length === rawWrapperArgs.length;
|
|
90
88
|
|
|
91
|
-
const conditionalVriablesText = isOptionalVariables? "variables?" : "variables";
|
|
89
|
+
const conditionalVriablesText = isOptionalVariables ? "variables?" : "variables";
|
|
92
90
|
const repalceTarget = "${" + conditionalVriablesText + ".";
|
|
93
91
|
|
|
94
|
-
|
|
95
92
|
return {
|
|
96
|
-
conditions:{
|
|
93
|
+
conditions: {
|
|
97
94
|
hasPagination,
|
|
95
|
+
includeReactQuery,
|
|
96
|
+
includeReactSuspenseQuery,
|
|
98
97
|
isQuery,
|
|
99
98
|
isMutation,
|
|
100
99
|
isOptionalVariables,
|
|
@@ -116,31 +115,32 @@ const getConfigByRoute = (route) => {
|
|
|
116
115
|
removeModuleName,
|
|
117
116
|
argToTmpl,
|
|
118
117
|
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
118
|
+
};
|
|
119
|
+
};
|
|
121
120
|
|
|
122
121
|
const dataForReactHookTemplate = {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
122
|
+
getConfigByRoute,
|
|
123
|
+
queryKeyName,
|
|
124
|
+
apiClassName,
|
|
125
|
+
apiInstanceName,
|
|
126
|
+
};
|
|
129
127
|
%>
|
|
130
128
|
|
|
131
|
-
<% if (config.httpClientType === config.constants.HTTP_CLIENT.AXIOS) { %>
|
|
129
|
+
<% if (config.httpClientType === config.constants.HTTP_CLIENT.AXIOS) { %>
|
|
130
|
+
import { AxiosRequestConfig, AxiosResponse } from "axios";
|
|
131
|
+
<% } %>
|
|
132
132
|
|
|
133
133
|
import { AxiosError } from 'axios';
|
|
134
|
-
import { useQuery, useMutation, useInfiniteQuery, InfiniteData } from '@tanstack/react-query';
|
|
135
|
-
import { QueryHookParams, InfiniteQueryHookParams, MutationHookParams, Parameter, RequestFnReturn } from "../@types/react-query-type";
|
|
136
|
-
import { paramsSerializerBy } "../@utils/param-serializer-by"
|
|
134
|
+
import { useQuery, useMutation, useInfiniteQuery, useSuspenseQuery, useSuspenseInfiniteQuery, InfiniteData } from '@tanstack/react-query';
|
|
135
|
+
import { QueryHookParams, InfiniteQueryHookParams, MutationHookParams, Parameter, RequestFnReturn, SuspenseInfiniteQueryHookParams, SuspenseQueryHookParams } from "../@types/react-query-type";
|
|
136
|
+
import { paramsSerializerBy } from "../@utils/param-serializer-by";
|
|
137
137
|
|
|
138
|
-
import instance from "
|
|
139
|
-
import { HttpClient, RequestParams, ContentType, HttpResponse } from "
|
|
138
|
+
import instance from "<%= instancePath %>";
|
|
139
|
+
import { HttpClient, RequestParams, ContentType, HttpResponse } from "../@<%= config.fileNames.httpClient %>";
|
|
140
140
|
import { DeepOmitReadOnly } from '../@types/util-types';
|
|
141
141
|
|
|
142
142
|
<% if (dataContracts.length) { %>
|
|
143
|
-
|
|
143
|
+
import { <%= dataContracts.join(", ") %> } from "../@types/<%= config.fileNames.dataContracts %>";
|
|
144
144
|
<% } %>
|
|
145
145
|
|
|
146
146
|
/**
|
|
@@ -149,8 +149,6 @@ import { DeepOmitReadOnly } from '../@types/util-types';
|
|
|
149
149
|
* 스크립트가 실행될때, 파일을 항상 새로 쓰기 때문에 파일 수정시 작성내용이 제거 될 수 있습니다.
|
|
150
150
|
*/
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
|
|
154
152
|
export class <%= apiClassName %><SecurityDataType = unknown><% if (!config.singleHttpClient) { %> extends HttpClient<SecurityDataType> <% } %> {
|
|
155
153
|
<% if(config.singleHttpClient) { %>
|
|
156
154
|
http: HttpClient<SecurityDataType>;
|
|
@@ -160,33 +158,52 @@ export class <%= apiClassName %><SecurityDataType = unknown><% if (!config.singl
|
|
|
160
158
|
}
|
|
161
159
|
<% } %>
|
|
162
160
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
161
|
+
<% routes.forEach((route) => { %>
|
|
162
|
+
<%~ includeFile('./procedure-call.eta', { ...it, route }) %>
|
|
163
|
+
<% }) %>
|
|
166
164
|
}
|
|
167
165
|
|
|
166
|
+
<% if(myConfig.includeReactQuery || myConfig.includeReactSuspenseQuery) { %>
|
|
167
|
+
//<%= myConfig.QUERY_HOOK_INDICATOR %>
|
|
168
168
|
|
|
169
|
+
<% if(myConfig.includeReactQuery) { %>
|
|
170
|
+
/**
|
|
171
|
+
* !DO NOT EDIT THIS FILE
|
|
172
|
+
*
|
|
173
|
+
* 스크립트가 실행될때, 파일을 항상 새로 쓰기 때문에 파일 수정시 작성내용이 제거 될 수 있습니다.
|
|
174
|
+
*/
|
|
169
175
|
|
|
170
|
-
|
|
171
|
-
|
|
176
|
+
/**
|
|
177
|
+
* tok-cli.config.ts 에서 설정된 instance 경로의 axios instace 가 적용된, api 의 instance 입니다.
|
|
178
|
+
*/
|
|
179
|
+
export const <%= apiInstanceName %> = new <%= apiClassName %>({ instance:instance });
|
|
172
180
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
181
|
+
<%~ includeFile(reactQuerKeyTemplatePath, { ...it, route , dataFromApiTemplate:dataForReactHookTemplate}) %>
|
|
182
|
+
|
|
183
|
+
<% routes.forEach((route) => { %>
|
|
184
|
+
<%~ includeFile(reactQueryTemplatePath, { ...it, route , dataFromApiTemplate:dataForReactHookTemplate}) %>
|
|
185
|
+
<% }) %>
|
|
186
|
+
<% } %>
|
|
178
187
|
|
|
188
|
+
<% if(myConfig.includeReactSuspenseQuery) { %>
|
|
189
|
+
//<%= myConfig.USE_SUSPENSE_QUERY_HOOK_INDICATOR %>
|
|
179
190
|
|
|
180
|
-
/**
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
191
|
+
/**
|
|
192
|
+
* !DO NOT EDIT THIS FILE
|
|
193
|
+
*
|
|
194
|
+
* 스크립트가 실행될때, 파일을 항상 새로 쓰기 때문에 파일 수정시 작성내용이 제거 될 수 있습니다.
|
|
195
|
+
*/
|
|
184
196
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
197
|
+
/**
|
|
198
|
+
* tok-cli.config.ts 에서 설정된 instance 경로의 axios instace 가 적용된, api 의 instance 입니다.
|
|
199
|
+
*/
|
|
200
|
+
export const <%= apiInstanceName %> = new <%= apiClassName %>({ instance:instance });
|
|
201
|
+
|
|
202
|
+
<%~ includeFile(reactQuerKeyTemplatePath, { ...it, route , dataFromApiTemplate:dataForReactHookTemplate}) %>
|
|
203
|
+
|
|
204
|
+
<% routes.forEach((route) => { %>
|
|
205
|
+
<%~ includeFile(reactSuspenseQueryTemplatePath, { ...it, route , dataFromApiTemplate:dataForReactHookTemplate}) %>
|
|
189
206
|
<% }) %>
|
|
207
|
+
<% } %>
|
|
190
208
|
<% } %>
|
|
191
|
-
|
|
192
209
|
|
|
@@ -9,12 +9,16 @@ const dataContracts = _.map(modelTypes, "name");
|
|
|
9
9
|
const projectRootPath = process.env.PWD;
|
|
10
10
|
const myTemeplatePath = `../my`
|
|
11
11
|
const reactQueryTemplatePath = `${myTemeplatePath}/react-query-hook.eta`
|
|
12
|
-
const
|
|
12
|
+
const reactSuspenseQueryTemplatePath = `${myTemeplatePath}/react-query-suspense-hook.eta`;
|
|
13
|
+
const reactQueryKeyTemplatePath = `${myTemeplatePath}/react-query-key.eta`
|
|
13
14
|
|
|
14
15
|
const apiClassName = classNameCase(route.moduleName) + 'Api';
|
|
15
16
|
const paginationSets = myConfig?.paginationSets;
|
|
16
17
|
const instancePath = myConfig?.instancePath || "@/configs/fetch/fetch-extend";
|
|
17
18
|
|
|
19
|
+
const includeReactQuery = myConfig?.includeReactQuery;
|
|
20
|
+
const includeReactSuspenseQuery = myConfig?.includeReactSuspenseQuery;
|
|
21
|
+
|
|
18
22
|
const apiInstanceName = route.moduleName + "Api";
|
|
19
23
|
const queryKeyName = "QUERY_KEY_" + _.upperCase(apiClassName).replace(/ /g, '_');
|
|
20
24
|
|
|
@@ -90,6 +94,8 @@ const getConfigByRoute = (route) => {
|
|
|
90
94
|
return {
|
|
91
95
|
conditions: {
|
|
92
96
|
hasPagination,
|
|
97
|
+
includeReactQuery,
|
|
98
|
+
includeReactSuspenseQuery,
|
|
93
99
|
isQuery,
|
|
94
100
|
isMutation,
|
|
95
101
|
isOptionalVariables,
|
|
@@ -122,8 +128,8 @@ const dataForReactHookTemplate = {
|
|
|
122
128
|
};
|
|
123
129
|
%>
|
|
124
130
|
|
|
125
|
-
import { useQuery, useMutation, useInfiniteQuery, InfiniteData } from '@tanstack/react-query';
|
|
126
|
-
import { QueryHookParams, InfiniteQueryHookParams, MutationHookParams, Parameter, RequestFnReturn } from "../@types/react-query-type";
|
|
131
|
+
import { useQuery, useMutation, useInfiniteQuery, useSuspenseQuery, useSuspenseInfiniteQuery, InfiniteData } from '@tanstack/react-query';
|
|
132
|
+
import { QueryHookParams, InfiniteQueryHookParams, MutationHookParams, Parameter, RequestFnReturn, SuspenseInfiniteQueryHookParams, SuspenseQueryHookParams } from "../@types/react-query-type";
|
|
127
133
|
import { paramsSerializerBy } from "../@utils/param-serializer-by";
|
|
128
134
|
import fetchExtended from "<%= instancePath %>";
|
|
129
135
|
|
|
@@ -141,13 +147,11 @@ import { <%~ dataContracts.join(", ") %> } from "../@types/<%~ config.fileNames.
|
|
|
141
147
|
* 스크립트가 실행될때, 파일을 항상 새로 쓰기 때문에 파일 수정시 작성내용이 제거 될 수 있습니다.
|
|
142
148
|
*/
|
|
143
149
|
|
|
144
|
-
|
|
145
|
-
|
|
146
150
|
export class <%= apiClassName %><SecurityDataType = unknown><% if (!config.singleHttpClient) { %> extends HttpClient<SecurityDataType> <% } %> {
|
|
147
|
-
<% if
|
|
151
|
+
<% if(config.singleHttpClient) { %>
|
|
148
152
|
http: HttpClient<SecurityDataType>;
|
|
149
153
|
|
|
150
|
-
constructor(http: HttpClient<SecurityDataType>) {
|
|
154
|
+
constructor (http: HttpClient<SecurityDataType>) {
|
|
151
155
|
this.http = http;
|
|
152
156
|
}
|
|
153
157
|
<% } %>
|
|
@@ -157,25 +161,47 @@ export class <%= apiClassName %><SecurityDataType = unknown><% if (!config.singl
|
|
|
157
161
|
<% }) %>
|
|
158
162
|
}
|
|
159
163
|
|
|
164
|
+
<% if(myConfig.includeReactQuery || myConfig.includeReactSuspenseQuery) { %>
|
|
165
|
+
//<%= myConfig.QUERY_HOOK_INDICATOR %>
|
|
160
166
|
|
|
161
|
-
<% if
|
|
162
|
-
|
|
167
|
+
<% if(myConfig.includeReactQuery) { %>
|
|
168
|
+
/**
|
|
169
|
+
* !DO NOT EDIT THIS FILE
|
|
170
|
+
*
|
|
171
|
+
* 스크립트가 실행될때, 파일을 항상 새로 쓰기 때문에 파일 수정시 작성내용이 제거 될 수 있습니다.
|
|
172
|
+
*/
|
|
163
173
|
|
|
174
|
+
/**
|
|
175
|
+
* tok-cli.config.ts 에서 설정된 instance 경로의 axios instace 가 적용된, api 의 instance 입니다.
|
|
176
|
+
*/
|
|
177
|
+
export const <%= apiInstanceName %> = new <%= apiClassName %>({ customFetch: fetchExtended });
|
|
164
178
|
|
|
165
|
-
|
|
166
|
-
* !DO NOT EDIT THIS FILE
|
|
167
|
-
*
|
|
168
|
-
* 스크립트가 실행될때, 파일을 항상 새로 쓰기 때문에 파일 수정시 작성내용이 제거 될 수 있습니다.
|
|
169
|
-
*/
|
|
179
|
+
<%~ includeFile(reactQueryKeyTemplatePath, { ...it, route , dataFromApiTemplate:dataForReactHookTemplate}) %>
|
|
170
180
|
|
|
181
|
+
<% routes.forEach((route) => { %>
|
|
182
|
+
<%~ includeFile(reactQueryTemplatePath, { ...it, route , dataFromApiTemplate:dataForReactHookTemplate}) %>
|
|
183
|
+
<% }) %>
|
|
184
|
+
<% } %>
|
|
171
185
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
*/
|
|
175
|
-
export const <%= apiInstanceName %> = new <%= apiClassName %>({ customFetch: fetchExtended });
|
|
176
|
-
<%~ includeFile(reactQuerKeyTemplatePath, { ...it, route, dataFromApiTemplate: dataForReactHookTemplate }) %>
|
|
186
|
+
<% if(myConfig.includeReactSuspenseQuery) { %>
|
|
187
|
+
//<%= myConfig.USE_SUSPENSE_QUERY_HOOK_INDICATOR %>
|
|
177
188
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
189
|
+
/**
|
|
190
|
+
* !DO NOT EDIT THIS FILE
|
|
191
|
+
*
|
|
192
|
+
* 스크립트가 실행될때, 파일을 항상 새로 쓰기 때문에 파일 수정시 작성내용이 제거 될 수 있습니다.
|
|
193
|
+
*/
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* tok-cli.config.ts 에서 설정된 instance 경로의 axios instace 가 적용된, api 의 instance 입니다.
|
|
197
|
+
*/
|
|
198
|
+
export const <%= apiInstanceName %> = new <%= apiClassName %>({ customFetch: fetchExtended });
|
|
199
|
+
|
|
200
|
+
<%~ includeFile(reactQueryKeyTemplatePath, { ...it, route , dataFromApiTemplate:dataForReactHookTemplate}) %>
|
|
201
|
+
|
|
202
|
+
<% routes.forEach((route) => { %>
|
|
203
|
+
<%~ includeFile(reactSuspenseQueryTemplatePath, { ...it, route , dataFromApiTemplate:dataForReactHookTemplate}) %>
|
|
204
|
+
<% }) %>
|
|
205
|
+
<% } %>
|
|
181
206
|
<% } %>
|
|
207
|
+
|
|
@@ -42,9 +42,10 @@ export interface ApiConfig<SecurityDataType = unknown> {
|
|
|
42
42
|
customFetch?: typeof fetch;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export interface HttpResponse<D
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
export interface HttpResponse<D, E = unknown>
|
|
46
|
+
extends Response {
|
|
47
|
+
data: D
|
|
48
|
+
error: E
|
|
48
49
|
}
|
|
49
50
|
|
|
50
51
|
type CancelToken = Symbol | string | number;
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
const { errorType } = route.response;
|
|
5
5
|
const { getConfigByRoute,paginationTargetKeywords } = dataFromApiTemplate;
|
|
6
6
|
|
|
7
|
-
|
|
8
7
|
const {
|
|
9
8
|
conditions:{
|
|
10
9
|
hasPagination,
|
|
10
|
+
includeReactQuery,
|
|
11
|
+
includeReactSuspenseQuery,
|
|
11
12
|
isQuery,
|
|
12
13
|
isMutation,
|
|
13
14
|
isOptionalVariables,
|
|
@@ -47,8 +48,6 @@
|
|
|
47
48
|
const isAxiosInstance = myConfig.httpClientType === 'axios'
|
|
48
49
|
const fetchErrorType = `{ error: ${errorType} }`
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
51
|
const initialPageParam = () => {
|
|
53
52
|
if(typeof pagination.initialPageParam === "string") return pagination.initialPageParam;
|
|
54
53
|
if(typeof pagination.initialPageParam === "function") return pagination.initialPageParam({ apiInstanceName, functionName, pagination})
|
|
@@ -63,111 +62,114 @@
|
|
|
63
62
|
if(typeof pagination.getNextPageParam === "string") return pagination.getNextPageParam;
|
|
64
63
|
if(typeof pagination.getNextPageParam === "function") return pagination.getNextPageParam({ apiInstanceName, functionName, pagination})
|
|
65
64
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
65
|
%>
|
|
69
66
|
|
|
70
|
-
|
|
71
|
-
|
|
67
|
+
<% if (isQuery) { %>
|
|
68
|
+
<% if(includeReactQuery) { %>
|
|
69
|
+
/**
|
|
70
|
+
<%~ routeDocs.description %>
|
|
72
71
|
|
|
73
|
-
|
|
72
|
+
* <% /* Here you can add some other JSDoc tags */ %>
|
|
74
73
|
|
|
75
|
-
<%~ routeDocs.lines %>
|
|
76
|
-
|
|
74
|
+
<%~ routeDocs.lines %>
|
|
75
|
+
*/
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
77
|
+
export const use<%~ classNameCase(functionName) %>Query = <
|
|
78
|
+
TData = RequestFnReturn<typeof <%= apiInstanceName %>.<%~ functionName %>>,
|
|
79
|
+
>(
|
|
80
|
+
<%~ conditionalParamsText %>: QueryHookParams<typeof <%= apiInstanceName %>.<%~ functionName %>,
|
|
81
|
+
<% if (isAxiosInstance) { %>
|
|
82
|
+
AxiosError<<%~ errorType %>>
|
|
83
|
+
<% } else { %>
|
|
84
|
+
<%~ fetchErrorType %>
|
|
85
|
+
<% } %>
|
|
86
|
+
, TData>,
|
|
87
|
+
) => {
|
|
88
|
+
const <%~ hookKeyName %> = <%~ queryKeyName %>.<%~ methodKey %>(<%~ `${conditionalParamsText}.variables` %>);
|
|
89
|
+
return useQuery({
|
|
90
|
+
<%~ hookKeyName %>,
|
|
91
|
+
queryFn: () => <%= apiInstanceName %>.<%~ functionName %>(<%~ `${conditionalParamsText}.variables` %>),
|
|
92
|
+
...params?.options,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
<% } %>
|
|
97
96
|
<% } else { %>
|
|
97
|
+
/**
|
|
98
|
+
<%~ routeDocs.description %>
|
|
99
|
+
|
|
100
|
+
* <% /* Here you can add some other JSDoc tags */ %>
|
|
101
|
+
|
|
102
|
+
<%~ routeDocs.lines %>
|
|
103
|
+
*/
|
|
104
|
+
|
|
98
105
|
export const use<%~ classNameCase(functionName) %>Mutation = (
|
|
99
|
-
|
|
106
|
+
<%~ conditionalParamsText %>: MutationHookParams<typeof <%= apiInstanceName %>.<%~ functionName %>,
|
|
100
107
|
<% if (isAxiosInstance) { %>
|
|
101
|
-
|
|
108
|
+
AxiosError<<%~ errorType %>>
|
|
102
109
|
<% } else { %>
|
|
103
|
-
|
|
110
|
+
<%~ fetchErrorType %>
|
|
104
111
|
<% } %>
|
|
105
112
|
>,
|
|
106
|
-
) => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
};
|
|
113
|
+
) => {
|
|
114
|
+
const <%~ hookKeyName %> = <%~ queryKeyName %>.<%~ methodKey %>();
|
|
115
|
+
return useMutation({
|
|
116
|
+
<%~ hookKeyName %>,
|
|
117
|
+
mutationFn: <%= apiInstanceName %>.<%~ functionName %>,
|
|
118
|
+
...params?.options,
|
|
119
|
+
});
|
|
120
|
+
};
|
|
114
121
|
<% } %>
|
|
115
122
|
|
|
116
|
-
|
|
117
123
|
<% if (isQuery && hasPagination) { %>
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
<%~
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
<%~ conditionalParamsText %>: InfiniteQueryHookParams<typeof <%= apiInstanceName %>.<%~ functionName %>,
|
|
134
|
-
<% if (isAxiosInstance) { %>
|
|
135
|
-
AxiosError<<%~ errorType %>>
|
|
136
|
-
<% } else { %>
|
|
137
|
-
<%~ errorType %>
|
|
138
|
-
<% } %>
|
|
139
|
-
, TData>,
|
|
140
|
-
) => {
|
|
141
|
-
const <%~ hookKeyName %> = <%~ queryKeyName %>.<%~ methodKey %>_INFINITE(<%~ conditionalQueryKeyParams %>);
|
|
142
|
-
|
|
143
|
-
return useInfiniteQuery({
|
|
144
|
-
<%~ hookKeyName %>,
|
|
145
|
-
initialPageParam: <% if (initialPageParam()) { %>
|
|
146
|
-
<%~ initialPageParam() %>
|
|
147
|
-
<% } else { %>
|
|
148
|
-
null
|
|
149
|
-
<% } %>,
|
|
150
|
-
queryFn: <% if (getNextPage()) { %>
|
|
151
|
-
<%~ getNextPage() %>
|
|
124
|
+
<% if (includeReactQuery) { %>
|
|
125
|
+
/**
|
|
126
|
+
<%~ routeDocs.description %>
|
|
127
|
+
* <% /* Here you can add some other JSDoc tags */ %>
|
|
128
|
+
<%~ routeDocs.lines %>
|
|
129
|
+
*/
|
|
130
|
+
export const use<%~ classNameCase(functionName) %>InfiniteQuery = <
|
|
131
|
+
TData = InfiniteData<
|
|
132
|
+
RequestFnReturn<typeof <%= apiInstanceName %>.<%~ functionName %>>,
|
|
133
|
+
Parameter<typeof <%= apiInstanceName %>.<%~ functionName %>>
|
|
134
|
+
>,
|
|
135
|
+
>(
|
|
136
|
+
<%~ conditionalParamsText %>: InfiniteQueryHookParams<typeof <%= apiInstanceName %>.<%~ functionName %>,
|
|
137
|
+
<% if (isAxiosInstance) { %>
|
|
138
|
+
AxiosError<<%~ errorType %>>
|
|
152
139
|
<% } else { %>
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
140
|
+
<%~ errorType %>
|
|
141
|
+
<% } %>
|
|
142
|
+
, TData>,
|
|
143
|
+
) => {
|
|
144
|
+
const <%~ hookKeyName %> = <%~ queryKeyName %>.<%~ methodKey %>_INFINITE(<%~ conditionalQueryKeyParams %>);
|
|
145
|
+
return useInfiniteQuery({
|
|
146
|
+
<%~ hookKeyName %>,
|
|
147
|
+
initialPageParam: <% if (initialPageParam()) { %>
|
|
148
|
+
<%~ initialPageParam() %>
|
|
149
|
+
<% } else { %>
|
|
150
|
+
null
|
|
151
|
+
<% } %>,
|
|
152
|
+
queryFn: <% if (getNextPage()) { %>
|
|
153
|
+
<%~ getNextPage() %>
|
|
154
|
+
<% } else { %>
|
|
155
|
+
({ pageParam }) => {
|
|
156
|
+
return <%= apiInstanceName %>.<%~ functionName %>({
|
|
157
|
+
...params?.variables,
|
|
158
|
+
query: { ...params?.variables?.query, <%~ pagination.nextKey %>: pageParam, }
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
<% } %>,
|
|
162
|
+
getNextPageParam:
|
|
163
|
+
<% if (getNextPageParam()) { %>
|
|
164
|
+
<%~ getNextPageParam() %>
|
|
163
165
|
<% } else { %>
|
|
164
166
|
(lastPage) => {
|
|
165
167
|
const <%~ pagination.nextKey %> = lastPage.cursor ?? null;
|
|
166
168
|
return <%~ pagination.nextKey %>;
|
|
167
169
|
}
|
|
168
170
|
<% } %>,
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
};
|
|
172
|
-
|
|
171
|
+
...params?.options,
|
|
172
|
+
});
|
|
173
|
+
};
|
|
174
|
+
<% } %>
|
|
173
175
|
<% } %>
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
|
|
2
|
+
<%
|
|
3
|
+
const { utils, route, config, myConfig, dataFromApiTemplate } = it;
|
|
4
|
+
const { query } = route.request;
|
|
5
|
+
const { errorType } = route.response;
|
|
6
|
+
const { getConfigByRoute,paginationTargetKeywords } = dataFromApiTemplate;
|
|
7
|
+
|
|
8
|
+
const {
|
|
9
|
+
conditions:{
|
|
10
|
+
hasPagination,
|
|
11
|
+
includeReactQuery,
|
|
12
|
+
includeReactSuspenseQuery,
|
|
13
|
+
isQuery,
|
|
14
|
+
isMutation,
|
|
15
|
+
isOptionalVariables,
|
|
16
|
+
},
|
|
17
|
+
data: {
|
|
18
|
+
rawWrapperArgs,
|
|
19
|
+
wrapperArgs,
|
|
20
|
+
queryKeyName,
|
|
21
|
+
functionName,
|
|
22
|
+
apiInstanceName,
|
|
23
|
+
apiClassName,
|
|
24
|
+
hookVariant,
|
|
25
|
+
key,
|
|
26
|
+
methodKey,
|
|
27
|
+
pagination
|
|
28
|
+
},
|
|
29
|
+
utils: {
|
|
30
|
+
upperSnakeCase,
|
|
31
|
+
removeModuleName,
|
|
32
|
+
argToTmpl,
|
|
33
|
+
}
|
|
34
|
+
} = getConfigByRoute(route);
|
|
35
|
+
|
|
36
|
+
const { _, classNameCase } = utils;
|
|
37
|
+
|
|
38
|
+
const conditionalParamsText = isOptionalVariables ? "params?" : "params"
|
|
39
|
+
const conditionCallWithVariabels = isQuery ? `(${conditionalParamsText}.variables)` : "";
|
|
40
|
+
const conditionParamQueryKey = isQuery ? `,${conditionalParamsText}.variables` : "";
|
|
41
|
+
const conditionWrapFunc = isQuery ? "() =>" : "";
|
|
42
|
+
const conditionalQueryKeyParams = isQuery ? `${conditionalParamsText}.variables` : "";
|
|
43
|
+
const conditionalFn = isQuery ? "queryFn" : "mutationFn";
|
|
44
|
+
|
|
45
|
+
const routeDocs = includeFile("@base/route-docs", { config, route, utils });
|
|
46
|
+
const lowerhookVariant = _.lowerCase(hookVariant)
|
|
47
|
+
const hookKeyName = `${lowerhookVariant}Key`;
|
|
48
|
+
|
|
49
|
+
const isAxiosInstance = myConfig.httpClientType === 'axios'
|
|
50
|
+
const fetchErrorType = `{ error: ${errorType} }`
|
|
51
|
+
|
|
52
|
+
const initialPageParam = () => {
|
|
53
|
+
if(typeof pagination.initialPageParam === "string") return pagination.initialPageParam;
|
|
54
|
+
if(typeof pagination.initialPageParam === "function") return pagination.initialPageParam({ apiInstanceName, functionName, pagination})
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const getNextPage = () => {
|
|
58
|
+
if(typeof pagination.getNextPage === "string") return pagination.getNextPage;
|
|
59
|
+
if(typeof pagination.getNextPage === "function") return pagination.getNextPage({ apiInstanceName, functionName, pagination})
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const getNextPageParam = () => {
|
|
63
|
+
if(typeof pagination.getNextPageParam === "string") return pagination.getNextPageParam;
|
|
64
|
+
if(typeof pagination.getNextPageParam === "function") return pagination.getNextPageParam({ apiInstanceName, functionName, pagination})
|
|
65
|
+
}
|
|
66
|
+
%>
|
|
67
|
+
|
|
68
|
+
<% if (isQuery) { %>
|
|
69
|
+
<% if (includeReactSuspenseQuery) { %>
|
|
70
|
+
/**
|
|
71
|
+
<%~ routeDocs.description %>
|
|
72
|
+
|
|
73
|
+
* <% /* Here you can add some other JSDoc tags */ %>
|
|
74
|
+
|
|
75
|
+
<%~ routeDocs.lines %>
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
export const use<%~ classNameCase(functionName) %>SuspenseQuery = <
|
|
79
|
+
TData = RequestFnReturn<typeof <%= apiInstanceName %>.<%~ functionName %>>,
|
|
80
|
+
>(
|
|
81
|
+
<%~ conditionalParamsText %>: SuspenseQueryHookParams<typeof <%= apiInstanceName %>.<%~ functionName %>,
|
|
82
|
+
<% if (isAxiosInstance) { %>
|
|
83
|
+
AxiosError<<%~ errorType %>>
|
|
84
|
+
<% } else { %>
|
|
85
|
+
<%~ fetchErrorType %>
|
|
86
|
+
<% } %>
|
|
87
|
+
, TData>,
|
|
88
|
+
) => {
|
|
89
|
+
const <%~ hookKeyName %> = <%~ queryKeyName %>.<%~ methodKey %>(<%~ `${conditionalParamsText}.variables` %>);
|
|
90
|
+
return useSuspenseQuery({
|
|
91
|
+
<%~ hookKeyName %>,
|
|
92
|
+
queryFn: () => <%= apiInstanceName %>.<%~ functionName %>(<%~ `${conditionalParamsText}.variables` %>),
|
|
93
|
+
...params?.options,
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @name <%~ _.camelCase(functionName) %>QueryOptions
|
|
100
|
+
* @description 이 옵션은 Suspense 기반의 병렬 데이터 쿼리를 위한 설정입니다.
|
|
101
|
+
* `useSuspenseQueries`를 사용하여 여러 쿼리를 병렬로 처리할 때 활용하세요.
|
|
102
|
+
*/
|
|
103
|
+
|
|
104
|
+
export const <%~ _.camelCase(functionName) %>SuspenseQueryOptions = <
|
|
105
|
+
TData = RequestFnReturn<typeof <%= apiInstanceName %>.<%~ functionName %>>,
|
|
106
|
+
>(
|
|
107
|
+
<%~ conditionalParamsText %>: SuspenseQueryHookParams<typeof <%= apiInstanceName %>.<%~ functionName %>,
|
|
108
|
+
<% if (isAxiosInstance) { %>
|
|
109
|
+
unknown
|
|
110
|
+
<% } else { %>
|
|
111
|
+
<%~ fetchErrorType %>
|
|
112
|
+
<% } %>
|
|
113
|
+
, TData>,
|
|
114
|
+
) => {
|
|
115
|
+
const queryKey = <%~ queryKeyName %>.<%~ methodKey %>(<%~ `${conditionalParamsText}.variables` %>);
|
|
116
|
+
return {
|
|
117
|
+
queryKey,
|
|
118
|
+
queryFn: () => <%= apiInstanceName %>.<%~ functionName %>(<%~ `${conditionalParamsText}.variables` %>),
|
|
119
|
+
...params?.options,
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
<% } %>
|
|
123
|
+
|
|
124
|
+
<% if (isQuery && hasPagination) { %>
|
|
125
|
+
/**
|
|
126
|
+
<%~ routeDocs.description %>
|
|
127
|
+
* <% /* Here you can add some other JSDoc tags */ %>
|
|
128
|
+
<%~ routeDocs.lines %>
|
|
129
|
+
*/
|
|
130
|
+
export const use<%~ classNameCase(functionName) %>InfiniteSuspenseQuery = <
|
|
131
|
+
TData = InfiniteData<
|
|
132
|
+
RequestFnReturn<typeof <%= apiInstanceName %>.<%~ functionName %>>,
|
|
133
|
+
Parameter<typeof <%= apiInstanceName %>.<%~ functionName %>>
|
|
134
|
+
>,
|
|
135
|
+
>(
|
|
136
|
+
<%~ conditionalParamsText %>: SuspenseInfiniteQueryHookParams<typeof <%= apiInstanceName %>.<%~ functionName %>,
|
|
137
|
+
<% if (isAxiosInstance) { %>
|
|
138
|
+
AxiosError<<%~ errorType %>>
|
|
139
|
+
<% } else { %>
|
|
140
|
+
<%~ errorType %>
|
|
141
|
+
<% } %>
|
|
142
|
+
, TData>,
|
|
143
|
+
) => {
|
|
144
|
+
const <%~ hookKeyName %> = <%~ queryKeyName %>.<%~ methodKey %>_INFINITE(<%~ conditionalQueryKeyParams %>);
|
|
145
|
+
return useSuspenseInfiniteQuery({
|
|
146
|
+
<%~ hookKeyName %>,
|
|
147
|
+
initialPageParam: <% if (initialPageParam()) { %>
|
|
148
|
+
<%~ initialPageParam() %>
|
|
149
|
+
<% } else { %>
|
|
150
|
+
null
|
|
151
|
+
<% } %>,
|
|
152
|
+
queryFn: <% if (getNextPage()) { %>
|
|
153
|
+
<%~ getNextPage() %>
|
|
154
|
+
<% } else { %>
|
|
155
|
+
({ pageParam }) => {
|
|
156
|
+
return <%= apiInstanceName %>.<%~ functionName %>({
|
|
157
|
+
...params?.variables,
|
|
158
|
+
query: { ...params?.variables?.query, <%~ pagination.nextKey %>: pageParam, }
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
<% } %>,
|
|
162
|
+
getNextPageParam:
|
|
163
|
+
<% if (getNextPageParam()) { %>
|
|
164
|
+
<%~ getNextPageParam() %>
|
|
165
|
+
<% } else { %>
|
|
166
|
+
(lastPage) => {
|
|
167
|
+
const <%~ pagination.nextKey %> = lastPage.cursor ?? null;
|
|
168
|
+
return <%~ pagination.nextKey %>;
|
|
169
|
+
}
|
|
170
|
+
<% } %>,
|
|
171
|
+
...params?.options,
|
|
172
|
+
});
|
|
173
|
+
};
|
|
174
|
+
<% } %>
|
|
175
|
+
<% } %>
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
UseInfiniteQueryOptions,
|
|
9
9
|
UseMutationOptions,
|
|
10
10
|
UseQueryOptions,
|
|
11
|
+
UseSuspenseQueryOptions,
|
|
12
|
+
UseSuspenseInfiniteQueryOptions,
|
|
11
13
|
} from '@tanstack/react-query';
|
|
12
14
|
|
|
13
15
|
|
|
@@ -59,6 +61,34 @@ export type MutationHookParams<
|
|
|
59
61
|
>;
|
|
60
62
|
};
|
|
61
63
|
|
|
64
|
+
export type SuspenseQueryHookParams<
|
|
65
|
+
T extends CustomRequestFn,
|
|
66
|
+
Error = <%~ errorType %>,
|
|
67
|
+
TData = RequestFnReturn<T>,
|
|
68
|
+
OriginData = RequestFnReturn<T>,
|
|
69
|
+
Variables = Parameter<T>,
|
|
70
|
+
> = {
|
|
71
|
+
options?: Omit<
|
|
72
|
+
UseSuspenseQueryOptions<OriginData, Error, TData>,
|
|
73
|
+
'queryKey' | 'queryFn'
|
|
74
|
+
>;
|
|
75
|
+
} & OptionalVariables<Variables>;
|
|
76
|
+
|
|
77
|
+
export type SuspenseInfiniteQueryHookParams<
|
|
78
|
+
T extends CustomRequestFn,
|
|
79
|
+
Error = <%~ errorType %>,
|
|
80
|
+
TData = RequestFnReturn<T>,
|
|
81
|
+
OriginData = RequestFnReturn<T>,
|
|
82
|
+
Variables = Parameter<T>,
|
|
83
|
+
> = {
|
|
84
|
+
options?: Partial<
|
|
85
|
+
Omit<
|
|
86
|
+
UseSuspenseInfiniteQueryOptions<OriginData, Error, TData, OriginData, any, any>,
|
|
87
|
+
'queryKey' | 'queryFn'
|
|
88
|
+
>
|
|
89
|
+
>;
|
|
90
|
+
} & OptionalVariables<Variables>;
|
|
91
|
+
|
|
62
92
|
export type OptionalVariables<T> = undefined extends T
|
|
63
93
|
? { variables?: T }
|
|
64
94
|
: { variables: T };
|