@constructive-io/graphql-codegen 2.18.0 → 2.20.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 (301) hide show
  1. package/README.md +1818 -113
  2. package/__tests__/codegen/input-types-generator.test.d.ts +1 -0
  3. package/__tests__/codegen/input-types-generator.test.js +635 -0
  4. package/cli/codegen/barrel.d.ts +27 -0
  5. package/cli/codegen/barrel.js +163 -0
  6. package/cli/codegen/client.d.ts +4 -0
  7. package/cli/codegen/client.js +170 -0
  8. package/cli/codegen/custom-mutations.d.ts +38 -0
  9. package/cli/codegen/custom-mutations.js +149 -0
  10. package/cli/codegen/custom-queries.d.ts +38 -0
  11. package/cli/codegen/custom-queries.js +358 -0
  12. package/cli/codegen/filters.d.ts +27 -0
  13. package/cli/codegen/filters.js +357 -0
  14. package/cli/codegen/gql-ast.d.ts +41 -0
  15. package/cli/codegen/gql-ast.js +329 -0
  16. package/cli/codegen/index.d.ts +71 -0
  17. package/cli/codegen/index.js +147 -0
  18. package/cli/codegen/mutations.d.ts +30 -0
  19. package/cli/codegen/mutations.js +410 -0
  20. package/cli/codegen/orm/barrel.d.ts +18 -0
  21. package/cli/codegen/orm/barrel.js +48 -0
  22. package/cli/codegen/orm/client-generator.d.ts +45 -0
  23. package/cli/codegen/orm/client-generator.js +646 -0
  24. package/cli/codegen/orm/custom-ops-generator.d.ts +30 -0
  25. package/cli/codegen/orm/custom-ops-generator.js +350 -0
  26. package/cli/codegen/orm/index.d.ts +38 -0
  27. package/cli/codegen/orm/index.js +88 -0
  28. package/cli/codegen/orm/input-types-generator.d.ts +21 -0
  29. package/cli/codegen/orm/input-types-generator.js +705 -0
  30. package/cli/codegen/orm/input-types-generator.test.d.ts +1 -0
  31. package/cli/codegen/orm/input-types-generator.test.js +75 -0
  32. package/cli/codegen/orm/model-generator.d.ts +32 -0
  33. package/cli/codegen/orm/model-generator.js +264 -0
  34. package/cli/codegen/orm/query-builder.d.ts +161 -0
  35. package/cli/codegen/orm/query-builder.js +366 -0
  36. package/cli/codegen/orm/select-types.d.ts +169 -0
  37. package/cli/codegen/orm/select-types.js +16 -0
  38. package/cli/codegen/orm/select-types.test.d.ts +11 -0
  39. package/cli/codegen/orm/select-types.test.js +22 -0
  40. package/cli/codegen/queries.d.ts +25 -0
  41. package/cli/codegen/queries.js +438 -0
  42. package/cli/codegen/scalars.d.ts +12 -0
  43. package/cli/codegen/scalars.js +71 -0
  44. package/cli/codegen/schema-gql-ast.d.ts +51 -0
  45. package/cli/codegen/schema-gql-ast.js +385 -0
  46. package/cli/codegen/ts-ast.d.ts +122 -0
  47. package/cli/codegen/ts-ast.js +280 -0
  48. package/cli/codegen/type-resolver.d.ts +96 -0
  49. package/cli/codegen/type-resolver.js +246 -0
  50. package/cli/codegen/types.d.ts +12 -0
  51. package/cli/codegen/types.js +69 -0
  52. package/cli/codegen/utils.d.ts +163 -0
  53. package/cli/codegen/utils.js +326 -0
  54. package/cli/commands/generate-orm.d.ts +37 -0
  55. package/cli/commands/generate-orm.js +195 -0
  56. package/cli/commands/generate.d.ts +39 -0
  57. package/cli/commands/generate.js +299 -0
  58. package/cli/commands/index.d.ts +7 -0
  59. package/cli/commands/index.js +12 -0
  60. package/cli/commands/init.d.ts +35 -0
  61. package/cli/commands/init.js +176 -0
  62. package/cli/index.d.ts +4 -0
  63. package/cli/index.js +291 -0
  64. package/cli/introspect/fetch-meta.d.ts +31 -0
  65. package/cli/introspect/fetch-meta.js +108 -0
  66. package/cli/introspect/fetch-schema.d.ts +21 -0
  67. package/cli/introspect/fetch-schema.js +86 -0
  68. package/cli/introspect/index.d.ts +8 -0
  69. package/cli/introspect/index.js +16 -0
  70. package/cli/introspect/meta-query.d.ts +111 -0
  71. package/cli/introspect/meta-query.js +191 -0
  72. package/cli/introspect/schema-query.d.ts +20 -0
  73. package/cli/introspect/schema-query.js +123 -0
  74. package/cli/introspect/transform-schema.d.ts +74 -0
  75. package/cli/introspect/transform-schema.js +269 -0
  76. package/cli/introspect/transform-schema.test.d.ts +1 -0
  77. package/cli/introspect/transform-schema.test.js +67 -0
  78. package/cli/introspect/transform.d.ts +21 -0
  79. package/cli/introspect/transform.js +216 -0
  80. package/cli/watch/cache.d.ts +45 -0
  81. package/cli/watch/cache.js +111 -0
  82. package/cli/watch/debounce.d.ts +19 -0
  83. package/cli/watch/debounce.js +89 -0
  84. package/cli/watch/hash.d.ts +17 -0
  85. package/cli/watch/hash.js +48 -0
  86. package/cli/watch/index.d.ts +10 -0
  87. package/cli/watch/index.js +22 -0
  88. package/cli/watch/orchestrator.d.ts +63 -0
  89. package/cli/watch/orchestrator.js +228 -0
  90. package/cli/watch/poller.d.ts +65 -0
  91. package/cli/watch/poller.js +203 -0
  92. package/cli/watch/types.d.ts +67 -0
  93. package/cli/watch/types.js +5 -0
  94. package/client/error.d.ts +95 -0
  95. package/client/error.js +255 -0
  96. package/client/execute.d.ts +57 -0
  97. package/client/execute.js +124 -0
  98. package/client/index.d.ts +6 -0
  99. package/client/index.js +18 -0
  100. package/client/typed-document.d.ts +31 -0
  101. package/client/typed-document.js +44 -0
  102. package/core/ast.d.ts +10 -0
  103. package/core/ast.js +593 -0
  104. package/core/custom-ast.d.ts +35 -0
  105. package/core/custom-ast.js +204 -0
  106. package/core/index.d.ts +8 -0
  107. package/core/index.js +33 -0
  108. package/core/meta-object/convert.d.ts +65 -0
  109. package/core/meta-object/convert.js +63 -0
  110. package/core/meta-object/format.json +93 -0
  111. package/core/meta-object/index.d.ts +2 -0
  112. package/core/meta-object/index.js +18 -0
  113. package/core/meta-object/validate.d.ts +9 -0
  114. package/core/meta-object/validate.js +34 -0
  115. package/core/query-builder.d.ts +46 -0
  116. package/core/query-builder.js +412 -0
  117. package/core/types.d.ts +139 -0
  118. package/core/types.js +28 -0
  119. package/esm/__tests__/codegen/input-types-generator.test.d.ts +1 -0
  120. package/esm/__tests__/codegen/input-types-generator.test.js +633 -0
  121. package/esm/cli/codegen/barrel.d.ts +27 -0
  122. package/esm/cli/codegen/barrel.js +156 -0
  123. package/esm/cli/codegen/client.d.ts +4 -0
  124. package/esm/cli/codegen/client.js +167 -0
  125. package/esm/cli/codegen/custom-mutations.d.ts +38 -0
  126. package/esm/cli/codegen/custom-mutations.js +145 -0
  127. package/esm/cli/codegen/custom-queries.d.ts +38 -0
  128. package/esm/cli/codegen/custom-queries.js +354 -0
  129. package/esm/cli/codegen/filters.d.ts +27 -0
  130. package/esm/cli/codegen/filters.js +351 -0
  131. package/esm/cli/codegen/gql-ast.d.ts +41 -0
  132. package/esm/cli/codegen/gql-ast.js +288 -0
  133. package/esm/cli/codegen/index.d.ts +71 -0
  134. package/esm/cli/codegen/index.js +124 -0
  135. package/esm/cli/codegen/mutations.d.ts +30 -0
  136. package/esm/cli/codegen/mutations.js +404 -0
  137. package/esm/cli/codegen/orm/barrel.d.ts +18 -0
  138. package/esm/cli/codegen/orm/barrel.js +44 -0
  139. package/esm/cli/codegen/orm/client-generator.d.ts +45 -0
  140. package/esm/cli/codegen/orm/client-generator.js +640 -0
  141. package/esm/cli/codegen/orm/custom-ops-generator.d.ts +30 -0
  142. package/esm/cli/codegen/orm/custom-ops-generator.js +346 -0
  143. package/esm/cli/codegen/orm/index.d.ts +38 -0
  144. package/esm/cli/codegen/orm/index.js +75 -0
  145. package/esm/cli/codegen/orm/input-types-generator.d.ts +21 -0
  146. package/esm/cli/codegen/orm/input-types-generator.js +700 -0
  147. package/esm/cli/codegen/orm/input-types-generator.test.d.ts +1 -0
  148. package/esm/cli/codegen/orm/input-types-generator.test.js +73 -0
  149. package/esm/cli/codegen/orm/model-generator.d.ts +32 -0
  150. package/esm/cli/codegen/orm/model-generator.js +260 -0
  151. package/esm/cli/codegen/orm/query-builder.d.ts +161 -0
  152. package/esm/cli/codegen/orm/query-builder.js +353 -0
  153. package/esm/cli/codegen/orm/select-types.d.ts +169 -0
  154. package/esm/cli/codegen/orm/select-types.js +15 -0
  155. package/esm/cli/codegen/orm/select-types.test.d.ts +11 -0
  156. package/esm/cli/codegen/orm/select-types.test.js +21 -0
  157. package/esm/cli/codegen/queries.d.ts +25 -0
  158. package/esm/cli/codegen/queries.js +433 -0
  159. package/esm/cli/codegen/scalars.d.ts +12 -0
  160. package/esm/cli/codegen/scalars.js +66 -0
  161. package/esm/cli/codegen/schema-gql-ast.d.ts +51 -0
  162. package/esm/cli/codegen/schema-gql-ast.js +343 -0
  163. package/esm/cli/codegen/ts-ast.d.ts +122 -0
  164. package/esm/cli/codegen/ts-ast.js +260 -0
  165. package/esm/cli/codegen/type-resolver.d.ts +96 -0
  166. package/esm/cli/codegen/type-resolver.js +224 -0
  167. package/esm/cli/codegen/types.d.ts +12 -0
  168. package/esm/cli/codegen/types.js +65 -0
  169. package/esm/cli/codegen/utils.d.ts +163 -0
  170. package/esm/cli/codegen/utils.js +288 -0
  171. package/esm/cli/commands/generate-orm.d.ts +37 -0
  172. package/esm/cli/commands/generate-orm.js +192 -0
  173. package/esm/cli/commands/generate.d.ts +39 -0
  174. package/esm/cli/commands/generate.js +262 -0
  175. package/esm/cli/commands/index.d.ts +7 -0
  176. package/esm/cli/commands/index.js +5 -0
  177. package/esm/cli/commands/init.d.ts +35 -0
  178. package/esm/cli/commands/init.js +138 -0
  179. package/esm/cli/index.d.ts +4 -0
  180. package/esm/cli/index.js +256 -0
  181. package/esm/cli/introspect/fetch-meta.d.ts +31 -0
  182. package/esm/cli/introspect/fetch-meta.js +104 -0
  183. package/esm/cli/introspect/fetch-schema.d.ts +21 -0
  184. package/esm/cli/introspect/fetch-schema.js +83 -0
  185. package/esm/cli/introspect/index.d.ts +8 -0
  186. package/esm/cli/introspect/index.js +6 -0
  187. package/esm/cli/introspect/meta-query.d.ts +111 -0
  188. package/esm/cli/introspect/meta-query.js +188 -0
  189. package/esm/cli/introspect/schema-query.d.ts +20 -0
  190. package/esm/cli/introspect/schema-query.js +120 -0
  191. package/esm/cli/introspect/transform-schema.d.ts +74 -0
  192. package/esm/cli/introspect/transform-schema.js +259 -0
  193. package/esm/cli/introspect/transform-schema.test.d.ts +1 -0
  194. package/esm/cli/introspect/transform-schema.test.js +65 -0
  195. package/esm/cli/introspect/transform.d.ts +21 -0
  196. package/esm/cli/introspect/transform.js +210 -0
  197. package/esm/cli/watch/cache.d.ts +45 -0
  198. package/esm/cli/watch/cache.js +73 -0
  199. package/esm/cli/watch/debounce.d.ts +19 -0
  200. package/esm/cli/watch/debounce.js +85 -0
  201. package/esm/cli/watch/hash.d.ts +17 -0
  202. package/esm/cli/watch/hash.js +43 -0
  203. package/esm/cli/watch/index.d.ts +10 -0
  204. package/esm/cli/watch/index.js +8 -0
  205. package/esm/cli/watch/orchestrator.d.ts +63 -0
  206. package/esm/cli/watch/orchestrator.js +223 -0
  207. package/esm/cli/watch/poller.d.ts +65 -0
  208. package/esm/cli/watch/poller.js +198 -0
  209. package/esm/cli/watch/types.d.ts +67 -0
  210. package/esm/cli/watch/types.js +4 -0
  211. package/esm/client/error.d.ts +95 -0
  212. package/esm/client/error.js +249 -0
  213. package/esm/client/execute.d.ts +57 -0
  214. package/esm/client/execute.js +120 -0
  215. package/esm/client/index.d.ts +6 -0
  216. package/esm/client/index.js +6 -0
  217. package/esm/client/typed-document.d.ts +31 -0
  218. package/esm/client/typed-document.js +40 -0
  219. package/esm/core/ast.d.ts +10 -0
  220. package/esm/core/ast.js +549 -0
  221. package/esm/core/custom-ast.d.ts +35 -0
  222. package/esm/core/custom-ast.js +161 -0
  223. package/esm/core/index.d.ts +8 -0
  224. package/esm/core/index.js +12 -0
  225. package/esm/core/meta-object/convert.d.ts +65 -0
  226. package/esm/core/meta-object/convert.js +60 -0
  227. package/esm/core/meta-object/format.json +93 -0
  228. package/esm/core/meta-object/index.d.ts +2 -0
  229. package/esm/core/meta-object/index.js +2 -0
  230. package/esm/core/meta-object/validate.d.ts +9 -0
  231. package/esm/core/meta-object/validate.js +28 -0
  232. package/esm/core/query-builder.d.ts +46 -0
  233. package/esm/core/query-builder.js +375 -0
  234. package/esm/core/types.d.ts +139 -0
  235. package/esm/core/types.js +24 -0
  236. package/esm/generators/field-selector.d.ts +30 -0
  237. package/esm/generators/field-selector.js +355 -0
  238. package/esm/generators/index.d.ts +6 -0
  239. package/esm/generators/index.js +9 -0
  240. package/esm/generators/mutations.d.ts +31 -0
  241. package/esm/generators/mutations.js +197 -0
  242. package/esm/generators/select.d.ts +50 -0
  243. package/esm/generators/select.js +636 -0
  244. package/esm/index.d.ts +12 -0
  245. package/esm/index.js +17 -3
  246. package/esm/react/index.d.ts +5 -0
  247. package/esm/react/index.js +6 -0
  248. package/esm/types/config.d.ts +199 -0
  249. package/esm/types/config.js +106 -0
  250. package/esm/types/index.d.ts +9 -0
  251. package/esm/types/index.js +4 -0
  252. package/esm/types/introspection.d.ts +121 -0
  253. package/esm/types/introspection.js +54 -0
  254. package/esm/types/mutation.d.ts +45 -0
  255. package/esm/types/mutation.js +4 -0
  256. package/esm/types/query.d.ts +82 -0
  257. package/esm/types/query.js +4 -0
  258. package/esm/types/schema.d.ts +253 -0
  259. package/esm/types/schema.js +5 -0
  260. package/esm/types/selection.d.ts +43 -0
  261. package/esm/types/selection.js +4 -0
  262. package/esm/utils/index.d.ts +4 -0
  263. package/esm/utils/index.js +4 -0
  264. package/generators/field-selector.d.ts +30 -0
  265. package/generators/field-selector.js +361 -0
  266. package/generators/index.d.ts +6 -0
  267. package/generators/index.js +27 -0
  268. package/generators/mutations.d.ts +31 -0
  269. package/generators/mutations.js +235 -0
  270. package/generators/select.d.ts +50 -0
  271. package/generators/select.js +679 -0
  272. package/index.d.ts +12 -3
  273. package/index.js +19 -3
  274. package/package.json +59 -38
  275. package/react/index.d.ts +5 -0
  276. package/react/index.js +9 -0
  277. package/types/config.d.ts +199 -0
  278. package/types/config.js +111 -0
  279. package/types/index.d.ts +9 -0
  280. package/types/index.js +10 -0
  281. package/types/introspection.d.ts +121 -0
  282. package/types/introspection.js +62 -0
  283. package/types/mutation.d.ts +45 -0
  284. package/types/mutation.js +5 -0
  285. package/types/query.d.ts +82 -0
  286. package/types/query.js +5 -0
  287. package/types/schema.d.ts +253 -0
  288. package/types/schema.js +6 -0
  289. package/types/selection.d.ts +43 -0
  290. package/types/selection.js +5 -0
  291. package/utils/index.d.ts +4 -0
  292. package/utils/index.js +7 -0
  293. package/codegen.d.ts +0 -13
  294. package/codegen.js +0 -293
  295. package/esm/codegen.js +0 -253
  296. package/esm/gql.js +0 -939
  297. package/esm/options.js +0 -27
  298. package/gql.d.ts +0 -188
  299. package/gql.js +0 -992
  300. package/options.d.ts +0 -45
  301. package/options.js +0 -31
@@ -0,0 +1,433 @@
1
+ import { createProject, createSourceFile, getFormattedOutput, createFileHeader, createImport, createInterface, createConst, createTypeAlias, createUnionType, createFilterInterface, } from './ts-ast';
2
+ import { buildListQueryAST, buildSingleQueryAST, printGraphQL, } from './gql-ast';
3
+ import { getTableNames, getListQueryHookName, getSingleQueryHookName, getListQueryFileName, getSingleQueryFileName, getAllRowsQueryName, getSingleRowQueryName, getFilterTypeName, getOrderByTypeName, getScalarFields, getScalarFilterType, toScreamingSnake, ucFirst, } from './utils';
4
+ // ============================================================================
5
+ // List query hook generator
6
+ // ============================================================================
7
+ /**
8
+ * Generate list query hook file content using AST
9
+ */
10
+ export function generateListQueryHook(table) {
11
+ const project = createProject();
12
+ const { typeName, pluralName } = getTableNames(table);
13
+ const hookName = getListQueryHookName(table);
14
+ const queryName = getAllRowsQueryName(table);
15
+ const filterTypeName = getFilterTypeName(table);
16
+ const orderByTypeName = getOrderByTypeName(table);
17
+ const scalarFields = getScalarFields(table);
18
+ // Generate GraphQL document via AST
19
+ const queryAST = buildListQueryAST({ table });
20
+ const queryDocument = printGraphQL(queryAST);
21
+ const sourceFile = createSourceFile(project, getListQueryFileName(table));
22
+ // Add file header as leading comment
23
+ sourceFile.insertText(0, createFileHeader(`List query hook for ${typeName}`) + '\n\n');
24
+ // Collect all filter types used by this table's fields
25
+ const filterTypesUsed = new Set();
26
+ for (const field of scalarFields) {
27
+ const filterType = getScalarFilterType(field.type.gqlType);
28
+ if (filterType) {
29
+ filterTypesUsed.add(filterType);
30
+ }
31
+ }
32
+ // Add imports
33
+ sourceFile.addImportDeclarations([
34
+ createImport({
35
+ moduleSpecifier: '@tanstack/react-query',
36
+ namedImports: ['useQuery'],
37
+ typeOnlyNamedImports: ['UseQueryOptions', 'QueryClient'],
38
+ }),
39
+ createImport({
40
+ moduleSpecifier: '../client',
41
+ namedImports: ['execute'],
42
+ typeOnlyNamedImports: ['ExecuteOptions'],
43
+ }),
44
+ createImport({
45
+ moduleSpecifier: '../types',
46
+ typeOnlyNamedImports: [typeName, ...Array.from(filterTypesUsed)],
47
+ }),
48
+ ]);
49
+ // Re-export entity type
50
+ sourceFile.addStatements(`\n// Re-export entity type for convenience\nexport type { ${typeName} };\n`);
51
+ // Add section comment
52
+ sourceFile.addStatements('\n// ============================================================================');
53
+ sourceFile.addStatements('// GraphQL Document');
54
+ sourceFile.addStatements('// ============================================================================\n');
55
+ // Add query document constant
56
+ sourceFile.addVariableStatement(createConst(`${queryName}QueryDocument`, '`\n' + queryDocument + '`'));
57
+ // Add section comment
58
+ sourceFile.addStatements('\n// ============================================================================');
59
+ sourceFile.addStatements('// Types');
60
+ sourceFile.addStatements('// ============================================================================\n');
61
+ // Generate filter interface
62
+ const fieldFilters = scalarFields
63
+ .map((field) => {
64
+ const filterType = getScalarFilterType(field.type.gqlType);
65
+ return filterType ? { fieldName: field.name, filterType } : null;
66
+ })
67
+ .filter((f) => f !== null);
68
+ sourceFile.addInterface(createFilterInterface(filterTypeName, fieldFilters));
69
+ // Generate OrderBy type
70
+ const orderByValues = [
71
+ ...scalarFields.flatMap((f) => [
72
+ `${toScreamingSnake(f.name)}_ASC`,
73
+ `${toScreamingSnake(f.name)}_DESC`,
74
+ ]),
75
+ 'NATURAL',
76
+ 'PRIMARY_KEY_ASC',
77
+ 'PRIMARY_KEY_DESC',
78
+ ];
79
+ sourceFile.addTypeAlias(createTypeAlias(orderByTypeName, createUnionType(orderByValues)));
80
+ // Variables interface
81
+ const variablesProps = [
82
+ { name: 'first', type: 'number', optional: true },
83
+ { name: 'offset', type: 'number', optional: true },
84
+ { name: 'filter', type: filterTypeName, optional: true },
85
+ { name: 'orderBy', type: `${orderByTypeName}[]`, optional: true },
86
+ ];
87
+ sourceFile.addInterface(createInterface(`${ucFirst(pluralName)}QueryVariables`, variablesProps));
88
+ // Result interface
89
+ const resultProps = [
90
+ {
91
+ name: queryName,
92
+ type: `{
93
+ totalCount: number;
94
+ nodes: ${typeName}[];
95
+ pageInfo: {
96
+ hasNextPage: boolean;
97
+ hasPreviousPage: boolean;
98
+ startCursor: string | null;
99
+ endCursor: string | null;
100
+ };
101
+ }`,
102
+ },
103
+ ];
104
+ sourceFile.addInterface(createInterface(`${ucFirst(pluralName)}QueryResult`, resultProps));
105
+ // Add section comment
106
+ sourceFile.addStatements('\n// ============================================================================');
107
+ sourceFile.addStatements('// Query Key');
108
+ sourceFile.addStatements('// ============================================================================\n');
109
+ // Query key factory
110
+ sourceFile.addVariableStatement(createConst(`${queryName}QueryKey`, `(variables?: ${ucFirst(pluralName)}QueryVariables) =>
111
+ ['${typeName.toLowerCase()}', 'list', variables] as const`));
112
+ // Add section comment
113
+ sourceFile.addStatements('\n// ============================================================================');
114
+ sourceFile.addStatements('// Hook');
115
+ sourceFile.addStatements('// ============================================================================\n');
116
+ // Hook function
117
+ sourceFile.addFunction({
118
+ name: hookName,
119
+ isExported: true,
120
+ parameters: [
121
+ {
122
+ name: 'variables',
123
+ type: `${ucFirst(pluralName)}QueryVariables`,
124
+ hasQuestionToken: true,
125
+ },
126
+ {
127
+ name: 'options',
128
+ type: `Omit<UseQueryOptions<${ucFirst(pluralName)}QueryResult, Error>, 'queryKey' | 'queryFn'>`,
129
+ hasQuestionToken: true,
130
+ },
131
+ ],
132
+ statements: `return useQuery({
133
+ queryKey: ${queryName}QueryKey(variables),
134
+ queryFn: () => execute<${ucFirst(pluralName)}QueryResult, ${ucFirst(pluralName)}QueryVariables>(
135
+ ${queryName}QueryDocument,
136
+ variables
137
+ ),
138
+ ...options,
139
+ });`,
140
+ docs: [
141
+ {
142
+ description: `Query hook for fetching ${typeName} list
143
+
144
+ @example
145
+ \`\`\`tsx
146
+ const { data, isLoading } = ${hookName}({
147
+ first: 10,
148
+ filter: { name: { equalTo: "example" } },
149
+ orderBy: ['CREATED_AT_DESC'],
150
+ });
151
+ \`\`\``,
152
+ },
153
+ ],
154
+ });
155
+ // Add section comment for standalone functions
156
+ sourceFile.addStatements('\n// ============================================================================');
157
+ sourceFile.addStatements('// Standalone Functions (non-React)');
158
+ sourceFile.addStatements('// ============================================================================\n');
159
+ // Fetch function (standalone, no React)
160
+ sourceFile.addFunction({
161
+ name: `fetch${ucFirst(pluralName)}Query`,
162
+ isExported: true,
163
+ isAsync: true,
164
+ parameters: [
165
+ {
166
+ name: 'variables',
167
+ type: `${ucFirst(pluralName)}QueryVariables`,
168
+ hasQuestionToken: true,
169
+ },
170
+ {
171
+ name: 'options',
172
+ type: 'ExecuteOptions',
173
+ hasQuestionToken: true,
174
+ },
175
+ ],
176
+ returnType: `Promise<${ucFirst(pluralName)}QueryResult>`,
177
+ statements: `return execute<${ucFirst(pluralName)}QueryResult, ${ucFirst(pluralName)}QueryVariables>(
178
+ ${queryName}QueryDocument,
179
+ variables,
180
+ options
181
+ );`,
182
+ docs: [
183
+ {
184
+ description: `Fetch ${typeName} list without React hooks
185
+
186
+ @example
187
+ \`\`\`ts
188
+ // Direct fetch
189
+ const data = await fetch${ucFirst(pluralName)}Query({ first: 10 });
190
+
191
+ // With QueryClient
192
+ const data = await queryClient.fetchQuery({
193
+ queryKey: ${queryName}QueryKey(variables),
194
+ queryFn: () => fetch${ucFirst(pluralName)}Query(variables),
195
+ });
196
+ \`\`\``,
197
+ },
198
+ ],
199
+ });
200
+ // Prefetch function (for SSR/QueryClient)
201
+ sourceFile.addFunction({
202
+ name: `prefetch${ucFirst(pluralName)}Query`,
203
+ isExported: true,
204
+ isAsync: true,
205
+ parameters: [
206
+ {
207
+ name: 'queryClient',
208
+ type: 'QueryClient',
209
+ },
210
+ {
211
+ name: 'variables',
212
+ type: `${ucFirst(pluralName)}QueryVariables`,
213
+ hasQuestionToken: true,
214
+ },
215
+ {
216
+ name: 'options',
217
+ type: 'ExecuteOptions',
218
+ hasQuestionToken: true,
219
+ },
220
+ ],
221
+ returnType: 'Promise<void>',
222
+ statements: `await queryClient.prefetchQuery({
223
+ queryKey: ${queryName}QueryKey(variables),
224
+ queryFn: () => execute<${ucFirst(pluralName)}QueryResult, ${ucFirst(pluralName)}QueryVariables>(
225
+ ${queryName}QueryDocument,
226
+ variables,
227
+ options
228
+ ),
229
+ });`,
230
+ docs: [
231
+ {
232
+ description: `Prefetch ${typeName} list for SSR or cache warming
233
+
234
+ @example
235
+ \`\`\`ts
236
+ await prefetch${ucFirst(pluralName)}Query(queryClient, { first: 10 });
237
+ \`\`\``,
238
+ },
239
+ ],
240
+ });
241
+ return {
242
+ fileName: getListQueryFileName(table),
243
+ content: getFormattedOutput(sourceFile),
244
+ };
245
+ }
246
+ // ============================================================================
247
+ // Single item query hook generator
248
+ // ============================================================================
249
+ /**
250
+ * Generate single item query hook file content using AST
251
+ */
252
+ export function generateSingleQueryHook(table) {
253
+ const project = createProject();
254
+ const { typeName, singularName } = getTableNames(table);
255
+ const hookName = getSingleQueryHookName(table);
256
+ const queryName = getSingleRowQueryName(table);
257
+ // Generate GraphQL document via AST
258
+ const queryAST = buildSingleQueryAST({ table });
259
+ const queryDocument = printGraphQL(queryAST);
260
+ const sourceFile = createSourceFile(project, getSingleQueryFileName(table));
261
+ // Add file header
262
+ sourceFile.insertText(0, createFileHeader(`Single item query hook for ${typeName}`) + '\n\n');
263
+ // Add imports
264
+ sourceFile.addImportDeclarations([
265
+ createImport({
266
+ moduleSpecifier: '@tanstack/react-query',
267
+ namedImports: ['useQuery'],
268
+ typeOnlyNamedImports: ['UseQueryOptions', 'QueryClient'],
269
+ }),
270
+ createImport({
271
+ moduleSpecifier: '../client',
272
+ namedImports: ['execute'],
273
+ typeOnlyNamedImports: ['ExecuteOptions'],
274
+ }),
275
+ createImport({
276
+ moduleSpecifier: '../types',
277
+ typeOnlyNamedImports: [typeName],
278
+ }),
279
+ ]);
280
+ // Re-export entity type
281
+ sourceFile.addStatements(`\n// Re-export entity type for convenience\nexport type { ${typeName} };\n`);
282
+ // Add section comment
283
+ sourceFile.addStatements('\n// ============================================================================');
284
+ sourceFile.addStatements('// GraphQL Document');
285
+ sourceFile.addStatements('// ============================================================================\n');
286
+ // Add query document constant
287
+ sourceFile.addVariableStatement(createConst(`${queryName}QueryDocument`, '`\n' + queryDocument + '`'));
288
+ // Add section comment
289
+ sourceFile.addStatements('\n// ============================================================================');
290
+ sourceFile.addStatements('// Types');
291
+ sourceFile.addStatements('// ============================================================================\n');
292
+ // Variables interface
293
+ sourceFile.addInterface(createInterface(`${ucFirst(singularName)}QueryVariables`, [
294
+ { name: 'id', type: 'string' },
295
+ ]));
296
+ // Result interface
297
+ sourceFile.addInterface(createInterface(`${ucFirst(singularName)}QueryResult`, [
298
+ { name: queryName, type: `${typeName} | null` },
299
+ ]));
300
+ // Add section comment
301
+ sourceFile.addStatements('\n// ============================================================================');
302
+ sourceFile.addStatements('// Query Key');
303
+ sourceFile.addStatements('// ============================================================================\n');
304
+ // Query key factory
305
+ sourceFile.addVariableStatement(createConst(`${queryName}QueryKey`, `(id: string) =>
306
+ ['${typeName.toLowerCase()}', 'detail', id] as const`));
307
+ // Add section comment
308
+ sourceFile.addStatements('\n// ============================================================================');
309
+ sourceFile.addStatements('// Hook');
310
+ sourceFile.addStatements('// ============================================================================\n');
311
+ // Hook function
312
+ sourceFile.addFunction({
313
+ name: hookName,
314
+ isExported: true,
315
+ parameters: [
316
+ { name: 'id', type: 'string' },
317
+ {
318
+ name: 'options',
319
+ type: `Omit<UseQueryOptions<${ucFirst(singularName)}QueryResult, Error>, 'queryKey' | 'queryFn'>`,
320
+ hasQuestionToken: true,
321
+ },
322
+ ],
323
+ statements: `return useQuery({
324
+ queryKey: ${queryName}QueryKey(id),
325
+ queryFn: () => execute<${ucFirst(singularName)}QueryResult, ${ucFirst(singularName)}QueryVariables>(
326
+ ${queryName}QueryDocument,
327
+ { id }
328
+ ),
329
+ enabled: !!id && (options?.enabled !== false),
330
+ ...options,
331
+ });`,
332
+ docs: [
333
+ {
334
+ description: `Query hook for fetching a single ${typeName} by ID
335
+
336
+ @example
337
+ \`\`\`tsx
338
+ const { data, isLoading } = ${hookName}('uuid-here');
339
+
340
+ if (data?.${queryName}) {
341
+ console.log(data.${queryName}.id);
342
+ }
343
+ \`\`\``,
344
+ },
345
+ ],
346
+ });
347
+ // Add section comment for standalone functions
348
+ sourceFile.addStatements('\n// ============================================================================');
349
+ sourceFile.addStatements('// Standalone Functions (non-React)');
350
+ sourceFile.addStatements('// ============================================================================\n');
351
+ // Fetch function (standalone, no React)
352
+ sourceFile.addFunction({
353
+ name: `fetch${ucFirst(singularName)}Query`,
354
+ isExported: true,
355
+ isAsync: true,
356
+ parameters: [
357
+ { name: 'id', type: 'string' },
358
+ {
359
+ name: 'options',
360
+ type: 'ExecuteOptions',
361
+ hasQuestionToken: true,
362
+ },
363
+ ],
364
+ returnType: `Promise<${ucFirst(singularName)}QueryResult>`,
365
+ statements: `return execute<${ucFirst(singularName)}QueryResult, ${ucFirst(singularName)}QueryVariables>(
366
+ ${queryName}QueryDocument,
367
+ { id },
368
+ options
369
+ );`,
370
+ docs: [
371
+ {
372
+ description: `Fetch a single ${typeName} by ID without React hooks
373
+
374
+ @example
375
+ \`\`\`ts
376
+ const data = await fetch${ucFirst(singularName)}Query('uuid-here');
377
+ \`\`\``,
378
+ },
379
+ ],
380
+ });
381
+ // Prefetch function (for SSR/QueryClient)
382
+ sourceFile.addFunction({
383
+ name: `prefetch${ucFirst(singularName)}Query`,
384
+ isExported: true,
385
+ isAsync: true,
386
+ parameters: [
387
+ { name: 'queryClient', type: 'QueryClient' },
388
+ { name: 'id', type: 'string' },
389
+ {
390
+ name: 'options',
391
+ type: 'ExecuteOptions',
392
+ hasQuestionToken: true,
393
+ },
394
+ ],
395
+ returnType: 'Promise<void>',
396
+ statements: `await queryClient.prefetchQuery({
397
+ queryKey: ${queryName}QueryKey(id),
398
+ queryFn: () => execute<${ucFirst(singularName)}QueryResult, ${ucFirst(singularName)}QueryVariables>(
399
+ ${queryName}QueryDocument,
400
+ { id },
401
+ options
402
+ ),
403
+ });`,
404
+ docs: [
405
+ {
406
+ description: `Prefetch a single ${typeName} for SSR or cache warming
407
+
408
+ @example
409
+ \`\`\`ts
410
+ await prefetch${ucFirst(singularName)}Query(queryClient, 'uuid-here');
411
+ \`\`\``,
412
+ },
413
+ ],
414
+ });
415
+ return {
416
+ fileName: getSingleQueryFileName(table),
417
+ content: getFormattedOutput(sourceFile),
418
+ };
419
+ }
420
+ // ============================================================================
421
+ // Batch generator
422
+ // ============================================================================
423
+ /**
424
+ * Generate all query hook files for all tables
425
+ */
426
+ export function generateAllQueryHooks(tables) {
427
+ const files = [];
428
+ for (const table of tables) {
429
+ files.push(generateListQueryHook(table));
430
+ files.push(generateSingleQueryHook(table));
431
+ }
432
+ return files;
433
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Shared scalar mappings for code generation
3
+ */
4
+ export declare const SCALAR_TS_MAP: Record<string, string>;
5
+ export declare const SCALAR_FILTER_MAP: Record<string, string>;
6
+ export declare const SCALAR_NAMES: Set<string>;
7
+ export interface ScalarToTsOptions {
8
+ unknownScalar?: 'unknown' | 'name';
9
+ overrides?: Record<string, string>;
10
+ }
11
+ export declare function scalarToTsType(scalarName: string, options?: ScalarToTsOptions): string;
12
+ export declare function scalarToFilterType(scalarName: string): string | null;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Shared scalar mappings for code generation
3
+ */
4
+ export const SCALAR_TS_MAP = {
5
+ // Standard GraphQL scalars
6
+ String: 'string',
7
+ Int: 'number',
8
+ Float: 'number',
9
+ Boolean: 'boolean',
10
+ ID: 'string',
11
+ // PostGraphile scalars
12
+ UUID: 'string',
13
+ Cursor: 'string',
14
+ Datetime: 'string',
15
+ Date: 'string',
16
+ Time: 'string',
17
+ JSON: 'unknown',
18
+ BigInt: 'string',
19
+ BigFloat: 'string',
20
+ // Geometry types
21
+ GeoJSON: 'unknown',
22
+ Geometry: 'unknown',
23
+ Point: 'unknown',
24
+ // Interval
25
+ Interval: 'string',
26
+ // PostgreSQL-specific types
27
+ BitString: 'string',
28
+ FullText: 'string',
29
+ InternetAddress: 'string',
30
+ Inet: 'string',
31
+ Cidr: 'string',
32
+ MacAddr: 'string',
33
+ TsVector: 'string',
34
+ TsQuery: 'string',
35
+ };
36
+ export const SCALAR_FILTER_MAP = {
37
+ String: 'StringFilter',
38
+ Int: 'IntFilter',
39
+ Float: 'FloatFilter',
40
+ Boolean: 'BooleanFilter',
41
+ UUID: 'UUIDFilter',
42
+ ID: 'UUIDFilter',
43
+ Datetime: 'DatetimeFilter',
44
+ Date: 'DateFilter',
45
+ Time: 'StringFilter',
46
+ JSON: 'JSONFilter',
47
+ BigInt: 'BigIntFilter',
48
+ BigFloat: 'BigFloatFilter',
49
+ BitString: 'BitStringFilter',
50
+ InternetAddress: 'InternetAddressFilter',
51
+ FullText: 'FullTextFilter',
52
+ Interval: 'StringFilter',
53
+ };
54
+ export const SCALAR_NAMES = new Set(Object.keys(SCALAR_TS_MAP));
55
+ export function scalarToTsType(scalarName, options = {}) {
56
+ const override = options.overrides?.[scalarName];
57
+ if (override)
58
+ return override;
59
+ const mapped = SCALAR_TS_MAP[scalarName];
60
+ if (mapped)
61
+ return mapped;
62
+ return options.unknownScalar === 'unknown' ? 'unknown' : scalarName;
63
+ }
64
+ export function scalarToFilterType(scalarName) {
65
+ return SCALAR_FILTER_MAP[scalarName] ?? null;
66
+ }
@@ -0,0 +1,51 @@
1
+ import type { DocumentNode, FieldNode, VariableDefinitionNode } from 'graphql';
2
+ import type { CleanOperation, CleanArgument, CleanTypeRef, TypeRegistry } from '../../types/schema';
3
+ export interface FieldSelectionConfig {
4
+ /** Max depth for nested object selections */
5
+ maxDepth: number;
6
+ /** Skip the 'query' field in payloads */
7
+ skipQueryField: boolean;
8
+ /** Type registry for resolving nested types */
9
+ typeRegistry?: TypeRegistry;
10
+ }
11
+ /**
12
+ * Build variable definitions from operation arguments
13
+ */
14
+ export declare function buildVariableDefinitions(args: CleanArgument[]): VariableDefinitionNode[];
15
+ /**
16
+ * Build field selections for an object type
17
+ * Recursively handles nested objects up to maxDepth
18
+ */
19
+ export declare function buildFieldSelections(typeRef: CleanTypeRef, config: FieldSelectionConfig, currentDepth?: number): FieldNode[];
20
+ export interface CustomQueryConfig {
21
+ operation: CleanOperation;
22
+ typeRegistry?: TypeRegistry;
23
+ maxDepth?: number;
24
+ skipQueryField?: boolean;
25
+ }
26
+ /**
27
+ * Build a custom query AST from a CleanOperation
28
+ */
29
+ export declare function buildCustomQueryAST(config: CustomQueryConfig): DocumentNode;
30
+ export interface CustomMutationConfig {
31
+ operation: CleanOperation;
32
+ typeRegistry?: TypeRegistry;
33
+ maxDepth?: number;
34
+ skipQueryField?: boolean;
35
+ }
36
+ /**
37
+ * Build a custom mutation AST from a CleanOperation
38
+ */
39
+ export declare function buildCustomMutationAST(config: CustomMutationConfig): DocumentNode;
40
+ /**
41
+ * Print a document AST to GraphQL string
42
+ */
43
+ export declare function printGraphQL(ast: DocumentNode): string;
44
+ /**
45
+ * Build and print a custom query in one call
46
+ */
47
+ export declare function buildCustomQueryString(config: CustomQueryConfig): string;
48
+ /**
49
+ * Build and print a custom mutation in one call
50
+ */
51
+ export declare function buildCustomMutationString(config: CustomMutationConfig): string;