@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,346 @@
1
+ import { createProject, createSourceFile, getFormattedOutput, createFileHeader, createImport, } from '../ts-ast';
2
+ import { ucFirst } from '../utils';
3
+ import { typeRefToTsType, isTypeRequired, getTypeBaseName } from '../type-resolver';
4
+ import { SCALAR_NAMES } from '../scalars';
5
+ /**
6
+ * Collect all input type names used by operations
7
+ */
8
+ function collectInputTypeNamesFromOps(operations) {
9
+ const inputTypes = new Set();
10
+ for (const op of operations) {
11
+ for (const arg of op.args) {
12
+ const baseName = getTypeBaseName(arg.type);
13
+ if (baseName && (baseName.endsWith('Input') || baseName.endsWith('Filter'))) {
14
+ inputTypes.add(baseName);
15
+ }
16
+ }
17
+ }
18
+ return Array.from(inputTypes);
19
+ }
20
+ // Types that don't need Select types
21
+ const NON_SELECT_TYPES = new Set([...SCALAR_NAMES, 'Query', 'Mutation']);
22
+ /**
23
+ * Collect all payload/return type names from operations (for Select types)
24
+ * Filters out scalar types
25
+ */
26
+ function collectPayloadTypeNamesFromOps(operations) {
27
+ const payloadTypes = new Set();
28
+ for (const op of operations) {
29
+ const baseName = getTypeBaseName(op.returnType);
30
+ if (baseName &&
31
+ !baseName.endsWith('Connection') &&
32
+ baseName !== 'Query' &&
33
+ baseName !== 'Mutation' &&
34
+ !NON_SELECT_TYPES.has(baseName)) {
35
+ payloadTypes.add(baseName);
36
+ }
37
+ }
38
+ return Array.from(payloadTypes);
39
+ }
40
+ /**
41
+ * Get the Select type name for a return type
42
+ * Returns null for scalar types, Connection types (no select needed)
43
+ */
44
+ function getSelectTypeName(returnType) {
45
+ const baseName = getTypeBaseName(returnType);
46
+ if (baseName &&
47
+ !NON_SELECT_TYPES.has(baseName) &&
48
+ baseName !== 'Query' &&
49
+ baseName !== 'Mutation' &&
50
+ !baseName.endsWith('Connection')) {
51
+ return `${baseName}Select`;
52
+ }
53
+ return null;
54
+ }
55
+ /**
56
+ * Generate the query/index.ts file for custom query operations
57
+ */
58
+ export function generateCustomQueryOpsFile(operations) {
59
+ const project = createProject();
60
+ const sourceFile = createSourceFile(project, 'index.ts');
61
+ // Collect all input type names and payload type names
62
+ const inputTypeNames = collectInputTypeNamesFromOps(operations);
63
+ const payloadTypeNames = collectPayloadTypeNamesFromOps(operations);
64
+ // Generate Select type names for payloads
65
+ const selectTypeNames = payloadTypeNames.map((p) => `${p}Select`);
66
+ // Combine all type imports
67
+ const allTypeImports = [...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames])];
68
+ // Add file header
69
+ sourceFile.insertText(0, createFileHeader('Custom query operations') + '\n\n');
70
+ // Add imports
71
+ sourceFile.addImportDeclarations([
72
+ createImport({
73
+ moduleSpecifier: '../client',
74
+ namedImports: ['OrmClient'],
75
+ }),
76
+ createImport({
77
+ moduleSpecifier: '../query-builder',
78
+ namedImports: ['QueryBuilder', 'buildCustomDocument'],
79
+ }),
80
+ createImport({
81
+ moduleSpecifier: '../select-types',
82
+ typeOnlyNamedImports: ['InferSelectResult'],
83
+ }),
84
+ ]);
85
+ // Import types from input-types if we have any
86
+ if (allTypeImports.length > 0) {
87
+ sourceFile.addImportDeclarations([
88
+ createImport({
89
+ moduleSpecifier: '../input-types',
90
+ typeOnlyNamedImports: allTypeImports,
91
+ }),
92
+ ]);
93
+ }
94
+ // Generate variable definitions type for each operation
95
+ sourceFile.addStatements('\n// ============================================================================');
96
+ sourceFile.addStatements('// Variable Types');
97
+ sourceFile.addStatements('// ============================================================================\n');
98
+ for (const op of operations) {
99
+ if (op.args.length > 0) {
100
+ const varTypeName = `${ucFirst(op.name)}Variables`;
101
+ const props = op.args.map((arg) => {
102
+ const optional = !isTypeRequired(arg.type);
103
+ return `${arg.name}${optional ? '?' : ''}: ${typeRefToTsType(arg.type)};`;
104
+ });
105
+ sourceFile.addStatements(`export interface ${varTypeName} {\n ${props.join('\n ')}\n}\n`);
106
+ }
107
+ }
108
+ // Generate factory function
109
+ sourceFile.addStatements('\n// ============================================================================');
110
+ sourceFile.addStatements('// Query Operations Factory');
111
+ sourceFile.addStatements('// ============================================================================\n');
112
+ // Build the operations object
113
+ const operationMethods = operations.map((op) => {
114
+ const hasArgs = op.args.length > 0;
115
+ const varTypeName = `${ucFirst(op.name)}Variables`;
116
+ const varDefs = op.args.map((arg) => ({
117
+ name: arg.name,
118
+ type: formatGraphQLType(arg.type),
119
+ }));
120
+ const varDefsJson = JSON.stringify(varDefs);
121
+ // Get Select type for return type
122
+ const selectTypeName = getSelectTypeName(op.returnType);
123
+ const payloadTypeName = getTypeBaseName(op.returnType);
124
+ // Use typed select if available, otherwise fall back to Record<string, unknown>
125
+ const selectType = selectTypeName ?? 'Record<string, unknown>';
126
+ const returnTypePart = selectTypeName && payloadTypeName
127
+ ? `{ ${op.name}: InferSelectResult<${payloadTypeName}, S> }`
128
+ : 'unknown';
129
+ if (hasArgs) {
130
+ if (selectTypeName) {
131
+ return `${op.name}: <const S extends ${selectType}>(args: ${varTypeName}, options?: { select?: S }) =>
132
+ new QueryBuilder<${returnTypePart}>({
133
+ client,
134
+ operation: 'query',
135
+ operationName: '${ucFirst(op.name)}',
136
+ fieldName: '${op.name}',
137
+ ...buildCustomDocument('query', '${ucFirst(op.name)}', '${op.name}', options?.select, args, ${varDefsJson}),
138
+ })`;
139
+ }
140
+ else {
141
+ return `${op.name}: (args: ${varTypeName}, options?: { select?: Record<string, unknown> }) =>
142
+ new QueryBuilder({
143
+ client,
144
+ operation: 'query',
145
+ operationName: '${ucFirst(op.name)}',
146
+ fieldName: '${op.name}',
147
+ ...buildCustomDocument('query', '${ucFirst(op.name)}', '${op.name}', options?.select, args, ${varDefsJson}),
148
+ })`;
149
+ }
150
+ }
151
+ else {
152
+ // No args - still provide typed select
153
+ if (selectTypeName) {
154
+ return `${op.name}: <const S extends ${selectType}>(options?: { select?: S }) =>
155
+ new QueryBuilder<${returnTypePart}>({
156
+ client,
157
+ operation: 'query',
158
+ operationName: '${ucFirst(op.name)}',
159
+ fieldName: '${op.name}',
160
+ ...buildCustomDocument('query', '${ucFirst(op.name)}', '${op.name}', options?.select, undefined, []),
161
+ })`;
162
+ }
163
+ else {
164
+ return `${op.name}: (options?: { select?: Record<string, unknown> }) =>
165
+ new QueryBuilder({
166
+ client,
167
+ operation: 'query',
168
+ operationName: '${ucFirst(op.name)}',
169
+ fieldName: '${op.name}',
170
+ ...buildCustomDocument('query', '${ucFirst(op.name)}', '${op.name}', options?.select, undefined, []),
171
+ })`;
172
+ }
173
+ }
174
+ });
175
+ sourceFile.addFunction({
176
+ name: 'createQueryOperations',
177
+ isExported: true,
178
+ parameters: [{ name: 'client', type: 'OrmClient' }],
179
+ statements: `return {
180
+ ${operationMethods.join(',\n ')},
181
+ };`,
182
+ });
183
+ return {
184
+ fileName: 'query/index.ts',
185
+ content: getFormattedOutput(sourceFile),
186
+ };
187
+ }
188
+ /**
189
+ * Generate the mutation/index.ts file for custom mutation operations
190
+ */
191
+ export function generateCustomMutationOpsFile(operations) {
192
+ const project = createProject();
193
+ const sourceFile = createSourceFile(project, 'index.ts');
194
+ // Collect all input type names and payload type names
195
+ const inputTypeNames = collectInputTypeNamesFromOps(operations);
196
+ const payloadTypeNames = collectPayloadTypeNamesFromOps(operations);
197
+ // Generate Select type names for payloads
198
+ const selectTypeNames = payloadTypeNames.map((p) => `${p}Select`);
199
+ // Combine all type imports
200
+ const allTypeImports = [...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames])];
201
+ // Add file header
202
+ sourceFile.insertText(0, createFileHeader('Custom mutation operations') + '\n\n');
203
+ // Add imports
204
+ sourceFile.addImportDeclarations([
205
+ createImport({
206
+ moduleSpecifier: '../client',
207
+ namedImports: ['OrmClient'],
208
+ }),
209
+ createImport({
210
+ moduleSpecifier: '../query-builder',
211
+ namedImports: ['QueryBuilder', 'buildCustomDocument'],
212
+ }),
213
+ createImport({
214
+ moduleSpecifier: '../select-types',
215
+ typeOnlyNamedImports: ['InferSelectResult'],
216
+ }),
217
+ ]);
218
+ // Import types from input-types if we have any
219
+ if (allTypeImports.length > 0) {
220
+ sourceFile.addImportDeclarations([
221
+ createImport({
222
+ moduleSpecifier: '../input-types',
223
+ typeOnlyNamedImports: allTypeImports,
224
+ }),
225
+ ]);
226
+ }
227
+ // Generate variable definitions type for each operation
228
+ sourceFile.addStatements('\n// ============================================================================');
229
+ sourceFile.addStatements('// Variable Types');
230
+ sourceFile.addStatements('// ============================================================================\n');
231
+ for (const op of operations) {
232
+ if (op.args.length > 0) {
233
+ const varTypeName = `${ucFirst(op.name)}Variables`;
234
+ const props = op.args.map((arg) => {
235
+ const optional = !isTypeRequired(arg.type);
236
+ return `${arg.name}${optional ? '?' : ''}: ${typeRefToTsType(arg.type)};`;
237
+ });
238
+ sourceFile.addStatements(`export interface ${varTypeName} {\n ${props.join('\n ')}\n}\n`);
239
+ }
240
+ }
241
+ // Generate factory function
242
+ sourceFile.addStatements('\n// ============================================================================');
243
+ sourceFile.addStatements('// Mutation Operations Factory');
244
+ sourceFile.addStatements('// ============================================================================\n');
245
+ // Build the operations object
246
+ const operationMethods = operations.map((op) => {
247
+ const hasArgs = op.args.length > 0;
248
+ const varTypeName = `${ucFirst(op.name)}Variables`;
249
+ const varDefs = op.args.map((arg) => ({
250
+ name: arg.name,
251
+ type: formatGraphQLType(arg.type),
252
+ }));
253
+ const varDefsJson = JSON.stringify(varDefs);
254
+ // Get Select type for return type
255
+ const selectTypeName = getSelectTypeName(op.returnType);
256
+ const payloadTypeName = getTypeBaseName(op.returnType);
257
+ // Use typed select if available, otherwise fall back to Record<string, unknown>
258
+ const selectType = selectTypeName ?? 'Record<string, unknown>';
259
+ const returnTypePart = selectTypeName && payloadTypeName
260
+ ? `{ ${op.name}: InferSelectResult<${payloadTypeName}, S> }`
261
+ : 'unknown';
262
+ if (hasArgs) {
263
+ if (selectTypeName) {
264
+ return `${op.name}: <const S extends ${selectType}>(args: ${varTypeName}, options?: { select?: S }) =>
265
+ new QueryBuilder<${returnTypePart}>({
266
+ client,
267
+ operation: 'mutation',
268
+ operationName: '${ucFirst(op.name)}',
269
+ fieldName: '${op.name}',
270
+ ...buildCustomDocument('mutation', '${ucFirst(op.name)}', '${op.name}', options?.select, args, ${varDefsJson}),
271
+ })`;
272
+ }
273
+ else {
274
+ return `${op.name}: (args: ${varTypeName}, options?: { select?: Record<string, unknown> }) =>
275
+ new QueryBuilder({
276
+ client,
277
+ operation: 'mutation',
278
+ operationName: '${ucFirst(op.name)}',
279
+ fieldName: '${op.name}',
280
+ ...buildCustomDocument('mutation', '${ucFirst(op.name)}', '${op.name}', options?.select, args, ${varDefsJson}),
281
+ })`;
282
+ }
283
+ }
284
+ else {
285
+ // No args - still provide typed select
286
+ if (selectTypeName) {
287
+ return `${op.name}: <const S extends ${selectType}>(options?: { select?: S }) =>
288
+ new QueryBuilder<${returnTypePart}>({
289
+ client,
290
+ operation: 'mutation',
291
+ operationName: '${ucFirst(op.name)}',
292
+ fieldName: '${op.name}',
293
+ ...buildCustomDocument('mutation', '${ucFirst(op.name)}', '${op.name}', options?.select, undefined, []),
294
+ })`;
295
+ }
296
+ else {
297
+ return `${op.name}: (options?: { select?: Record<string, unknown> }) =>
298
+ new QueryBuilder({
299
+ client,
300
+ operation: 'mutation',
301
+ operationName: '${ucFirst(op.name)}',
302
+ fieldName: '${op.name}',
303
+ ...buildCustomDocument('mutation', '${ucFirst(op.name)}', '${op.name}', options?.select, undefined, []),
304
+ })`;
305
+ }
306
+ }
307
+ });
308
+ sourceFile.addFunction({
309
+ name: 'createMutationOperations',
310
+ isExported: true,
311
+ parameters: [{ name: 'client', type: 'OrmClient' }],
312
+ statements: `return {
313
+ ${operationMethods.join(',\n ')},
314
+ };`,
315
+ });
316
+ return {
317
+ fileName: 'mutation/index.ts',
318
+ content: getFormattedOutput(sourceFile),
319
+ };
320
+ }
321
+ /**
322
+ * Format a CleanTypeRef to GraphQL type string
323
+ */
324
+ function formatGraphQLType(typeRef) {
325
+ let result = '';
326
+ if (typeRef.kind === 'NON_NULL') {
327
+ if (typeRef.ofType) {
328
+ result = formatGraphQLType(typeRef.ofType) + '!';
329
+ }
330
+ else {
331
+ result = (typeRef.name ?? 'String') + '!';
332
+ }
333
+ }
334
+ else if (typeRef.kind === 'LIST') {
335
+ if (typeRef.ofType) {
336
+ result = `[${formatGraphQLType(typeRef.ofType)}]`;
337
+ }
338
+ else {
339
+ result = '[String]';
340
+ }
341
+ }
342
+ else {
343
+ result = typeRef.name ?? 'String';
344
+ }
345
+ return result;
346
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * ORM Generator Orchestrator
3
+ *
4
+ * Main entry point for ORM code generation. Coordinates all generators
5
+ * and produces the complete ORM client output.
6
+ */
7
+ import type { CleanTable, CleanOperation, TypeRegistry } from '../../../types/schema';
8
+ import type { ResolvedConfig } from '../../../types/config';
9
+ export interface GeneratedFile {
10
+ path: string;
11
+ content: string;
12
+ }
13
+ export interface GenerateOrmOptions {
14
+ tables: CleanTable[];
15
+ customOperations?: {
16
+ queries: CleanOperation[];
17
+ mutations: CleanOperation[];
18
+ typeRegistry?: TypeRegistry;
19
+ };
20
+ config: ResolvedConfig;
21
+ }
22
+ export interface GenerateOrmResult {
23
+ files: GeneratedFile[];
24
+ stats: {
25
+ tables: number;
26
+ customQueries: number;
27
+ customMutations: number;
28
+ totalFiles: number;
29
+ };
30
+ }
31
+ /**
32
+ * Generate all ORM client files
33
+ */
34
+ export declare function generateOrm(options: GenerateOrmOptions): GenerateOrmResult;
35
+ export { generateOrmClientFile, generateQueryBuilderFile, generateSelectTypesFile } from './client-generator';
36
+ export { generateModelFile, generateAllModelFiles } from './model-generator';
37
+ export { generateCustomQueryOpsFile, generateCustomMutationOpsFile } from './custom-ops-generator';
38
+ export { generateModelsBarrel, generateTypesBarrel } from './barrel';
@@ -0,0 +1,75 @@
1
+ import { generateOrmClientFile, generateQueryBuilderFile, generateSelectTypesFile, generateCreateClientFile, } from './client-generator';
2
+ import { generateAllModelFiles } from './model-generator';
3
+ import { generateCustomQueryOpsFile, generateCustomMutationOpsFile, } from './custom-ops-generator';
4
+ import { generateModelsBarrel, generateTypesBarrel } from './barrel';
5
+ import { generateInputTypesFile, collectInputTypeNames, collectPayloadTypeNames } from './input-types-generator';
6
+ /**
7
+ * Generate all ORM client files
8
+ */
9
+ export function generateOrm(options) {
10
+ const { tables, customOperations, config } = options;
11
+ const files = [];
12
+ const useSharedTypes = config.orm?.useSharedTypes ?? true;
13
+ const hasCustomQueries = (customOperations?.queries.length ?? 0) > 0;
14
+ const hasCustomMutations = (customOperations?.mutations.length ?? 0) > 0;
15
+ const typeRegistry = customOperations?.typeRegistry;
16
+ // 1. Generate runtime files (client, query-builder, select-types)
17
+ const clientFile = generateOrmClientFile();
18
+ files.push({ path: clientFile.fileName, content: clientFile.content });
19
+ const queryBuilderFile = generateQueryBuilderFile();
20
+ files.push({ path: queryBuilderFile.fileName, content: queryBuilderFile.content });
21
+ const selectTypesFile = generateSelectTypesFile();
22
+ files.push({ path: selectTypesFile.fileName, content: selectTypesFile.content });
23
+ // 2. Generate model files
24
+ const modelFiles = generateAllModelFiles(tables, useSharedTypes);
25
+ for (const modelFile of modelFiles) {
26
+ files.push({
27
+ path: `models/${modelFile.fileName}`,
28
+ content: modelFile.content,
29
+ });
30
+ }
31
+ // 3. Generate models barrel
32
+ const modelsBarrel = generateModelsBarrel(tables);
33
+ files.push({ path: modelsBarrel.fileName, content: modelsBarrel.content });
34
+ // 4. Generate comprehensive input types (entities, filters, orderBy, CRUD inputs, custom inputs, payload types)
35
+ // Always generate if we have tables or custom operations
36
+ if (tables.length > 0 || (typeRegistry && (hasCustomQueries || hasCustomMutations))) {
37
+ const allOps = [
38
+ ...(customOperations?.queries ?? []),
39
+ ...(customOperations?.mutations ?? []),
40
+ ];
41
+ const usedInputTypes = collectInputTypeNames(allOps);
42
+ const usedPayloadTypes = collectPayloadTypeNames(allOps);
43
+ const inputTypesFile = generateInputTypesFile(typeRegistry ?? new Map(), usedInputTypes, tables, usedPayloadTypes);
44
+ files.push({ path: inputTypesFile.fileName, content: inputTypesFile.content });
45
+ }
46
+ // 5. Generate custom operations (if any)
47
+ if (hasCustomQueries && customOperations?.queries) {
48
+ const queryOpsFile = generateCustomQueryOpsFile(customOperations.queries);
49
+ files.push({ path: queryOpsFile.fileName, content: queryOpsFile.content });
50
+ }
51
+ if (hasCustomMutations && customOperations?.mutations) {
52
+ const mutationOpsFile = generateCustomMutationOpsFile(customOperations.mutations);
53
+ files.push({ path: mutationOpsFile.fileName, content: mutationOpsFile.content });
54
+ }
55
+ // 6. Generate types barrel
56
+ const typesBarrel = generateTypesBarrel(useSharedTypes);
57
+ files.push({ path: typesBarrel.fileName, content: typesBarrel.content });
58
+ // 7. Generate main index.ts with createClient
59
+ const indexFile = generateCreateClientFile(tables, hasCustomQueries, hasCustomMutations);
60
+ files.push({ path: indexFile.fileName, content: indexFile.content });
61
+ return {
62
+ files,
63
+ stats: {
64
+ tables: tables.length,
65
+ customQueries: customOperations?.queries.length ?? 0,
66
+ customMutations: customOperations?.mutations.length ?? 0,
67
+ totalFiles: files.length,
68
+ },
69
+ };
70
+ }
71
+ // Re-export generators for direct use
72
+ export { generateOrmClientFile, generateQueryBuilderFile, generateSelectTypesFile } from './client-generator';
73
+ export { generateModelFile, generateAllModelFiles } from './model-generator';
74
+ export { generateCustomQueryOpsFile, generateCustomMutationOpsFile } from './custom-ops-generator';
75
+ export { generateModelsBarrel, generateTypesBarrel } from './barrel';
@@ -0,0 +1,21 @@
1
+ import type { TypeRegistry, CleanArgument, CleanTable } from '../../../types/schema';
2
+ export interface GeneratedInputTypesFile {
3
+ fileName: string;
4
+ content: string;
5
+ }
6
+ /**
7
+ * Collect all input type names used by operations
8
+ */
9
+ export declare function collectInputTypeNames(operations: Array<{
10
+ args: CleanArgument[];
11
+ }>): Set<string>;
12
+ /**
13
+ * Collect all payload type names from operation return types
14
+ */
15
+ export declare function collectPayloadTypeNames(operations: Array<{
16
+ returnType: CleanArgument['type'];
17
+ }>): Set<string>;
18
+ /**
19
+ * Generate comprehensive input-types.ts file using ts-morph AST
20
+ */
21
+ export declare function generateInputTypesFile(typeRegistry: TypeRegistry, usedInputTypes: Set<string>, tables?: CleanTable[], usedPayloadTypes?: Set<string>): GeneratedInputTypesFile;