@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,355 @@
1
+ /**
2
+ * Convert simplified field selection to QueryBuilder SelectionOptions
3
+ */
4
+ export function convertToSelectionOptions(table, allTables, selection) {
5
+ if (!selection) {
6
+ return convertPresetToSelection(table, 'display');
7
+ }
8
+ if (typeof selection === 'string') {
9
+ return convertPresetToSelection(table, selection);
10
+ }
11
+ return convertCustomSelectionToOptions(table, allTables, selection);
12
+ }
13
+ /**
14
+ * Convert preset to selection options
15
+ */
16
+ function convertPresetToSelection(table, preset) {
17
+ const options = {};
18
+ switch (preset) {
19
+ case 'minimal': {
20
+ // Just id and first display field
21
+ const minimalFields = getMinimalFields(table);
22
+ minimalFields.forEach((field) => {
23
+ options[field] = true;
24
+ });
25
+ break;
26
+ }
27
+ case 'display': {
28
+ // Common display fields
29
+ const displayFields = getDisplayFields(table);
30
+ displayFields.forEach((field) => {
31
+ options[field] = true;
32
+ });
33
+ break;
34
+ }
35
+ case 'all': {
36
+ // All non-relational fields (includes complex fields like JSON, geometry, etc.)
37
+ const allFields = getNonRelationalFields(table);
38
+ allFields.forEach((field) => {
39
+ options[field] = true;
40
+ });
41
+ break;
42
+ }
43
+ case 'full':
44
+ // All fields including basic relations
45
+ table.fields.forEach((field) => {
46
+ options[field.name] = true;
47
+ });
48
+ break;
49
+ default: {
50
+ // Default to display
51
+ const defaultFields = getDisplayFields(table);
52
+ defaultFields.forEach((field) => {
53
+ options[field] = true;
54
+ });
55
+ }
56
+ }
57
+ return options;
58
+ }
59
+ /**
60
+ * Convert custom selection to options
61
+ */
62
+ function convertCustomSelectionToOptions(table, allTables, selection) {
63
+ const options = {};
64
+ // Start with selected fields or all non-relational fields (including complex types)
65
+ let fieldsToInclude;
66
+ if (selection.select) {
67
+ fieldsToInclude = selection.select;
68
+ }
69
+ else {
70
+ fieldsToInclude = getNonRelationalFields(table);
71
+ }
72
+ // Add basic fields
73
+ fieldsToInclude.forEach((field) => {
74
+ if (table.fields.some((f) => f.name === field)) {
75
+ options[field] = true;
76
+ }
77
+ });
78
+ // Handle includeRelations (simple API for relation fields)
79
+ if (selection.includeRelations) {
80
+ selection.includeRelations.forEach((relationField) => {
81
+ if (isRelationalField(relationField, table)) {
82
+ // Include with dynamically determined scalar fields from the related table
83
+ options[relationField] = {
84
+ select: getRelatedTableScalarFields(relationField, table, allTables),
85
+ variables: {},
86
+ };
87
+ }
88
+ });
89
+ }
90
+ // Handle includes (relations) - more detailed API
91
+ if (selection.include) {
92
+ Object.entries(selection.include).forEach(([relationField, relationSelection]) => {
93
+ if (isRelationalField(relationField, table)) {
94
+ if (relationSelection === true) {
95
+ // Include with dynamically determined scalar fields from the related table
96
+ options[relationField] = {
97
+ select: getRelatedTableScalarFields(relationField, table, allTables),
98
+ variables: {},
99
+ };
100
+ }
101
+ else if (Array.isArray(relationSelection)) {
102
+ // Include with specific fields
103
+ const selectObj = {};
104
+ relationSelection.forEach((field) => {
105
+ selectObj[field] = true;
106
+ });
107
+ options[relationField] = {
108
+ select: selectObj,
109
+ variables: {},
110
+ };
111
+ }
112
+ }
113
+ });
114
+ }
115
+ // Handle excludes
116
+ if (selection.exclude) {
117
+ selection.exclude.forEach((field) => {
118
+ delete options[field];
119
+ });
120
+ }
121
+ return options;
122
+ }
123
+ /**
124
+ * Get minimal fields - completely schema-driven, no hardcoded assumptions
125
+ */
126
+ function getMinimalFields(table) {
127
+ // Get all non-relational fields from the actual schema
128
+ const nonRelationalFields = getNonRelationalFields(table);
129
+ // Return the first few fields from the schema (typically includes primary key and basic fields)
130
+ // This is completely dynamic based on what the schema actually provides
131
+ return nonRelationalFields.slice(0, 3); // Limit to first 3 fields for minimal selection
132
+ }
133
+ /**
134
+ * Get display fields - completely schema-driven, no hardcoded field names
135
+ */
136
+ function getDisplayFields(table) {
137
+ // Get all non-relational fields from the actual schema
138
+ const nonRelationalFields = getNonRelationalFields(table);
139
+ // Return a reasonable subset for display purposes (first half of available fields)
140
+ // This is completely dynamic based on what the schema actually provides
141
+ const maxDisplayFields = Math.max(5, Math.floor(nonRelationalFields.length / 2));
142
+ return nonRelationalFields.slice(0, maxDisplayFields);
143
+ }
144
+ /**
145
+ * Get all non-relational fields (includes both scalar and complex fields)
146
+ * Complex fields like JSON, geometry, images should be included by default
147
+ */
148
+ function getNonRelationalFields(table) {
149
+ return table.fields
150
+ .filter((field) => !isRelationalField(field.name, table))
151
+ .map((field) => field.name);
152
+ }
153
+ /**
154
+ * Check if a field is relational using table metadata
155
+ */
156
+ export function isRelationalField(fieldName, table) {
157
+ const { belongsTo, hasOne, hasMany, manyToMany } = table.relations;
158
+ return (belongsTo.some((rel) => rel.fieldName === fieldName) ||
159
+ hasOne.some((rel) => rel.fieldName === fieldName) ||
160
+ hasMany.some((rel) => rel.fieldName === fieldName) ||
161
+ manyToMany.some((rel) => rel.fieldName === fieldName));
162
+ }
163
+ /**
164
+ * Get scalar fields for a related table to include in relation queries
165
+ * Uses only the _meta query data - no hardcoded field names or assumptions
166
+ */
167
+ function getRelatedTableScalarFields(relationField, table, allTables) {
168
+ // Find the related table name
169
+ let referencedTableName;
170
+ // Check belongsTo relations
171
+ const belongsToRel = table.relations.belongsTo.find((rel) => rel.fieldName === relationField);
172
+ if (belongsToRel) {
173
+ referencedTableName = belongsToRel.referencesTable;
174
+ }
175
+ // Check hasOne relations
176
+ if (!referencedTableName) {
177
+ const hasOneRel = table.relations.hasOne.find((rel) => rel.fieldName === relationField);
178
+ if (hasOneRel) {
179
+ referencedTableName = hasOneRel.referencedByTable;
180
+ }
181
+ }
182
+ // Check hasMany relations
183
+ if (!referencedTableName) {
184
+ const hasManyRel = table.relations.hasMany.find((rel) => rel.fieldName === relationField);
185
+ if (hasManyRel) {
186
+ referencedTableName = hasManyRel.referencedByTable;
187
+ }
188
+ }
189
+ // Check manyToMany relations
190
+ if (!referencedTableName) {
191
+ const manyToManyRel = table.relations.manyToMany.find((rel) => rel.fieldName === relationField);
192
+ if (manyToManyRel) {
193
+ referencedTableName = manyToManyRel.rightTable;
194
+ }
195
+ }
196
+ if (!referencedTableName) {
197
+ // No related table found - return empty selection
198
+ return {};
199
+ }
200
+ // Find the related table in allTables
201
+ const relatedTable = allTables.find((t) => t.name === referencedTableName);
202
+ if (!relatedTable) {
203
+ // Related table not found in schema - return empty selection
204
+ return {};
205
+ }
206
+ // Get ALL scalar fields from the related table (non-relational fields)
207
+ // This is completely dynamic based on the actual schema
208
+ const scalarFields = relatedTable.fields
209
+ .filter((field) => !isRelationalField(field.name, relatedTable))
210
+ .map((field) => field.name);
211
+ // Perf guardrail: select a small, display-oriented subset.
212
+ const MAX_RELATED_FIELDS = 8;
213
+ const preferred = [
214
+ 'displayName',
215
+ 'fullName',
216
+ 'preferredName',
217
+ 'nickname',
218
+ 'firstName',
219
+ 'lastName',
220
+ 'username',
221
+ 'email',
222
+ 'name',
223
+ 'title',
224
+ 'label',
225
+ 'slug',
226
+ 'code',
227
+ 'createdAt',
228
+ 'updatedAt',
229
+ ];
230
+ const included = [];
231
+ const push = (fieldName) => {
232
+ if (!fieldName)
233
+ return;
234
+ if (!scalarFields.includes(fieldName))
235
+ return;
236
+ if (included.includes(fieldName))
237
+ return;
238
+ if (included.length >= MAX_RELATED_FIELDS)
239
+ return;
240
+ included.push(fieldName);
241
+ };
242
+ // Always try to include stable identifiers first.
243
+ push('id');
244
+ push('nodeId');
245
+ for (const fieldName of preferred)
246
+ push(fieldName);
247
+ for (const fieldName of scalarFields)
248
+ push(fieldName);
249
+ const selection = {};
250
+ for (const fieldName of included)
251
+ selection[fieldName] = true;
252
+ return selection;
253
+ }
254
+ /**
255
+ * Get all available relation fields from a table
256
+ */
257
+ export function getAvailableRelations(table) {
258
+ const relations = [];
259
+ // Add belongsTo relations
260
+ table.relations.belongsTo.forEach((rel) => {
261
+ if (rel.fieldName) {
262
+ relations.push({
263
+ fieldName: rel.fieldName,
264
+ type: 'belongsTo',
265
+ referencedTable: rel.referencesTable || undefined,
266
+ });
267
+ }
268
+ });
269
+ // Add hasOne relations
270
+ table.relations.hasOne.forEach((rel) => {
271
+ if (rel.fieldName) {
272
+ relations.push({
273
+ fieldName: rel.fieldName,
274
+ type: 'hasOne',
275
+ referencedTable: rel.referencedByTable || undefined,
276
+ });
277
+ }
278
+ });
279
+ // Add hasMany relations
280
+ table.relations.hasMany.forEach((rel) => {
281
+ if (rel.fieldName) {
282
+ relations.push({
283
+ fieldName: rel.fieldName,
284
+ type: 'hasMany',
285
+ referencedTable: rel.referencedByTable || undefined,
286
+ });
287
+ }
288
+ });
289
+ // Add manyToMany relations
290
+ table.relations.manyToMany.forEach((rel) => {
291
+ if (rel.fieldName) {
292
+ relations.push({
293
+ fieldName: rel.fieldName,
294
+ type: 'manyToMany',
295
+ referencedTable: rel.rightTable || undefined,
296
+ });
297
+ }
298
+ });
299
+ return relations;
300
+ }
301
+ /**
302
+ * Validate field selection against table schema
303
+ */
304
+ export function validateFieldSelection(selection, table) {
305
+ const errors = [];
306
+ if (typeof selection === 'string') {
307
+ // Presets are always valid
308
+ return { isValid: true, errors: [] };
309
+ }
310
+ const tableFieldNames = table.fields.map((f) => f.name);
311
+ // Validate select fields
312
+ if (selection.select) {
313
+ selection.select.forEach((field) => {
314
+ if (!tableFieldNames.includes(field)) {
315
+ errors.push(`Field '${field}' does not exist in table '${table.name}'`);
316
+ }
317
+ });
318
+ }
319
+ // Validate includeRelations fields
320
+ if (selection.includeRelations) {
321
+ selection.includeRelations.forEach((field) => {
322
+ if (!isRelationalField(field, table)) {
323
+ errors.push(`Field '${field}' is not a relational field in table '${table.name}'`);
324
+ }
325
+ });
326
+ }
327
+ // Validate include fields
328
+ if (selection.include) {
329
+ Object.keys(selection.include).forEach((field) => {
330
+ if (!isRelationalField(field, table)) {
331
+ errors.push(`Field '${field}' is not a relational field in table '${table.name}'`);
332
+ }
333
+ });
334
+ }
335
+ // Validate exclude fields
336
+ if (selection.exclude) {
337
+ selection.exclude.forEach((field) => {
338
+ if (!tableFieldNames.includes(field)) {
339
+ errors.push(`Exclude field '${field}' does not exist in table '${table.name}'`);
340
+ }
341
+ });
342
+ }
343
+ // Validate maxDepth
344
+ if (selection.maxDepth !== undefined) {
345
+ if (typeof selection.maxDepth !== 'number' ||
346
+ selection.maxDepth < 0 ||
347
+ selection.maxDepth > 5) {
348
+ errors.push('maxDepth must be a number between 0 and 5');
349
+ }
350
+ }
351
+ return {
352
+ isValid: errors.length === 0,
353
+ errors,
354
+ };
355
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Query and mutation generator exports
3
+ */
4
+ export { convertToSelectionOptions, isRelationalField, getAvailableRelations, validateFieldSelection, } from './field-selector';
5
+ export { buildSelect, buildFindOne, buildCount, toCamelCasePlural, toOrderByTypeName, cleanTableToMetaObject, generateIntrospectionSchema, createASTQueryBuilder, } from './select';
6
+ export { buildPostGraphileCreate, buildPostGraphileUpdate, buildPostGraphileDelete, } from './mutations';
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Query and mutation generator exports
3
+ */
4
+ // Field selector utilities
5
+ export { convertToSelectionOptions, isRelationalField, getAvailableRelations, validateFieldSelection, } from './field-selector';
6
+ // Query generators
7
+ export { buildSelect, buildFindOne, buildCount, toCamelCasePlural, toOrderByTypeName, cleanTableToMetaObject, generateIntrospectionSchema, createASTQueryBuilder, } from './select';
8
+ // Mutation generators
9
+ export { buildPostGraphileCreate, buildPostGraphileUpdate, buildPostGraphileDelete, } from './mutations';
@@ -0,0 +1,31 @@
1
+ import { TypedDocumentString } from '../client/typed-document';
2
+ import type { CleanTable } from '../types/schema';
3
+ import type { MutationOptions } from '../types/mutation';
4
+ /**
5
+ * Build PostGraphile-style CREATE mutation
6
+ * PostGraphile expects: mutation { createTableName(input: { tableName: TableNameInput! }) { tableName { ... } } }
7
+ */
8
+ export declare function buildPostGraphileCreate(table: CleanTable, _allTables: CleanTable[], _options?: MutationOptions): TypedDocumentString<Record<string, unknown>, {
9
+ input: {
10
+ [key: string]: Record<string, unknown>;
11
+ };
12
+ }>;
13
+ /**
14
+ * Build PostGraphile-style UPDATE mutation
15
+ * PostGraphile expects: mutation { updateTableName(input: { id: UUID!, patch: TableNamePatch! }) { tableName { ... } } }
16
+ */
17
+ export declare function buildPostGraphileUpdate(table: CleanTable, _allTables: CleanTable[], _options?: MutationOptions): TypedDocumentString<Record<string, unknown>, {
18
+ input: {
19
+ id: string | number;
20
+ patch: Record<string, unknown>;
21
+ };
22
+ }>;
23
+ /**
24
+ * Build PostGraphile-style DELETE mutation
25
+ * PostGraphile expects: mutation { deleteTableName(input: { id: UUID! }) { clientMutationId } }
26
+ */
27
+ export declare function buildPostGraphileDelete(table: CleanTable, _allTables: CleanTable[], _options?: MutationOptions): TypedDocumentString<Record<string, unknown>, {
28
+ input: {
29
+ id: string | number;
30
+ };
31
+ }>;
@@ -0,0 +1,197 @@
1
+ /**
2
+ * Mutation generators for CREATE, UPDATE, and DELETE operations
3
+ * Uses AST-based approach for PostGraphile-compatible mutations
4
+ */
5
+ import * as t from 'gql-ast';
6
+ import { print } from 'graphql';
7
+ import * as inflection from 'inflection';
8
+ import { TypedDocumentString } from '../client/typed-document';
9
+ import { getCustomAstForCleanField, requiresSubfieldSelection, } from '../core/custom-ast';
10
+ import { isRelationalField } from './field-selector';
11
+ /**
12
+ * Generate field selections for PostGraphile mutations using custom AST logic
13
+ * This handles both scalar fields and complex types that require subfield selections
14
+ */
15
+ function generateFieldSelections(table) {
16
+ return table.fields
17
+ .filter((field) => !isRelationalField(field.name, table)) // Exclude relational fields
18
+ .map((field) => {
19
+ if (requiresSubfieldSelection(field)) {
20
+ // Use custom AST generation for complex types
21
+ return getCustomAstForCleanField(field);
22
+ }
23
+ else {
24
+ // Use simple field selection for scalar types
25
+ return t.field({ name: field.name });
26
+ }
27
+ });
28
+ }
29
+ /**
30
+ * Build PostGraphile-style CREATE mutation
31
+ * PostGraphile expects: mutation { createTableName(input: { tableName: TableNameInput! }) { tableName { ... } } }
32
+ */
33
+ export function buildPostGraphileCreate(table, _allTables, _options = {}) {
34
+ const mutationName = `create${table.name}`;
35
+ const singularName = inflection.camelize(table.name, true);
36
+ // Create the variable definition for $input
37
+ const variableDefinitions = [
38
+ t.variableDefinition({
39
+ variable: t.variable({ name: 'input' }),
40
+ type: t.nonNullType({
41
+ type: t.namedType({ type: `Create${table.name}Input` }),
42
+ }),
43
+ }),
44
+ ];
45
+ // Create the mutation arguments
46
+ const mutationArgs = [
47
+ t.argument({
48
+ name: 'input',
49
+ value: t.variable({ name: 'input' }),
50
+ }),
51
+ ];
52
+ // Get the field selections for the return value using custom AST logic
53
+ const fieldSelections = generateFieldSelections(table);
54
+ // Build the mutation AST
55
+ const ast = t.document({
56
+ definitions: [
57
+ t.operationDefinition({
58
+ operation: 'mutation',
59
+ name: `${mutationName}Mutation`,
60
+ variableDefinitions,
61
+ selectionSet: t.selectionSet({
62
+ selections: [
63
+ t.field({
64
+ name: mutationName,
65
+ args: mutationArgs,
66
+ selectionSet: t.selectionSet({
67
+ selections: [
68
+ t.field({
69
+ name: singularName,
70
+ selectionSet: t.selectionSet({
71
+ selections: fieldSelections,
72
+ }),
73
+ }),
74
+ ],
75
+ }),
76
+ }),
77
+ ],
78
+ }),
79
+ }),
80
+ ],
81
+ });
82
+ // Print the AST to get the query string
83
+ const queryString = print(ast);
84
+ return new TypedDocumentString(queryString, {
85
+ __ast: ast,
86
+ });
87
+ }
88
+ /**
89
+ * Build PostGraphile-style UPDATE mutation
90
+ * PostGraphile expects: mutation { updateTableName(input: { id: UUID!, patch: TableNamePatch! }) { tableName { ... } } }
91
+ */
92
+ export function buildPostGraphileUpdate(table, _allTables, _options = {}) {
93
+ const mutationName = `update${table.name}`;
94
+ const singularName = inflection.camelize(table.name, true);
95
+ // Create the variable definition for $input
96
+ const variableDefinitions = [
97
+ t.variableDefinition({
98
+ variable: t.variable({ name: 'input' }),
99
+ type: t.nonNullType({
100
+ type: t.namedType({ type: `Update${table.name}Input` }),
101
+ }),
102
+ }),
103
+ ];
104
+ // Create the mutation arguments
105
+ const mutationArgs = [
106
+ t.argument({
107
+ name: 'input',
108
+ value: t.variable({ name: 'input' }),
109
+ }),
110
+ ];
111
+ // Get the field selections for the return value using custom AST logic
112
+ const fieldSelections = generateFieldSelections(table);
113
+ // Build the mutation AST
114
+ const ast = t.document({
115
+ definitions: [
116
+ t.operationDefinition({
117
+ operation: 'mutation',
118
+ name: `${mutationName}Mutation`,
119
+ variableDefinitions,
120
+ selectionSet: t.selectionSet({
121
+ selections: [
122
+ t.field({
123
+ name: mutationName,
124
+ args: mutationArgs,
125
+ selectionSet: t.selectionSet({
126
+ selections: [
127
+ t.field({
128
+ name: singularName,
129
+ selectionSet: t.selectionSet({
130
+ selections: fieldSelections,
131
+ }),
132
+ }),
133
+ ],
134
+ }),
135
+ }),
136
+ ],
137
+ }),
138
+ }),
139
+ ],
140
+ });
141
+ // Print the AST to get the query string
142
+ const queryString = print(ast);
143
+ return new TypedDocumentString(queryString, {
144
+ __ast: ast,
145
+ });
146
+ }
147
+ /**
148
+ * Build PostGraphile-style DELETE mutation
149
+ * PostGraphile expects: mutation { deleteTableName(input: { id: UUID! }) { clientMutationId } }
150
+ */
151
+ export function buildPostGraphileDelete(table, _allTables, _options = {}) {
152
+ const mutationName = `delete${table.name}`;
153
+ // Create the variable definition for $input
154
+ const variableDefinitions = [
155
+ t.variableDefinition({
156
+ variable: t.variable({ name: 'input' }),
157
+ type: t.nonNullType({
158
+ type: t.namedType({ type: `Delete${table.name}Input` }),
159
+ }),
160
+ }),
161
+ ];
162
+ // Create the mutation arguments
163
+ const mutationArgs = [
164
+ t.argument({
165
+ name: 'input',
166
+ value: t.variable({ name: 'input' }),
167
+ }),
168
+ ];
169
+ // PostGraphile delete mutations typically return clientMutationId
170
+ const fieldSelections = [t.field({ name: 'clientMutationId' })];
171
+ // Build the mutation AST
172
+ const ast = t.document({
173
+ definitions: [
174
+ t.operationDefinition({
175
+ operation: 'mutation',
176
+ name: `${mutationName}Mutation`,
177
+ variableDefinitions,
178
+ selectionSet: t.selectionSet({
179
+ selections: [
180
+ t.field({
181
+ name: mutationName,
182
+ args: mutationArgs,
183
+ selectionSet: t.selectionSet({
184
+ selections: fieldSelections,
185
+ }),
186
+ }),
187
+ ],
188
+ }),
189
+ }),
190
+ ],
191
+ });
192
+ // Print the AST to get the query string
193
+ const queryString = print(ast);
194
+ return new TypedDocumentString(queryString, {
195
+ __ast: ast,
196
+ });
197
+ }
@@ -0,0 +1,50 @@
1
+ import { TypedDocumentString } from '../client/typed-document';
2
+ import { QueryBuilder } from '../core/query-builder';
3
+ import type { IntrospectionSchema, MetaObject } from '../core/types';
4
+ import type { CleanTable } from '../types/schema';
5
+ import type { QueryOptions } from '../types/query';
6
+ /**
7
+ * Convert PascalCase table name to camelCase plural for GraphQL queries
8
+ * Uses the inflection library for proper pluralization
9
+ * Example: "ActionGoal" -> "actionGoals", "User" -> "users", "Person" -> "people"
10
+ */
11
+ export declare function toCamelCasePlural(tableName: string): string;
12
+ /**
13
+ * Generate the PostGraphile OrderBy enum type name for a table
14
+ * PostGraphile uses pluralized PascalCase: "Product" -> "ProductsOrderBy"
15
+ * Example: "Product" -> "ProductsOrderBy", "Person" -> "PeopleOrderBy"
16
+ */
17
+ export declare function toOrderByTypeName(tableName: string): string;
18
+ /**
19
+ * Convert CleanTable to MetaObject format for QueryBuilder
20
+ */
21
+ export declare function cleanTableToMetaObject(tables: CleanTable[]): MetaObject;
22
+ /**
23
+ * Generate basic IntrospectionSchema from CleanTable array
24
+ * This creates a minimal schema for AST generation
25
+ */
26
+ export declare function generateIntrospectionSchema(tables: CleanTable[]): IntrospectionSchema;
27
+ /**
28
+ * Create AST-based query builder for a table
29
+ */
30
+ export declare function createASTQueryBuilder(tables: CleanTable[]): QueryBuilder;
31
+ /**
32
+ * Build a SELECT query for a table with optional filtering, sorting, and pagination
33
+ * Uses direct AST generation without intermediate conversions
34
+ */
35
+ export declare function buildSelect(table: CleanTable, allTables: readonly CleanTable[], options?: QueryOptions): TypedDocumentString<Record<string, unknown>, QueryOptions>;
36
+ /**
37
+ * Build a single row query by primary key or unique field
38
+ */
39
+ export declare function buildFindOne(table: CleanTable, _pkField?: string): TypedDocumentString<Record<string, unknown>, Record<string, unknown>>;
40
+ /**
41
+ * Build a count query for a table
42
+ */
43
+ export declare function buildCount(table: CleanTable): TypedDocumentString<{
44
+ [key: string]: {
45
+ totalCount: number;
46
+ };
47
+ }, {
48
+ condition?: Record<string, unknown>;
49
+ filter?: Record<string, unknown>;
50
+ }>;