@constructive-io/graphql-codegen 2.20.0 → 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.
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Tests for React Query optional flag in code generators
3
+ *
4
+ * Verifies that when reactQueryEnabled is false:
5
+ * - Query generators skip React Query imports and hooks
6
+ * - Mutation generators return null (since they require React Query)
7
+ * - Standalone fetch functions are still generated for queries
8
+ */
9
+ import { generateListQueryHook, generateSingleQueryHook, generateAllQueryHooks } from '../../cli/codegen/queries';
10
+ import { generateCreateMutationHook, generateUpdateMutationHook, generateDeleteMutationHook, generateAllMutationHooks } from '../../cli/codegen/mutations';
11
+ import { generateCustomQueryHook, generateAllCustomQueryHooks } from '../../cli/codegen/custom-queries';
12
+ import { generateCustomMutationHook, generateAllCustomMutationHooks } from '../../cli/codegen/custom-mutations';
13
+ // ============================================================================
14
+ // Test Fixtures
15
+ // ============================================================================
16
+ const fieldTypes = {
17
+ uuid: { gqlType: 'UUID', isArray: false },
18
+ string: { gqlType: 'String', isArray: false },
19
+ int: { gqlType: 'Int', isArray: false },
20
+ datetime: { gqlType: 'Datetime', isArray: false },
21
+ };
22
+ const emptyRelations = {
23
+ belongsTo: [],
24
+ hasOne: [],
25
+ hasMany: [],
26
+ manyToMany: [],
27
+ };
28
+ function createTable(partial) {
29
+ return {
30
+ name: partial.name,
31
+ fields: partial.fields ?? [],
32
+ relations: partial.relations ?? emptyRelations,
33
+ query: partial.query,
34
+ inflection: partial.inflection,
35
+ constraints: partial.constraints,
36
+ };
37
+ }
38
+ const userTable = createTable({
39
+ name: 'User',
40
+ fields: [
41
+ { name: 'id', type: fieldTypes.uuid },
42
+ { name: 'email', type: fieldTypes.string },
43
+ { name: 'name', type: fieldTypes.string },
44
+ { name: 'createdAt', type: fieldTypes.datetime },
45
+ ],
46
+ query: {
47
+ all: 'users',
48
+ one: 'user',
49
+ create: 'createUser',
50
+ update: 'updateUser',
51
+ delete: 'deleteUser',
52
+ },
53
+ });
54
+ function createTypeRef(kind, name, ofType) {
55
+ return { kind, name, ofType };
56
+ }
57
+ const sampleQueryOperation = {
58
+ name: 'currentUser',
59
+ kind: 'query',
60
+ args: [],
61
+ returnType: createTypeRef('OBJECT', 'User'),
62
+ description: 'Get the current authenticated user',
63
+ };
64
+ const sampleMutationOperation = {
65
+ name: 'login',
66
+ kind: 'mutation',
67
+ args: [
68
+ { name: 'email', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) },
69
+ { name: 'password', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) },
70
+ ],
71
+ returnType: createTypeRef('OBJECT', 'LoginPayload'),
72
+ description: 'Authenticate user',
73
+ };
74
+ const emptyTypeRegistry = new Map();
75
+ // ============================================================================
76
+ // Tests - Query Generators with reactQueryEnabled: false
77
+ // ============================================================================
78
+ describe('Query generators with reactQueryEnabled: false', () => {
79
+ describe('generateListQueryHook', () => {
80
+ it('should not include React Query imports when disabled', () => {
81
+ const result = generateListQueryHook(userTable, { reactQueryEnabled: false });
82
+ expect(result.content).not.toContain('@tanstack/react-query');
83
+ expect(result.content).not.toContain('useQuery');
84
+ expect(result.content).not.toContain('UseQueryOptions');
85
+ });
86
+ it('should not include useXxxQuery hook when disabled', () => {
87
+ const result = generateListQueryHook(userTable, { reactQueryEnabled: false });
88
+ expect(result.content).not.toContain('export function useUsersQuery');
89
+ });
90
+ it('should not include prefetch function when disabled', () => {
91
+ const result = generateListQueryHook(userTable, { reactQueryEnabled: false });
92
+ expect(result.content).not.toContain('export async function prefetchUsersQuery');
93
+ });
94
+ it('should still include standalone fetch function when disabled', () => {
95
+ const result = generateListQueryHook(userTable, { reactQueryEnabled: false });
96
+ expect(result.content).toContain('export async function fetchUsersQuery');
97
+ });
98
+ it('should still include GraphQL document when disabled', () => {
99
+ const result = generateListQueryHook(userTable, { reactQueryEnabled: false });
100
+ expect(result.content).toContain('usersQueryDocument');
101
+ });
102
+ it('should still include query key factory when disabled', () => {
103
+ const result = generateListQueryHook(userTable, { reactQueryEnabled: false });
104
+ expect(result.content).toContain('usersQueryKey');
105
+ });
106
+ it('should update file header when disabled', () => {
107
+ const result = generateListQueryHook(userTable, { reactQueryEnabled: false });
108
+ expect(result.content).toContain('List query functions for User');
109
+ });
110
+ });
111
+ describe('generateSingleQueryHook', () => {
112
+ it('should not include React Query imports when disabled', () => {
113
+ const result = generateSingleQueryHook(userTable, { reactQueryEnabled: false });
114
+ expect(result.content).not.toContain('@tanstack/react-query');
115
+ expect(result.content).not.toContain('useQuery');
116
+ });
117
+ it('should not include useXxxQuery hook when disabled', () => {
118
+ const result = generateSingleQueryHook(userTable, { reactQueryEnabled: false });
119
+ expect(result.content).not.toContain('export function useUserQuery');
120
+ });
121
+ it('should still include standalone fetch function when disabled', () => {
122
+ const result = generateSingleQueryHook(userTable, { reactQueryEnabled: false });
123
+ expect(result.content).toContain('export async function fetchUserQuery');
124
+ });
125
+ });
126
+ describe('generateAllQueryHooks', () => {
127
+ it('should generate files without React Query when disabled', () => {
128
+ const results = generateAllQueryHooks([userTable], { reactQueryEnabled: false });
129
+ expect(results.length).toBe(2); // list + single
130
+ for (const result of results) {
131
+ expect(result.content).not.toContain('@tanstack/react-query');
132
+ expect(result.content).not.toContain('useQuery');
133
+ }
134
+ });
135
+ });
136
+ });
137
+ // ============================================================================
138
+ // Tests - Query Generators with reactQueryEnabled: true (default)
139
+ // ============================================================================
140
+ describe('Query generators with reactQueryEnabled: true (default)', () => {
141
+ describe('generateListQueryHook', () => {
142
+ it('should include React Query imports by default', () => {
143
+ const result = generateListQueryHook(userTable);
144
+ expect(result.content).toContain('@tanstack/react-query');
145
+ expect(result.content).toContain('useQuery');
146
+ });
147
+ it('should include useXxxQuery hook by default', () => {
148
+ const result = generateListQueryHook(userTable);
149
+ expect(result.content).toContain('export function useUsersQuery');
150
+ });
151
+ it('should include prefetch function by default', () => {
152
+ const result = generateListQueryHook(userTable);
153
+ expect(result.content).toContain('export async function prefetchUsersQuery');
154
+ });
155
+ it('should include standalone fetch function by default', () => {
156
+ const result = generateListQueryHook(userTable);
157
+ expect(result.content).toContain('export async function fetchUsersQuery');
158
+ });
159
+ });
160
+ });
161
+ // ============================================================================
162
+ // Tests - Mutation Generators with reactQueryEnabled: false
163
+ // ============================================================================
164
+ describe('Mutation generators with reactQueryEnabled: false', () => {
165
+ describe('generateCreateMutationHook', () => {
166
+ it('should return null when disabled', () => {
167
+ const result = generateCreateMutationHook(userTable, { reactQueryEnabled: false });
168
+ expect(result).toBeNull();
169
+ });
170
+ });
171
+ describe('generateUpdateMutationHook', () => {
172
+ it('should return null when disabled', () => {
173
+ const result = generateUpdateMutationHook(userTable, { reactQueryEnabled: false });
174
+ expect(result).toBeNull();
175
+ });
176
+ });
177
+ describe('generateDeleteMutationHook', () => {
178
+ it('should return null when disabled', () => {
179
+ const result = generateDeleteMutationHook(userTable, { reactQueryEnabled: false });
180
+ expect(result).toBeNull();
181
+ });
182
+ });
183
+ describe('generateAllMutationHooks', () => {
184
+ it('should return empty array when disabled', () => {
185
+ const results = generateAllMutationHooks([userTable], { reactQueryEnabled: false });
186
+ expect(results).toEqual([]);
187
+ });
188
+ });
189
+ });
190
+ // ============================================================================
191
+ // Tests - Mutation Generators with reactQueryEnabled: true (default)
192
+ // ============================================================================
193
+ describe('Mutation generators with reactQueryEnabled: true (default)', () => {
194
+ describe('generateCreateMutationHook', () => {
195
+ it('should return mutation file by default', () => {
196
+ const result = generateCreateMutationHook(userTable);
197
+ expect(result).not.toBeNull();
198
+ expect(result.content).toContain('useMutation');
199
+ });
200
+ });
201
+ describe('generateAllMutationHooks', () => {
202
+ it('should return mutation files by default', () => {
203
+ const results = generateAllMutationHooks([userTable]);
204
+ expect(results.length).toBeGreaterThan(0);
205
+ });
206
+ });
207
+ });
208
+ // ============================================================================
209
+ // Tests - Custom Query Generators with reactQueryEnabled: false
210
+ // ============================================================================
211
+ describe('Custom query generators with reactQueryEnabled: false', () => {
212
+ describe('generateCustomQueryHook', () => {
213
+ it('should not include React Query imports when disabled', () => {
214
+ const result = generateCustomQueryHook({
215
+ operation: sampleQueryOperation,
216
+ typeRegistry: emptyTypeRegistry,
217
+ reactQueryEnabled: false,
218
+ });
219
+ expect(result.content).not.toContain('@tanstack/react-query');
220
+ expect(result.content).not.toContain('useQuery');
221
+ });
222
+ it('should not include useXxxQuery hook when disabled', () => {
223
+ const result = generateCustomQueryHook({
224
+ operation: sampleQueryOperation,
225
+ typeRegistry: emptyTypeRegistry,
226
+ reactQueryEnabled: false,
227
+ });
228
+ expect(result.content).not.toContain('export function useCurrentUserQuery');
229
+ });
230
+ it('should still include standalone fetch function when disabled', () => {
231
+ const result = generateCustomQueryHook({
232
+ operation: sampleQueryOperation,
233
+ typeRegistry: emptyTypeRegistry,
234
+ reactQueryEnabled: false,
235
+ });
236
+ expect(result.content).toContain('export async function fetchCurrentUserQuery');
237
+ });
238
+ });
239
+ describe('generateAllCustomQueryHooks', () => {
240
+ it('should generate files without React Query when disabled', () => {
241
+ const results = generateAllCustomQueryHooks({
242
+ operations: [sampleQueryOperation],
243
+ typeRegistry: emptyTypeRegistry,
244
+ reactQueryEnabled: false,
245
+ });
246
+ expect(results.length).toBe(1);
247
+ expect(results[0].content).not.toContain('@tanstack/react-query');
248
+ });
249
+ });
250
+ });
251
+ // ============================================================================
252
+ // Tests - Custom Mutation Generators with reactQueryEnabled: false
253
+ // ============================================================================
254
+ describe('Custom mutation generators with reactQueryEnabled: false', () => {
255
+ describe('generateCustomMutationHook', () => {
256
+ it('should return null when disabled', () => {
257
+ const result = generateCustomMutationHook({
258
+ operation: sampleMutationOperation,
259
+ typeRegistry: emptyTypeRegistry,
260
+ reactQueryEnabled: false,
261
+ });
262
+ expect(result).toBeNull();
263
+ });
264
+ });
265
+ describe('generateAllCustomMutationHooks', () => {
266
+ it('should return empty array when disabled', () => {
267
+ const results = generateAllCustomMutationHooks({
268
+ operations: [sampleMutationOperation],
269
+ typeRegistry: emptyTypeRegistry,
270
+ reactQueryEnabled: false,
271
+ });
272
+ expect(results).toEqual([]);
273
+ });
274
+ });
275
+ });
276
+ // ============================================================================
277
+ // Tests - Custom Mutation Generators with reactQueryEnabled: true (default)
278
+ // ============================================================================
279
+ describe('Custom mutation generators with reactQueryEnabled: true (default)', () => {
280
+ describe('generateCustomMutationHook', () => {
281
+ it('should return mutation file by default', () => {
282
+ const result = generateCustomMutationHook({
283
+ operation: sampleMutationOperation,
284
+ typeRegistry: emptyTypeRegistry,
285
+ });
286
+ expect(result).not.toBeNull();
287
+ expect(result.content).toContain('useMutation');
288
+ });
289
+ });
290
+ });
@@ -21,18 +21,24 @@ export interface GenerateCustomMutationHookOptions {
21
21
  typeRegistry: TypeRegistry;
22
22
  maxDepth?: number;
23
23
  skipQueryField?: boolean;
24
+ /** Whether to generate React Query hooks (default: true for backwards compatibility) */
25
+ reactQueryEnabled?: boolean;
24
26
  }
25
27
  /**
26
28
  * Generate a custom mutation hook file
29
+ * When reactQueryEnabled is false, returns null since mutations require React Query
27
30
  */
28
- export declare function generateCustomMutationHook(options: GenerateCustomMutationHookOptions): GeneratedCustomMutationFile;
31
+ export declare function generateCustomMutationHook(options: GenerateCustomMutationHookOptions): GeneratedCustomMutationFile | null;
29
32
  export interface GenerateAllCustomMutationHooksOptions {
30
33
  operations: CleanOperation[];
31
34
  typeRegistry: TypeRegistry;
32
35
  maxDepth?: number;
33
36
  skipQueryField?: boolean;
37
+ /** Whether to generate React Query hooks (default: true for backwards compatibility) */
38
+ reactQueryEnabled?: boolean;
34
39
  }
35
40
  /**
36
41
  * Generate all custom mutation hook files
42
+ * When reactQueryEnabled is false, returns empty array since mutations require React Query
37
43
  */
38
44
  export declare function generateAllCustomMutationHooks(options: GenerateAllCustomMutationHooksOptions): GeneratedCustomMutationFile[];
@@ -3,9 +3,14 @@ import { buildCustomMutationString } from './schema-gql-ast';
3
3
  import { typeRefToTsType, isTypeRequired, getOperationHookName, getOperationFileName, getOperationVariablesTypeName, getOperationResultTypeName, getDocumentConstName, } from './type-resolver';
4
4
  /**
5
5
  * Generate a custom mutation hook file
6
+ * When reactQueryEnabled is false, returns null since mutations require React Query
6
7
  */
7
8
  export function generateCustomMutationHook(options) {
8
- const { operation } = options;
9
+ const { operation, reactQueryEnabled = true } = options;
10
+ // Mutations require React Query - skip generation when disabled
11
+ if (!reactQueryEnabled) {
12
+ return null;
13
+ }
9
14
  try {
10
15
  return generateCustomMutationHookInternal(options);
11
16
  }
@@ -131,9 +136,10 @@ function generateHookBody(operation, documentConstName, variablesTypeName, resul
131
136
  }
132
137
  /**
133
138
  * Generate all custom mutation hook files
139
+ * When reactQueryEnabled is false, returns empty array since mutations require React Query
134
140
  */
135
141
  export function generateAllCustomMutationHooks(options) {
136
- const { operations, typeRegistry, maxDepth = 2, skipQueryField = true } = options;
142
+ const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true } = options;
137
143
  return operations
138
144
  .filter((op) => op.kind === 'mutation')
139
145
  .map((operation) => generateCustomMutationHook({
@@ -141,5 +147,7 @@ export function generateAllCustomMutationHooks(options) {
141
147
  typeRegistry,
142
148
  maxDepth,
143
149
  skipQueryField,
144
- }));
150
+ reactQueryEnabled,
151
+ }))
152
+ .filter((result) => result !== null);
145
153
  }
@@ -21,6 +21,8 @@ export interface GenerateCustomQueryHookOptions {
21
21
  typeRegistry: TypeRegistry;
22
22
  maxDepth?: number;
23
23
  skipQueryField?: boolean;
24
+ /** Whether to generate React Query hooks (default: true for backwards compatibility) */
25
+ reactQueryEnabled?: boolean;
24
26
  }
25
27
  /**
26
28
  * Generate a custom query hook file
@@ -31,6 +33,8 @@ export interface GenerateAllCustomQueryHooksOptions {
31
33
  typeRegistry: TypeRegistry;
32
34
  maxDepth?: number;
33
35
  skipQueryField?: boolean;
36
+ /** Whether to generate React Query hooks (default: true for backwards compatibility) */
37
+ reactQueryEnabled?: boolean;
34
38
  }
35
39
  /**
36
40
  * Generate all custom query hook files
@@ -6,7 +6,7 @@ import { ucFirst } from './utils';
6
6
  * Generate a custom query hook file
7
7
  */
8
8
  export function generateCustomQueryHook(options) {
9
- const { operation, typeRegistry, maxDepth = 2, skipQueryField = true } = options;
9
+ const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true } = options;
10
10
  const project = createProject();
11
11
  const hookName = getOperationHookName(operation.name, 'query');
12
12
  const fileName = getOperationFileName(operation.name, 'query');
@@ -23,20 +23,25 @@ export function generateCustomQueryHook(options) {
23
23
  });
24
24
  const sourceFile = createSourceFile(project, fileName);
25
25
  // Add file header
26
- sourceFile.insertText(0, createFileHeader(`Custom query hook for ${operation.name}`) + '\n\n');
27
- // Add imports
28
- sourceFile.addImportDeclarations([
29
- createImport({
26
+ const headerText = reactQueryEnabled
27
+ ? `Custom query hook for ${operation.name}`
28
+ : `Custom query functions for ${operation.name}`;
29
+ sourceFile.insertText(0, createFileHeader(headerText) + '\n\n');
30
+ // Add imports - conditionally include React Query imports
31
+ const imports = [];
32
+ if (reactQueryEnabled) {
33
+ imports.push(createImport({
30
34
  moduleSpecifier: '@tanstack/react-query',
31
35
  namedImports: ['useQuery'],
32
36
  typeOnlyNamedImports: ['UseQueryOptions', 'QueryClient'],
33
- }),
34
- createImport({
35
- moduleSpecifier: '../client',
36
- namedImports: ['execute'],
37
- typeOnlyNamedImports: ['ExecuteOptions'],
38
- }),
39
- ]);
37
+ }));
38
+ }
39
+ imports.push(createImport({
40
+ moduleSpecifier: '../client',
41
+ namedImports: ['execute'],
42
+ typeOnlyNamedImports: ['ExecuteOptions'],
43
+ }));
44
+ sourceFile.addImportDeclarations(imports);
40
45
  // Add query document constant
41
46
  sourceFile.addVariableStatement(createConst(documentConstName, '`\n' + queryDocument + '`', {
42
47
  docs: ['GraphQL query document'],
@@ -62,17 +67,19 @@ export function generateCustomQueryHook(options) {
62
67
  docs: ['Query key factory for caching'],
63
68
  }));
64
69
  }
65
- // Generate hook function
66
- const hookParams = generateHookParameters(operation, variablesTypeName, resultTypeName);
67
- const hookBody = generateHookBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName);
68
- const hookDoc = generateHookDoc(operation, hookName);
69
- sourceFile.addFunction({
70
- name: hookName,
71
- isExported: true,
72
- parameters: hookParams,
73
- statements: hookBody,
74
- docs: [{ description: hookDoc }],
75
- });
70
+ // Generate hook function (only if React Query is enabled)
71
+ if (reactQueryEnabled) {
72
+ const hookParams = generateHookParameters(operation, variablesTypeName, resultTypeName);
73
+ const hookBody = generateHookBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName);
74
+ const hookDoc = generateHookDoc(operation, hookName);
75
+ sourceFile.addFunction({
76
+ name: hookName,
77
+ isExported: true,
78
+ parameters: hookParams,
79
+ statements: hookBody,
80
+ docs: [{ description: hookDoc }],
81
+ });
82
+ }
76
83
  // Add standalone functions section
77
84
  sourceFile.addStatements('\n// ============================================================================');
78
85
  sourceFile.addStatements('// Standalone Functions (non-React)');
@@ -91,20 +98,22 @@ export function generateCustomQueryHook(options) {
91
98
  statements: fetchBody,
92
99
  docs: [{ description: fetchDoc }],
93
100
  });
94
- // Generate prefetch function
95
- const prefetchFnName = `prefetch${ucFirst(operation.name)}Query`;
96
- const prefetchParams = generatePrefetchParameters(operation, variablesTypeName);
97
- const prefetchBody = generatePrefetchBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName);
98
- const prefetchDoc = generatePrefetchDoc(operation, prefetchFnName);
99
- sourceFile.addFunction({
100
- name: prefetchFnName,
101
- isExported: true,
102
- isAsync: true,
103
- parameters: prefetchParams,
104
- returnType: 'Promise<void>',
105
- statements: prefetchBody,
106
- docs: [{ description: prefetchDoc }],
107
- });
101
+ // Generate prefetch function (only if React Query is enabled)
102
+ if (reactQueryEnabled) {
103
+ const prefetchFnName = `prefetch${ucFirst(operation.name)}Query`;
104
+ const prefetchParams = generatePrefetchParameters(operation, variablesTypeName);
105
+ const prefetchBody = generatePrefetchBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName);
106
+ const prefetchDoc = generatePrefetchDoc(operation, prefetchFnName);
107
+ sourceFile.addFunction({
108
+ name: prefetchFnName,
109
+ isExported: true,
110
+ isAsync: true,
111
+ parameters: prefetchParams,
112
+ returnType: 'Promise<void>',
113
+ statements: prefetchBody,
114
+ docs: [{ description: prefetchDoc }],
115
+ });
116
+ }
108
117
  return {
109
118
  fileName,
110
119
  content: getFormattedOutput(sourceFile),
@@ -342,7 +351,7 @@ await ${fnName}(queryClient);
342
351
  * Generate all custom query hook files
343
352
  */
344
353
  export function generateAllCustomQueryHooks(options) {
345
- const { operations, typeRegistry, maxDepth = 2, skipQueryField = true } = options;
354
+ const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true } = options;
346
355
  return operations
347
356
  .filter((op) => op.kind === 'query')
348
357
  .map((operation) => generateCustomQueryHook({
@@ -350,5 +359,6 @@ export function generateAllCustomQueryHooks(options) {
350
359
  typeRegistry,
351
360
  maxDepth,
352
361
  skipQueryField,
362
+ reactQueryEnabled,
353
363
  }));
354
364
  }
@@ -23,6 +23,7 @@ export function generate(options) {
23
23
  // Extract codegen options
24
24
  const maxDepth = config.codegen.maxFieldDepth;
25
25
  const skipQueryField = config.codegen.skipQueryField;
26
+ const reactQueryEnabled = config.reactQuery.enabled;
26
27
  // 1. Generate client.ts
27
28
  files.push({
28
29
  path: 'client.ts',
@@ -34,7 +35,7 @@ export function generate(options) {
34
35
  content: generateTypesFile(tables),
35
36
  });
36
37
  // 3. Generate table-based query hooks (queries/*.ts)
37
- const queryHooks = generateAllQueryHooks(tables);
38
+ const queryHooks = generateAllQueryHooks(tables, { reactQueryEnabled });
38
39
  for (const hook of queryHooks) {
39
40
  files.push({
40
41
  path: `queries/${hook.fileName}`,
@@ -49,6 +50,7 @@ export function generate(options) {
49
50
  typeRegistry: customOperations.typeRegistry,
50
51
  maxDepth,
51
52
  skipQueryField,
53
+ reactQueryEnabled,
52
54
  });
53
55
  for (const hook of customQueryHooks) {
54
56
  files.push({
@@ -65,7 +67,7 @@ export function generate(options) {
65
67
  : generateQueriesBarrel(tables),
66
68
  });
67
69
  // 6. Generate table-based mutation hooks (mutations/*.ts)
68
- const mutationHooks = generateAllMutationHooks(tables);
70
+ const mutationHooks = generateAllMutationHooks(tables, { reactQueryEnabled });
69
71
  for (const hook of mutationHooks) {
70
72
  files.push({
71
73
  path: `mutations/${hook.fileName}`,
@@ -80,6 +82,7 @@ export function generate(options) {
80
82
  typeRegistry: customOperations.typeRegistry,
81
83
  maxDepth,
82
84
  skipQueryField,
85
+ reactQueryEnabled,
83
86
  });
84
87
  for (const hook of customMutationHooks) {
85
88
  files.push({
@@ -12,19 +12,27 @@ export interface GeneratedMutationFile {
12
12
  fileName: string;
13
13
  content: string;
14
14
  }
15
+ export interface MutationGeneratorOptions {
16
+ /** Whether to generate React Query hooks (default: true for backwards compatibility) */
17
+ reactQueryEnabled?: boolean;
18
+ }
15
19
  /**
16
20
  * Generate create mutation hook file content using AST
21
+ * When reactQueryEnabled is false, returns null since mutations require React Query
17
22
  */
18
- export declare function generateCreateMutationHook(table: CleanTable): GeneratedMutationFile;
23
+ export declare function generateCreateMutationHook(table: CleanTable, options?: MutationGeneratorOptions): GeneratedMutationFile | null;
19
24
  /**
20
25
  * Generate update mutation hook file content using AST
26
+ * When reactQueryEnabled is false, returns null since mutations require React Query
21
27
  */
22
- export declare function generateUpdateMutationHook(table: CleanTable): GeneratedMutationFile | null;
28
+ export declare function generateUpdateMutationHook(table: CleanTable, options?: MutationGeneratorOptions): GeneratedMutationFile | null;
23
29
  /**
24
30
  * Generate delete mutation hook file content using AST
31
+ * When reactQueryEnabled is false, returns null since mutations require React Query
25
32
  */
26
- export declare function generateDeleteMutationHook(table: CleanTable): GeneratedMutationFile | null;
33
+ export declare function generateDeleteMutationHook(table: CleanTable, options?: MutationGeneratorOptions): GeneratedMutationFile | null;
27
34
  /**
28
35
  * Generate all mutation hook files for all tables
36
+ * When reactQueryEnabled is false, returns empty array since mutations require React Query
29
37
  */
30
- export declare function generateAllMutationHooks(tables: CleanTable[]): GeneratedMutationFile[];
38
+ export declare function generateAllMutationHooks(tables: CleanTable[], options?: MutationGeneratorOptions): GeneratedMutationFile[];
@@ -6,8 +6,14 @@ import { getTableNames, getCreateMutationHookName, getUpdateMutationHookName, ge
6
6
  // ============================================================================
7
7
  /**
8
8
  * Generate create mutation hook file content using AST
9
+ * When reactQueryEnabled is false, returns null since mutations require React Query
9
10
  */
10
- export function generateCreateMutationHook(table) {
11
+ export function generateCreateMutationHook(table, options = {}) {
12
+ const { reactQueryEnabled = true } = options;
13
+ // Mutations require React Query - skip generation when disabled
14
+ if (!reactQueryEnabled) {
15
+ return null;
16
+ }
11
17
  const project = createProject();
12
18
  const { typeName, singularName } = getTableNames(table);
13
19
  const hookName = getCreateMutationHookName(table);
@@ -137,8 +143,14 @@ mutate({
137
143
  // ============================================================================
138
144
  /**
139
145
  * Generate update mutation hook file content using AST
146
+ * When reactQueryEnabled is false, returns null since mutations require React Query
140
147
  */
141
- export function generateUpdateMutationHook(table) {
148
+ export function generateUpdateMutationHook(table, options = {}) {
149
+ const { reactQueryEnabled = true } = options;
150
+ // Mutations require React Query - skip generation when disabled
151
+ if (!reactQueryEnabled) {
152
+ return null;
153
+ }
142
154
  // Check if update mutation exists
143
155
  if (table.query?.update === null) {
144
156
  return null;
@@ -272,8 +284,14 @@ mutate({
272
284
  // ============================================================================
273
285
  /**
274
286
  * Generate delete mutation hook file content using AST
287
+ * When reactQueryEnabled is false, returns null since mutations require React Query
275
288
  */
276
- export function generateDeleteMutationHook(table) {
289
+ export function generateDeleteMutationHook(table, options = {}) {
290
+ const { reactQueryEnabled = true } = options;
291
+ // Mutations require React Query - skip generation when disabled
292
+ if (!reactQueryEnabled) {
293
+ return null;
294
+ }
277
295
  // Check if delete mutation exists
278
296
  if (table.query?.delete === null) {
279
297
  return null;
@@ -386,16 +404,20 @@ mutate({
386
404
  // ============================================================================
387
405
  /**
388
406
  * Generate all mutation hook files for all tables
407
+ * When reactQueryEnabled is false, returns empty array since mutations require React Query
389
408
  */
390
- export function generateAllMutationHooks(tables) {
409
+ export function generateAllMutationHooks(tables, options = {}) {
391
410
  const files = [];
392
411
  for (const table of tables) {
393
- files.push(generateCreateMutationHook(table));
394
- const updateHook = generateUpdateMutationHook(table);
412
+ const createHook = generateCreateMutationHook(table, options);
413
+ if (createHook) {
414
+ files.push(createHook);
415
+ }
416
+ const updateHook = generateUpdateMutationHook(table, options);
395
417
  if (updateHook) {
396
418
  files.push(updateHook);
397
419
  }
398
- const deleteHook = generateDeleteMutationHook(table);
420
+ const deleteHook = generateDeleteMutationHook(table, options);
399
421
  if (deleteHook) {
400
422
  files.push(deleteHook);
401
423
  }