@constructive-io/graphql-codegen 2.19.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,700 @@
1
+ import { createProject, createSourceFile, getMinimalFormattedOutput, createFileHeader, createInterface, createTypeAlias, addSectionComment, } from '../ts-ast';
2
+ import { getTableNames, getFilterTypeName, getOrderByTypeName, isRelationField, } from '../utils';
3
+ import { getTypeBaseName } from '../type-resolver';
4
+ import { scalarToTsType, scalarToFilterType } from '../scalars';
5
+ // ============================================================================
6
+ // Constants
7
+ // ============================================================================
8
+ /** Fields excluded from Create/Update inputs (auto-generated or system fields) */
9
+ const EXCLUDED_MUTATION_FIELDS = ['id', 'createdAt', 'updatedAt', 'nodeId'];
10
+ // ============================================================================
11
+ // Type Conversion Utilities
12
+ // ============================================================================
13
+ /**
14
+ * Overrides for input-type generation
15
+ */
16
+ const INPUT_SCALAR_OVERRIDES = {
17
+ JSON: 'Record<string, unknown>',
18
+ };
19
+ /**
20
+ * Convert GraphQL scalar to TypeScript type
21
+ */
22
+ function scalarToInputTs(scalar) {
23
+ return scalarToTsType(scalar, {
24
+ unknownScalar: 'name',
25
+ overrides: INPUT_SCALAR_OVERRIDES,
26
+ });
27
+ }
28
+ /**
29
+ * Convert a CleanTypeRef to TypeScript type string
30
+ */
31
+ function typeRefToTs(typeRef) {
32
+ if (typeRef.kind === 'NON_NULL') {
33
+ if (typeRef.ofType) {
34
+ return typeRefToTs(typeRef.ofType);
35
+ }
36
+ return typeRef.name ?? 'unknown';
37
+ }
38
+ if (typeRef.kind === 'LIST') {
39
+ if (typeRef.ofType) {
40
+ return `${typeRefToTs(typeRef.ofType)}[]`;
41
+ }
42
+ return 'unknown[]';
43
+ }
44
+ // Scalar or named type
45
+ const name = typeRef.name ?? 'unknown';
46
+ return scalarToInputTs(name);
47
+ }
48
+ /**
49
+ * Check if a type is required (NON_NULL)
50
+ */
51
+ function isRequired(typeRef) {
52
+ return typeRef.kind === 'NON_NULL';
53
+ }
54
+ /** Configuration for all scalar filter types - matches PostGraphile's generated filters */
55
+ const SCALAR_FILTER_CONFIGS = [
56
+ { name: 'StringFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison', 'string'] },
57
+ { name: 'IntFilter', tsType: 'number', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
58
+ { name: 'FloatFilter', tsType: 'number', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
59
+ { name: 'BooleanFilter', tsType: 'boolean', operators: ['equality'] },
60
+ { name: 'UUIDFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray'] },
61
+ { name: 'DatetimeFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
62
+ { name: 'DateFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
63
+ { name: 'JSONFilter', tsType: 'Record<string, unknown>', operators: ['equality', 'distinct', 'json'] },
64
+ { name: 'BigIntFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
65
+ { name: 'BigFloatFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison'] },
66
+ { name: 'BitStringFilter', tsType: 'string', operators: ['equality'] },
67
+ { name: 'InternetAddressFilter', tsType: 'string', operators: ['equality', 'distinct', 'inArray', 'comparison', 'inet'] },
68
+ { name: 'FullTextFilter', tsType: 'string', operators: ['fulltext'] },
69
+ ];
70
+ /**
71
+ * Build filter properties based on operator sets
72
+ */
73
+ function buildScalarFilterProperties(config) {
74
+ const { tsType, operators } = config;
75
+ const props = [];
76
+ // Equality operators (isNull, equalTo, notEqualTo)
77
+ if (operators.includes('equality')) {
78
+ props.push({ name: 'isNull', type: 'boolean', optional: true }, { name: 'equalTo', type: tsType, optional: true }, { name: 'notEqualTo', type: tsType, optional: true });
79
+ }
80
+ // Distinct operators
81
+ if (operators.includes('distinct')) {
82
+ props.push({ name: 'distinctFrom', type: tsType, optional: true }, { name: 'notDistinctFrom', type: tsType, optional: true });
83
+ }
84
+ // In/notIn operators
85
+ if (operators.includes('inArray')) {
86
+ props.push({ name: 'in', type: `${tsType}[]`, optional: true }, { name: 'notIn', type: `${tsType}[]`, optional: true });
87
+ }
88
+ // Comparison operators (less than, greater than)
89
+ if (operators.includes('comparison')) {
90
+ props.push({ name: 'lessThan', type: tsType, optional: true }, { name: 'lessThanOrEqualTo', type: tsType, optional: true }, { name: 'greaterThan', type: tsType, optional: true }, { name: 'greaterThanOrEqualTo', type: tsType, optional: true });
91
+ }
92
+ // String operators (includes, startsWith, like, etc.)
93
+ if (operators.includes('string')) {
94
+ props.push({ name: 'includes', type: 'string', optional: true }, { name: 'notIncludes', type: 'string', optional: true }, { name: 'includesInsensitive', type: 'string', optional: true }, { name: 'notIncludesInsensitive', type: 'string', optional: true }, { name: 'startsWith', type: 'string', optional: true }, { name: 'notStartsWith', type: 'string', optional: true }, { name: 'startsWithInsensitive', type: 'string', optional: true }, { name: 'notStartsWithInsensitive', type: 'string', optional: true }, { name: 'endsWith', type: 'string', optional: true }, { name: 'notEndsWith', type: 'string', optional: true }, { name: 'endsWithInsensitive', type: 'string', optional: true }, { name: 'notEndsWithInsensitive', type: 'string', optional: true }, { name: 'like', type: 'string', optional: true }, { name: 'notLike', type: 'string', optional: true }, { name: 'likeInsensitive', type: 'string', optional: true }, { name: 'notLikeInsensitive', type: 'string', optional: true });
95
+ }
96
+ // JSON operators (contains, containsKey, etc.)
97
+ if (operators.includes('json')) {
98
+ props.push({ name: 'contains', type: 'Record<string, unknown>', optional: true }, { name: 'containedBy', type: 'Record<string, unknown>', optional: true }, { name: 'containsKey', type: 'string', optional: true }, { name: 'containsAllKeys', type: 'string[]', optional: true }, { name: 'containsAnyKeys', type: 'string[]', optional: true });
99
+ }
100
+ // Internet address operators
101
+ if (operators.includes('inet')) {
102
+ props.push({ name: 'contains', type: 'string', optional: true }, { name: 'containsOrEqualTo', type: 'string', optional: true }, { name: 'containedBy', type: 'string', optional: true }, { name: 'containedByOrEqualTo', type: 'string', optional: true }, { name: 'containsOrContainedBy', type: 'string', optional: true });
103
+ }
104
+ // Full-text search operators
105
+ if (operators.includes('fulltext')) {
106
+ props.push({ name: 'matches', type: 'string', optional: true });
107
+ }
108
+ return props;
109
+ }
110
+ /**
111
+ * Add scalar filter types to source file using ts-morph
112
+ */
113
+ function addScalarFilterTypes(sourceFile) {
114
+ addSectionComment(sourceFile, 'Scalar Filter Types');
115
+ for (const config of SCALAR_FILTER_CONFIGS) {
116
+ sourceFile.addInterface(createInterface(config.name, buildScalarFilterProperties(config)));
117
+ }
118
+ }
119
+ // ============================================================================
120
+ // Entity Types Generator (AST-based)
121
+ // ============================================================================
122
+ /**
123
+ * Build properties for an entity interface
124
+ */
125
+ function buildEntityProperties(table) {
126
+ const properties = [];
127
+ for (const field of table.fields) {
128
+ if (isRelationField(field.name, table))
129
+ continue;
130
+ const fieldType = typeof field.type === 'string' ? field.type : field.type.gqlType;
131
+ const tsType = scalarToInputTs(fieldType);
132
+ const isNullable = field.name !== 'id' && field.name !== 'nodeId';
133
+ properties.push({
134
+ name: field.name,
135
+ type: isNullable ? `${tsType} | null` : tsType,
136
+ optional: isNullable,
137
+ });
138
+ }
139
+ return properties;
140
+ }
141
+ /**
142
+ * Add entity type interface for a table
143
+ */
144
+ function addEntityType(sourceFile, table) {
145
+ const { typeName } = getTableNames(table);
146
+ sourceFile.addInterface(createInterface(typeName, buildEntityProperties(table)));
147
+ }
148
+ /**
149
+ * Add all entity types
150
+ */
151
+ function addEntityTypes(sourceFile, tables) {
152
+ addSectionComment(sourceFile, 'Entity Types');
153
+ for (const table of tables) {
154
+ addEntityType(sourceFile, table);
155
+ }
156
+ }
157
+ // ============================================================================
158
+ // Relation Helper Types Generator (AST-based)
159
+ // ============================================================================
160
+ /**
161
+ * Add relation helper types (ConnectionResult, PageInfo)
162
+ */
163
+ function addRelationHelperTypes(sourceFile) {
164
+ addSectionComment(sourceFile, 'Relation Helper Types');
165
+ sourceFile.addInterface(createInterface('ConnectionResult<T>', [
166
+ { name: 'nodes', type: 'T[]', optional: false },
167
+ { name: 'totalCount', type: 'number', optional: false },
168
+ { name: 'pageInfo', type: 'PageInfo', optional: false },
169
+ ]));
170
+ sourceFile.addInterface(createInterface('PageInfo', [
171
+ { name: 'hasNextPage', type: 'boolean', optional: false },
172
+ { name: 'hasPreviousPage', type: 'boolean', optional: false },
173
+ { name: 'startCursor', type: 'string | null', optional: true },
174
+ { name: 'endCursor', type: 'string | null', optional: true },
175
+ ]));
176
+ }
177
+ // ============================================================================
178
+ // Entity Relation Types Generator (AST-based)
179
+ // ============================================================================
180
+ function getRelatedTypeName(tableName, tableByName) {
181
+ const relatedTable = tableByName.get(tableName);
182
+ return relatedTable ? getTableNames(relatedTable).typeName : tableName;
183
+ }
184
+ function getRelatedOrderByName(tableName, tableByName) {
185
+ const relatedTable = tableByName.get(tableName);
186
+ return relatedTable ? getOrderByTypeName(relatedTable) : `${tableName}sOrderBy`;
187
+ }
188
+ function getRelatedFilterName(tableName, tableByName) {
189
+ const relatedTable = tableByName.get(tableName);
190
+ return relatedTable ? getFilterTypeName(relatedTable) : `${tableName}Filter`;
191
+ }
192
+ /**
193
+ * Build properties for entity relations interface
194
+ */
195
+ function buildEntityRelationProperties(table, tableByName) {
196
+ const properties = [];
197
+ for (const relation of table.relations.belongsTo) {
198
+ if (!relation.fieldName)
199
+ continue;
200
+ const relatedTypeName = getRelatedTypeName(relation.referencesTable, tableByName);
201
+ properties.push({
202
+ name: relation.fieldName,
203
+ type: `${relatedTypeName} | null`,
204
+ optional: true,
205
+ });
206
+ }
207
+ for (const relation of table.relations.hasOne) {
208
+ if (!relation.fieldName)
209
+ continue;
210
+ const relatedTypeName = getRelatedTypeName(relation.referencedByTable, tableByName);
211
+ properties.push({
212
+ name: relation.fieldName,
213
+ type: `${relatedTypeName} | null`,
214
+ optional: true,
215
+ });
216
+ }
217
+ for (const relation of table.relations.hasMany) {
218
+ if (!relation.fieldName)
219
+ continue;
220
+ const relatedTypeName = getRelatedTypeName(relation.referencedByTable, tableByName);
221
+ properties.push({
222
+ name: relation.fieldName,
223
+ type: `ConnectionResult<${relatedTypeName}>`,
224
+ optional: true,
225
+ });
226
+ }
227
+ for (const relation of table.relations.manyToMany) {
228
+ if (!relation.fieldName)
229
+ continue;
230
+ const relatedTypeName = getRelatedTypeName(relation.rightTable, tableByName);
231
+ properties.push({
232
+ name: relation.fieldName,
233
+ type: `ConnectionResult<${relatedTypeName}>`,
234
+ optional: true,
235
+ });
236
+ }
237
+ return properties;
238
+ }
239
+ /**
240
+ * Add entity relation types
241
+ */
242
+ function addEntityRelationTypes(sourceFile, tables, tableByName) {
243
+ addSectionComment(sourceFile, 'Entity Relation Types');
244
+ for (const table of tables) {
245
+ const { typeName } = getTableNames(table);
246
+ sourceFile.addInterface(createInterface(`${typeName}Relations`, buildEntityRelationProperties(table, tableByName)));
247
+ }
248
+ }
249
+ /**
250
+ * Add entity types with relations (intersection types)
251
+ */
252
+ function addEntityWithRelations(sourceFile, tables) {
253
+ addSectionComment(sourceFile, 'Entity Types With Relations');
254
+ for (const table of tables) {
255
+ const { typeName } = getTableNames(table);
256
+ sourceFile.addTypeAlias(createTypeAlias(`${typeName}WithRelations`, `${typeName} & ${typeName}Relations`));
257
+ }
258
+ }
259
+ // ============================================================================
260
+ // Entity Select Types Generator (AST-based)
261
+ // ============================================================================
262
+ /**
263
+ * Build the type string for a Select type (as object type literal)
264
+ */
265
+ function buildSelectTypeBody(table, tableByName) {
266
+ const lines = ['{'];
267
+ // Add scalar fields
268
+ for (const field of table.fields) {
269
+ if (!isRelationField(field.name, table)) {
270
+ lines.push(`${field.name}?: boolean;`);
271
+ }
272
+ }
273
+ // Add belongsTo relations
274
+ for (const relation of table.relations.belongsTo) {
275
+ if (relation.fieldName) {
276
+ const relatedTypeName = getRelatedTypeName(relation.referencesTable, tableByName);
277
+ lines.push(`${relation.fieldName}?: boolean | { select?: ${relatedTypeName}Select };`);
278
+ }
279
+ }
280
+ // Add hasMany relations
281
+ for (const relation of table.relations.hasMany) {
282
+ if (relation.fieldName) {
283
+ const relatedTypeName = getRelatedTypeName(relation.referencedByTable, tableByName);
284
+ const filterName = getRelatedFilterName(relation.referencedByTable, tableByName);
285
+ const orderByName = getRelatedOrderByName(relation.referencedByTable, tableByName);
286
+ lines.push(`${relation.fieldName}?: boolean | {`);
287
+ lines.push(` select?: ${relatedTypeName}Select;`);
288
+ lines.push(` first?: number;`);
289
+ lines.push(` filter?: ${filterName};`);
290
+ lines.push(` orderBy?: ${orderByName}[];`);
291
+ lines.push(`};`);
292
+ }
293
+ }
294
+ // Add manyToMany relations
295
+ for (const relation of table.relations.manyToMany) {
296
+ if (relation.fieldName) {
297
+ const relatedTypeName = getRelatedTypeName(relation.rightTable, tableByName);
298
+ const filterName = getRelatedFilterName(relation.rightTable, tableByName);
299
+ const orderByName = getRelatedOrderByName(relation.rightTable, tableByName);
300
+ lines.push(`${relation.fieldName}?: boolean | {`);
301
+ lines.push(` select?: ${relatedTypeName}Select;`);
302
+ lines.push(` first?: number;`);
303
+ lines.push(` filter?: ${filterName};`);
304
+ lines.push(` orderBy?: ${orderByName}[];`);
305
+ lines.push(`};`);
306
+ }
307
+ }
308
+ // Add hasOne relations
309
+ for (const relation of table.relations.hasOne) {
310
+ if (relation.fieldName) {
311
+ const relatedTypeName = getRelatedTypeName(relation.referencedByTable, tableByName);
312
+ lines.push(`${relation.fieldName}?: boolean | { select?: ${relatedTypeName}Select };`);
313
+ }
314
+ }
315
+ lines.push('}');
316
+ return lines.join('\n');
317
+ }
318
+ /**
319
+ * Add entity Select types
320
+ */
321
+ function addEntitySelectTypes(sourceFile, tables, tableByName) {
322
+ addSectionComment(sourceFile, 'Entity Select Types');
323
+ for (const table of tables) {
324
+ const { typeName } = getTableNames(table);
325
+ sourceFile.addTypeAlias(createTypeAlias(`${typeName}Select`, buildSelectTypeBody(table, tableByName)));
326
+ }
327
+ }
328
+ // ============================================================================
329
+ // Table Filter Types Generator (AST-based)
330
+ // ============================================================================
331
+ /**
332
+ * Map field type to filter type
333
+ */
334
+ function getFilterTypeForField(fieldType) {
335
+ return scalarToFilterType(fieldType) ?? 'StringFilter';
336
+ }
337
+ /**
338
+ * Build properties for a table filter interface
339
+ */
340
+ function buildTableFilterProperties(table) {
341
+ const filterName = getFilterTypeName(table);
342
+ const properties = [];
343
+ for (const field of table.fields) {
344
+ const fieldType = typeof field.type === 'string' ? field.type : field.type.gqlType;
345
+ if (isRelationField(field.name, table))
346
+ continue;
347
+ const filterType = getFilterTypeForField(fieldType);
348
+ properties.push({ name: field.name, type: filterType, optional: true });
349
+ }
350
+ // Add logical operators
351
+ properties.push({ name: 'and', type: `${filterName}[]`, optional: true });
352
+ properties.push({ name: 'or', type: `${filterName}[]`, optional: true });
353
+ properties.push({ name: 'not', type: filterName, optional: true });
354
+ return properties;
355
+ }
356
+ /**
357
+ * Add table filter types
358
+ */
359
+ function addTableFilterTypes(sourceFile, tables) {
360
+ addSectionComment(sourceFile, 'Table Filter Types');
361
+ for (const table of tables) {
362
+ const filterName = getFilterTypeName(table);
363
+ sourceFile.addInterface(createInterface(filterName, buildTableFilterProperties(table)));
364
+ }
365
+ }
366
+ // ============================================================================
367
+ // OrderBy Types Generator (AST-based)
368
+ // ============================================================================
369
+ /**
370
+ * Build OrderBy union type string
371
+ */
372
+ function buildOrderByUnion(table) {
373
+ const values = ['PRIMARY_KEY_ASC', 'PRIMARY_KEY_DESC', 'NATURAL'];
374
+ for (const field of table.fields) {
375
+ if (isRelationField(field.name, table))
376
+ continue;
377
+ const upperSnake = field.name.replace(/([A-Z])/g, '_$1').toUpperCase();
378
+ values.push(`${upperSnake}_ASC`);
379
+ values.push(`${upperSnake}_DESC`);
380
+ }
381
+ return values.map((v) => `'${v}'`).join(' | ');
382
+ }
383
+ /**
384
+ * Add OrderBy types
385
+ */
386
+ function addOrderByTypes(sourceFile, tables) {
387
+ addSectionComment(sourceFile, 'OrderBy Types');
388
+ for (const table of tables) {
389
+ const enumName = getOrderByTypeName(table);
390
+ sourceFile.addTypeAlias(createTypeAlias(enumName, buildOrderByUnion(table)));
391
+ }
392
+ }
393
+ // ============================================================================
394
+ // CRUD Input Types Generator (AST-based)
395
+ // ============================================================================
396
+ /**
397
+ * Build the nested data object fields for Create input
398
+ */
399
+ function buildCreateDataFields(table) {
400
+ const fields = [];
401
+ for (const field of table.fields) {
402
+ if (EXCLUDED_MUTATION_FIELDS.includes(field.name))
403
+ continue;
404
+ if (isRelationField(field.name, table))
405
+ continue;
406
+ const fieldType = typeof field.type === 'string' ? field.type : field.type.gqlType;
407
+ const tsType = scalarToInputTs(fieldType);
408
+ const isOptional = !field.name.endsWith('Id');
409
+ fields.push({ name: field.name, type: tsType, optional: isOptional });
410
+ }
411
+ return fields;
412
+ }
413
+ /**
414
+ * Generate Create input interface as formatted string.
415
+ *
416
+ * ts-morph doesn't handle nested object types in interface properties well,
417
+ * so we build this manually with pre-doubled indentation (4→2, 8→4) since
418
+ * getMinimalFormattedOutput halves all indentation.
419
+ */
420
+ function buildCreateInputInterface(table) {
421
+ const { typeName, singularName } = getTableNames(table);
422
+ const fields = buildCreateDataFields(table);
423
+ const lines = [
424
+ `export interface Create${typeName}Input {`,
425
+ ` clientMutationId?: string;`,
426
+ ` ${singularName}: {`,
427
+ ];
428
+ for (const field of fields) {
429
+ const opt = field.optional ? '?' : '';
430
+ lines.push(` ${field.name}${opt}: ${field.type};`);
431
+ }
432
+ lines.push(' };');
433
+ lines.push('}');
434
+ return lines.join('\n');
435
+ }
436
+ /**
437
+ * Build Patch type properties
438
+ */
439
+ function buildPatchProperties(table) {
440
+ const properties = [];
441
+ for (const field of table.fields) {
442
+ if (EXCLUDED_MUTATION_FIELDS.includes(field.name))
443
+ continue;
444
+ if (isRelationField(field.name, table))
445
+ continue;
446
+ const fieldType = typeof field.type === 'string' ? field.type : field.type.gqlType;
447
+ const tsType = scalarToInputTs(fieldType);
448
+ properties.push({ name: field.name, type: `${tsType} | null`, optional: true });
449
+ }
450
+ return properties;
451
+ }
452
+ /**
453
+ * Add CRUD input types for a table
454
+ */
455
+ function addCrudInputTypes(sourceFile, table) {
456
+ const { typeName } = getTableNames(table);
457
+ const patchName = `${typeName}Patch`;
458
+ // Create input - build as raw statement due to nested object type formatting
459
+ sourceFile.addStatements(buildCreateInputInterface(table));
460
+ // Patch interface
461
+ sourceFile.addInterface(createInterface(patchName, buildPatchProperties(table)));
462
+ // Update input
463
+ sourceFile.addInterface(createInterface(`Update${typeName}Input`, [
464
+ { name: 'clientMutationId', type: 'string', optional: true },
465
+ { name: 'id', type: 'string', optional: false },
466
+ { name: 'patch', type: patchName, optional: false },
467
+ ]));
468
+ // Delete input
469
+ sourceFile.addInterface(createInterface(`Delete${typeName}Input`, [
470
+ { name: 'clientMutationId', type: 'string', optional: true },
471
+ { name: 'id', type: 'string', optional: false },
472
+ ]));
473
+ }
474
+ /**
475
+ * Add all CRUD input types
476
+ */
477
+ function addAllCrudInputTypes(sourceFile, tables) {
478
+ addSectionComment(sourceFile, 'CRUD Input Types');
479
+ for (const table of tables) {
480
+ addCrudInputTypes(sourceFile, table);
481
+ }
482
+ }
483
+ // ============================================================================
484
+ // Custom Input Types Generator (AST-based)
485
+ // ============================================================================
486
+ /**
487
+ * Collect all input type names used by operations
488
+ */
489
+ export function collectInputTypeNames(operations) {
490
+ const inputTypes = new Set();
491
+ function collectFromTypeRef(typeRef) {
492
+ const baseName = getTypeBaseName(typeRef);
493
+ if (baseName && baseName.endsWith('Input')) {
494
+ inputTypes.add(baseName);
495
+ }
496
+ if (baseName && baseName.endsWith('Filter')) {
497
+ inputTypes.add(baseName);
498
+ }
499
+ }
500
+ for (const op of operations) {
501
+ for (const arg of op.args) {
502
+ collectFromTypeRef(arg.type);
503
+ }
504
+ }
505
+ return inputTypes;
506
+ }
507
+ /**
508
+ * Add custom input types from TypeRegistry
509
+ */
510
+ function addCustomInputTypes(sourceFile, typeRegistry, usedInputTypes) {
511
+ addSectionComment(sourceFile, 'Custom Input Types (from schema)');
512
+ const generatedTypes = new Set();
513
+ const typesToGenerate = new Set(Array.from(usedInputTypes));
514
+ // Filter out types we've already generated
515
+ const typesToRemove = [];
516
+ typesToGenerate.forEach((typeName) => {
517
+ if (typeName.endsWith('Filter') ||
518
+ typeName.startsWith('Create') ||
519
+ typeName.startsWith('Update') ||
520
+ typeName.startsWith('Delete')) {
521
+ const isTableCrud = /^(Create|Update|Delete)[A-Z][a-zA-Z]+Input$/.test(typeName) ||
522
+ /^[A-Z][a-zA-Z]+Filter$/.test(typeName);
523
+ if (isTableCrud) {
524
+ typesToRemove.push(typeName);
525
+ }
526
+ }
527
+ });
528
+ typesToRemove.forEach((t) => typesToGenerate.delete(t));
529
+ let iterations = 0;
530
+ const maxIterations = 200;
531
+ while (typesToGenerate.size > 0 && iterations < maxIterations) {
532
+ iterations++;
533
+ const typeNameResult = typesToGenerate.values().next();
534
+ if (typeNameResult.done)
535
+ break;
536
+ const typeName = typeNameResult.value;
537
+ typesToGenerate.delete(typeName);
538
+ if (generatedTypes.has(typeName))
539
+ continue;
540
+ generatedTypes.add(typeName);
541
+ const typeInfo = typeRegistry.get(typeName);
542
+ if (!typeInfo) {
543
+ sourceFile.addStatements(`// Type '${typeName}' not found in schema`);
544
+ sourceFile.addTypeAlias(createTypeAlias(typeName, 'Record<string, unknown>'));
545
+ continue;
546
+ }
547
+ if (typeInfo.kind === 'INPUT_OBJECT' && typeInfo.inputFields) {
548
+ const properties = [];
549
+ for (const field of typeInfo.inputFields) {
550
+ const optional = !isRequired(field.type);
551
+ const tsType = typeRefToTs(field.type);
552
+ properties.push({ name: field.name, type: tsType, optional });
553
+ // Follow nested Input types
554
+ const baseType = getTypeBaseName(field.type);
555
+ if (baseType && baseType.endsWith('Input') && !generatedTypes.has(baseType)) {
556
+ typesToGenerate.add(baseType);
557
+ }
558
+ }
559
+ sourceFile.addInterface(createInterface(typeName, properties));
560
+ }
561
+ else if (typeInfo.kind === 'ENUM' && typeInfo.enumValues) {
562
+ const values = typeInfo.enumValues.map((v) => `'${v}'`).join(' | ');
563
+ sourceFile.addTypeAlias(createTypeAlias(typeName, values));
564
+ }
565
+ else {
566
+ sourceFile.addStatements(`// Type '${typeName}' is ${typeInfo.kind}`);
567
+ sourceFile.addTypeAlias(createTypeAlias(typeName, 'unknown'));
568
+ }
569
+ }
570
+ }
571
+ // ============================================================================
572
+ // Payload/Return Types Generator (AST-based)
573
+ // ============================================================================
574
+ /**
575
+ * Collect all payload type names from operation return types
576
+ */
577
+ export function collectPayloadTypeNames(operations) {
578
+ const payloadTypes = new Set();
579
+ for (const op of operations) {
580
+ const baseName = getTypeBaseName(op.returnType);
581
+ if (baseName && (baseName.endsWith('Payload') || !baseName.endsWith('Connection'))) {
582
+ payloadTypes.add(baseName);
583
+ }
584
+ }
585
+ return payloadTypes;
586
+ }
587
+ /**
588
+ * Add payload/return types
589
+ */
590
+ function addPayloadTypes(sourceFile, typeRegistry, usedPayloadTypes, alreadyGeneratedTypes) {
591
+ addSectionComment(sourceFile, 'Payload/Return Types (for custom operations)');
592
+ const generatedTypes = new Set(alreadyGeneratedTypes);
593
+ const typesToGenerate = new Set(Array.from(usedPayloadTypes));
594
+ const skipTypes = new Set([
595
+ 'String', 'Int', 'Float', 'Boolean', 'ID', 'UUID', 'Datetime', 'Date',
596
+ 'Time', 'JSON', 'BigInt', 'BigFloat', 'Cursor', 'Query', 'Mutation',
597
+ ]);
598
+ let iterations = 0;
599
+ const maxIterations = 200;
600
+ while (typesToGenerate.size > 0 && iterations < maxIterations) {
601
+ iterations++;
602
+ const typeNameResult = typesToGenerate.values().next();
603
+ if (typeNameResult.done)
604
+ break;
605
+ const typeName = typeNameResult.value;
606
+ typesToGenerate.delete(typeName);
607
+ if (generatedTypes.has(typeName) || skipTypes.has(typeName))
608
+ continue;
609
+ const typeInfo = typeRegistry.get(typeName);
610
+ if (!typeInfo)
611
+ continue;
612
+ if (typeInfo.kind !== 'OBJECT' || !typeInfo.fields)
613
+ continue;
614
+ generatedTypes.add(typeName);
615
+ // Build interface properties
616
+ const interfaceProps = [];
617
+ for (const field of typeInfo.fields) {
618
+ const baseType = getTypeBaseName(field.type);
619
+ if (baseType === 'Query' || baseType === 'Mutation')
620
+ continue;
621
+ const tsType = typeRefToTs(field.type);
622
+ const isNullable = !isRequired(field.type);
623
+ interfaceProps.push({
624
+ name: field.name,
625
+ type: isNullable ? `${tsType} | null` : tsType,
626
+ optional: isNullable,
627
+ });
628
+ // Follow nested OBJECT types
629
+ if (baseType && !generatedTypes.has(baseType) && !skipTypes.has(baseType)) {
630
+ const nestedType = typeRegistry.get(baseType);
631
+ if (nestedType?.kind === 'OBJECT') {
632
+ typesToGenerate.add(baseType);
633
+ }
634
+ }
635
+ }
636
+ sourceFile.addInterface(createInterface(typeName, interfaceProps));
637
+ // Build Select type (no indentation - ts-morph adds it)
638
+ const selectLines = ['{'];
639
+ for (const field of typeInfo.fields) {
640
+ const baseType = getTypeBaseName(field.type);
641
+ if (baseType === 'Query' || baseType === 'Mutation')
642
+ continue;
643
+ const nestedType = baseType ? typeRegistry.get(baseType) : null;
644
+ if (nestedType?.kind === 'OBJECT') {
645
+ selectLines.push(`${field.name}?: boolean | { select?: ${baseType}Select };`);
646
+ }
647
+ else {
648
+ selectLines.push(`${field.name}?: boolean;`);
649
+ }
650
+ }
651
+ selectLines.push('}');
652
+ sourceFile.addTypeAlias(createTypeAlias(`${typeName}Select`, selectLines.join('\n')));
653
+ }
654
+ }
655
+ // ============================================================================
656
+ // Main Generator (AST-based)
657
+ // ============================================================================
658
+ /**
659
+ * Generate comprehensive input-types.ts file using ts-morph AST
660
+ */
661
+ export function generateInputTypesFile(typeRegistry, usedInputTypes, tables, usedPayloadTypes) {
662
+ const project = createProject();
663
+ const sourceFile = createSourceFile(project, 'input-types.ts');
664
+ // Add file header
665
+ sourceFile.insertText(0, createFileHeader('GraphQL types for ORM client') + '\n');
666
+ // 1. Scalar filter types
667
+ addScalarFilterTypes(sourceFile);
668
+ // 2. Entity and relation types (if tables provided)
669
+ if (tables && tables.length > 0) {
670
+ const tableByName = new Map(tables.map((table) => [table.name, table]));
671
+ addEntityTypes(sourceFile, tables);
672
+ addRelationHelperTypes(sourceFile);
673
+ addEntityRelationTypes(sourceFile, tables, tableByName);
674
+ addEntityWithRelations(sourceFile, tables);
675
+ addEntitySelectTypes(sourceFile, tables, tableByName);
676
+ // 3. Table filter types
677
+ addTableFilterTypes(sourceFile, tables);
678
+ // 4. OrderBy types
679
+ addOrderByTypes(sourceFile, tables);
680
+ // 5. CRUD input types
681
+ addAllCrudInputTypes(sourceFile, tables);
682
+ }
683
+ // 6. Custom input types from TypeRegistry
684
+ addCustomInputTypes(sourceFile, typeRegistry, usedInputTypes);
685
+ // 7. Payload/return types for custom operations
686
+ if (usedPayloadTypes && usedPayloadTypes.size > 0) {
687
+ const alreadyGeneratedTypes = new Set();
688
+ if (tables) {
689
+ for (const table of tables) {
690
+ const { typeName } = getTableNames(table);
691
+ alreadyGeneratedTypes.add(typeName);
692
+ }
693
+ }
694
+ addPayloadTypes(sourceFile, typeRegistry, usedPayloadTypes, alreadyGeneratedTypes);
695
+ }
696
+ return {
697
+ fileName: 'input-types.ts',
698
+ content: getMinimalFormattedOutput(sourceFile),
699
+ };
700
+ }