@constructive-io/graphql-codegen 3.2.0 → 3.3.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 (216) hide show
  1. package/README.md +25 -30
  2. package/cli/index.js +36 -41
  3. package/cli/shared.d.ts +15 -17
  4. package/cli/shared.js +113 -21
  5. package/client/error.js +31 -9
  6. package/client/execute.js +2 -2
  7. package/client/index.d.ts +3 -3
  8. package/client/index.js +6 -6
  9. package/core/ast.d.ts +1 -1
  10. package/core/ast.js +1 -1
  11. package/core/codegen/babel-ast.d.ts +1 -1
  12. package/core/codegen/babel-ast.js +2 -2
  13. package/core/codegen/barrel.d.ts +0 -6
  14. package/core/codegen/barrel.js +22 -19
  15. package/core/codegen/client.d.ts +2 -12
  16. package/core/codegen/client.js +7 -21
  17. package/core/codegen/custom-mutations.d.ts +0 -14
  18. package/core/codegen/custom-mutations.js +139 -88
  19. package/core/codegen/custom-queries.d.ts +0 -14
  20. package/core/codegen/custom-queries.js +483 -193
  21. package/core/codegen/hooks-ast.d.ts +75 -0
  22. package/core/codegen/hooks-ast.js +522 -0
  23. package/core/codegen/index.d.ts +16 -18
  24. package/core/codegen/index.js +42 -88
  25. package/core/codegen/invalidation.d.ts +1 -7
  26. package/core/codegen/invalidation.js +50 -16
  27. package/core/codegen/mutation-keys.d.ts +1 -10
  28. package/core/codegen/mutation-keys.js +22 -8
  29. package/core/codegen/mutations.d.ts +0 -13
  30. package/core/codegen/mutations.js +301 -366
  31. package/core/codegen/orm/barrel.d.ts +0 -5
  32. package/core/codegen/orm/barrel.js +5 -0
  33. package/core/codegen/orm/client-generator.d.ts +0 -5
  34. package/core/codegen/orm/client-generator.js +7 -2
  35. package/core/codegen/orm/client.js +3 -1
  36. package/core/codegen/orm/custom-ops-generator.d.ts +0 -6
  37. package/core/codegen/orm/custom-ops-generator.js +104 -51
  38. package/core/codegen/orm/index.d.ts +4 -4
  39. package/core/codegen/orm/index.js +28 -15
  40. package/core/codegen/orm/input-types-generator.d.ts +1 -13
  41. package/core/codegen/orm/input-types-generator.js +85 -23
  42. package/core/codegen/orm/model-generator.d.ts +0 -5
  43. package/core/codegen/orm/model-generator.js +309 -131
  44. package/core/codegen/orm/select-types.d.ts +19 -14
  45. package/core/codegen/queries.d.ts +0 -8
  46. package/core/codegen/queries.js +360 -559
  47. package/core/codegen/query-keys.d.ts +1 -1
  48. package/core/codegen/query-keys.js +37 -23
  49. package/core/codegen/scalars.js +3 -1
  50. package/core/codegen/schema-types-generator.d.ts +1 -1
  51. package/core/codegen/schema-types-generator.js +17 -2
  52. package/core/codegen/select-helpers.d.ts +19 -0
  53. package/core/codegen/select-helpers.js +40 -0
  54. package/core/codegen/selection.d.ts +4 -0
  55. package/core/codegen/selection.js +65 -0
  56. package/core/codegen/shared/index.d.ts +2 -15
  57. package/core/codegen/shared/index.js +17 -4
  58. package/core/codegen/templates/hooks-client.ts +49 -0
  59. package/core/codegen/templates/hooks-selection.ts +58 -0
  60. package/core/codegen/templates/orm-client.ts +8 -6
  61. package/core/codegen/templates/query-builder.ts +250 -46
  62. package/core/codegen/templates/select-types.ts +31 -14
  63. package/core/codegen/type-resolver.d.ts +1 -5
  64. package/core/codegen/type-resolver.js +0 -22
  65. package/core/codegen/types.d.ts +0 -3
  66. package/core/codegen/types.js +71 -14
  67. package/core/codegen/utils.d.ts +1 -4
  68. package/core/codegen/utils.js +4 -1
  69. package/core/config/index.d.ts +1 -1
  70. package/core/config/resolver.js +1 -3
  71. package/core/generate.js +38 -50
  72. package/core/index.d.ts +3 -3
  73. package/core/index.js +3 -4
  74. package/core/introspect/index.d.ts +6 -6
  75. package/core/introspect/index.js +5 -8
  76. package/core/introspect/infer-tables.d.ts +0 -14
  77. package/core/introspect/infer-tables.js +15 -1
  78. package/core/introspect/source/database.js +1 -1
  79. package/core/introspect/source/endpoint.d.ts +0 -6
  80. package/core/introspect/source/endpoint.js +7 -1
  81. package/core/introspect/source/index.d.ts +4 -4
  82. package/core/introspect/source/index.js +5 -9
  83. package/core/introspect/source/pgpm-module.js +3 -3
  84. package/core/introspect/transform-schema.d.ts +2 -2
  85. package/core/introspect/transform-schema.js +2 -2
  86. package/core/output/index.d.ts +1 -1
  87. package/core/output/index.js +2 -2
  88. package/core/output/writer.d.ts +3 -0
  89. package/core/output/writer.js +20 -1
  90. package/core/pipeline/index.d.ts +2 -2
  91. package/core/query-builder.d.ts +2 -2
  92. package/core/query-builder.js +1 -1
  93. package/core/watch/index.d.ts +4 -4
  94. package/core/watch/index.js +9 -9
  95. package/core/watch/orchestrator.js +5 -3
  96. package/esm/cli/index.js +37 -42
  97. package/esm/cli/shared.d.ts +15 -17
  98. package/esm/cli/shared.js +103 -20
  99. package/esm/client/error.js +31 -9
  100. package/esm/client/execute.js +2 -2
  101. package/esm/client/index.d.ts +3 -3
  102. package/esm/client/index.js +3 -3
  103. package/esm/core/ast.d.ts +1 -1
  104. package/esm/core/ast.js +1 -1
  105. package/esm/core/codegen/babel-ast.d.ts +1 -1
  106. package/esm/core/codegen/babel-ast.js +2 -2
  107. package/esm/core/codegen/barrel.d.ts +0 -6
  108. package/esm/core/codegen/barrel.js +23 -20
  109. package/esm/core/codegen/client.d.ts +2 -12
  110. package/esm/core/codegen/client.js +7 -21
  111. package/esm/core/codegen/custom-mutations.d.ts +0 -14
  112. package/esm/core/codegen/custom-mutations.js +141 -90
  113. package/esm/core/codegen/custom-queries.d.ts +0 -14
  114. package/esm/core/codegen/custom-queries.js +486 -196
  115. package/esm/core/codegen/hooks-ast.d.ts +75 -0
  116. package/esm/core/codegen/hooks-ast.js +424 -0
  117. package/esm/core/codegen/index.d.ts +16 -18
  118. package/esm/core/codegen/index.js +26 -71
  119. package/esm/core/codegen/invalidation.d.ts +1 -7
  120. package/esm/core/codegen/invalidation.js +51 -17
  121. package/esm/core/codegen/mutation-keys.d.ts +1 -10
  122. package/esm/core/codegen/mutation-keys.js +23 -9
  123. package/esm/core/codegen/mutations.d.ts +0 -13
  124. package/esm/core/codegen/mutations.js +302 -367
  125. package/esm/core/codegen/orm/barrel.d.ts +0 -5
  126. package/esm/core/codegen/orm/barrel.js +6 -1
  127. package/esm/core/codegen/orm/client-generator.d.ts +0 -5
  128. package/esm/core/codegen/orm/client-generator.js +7 -2
  129. package/esm/core/codegen/orm/client.js +3 -1
  130. package/esm/core/codegen/orm/custom-ops-generator.d.ts +0 -6
  131. package/esm/core/codegen/orm/custom-ops-generator.js +103 -50
  132. package/esm/core/codegen/orm/index.d.ts +4 -4
  133. package/esm/core/codegen/orm/index.js +25 -12
  134. package/esm/core/codegen/orm/input-types-generator.d.ts +1 -13
  135. package/esm/core/codegen/orm/input-types-generator.js +85 -23
  136. package/esm/core/codegen/orm/model-generator.d.ts +0 -5
  137. package/esm/core/codegen/orm/model-generator.js +310 -132
  138. package/esm/core/codegen/orm/select-types.d.ts +19 -14
  139. package/esm/core/codegen/queries.d.ts +0 -8
  140. package/esm/core/codegen/queries.js +362 -561
  141. package/esm/core/codegen/query-keys.d.ts +1 -1
  142. package/esm/core/codegen/query-keys.js +38 -24
  143. package/esm/core/codegen/scalars.js +3 -1
  144. package/esm/core/codegen/schema-types-generator.d.ts +1 -1
  145. package/esm/core/codegen/schema-types-generator.js +17 -2
  146. package/esm/core/codegen/select-helpers.d.ts +19 -0
  147. package/esm/core/codegen/select-helpers.js +35 -0
  148. package/esm/core/codegen/selection.d.ts +4 -0
  149. package/esm/core/codegen/selection.js +29 -0
  150. package/esm/core/codegen/shared/index.d.ts +2 -15
  151. package/esm/core/codegen/shared/index.js +16 -3
  152. package/esm/core/codegen/type-resolver.d.ts +1 -5
  153. package/esm/core/codegen/type-resolver.js +1 -22
  154. package/esm/core/codegen/types.d.ts +0 -3
  155. package/esm/core/codegen/types.js +72 -15
  156. package/esm/core/codegen/utils.d.ts +1 -4
  157. package/esm/core/codegen/utils.js +4 -1
  158. package/esm/core/config/index.d.ts +1 -1
  159. package/esm/core/config/resolver.js +2 -4
  160. package/esm/core/generate.js +38 -50
  161. package/esm/core/index.d.ts +3 -3
  162. package/esm/core/index.js +2 -3
  163. package/esm/core/introspect/index.d.ts +6 -6
  164. package/esm/core/introspect/index.js +3 -6
  165. package/esm/core/introspect/infer-tables.d.ts +0 -14
  166. package/esm/core/introspect/infer-tables.js +16 -2
  167. package/esm/core/introspect/source/database.js +2 -2
  168. package/esm/core/introspect/source/endpoint.d.ts +0 -6
  169. package/esm/core/introspect/source/endpoint.js +7 -1
  170. package/esm/core/introspect/source/index.d.ts +4 -4
  171. package/esm/core/introspect/source/index.js +6 -10
  172. package/esm/core/introspect/source/pgpm-module.js +3 -3
  173. package/esm/core/introspect/transform-schema.d.ts +2 -2
  174. package/esm/core/introspect/transform-schema.js +2 -2
  175. package/esm/core/output/index.d.ts +1 -1
  176. package/esm/core/output/index.js +1 -1
  177. package/esm/core/output/writer.d.ts +3 -0
  178. package/esm/core/output/writer.js +20 -1
  179. package/esm/core/pipeline/index.d.ts +2 -2
  180. package/esm/core/pipeline/index.js +2 -2
  181. package/esm/core/query-builder.d.ts +2 -2
  182. package/esm/core/query-builder.js +2 -2
  183. package/esm/core/watch/index.d.ts +4 -4
  184. package/esm/core/watch/index.js +3 -3
  185. package/esm/core/watch/orchestrator.js +5 -3
  186. package/esm/generators/index.d.ts +3 -3
  187. package/esm/generators/index.js +3 -3
  188. package/esm/generators/mutations.d.ts +1 -1
  189. package/esm/generators/select.d.ts +1 -1
  190. package/esm/index.d.ts +3 -3
  191. package/esm/index.js +1 -4
  192. package/esm/types/config.d.ts +0 -10
  193. package/esm/types/config.js +0 -2
  194. package/esm/types/index.d.ts +6 -6
  195. package/esm/types/index.js +1 -1
  196. package/generators/index.d.ts +3 -3
  197. package/generators/index.js +8 -8
  198. package/generators/mutations.d.ts +1 -1
  199. package/generators/select.d.ts +1 -1
  200. package/index.d.ts +3 -3
  201. package/index.js +11 -5
  202. package/package.json +11 -11
  203. package/types/config.d.ts +0 -10
  204. package/types/config.js +0 -2
  205. package/types/index.d.ts +6 -6
  206. package/types/index.js +2 -2
  207. package/core/codegen/gql-ast.d.ts +0 -41
  208. package/core/codegen/gql-ast.js +0 -353
  209. package/core/codegen/schema-gql-ast.d.ts +0 -51
  210. package/core/codegen/schema-gql-ast.js +0 -385
  211. package/core/codegen/templates/client.browser.ts +0 -271
  212. package/core/codegen/templates/client.node.ts +0 -337
  213. package/esm/core/codegen/gql-ast.d.ts +0 -41
  214. package/esm/core/codegen/gql-ast.js +0 -312
  215. package/esm/core/codegen/schema-gql-ast.d.ts +0 -51
  216. package/esm/core/codegen/schema-gql-ast.js +0 -343
@@ -36,325 +36,109 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.generateListQueryHook = generateListQueryHook;
37
37
  exports.generateSingleQueryHook = generateSingleQueryHook;
38
38
  exports.generateAllQueryHooks = generateAllQueryHooks;
39
+ /**
40
+ * Query hook generators - delegates to ORM model methods (Babel AST-based)
41
+ *
42
+ * Output structure:
43
+ * queries/
44
+ * useCarsQuery.ts - List query hook -> ORM findMany
45
+ * useCarQuery.ts - Single item query hook -> ORM findOne
46
+ */
39
47
  const t = __importStar(require("@babel/types"));
40
48
  const babel_ast_1 = require("./babel-ast");
41
- const gql_ast_1 = require("./gql-ast");
49
+ const hooks_ast_1 = require("./hooks-ast");
42
50
  const utils_1 = require("./utils");
43
- function createUnionType(values) {
44
- return t.tsUnionType(values.map((v) => t.tsLiteralType(t.stringLiteral(v))));
45
- }
46
- function createFilterInterfaceDeclaration(name, fieldFilters, isExported = true) {
47
- const properties = [];
48
- for (const filter of fieldFilters) {
49
- const prop = t.tsPropertySignature(t.identifier(filter.fieldName), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(filter.filterType))));
50
- prop.optional = true;
51
- properties.push(prop);
52
- }
53
- const andProp = t.tsPropertySignature(t.identifier('and'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(name)))));
54
- andProp.optional = true;
55
- properties.push(andProp);
56
- const orProp = t.tsPropertySignature(t.identifier('or'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(name)))));
57
- orProp.optional = true;
58
- properties.push(orProp);
59
- const notProp = t.tsPropertySignature(t.identifier('not'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(name))));
60
- notProp.optional = true;
61
- properties.push(notProp);
62
- const body = t.tsInterfaceBody(properties);
63
- const interfaceDecl = t.tsInterfaceDeclaration(t.identifier(name), null, null, body);
64
- if (isExported) {
65
- return t.exportNamedDeclaration(interfaceDecl);
66
- }
67
- return interfaceDecl;
68
- }
69
51
  function generateListQueryHook(table, options = {}) {
70
52
  const { reactQueryEnabled = true, useCentralizedKeys = true, hasRelationships = false, } = options;
71
- const { typeName, pluralName } = (0, utils_1.getTableNames)(table);
53
+ const { typeName, pluralName, singularName } = (0, utils_1.getTableNames)(table);
72
54
  const hookName = (0, utils_1.getListQueryHookName)(table);
73
55
  const queryName = (0, utils_1.getAllRowsQueryName)(table);
74
56
  const filterTypeName = (0, utils_1.getFilterTypeName)(table);
75
- const conditionTypeName = (0, utils_1.getConditionTypeName)(table);
76
57
  const orderByTypeName = (0, utils_1.getOrderByTypeName)(table);
77
- const scalarFields = (0, utils_1.getScalarFields)(table);
78
58
  const keysName = `${(0, utils_1.lcFirst)(typeName)}Keys`;
79
59
  const scopeTypeName = `${typeName}Scope`;
80
- const queryAST = (0, gql_ast_1.buildListQueryAST)({ table });
81
- const queryDocument = (0, gql_ast_1.printGraphQL)(queryAST);
60
+ const selectTypeName = `${typeName}Select`;
61
+ const relationTypeName = `${typeName}WithRelations`;
62
+ const listResultTypeAST = (sel) => (0, hooks_ast_1.listQueryResultType)(queryName, relationTypeName, sel);
82
63
  const statements = [];
83
- const filterTypesUsed = new Set();
84
- for (const field of scalarFields) {
85
- const filterType = (0, utils_1.getScalarFilterType)(field.type.gqlType, field.type.isArray);
86
- if (filterType) {
87
- filterTypesUsed.add(filterType);
88
- }
89
- }
64
+ // Imports
90
65
  if (reactQueryEnabled) {
91
- const reactQueryImport = t.importDeclaration([t.importSpecifier(t.identifier('useQuery'), t.identifier('useQuery'))], t.stringLiteral('@tanstack/react-query'));
92
- statements.push(reactQueryImport);
93
- const reactQueryTypeImport = t.importDeclaration([
94
- t.importSpecifier(t.identifier('UseQueryOptions'), t.identifier('UseQueryOptions')),
95
- t.importSpecifier(t.identifier('QueryClient'), t.identifier('QueryClient')),
96
- ], t.stringLiteral('@tanstack/react-query'));
97
- reactQueryTypeImport.importKind = 'type';
98
- statements.push(reactQueryTypeImport);
66
+ statements.push((0, hooks_ast_1.createImportDeclaration)('@tanstack/react-query', ['useQuery']));
67
+ statements.push((0, hooks_ast_1.createImportDeclaration)('@tanstack/react-query', ['UseQueryOptions', 'UseQueryResult', 'QueryClient'], true));
99
68
  }
100
- const clientImport = t.importDeclaration([t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], t.stringLiteral('../client'));
101
- statements.push(clientImport);
102
- const clientTypeImport = t.importDeclaration([
103
- t.importSpecifier(t.identifier('ExecuteOptions'), t.identifier('ExecuteOptions')),
104
- ], t.stringLiteral('../client'));
105
- clientTypeImport.importKind = 'type';
106
- statements.push(clientTypeImport);
107
- const typesImport = t.importDeclaration([
108
- t.importSpecifier(t.identifier(typeName), t.identifier(typeName)),
109
- ...Array.from(filterTypesUsed).map((ft) => t.importSpecifier(t.identifier(ft), t.identifier(ft))),
110
- ], t.stringLiteral('../types'));
111
- typesImport.importKind = 'type';
112
- statements.push(typesImport);
69
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../client', ['getClient']));
70
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../selection', ['buildListSelectionArgs']));
71
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../selection', ['ListSelectionConfig'], true));
113
72
  if (useCentralizedKeys) {
114
- const queryKeyImport = t.importDeclaration([t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], t.stringLiteral('../query-keys'));
115
- statements.push(queryKeyImport);
73
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../query-keys', [keysName]));
116
74
  if (hasRelationships) {
117
- const scopeTypeImport = t.importDeclaration([
118
- t.importSpecifier(t.identifier(scopeTypeName), t.identifier(scopeTypeName)),
119
- ], t.stringLiteral('../query-keys'));
120
- scopeTypeImport.importKind = 'type';
121
- statements.push(scopeTypeImport);
75
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../query-keys', [scopeTypeName], true));
122
76
  }
123
77
  }
124
- const reExportDecl = t.exportNamedDeclaration(null, [t.exportSpecifier(t.identifier(typeName), t.identifier(typeName))], t.stringLiteral('../types'));
125
- reExportDecl.exportKind = 'type';
126
- statements.push(reExportDecl);
127
- const queryDocConst = t.variableDeclaration('const', [
128
- t.variableDeclarator(t.identifier(`${queryName}QueryDocument`), t.templateLiteral([
129
- t.templateElement({ raw: '\n' + queryDocument, cooked: '\n' + queryDocument }, true),
130
- ], [])),
131
- ]);
132
- statements.push(t.exportNamedDeclaration(queryDocConst));
133
- const fieldFilters = scalarFields
134
- .map((field) => {
135
- const filterType = (0, utils_1.getScalarFilterType)(field.type.gqlType, field.type.isArray);
136
- return filterType ? { fieldName: field.name, filterType } : null;
137
- })
138
- .filter((f) => f !== null);
139
- statements.push(createFilterInterfaceDeclaration(filterTypeName, fieldFilters, false));
140
- // Generate Condition interface (simple equality filter with scalar types)
141
- // Track non-primitive types (enums) that need to be imported
142
- const enumTypesUsed = new Set();
143
- const conditionProperties = scalarFields.map((field) => {
144
- const tsType = (0, utils_1.fieldTypeToTs)(field.type);
145
- const isPrimitive = tsType === 'string' ||
146
- tsType === 'number' ||
147
- tsType === 'boolean' ||
148
- tsType === 'unknown' ||
149
- tsType.endsWith('[]');
150
- let typeAnnotation;
151
- if (field.type.isArray) {
152
- const baseType = tsType.replace('[]', '');
153
- const isBasePrimitive = baseType === 'string' ||
154
- baseType === 'number' ||
155
- baseType === 'boolean' ||
156
- baseType === 'unknown';
157
- if (!isBasePrimitive) {
158
- enumTypesUsed.add(baseType);
159
- }
160
- typeAnnotation = t.tsArrayType(baseType === 'string'
161
- ? t.tsStringKeyword()
162
- : baseType === 'number'
163
- ? t.tsNumberKeyword()
164
- : baseType === 'boolean'
165
- ? t.tsBooleanKeyword()
166
- : t.tsTypeReference(t.identifier(baseType)));
167
- }
168
- else {
169
- if (!isPrimitive) {
170
- enumTypesUsed.add(tsType);
171
- }
172
- typeAnnotation =
173
- tsType === 'string'
174
- ? t.tsStringKeyword()
175
- : tsType === 'number'
176
- ? t.tsNumberKeyword()
177
- : tsType === 'boolean'
178
- ? t.tsBooleanKeyword()
179
- : t.tsTypeReference(t.identifier(tsType));
180
- }
181
- const prop = t.tsPropertySignature(t.identifier(field.name), t.tsTypeAnnotation(typeAnnotation));
182
- prop.optional = true;
183
- return prop;
184
- });
185
- // Add import for enum types if any are used
186
- if (enumTypesUsed.size > 0) {
187
- const schemaTypesImport = t.importDeclaration(Array.from(enumTypesUsed).map((et) => t.importSpecifier(t.identifier(et), t.identifier(et))), t.stringLiteral('../schema-types'));
188
- schemaTypesImport.importKind = 'type';
189
- statements.push(schemaTypesImport);
190
- }
191
- const conditionInterface = t.tsInterfaceDeclaration(t.identifier(conditionTypeName), null, null, t.tsInterfaceBody(conditionProperties));
192
- statements.push(conditionInterface);
193
- const orderByValues = [
194
- ...scalarFields.flatMap((f) => [
195
- `${(0, utils_1.toScreamingSnake)(f.name)}_ASC`,
196
- `${(0, utils_1.toScreamingSnake)(f.name)}_DESC`,
197
- ]),
198
- 'NATURAL',
199
- 'PRIMARY_KEY_ASC',
200
- 'PRIMARY_KEY_DESC',
201
- ];
202
- const orderByTypeAlias = t.tsTypeAliasDeclaration(t.identifier(orderByTypeName), null, createUnionType(orderByValues));
203
- statements.push(orderByTypeAlias);
204
- const variablesInterfaceBody = t.tsInterfaceBody([
205
- (() => {
206
- const p = t.tsPropertySignature(t.identifier('first'), t.tsTypeAnnotation(t.tsNumberKeyword()));
207
- p.optional = true;
208
- return p;
209
- })(),
210
- (() => {
211
- const p = t.tsPropertySignature(t.identifier('last'), t.tsTypeAnnotation(t.tsNumberKeyword()));
212
- p.optional = true;
213
- return p;
214
- })(),
215
- (() => {
216
- const p = t.tsPropertySignature(t.identifier('offset'), t.tsTypeAnnotation(t.tsNumberKeyword()));
217
- p.optional = true;
218
- return p;
219
- })(),
220
- (() => {
221
- const p = t.tsPropertySignature(t.identifier('before'), t.tsTypeAnnotation(t.tsStringKeyword()));
222
- p.optional = true;
223
- return p;
224
- })(),
225
- (() => {
226
- const p = t.tsPropertySignature(t.identifier('after'), t.tsTypeAnnotation(t.tsStringKeyword()));
227
- p.optional = true;
228
- return p;
229
- })(),
230
- (() => {
231
- const p = t.tsPropertySignature(t.identifier('filter'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(filterTypeName))));
232
- p.optional = true;
233
- return p;
234
- })(),
235
- (() => {
236
- const p = t.tsPropertySignature(t.identifier('condition'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(conditionTypeName))));
237
- p.optional = true;
238
- return p;
239
- })(),
240
- (() => {
241
- const p = t.tsPropertySignature(t.identifier('orderBy'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(orderByTypeName)))));
242
- p.optional = true;
243
- return p;
244
- })(),
245
- ]);
246
- const variablesInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`), null, null, variablesInterfaceBody);
247
- statements.push(t.exportNamedDeclaration(variablesInterface));
248
- const pageInfoType = t.tsTypeLiteral([
249
- t.tsPropertySignature(t.identifier('hasNextPage'), t.tsTypeAnnotation(t.tsBooleanKeyword())),
250
- t.tsPropertySignature(t.identifier('hasPreviousPage'), t.tsTypeAnnotation(t.tsBooleanKeyword())),
251
- t.tsPropertySignature(t.identifier('startCursor'), t.tsTypeAnnotation(t.tsUnionType([t.tsStringKeyword(), t.tsNullKeyword()]))),
252
- t.tsPropertySignature(t.identifier('endCursor'), t.tsTypeAnnotation(t.tsUnionType([t.tsStringKeyword(), t.tsNullKeyword()]))),
253
- ]);
254
- const resultType = t.tsTypeLiteral([
255
- t.tsPropertySignature(t.identifier('totalCount'), t.tsTypeAnnotation(t.tsNumberKeyword())),
256
- t.tsPropertySignature(t.identifier('nodes'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(typeName))))),
257
- t.tsPropertySignature(t.identifier('pageInfo'), t.tsTypeAnnotation(pageInfoType)),
258
- ]);
259
- const resultInterfaceBody = t.tsInterfaceBody([
260
- t.tsPropertySignature(t.identifier(queryName), t.tsTypeAnnotation(resultType)),
261
- ]);
262
- const resultInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryResult`), null, null, resultInterfaceBody);
263
- statements.push(t.exportNamedDeclaration(resultInterface));
78
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/input-types', [selectTypeName, relationTypeName, filterTypeName, orderByTypeName], true));
79
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['FindManyArgs', 'InferSelectResult', 'ConnectionResult', 'StrictSelect'], true));
80
+ // Re-exports
81
+ statements.push((0, hooks_ast_1.createTypeReExport)([selectTypeName, relationTypeName, filterTypeName, orderByTypeName], '../../orm/input-types'));
82
+ // Query key
264
83
  if (useCentralizedKeys) {
265
- const queryKeyConst = t.variableDeclaration('const', [
84
+ const keyDecl = t.exportNamedDeclaration(t.variableDeclaration('const', [
266
85
  t.variableDeclarator(t.identifier(`${queryName}QueryKey`), t.memberExpression(t.identifier(keysName), t.identifier('list'))),
267
- ]);
268
- const queryKeyExport = t.exportNamedDeclaration(queryKeyConst);
269
- (0, babel_ast_1.addJSDocComment)(queryKeyExport, [
86
+ ]));
87
+ (0, hooks_ast_1.addJSDocComment)(keyDecl, [
270
88
  'Query key factory - re-exported from query-keys.ts',
271
89
  ]);
272
- statements.push(queryKeyExport);
90
+ statements.push(keyDecl);
273
91
  }
274
92
  else {
275
- const queryKeyArrow = t.arrowFunctionExpression([
276
- (0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)), true),
277
- ], t.tsAsExpression(t.arrayExpression([
93
+ const keyFn = t.arrowFunctionExpression([
94
+ (0, hooks_ast_1.createFunctionParam)('variables', (0, hooks_ast_1.typeRef)('FindManyArgs', [
95
+ t.tsUnknownKeyword(),
96
+ (0, hooks_ast_1.typeRef)(filterTypeName),
97
+ (0, hooks_ast_1.typeRef)(orderByTypeName),
98
+ ]), true),
99
+ ], (0, babel_ast_1.asConst)(t.arrayExpression([
278
100
  t.stringLiteral(typeName.toLowerCase()),
279
101
  t.stringLiteral('list'),
280
102
  t.identifier('variables'),
281
- ]), t.tsTypeReference(t.identifier('const'))));
282
- const queryKeyConst = t.variableDeclaration('const', [
283
- t.variableDeclarator(t.identifier(`${queryName}QueryKey`), queryKeyArrow),
284
- ]);
285
- statements.push(t.exportNamedDeclaration(queryKeyConst));
103
+ ])));
104
+ statements.push(t.exportNamedDeclaration(t.variableDeclaration('const', [
105
+ t.variableDeclarator(t.identifier(`${queryName}QueryKey`), keyFn),
106
+ ])));
286
107
  }
287
- if (reactQueryEnabled) {
288
- const hookBodyStatements = [];
289
- if (hasRelationships && useCentralizedKeys) {
290
- hookBodyStatements.push(t.variableDeclaration('const', [
291
- t.variableDeclarator(t.objectPattern([
292
- t.objectProperty(t.identifier('scope'), t.identifier('scope'), false, true),
293
- t.restElement(t.identifier('queryOptions')),
294
- ]), t.logicalExpression('??', t.identifier('options'), t.objectExpression([]))),
295
- ]));
296
- hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [
297
- t.objectExpression([
298
- t.objectProperty(t.identifier('queryKey'), t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('list')), [t.identifier('variables'), t.identifier('scope')])),
299
- t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${queryName}QueryDocument`), t.identifier('variables')], [
300
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryResult`)),
301
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)),
302
- ]))),
303
- t.spreadElement(t.identifier('queryOptions')),
304
- ]),
305
- ])));
306
- }
307
- else if (useCentralizedKeys) {
308
- hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [
309
- t.objectExpression([
310
- t.objectProperty(t.identifier('queryKey'), t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('list')), [t.identifier('variables')])),
311
- t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${queryName}QueryDocument`), t.identifier('variables')], [
312
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryResult`)),
313
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)),
314
- ]))),
315
- t.spreadElement(t.identifier('options')),
316
- ]),
317
- ])));
318
- }
319
- else {
320
- hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [
321
- t.objectExpression([
322
- t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(`${queryName}QueryKey`), [
323
- t.identifier('variables'),
324
- ])),
325
- t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${queryName}QueryDocument`), t.identifier('variables')], [
326
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryResult`)),
327
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)),
328
- ]))),
329
- t.spreadElement(t.identifier('options')),
330
- ]),
331
- ])));
108
+ // Helper for query key call
109
+ const buildListQueryKey = (argsExpr, scopeExpr) => {
110
+ if (useCentralizedKeys) {
111
+ const args = [argsExpr];
112
+ if (scopeExpr)
113
+ args.push(scopeExpr);
114
+ return (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier(keysName), t.identifier('list')), args);
332
115
  }
333
- const hookParams = [
334
- (0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)), true),
335
- ];
336
- let optionsTypeStr;
116
+ return (0, hooks_ast_1.callExpr)(t.identifier(`${queryName}QueryKey`), [argsExpr]);
117
+ };
118
+ // Helper for findMany queryFn
119
+ const buildFindManyFn = () => t.arrowFunctionExpression([], (0, hooks_ast_1.buildFindManyCallExpr)(singularName, 'args'));
120
+ // Options type builder with optional scope
121
+ const buildOptionsType = (queryDataType, dataType) => {
122
+ const base = (0, hooks_ast_1.omitType)((0, hooks_ast_1.typeRef)('UseQueryOptions', [queryDataType, (0, hooks_ast_1.typeRef)('Error'), dataType]), ['queryKey', 'queryFn']);
337
123
  if (hasRelationships && useCentralizedKeys) {
338
- optionsTypeStr = `Omit<UseQueryOptions<${(0, utils_1.ucFirst)(pluralName)}QueryResult, Error>, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }`;
124
+ return t.tsIntersectionType([base, (0, hooks_ast_1.scopeTypeLiteral)(scopeTypeName)]);
339
125
  }
340
- else {
341
- optionsTypeStr = `Omit<UseQueryOptions<${(0, utils_1.ucFirst)(pluralName)}QueryResult, Error>, 'queryKey' | 'queryFn'>`;
342
- }
343
- const optionsParam = t.identifier('options');
344
- optionsParam.optional = true;
345
- optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr)));
346
- hookParams.push(optionsParam);
347
- const hookFunc = t.functionDeclaration(t.identifier(hookName), hookParams, t.blockStatement(hookBodyStatements));
348
- const hookExport = t.exportNamedDeclaration(hookFunc);
126
+ return base;
127
+ };
128
+ // Hook
129
+ if (reactQueryEnabled) {
349
130
  const docLines = [
350
131
  `Query hook for fetching ${typeName} list`,
351
132
  '',
352
133
  '@example',
353
134
  '```tsx',
354
135
  `const { data, isLoading } = ${hookName}({`,
355
- ' first: 10,',
356
- ' filter: { name: { equalTo: "example" } },',
357
- " orderBy: ['CREATED_AT_DESC'],",
136
+ ' selection: {',
137
+ ' fields: { id: true, name: true },',
138
+ ' where: { name: { equalTo: "example" } },',
139
+ " orderBy: ['CREATED_AT_DESC'],",
140
+ ' first: 10,',
141
+ ' },',
358
142
  '});',
359
143
  '```',
360
144
  ];
@@ -362,364 +146,381 @@ function generateListQueryHook(table, options = {}) {
362
146
  docLines.push('');
363
147
  docLines.push('@example With scope for hierarchical cache invalidation');
364
148
  docLines.push('```tsx');
365
- docLines.push(`const { data } = ${hookName}(`);
366
- docLines.push(' { first: 10 },');
367
- docLines.push(" { scope: { parentId: 'parent-id' } }");
368
- docLines.push(');');
149
+ docLines.push(`const { data } = ${hookName}({`);
150
+ docLines.push(' selection: { fields: { id: true }, first: 10 },');
151
+ docLines.push(" scope: { parentId: 'parent-id' },");
152
+ docLines.push('});');
369
153
  docLines.push('```');
370
154
  }
371
- (0, babel_ast_1.addJSDocComment)(hookExport, docLines);
372
- statements.push(hookExport);
373
- }
374
- const fetchFuncBody = t.blockStatement([
375
- t.returnStatement((0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${queryName}QueryDocument`), t.identifier('variables'), t.identifier('options')], [
376
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryResult`)),
377
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)),
378
- ])),
379
- ]);
380
- const fetchFunc = t.functionDeclaration(t.identifier(`fetch${(0, utils_1.ucFirst)(pluralName)}Query`), [
381
- (0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)), true),
382
- (0, babel_ast_1.typedParam)('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true),
383
- ], fetchFuncBody);
384
- fetchFunc.async = true;
385
- fetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([
386
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryResult`)),
387
- ])));
388
- const fetchExport = t.exportNamedDeclaration(fetchFunc);
389
- (0, babel_ast_1.addJSDocComment)(fetchExport, [
390
- `Fetch ${typeName} list without React hooks`,
391
- '',
392
- '@example',
393
- '```ts',
394
- '// Direct fetch',
395
- `const data = await fetch${(0, utils_1.ucFirst)(pluralName)}Query({ first: 10 });`,
396
- '',
397
- '// With QueryClient',
398
- 'const data = await queryClient.fetchQuery({',
399
- ` queryKey: ${queryName}QueryKey(variables),`,
400
- ` queryFn: () => fetch${(0, utils_1.ucFirst)(pluralName)}Query(variables),`,
401
- '});',
402
- '```',
403
- ]);
404
- statements.push(fetchExport);
405
- if (reactQueryEnabled) {
406
- const prefetchParams = [
407
- (0, babel_ast_1.typedParam)('queryClient', t.tsTypeReference(t.identifier('QueryClient'))),
408
- (0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)), true),
409
- ];
410
- if (hasRelationships && useCentralizedKeys) {
411
- prefetchParams.push((0, babel_ast_1.typedParam)('scope', t.tsTypeReference(t.identifier(scopeTypeName)), true));
412
- }
413
- prefetchParams.push((0, babel_ast_1.typedParam)('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true));
414
- let prefetchQueryKeyExpr;
155
+ // Overload 1: with fields
156
+ const o1ParamType = t.tsIntersectionType([
157
+ t.tsTypeLiteral([
158
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.withFieldsListSelectionType)((0, hooks_ast_1.sRef)(), selectTypeName, filterTypeName, orderByTypeName))),
159
+ ]),
160
+ buildOptionsType(listResultTypeAST((0, hooks_ast_1.sRef)()), (0, hooks_ast_1.typeRef)('TData')),
161
+ ]);
162
+ const o1 = (0, hooks_ast_1.exportDeclareFunction)(hookName, (0, hooks_ast_1.createSAndTDataTypeParams)(selectTypeName, listResultTypeAST((0, hooks_ast_1.sRef)())), [(0, hooks_ast_1.createFunctionParam)('params', o1ParamType)], (0, hooks_ast_1.typeRef)('UseQueryResult', [(0, hooks_ast_1.typeRef)('TData')]));
163
+ (0, hooks_ast_1.addJSDocComment)(o1, docLines);
164
+ statements.push(o1);
165
+ // Implementation
166
+ const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.listSelectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName), filterTypeName, orderByTypeName)));
167
+ const implOptionsType = (() => {
168
+ const base = (0, hooks_ast_1.useQueryOptionsImplType)();
169
+ if (hasRelationships && useCentralizedKeys) {
170
+ return t.tsIntersectionType([base, (0, hooks_ast_1.scopeTypeLiteral)(scopeTypeName)]);
171
+ }
172
+ return base;
173
+ })();
174
+ const implParamType = t.tsIntersectionType([
175
+ t.tsTypeLiteral([implSelProp]),
176
+ implOptionsType,
177
+ ]);
178
+ const body = [];
179
+ body.push((0, hooks_ast_1.buildListSelectionArgsCall)(selectTypeName, filterTypeName, orderByTypeName));
415
180
  if (hasRelationships && useCentralizedKeys) {
416
- prefetchQueryKeyExpr = t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('list')), [t.identifier('variables'), t.identifier('scope')]);
417
- }
418
- else if (useCentralizedKeys) {
419
- prefetchQueryKeyExpr = t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('list')), [t.identifier('variables')]);
181
+ body.push((0, hooks_ast_1.destructureParamsWithSelectionAndScope)('queryOptions'));
182
+ body.push((0, hooks_ast_1.voidStatement)('_selection'));
183
+ body.push((0, hooks_ast_1.returnUseQuery)(buildListQueryKey(t.identifier('args'), t.identifier('scope')), buildFindManyFn(), [(0, hooks_ast_1.spreadObj)(t.identifier('queryOptions'))]));
420
184
  }
421
185
  else {
422
- prefetchQueryKeyExpr = t.callExpression(t.identifier(`${queryName}QueryKey`), [t.identifier('variables')]);
186
+ body.push((0, hooks_ast_1.destructureParamsWithSelection)('queryOptions'));
187
+ body.push((0, hooks_ast_1.voidStatement)('_selection'));
188
+ body.push((0, hooks_ast_1.returnUseQuery)(buildListQueryKey(t.identifier('args')), buildFindManyFn(), [(0, hooks_ast_1.spreadObj)(t.identifier('queryOptions'))]));
423
189
  }
424
- const prefetchFuncBody = t.blockStatement([
425
- t.expressionStatement(t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [
426
- t.objectExpression([
427
- t.objectProperty(t.identifier('queryKey'), prefetchQueryKeyExpr),
428
- t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${queryName}QueryDocument`), t.identifier('variables'), t.identifier('options')], [
429
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryResult`)),
430
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(pluralName)}QueryVariables`)),
431
- ]))),
432
- ]),
433
- ]))),
190
+ statements.push((0, hooks_ast_1.exportFunction)(hookName, null, [(0, hooks_ast_1.createFunctionParam)('params', implParamType)], body));
191
+ }
192
+ // Fetch function
193
+ const fetchFnName = `fetch${(0, utils_1.ucFirst)(pluralName)}Query`;
194
+ {
195
+ // Overload 1: with fields
196
+ const f1ParamType = t.tsTypeLiteral([
197
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.withFieldsListSelectionType)((0, hooks_ast_1.sRef)(), selectTypeName, filterTypeName, orderByTypeName))),
198
+ ]);
199
+ const f1Decl = (0, hooks_ast_1.exportAsyncDeclareFunction)(fetchFnName, (0, hooks_ast_1.createSTypeParam)(selectTypeName), [(0, hooks_ast_1.createFunctionParam)('params', f1ParamType)], (0, hooks_ast_1.typeRef)('Promise', [listResultTypeAST((0, hooks_ast_1.sRef)())]));
200
+ (0, hooks_ast_1.addJSDocComment)(f1Decl, [
201
+ `Fetch ${typeName} list without React hooks`,
202
+ '',
203
+ '@example',
204
+ '```ts',
205
+ `const data = await ${fetchFnName}({`,
206
+ ' selection: {',
207
+ ' fields: { id: true },',
208
+ ' first: 10,',
209
+ ' },',
210
+ '});',
211
+ '```',
212
+ ]);
213
+ statements.push(f1Decl);
214
+ // Implementation
215
+ const fImplParamType = t.tsTypeLiteral([
216
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.listSelectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName), filterTypeName, orderByTypeName))),
434
217
  ]);
435
- const prefetchFunc = t.functionDeclaration(t.identifier(`prefetch${(0, utils_1.ucFirst)(pluralName)}Query`), prefetchParams, prefetchFuncBody);
436
- prefetchFunc.async = true;
437
- prefetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([t.tsVoidKeyword()])));
438
- const prefetchExport = t.exportNamedDeclaration(prefetchFunc);
439
- (0, babel_ast_1.addJSDocComment)(prefetchExport, [
218
+ const fBody = [];
219
+ fBody.push((0, hooks_ast_1.buildListSelectionArgsCall)(selectTypeName, filterTypeName, orderByTypeName));
220
+ fBody.push(t.returnStatement((0, hooks_ast_1.buildFindManyCallExpr)(singularName, 'args')));
221
+ statements.push((0, hooks_ast_1.exportAsyncFunction)(fetchFnName, null, [(0, hooks_ast_1.createFunctionParam)('params', fImplParamType)], fBody));
222
+ }
223
+ // Prefetch function
224
+ if (reactQueryEnabled) {
225
+ const prefetchFnName = `prefetch${(0, utils_1.ucFirst)(pluralName)}Query`;
226
+ // Overload 1: with fields
227
+ const p1Params = [
228
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.withFieldsListSelectionType)((0, hooks_ast_1.sRef)(), selectTypeName, filterTypeName, orderByTypeName))),
229
+ ];
230
+ const p1ParamType = hasRelationships && useCentralizedKeys
231
+ ? t.tsIntersectionType([
232
+ t.tsTypeLiteral(p1Params),
233
+ (0, hooks_ast_1.scopeTypeLiteral)(scopeTypeName),
234
+ ])
235
+ : t.tsTypeLiteral(p1Params);
236
+ const p1Decl = (0, hooks_ast_1.exportAsyncDeclareFunction)(prefetchFnName, (0, hooks_ast_1.createSTypeParam)(selectTypeName), [
237
+ (0, hooks_ast_1.createFunctionParam)('queryClient', (0, hooks_ast_1.typeRef)('QueryClient')),
238
+ (0, hooks_ast_1.createFunctionParam)('params', p1ParamType),
239
+ ], (0, hooks_ast_1.typeRef)('Promise', [t.tsVoidKeyword()]));
240
+ (0, hooks_ast_1.addJSDocComment)(p1Decl, [
440
241
  `Prefetch ${typeName} list for SSR or cache warming`,
441
242
  '',
442
243
  '@example',
443
244
  '```ts',
444
- `await prefetch${(0, utils_1.ucFirst)(pluralName)}Query(queryClient, { first: 10 });`,
245
+ `await ${prefetchFnName}(queryClient, { selection: { fields: { id: true }, first: 10 } });`,
445
246
  '```',
446
247
  ]);
447
- statements.push(prefetchExport);
248
+ statements.push(p1Decl);
249
+ // Implementation
250
+ const pImplParamType = hasRelationships && useCentralizedKeys
251
+ ? t.tsIntersectionType([
252
+ t.tsTypeLiteral([
253
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.listSelectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName), filterTypeName, orderByTypeName))),
254
+ ]),
255
+ (0, hooks_ast_1.scopeTypeLiteral)(scopeTypeName),
256
+ ])
257
+ : t.tsTypeLiteral([
258
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.listSelectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName), filterTypeName, orderByTypeName))),
259
+ ]);
260
+ const pBody = [];
261
+ pBody.push((0, hooks_ast_1.buildListSelectionArgsCall)(selectTypeName, filterTypeName, orderByTypeName));
262
+ const queryKeyExpr = hasRelationships && useCentralizedKeys
263
+ ? buildListQueryKey(t.identifier('args'), t.optionalMemberExpression(t.identifier('params'), t.identifier('scope'), false, true))
264
+ : buildListQueryKey(t.identifier('args'));
265
+ const prefetchCall = (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [
266
+ t.objectExpression([
267
+ (0, hooks_ast_1.objectProp)('queryKey', queryKeyExpr),
268
+ (0, hooks_ast_1.objectProp)('queryFn', buildFindManyFn()),
269
+ ]),
270
+ ]);
271
+ pBody.push(t.expressionStatement(t.awaitExpression(prefetchCall)));
272
+ statements.push((0, hooks_ast_1.exportAsyncFunction)(prefetchFnName, null, [
273
+ (0, hooks_ast_1.createFunctionParam)('queryClient', (0, hooks_ast_1.typeRef)('QueryClient')),
274
+ (0, hooks_ast_1.createFunctionParam)('params', pImplParamType),
275
+ ], pBody, (0, hooks_ast_1.typeRef)('Promise', [t.tsVoidKeyword()])));
448
276
  }
449
- const code = (0, babel_ast_1.generateCode)(statements);
450
277
  const headerText = reactQueryEnabled
451
278
  ? `List query hook for ${typeName}`
452
279
  : `List query functions for ${typeName}`;
453
- const content = (0, utils_1.getGeneratedFileHeader)(headerText) + '\n\n' + code;
454
280
  return {
455
281
  fileName: (0, utils_1.getListQueryFileName)(table),
456
- content,
282
+ content: (0, hooks_ast_1.generateHookFileCode)(headerText, statements),
457
283
  };
458
284
  }
459
285
  function generateSingleQueryHook(table, options = {}) {
460
- // Skip tables with composite keys - they are handled as custom queries
461
- if (!(0, utils_1.hasValidPrimaryKey)(table)) {
286
+ if (!(0, utils_1.hasValidPrimaryKey)(table))
462
287
  return null;
463
- }
464
288
  const { reactQueryEnabled = true, useCentralizedKeys = true, hasRelationships = false, } = options;
465
289
  const { typeName, singularName } = (0, utils_1.getTableNames)(table);
466
290
  const hookName = (0, utils_1.getSingleQueryHookName)(table);
467
291
  const queryName = (0, utils_1.getSingleRowQueryName)(table);
468
292
  const keysName = `${(0, utils_1.lcFirst)(typeName)}Keys`;
469
293
  const scopeTypeName = `${typeName}Scope`;
294
+ const selectTypeName = `${typeName}Select`;
295
+ const relationTypeName = `${typeName}WithRelations`;
470
296
  const pkFields = (0, utils_1.getPrimaryKeyInfo)(table);
471
297
  const pkField = pkFields[0];
472
- const pkName = pkField.name;
473
- const pkTsType = pkField.tsType;
474
- const queryAST = (0, gql_ast_1.buildSingleQueryAST)({ table });
475
- const queryDocument = (0, gql_ast_1.printGraphQL)(queryAST);
298
+ const pkFieldName = pkField?.name ?? 'id';
299
+ const pkFieldTsType = pkField?.tsType ?? 'string';
300
+ const pkTsType = pkFieldTsType === 'string' ? t.tsStringKeyword() : t.tsNumberKeyword();
301
+ const singleResultTypeAST = (sel) => (0, hooks_ast_1.singleQueryResultType)(queryName, relationTypeName, sel);
476
302
  const statements = [];
303
+ // Imports
477
304
  if (reactQueryEnabled) {
478
- const reactQueryImport = t.importDeclaration([t.importSpecifier(t.identifier('useQuery'), t.identifier('useQuery'))], t.stringLiteral('@tanstack/react-query'));
479
- statements.push(reactQueryImport);
480
- const reactQueryTypeImport = t.importDeclaration([
481
- t.importSpecifier(t.identifier('UseQueryOptions'), t.identifier('UseQueryOptions')),
482
- t.importSpecifier(t.identifier('QueryClient'), t.identifier('QueryClient')),
483
- ], t.stringLiteral('@tanstack/react-query'));
484
- reactQueryTypeImport.importKind = 'type';
485
- statements.push(reactQueryTypeImport);
305
+ statements.push((0, hooks_ast_1.createImportDeclaration)('@tanstack/react-query', ['useQuery']));
306
+ statements.push((0, hooks_ast_1.createImportDeclaration)('@tanstack/react-query', ['UseQueryOptions', 'UseQueryResult', 'QueryClient'], true));
486
307
  }
487
- const clientImport = t.importDeclaration([t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], t.stringLiteral('../client'));
488
- statements.push(clientImport);
489
- const clientTypeImport = t.importDeclaration([
490
- t.importSpecifier(t.identifier('ExecuteOptions'), t.identifier('ExecuteOptions')),
491
- ], t.stringLiteral('../client'));
492
- clientTypeImport.importKind = 'type';
493
- statements.push(clientTypeImport);
494
- const typesImport = t.importDeclaration([t.importSpecifier(t.identifier(typeName), t.identifier(typeName))], t.stringLiteral('../types'));
495
- typesImport.importKind = 'type';
496
- statements.push(typesImport);
308
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../client', ['getClient']));
309
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../selection', ['buildSelectionArgs']));
310
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../selection', ['SelectionConfig'], true));
497
311
  if (useCentralizedKeys) {
498
- const queryKeyImport = t.importDeclaration([t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], t.stringLiteral('../query-keys'));
499
- statements.push(queryKeyImport);
312
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../query-keys', [keysName]));
500
313
  if (hasRelationships) {
501
- const scopeTypeImport = t.importDeclaration([
502
- t.importSpecifier(t.identifier(scopeTypeName), t.identifier(scopeTypeName)),
503
- ], t.stringLiteral('../query-keys'));
504
- scopeTypeImport.importKind = 'type';
505
- statements.push(scopeTypeImport);
314
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../query-keys', [scopeTypeName], true));
506
315
  }
507
316
  }
508
- const reExportDecl = t.exportNamedDeclaration(null, [t.exportSpecifier(t.identifier(typeName), t.identifier(typeName))], t.stringLiteral('../types'));
509
- reExportDecl.exportKind = 'type';
510
- statements.push(reExportDecl);
511
- const queryDocConst = t.variableDeclaration('const', [
512
- t.variableDeclarator(t.identifier(`${queryName}QueryDocument`), t.templateLiteral([
513
- t.templateElement({ raw: '\n' + queryDocument, cooked: '\n' + queryDocument }, true),
514
- ], [])),
515
- ]);
516
- statements.push(t.exportNamedDeclaration(queryDocConst));
517
- const pkTypeAnnotation = pkTsType === 'string'
518
- ? t.tsStringKeyword()
519
- : pkTsType === 'number'
520
- ? t.tsNumberKeyword()
521
- : t.tsTypeReference(t.identifier(pkTsType));
522
- const variablesInterfaceBody = t.tsInterfaceBody([
523
- t.tsPropertySignature(t.identifier(pkName), t.tsTypeAnnotation(pkTypeAnnotation)),
524
- ]);
525
- const variablesInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`), null, null, variablesInterfaceBody);
526
- statements.push(t.exportNamedDeclaration(variablesInterface));
527
- const resultInterfaceBody = t.tsInterfaceBody([
528
- t.tsPropertySignature(t.identifier(queryName), t.tsTypeAnnotation(t.tsUnionType([
529
- t.tsTypeReference(t.identifier(typeName)),
530
- t.tsNullKeyword(),
531
- ]))),
532
- ]);
533
- const resultInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryResult`), null, null, resultInterfaceBody);
534
- statements.push(t.exportNamedDeclaration(resultInterface));
317
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/input-types', [selectTypeName, relationTypeName], true));
318
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true));
319
+ // Re-exports
320
+ statements.push((0, hooks_ast_1.createTypeReExport)([selectTypeName, relationTypeName], '../../orm/input-types'));
321
+ // Query key
535
322
  if (useCentralizedKeys) {
536
- const queryKeyConst = t.variableDeclaration('const', [
323
+ const keyDecl = t.exportNamedDeclaration(t.variableDeclaration('const', [
537
324
  t.variableDeclarator(t.identifier(`${queryName}QueryKey`), t.memberExpression(t.identifier(keysName), t.identifier('detail'))),
538
- ]);
539
- const queryKeyExport = t.exportNamedDeclaration(queryKeyConst);
540
- (0, babel_ast_1.addJSDocComment)(queryKeyExport, [
325
+ ]));
326
+ (0, hooks_ast_1.addJSDocComment)(keyDecl, [
541
327
  'Query key factory - re-exported from query-keys.ts',
542
328
  ]);
543
- statements.push(queryKeyExport);
329
+ statements.push(keyDecl);
544
330
  }
545
331
  else {
546
- const queryKeyArrow = t.arrowFunctionExpression([(0, babel_ast_1.typedParam)(pkName, pkTypeAnnotation)], t.tsAsExpression(t.arrayExpression([
332
+ const keyFn = t.arrowFunctionExpression([(0, hooks_ast_1.createFunctionParam)('id', pkTsType)], (0, babel_ast_1.asConst)(t.arrayExpression([
547
333
  t.stringLiteral(typeName.toLowerCase()),
548
334
  t.stringLiteral('detail'),
549
- t.identifier(pkName),
550
- ]), t.tsTypeReference(t.identifier('const'))));
551
- const queryKeyConst = t.variableDeclaration('const', [
552
- t.variableDeclarator(t.identifier(`${queryName}QueryKey`), queryKeyArrow),
553
- ]);
554
- statements.push(t.exportNamedDeclaration(queryKeyConst));
335
+ t.identifier('id'),
336
+ ])));
337
+ statements.push(t.exportNamedDeclaration(t.variableDeclaration('const', [
338
+ t.variableDeclarator(t.identifier(`${queryName}QueryKey`), keyFn),
339
+ ])));
555
340
  }
556
- if (reactQueryEnabled) {
557
- const hookBodyStatements = [];
558
- if (hasRelationships && useCentralizedKeys) {
559
- hookBodyStatements.push(t.variableDeclaration('const', [
560
- t.variableDeclarator(t.objectPattern([
561
- t.objectProperty(t.identifier('scope'), t.identifier('scope'), false, true),
562
- t.restElement(t.identifier('queryOptions')),
563
- ]), t.logicalExpression('??', t.identifier('options'), t.objectExpression([]))),
564
- ]));
565
- hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [
566
- t.objectExpression([
567
- t.objectProperty(t.identifier('queryKey'), t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [
568
- t.memberExpression(t.identifier('variables'), t.identifier(pkName)),
569
- t.identifier('scope'),
570
- ])),
571
- t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${queryName}QueryDocument`), t.identifier('variables')], [
572
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryResult`)),
573
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`)),
574
- ]))),
575
- t.spreadElement(t.identifier('queryOptions')),
576
- ]),
577
- ])));
341
+ // Helper for query key call
342
+ const buildDetailQueryKey = (pkExpr, scopeExpr) => {
343
+ if (useCentralizedKeys) {
344
+ const args = [pkExpr];
345
+ if (scopeExpr)
346
+ args.push(scopeExpr);
347
+ return (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier(keysName), t.identifier('detail')), args);
578
348
  }
579
- else if (useCentralizedKeys) {
580
- hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [
581
- t.objectExpression([
582
- t.objectProperty(t.identifier('queryKey'), t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [
583
- t.memberExpression(t.identifier('variables'), t.identifier(pkName)),
584
- ])),
585
- t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${queryName}QueryDocument`), t.identifier('variables')], [
586
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryResult`)),
587
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`)),
588
- ]))),
589
- t.spreadElement(t.identifier('options')),
590
- ]),
591
- ])));
592
- }
593
- else {
594
- hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [
595
- t.objectExpression([
596
- t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(`${queryName}QueryKey`), [
597
- t.memberExpression(t.identifier('variables'), t.identifier(pkName)),
598
- ])),
599
- t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${queryName}QueryDocument`), t.identifier('variables')], [
600
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryResult`)),
601
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`)),
602
- ]))),
603
- t.spreadElement(t.identifier('options')),
604
- ]),
605
- ])));
606
- }
607
- const hookParams = [
608
- (0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`))),
609
- ];
610
- let optionsTypeStr;
349
+ return (0, hooks_ast_1.callExpr)(t.identifier(`${queryName}QueryKey`), [pkExpr]);
350
+ };
351
+ // Helper for findOne queryFn
352
+ const buildFindOneFn = () => t.arrowFunctionExpression([], (0, hooks_ast_1.buildFindOneCallExpr)(singularName, pkFieldName, 'args'));
353
+ // Options type builder with optional scope
354
+ const buildSingleOptionsType = (queryDataType, dataType) => {
355
+ const base = (0, hooks_ast_1.omitType)((0, hooks_ast_1.typeRef)('UseQueryOptions', [queryDataType, (0, hooks_ast_1.typeRef)('Error'), dataType]), ['queryKey', 'queryFn']);
611
356
  if (hasRelationships && useCentralizedKeys) {
612
- optionsTypeStr = `Omit<UseQueryOptions<${(0, utils_1.ucFirst)(singularName)}QueryResult, Error>, 'queryKey' | 'queryFn'> & { scope?: ${scopeTypeName} }`;
613
- }
614
- else {
615
- optionsTypeStr = `Omit<UseQueryOptions<${(0, utils_1.ucFirst)(singularName)}QueryResult, Error>, 'queryKey' | 'queryFn'>`;
357
+ return t.tsIntersectionType([base, (0, hooks_ast_1.scopeTypeLiteral)(scopeTypeName)]);
616
358
  }
617
- const optionsParam = t.identifier('options');
618
- optionsParam.optional = true;
619
- optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr)));
620
- hookParams.push(optionsParam);
621
- const hookFunc = t.functionDeclaration(t.identifier(hookName), hookParams, t.blockStatement(hookBodyStatements));
622
- const hookExport = t.exportNamedDeclaration(hookFunc);
359
+ return base;
360
+ };
361
+ // Hook
362
+ if (reactQueryEnabled) {
623
363
  const docLines = [
624
364
  `Query hook for fetching a single ${typeName}`,
625
365
  '',
626
366
  '@example',
627
367
  '```tsx',
628
- `const { data, isLoading } = ${hookName}({ ${pkName}: 'some-id' });`,
368
+ `const { data, isLoading } = ${hookName}({`,
369
+ ` ${pkFieldName}: 'some-id',`,
370
+ ' selection: { fields: { id: true, name: true } },',
371
+ '});',
629
372
  '```',
630
373
  ];
631
374
  if (hasRelationships && useCentralizedKeys) {
632
375
  docLines.push('');
633
376
  docLines.push('@example With scope for hierarchical cache invalidation');
634
377
  docLines.push('```tsx');
635
- docLines.push(`const { data } = ${hookName}(`);
636
- docLines.push(` { ${pkName}: 'some-id' },`);
637
- docLines.push(" { scope: { parentId: 'parent-id' } }");
638
- docLines.push(');');
378
+ docLines.push(`const { data } = ${hookName}({`);
379
+ docLines.push(` ${pkFieldName}: 'some-id',`);
380
+ docLines.push(' selection: { fields: { id: true } },');
381
+ docLines.push(" scope: { parentId: 'parent-id' },");
382
+ docLines.push('});');
639
383
  docLines.push('```');
640
384
  }
641
- (0, babel_ast_1.addJSDocComment)(hookExport, docLines);
642
- statements.push(hookExport);
643
- }
644
- const fetchFuncBody = t.blockStatement([
645
- t.returnStatement((0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${queryName}QueryDocument`), t.identifier('variables'), t.identifier('options')], [
646
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryResult`)),
647
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`)),
648
- ])),
649
- ]);
650
- const fetchFunc = t.functionDeclaration(t.identifier(`fetch${(0, utils_1.ucFirst)(singularName)}Query`), [
651
- (0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`))),
652
- (0, babel_ast_1.typedParam)('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true),
653
- ], fetchFuncBody);
654
- fetchFunc.async = true;
655
- fetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([
656
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryResult`)),
657
- ])));
658
- const fetchExport = t.exportNamedDeclaration(fetchFunc);
659
- (0, babel_ast_1.addJSDocComment)(fetchExport, [
660
- `Fetch a single ${typeName} without React hooks`,
661
- '',
662
- '@example',
663
- '```ts',
664
- `const data = await fetch${(0, utils_1.ucFirst)(singularName)}Query({ ${pkName}: 'some-id' });`,
665
- '```',
666
- ]);
667
- statements.push(fetchExport);
668
- if (reactQueryEnabled) {
669
- const prefetchParams = [
670
- (0, babel_ast_1.typedParam)('queryClient', t.tsTypeReference(t.identifier('QueryClient'))),
671
- (0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`))),
385
+ // Overload 1: with fields
386
+ const o1Props = [
387
+ t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)),
388
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.withFieldsSelectionType)((0, hooks_ast_1.sRef)(), selectTypeName))),
672
389
  ];
390
+ const o1ParamType = t.tsIntersectionType([
391
+ t.tsTypeLiteral(o1Props),
392
+ buildSingleOptionsType(singleResultTypeAST((0, hooks_ast_1.sRef)()), (0, hooks_ast_1.typeRef)('TData')),
393
+ ]);
394
+ const o1 = (0, hooks_ast_1.exportDeclareFunction)(hookName, (0, hooks_ast_1.createSAndTDataTypeParams)(selectTypeName, singleResultTypeAST((0, hooks_ast_1.sRef)())), [(0, hooks_ast_1.createFunctionParam)('params', o1ParamType)], (0, hooks_ast_1.typeRef)('UseQueryResult', [(0, hooks_ast_1.typeRef)('TData')]));
395
+ (0, hooks_ast_1.addJSDocComment)(o1, docLines);
396
+ statements.push(o1);
397
+ // Implementation
398
+ const implProps = [
399
+ t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)),
400
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.selectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName)))),
401
+ ];
402
+ const implOptionsType = (() => {
403
+ const base = (0, hooks_ast_1.useQueryOptionsImplType)();
404
+ if (hasRelationships && useCentralizedKeys) {
405
+ return t.tsIntersectionType([base, (0, hooks_ast_1.scopeTypeLiteral)(scopeTypeName)]);
406
+ }
407
+ return base;
408
+ })();
409
+ const implParamType = t.tsIntersectionType([
410
+ t.tsTypeLiteral(implProps),
411
+ implOptionsType,
412
+ ]);
413
+ const body = [];
414
+ body.push((0, hooks_ast_1.buildSelectionArgsCall)(selectTypeName));
415
+ const pkMemberExpr = t.memberExpression(t.identifier('params'), t.identifier(pkFieldName));
673
416
  if (hasRelationships && useCentralizedKeys) {
674
- prefetchParams.push((0, babel_ast_1.typedParam)('scope', t.tsTypeReference(t.identifier(scopeTypeName)), true));
675
- }
676
- prefetchParams.push((0, babel_ast_1.typedParam)('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true));
677
- let prefetchQueryKeyExpr;
678
- if (hasRelationships && useCentralizedKeys) {
679
- prefetchQueryKeyExpr = t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [
680
- t.memberExpression(t.identifier('variables'), t.identifier(pkName)),
681
- t.identifier('scope'),
682
- ]);
683
- }
684
- else if (useCentralizedKeys) {
685
- prefetchQueryKeyExpr = t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [t.memberExpression(t.identifier('variables'), t.identifier(pkName))]);
417
+ body.push((0, hooks_ast_1.destructureParamsWithSelectionAndScope)('queryOptions'));
418
+ body.push((0, hooks_ast_1.voidStatement)('_selection'));
419
+ body.push((0, hooks_ast_1.returnUseQuery)(buildDetailQueryKey(pkMemberExpr, t.identifier('scope')), buildFindOneFn(), [(0, hooks_ast_1.spreadObj)(t.identifier('queryOptions'))]));
686
420
  }
687
421
  else {
688
- prefetchQueryKeyExpr = t.callExpression(t.identifier(`${queryName}QueryKey`), [t.memberExpression(t.identifier('variables'), t.identifier(pkName))]);
422
+ body.push((0, hooks_ast_1.destructureParamsWithSelection)('queryOptions'));
423
+ body.push((0, hooks_ast_1.voidStatement)('_selection'));
424
+ body.push((0, hooks_ast_1.returnUseQuery)(buildDetailQueryKey(pkMemberExpr), buildFindOneFn(), [
425
+ (0, hooks_ast_1.spreadObj)(t.identifier('queryOptions')),
426
+ ]));
689
427
  }
690
- const prefetchFuncBody = t.blockStatement([
691
- t.expressionStatement(t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [
692
- t.objectExpression([
693
- t.objectProperty(t.identifier('queryKey'), prefetchQueryKeyExpr),
694
- t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${queryName}QueryDocument`), t.identifier('variables'), t.identifier('options')], [
695
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryResult`)),
696
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(singularName)}QueryVariables`)),
697
- ]))),
698
- ]),
699
- ]))),
428
+ statements.push((0, hooks_ast_1.exportFunction)(hookName, null, [(0, hooks_ast_1.createFunctionParam)('params', implParamType)], body));
429
+ }
430
+ // Fetch function
431
+ const fetchFnName = `fetch${(0, utils_1.ucFirst)(singularName)}Query`;
432
+ {
433
+ // Overload 1: with fields
434
+ const f1Props = [
435
+ t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)),
436
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.withFieldsSelectionType)((0, hooks_ast_1.sRef)(), selectTypeName))),
437
+ ];
438
+ const f1Decl = (0, hooks_ast_1.exportAsyncDeclareFunction)(fetchFnName, (0, hooks_ast_1.createSTypeParam)(selectTypeName), [(0, hooks_ast_1.createFunctionParam)('params', t.tsTypeLiteral(f1Props))], (0, hooks_ast_1.typeRef)('Promise', [singleResultTypeAST((0, hooks_ast_1.sRef)())]));
439
+ (0, hooks_ast_1.addJSDocComment)(f1Decl, [
440
+ `Fetch a single ${typeName} without React hooks`,
441
+ '',
442
+ '@example',
443
+ '```ts',
444
+ `const data = await ${fetchFnName}({`,
445
+ ` ${pkFieldName}: 'some-id',`,
446
+ ' selection: { fields: { id: true } },',
447
+ '});',
448
+ '```',
700
449
  ]);
701
- const prefetchFunc = t.functionDeclaration(t.identifier(`prefetch${(0, utils_1.ucFirst)(singularName)}Query`), prefetchParams, prefetchFuncBody);
702
- prefetchFunc.async = true;
703
- prefetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([t.tsVoidKeyword()])));
704
- const prefetchExport = t.exportNamedDeclaration(prefetchFunc);
705
- (0, babel_ast_1.addJSDocComment)(prefetchExport, [
450
+ statements.push(f1Decl);
451
+ // Implementation
452
+ const fBody = [];
453
+ fBody.push((0, hooks_ast_1.buildSelectionArgsCall)(selectTypeName));
454
+ fBody.push(t.returnStatement((0, hooks_ast_1.buildFindOneCallExpr)(singularName, pkFieldName, 'args')));
455
+ const fImplProps = [
456
+ t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)),
457
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.selectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName)))),
458
+ ];
459
+ statements.push((0, hooks_ast_1.exportAsyncFunction)(fetchFnName, null, [(0, hooks_ast_1.createFunctionParam)('params', t.tsTypeLiteral(fImplProps))], fBody));
460
+ }
461
+ // Prefetch function
462
+ if (reactQueryEnabled) {
463
+ const prefetchFnName = `prefetch${(0, utils_1.ucFirst)(singularName)}Query`;
464
+ // Overload 1: with fields
465
+ const p1Props = [
466
+ t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)),
467
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.withFieldsSelectionType)((0, hooks_ast_1.sRef)(), selectTypeName))),
468
+ ];
469
+ const p1ParamType = hasRelationships && useCentralizedKeys
470
+ ? t.tsIntersectionType([
471
+ t.tsTypeLiteral(p1Props),
472
+ (0, hooks_ast_1.scopeTypeLiteral)(scopeTypeName),
473
+ ])
474
+ : t.tsTypeLiteral(p1Props);
475
+ const p1Decl = (0, hooks_ast_1.exportAsyncDeclareFunction)(prefetchFnName, (0, hooks_ast_1.createSTypeParam)(selectTypeName), [
476
+ (0, hooks_ast_1.createFunctionParam)('queryClient', (0, hooks_ast_1.typeRef)('QueryClient')),
477
+ (0, hooks_ast_1.createFunctionParam)('params', p1ParamType),
478
+ ], (0, hooks_ast_1.typeRef)('Promise', [t.tsVoidKeyword()]));
479
+ (0, hooks_ast_1.addJSDocComment)(p1Decl, [
706
480
  `Prefetch a single ${typeName} for SSR or cache warming`,
707
481
  '',
708
482
  '@example',
709
483
  '```ts',
710
- `await prefetch${(0, utils_1.ucFirst)(singularName)}Query(queryClient, { ${pkName}: 'some-id' });`,
484
+ `await ${prefetchFnName}(queryClient, { ${pkFieldName}: 'some-id', selection: { fields: { id: true } } });`,
711
485
  '```',
712
486
  ]);
713
- statements.push(prefetchExport);
487
+ statements.push(p1Decl);
488
+ // Implementation
489
+ const pImplParamType = hasRelationships && useCentralizedKeys
490
+ ? t.tsIntersectionType([
491
+ t.tsTypeLiteral([
492
+ t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)),
493
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.selectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName)))),
494
+ ]),
495
+ (0, hooks_ast_1.scopeTypeLiteral)(scopeTypeName),
496
+ ])
497
+ : t.tsTypeLiteral([
498
+ t.tsPropertySignature(t.identifier(pkFieldName), t.tsTypeAnnotation(pkTsType)),
499
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.selectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName)))),
500
+ ]);
501
+ const pBody = [];
502
+ pBody.push((0, hooks_ast_1.buildSelectionArgsCall)(selectTypeName));
503
+ const queryKeyExpr = hasRelationships && useCentralizedKeys
504
+ ? buildDetailQueryKey(t.memberExpression(t.identifier('params'), t.identifier(pkFieldName)), t.optionalMemberExpression(t.identifier('params'), t.identifier('scope'), false, true))
505
+ : buildDetailQueryKey(t.memberExpression(t.identifier('params'), t.identifier(pkFieldName)));
506
+ const prefetchCall = (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [
507
+ t.objectExpression([
508
+ (0, hooks_ast_1.objectProp)('queryKey', queryKeyExpr),
509
+ (0, hooks_ast_1.objectProp)('queryFn', buildFindOneFn()),
510
+ ]),
511
+ ]);
512
+ pBody.push(t.expressionStatement(t.awaitExpression(prefetchCall)));
513
+ statements.push((0, hooks_ast_1.exportAsyncFunction)(prefetchFnName, null, [
514
+ (0, hooks_ast_1.createFunctionParam)('queryClient', (0, hooks_ast_1.typeRef)('QueryClient')),
515
+ (0, hooks_ast_1.createFunctionParam)('params', pImplParamType),
516
+ ], pBody, (0, hooks_ast_1.typeRef)('Promise', [t.tsVoidKeyword()])));
714
517
  }
715
- const code = (0, babel_ast_1.generateCode)(statements);
716
518
  const headerText = reactQueryEnabled
717
519
  ? `Single item query hook for ${typeName}`
718
520
  : `Single item query functions for ${typeName}`;
719
- const content = (0, utils_1.getGeneratedFileHeader)(headerText) + '\n\n' + code;
720
521
  return {
721
522
  fileName: (0, utils_1.getSingleQueryFileName)(table),
722
- content,
523
+ content: (0, hooks_ast_1.generateHookFileCode)(headerText, statements),
723
524
  };
724
525
  }
725
526
  function generateAllQueryHooks(tables, options = {}) {