@constructive-io/graphql-codegen 2.20.1 → 2.22.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.
Files changed (96) hide show
  1. package/README.md +15 -3
  2. package/cli/codegen/barrel.d.ts +4 -1
  3. package/cli/codegen/barrel.js +18 -12
  4. package/cli/codegen/client.js +33 -0
  5. package/cli/codegen/custom-mutations.d.ts +11 -1
  6. package/cli/codegen/custom-mutations.js +49 -15
  7. package/cli/codegen/custom-queries.d.ts +8 -0
  8. package/cli/codegen/custom-queries.js +82 -47
  9. package/cli/codegen/gql-ast.js +9 -5
  10. package/cli/codegen/index.js +39 -8
  11. package/cli/codegen/mutations.d.ts +14 -4
  12. package/cli/codegen/mutations.js +114 -28
  13. package/cli/codegen/orm/barrel.js +4 -2
  14. package/cli/codegen/orm/index.js +17 -0
  15. package/cli/codegen/orm/input-types-generator.js +83 -29
  16. package/cli/codegen/orm/model-generator.js +6 -4
  17. package/cli/codegen/queries.d.ts +7 -3
  18. package/cli/codegen/queries.js +185 -158
  19. package/cli/codegen/scalars.d.ts +6 -4
  20. package/cli/codegen/scalars.js +17 -9
  21. package/cli/codegen/schema-types-generator.d.ts +26 -0
  22. package/cli/codegen/schema-types-generator.js +365 -0
  23. package/cli/codegen/ts-ast.d.ts +3 -1
  24. package/cli/codegen/ts-ast.js +2 -2
  25. package/cli/codegen/type-resolver.d.ts +52 -6
  26. package/cli/codegen/type-resolver.js +97 -19
  27. package/cli/codegen/types.d.ts +7 -4
  28. package/cli/codegen/types.js +94 -41
  29. package/cli/codegen/utils.d.ts +20 -2
  30. package/cli/codegen/utils.js +32 -7
  31. package/cli/commands/generate-orm.js +5 -5
  32. package/cli/commands/generate.d.ts +4 -1
  33. package/cli/commands/generate.js +27 -8
  34. package/cli/introspect/transform-schema.d.ts +33 -21
  35. package/cli/introspect/transform-schema.js +31 -21
  36. package/esm/cli/codegen/barrel.d.ts +4 -1
  37. package/esm/cli/codegen/barrel.js +18 -12
  38. package/esm/cli/codegen/client.js +33 -0
  39. package/esm/cli/codegen/custom-mutations.d.ts +11 -1
  40. package/esm/cli/codegen/custom-mutations.js +50 -16
  41. package/esm/cli/codegen/custom-queries.d.ts +8 -0
  42. package/esm/cli/codegen/custom-queries.js +83 -48
  43. package/esm/cli/codegen/gql-ast.js +10 -6
  44. package/esm/cli/codegen/index.js +39 -8
  45. package/esm/cli/codegen/mutations.d.ts +14 -4
  46. package/esm/cli/codegen/mutations.js +115 -29
  47. package/esm/cli/codegen/orm/barrel.js +4 -2
  48. package/esm/cli/codegen/orm/index.js +17 -0
  49. package/esm/cli/codegen/orm/input-types-generator.js +83 -29
  50. package/esm/cli/codegen/orm/model-generator.js +7 -5
  51. package/esm/cli/codegen/queries.d.ts +7 -3
  52. package/esm/cli/codegen/queries.js +186 -159
  53. package/esm/cli/codegen/scalars.d.ts +6 -4
  54. package/esm/cli/codegen/scalars.js +16 -8
  55. package/esm/cli/codegen/schema-types-generator.d.ts +26 -0
  56. package/esm/cli/codegen/schema-types-generator.js +362 -0
  57. package/esm/cli/codegen/ts-ast.d.ts +3 -1
  58. package/esm/cli/codegen/ts-ast.js +2 -2
  59. package/esm/cli/codegen/type-resolver.d.ts +52 -6
  60. package/esm/cli/codegen/type-resolver.js +97 -20
  61. package/esm/cli/codegen/types.d.ts +7 -4
  62. package/esm/cli/codegen/types.js +95 -41
  63. package/esm/cli/codegen/utils.d.ts +20 -2
  64. package/esm/cli/codegen/utils.js +31 -7
  65. package/esm/cli/commands/generate-orm.js +5 -5
  66. package/esm/cli/commands/generate.d.ts +4 -1
  67. package/esm/cli/commands/generate.js +27 -8
  68. package/esm/cli/introspect/transform-schema.d.ts +33 -21
  69. package/esm/cli/introspect/transform-schema.js +31 -21
  70. package/esm/types/config.d.ts +16 -1
  71. package/esm/types/config.js +6 -0
  72. package/esm/types/schema.d.ts +2 -0
  73. package/package.json +8 -6
  74. package/types/config.d.ts +16 -1
  75. package/types/config.js +6 -0
  76. package/types/schema.d.ts +2 -0
  77. package/__tests__/codegen/input-types-generator.test.d.ts +0 -1
  78. package/__tests__/codegen/input-types-generator.test.js +0 -635
  79. package/cli/codegen/filters.d.ts +0 -27
  80. package/cli/codegen/filters.js +0 -357
  81. package/cli/codegen/orm/input-types-generator.test.d.ts +0 -1
  82. package/cli/codegen/orm/input-types-generator.test.js +0 -75
  83. package/cli/codegen/orm/select-types.test.d.ts +0 -11
  84. package/cli/codegen/orm/select-types.test.js +0 -22
  85. package/cli/introspect/transform-schema.test.d.ts +0 -1
  86. package/cli/introspect/transform-schema.test.js +0 -67
  87. package/esm/__tests__/codegen/input-types-generator.test.d.ts +0 -1
  88. package/esm/__tests__/codegen/input-types-generator.test.js +0 -633
  89. package/esm/cli/codegen/filters.d.ts +0 -27
  90. package/esm/cli/codegen/filters.js +0 -351
  91. package/esm/cli/codegen/orm/input-types-generator.test.d.ts +0 -1
  92. package/esm/cli/codegen/orm/input-types-generator.test.js +0 -73
  93. package/esm/cli/codegen/orm/select-types.test.d.ts +0 -11
  94. package/esm/cli/codegen/orm/select-types.test.js +0 -21
  95. package/esm/cli/introspect/transform-schema.test.d.ts +0 -1
  96. package/esm/cli/introspect/transform-schema.test.js +0 -65
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',
@@ -15,8 +15,11 @@ export declare function generateQueriesBarrel(tables: CleanTable[]): string;
15
15
  export declare function generateMutationsBarrel(tables: CleanTable[]): string;
16
16
  /**
17
17
  * Generate the main index.ts barrel file
18
+ *
19
+ * @param tables - The tables to include in the SDK
20
+ * @param hasSchemaTypes - Whether schema-types.ts was generated
18
21
  */
19
- export declare function generateMainBarrel(tables: CleanTable[]): string;
22
+ export declare function generateMainBarrel(tables: CleanTable[], hasSchemaTypes?: boolean): string;
20
23
  /**
21
24
  * Generate queries barrel including custom query operations
22
25
  */
@@ -12,10 +12,7 @@ const type_resolver_1 = require("./type-resolver");
12
12
  * Generate the queries/index.ts barrel file
13
13
  */
14
14
  function generateQueriesBarrel(tables) {
15
- const lines = [
16
- (0, ts_ast_1.createFileHeader)('Query hooks barrel export'),
17
- '',
18
- ];
15
+ const lines = [(0, ts_ast_1.createFileHeader)('Query hooks barrel export'), ''];
19
16
  // Export all query hooks
20
17
  for (const table of tables) {
21
18
  const listHookName = (0, utils_1.getListQueryHookName)(table);
@@ -51,31 +48,40 @@ function generateMutationsBarrel(tables) {
51
48
  }
52
49
  /**
53
50
  * Generate the main index.ts barrel file
51
+ *
52
+ * @param tables - The tables to include in the SDK
53
+ * @param hasSchemaTypes - Whether schema-types.ts was generated
54
54
  */
55
- function generateMainBarrel(tables) {
55
+ function generateMainBarrel(tables, hasSchemaTypes = false) {
56
56
  const tableNames = tables.map((t) => t.name).join(', ');
57
+ const schemaTypesExport = hasSchemaTypes
58
+ ? `
59
+ // Schema types (input, payload, enum types)
60
+ export * from './schema-types';
61
+ `
62
+ : '';
57
63
  return `/**
58
64
  * Auto-generated GraphQL SDK
59
65
  * @generated by @constructive-io/graphql-codegen
60
- *
66
+ *
61
67
  * Tables: ${tableNames}
62
- *
68
+ *
63
69
  * Usage:
64
- *
70
+ *
65
71
  * 1. Configure the client:
66
72
  * \`\`\`ts
67
73
  * import { configure } from './generated';
68
- *
74
+ *
69
75
  * configure({
70
76
  * endpoint: 'https://api.example.com/graphql',
71
77
  * headers: { Authorization: 'Bearer <token>' },
72
78
  * });
73
79
  * \`\`\`
74
- *
80
+ *
75
81
  * 2. Use the hooks:
76
82
  * \`\`\`tsx
77
83
  * import { useCarsQuery, useCreateCarMutation } from './generated';
78
- *
84
+ *
79
85
  * function MyComponent() {
80
86
  * const { data, isLoading } = useCarsQuery({ first: 10 });
81
87
  * const { mutate } = useCreateCarMutation();
@@ -89,7 +95,7 @@ export * from './client';
89
95
 
90
96
  // Entity and filter types
91
97
  export * from './types';
92
-
98
+ ${schemaTypesExport}
93
99
  // Query hooks
94
100
  export * from './queries';
95
101
 
@@ -56,6 +56,39 @@ export function getConfig(): GraphQLClientConfig {
56
56
  return globalConfig;
57
57
  }
58
58
 
59
+ /**
60
+ * Set a single header value
61
+ * Useful for updating Authorization after login
62
+ *
63
+ * @example
64
+ * \`\`\`ts
65
+ * setHeader('Authorization', 'Bearer <new-token>');
66
+ * \`\`\`
67
+ */
68
+ export function setHeader(key: string, value: string): void {
69
+ const config = getConfig();
70
+ globalConfig = {
71
+ ...config,
72
+ headers: { ...config.headers, [key]: value },
73
+ };
74
+ }
75
+
76
+ /**
77
+ * Merge multiple headers into the current configuration
78
+ *
79
+ * @example
80
+ * \`\`\`ts
81
+ * setHeaders({ Authorization: 'Bearer <token>', 'X-Custom': 'value' });
82
+ * \`\`\`
83
+ */
84
+ export function setHeaders(headers: Record<string, string>): void {
85
+ const config = getConfig();
86
+ globalConfig = {
87
+ ...config,
88
+ headers: { ...config.headers, ...headers },
89
+ };
90
+ }
91
+
59
92
  // ============================================================================
60
93
  // Error handling
61
94
  // ============================================================================
@@ -21,18 +21,28 @@ 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;
26
+ /** Table entity type names (for import path resolution) */
27
+ tableTypeNames?: Set<string>;
24
28
  }
25
29
  /**
26
30
  * Generate a custom mutation hook file
31
+ * When reactQueryEnabled is false, returns null since mutations require React Query
27
32
  */
28
- export declare function generateCustomMutationHook(options: GenerateCustomMutationHookOptions): GeneratedCustomMutationFile;
33
+ export declare function generateCustomMutationHook(options: GenerateCustomMutationHookOptions): GeneratedCustomMutationFile | null;
29
34
  export interface GenerateAllCustomMutationHooksOptions {
30
35
  operations: CleanOperation[];
31
36
  typeRegistry: TypeRegistry;
32
37
  maxDepth?: number;
33
38
  skipQueryField?: boolean;
39
+ /** Whether to generate React Query hooks (default: true for backwards compatibility) */
40
+ reactQueryEnabled?: boolean;
41
+ /** Table entity type names (for import path resolution) */
42
+ tableTypeNames?: Set<string>;
34
43
  }
35
44
  /**
36
45
  * Generate all custom mutation hook files
46
+ * When reactQueryEnabled is false, returns empty array since mutations require React Query
37
47
  */
38
48
  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
  }
@@ -20,13 +25,15 @@ function generateCustomMutationHook(options) {
20
25
  }
21
26
  }
22
27
  function generateCustomMutationHookInternal(options) {
23
- const { operation, typeRegistry, maxDepth = 2, skipQueryField = true } = options;
28
+ const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, tableTypeNames } = options;
24
29
  const project = (0, ts_ast_1.createProject)();
25
30
  const hookName = (0, type_resolver_1.getOperationHookName)(operation.name, 'mutation');
26
31
  const fileName = (0, type_resolver_1.getOperationFileName)(operation.name, 'mutation');
27
32
  const variablesTypeName = (0, type_resolver_1.getOperationVariablesTypeName)(operation.name, 'mutation');
28
33
  const resultTypeName = (0, type_resolver_1.getOperationResultTypeName)(operation.name, 'mutation');
29
34
  const documentConstName = (0, type_resolver_1.getDocumentConstName)(operation.name, 'mutation');
35
+ // Create type tracker to collect referenced types (with table type awareness)
36
+ const tracker = (0, type_resolver_1.createTypeTracker)({ tableTypeNames });
30
37
  // Generate GraphQL document
31
38
  const mutationDocument = (0, schema_gql_ast_1.buildCustomMutationString)({
32
39
  operation,
@@ -37,8 +44,21 @@ function generateCustomMutationHookInternal(options) {
37
44
  const sourceFile = (0, ts_ast_1.createSourceFile)(project, fileName);
38
45
  // Add file header
39
46
  sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)(`Custom mutation hook for ${operation.name}`) + '\n\n');
47
+ // Generate variables interface if there are arguments (with tracking)
48
+ let variablesProps = [];
49
+ if (operation.args.length > 0) {
50
+ variablesProps = generateVariablesProperties(operation.args, tracker);
51
+ }
52
+ // Generate result interface (with tracking)
53
+ const resultType = (0, type_resolver_1.typeRefToTsType)(operation.returnType, tracker);
54
+ const resultProps = [
55
+ { name: operation.name, type: resultType },
56
+ ];
57
+ // Get importable types from tracker (separated by source)
58
+ const schemaTypes = tracker.getImportableTypes(); // From schema-types.ts
59
+ const tableTypes = tracker.getTableTypes(); // From types.ts
40
60
  // Add imports
41
- sourceFile.addImportDeclarations([
61
+ const imports = [
42
62
  (0, ts_ast_1.createImport)({
43
63
  moduleSpecifier: '@tanstack/react-query',
44
64
  namedImports: ['useMutation'],
@@ -48,21 +68,31 @@ function generateCustomMutationHookInternal(options) {
48
68
  moduleSpecifier: '../client',
49
69
  namedImports: ['execute'],
50
70
  }),
51
- ]);
71
+ ];
72
+ // Add types.ts import for table entity types
73
+ if (tableTypes.length > 0) {
74
+ imports.push((0, ts_ast_1.createImport)({
75
+ moduleSpecifier: '../types',
76
+ typeOnlyNamedImports: tableTypes,
77
+ }));
78
+ }
79
+ // Add schema-types import for Input/Payload/Enum types
80
+ if (schemaTypes.length > 0) {
81
+ imports.push((0, ts_ast_1.createImport)({
82
+ moduleSpecifier: '../schema-types',
83
+ typeOnlyNamedImports: schemaTypes,
84
+ }));
85
+ }
86
+ sourceFile.addImportDeclarations(imports);
52
87
  // Add mutation document constant
53
88
  sourceFile.addVariableStatement((0, ts_ast_1.createConst)(documentConstName, '`\n' + mutationDocument + '`', {
54
89
  docs: ['GraphQL mutation document'],
55
90
  }));
56
- // Generate variables interface if there are arguments
91
+ // Add variables interface
57
92
  if (operation.args.length > 0) {
58
- const variablesProps = generateVariablesProperties(operation.args);
59
93
  sourceFile.addInterface((0, ts_ast_1.createInterface)(variablesTypeName, variablesProps));
60
94
  }
61
- // Generate result interface
62
- const resultType = (0, type_resolver_1.typeRefToTsType)(operation.returnType);
63
- const resultProps = [
64
- { name: operation.name, type: resultType },
65
- ];
95
+ // Add result interface
66
96
  sourceFile.addInterface((0, ts_ast_1.createInterface)(resultTypeName, resultProps));
67
97
  // Generate hook function
68
98
  const hookParams = generateHookParameters(operation, variablesTypeName, resultTypeName);
@@ -86,10 +116,10 @@ function generateCustomMutationHookInternal(options) {
86
116
  /**
87
117
  * Generate interface properties from CleanArguments
88
118
  */
89
- function generateVariablesProperties(args) {
119
+ function generateVariablesProperties(args, tracker) {
90
120
  return args.map((arg) => ({
91
121
  name: arg.name,
92
- type: (0, type_resolver_1.typeRefToTsType)(arg.type),
122
+ type: (0, type_resolver_1.typeRefToTsType)(arg.type, tracker),
93
123
  optional: !(0, type_resolver_1.isTypeRequired)(arg.type),
94
124
  docs: arg.description ? [arg.description] : undefined,
95
125
  }));
@@ -135,9 +165,10 @@ function generateHookBody(operation, documentConstName, variablesTypeName, resul
135
165
  }
136
166
  /**
137
167
  * Generate all custom mutation hook files
168
+ * When reactQueryEnabled is false, returns empty array since mutations require React Query
138
169
  */
139
170
  function generateAllCustomMutationHooks(options) {
140
- const { operations, typeRegistry, maxDepth = 2, skipQueryField = true } = options;
171
+ const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames } = options;
141
172
  return operations
142
173
  .filter((op) => op.kind === 'mutation')
143
174
  .map((operation) => generateCustomMutationHook({
@@ -145,5 +176,8 @@ function generateAllCustomMutationHooks(options) {
145
176
  typeRegistry,
146
177
  maxDepth,
147
178
  skipQueryField,
148
- }));
179
+ reactQueryEnabled,
180
+ tableTypeNames,
181
+ }))
182
+ .filter((result) => result !== null);
149
183
  }
@@ -21,6 +21,10 @@ 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;
26
+ /** Table entity type names (for import path resolution) */
27
+ tableTypeNames?: Set<string>;
24
28
  }
25
29
  /**
26
30
  * Generate a custom query hook file
@@ -31,6 +35,10 @@ export interface GenerateAllCustomQueryHooksOptions {
31
35
  typeRegistry: TypeRegistry;
32
36
  maxDepth?: number;
33
37
  skipQueryField?: boolean;
38
+ /** Whether to generate React Query hooks (default: true for backwards compatibility) */
39
+ reactQueryEnabled?: boolean;
40
+ /** Table entity type names (for import path resolution) */
41
+ tableTypeNames?: Set<string>;
34
42
  }
35
43
  /**
36
44
  * 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, tableTypeNames } = 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');
@@ -18,6 +18,8 @@ function generateCustomQueryHook(options) {
18
18
  const resultTypeName = (0, type_resolver_1.getOperationResultTypeName)(operation.name, 'query');
19
19
  const documentConstName = (0, type_resolver_1.getDocumentConstName)(operation.name, 'query');
20
20
  const queryKeyName = (0, type_resolver_1.getQueryKeyName)(operation.name);
21
+ // Create type tracker to collect referenced types (with table type awareness)
22
+ const tracker = (0, type_resolver_1.createTypeTracker)({ tableTypeNames });
21
23
  // Generate GraphQL document
22
24
  const queryDocument = (0, schema_gql_ast_1.buildCustomQueryString)({
23
25
  operation,
@@ -27,34 +29,61 @@ function generateCustomQueryHook(options) {
27
29
  });
28
30
  const sourceFile = (0, ts_ast_1.createSourceFile)(project, fileName);
29
31
  // 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)({
32
+ const headerText = reactQueryEnabled
33
+ ? `Custom query hook for ${operation.name}`
34
+ : `Custom query functions for ${operation.name}`;
35
+ sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)(headerText) + '\n\n');
36
+ // Generate variables interface if there are arguments (with tracking)
37
+ let variablesProps = [];
38
+ if (operation.args.length > 0) {
39
+ variablesProps = generateVariablesProperties(operation.args, tracker);
40
+ }
41
+ // Generate result interface (with tracking)
42
+ const resultType = (0, type_resolver_1.typeRefToTsType)(operation.returnType, tracker);
43
+ const resultProps = [
44
+ { name: operation.name, type: resultType },
45
+ ];
46
+ // Get importable types from tracker (separated by source)
47
+ const schemaTypes = tracker.getImportableTypes(); // From schema-types.ts
48
+ const tableTypes = tracker.getTableTypes(); // From types.ts
49
+ // Add imports - conditionally include React Query imports
50
+ const imports = [];
51
+ if (reactQueryEnabled) {
52
+ imports.push((0, ts_ast_1.createImport)({
34
53
  moduleSpecifier: '@tanstack/react-query',
35
54
  namedImports: ['useQuery'],
36
55
  typeOnlyNamedImports: ['UseQueryOptions', 'QueryClient'],
37
- }),
38
- (0, ts_ast_1.createImport)({
39
- moduleSpecifier: '../client',
40
- namedImports: ['execute'],
41
- typeOnlyNamedImports: ['ExecuteOptions'],
42
- }),
43
- ]);
56
+ }));
57
+ }
58
+ imports.push((0, ts_ast_1.createImport)({
59
+ moduleSpecifier: '../client',
60
+ namedImports: ['execute'],
61
+ typeOnlyNamedImports: ['ExecuteOptions'],
62
+ }));
63
+ // Add types.ts import for table entity types
64
+ if (tableTypes.length > 0) {
65
+ imports.push((0, ts_ast_1.createImport)({
66
+ moduleSpecifier: '../types',
67
+ typeOnlyNamedImports: tableTypes,
68
+ }));
69
+ }
70
+ // Add schema-types import for Input/Payload/Enum types
71
+ if (schemaTypes.length > 0) {
72
+ imports.push((0, ts_ast_1.createImport)({
73
+ moduleSpecifier: '../schema-types',
74
+ typeOnlyNamedImports: schemaTypes,
75
+ }));
76
+ }
77
+ sourceFile.addImportDeclarations(imports);
44
78
  // Add query document constant
45
79
  sourceFile.addVariableStatement((0, ts_ast_1.createConst)(documentConstName, '`\n' + queryDocument + '`', {
46
80
  docs: ['GraphQL query document'],
47
81
  }));
48
- // Generate variables interface if there are arguments
82
+ // Add variables interface
49
83
  if (operation.args.length > 0) {
50
- const variablesProps = generateVariablesProperties(operation.args);
51
84
  sourceFile.addInterface((0, ts_ast_1.createInterface)(variablesTypeName, variablesProps));
52
85
  }
53
- // Generate result interface
54
- const resultType = (0, type_resolver_1.typeRefToTsType)(operation.returnType);
55
- const resultProps = [
56
- { name: operation.name, type: resultType },
57
- ];
86
+ // Add result interface
58
87
  sourceFile.addInterface((0, ts_ast_1.createInterface)(resultTypeName, resultProps));
59
88
  // Query key factory
60
89
  if (operation.args.length > 0) {
@@ -66,17 +95,19 @@ function generateCustomQueryHook(options) {
66
95
  docs: ['Query key factory for caching'],
67
96
  }));
68
97
  }
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
- });
98
+ // Generate hook function (only if React Query is enabled)
99
+ if (reactQueryEnabled) {
100
+ const hookParams = generateHookParameters(operation, variablesTypeName, resultTypeName);
101
+ const hookBody = generateHookBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName);
102
+ const hookDoc = generateHookDoc(operation, hookName);
103
+ sourceFile.addFunction({
104
+ name: hookName,
105
+ isExported: true,
106
+ parameters: hookParams,
107
+ statements: hookBody,
108
+ docs: [{ description: hookDoc }],
109
+ });
110
+ }
80
111
  // Add standalone functions section
81
112
  sourceFile.addStatements('\n// ============================================================================');
82
113
  sourceFile.addStatements('// Standalone Functions (non-React)');
@@ -95,20 +126,22 @@ function generateCustomQueryHook(options) {
95
126
  statements: fetchBody,
96
127
  docs: [{ description: fetchDoc }],
97
128
  });
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
- });
129
+ // Generate prefetch function (only if React Query is enabled)
130
+ if (reactQueryEnabled) {
131
+ const prefetchFnName = `prefetch${(0, utils_1.ucFirst)(operation.name)}Query`;
132
+ const prefetchParams = generatePrefetchParameters(operation, variablesTypeName);
133
+ const prefetchBody = generatePrefetchBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName);
134
+ const prefetchDoc = generatePrefetchDoc(operation, prefetchFnName);
135
+ sourceFile.addFunction({
136
+ name: prefetchFnName,
137
+ isExported: true,
138
+ isAsync: true,
139
+ parameters: prefetchParams,
140
+ returnType: 'Promise<void>',
141
+ statements: prefetchBody,
142
+ docs: [{ description: prefetchDoc }],
143
+ });
144
+ }
112
145
  return {
113
146
  fileName,
114
147
  content: (0, ts_ast_1.getFormattedOutput)(sourceFile),
@@ -121,10 +154,10 @@ function generateCustomQueryHook(options) {
121
154
  /**
122
155
  * Generate interface properties from CleanArguments
123
156
  */
124
- function generateVariablesProperties(args) {
157
+ function generateVariablesProperties(args, tracker) {
125
158
  return args.map((arg) => ({
126
159
  name: arg.name,
127
- type: (0, type_resolver_1.typeRefToTsType)(arg.type),
160
+ type: (0, type_resolver_1.typeRefToTsType)(arg.type, tracker),
128
161
  optional: !(0, type_resolver_1.isTypeRequired)(arg.type),
129
162
  docs: arg.description ? [arg.description] : undefined,
130
163
  }));
@@ -346,7 +379,7 @@ await ${fnName}(queryClient);
346
379
  * Generate all custom query hook files
347
380
  */
348
381
  function generateAllCustomQueryHooks(options) {
349
- const { operations, typeRegistry, maxDepth = 2, skipQueryField = true } = options;
382
+ const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames } = options;
350
383
  return operations
351
384
  .filter((op) => op.kind === 'query')
352
385
  .map((operation) => generateCustomQueryHook({
@@ -354,5 +387,7 @@ function generateAllCustomQueryHooks(options) {
354
387
  typeRegistry,
355
388
  maxDepth,
356
389
  skipQueryField,
390
+ reactQueryEnabled,
391
+ tableTypeNames,
357
392
  }));
358
393
  }
@@ -147,16 +147,20 @@ function buildSingleQueryAST(config) {
147
147
  const { table } = config;
148
148
  const queryName = (0, utils_1.getSingleRowQueryName)(table);
149
149
  const scalarFields = (0, utils_1.getScalarFields)(table);
150
- // Variable definitions - assume UUID primary key
150
+ // Get primary key info dynamically from table constraints
151
+ const pkFields = (0, utils_1.getPrimaryKeyInfo)(table);
152
+ // For simplicity, use first PK field (most common case)
153
+ const pkField = pkFields[0];
154
+ // Variable definitions - use dynamic PK field name and type
151
155
  const variableDefinitions = [
152
156
  t.variableDefinition({
153
- variable: t.variable({ name: 'id' }),
154
- type: t.nonNullType({ type: t.namedType({ type: 'UUID' }) }),
157
+ variable: t.variable({ name: pkField.name }),
158
+ type: t.nonNullType({ type: t.namedType({ type: pkField.gqlType }) }),
155
159
  }),
156
160
  ];
157
- // Query arguments
161
+ // Query arguments - use dynamic PK field name
158
162
  const args = [
159
- t.argument({ name: 'id', value: t.variable({ name: 'id' }) }),
163
+ t.argument({ name: pkField.name, value: t.variable({ name: pkField.name }) }),
160
164
  ];
161
165
  // Field selections
162
166
  const fieldSelections = createFieldSelections(scalarFields);