@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.
package/README.md CHANGED
@@ -1,4 +1,16 @@
1
- # @constructive-io/graphql-sdk
1
+ # @constructive-io/graphql-codegen
2
+
3
+ <p align="center" width="100%">
4
+ <img height="250" src="https://raw.githubusercontent.com/constructive-io/constructive/refs/heads/main/assets/outline-logo.svg" />
5
+ </p>
6
+
7
+ <p align="center" width="100%">
8
+ <a href="https://github.com/constructive-io/constructive/actions/workflows/run-tests.yaml">
9
+ <img height="20" src="https://github.com/constructive-io/constructive/actions/workflows/run-tests.yaml/badge.svg" />
10
+ </a>
11
+ <a href="https://github.com/constructive-io/constructive/blob/main/LICENSE"><img height="20" src="https://img.shields.io/badge/license-MIT-blue.svg"/></a>
12
+ <a href="https://www.npmjs.com/package/@constructive-io/graphql-codegen"><img height="20" src="https://img.shields.io/github/package-json/v/constructive-io/constructive?filename=graphql%2Fcodegen%2Fpackage.json"/></a>
13
+ </p>
2
14
 
3
15
  CLI-based GraphQL SDK generator for PostGraphile endpoints. Generate type-safe React Query hooks or a Prisma-like ORM client from your GraphQL schema.
4
16
 
@@ -39,7 +51,7 @@ CLI-based GraphQL SDK generator for PostGraphile endpoints. Generate type-safe R
39
51
  ## Installation
40
52
 
41
53
  ```bash
42
- pnpm add @constructive-io/graphql-sdk
54
+ pnpm add @constructive-io/graphql-codegen
43
55
  ```
44
56
 
45
57
  ## Quick Start
@@ -53,7 +65,7 @@ npx graphql-sdk init
53
65
  Creates a `graphql-sdk.config.ts` file:
54
66
 
55
67
  ```typescript
56
- import { defineConfig } from '@constructive-io/graphql-sdk';
68
+ import { defineConfig } from '@constructive-io/graphql-codegen';
57
69
 
58
70
  export default defineConfig({
59
71
  endpoint: 'https://api.example.com/graphql',
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,292 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Tests for React Query optional flag in code generators
5
+ *
6
+ * Verifies that when reactQueryEnabled is false:
7
+ * - Query generators skip React Query imports and hooks
8
+ * - Mutation generators return null (since they require React Query)
9
+ * - Standalone fetch functions are still generated for queries
10
+ */
11
+ const queries_1 = require("../../cli/codegen/queries");
12
+ const mutations_1 = require("../../cli/codegen/mutations");
13
+ const custom_queries_1 = require("../../cli/codegen/custom-queries");
14
+ const custom_mutations_1 = require("../../cli/codegen/custom-mutations");
15
+ // ============================================================================
16
+ // Test Fixtures
17
+ // ============================================================================
18
+ const fieldTypes = {
19
+ uuid: { gqlType: 'UUID', isArray: false },
20
+ string: { gqlType: 'String', isArray: false },
21
+ int: { gqlType: 'Int', isArray: false },
22
+ datetime: { gqlType: 'Datetime', isArray: false },
23
+ };
24
+ const emptyRelations = {
25
+ belongsTo: [],
26
+ hasOne: [],
27
+ hasMany: [],
28
+ manyToMany: [],
29
+ };
30
+ function createTable(partial) {
31
+ return {
32
+ name: partial.name,
33
+ fields: partial.fields ?? [],
34
+ relations: partial.relations ?? emptyRelations,
35
+ query: partial.query,
36
+ inflection: partial.inflection,
37
+ constraints: partial.constraints,
38
+ };
39
+ }
40
+ const userTable = createTable({
41
+ name: 'User',
42
+ fields: [
43
+ { name: 'id', type: fieldTypes.uuid },
44
+ { name: 'email', type: fieldTypes.string },
45
+ { name: 'name', type: fieldTypes.string },
46
+ { name: 'createdAt', type: fieldTypes.datetime },
47
+ ],
48
+ query: {
49
+ all: 'users',
50
+ one: 'user',
51
+ create: 'createUser',
52
+ update: 'updateUser',
53
+ delete: 'deleteUser',
54
+ },
55
+ });
56
+ function createTypeRef(kind, name, ofType) {
57
+ return { kind, name, ofType };
58
+ }
59
+ const sampleQueryOperation = {
60
+ name: 'currentUser',
61
+ kind: 'query',
62
+ args: [],
63
+ returnType: createTypeRef('OBJECT', 'User'),
64
+ description: 'Get the current authenticated user',
65
+ };
66
+ const sampleMutationOperation = {
67
+ name: 'login',
68
+ kind: 'mutation',
69
+ args: [
70
+ { name: 'email', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) },
71
+ { name: 'password', type: createTypeRef('NON_NULL', null, createTypeRef('SCALAR', 'String')) },
72
+ ],
73
+ returnType: createTypeRef('OBJECT', 'LoginPayload'),
74
+ description: 'Authenticate user',
75
+ };
76
+ const emptyTypeRegistry = new Map();
77
+ // ============================================================================
78
+ // Tests - Query Generators with reactQueryEnabled: false
79
+ // ============================================================================
80
+ describe('Query generators with reactQueryEnabled: false', () => {
81
+ describe('generateListQueryHook', () => {
82
+ it('should not include React Query imports when disabled', () => {
83
+ const result = (0, queries_1.generateListQueryHook)(userTable, { reactQueryEnabled: false });
84
+ expect(result.content).not.toContain('@tanstack/react-query');
85
+ expect(result.content).not.toContain('useQuery');
86
+ expect(result.content).not.toContain('UseQueryOptions');
87
+ });
88
+ it('should not include useXxxQuery hook when disabled', () => {
89
+ const result = (0, queries_1.generateListQueryHook)(userTable, { reactQueryEnabled: false });
90
+ expect(result.content).not.toContain('export function useUsersQuery');
91
+ });
92
+ it('should not include prefetch function when disabled', () => {
93
+ const result = (0, queries_1.generateListQueryHook)(userTable, { reactQueryEnabled: false });
94
+ expect(result.content).not.toContain('export async function prefetchUsersQuery');
95
+ });
96
+ it('should still include standalone fetch function when disabled', () => {
97
+ const result = (0, queries_1.generateListQueryHook)(userTable, { reactQueryEnabled: false });
98
+ expect(result.content).toContain('export async function fetchUsersQuery');
99
+ });
100
+ it('should still include GraphQL document when disabled', () => {
101
+ const result = (0, queries_1.generateListQueryHook)(userTable, { reactQueryEnabled: false });
102
+ expect(result.content).toContain('usersQueryDocument');
103
+ });
104
+ it('should still include query key factory when disabled', () => {
105
+ const result = (0, queries_1.generateListQueryHook)(userTable, { reactQueryEnabled: false });
106
+ expect(result.content).toContain('usersQueryKey');
107
+ });
108
+ it('should update file header when disabled', () => {
109
+ const result = (0, queries_1.generateListQueryHook)(userTable, { reactQueryEnabled: false });
110
+ expect(result.content).toContain('List query functions for User');
111
+ });
112
+ });
113
+ describe('generateSingleQueryHook', () => {
114
+ it('should not include React Query imports when disabled', () => {
115
+ const result = (0, queries_1.generateSingleQueryHook)(userTable, { reactQueryEnabled: false });
116
+ expect(result.content).not.toContain('@tanstack/react-query');
117
+ expect(result.content).not.toContain('useQuery');
118
+ });
119
+ it('should not include useXxxQuery hook when disabled', () => {
120
+ const result = (0, queries_1.generateSingleQueryHook)(userTable, { reactQueryEnabled: false });
121
+ expect(result.content).not.toContain('export function useUserQuery');
122
+ });
123
+ it('should still include standalone fetch function when disabled', () => {
124
+ const result = (0, queries_1.generateSingleQueryHook)(userTable, { reactQueryEnabled: false });
125
+ expect(result.content).toContain('export async function fetchUserQuery');
126
+ });
127
+ });
128
+ describe('generateAllQueryHooks', () => {
129
+ it('should generate files without React Query when disabled', () => {
130
+ const results = (0, queries_1.generateAllQueryHooks)([userTable], { reactQueryEnabled: false });
131
+ expect(results.length).toBe(2); // list + single
132
+ for (const result of results) {
133
+ expect(result.content).not.toContain('@tanstack/react-query');
134
+ expect(result.content).not.toContain('useQuery');
135
+ }
136
+ });
137
+ });
138
+ });
139
+ // ============================================================================
140
+ // Tests - Query Generators with reactQueryEnabled: true (default)
141
+ // ============================================================================
142
+ describe('Query generators with reactQueryEnabled: true (default)', () => {
143
+ describe('generateListQueryHook', () => {
144
+ it('should include React Query imports by default', () => {
145
+ const result = (0, queries_1.generateListQueryHook)(userTable);
146
+ expect(result.content).toContain('@tanstack/react-query');
147
+ expect(result.content).toContain('useQuery');
148
+ });
149
+ it('should include useXxxQuery hook by default', () => {
150
+ const result = (0, queries_1.generateListQueryHook)(userTable);
151
+ expect(result.content).toContain('export function useUsersQuery');
152
+ });
153
+ it('should include prefetch function by default', () => {
154
+ const result = (0, queries_1.generateListQueryHook)(userTable);
155
+ expect(result.content).toContain('export async function prefetchUsersQuery');
156
+ });
157
+ it('should include standalone fetch function by default', () => {
158
+ const result = (0, queries_1.generateListQueryHook)(userTable);
159
+ expect(result.content).toContain('export async function fetchUsersQuery');
160
+ });
161
+ });
162
+ });
163
+ // ============================================================================
164
+ // Tests - Mutation Generators with reactQueryEnabled: false
165
+ // ============================================================================
166
+ describe('Mutation generators with reactQueryEnabled: false', () => {
167
+ describe('generateCreateMutationHook', () => {
168
+ it('should return null when disabled', () => {
169
+ const result = (0, mutations_1.generateCreateMutationHook)(userTable, { reactQueryEnabled: false });
170
+ expect(result).toBeNull();
171
+ });
172
+ });
173
+ describe('generateUpdateMutationHook', () => {
174
+ it('should return null when disabled', () => {
175
+ const result = (0, mutations_1.generateUpdateMutationHook)(userTable, { reactQueryEnabled: false });
176
+ expect(result).toBeNull();
177
+ });
178
+ });
179
+ describe('generateDeleteMutationHook', () => {
180
+ it('should return null when disabled', () => {
181
+ const result = (0, mutations_1.generateDeleteMutationHook)(userTable, { reactQueryEnabled: false });
182
+ expect(result).toBeNull();
183
+ });
184
+ });
185
+ describe('generateAllMutationHooks', () => {
186
+ it('should return empty array when disabled', () => {
187
+ const results = (0, mutations_1.generateAllMutationHooks)([userTable], { reactQueryEnabled: false });
188
+ expect(results).toEqual([]);
189
+ });
190
+ });
191
+ });
192
+ // ============================================================================
193
+ // Tests - Mutation Generators with reactQueryEnabled: true (default)
194
+ // ============================================================================
195
+ describe('Mutation generators with reactQueryEnabled: true (default)', () => {
196
+ describe('generateCreateMutationHook', () => {
197
+ it('should return mutation file by default', () => {
198
+ const result = (0, mutations_1.generateCreateMutationHook)(userTable);
199
+ expect(result).not.toBeNull();
200
+ expect(result.content).toContain('useMutation');
201
+ });
202
+ });
203
+ describe('generateAllMutationHooks', () => {
204
+ it('should return mutation files by default', () => {
205
+ const results = (0, mutations_1.generateAllMutationHooks)([userTable]);
206
+ expect(results.length).toBeGreaterThan(0);
207
+ });
208
+ });
209
+ });
210
+ // ============================================================================
211
+ // Tests - Custom Query Generators with reactQueryEnabled: false
212
+ // ============================================================================
213
+ describe('Custom query generators with reactQueryEnabled: false', () => {
214
+ describe('generateCustomQueryHook', () => {
215
+ it('should not include React Query imports when disabled', () => {
216
+ const result = (0, custom_queries_1.generateCustomQueryHook)({
217
+ operation: sampleQueryOperation,
218
+ typeRegistry: emptyTypeRegistry,
219
+ reactQueryEnabled: false,
220
+ });
221
+ expect(result.content).not.toContain('@tanstack/react-query');
222
+ expect(result.content).not.toContain('useQuery');
223
+ });
224
+ it('should not include useXxxQuery hook when disabled', () => {
225
+ const result = (0, custom_queries_1.generateCustomQueryHook)({
226
+ operation: sampleQueryOperation,
227
+ typeRegistry: emptyTypeRegistry,
228
+ reactQueryEnabled: false,
229
+ });
230
+ expect(result.content).not.toContain('export function useCurrentUserQuery');
231
+ });
232
+ it('should still include standalone fetch function when disabled', () => {
233
+ const result = (0, custom_queries_1.generateCustomQueryHook)({
234
+ operation: sampleQueryOperation,
235
+ typeRegistry: emptyTypeRegistry,
236
+ reactQueryEnabled: false,
237
+ });
238
+ expect(result.content).toContain('export async function fetchCurrentUserQuery');
239
+ });
240
+ });
241
+ describe('generateAllCustomQueryHooks', () => {
242
+ it('should generate files without React Query when disabled', () => {
243
+ const results = (0, custom_queries_1.generateAllCustomQueryHooks)({
244
+ operations: [sampleQueryOperation],
245
+ typeRegistry: emptyTypeRegistry,
246
+ reactQueryEnabled: false,
247
+ });
248
+ expect(results.length).toBe(1);
249
+ expect(results[0].content).not.toContain('@tanstack/react-query');
250
+ });
251
+ });
252
+ });
253
+ // ============================================================================
254
+ // Tests - Custom Mutation Generators with reactQueryEnabled: false
255
+ // ============================================================================
256
+ describe('Custom mutation generators with reactQueryEnabled: false', () => {
257
+ describe('generateCustomMutationHook', () => {
258
+ it('should return null when disabled', () => {
259
+ const result = (0, custom_mutations_1.generateCustomMutationHook)({
260
+ operation: sampleMutationOperation,
261
+ typeRegistry: emptyTypeRegistry,
262
+ reactQueryEnabled: false,
263
+ });
264
+ expect(result).toBeNull();
265
+ });
266
+ });
267
+ describe('generateAllCustomMutationHooks', () => {
268
+ it('should return empty array when disabled', () => {
269
+ const results = (0, custom_mutations_1.generateAllCustomMutationHooks)({
270
+ operations: [sampleMutationOperation],
271
+ typeRegistry: emptyTypeRegistry,
272
+ reactQueryEnabled: false,
273
+ });
274
+ expect(results).toEqual([]);
275
+ });
276
+ });
277
+ });
278
+ // ============================================================================
279
+ // Tests - Custom Mutation Generators with reactQueryEnabled: true (default)
280
+ // ============================================================================
281
+ describe('Custom mutation generators with reactQueryEnabled: true (default)', () => {
282
+ describe('generateCustomMutationHook', () => {
283
+ it('should return mutation file by default', () => {
284
+ const result = (0, custom_mutations_1.generateCustomMutationHook)({
285
+ operation: sampleMutationOperation,
286
+ typeRegistry: emptyTypeRegistry,
287
+ });
288
+ expect(result).not.toBeNull();
289
+ expect(result.content).toContain('useMutation');
290
+ });
291
+ });
292
+ });
@@ -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[];
@@ -7,9 +7,14 @@ const schema_gql_ast_1 = require("./schema-gql-ast");
7
7
  const type_resolver_1 = require("./type-resolver");
8
8
  /**
9
9
  * Generate a custom mutation hook file
10
+ * When reactQueryEnabled is false, returns null since mutations require React Query
10
11
  */
11
12
  function generateCustomMutationHook(options) {
12
- const { operation } = options;
13
+ const { operation, reactQueryEnabled = true } = options;
14
+ // Mutations require React Query - skip generation when disabled
15
+ if (!reactQueryEnabled) {
16
+ return null;
17
+ }
13
18
  try {
14
19
  return generateCustomMutationHookInternal(options);
15
20
  }
@@ -135,9 +140,10 @@ function generateHookBody(operation, documentConstName, variablesTypeName, resul
135
140
  }
136
141
  /**
137
142
  * Generate all custom mutation hook files
143
+ * When reactQueryEnabled is false, returns empty array since mutations require React Query
138
144
  */
139
145
  function generateAllCustomMutationHooks(options) {
140
- const { operations, typeRegistry, maxDepth = 2, skipQueryField = true } = options;
146
+ const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true } = options;
141
147
  return operations
142
148
  .filter((op) => op.kind === 'mutation')
143
149
  .map((operation) => generateCustomMutationHook({
@@ -145,5 +151,7 @@ function generateAllCustomMutationHooks(options) {
145
151
  typeRegistry,
146
152
  maxDepth,
147
153
  skipQueryField,
148
- }));
154
+ reactQueryEnabled,
155
+ }))
156
+ .filter((result) => result !== null);
149
157
  }
@@ -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
@@ -10,7 +10,7 @@ const utils_1 = require("./utils");
10
10
  * Generate a custom query hook file
11
11
  */
12
12
  function generateCustomQueryHook(options) {
13
- const { operation, typeRegistry, maxDepth = 2, skipQueryField = true } = options;
13
+ const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true } = options;
14
14
  const project = (0, ts_ast_1.createProject)();
15
15
  const hookName = (0, type_resolver_1.getOperationHookName)(operation.name, 'query');
16
16
  const fileName = (0, type_resolver_1.getOperationFileName)(operation.name, 'query');
@@ -27,20 +27,25 @@ function generateCustomQueryHook(options) {
27
27
  });
28
28
  const sourceFile = (0, ts_ast_1.createSourceFile)(project, fileName);
29
29
  // Add file header
30
- sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)(`Custom query hook for ${operation.name}`) + '\n\n');
31
- // Add imports
32
- sourceFile.addImportDeclarations([
33
- (0, ts_ast_1.createImport)({
30
+ const headerText = reactQueryEnabled
31
+ ? `Custom query hook for ${operation.name}`
32
+ : `Custom query functions for ${operation.name}`;
33
+ sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)(headerText) + '\n\n');
34
+ // Add imports - conditionally include React Query imports
35
+ const imports = [];
36
+ if (reactQueryEnabled) {
37
+ imports.push((0, ts_ast_1.createImport)({
34
38
  moduleSpecifier: '@tanstack/react-query',
35
39
  namedImports: ['useQuery'],
36
40
  typeOnlyNamedImports: ['UseQueryOptions', 'QueryClient'],
37
- }),
38
- (0, ts_ast_1.createImport)({
39
- moduleSpecifier: '../client',
40
- namedImports: ['execute'],
41
- typeOnlyNamedImports: ['ExecuteOptions'],
42
- }),
43
- ]);
41
+ }));
42
+ }
43
+ imports.push((0, ts_ast_1.createImport)({
44
+ moduleSpecifier: '../client',
45
+ namedImports: ['execute'],
46
+ typeOnlyNamedImports: ['ExecuteOptions'],
47
+ }));
48
+ sourceFile.addImportDeclarations(imports);
44
49
  // Add query document constant
45
50
  sourceFile.addVariableStatement((0, ts_ast_1.createConst)(documentConstName, '`\n' + queryDocument + '`', {
46
51
  docs: ['GraphQL query document'],
@@ -66,17 +71,19 @@ function generateCustomQueryHook(options) {
66
71
  docs: ['Query key factory for caching'],
67
72
  }));
68
73
  }
69
- // Generate hook function
70
- const hookParams = generateHookParameters(operation, variablesTypeName, resultTypeName);
71
- const hookBody = generateHookBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName);
72
- const hookDoc = generateHookDoc(operation, hookName);
73
- sourceFile.addFunction({
74
- name: hookName,
75
- isExported: true,
76
- parameters: hookParams,
77
- statements: hookBody,
78
- docs: [{ description: hookDoc }],
79
- });
74
+ // Generate hook function (only if React Query is enabled)
75
+ if (reactQueryEnabled) {
76
+ const hookParams = generateHookParameters(operation, variablesTypeName, resultTypeName);
77
+ const hookBody = generateHookBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName);
78
+ const hookDoc = generateHookDoc(operation, hookName);
79
+ sourceFile.addFunction({
80
+ name: hookName,
81
+ isExported: true,
82
+ parameters: hookParams,
83
+ statements: hookBody,
84
+ docs: [{ description: hookDoc }],
85
+ });
86
+ }
80
87
  // Add standalone functions section
81
88
  sourceFile.addStatements('\n// ============================================================================');
82
89
  sourceFile.addStatements('// Standalone Functions (non-React)');
@@ -95,20 +102,22 @@ function generateCustomQueryHook(options) {
95
102
  statements: fetchBody,
96
103
  docs: [{ description: fetchDoc }],
97
104
  });
98
- // Generate prefetch function
99
- const prefetchFnName = `prefetch${(0, utils_1.ucFirst)(operation.name)}Query`;
100
- const prefetchParams = generatePrefetchParameters(operation, variablesTypeName);
101
- const prefetchBody = generatePrefetchBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName);
102
- const prefetchDoc = generatePrefetchDoc(operation, prefetchFnName);
103
- sourceFile.addFunction({
104
- name: prefetchFnName,
105
- isExported: true,
106
- isAsync: true,
107
- parameters: prefetchParams,
108
- returnType: 'Promise<void>',
109
- statements: prefetchBody,
110
- docs: [{ description: prefetchDoc }],
111
- });
105
+ // Generate prefetch function (only if React Query is enabled)
106
+ if (reactQueryEnabled) {
107
+ const prefetchFnName = `prefetch${(0, utils_1.ucFirst)(operation.name)}Query`;
108
+ const prefetchParams = generatePrefetchParameters(operation, variablesTypeName);
109
+ const prefetchBody = generatePrefetchBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName);
110
+ const prefetchDoc = generatePrefetchDoc(operation, prefetchFnName);
111
+ sourceFile.addFunction({
112
+ name: prefetchFnName,
113
+ isExported: true,
114
+ isAsync: true,
115
+ parameters: prefetchParams,
116
+ returnType: 'Promise<void>',
117
+ statements: prefetchBody,
118
+ docs: [{ description: prefetchDoc }],
119
+ });
120
+ }
112
121
  return {
113
122
  fileName,
114
123
  content: (0, ts_ast_1.getFormattedOutput)(sourceFile),
@@ -346,7 +355,7 @@ await ${fnName}(queryClient);
346
355
  * Generate all custom query hook files
347
356
  */
348
357
  function generateAllCustomQueryHooks(options) {
349
- const { operations, typeRegistry, maxDepth = 2, skipQueryField = true } = options;
358
+ const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true } = options;
350
359
  return operations
351
360
  .filter((op) => op.kind === 'query')
352
361
  .map((operation) => generateCustomQueryHook({
@@ -354,5 +363,6 @@ function generateAllCustomQueryHooks(options) {
354
363
  typeRegistry,
355
364
  maxDepth,
356
365
  skipQueryField,
366
+ reactQueryEnabled,
357
367
  }));
358
368
  }
@@ -28,6 +28,7 @@ function generate(options) {
28
28
  // Extract codegen options
29
29
  const maxDepth = config.codegen.maxFieldDepth;
30
30
  const skipQueryField = config.codegen.skipQueryField;
31
+ const reactQueryEnabled = config.reactQuery.enabled;
31
32
  // 1. Generate client.ts
32
33
  files.push({
33
34
  path: 'client.ts',
@@ -39,7 +40,7 @@ function generate(options) {
39
40
  content: (0, types_1.generateTypesFile)(tables),
40
41
  });
41
42
  // 3. Generate table-based query hooks (queries/*.ts)
42
- const queryHooks = (0, queries_1.generateAllQueryHooks)(tables);
43
+ const queryHooks = (0, queries_1.generateAllQueryHooks)(tables, { reactQueryEnabled });
43
44
  for (const hook of queryHooks) {
44
45
  files.push({
45
46
  path: `queries/${hook.fileName}`,
@@ -54,6 +55,7 @@ function generate(options) {
54
55
  typeRegistry: customOperations.typeRegistry,
55
56
  maxDepth,
56
57
  skipQueryField,
58
+ reactQueryEnabled,
57
59
  });
58
60
  for (const hook of customQueryHooks) {
59
61
  files.push({
@@ -70,7 +72,7 @@ function generate(options) {
70
72
  : (0, barrel_1.generateQueriesBarrel)(tables),
71
73
  });
72
74
  // 6. Generate table-based mutation hooks (mutations/*.ts)
73
- const mutationHooks = (0, mutations_1.generateAllMutationHooks)(tables);
75
+ const mutationHooks = (0, mutations_1.generateAllMutationHooks)(tables, { reactQueryEnabled });
74
76
  for (const hook of mutationHooks) {
75
77
  files.push({
76
78
  path: `mutations/${hook.fileName}`,
@@ -85,6 +87,7 @@ function generate(options) {
85
87
  typeRegistry: customOperations.typeRegistry,
86
88
  maxDepth,
87
89
  skipQueryField,
90
+ reactQueryEnabled,
88
91
  });
89
92
  for (const hook of customMutationHooks) {
90
93
  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[];