@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,636 @@
1
+ /**
2
+ * Query generators for SELECT, FindOne, and Count operations
3
+ * Uses AST-based approach for all query generation
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 { QueryBuilder } from '../core/query-builder';
11
+ import { convertToSelectionOptions, isRelationalField } from './field-selector';
12
+ /**
13
+ * Convert PascalCase table name to camelCase plural for GraphQL queries
14
+ * Uses the inflection library for proper pluralization
15
+ * Example: "ActionGoal" -> "actionGoals", "User" -> "users", "Person" -> "people"
16
+ */
17
+ export function toCamelCasePlural(tableName) {
18
+ // First convert to camelCase (lowercase first letter)
19
+ const camelCase = inflection.camelize(tableName, true);
20
+ // Then pluralize properly
21
+ return inflection.pluralize(camelCase);
22
+ }
23
+ /**
24
+ * Generate the PostGraphile OrderBy enum type name for a table
25
+ * PostGraphile uses pluralized PascalCase: "Product" -> "ProductsOrderBy"
26
+ * Example: "Product" -> "ProductsOrderBy", "Person" -> "PeopleOrderBy"
27
+ */
28
+ export function toOrderByTypeName(tableName) {
29
+ const plural = toCamelCasePlural(tableName); // "products", "people"
30
+ // Capitalize first letter for PascalCase
31
+ return `${plural.charAt(0).toUpperCase() + plural.slice(1)}OrderBy`;
32
+ }
33
+ /**
34
+ * Convert CleanTable to MetaObject format for QueryBuilder
35
+ */
36
+ export function cleanTableToMetaObject(tables) {
37
+ return {
38
+ tables: tables.map((table) => ({
39
+ name: table.name,
40
+ fields: table.fields.map((field) => ({
41
+ name: field.name,
42
+ type: {
43
+ gqlType: field.type.gqlType,
44
+ isArray: field.type.isArray,
45
+ modifier: field.type.modifier,
46
+ pgAlias: field.type.pgAlias,
47
+ pgType: field.type.pgType,
48
+ subtype: field.type.subtype,
49
+ typmod: field.type.typmod,
50
+ },
51
+ })),
52
+ primaryConstraints: [], // Would need to be derived from schema
53
+ uniqueConstraints: [], // Would need to be derived from schema
54
+ foreignConstraints: table.relations.belongsTo.map((rel) => ({
55
+ refTable: rel.referencesTable,
56
+ fromKey: {
57
+ name: rel.fieldName || '',
58
+ type: {
59
+ gqlType: 'UUID', // Default, should be derived from actual field
60
+ isArray: false,
61
+ modifier: null,
62
+ pgAlias: null,
63
+ pgType: null,
64
+ subtype: null,
65
+ typmod: null,
66
+ },
67
+ alias: rel.fieldName || '',
68
+ },
69
+ toKey: {
70
+ name: 'id',
71
+ type: {
72
+ gqlType: 'UUID',
73
+ isArray: false,
74
+ modifier: null,
75
+ pgAlias: null,
76
+ pgType: null,
77
+ subtype: null,
78
+ typmod: null,
79
+ },
80
+ },
81
+ })),
82
+ })),
83
+ };
84
+ }
85
+ /**
86
+ * Generate basic IntrospectionSchema from CleanTable array
87
+ * This creates a minimal schema for AST generation
88
+ */
89
+ export function generateIntrospectionSchema(tables) {
90
+ const schema = {};
91
+ for (const table of tables) {
92
+ const modelName = table.name;
93
+ const pluralName = toCamelCasePlural(modelName);
94
+ // Basic field selection for the model
95
+ const selection = table.fields.map((field) => field.name);
96
+ // Add getMany query
97
+ schema[pluralName] = {
98
+ qtype: 'getMany',
99
+ model: modelName,
100
+ selection,
101
+ properties: convertFieldsToProperties(table.fields),
102
+ };
103
+ // Add getOne query (by ID)
104
+ const singularName = inflection.camelize(modelName, true);
105
+ schema[singularName] = {
106
+ qtype: 'getOne',
107
+ model: modelName,
108
+ selection,
109
+ properties: convertFieldsToProperties(table.fields),
110
+ };
111
+ // Add create mutation
112
+ schema[`create${modelName}`] = {
113
+ qtype: 'mutation',
114
+ mutationType: 'create',
115
+ model: modelName,
116
+ selection,
117
+ properties: {
118
+ input: {
119
+ name: 'input',
120
+ type: `Create${modelName}Input`,
121
+ isNotNull: true,
122
+ isArray: false,
123
+ isArrayNotNull: false,
124
+ properties: {
125
+ [inflection.camelize(modelName, true)]: {
126
+ name: inflection.camelize(modelName, true),
127
+ type: `${modelName}Input`,
128
+ isNotNull: true,
129
+ isArray: false,
130
+ isArrayNotNull: false,
131
+ properties: convertFieldsToNestedProperties(table.fields),
132
+ },
133
+ },
134
+ },
135
+ },
136
+ };
137
+ // Add update mutation
138
+ schema[`update${modelName}`] = {
139
+ qtype: 'mutation',
140
+ mutationType: 'patch',
141
+ model: modelName,
142
+ selection,
143
+ properties: {
144
+ input: {
145
+ name: 'input',
146
+ type: `Update${modelName}Input`,
147
+ isNotNull: true,
148
+ isArray: false,
149
+ isArrayNotNull: false,
150
+ properties: {
151
+ patch: {
152
+ name: 'patch',
153
+ type: `${modelName}Patch`,
154
+ isNotNull: true,
155
+ isArray: false,
156
+ isArrayNotNull: false,
157
+ properties: convertFieldsToNestedProperties(table.fields),
158
+ },
159
+ },
160
+ },
161
+ },
162
+ };
163
+ // Add delete mutation
164
+ schema[`delete${modelName}`] = {
165
+ qtype: 'mutation',
166
+ mutationType: 'delete',
167
+ model: modelName,
168
+ selection,
169
+ properties: {
170
+ input: {
171
+ name: 'input',
172
+ type: `Delete${modelName}Input`,
173
+ isNotNull: true,
174
+ isArray: false,
175
+ isArrayNotNull: false,
176
+ properties: {
177
+ id: {
178
+ name: 'id',
179
+ type: 'UUID',
180
+ isNotNull: true,
181
+ isArray: false,
182
+ isArrayNotNull: false,
183
+ },
184
+ },
185
+ },
186
+ },
187
+ };
188
+ }
189
+ return schema;
190
+ }
191
+ /**
192
+ * Convert CleanTable fields to QueryBuilder properties
193
+ */
194
+ function convertFieldsToProperties(fields) {
195
+ const properties = {};
196
+ fields.forEach((field) => {
197
+ properties[field.name] = {
198
+ name: field.name,
199
+ type: field.type.gqlType,
200
+ isNotNull: !field.type.gqlType.endsWith('!'),
201
+ isArray: field.type.isArray,
202
+ isArrayNotNull: false,
203
+ };
204
+ });
205
+ return properties;
206
+ }
207
+ /**
208
+ * Convert fields to nested properties for mutations
209
+ */
210
+ function convertFieldsToNestedProperties(fields) {
211
+ const properties = {};
212
+ fields.forEach((field) => {
213
+ properties[field.name] = {
214
+ name: field.name,
215
+ type: field.type.gqlType,
216
+ isNotNull: false, // Mutations typically allow optional fields
217
+ isArray: field.type.isArray,
218
+ isArrayNotNull: false,
219
+ };
220
+ });
221
+ return properties;
222
+ }
223
+ /**
224
+ * Create AST-based query builder for a table
225
+ */
226
+ export function createASTQueryBuilder(tables) {
227
+ const metaObject = cleanTableToMetaObject(tables);
228
+ const introspectionSchema = generateIntrospectionSchema(tables);
229
+ return new QueryBuilder({
230
+ meta: metaObject,
231
+ introspection: introspectionSchema,
232
+ });
233
+ }
234
+ /**
235
+ * Build a SELECT query for a table with optional filtering, sorting, and pagination
236
+ * Uses direct AST generation without intermediate conversions
237
+ */
238
+ export function buildSelect(table, allTables, options = {}) {
239
+ const tableList = Array.from(allTables);
240
+ const selection = convertFieldSelectionToSelectionOptions(table, tableList, options.fieldSelection);
241
+ // Generate query directly using AST
242
+ const queryString = generateSelectQueryAST(table, tableList, selection, options);
243
+ return new TypedDocumentString(queryString, {});
244
+ }
245
+ /**
246
+ * Build a single row query by primary key or unique field
247
+ */
248
+ export function buildFindOne(table, _pkField = 'id') {
249
+ const queryString = generateFindOneQueryAST(table);
250
+ return new TypedDocumentString(queryString, {});
251
+ }
252
+ /**
253
+ * Build a count query for a table
254
+ */
255
+ export function buildCount(table) {
256
+ const queryString = generateCountQueryAST(table);
257
+ return new TypedDocumentString(queryString, {});
258
+ }
259
+ function convertFieldSelectionToSelectionOptions(table, allTables, options) {
260
+ return convertToSelectionOptions(table, allTables, options);
261
+ }
262
+ /**
263
+ * Generate SELECT query AST directly from CleanTable
264
+ */
265
+ function generateSelectQueryAST(table, allTables, selection, options) {
266
+ const pluralName = toCamelCasePlural(table.name);
267
+ // Generate field selections
268
+ const fieldSelections = generateFieldSelectionsFromOptions(table, allTables, selection);
269
+ // Build the query AST
270
+ const variableDefinitions = [];
271
+ const queryArgs = [];
272
+ // Add pagination variables if needed
273
+ const limitValue = options.limit ?? options.first;
274
+ if (limitValue !== undefined) {
275
+ variableDefinitions.push(t.variableDefinition({
276
+ variable: t.variable({ name: 'first' }),
277
+ type: t.namedType({ type: 'Int' }),
278
+ }));
279
+ queryArgs.push(t.argument({
280
+ name: 'first',
281
+ value: t.variable({ name: 'first' }),
282
+ }));
283
+ }
284
+ if (options.offset !== undefined) {
285
+ variableDefinitions.push(t.variableDefinition({
286
+ variable: t.variable({ name: 'offset' }),
287
+ type: t.namedType({ type: 'Int' }),
288
+ }));
289
+ queryArgs.push(t.argument({
290
+ name: 'offset',
291
+ value: t.variable({ name: 'offset' }),
292
+ }));
293
+ }
294
+ // Add cursor-based pagination variables if needed (for infinite scroll)
295
+ if (options.after !== undefined) {
296
+ variableDefinitions.push(t.variableDefinition({
297
+ variable: t.variable({ name: 'after' }),
298
+ type: t.namedType({ type: 'Cursor' }),
299
+ }));
300
+ queryArgs.push(t.argument({
301
+ name: 'after',
302
+ value: t.variable({ name: 'after' }),
303
+ }));
304
+ }
305
+ if (options.before !== undefined) {
306
+ variableDefinitions.push(t.variableDefinition({
307
+ variable: t.variable({ name: 'before' }),
308
+ type: t.namedType({ type: 'Cursor' }),
309
+ }));
310
+ queryArgs.push(t.argument({
311
+ name: 'before',
312
+ value: t.variable({ name: 'before' }),
313
+ }));
314
+ }
315
+ // Add filter variables if needed
316
+ if (options.where) {
317
+ variableDefinitions.push(t.variableDefinition({
318
+ variable: t.variable({ name: 'filter' }),
319
+ type: t.namedType({ type: `${table.name}Filter` }),
320
+ }));
321
+ queryArgs.push(t.argument({
322
+ name: 'filter',
323
+ value: t.variable({ name: 'filter' }),
324
+ }));
325
+ }
326
+ // Add orderBy variables if needed
327
+ if (options.orderBy && options.orderBy.length > 0) {
328
+ variableDefinitions.push(t.variableDefinition({
329
+ variable: t.variable({ name: 'orderBy' }),
330
+ // PostGraphile expects [ProductsOrderBy!] - list of non-null enum values
331
+ type: t.listType({
332
+ type: t.nonNullType({
333
+ type: t.namedType({ type: toOrderByTypeName(table.name) }),
334
+ }),
335
+ }),
336
+ }));
337
+ queryArgs.push(t.argument({
338
+ name: 'orderBy',
339
+ value: t.variable({ name: 'orderBy' }),
340
+ }));
341
+ }
342
+ // Build connection selections: totalCount, nodes, and optionally pageInfo
343
+ const connectionSelections = [
344
+ t.field({ name: 'totalCount' }),
345
+ t.field({
346
+ name: 'nodes',
347
+ selectionSet: t.selectionSet({
348
+ selections: fieldSelections,
349
+ }),
350
+ }),
351
+ ];
352
+ // Add pageInfo if requested (for cursor-based pagination / infinite scroll)
353
+ if (options.includePageInfo ||
354
+ options.after !== undefined ||
355
+ options.before !== undefined) {
356
+ connectionSelections.push(t.field({
357
+ name: 'pageInfo',
358
+ selectionSet: t.selectionSet({
359
+ selections: [
360
+ t.field({ name: 'hasNextPage' }),
361
+ t.field({ name: 'hasPreviousPage' }),
362
+ t.field({ name: 'startCursor' }),
363
+ t.field({ name: 'endCursor' }),
364
+ ],
365
+ }),
366
+ }));
367
+ }
368
+ const ast = t.document({
369
+ definitions: [
370
+ t.operationDefinition({
371
+ operation: 'query',
372
+ name: `${pluralName}Query`,
373
+ variableDefinitions,
374
+ selectionSet: t.selectionSet({
375
+ selections: [
376
+ t.field({
377
+ name: pluralName,
378
+ args: queryArgs,
379
+ selectionSet: t.selectionSet({
380
+ selections: connectionSelections,
381
+ }),
382
+ }),
383
+ ],
384
+ }),
385
+ }),
386
+ ],
387
+ });
388
+ return print(ast);
389
+ }
390
+ /**
391
+ * Generate field selections from SelectionOptions
392
+ */
393
+ function generateFieldSelectionsFromOptions(table, allTables, selection) {
394
+ const DEFAULT_NESTED_RELATION_FIRST = 20;
395
+ if (!selection) {
396
+ // Default to all non-relational fields (includes complex fields like JSON, geometry, etc.)
397
+ return table.fields
398
+ .filter((field) => !isRelationalField(field.name, table))
399
+ .map((field) => {
400
+ if (requiresSubfieldSelection(field)) {
401
+ // For complex fields that require subfield selection, use custom AST generation
402
+ return getCustomAstForCleanField(field);
403
+ }
404
+ else {
405
+ // For simple fields, use basic field selection
406
+ return t.field({ name: field.name });
407
+ }
408
+ });
409
+ }
410
+ const fieldSelections = [];
411
+ Object.entries(selection).forEach(([fieldName, fieldOptions]) => {
412
+ if (fieldOptions === true) {
413
+ // Check if this field requires subfield selection
414
+ const field = table.fields.find((f) => f.name === fieldName);
415
+ if (field && requiresSubfieldSelection(field)) {
416
+ // Use custom AST generation for complex fields
417
+ fieldSelections.push(getCustomAstForCleanField(field));
418
+ }
419
+ else {
420
+ // Simple field selection for scalar fields
421
+ fieldSelections.push(t.field({ name: fieldName }));
422
+ }
423
+ }
424
+ else if (typeof fieldOptions === 'object' && fieldOptions.select) {
425
+ // Nested field selection (for relation fields)
426
+ const nestedSelections = [];
427
+ // Find the related table to check for complex fields
428
+ const relatedTable = findRelatedTable(fieldName, table, allTables);
429
+ Object.entries(fieldOptions.select).forEach(([nestedField, include]) => {
430
+ if (include) {
431
+ // Check if this nested field requires subfield selection
432
+ const nestedFieldDef = relatedTable?.fields.find((f) => f.name === nestedField);
433
+ if (nestedFieldDef && requiresSubfieldSelection(nestedFieldDef)) {
434
+ // Use custom AST generation for complex nested fields
435
+ nestedSelections.push(getCustomAstForCleanField(nestedFieldDef));
436
+ }
437
+ else {
438
+ // Simple field selection for scalar nested fields
439
+ nestedSelections.push(t.field({ name: nestedField }));
440
+ }
441
+ }
442
+ });
443
+ // Check if this is a hasMany relation that uses Connection pattern
444
+ const relationInfo = getRelationInfo(fieldName, table);
445
+ if (relationInfo &&
446
+ (relationInfo.type === 'hasMany' || relationInfo.type === 'manyToMany')) {
447
+ // For hasMany/manyToMany relations, wrap selections in nodes { ... }
448
+ fieldSelections.push(t.field({
449
+ name: fieldName,
450
+ args: [
451
+ t.argument({
452
+ name: 'first',
453
+ value: t.intValue({
454
+ value: DEFAULT_NESTED_RELATION_FIRST.toString(),
455
+ }),
456
+ }),
457
+ ],
458
+ selectionSet: t.selectionSet({
459
+ selections: [
460
+ t.field({
461
+ name: 'nodes',
462
+ selectionSet: t.selectionSet({
463
+ selections: nestedSelections,
464
+ }),
465
+ }),
466
+ ],
467
+ }),
468
+ }));
469
+ }
470
+ else {
471
+ // For belongsTo/hasOne relations, use direct selection
472
+ fieldSelections.push(t.field({
473
+ name: fieldName,
474
+ selectionSet: t.selectionSet({
475
+ selections: nestedSelections,
476
+ }),
477
+ }));
478
+ }
479
+ }
480
+ });
481
+ return fieldSelections;
482
+ }
483
+ /**
484
+ * Get relation information for a field
485
+ */
486
+ function getRelationInfo(fieldName, table) {
487
+ const { belongsTo, hasOne, hasMany, manyToMany } = table.relations;
488
+ // Check belongsTo relations
489
+ const belongsToRel = belongsTo.find((rel) => rel.fieldName === fieldName);
490
+ if (belongsToRel) {
491
+ return { type: 'belongsTo', relation: belongsToRel };
492
+ }
493
+ // Check hasOne relations
494
+ const hasOneRel = hasOne.find((rel) => rel.fieldName === fieldName);
495
+ if (hasOneRel) {
496
+ return { type: 'hasOne', relation: hasOneRel };
497
+ }
498
+ // Check hasMany relations
499
+ const hasManyRel = hasMany.find((rel) => rel.fieldName === fieldName);
500
+ if (hasManyRel) {
501
+ return { type: 'hasMany', relation: hasManyRel };
502
+ }
503
+ // Check manyToMany relations
504
+ const manyToManyRel = manyToMany.find((rel) => rel.fieldName === fieldName);
505
+ if (manyToManyRel) {
506
+ return { type: 'manyToMany', relation: manyToManyRel };
507
+ }
508
+ return null;
509
+ }
510
+ /**
511
+ * Find the related table for a given relation field
512
+ */
513
+ function findRelatedTable(relationField, table, allTables) {
514
+ // Find the related table name
515
+ let referencedTableName;
516
+ // Check belongsTo relations
517
+ const belongsToRel = table.relations.belongsTo.find((rel) => rel.fieldName === relationField);
518
+ if (belongsToRel) {
519
+ referencedTableName = belongsToRel.referencesTable;
520
+ }
521
+ // Check hasOne relations
522
+ if (!referencedTableName) {
523
+ const hasOneRel = table.relations.hasOne.find((rel) => rel.fieldName === relationField);
524
+ if (hasOneRel) {
525
+ referencedTableName = hasOneRel.referencedByTable;
526
+ }
527
+ }
528
+ // Check hasMany relations
529
+ if (!referencedTableName) {
530
+ const hasManyRel = table.relations.hasMany.find((rel) => rel.fieldName === relationField);
531
+ if (hasManyRel) {
532
+ referencedTableName = hasManyRel.referencedByTable;
533
+ }
534
+ }
535
+ // Check manyToMany relations
536
+ if (!referencedTableName) {
537
+ const manyToManyRel = table.relations.manyToMany.find((rel) => rel.fieldName === relationField);
538
+ if (manyToManyRel) {
539
+ referencedTableName = manyToManyRel.rightTable;
540
+ }
541
+ }
542
+ if (!referencedTableName) {
543
+ return null;
544
+ }
545
+ // Find the related table in allTables
546
+ return allTables.find((tbl) => tbl.name === referencedTableName) || null;
547
+ }
548
+ /**
549
+ * Generate FindOne query AST directly from CleanTable
550
+ */
551
+ function generateFindOneQueryAST(table) {
552
+ const singularName = inflection.camelize(table.name, true);
553
+ // Generate field selections (include all non-relational fields, including complex types)
554
+ const fieldSelections = table.fields
555
+ .filter((field) => !isRelationalField(field.name, table))
556
+ .map((field) => {
557
+ if (requiresSubfieldSelection(field)) {
558
+ // For complex fields that require subfield selection, use custom AST generation
559
+ return getCustomAstForCleanField(field);
560
+ }
561
+ else {
562
+ // For simple fields, use basic field selection
563
+ return t.field({ name: field.name });
564
+ }
565
+ });
566
+ const ast = t.document({
567
+ definitions: [
568
+ t.operationDefinition({
569
+ operation: 'query',
570
+ name: `${singularName}Query`,
571
+ variableDefinitions: [
572
+ t.variableDefinition({
573
+ variable: t.variable({ name: 'id' }),
574
+ type: t.nonNullType({
575
+ type: t.namedType({ type: 'UUID' }),
576
+ }),
577
+ }),
578
+ ],
579
+ selectionSet: t.selectionSet({
580
+ selections: [
581
+ t.field({
582
+ name: singularName,
583
+ args: [
584
+ t.argument({
585
+ name: 'id',
586
+ value: t.variable({ name: 'id' }),
587
+ }),
588
+ ],
589
+ selectionSet: t.selectionSet({
590
+ selections: fieldSelections,
591
+ }),
592
+ }),
593
+ ],
594
+ }),
595
+ }),
596
+ ],
597
+ });
598
+ return print(ast);
599
+ }
600
+ /**
601
+ * Generate Count query AST directly from CleanTable
602
+ */
603
+ function generateCountQueryAST(table) {
604
+ const pluralName = toCamelCasePlural(table.name);
605
+ const ast = t.document({
606
+ definitions: [
607
+ t.operationDefinition({
608
+ operation: 'query',
609
+ name: `${pluralName}CountQuery`,
610
+ variableDefinitions: [
611
+ t.variableDefinition({
612
+ variable: t.variable({ name: 'filter' }),
613
+ type: t.namedType({ type: `${table.name}Filter` }),
614
+ }),
615
+ ],
616
+ selectionSet: t.selectionSet({
617
+ selections: [
618
+ t.field({
619
+ name: pluralName,
620
+ args: [
621
+ t.argument({
622
+ name: 'filter',
623
+ value: t.variable({ name: 'filter' }),
624
+ }),
625
+ ],
626
+ selectionSet: t.selectionSet({
627
+ selections: [t.field({ name: 'totalCount' })],
628
+ }),
629
+ }),
630
+ ],
631
+ }),
632
+ }),
633
+ ],
634
+ });
635
+ return print(ast);
636
+ }
package/esm/index.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @constructive-io/graphql-codegen
3
+ *
4
+ * CLI-based GraphQL SDK generator for PostGraphile endpoints.
5
+ * Introspects via _meta query and generates typed queries, mutations,
6
+ * and React Query v5 hooks.
7
+ */
8
+ export * from './types';
9
+ export * from './core';
10
+ export * from './generators';
11
+ export * from './client';
12
+ export { defineConfig } from './types/config';
package/esm/index.js CHANGED
@@ -1,3 +1,17 @@
1
- export * from './gql';
2
- export * from './codegen';
3
- export * from './options';
1
+ /**
2
+ * @constructive-io/graphql-codegen
3
+ *
4
+ * CLI-based GraphQL SDK generator for PostGraphile endpoints.
5
+ * Introspects via _meta query and generates typed queries, mutations,
6
+ * and React Query v5 hooks.
7
+ */
8
+ // Core types
9
+ export * from './types';
10
+ // Core query building
11
+ export * from './core';
12
+ // Generators
13
+ export * from './generators';
14
+ // Client utilities
15
+ export * from './client';
16
+ // Config definition helper
17
+ export { defineConfig } from './types/config';
@@ -0,0 +1,5 @@
1
+ /**
2
+ * React integration exports
3
+ * Will be populated in Phase 8
4
+ */
5
+ export declare const REACT_VERSION = "0.1.0";
@@ -0,0 +1,6 @@
1
+ /**
2
+ * React integration exports
3
+ * Will be populated in Phase 8
4
+ */
5
+ // Placeholder exports - will be implemented
6
+ export const REACT_VERSION = '0.1.0';