@constructive-io/graphql-codegen 2.19.0 → 2.20.1

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,646 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateOrmClientFile = generateOrmClientFile;
4
+ exports.generateQueryBuilderFile = generateQueryBuilderFile;
5
+ exports.generateSelectTypesFile = generateSelectTypesFile;
6
+ exports.generateCreateClientFile = generateCreateClientFile;
7
+ const ts_ast_1 = require("../ts-ast");
8
+ const utils_1 = require("../utils");
9
+ /**
10
+ * Generate the main client.ts file (OrmClient class)
11
+ * This is the runtime client that handles GraphQL execution
12
+ */
13
+ function generateOrmClientFile() {
14
+ // This is runtime code that doesn't change based on schema
15
+ // We generate it as a static file
16
+ const content = `/**
17
+ * ORM Client - Runtime GraphQL executor
18
+ * @generated by @constructive-io/graphql-codegen
19
+ * DO NOT EDIT - changes will be overwritten
20
+ */
21
+
22
+ export interface OrmClientConfig {
23
+ endpoint: string;
24
+ headers?: Record<string, string>;
25
+ }
26
+
27
+ export interface GraphQLError {
28
+ message: string;
29
+ locations?: { line: number; column: number }[];
30
+ path?: (string | number)[];
31
+ extensions?: Record<string, unknown>;
32
+ }
33
+
34
+ /**
35
+ * Error thrown when GraphQL request fails
36
+ */
37
+ export class GraphQLRequestError extends Error {
38
+ constructor(
39
+ public readonly errors: GraphQLError[],
40
+ public readonly data: unknown = null
41
+ ) {
42
+ const messages = errors.map(e => e.message).join('; ');
43
+ super(\`GraphQL Error: \${messages}\`);
44
+ this.name = 'GraphQLRequestError';
45
+ }
46
+ }
47
+
48
+ /**
49
+ * Discriminated union for query results
50
+ * Use .ok to check success, or use .unwrap() to get data or throw
51
+ */
52
+ export type QueryResult<T> =
53
+ | { ok: true; data: T; errors: undefined }
54
+ | { ok: false; data: null; errors: GraphQLError[] };
55
+
56
+ /**
57
+ * Legacy QueryResult type for backwards compatibility
58
+ * @deprecated Use QueryResult discriminated union instead
59
+ */
60
+ export interface LegacyQueryResult<T> {
61
+ data: T | null;
62
+ errors?: GraphQLError[];
63
+ }
64
+
65
+ export class OrmClient {
66
+ private endpoint: string;
67
+ private headers: Record<string, string>;
68
+
69
+ constructor(config: OrmClientConfig) {
70
+ this.endpoint = config.endpoint;
71
+ this.headers = config.headers ?? {};
72
+ }
73
+
74
+ async execute<T>(
75
+ document: string,
76
+ variables?: Record<string, unknown>
77
+ ): Promise<QueryResult<T>> {
78
+ const response = await fetch(this.endpoint, {
79
+ method: 'POST',
80
+ headers: {
81
+ 'Content-Type': 'application/json',
82
+ Accept: 'application/json',
83
+ ...this.headers,
84
+ },
85
+ body: JSON.stringify({
86
+ query: document,
87
+ variables: variables ?? {},
88
+ }),
89
+ });
90
+
91
+ if (!response.ok) {
92
+ return {
93
+ ok: false,
94
+ data: null,
95
+ errors: [{ message: \`HTTP \${response.status}: \${response.statusText}\` }],
96
+ };
97
+ }
98
+
99
+ const json = (await response.json()) as {
100
+ data?: T;
101
+ errors?: GraphQLError[];
102
+ };
103
+
104
+ // Return discriminated union based on presence of errors
105
+ if (json.errors && json.errors.length > 0) {
106
+ return {
107
+ ok: false,
108
+ data: null,
109
+ errors: json.errors,
110
+ };
111
+ }
112
+
113
+ return {
114
+ ok: true,
115
+ data: json.data as T,
116
+ errors: undefined,
117
+ };
118
+ }
119
+
120
+ setHeaders(headers: Record<string, string>): void {
121
+ this.headers = { ...this.headers, ...headers };
122
+ }
123
+
124
+ getEndpoint(): string {
125
+ return this.endpoint;
126
+ }
127
+ }
128
+ `;
129
+ return {
130
+ fileName: 'client.ts',
131
+ content,
132
+ };
133
+ }
134
+ /**
135
+ * Generate the query-builder.ts file (runtime query builder)
136
+ */
137
+ function generateQueryBuilderFile() {
138
+ const content = `/**
139
+ * Query Builder - Builds and executes GraphQL operations
140
+ * @generated by @constructive-io/graphql-codegen
141
+ * DO NOT EDIT - changes will be overwritten
142
+ */
143
+
144
+ import { OrmClient, QueryResult, GraphQLRequestError } from './client';
145
+
146
+ export interface QueryBuilderConfig {
147
+ client: OrmClient;
148
+ operation: 'query' | 'mutation';
149
+ operationName: string;
150
+ fieldName: string;
151
+ document: string;
152
+ variables?: Record<string, unknown>;
153
+ }
154
+
155
+ export class QueryBuilder<TResult> {
156
+ private config: QueryBuilderConfig;
157
+
158
+ constructor(config: QueryBuilderConfig) {
159
+ this.config = config;
160
+ }
161
+
162
+ /**
163
+ * Execute the query and return a discriminated union result
164
+ * Use result.ok to check success, or .unwrap() to throw on error
165
+ */
166
+ async execute(): Promise<QueryResult<TResult>> {
167
+ return this.config.client.execute<TResult>(
168
+ this.config.document,
169
+ this.config.variables
170
+ );
171
+ }
172
+
173
+ /**
174
+ * Execute and unwrap the result, throwing GraphQLRequestError on failure
175
+ * @throws {GraphQLRequestError} If the query returns errors
176
+ */
177
+ async unwrap(): Promise<TResult> {
178
+ const result = await this.execute();
179
+ if (!result.ok) {
180
+ throw new GraphQLRequestError(result.errors, result.data);
181
+ }
182
+ return result.data;
183
+ }
184
+
185
+ /**
186
+ * Execute and unwrap, returning defaultValue on error instead of throwing
187
+ */
188
+ async unwrapOr<D>(defaultValue: D): Promise<TResult | D> {
189
+ const result = await this.execute();
190
+ if (!result.ok) {
191
+ return defaultValue;
192
+ }
193
+ return result.data;
194
+ }
195
+
196
+ /**
197
+ * Execute and unwrap, calling onError callback on failure
198
+ */
199
+ async unwrapOrElse<D>(onError: (errors: import('./client').GraphQLError[]) => D): Promise<TResult | D> {
200
+ const result = await this.execute();
201
+ if (!result.ok) {
202
+ return onError(result.errors);
203
+ }
204
+ return result.data;
205
+ }
206
+
207
+ toGraphQL(): string {
208
+ return this.config.document;
209
+ }
210
+
211
+ getVariables(): Record<string, unknown> | undefined {
212
+ return this.config.variables;
213
+ }
214
+ }
215
+
216
+ // ============================================================================
217
+ // Document Builders
218
+ // ============================================================================
219
+
220
+ export function buildSelections<T>(select: T): string {
221
+ if (!select) return '';
222
+
223
+ const fields: string[] = [];
224
+
225
+ for (const [key, value] of Object.entries(select)) {
226
+ if (value === false || value === undefined) continue;
227
+
228
+ if (value === true) {
229
+ fields.push(key);
230
+ continue;
231
+ }
232
+
233
+ if (typeof value === 'object' && value !== null) {
234
+ const nested = value as {
235
+ select?: Record<string, unknown>;
236
+ first?: number;
237
+ filter?: Record<string, unknown>;
238
+ orderBy?: string[];
239
+ // New: connection flag to differentiate connection types from regular objects
240
+ connection?: boolean;
241
+ };
242
+
243
+ if (nested.select) {
244
+ const nestedSelections = buildSelections(nested.select);
245
+
246
+ // Check if this is a connection type (has pagination args or explicit connection flag)
247
+ const isConnection = nested.connection === true || nested.first !== undefined || nested.filter !== undefined;
248
+
249
+ if (isConnection) {
250
+ // Connection type - wrap in nodes/totalCount/pageInfo
251
+ const args: string[] = [];
252
+ if (nested.first !== undefined) args.push(\`first: \${nested.first}\`);
253
+ if (nested.orderBy?.length) args.push(\`orderBy: [\${nested.orderBy.join(', ')}]\`);
254
+ const argsStr = args.length > 0 ? \`(\${args.join(', ')})\` : '';
255
+
256
+ fields.push(\`\${key}\${argsStr} {
257
+ nodes { \${nestedSelections} }
258
+ totalCount
259
+ pageInfo { hasNextPage hasPreviousPage startCursor endCursor }
260
+ }\`);
261
+ } else {
262
+ // Regular nested object - just wrap in braces
263
+ fields.push(\`\${key} { \${nestedSelections} }\`);
264
+ }
265
+ }
266
+ }
267
+ }
268
+
269
+ return fields.join('\\n ');
270
+ }
271
+
272
+ export function buildFindManyDocument<TSelect, TWhere>(
273
+ operationName: string,
274
+ queryField: string,
275
+ select: TSelect,
276
+ args: {
277
+ where?: TWhere;
278
+ orderBy?: string[];
279
+ first?: number;
280
+ last?: number;
281
+ after?: string;
282
+ before?: string;
283
+ offset?: number;
284
+ },
285
+ filterTypeName: string
286
+ ): { document: string; variables: Record<string, unknown> } {
287
+ const selections = select ? buildSelections(select) : 'id';
288
+
289
+ const varDefs: string[] = [];
290
+ const queryArgs: string[] = [];
291
+ const variables: Record<string, unknown> = {};
292
+
293
+ if (args.where) {
294
+ varDefs.push(\`$where: \${filterTypeName}\`);
295
+ queryArgs.push('filter: $where');
296
+ variables.where = args.where;
297
+ }
298
+ if (args.orderBy?.length) {
299
+ varDefs.push(\`$orderBy: [\${operationName}sOrderBy!]\`);
300
+ queryArgs.push('orderBy: $orderBy');
301
+ variables.orderBy = args.orderBy;
302
+ }
303
+ if (args.first !== undefined) {
304
+ varDefs.push('$first: Int');
305
+ queryArgs.push('first: $first');
306
+ variables.first = args.first;
307
+ }
308
+ if (args.last !== undefined) {
309
+ varDefs.push('$last: Int');
310
+ queryArgs.push('last: $last');
311
+ variables.last = args.last;
312
+ }
313
+ if (args.after) {
314
+ varDefs.push('$after: Cursor');
315
+ queryArgs.push('after: $after');
316
+ variables.after = args.after;
317
+ }
318
+ if (args.before) {
319
+ varDefs.push('$before: Cursor');
320
+ queryArgs.push('before: $before');
321
+ variables.before = args.before;
322
+ }
323
+ if (args.offset !== undefined) {
324
+ varDefs.push('$offset: Int');
325
+ queryArgs.push('offset: $offset');
326
+ variables.offset = args.offset;
327
+ }
328
+
329
+ const varDefsStr = varDefs.length > 0 ? \`(\${varDefs.join(', ')})\` : '';
330
+ const queryArgsStr = queryArgs.length > 0 ? \`(\${queryArgs.join(', ')})\` : '';
331
+
332
+ const document = \`query \${operationName}Query\${varDefsStr} {
333
+ \${queryField}\${queryArgsStr} {
334
+ nodes { \${selections} }
335
+ totalCount
336
+ pageInfo { hasNextPage hasPreviousPage startCursor endCursor }
337
+ }
338
+ }\`;
339
+
340
+ return { document, variables };
341
+ }
342
+
343
+ export function buildFindFirstDocument<TSelect, TWhere>(
344
+ operationName: string,
345
+ queryField: string,
346
+ select: TSelect,
347
+ args: { where?: TWhere },
348
+ filterTypeName: string
349
+ ): { document: string; variables: Record<string, unknown> } {
350
+ const selections = select ? buildSelections(select) : 'id';
351
+
352
+ const varDefs: string[] = ['$first: Int'];
353
+ const queryArgs: string[] = ['first: $first'];
354
+ const variables: Record<string, unknown> = { first: 1 };
355
+
356
+ if (args.where) {
357
+ varDefs.push(\`$where: \${filterTypeName}\`);
358
+ queryArgs.push('filter: $where');
359
+ variables.where = args.where;
360
+ }
361
+
362
+ const document = \`query \${operationName}Query(\${varDefs.join(', ')}) {
363
+ \${queryField}(\${queryArgs.join(', ')}) {
364
+ nodes { \${selections} }
365
+ }
366
+ }\`;
367
+
368
+ return { document, variables };
369
+ }
370
+
371
+ export function buildCreateDocument<TSelect, TData>(
372
+ operationName: string,
373
+ mutationField: string,
374
+ entityField: string,
375
+ select: TSelect,
376
+ data: TData,
377
+ inputTypeName: string
378
+ ): { document: string; variables: Record<string, unknown> } {
379
+ const selections = select ? buildSelections(select) : 'id';
380
+
381
+ const document = \`mutation \${operationName}Mutation($input: \${inputTypeName}!) {
382
+ \${mutationField}(input: $input) {
383
+ \${entityField} { \${selections} }
384
+ }
385
+ }\`;
386
+
387
+ return {
388
+ document,
389
+ variables: { input: { [entityField]: data } },
390
+ };
391
+ }
392
+
393
+ export function buildUpdateDocument<TSelect, TWhere extends { id: string }, TData>(
394
+ operationName: string,
395
+ mutationField: string,
396
+ entityField: string,
397
+ select: TSelect,
398
+ where: TWhere,
399
+ data: TData,
400
+ inputTypeName: string
401
+ ): { document: string; variables: Record<string, unknown> } {
402
+ const selections = select ? buildSelections(select) : 'id';
403
+
404
+ const document = \`mutation \${operationName}Mutation($input: \${inputTypeName}!) {
405
+ \${mutationField}(input: $input) {
406
+ \${entityField} { \${selections} }
407
+ }
408
+ }\`;
409
+
410
+ return {
411
+ document,
412
+ variables: { input: { id: where.id, patch: data } },
413
+ };
414
+ }
415
+
416
+ export function buildDeleteDocument<TWhere extends { id: string }>(
417
+ operationName: string,
418
+ mutationField: string,
419
+ entityField: string,
420
+ where: TWhere,
421
+ inputTypeName: string
422
+ ): { document: string; variables: Record<string, unknown> } {
423
+ const document = \`mutation \${operationName}Mutation($input: \${inputTypeName}!) {
424
+ \${mutationField}(input: $input) {
425
+ \${entityField} { id }
426
+ }
427
+ }\`;
428
+
429
+ return {
430
+ document,
431
+ variables: { input: { id: where.id } },
432
+ };
433
+ }
434
+
435
+ export function buildCustomDocument<TSelect, TArgs>(
436
+ operationType: 'query' | 'mutation',
437
+ operationName: string,
438
+ fieldName: string,
439
+ select: TSelect,
440
+ args: TArgs,
441
+ variableDefinitions: Array<{ name: string; type: string }>
442
+ ): { document: string; variables: Record<string, unknown> } {
443
+ const selections = select ? buildSelections(select) : '';
444
+
445
+ const varDefs = variableDefinitions.map(v => \`$\${v.name}: \${v.type}\`);
446
+ const fieldArgs = variableDefinitions.map(v => \`\${v.name}: $\${v.name}\`);
447
+
448
+ const varDefsStr = varDefs.length > 0 ? \`(\${varDefs.join(', ')})\` : '';
449
+ const fieldArgsStr = fieldArgs.length > 0 ? \`(\${fieldArgs.join(', ')})\` : '';
450
+ const selectionsBlock = selections ? \` { \${selections} }\` : '';
451
+
452
+ const opType = operationType === 'query' ? 'query' : 'mutation';
453
+ const document = \`\${opType} \${operationName}\${varDefsStr} {
454
+ \${fieldName}\${fieldArgsStr}\${selectionsBlock}
455
+ }\`;
456
+
457
+ return { document, variables: (args ?? {}) as Record<string, unknown> };
458
+ }
459
+ `;
460
+ return {
461
+ fileName: 'query-builder.ts',
462
+ content,
463
+ };
464
+ }
465
+ /**
466
+ * Generate the select-types.ts file
467
+ */
468
+ function generateSelectTypesFile() {
469
+ const content = `/**
470
+ * Type utilities for select inference
471
+ * @generated by @constructive-io/graphql-codegen
472
+ * DO NOT EDIT - changes will be overwritten
473
+ */
474
+
475
+ export interface ConnectionResult<T> {
476
+ nodes: T[];
477
+ totalCount: number;
478
+ pageInfo: PageInfo;
479
+ }
480
+
481
+ export interface PageInfo {
482
+ hasNextPage: boolean;
483
+ hasPreviousPage: boolean;
484
+ startCursor?: string | null;
485
+ endCursor?: string | null;
486
+ }
487
+
488
+ export interface FindManyArgs<TSelect, TWhere, TOrderBy> {
489
+ select?: TSelect;
490
+ where?: TWhere;
491
+ orderBy?: TOrderBy[];
492
+ first?: number;
493
+ last?: number;
494
+ after?: string;
495
+ before?: string;
496
+ offset?: number;
497
+ }
498
+
499
+ export interface FindFirstArgs<TSelect, TWhere> {
500
+ select?: TSelect;
501
+ where?: TWhere;
502
+ }
503
+
504
+ export interface CreateArgs<TSelect, TData> {
505
+ data: TData;
506
+ select?: TSelect;
507
+ }
508
+
509
+ export interface UpdateArgs<TSelect, TWhere, TData> {
510
+ where: TWhere;
511
+ data: TData;
512
+ select?: TSelect;
513
+ }
514
+
515
+ export interface DeleteArgs<TWhere> {
516
+ where: TWhere;
517
+ }
518
+
519
+ /**
520
+ * Infer result type from select configuration
521
+ */
522
+ export type InferSelectResult<TEntity, TSelect> = TSelect extends undefined
523
+ ? TEntity
524
+ : {
525
+ [K in keyof TSelect as TSelect[K] extends false | undefined ? never : K]: TSelect[K] extends true
526
+ ? K extends keyof TEntity
527
+ ? TEntity[K]
528
+ : never
529
+ : TSelect[K] extends { select: infer NestedSelect }
530
+ ? K extends keyof TEntity
531
+ ? NonNullable<TEntity[K]> extends ConnectionResult<infer NodeType>
532
+ ? ConnectionResult<InferSelectResult<NodeType, NestedSelect>>
533
+ : InferSelectResult<NonNullable<TEntity[K]>, NestedSelect> | (null extends TEntity[K] ? null : never)
534
+ : never
535
+ : K extends keyof TEntity
536
+ ? TEntity[K]
537
+ : never;
538
+ };
539
+ `;
540
+ return {
541
+ fileName: 'select-types.ts',
542
+ content,
543
+ };
544
+ }
545
+ /**
546
+ * Generate the main index.ts with createClient factory
547
+ */
548
+ function generateCreateClientFile(tables, hasCustomQueries, hasCustomMutations) {
549
+ const project = (0, ts_ast_1.createProject)();
550
+ const sourceFile = (0, ts_ast_1.createSourceFile)(project, 'index.ts');
551
+ // Add file header
552
+ sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)('ORM Client - createClient factory') + '\n\n');
553
+ // Add imports
554
+ const imports = [
555
+ (0, ts_ast_1.createImport)({
556
+ moduleSpecifier: './client',
557
+ namedImports: ['OrmClient'],
558
+ typeOnlyNamedImports: ['OrmClientConfig'],
559
+ }),
560
+ ];
561
+ // Import models
562
+ for (const table of tables) {
563
+ const { typeName } = (0, utils_1.getTableNames)(table);
564
+ const modelName = `${typeName}Model`;
565
+ const fileName = (0, utils_1.lcFirst)(typeName);
566
+ imports.push((0, ts_ast_1.createImport)({
567
+ moduleSpecifier: `./models/${fileName}`,
568
+ namedImports: [modelName],
569
+ }));
570
+ }
571
+ // Import custom operations
572
+ if (hasCustomQueries) {
573
+ imports.push((0, ts_ast_1.createImport)({
574
+ moduleSpecifier: './query',
575
+ namedImports: ['createQueryOperations'],
576
+ }));
577
+ }
578
+ if (hasCustomMutations) {
579
+ imports.push((0, ts_ast_1.createImport)({
580
+ moduleSpecifier: './mutation',
581
+ namedImports: ['createMutationOperations'],
582
+ }));
583
+ }
584
+ sourceFile.addImportDeclarations(imports);
585
+ // Re-export types and classes
586
+ sourceFile.addStatements('\n// Re-export types and classes');
587
+ sourceFile.addStatements("export type { OrmClientConfig, QueryResult, GraphQLError } from './client';");
588
+ sourceFile.addStatements("export { GraphQLRequestError } from './client';");
589
+ sourceFile.addStatements("export { QueryBuilder } from './query-builder';");
590
+ sourceFile.addStatements("export * from './select-types';");
591
+ // Generate createClient function
592
+ sourceFile.addStatements('\n// ============================================================================');
593
+ sourceFile.addStatements('// Client Factory');
594
+ sourceFile.addStatements('// ============================================================================\n');
595
+ // Build the return object
596
+ const modelEntries = tables.map((table) => {
597
+ const { typeName, singularName } = (0, utils_1.getTableNames)(table);
598
+ return `${singularName}: new ${typeName}Model(client)`;
599
+ });
600
+ let returnObject = modelEntries.join(',\n ');
601
+ if (hasCustomQueries) {
602
+ returnObject += ',\n query: createQueryOperations(client)';
603
+ }
604
+ if (hasCustomMutations) {
605
+ returnObject += ',\n mutation: createMutationOperations(client)';
606
+ }
607
+ sourceFile.addFunction({
608
+ name: 'createClient',
609
+ isExported: true,
610
+ parameters: [{ name: 'config', type: 'OrmClientConfig' }],
611
+ statements: `const client = new OrmClient(config);
612
+
613
+ return {
614
+ ${returnObject},
615
+ };`,
616
+ docs: [
617
+ {
618
+ description: `Create an ORM client instance
619
+
620
+ @example
621
+ \`\`\`typescript
622
+ const db = createClient({
623
+ endpoint: 'https://api.example.com/graphql',
624
+ headers: { Authorization: 'Bearer token' },
625
+ });
626
+
627
+ // Query users
628
+ const users = await db.user.findMany({
629
+ select: { id: true, name: true },
630
+ first: 10,
631
+ }).execute();
632
+
633
+ // Create a user
634
+ const newUser = await db.user.create({
635
+ data: { name: 'John', email: 'john@example.com' },
636
+ select: { id: true },
637
+ }).execute();
638
+ \`\`\``,
639
+ },
640
+ ],
641
+ });
642
+ return {
643
+ fileName: 'index.ts',
644
+ content: (0, ts_ast_1.getFormattedOutput)(sourceFile),
645
+ };
646
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Custom operations generator for ORM client
3
+ *
4
+ * Generates db.query.* and db.mutation.* namespaces for non-table operations
5
+ * like login, register, currentUser, etc.
6
+ *
7
+ * Example output:
8
+ * ```typescript
9
+ * // query/index.ts
10
+ * export function createQueryOperations(client: OrmClient) {
11
+ * return {
12
+ * currentUser: (args?: { select?: CurrentUserSelect }) =>
13
+ * new QueryBuilder({ ... }),
14
+ * };
15
+ * }
16
+ * ```
17
+ */
18
+ import type { CleanOperation } from '../../../types/schema';
19
+ export interface GeneratedCustomOpsFile {
20
+ fileName: string;
21
+ content: string;
22
+ }
23
+ /**
24
+ * Generate the query/index.ts file for custom query operations
25
+ */
26
+ export declare function generateCustomQueryOpsFile(operations: CleanOperation[]): GeneratedCustomOpsFile;
27
+ /**
28
+ * Generate the mutation/index.ts file for custom mutation operations
29
+ */
30
+ export declare function generateCustomMutationOpsFile(operations: CleanOperation[]): GeneratedCustomOpsFile;