@constructive-io/graphql-codegen 2.20.1 → 2.21.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.
@@ -12,8 +12,14 @@ const utils_1 = require("./utils");
12
12
  // ============================================================================
13
13
  /**
14
14
  * Generate create mutation hook file content using AST
15
+ * When reactQueryEnabled is false, returns null since mutations require React Query
15
16
  */
16
- function generateCreateMutationHook(table) {
17
+ function generateCreateMutationHook(table, options = {}) {
18
+ const { reactQueryEnabled = true } = options;
19
+ // Mutations require React Query - skip generation when disabled
20
+ if (!reactQueryEnabled) {
21
+ return null;
22
+ }
17
23
  const project = (0, ts_ast_1.createProject)();
18
24
  const { typeName, singularName } = (0, utils_1.getTableNames)(table);
19
25
  const hookName = (0, utils_1.getCreateMutationHookName)(table);
@@ -143,8 +149,14 @@ mutate({
143
149
  // ============================================================================
144
150
  /**
145
151
  * Generate update mutation hook file content using AST
152
+ * When reactQueryEnabled is false, returns null since mutations require React Query
146
153
  */
147
- function generateUpdateMutationHook(table) {
154
+ function generateUpdateMutationHook(table, options = {}) {
155
+ const { reactQueryEnabled = true } = options;
156
+ // Mutations require React Query - skip generation when disabled
157
+ if (!reactQueryEnabled) {
158
+ return null;
159
+ }
148
160
  // Check if update mutation exists
149
161
  if (table.query?.update === null) {
150
162
  return null;
@@ -278,8 +290,14 @@ mutate({
278
290
  // ============================================================================
279
291
  /**
280
292
  * Generate delete mutation hook file content using AST
293
+ * When reactQueryEnabled is false, returns null since mutations require React Query
281
294
  */
282
- function generateDeleteMutationHook(table) {
295
+ function generateDeleteMutationHook(table, options = {}) {
296
+ const { reactQueryEnabled = true } = options;
297
+ // Mutations require React Query - skip generation when disabled
298
+ if (!reactQueryEnabled) {
299
+ return null;
300
+ }
283
301
  // Check if delete mutation exists
284
302
  if (table.query?.delete === null) {
285
303
  return null;
@@ -392,16 +410,20 @@ mutate({
392
410
  // ============================================================================
393
411
  /**
394
412
  * Generate all mutation hook files for all tables
413
+ * When reactQueryEnabled is false, returns empty array since mutations require React Query
395
414
  */
396
- function generateAllMutationHooks(tables) {
415
+ function generateAllMutationHooks(tables, options = {}) {
397
416
  const files = [];
398
417
  for (const table of tables) {
399
- files.push(generateCreateMutationHook(table));
400
- const updateHook = generateUpdateMutationHook(table);
418
+ const createHook = generateCreateMutationHook(table, options);
419
+ if (createHook) {
420
+ files.push(createHook);
421
+ }
422
+ const updateHook = generateUpdateMutationHook(table, options);
401
423
  if (updateHook) {
402
424
  files.push(updateHook);
403
425
  }
404
- const deleteHook = generateDeleteMutationHook(table);
426
+ const deleteHook = generateDeleteMutationHook(table, options);
405
427
  if (deleteHook) {
406
428
  files.push(deleteHook);
407
429
  }
@@ -11,15 +11,19 @@ export interface GeneratedQueryFile {
11
11
  fileName: string;
12
12
  content: string;
13
13
  }
14
+ export interface QueryGeneratorOptions {
15
+ /** Whether to generate React Query hooks (default: true for backwards compatibility) */
16
+ reactQueryEnabled?: boolean;
17
+ }
14
18
  /**
15
19
  * Generate list query hook file content using AST
16
20
  */
17
- export declare function generateListQueryHook(table: CleanTable): GeneratedQueryFile;
21
+ export declare function generateListQueryHook(table: CleanTable, options?: QueryGeneratorOptions): GeneratedQueryFile;
18
22
  /**
19
23
  * Generate single item query hook file content using AST
20
24
  */
21
- export declare function generateSingleQueryHook(table: CleanTable): GeneratedQueryFile;
25
+ export declare function generateSingleQueryHook(table: CleanTable, options?: QueryGeneratorOptions): GeneratedQueryFile;
22
26
  /**
23
27
  * Generate all query hook files for all tables
24
28
  */
25
- export declare function generateAllQueryHooks(tables: CleanTable[]): GeneratedQueryFile[];
29
+ export declare function generateAllQueryHooks(tables: CleanTable[], options?: QueryGeneratorOptions): GeneratedQueryFile[];
@@ -12,7 +12,8 @@ const utils_1 = require("./utils");
12
12
  /**
13
13
  * Generate list query hook file content using AST
14
14
  */
15
- function generateListQueryHook(table) {
15
+ function generateListQueryHook(table, options = {}) {
16
+ const { reactQueryEnabled = true } = options;
16
17
  const project = (0, ts_ast_1.createProject)();
17
18
  const { typeName, pluralName } = (0, utils_1.getTableNames)(table);
18
19
  const hookName = (0, utils_1.getListQueryHookName)(table);
@@ -25,7 +26,10 @@ function generateListQueryHook(table) {
25
26
  const queryDocument = (0, gql_ast_1.printGraphQL)(queryAST);
26
27
  const sourceFile = (0, ts_ast_1.createSourceFile)(project, (0, utils_1.getListQueryFileName)(table));
27
28
  // Add file header as leading comment
28
- sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)(`List query hook for ${typeName}`) + '\n\n');
29
+ const headerText = reactQueryEnabled
30
+ ? `List query hook for ${typeName}`
31
+ : `List query functions for ${typeName}`;
32
+ sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)(headerText) + '\n\n');
29
33
  // Collect all filter types used by this table's fields
30
34
  const filterTypesUsed = new Set();
31
35
  for (const field of scalarFields) {
@@ -34,23 +38,24 @@ function generateListQueryHook(table) {
34
38
  filterTypesUsed.add(filterType);
35
39
  }
36
40
  }
37
- // Add imports
38
- sourceFile.addImportDeclarations([
39
- (0, ts_ast_1.createImport)({
41
+ // Add imports - conditionally include React Query imports
42
+ const imports = [];
43
+ if (reactQueryEnabled) {
44
+ imports.push((0, ts_ast_1.createImport)({
40
45
  moduleSpecifier: '@tanstack/react-query',
41
46
  namedImports: ['useQuery'],
42
47
  typeOnlyNamedImports: ['UseQueryOptions', 'QueryClient'],
43
- }),
44
- (0, ts_ast_1.createImport)({
45
- moduleSpecifier: '../client',
46
- namedImports: ['execute'],
47
- typeOnlyNamedImports: ['ExecuteOptions'],
48
- }),
49
- (0, ts_ast_1.createImport)({
50
- moduleSpecifier: '../types',
51
- typeOnlyNamedImports: [typeName, ...Array.from(filterTypesUsed)],
52
- }),
53
- ]);
48
+ }));
49
+ }
50
+ imports.push((0, ts_ast_1.createImport)({
51
+ moduleSpecifier: '../client',
52
+ namedImports: ['execute'],
53
+ typeOnlyNamedImports: ['ExecuteOptions'],
54
+ }), (0, ts_ast_1.createImport)({
55
+ moduleSpecifier: '../types',
56
+ typeOnlyNamedImports: [typeName, ...Array.from(filterTypesUsed)],
57
+ }));
58
+ sourceFile.addImportDeclarations(imports);
54
59
  // Re-export entity type
55
60
  sourceFile.addStatements(`\n// Re-export entity type for convenience\nexport type { ${typeName} };\n`);
56
61
  // Add section comment
@@ -114,27 +119,28 @@ function generateListQueryHook(table) {
114
119
  // Query key factory
115
120
  sourceFile.addVariableStatement((0, ts_ast_1.createConst)(`${queryName}QueryKey`, `(variables?: ${(0, utils_1.ucFirst)(pluralName)}QueryVariables) =>
116
121
  ['${typeName.toLowerCase()}', 'list', variables] as const`));
117
- // Add section comment
118
- sourceFile.addStatements('\n// ============================================================================');
119
- sourceFile.addStatements('// Hook');
120
- sourceFile.addStatements('// ============================================================================\n');
121
- // Hook function
122
- sourceFile.addFunction({
123
- name: hookName,
124
- isExported: true,
125
- parameters: [
126
- {
127
- name: 'variables',
128
- type: `${(0, utils_1.ucFirst)(pluralName)}QueryVariables`,
129
- hasQuestionToken: true,
130
- },
131
- {
132
- name: 'options',
133
- type: `Omit<UseQueryOptions<${(0, utils_1.ucFirst)(pluralName)}QueryResult, Error>, 'queryKey' | 'queryFn'>`,
134
- hasQuestionToken: true,
135
- },
136
- ],
137
- statements: `return useQuery({
122
+ // Add React Query hook section (only if enabled)
123
+ if (reactQueryEnabled) {
124
+ sourceFile.addStatements('\n// ============================================================================');
125
+ sourceFile.addStatements('// Hook');
126
+ sourceFile.addStatements('// ============================================================================\n');
127
+ // Hook function
128
+ sourceFile.addFunction({
129
+ name: hookName,
130
+ isExported: true,
131
+ parameters: [
132
+ {
133
+ name: 'variables',
134
+ type: `${(0, utils_1.ucFirst)(pluralName)}QueryVariables`,
135
+ hasQuestionToken: true,
136
+ },
137
+ {
138
+ name: 'options',
139
+ type: `Omit<UseQueryOptions<${(0, utils_1.ucFirst)(pluralName)}QueryResult, Error>, 'queryKey' | 'queryFn'>`,
140
+ hasQuestionToken: true,
141
+ },
142
+ ],
143
+ statements: `return useQuery({
138
144
  queryKey: ${queryName}QueryKey(variables),
139
145
  queryFn: () => execute<${(0, utils_1.ucFirst)(pluralName)}QueryResult, ${(0, utils_1.ucFirst)(pluralName)}QueryVariables>(
140
146
  ${queryName}QueryDocument,
@@ -142,9 +148,9 @@ function generateListQueryHook(table) {
142
148
  ),
143
149
  ...options,
144
150
  });`,
145
- docs: [
146
- {
147
- description: `Query hook for fetching ${typeName} list
151
+ docs: [
152
+ {
153
+ description: `Query hook for fetching ${typeName} list
148
154
 
149
155
  @example
150
156
  \`\`\`tsx
@@ -154,9 +160,10 @@ const { data, isLoading } = ${hookName}({
154
160
  orderBy: ['CREATED_AT_DESC'],
155
161
  });
156
162
  \`\`\``,
157
- },
158
- ],
159
- });
163
+ },
164
+ ],
165
+ });
166
+ }
160
167
  // Add section comment for standalone functions
161
168
  sourceFile.addStatements('\n// ============================================================================');
162
169
  sourceFile.addStatements('// Standalone Functions (non-React)');
@@ -202,29 +209,30 @@ const data = await queryClient.fetchQuery({
202
209
  },
203
210
  ],
204
211
  });
205
- // Prefetch function (for SSR/QueryClient)
206
- sourceFile.addFunction({
207
- name: `prefetch${(0, utils_1.ucFirst)(pluralName)}Query`,
208
- isExported: true,
209
- isAsync: true,
210
- parameters: [
211
- {
212
- name: 'queryClient',
213
- type: 'QueryClient',
214
- },
215
- {
216
- name: 'variables',
217
- type: `${(0, utils_1.ucFirst)(pluralName)}QueryVariables`,
218
- hasQuestionToken: true,
219
- },
220
- {
221
- name: 'options',
222
- type: 'ExecuteOptions',
223
- hasQuestionToken: true,
224
- },
225
- ],
226
- returnType: 'Promise<void>',
227
- statements: `await queryClient.prefetchQuery({
212
+ // Prefetch function (for SSR/QueryClient) - only if React Query is enabled
213
+ if (reactQueryEnabled) {
214
+ sourceFile.addFunction({
215
+ name: `prefetch${(0, utils_1.ucFirst)(pluralName)}Query`,
216
+ isExported: true,
217
+ isAsync: true,
218
+ parameters: [
219
+ {
220
+ name: 'queryClient',
221
+ type: 'QueryClient',
222
+ },
223
+ {
224
+ name: 'variables',
225
+ type: `${(0, utils_1.ucFirst)(pluralName)}QueryVariables`,
226
+ hasQuestionToken: true,
227
+ },
228
+ {
229
+ name: 'options',
230
+ type: 'ExecuteOptions',
231
+ hasQuestionToken: true,
232
+ },
233
+ ],
234
+ returnType: 'Promise<void>',
235
+ statements: `await queryClient.prefetchQuery({
228
236
  queryKey: ${queryName}QueryKey(variables),
229
237
  queryFn: () => execute<${(0, utils_1.ucFirst)(pluralName)}QueryResult, ${(0, utils_1.ucFirst)(pluralName)}QueryVariables>(
230
238
  ${queryName}QueryDocument,
@@ -232,17 +240,18 @@ const data = await queryClient.fetchQuery({
232
240
  options
233
241
  ),
234
242
  });`,
235
- docs: [
236
- {
237
- description: `Prefetch ${typeName} list for SSR or cache warming
243
+ docs: [
244
+ {
245
+ description: `Prefetch ${typeName} list for SSR or cache warming
238
246
 
239
247
  @example
240
248
  \`\`\`ts
241
249
  await prefetch${(0, utils_1.ucFirst)(pluralName)}Query(queryClient, { first: 10 });
242
250
  \`\`\``,
243
- },
244
- ],
245
- });
251
+ },
252
+ ],
253
+ });
254
+ }
246
255
  return {
247
256
  fileName: (0, utils_1.getListQueryFileName)(table),
248
257
  content: (0, ts_ast_1.getFormattedOutput)(sourceFile),
@@ -254,7 +263,8 @@ await prefetch${(0, utils_1.ucFirst)(pluralName)}Query(queryClient, { first: 10
254
263
  /**
255
264
  * Generate single item query hook file content using AST
256
265
  */
257
- function generateSingleQueryHook(table) {
266
+ function generateSingleQueryHook(table, options = {}) {
267
+ const { reactQueryEnabled = true } = options;
258
268
  const project = (0, ts_ast_1.createProject)();
259
269
  const { typeName, singularName } = (0, utils_1.getTableNames)(table);
260
270
  const hookName = (0, utils_1.getSingleQueryHookName)(table);
@@ -264,24 +274,28 @@ function generateSingleQueryHook(table) {
264
274
  const queryDocument = (0, gql_ast_1.printGraphQL)(queryAST);
265
275
  const sourceFile = (0, ts_ast_1.createSourceFile)(project, (0, utils_1.getSingleQueryFileName)(table));
266
276
  // Add file header
267
- sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)(`Single item query hook for ${typeName}`) + '\n\n');
268
- // Add imports
269
- sourceFile.addImportDeclarations([
270
- (0, ts_ast_1.createImport)({
277
+ const headerText = reactQueryEnabled
278
+ ? `Single item query hook for ${typeName}`
279
+ : `Single item query functions for ${typeName}`;
280
+ sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)(headerText) + '\n\n');
281
+ // Add imports - conditionally include React Query imports
282
+ const imports = [];
283
+ if (reactQueryEnabled) {
284
+ imports.push((0, ts_ast_1.createImport)({
271
285
  moduleSpecifier: '@tanstack/react-query',
272
286
  namedImports: ['useQuery'],
273
287
  typeOnlyNamedImports: ['UseQueryOptions', 'QueryClient'],
274
- }),
275
- (0, ts_ast_1.createImport)({
276
- moduleSpecifier: '../client',
277
- namedImports: ['execute'],
278
- typeOnlyNamedImports: ['ExecuteOptions'],
279
- }),
280
- (0, ts_ast_1.createImport)({
281
- moduleSpecifier: '../types',
282
- typeOnlyNamedImports: [typeName],
283
- }),
284
- ]);
288
+ }));
289
+ }
290
+ imports.push((0, ts_ast_1.createImport)({
291
+ moduleSpecifier: '../client',
292
+ namedImports: ['execute'],
293
+ typeOnlyNamedImports: ['ExecuteOptions'],
294
+ }), (0, ts_ast_1.createImport)({
295
+ moduleSpecifier: '../types',
296
+ typeOnlyNamedImports: [typeName],
297
+ }));
298
+ sourceFile.addImportDeclarations(imports);
285
299
  // Re-export entity type
286
300
  sourceFile.addStatements(`\n// Re-export entity type for convenience\nexport type { ${typeName} };\n`);
287
301
  // Add section comment
@@ -309,23 +323,24 @@ function generateSingleQueryHook(table) {
309
323
  // Query key factory
310
324
  sourceFile.addVariableStatement((0, ts_ast_1.createConst)(`${queryName}QueryKey`, `(id: string) =>
311
325
  ['${typeName.toLowerCase()}', 'detail', id] as const`));
312
- // Add section comment
313
- sourceFile.addStatements('\n// ============================================================================');
314
- sourceFile.addStatements('// Hook');
315
- sourceFile.addStatements('// ============================================================================\n');
316
- // Hook function
317
- sourceFile.addFunction({
318
- name: hookName,
319
- isExported: true,
320
- parameters: [
321
- { name: 'id', type: 'string' },
322
- {
323
- name: 'options',
324
- type: `Omit<UseQueryOptions<${(0, utils_1.ucFirst)(singularName)}QueryResult, Error>, 'queryKey' | 'queryFn'>`,
325
- hasQuestionToken: true,
326
- },
327
- ],
328
- statements: `return useQuery({
326
+ // Add React Query hook section (only if enabled)
327
+ if (reactQueryEnabled) {
328
+ sourceFile.addStatements('\n// ============================================================================');
329
+ sourceFile.addStatements('// Hook');
330
+ sourceFile.addStatements('// ============================================================================\n');
331
+ // Hook function
332
+ sourceFile.addFunction({
333
+ name: hookName,
334
+ isExported: true,
335
+ parameters: [
336
+ { name: 'id', type: 'string' },
337
+ {
338
+ name: 'options',
339
+ type: `Omit<UseQueryOptions<${(0, utils_1.ucFirst)(singularName)}QueryResult, Error>, 'queryKey' | 'queryFn'>`,
340
+ hasQuestionToken: true,
341
+ },
342
+ ],
343
+ statements: `return useQuery({
329
344
  queryKey: ${queryName}QueryKey(id),
330
345
  queryFn: () => execute<${(0, utils_1.ucFirst)(singularName)}QueryResult, ${(0, utils_1.ucFirst)(singularName)}QueryVariables>(
331
346
  ${queryName}QueryDocument,
@@ -334,9 +349,9 @@ function generateSingleQueryHook(table) {
334
349
  enabled: !!id && (options?.enabled !== false),
335
350
  ...options,
336
351
  });`,
337
- docs: [
338
- {
339
- description: `Query hook for fetching a single ${typeName} by ID
352
+ docs: [
353
+ {
354
+ description: `Query hook for fetching a single ${typeName} by ID
340
355
 
341
356
  @example
342
357
  \`\`\`tsx
@@ -346,9 +361,10 @@ if (data?.${queryName}) {
346
361
  console.log(data.${queryName}.id);
347
362
  }
348
363
  \`\`\``,
349
- },
350
- ],
351
- });
364
+ },
365
+ ],
366
+ });
367
+ }
352
368
  // Add section comment for standalone functions
353
369
  sourceFile.addStatements('\n// ============================================================================');
354
370
  sourceFile.addStatements('// Standalone Functions (non-React)');
@@ -383,22 +399,23 @@ const data = await fetch${(0, utils_1.ucFirst)(singularName)}Query('uuid-here');
383
399
  },
384
400
  ],
385
401
  });
386
- // Prefetch function (for SSR/QueryClient)
387
- sourceFile.addFunction({
388
- name: `prefetch${(0, utils_1.ucFirst)(singularName)}Query`,
389
- isExported: true,
390
- isAsync: true,
391
- parameters: [
392
- { name: 'queryClient', type: 'QueryClient' },
393
- { name: 'id', type: 'string' },
394
- {
395
- name: 'options',
396
- type: 'ExecuteOptions',
397
- hasQuestionToken: true,
398
- },
399
- ],
400
- returnType: 'Promise<void>',
401
- statements: `await queryClient.prefetchQuery({
402
+ // Prefetch function (for SSR/QueryClient) - only if React Query is enabled
403
+ if (reactQueryEnabled) {
404
+ sourceFile.addFunction({
405
+ name: `prefetch${(0, utils_1.ucFirst)(singularName)}Query`,
406
+ isExported: true,
407
+ isAsync: true,
408
+ parameters: [
409
+ { name: 'queryClient', type: 'QueryClient' },
410
+ { name: 'id', type: 'string' },
411
+ {
412
+ name: 'options',
413
+ type: 'ExecuteOptions',
414
+ hasQuestionToken: true,
415
+ },
416
+ ],
417
+ returnType: 'Promise<void>',
418
+ statements: `await queryClient.prefetchQuery({
402
419
  queryKey: ${queryName}QueryKey(id),
403
420
  queryFn: () => execute<${(0, utils_1.ucFirst)(singularName)}QueryResult, ${(0, utils_1.ucFirst)(singularName)}QueryVariables>(
404
421
  ${queryName}QueryDocument,
@@ -406,17 +423,18 @@ const data = await fetch${(0, utils_1.ucFirst)(singularName)}Query('uuid-here');
406
423
  options
407
424
  ),
408
425
  });`,
409
- docs: [
410
- {
411
- description: `Prefetch a single ${typeName} for SSR or cache warming
426
+ docs: [
427
+ {
428
+ description: `Prefetch a single ${typeName} for SSR or cache warming
412
429
 
413
430
  @example
414
431
  \`\`\`ts
415
432
  await prefetch${(0, utils_1.ucFirst)(singularName)}Query(queryClient, 'uuid-here');
416
433
  \`\`\``,
417
- },
418
- ],
419
- });
434
+ },
435
+ ],
436
+ });
437
+ }
420
438
  return {
421
439
  fileName: (0, utils_1.getSingleQueryFileName)(table),
422
440
  content: (0, ts_ast_1.getFormattedOutput)(sourceFile),
@@ -428,11 +446,11 @@ await prefetch${(0, utils_1.ucFirst)(singularName)}Query(queryClient, 'uuid-here
428
446
  /**
429
447
  * Generate all query hook files for all tables
430
448
  */
431
- function generateAllQueryHooks(tables) {
449
+ function generateAllQueryHooks(tables, options = {}) {
432
450
  const files = [];
433
451
  for (const table of tables) {
434
- files.push(generateListQueryHook(table));
435
- files.push(generateSingleQueryHook(table));
452
+ files.push(generateListQueryHook(table, options));
453
+ files.push(generateSingleQueryHook(table, options));
436
454
  }
437
455
  return files;
438
456
  }