@constructive-io/graphql-codegen 3.2.1 → 3.3.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 (215) hide show
  1. package/cli/index.js +36 -43
  2. package/cli/shared.d.ts +15 -19
  3. package/cli/shared.js +104 -25
  4. package/client/error.js +31 -9
  5. package/client/execute.js +2 -2
  6. package/client/index.d.ts +3 -3
  7. package/client/index.js +6 -6
  8. package/core/ast.d.ts +1 -1
  9. package/core/ast.js +1 -1
  10. package/core/codegen/babel-ast.d.ts +1 -1
  11. package/core/codegen/babel-ast.js +2 -2
  12. package/core/codegen/barrel.d.ts +0 -6
  13. package/core/codegen/barrel.js +22 -19
  14. package/core/codegen/client.d.ts +2 -12
  15. package/core/codegen/client.js +7 -21
  16. package/core/codegen/custom-mutations.d.ts +0 -14
  17. package/core/codegen/custom-mutations.js +139 -88
  18. package/core/codegen/custom-queries.d.ts +0 -14
  19. package/core/codegen/custom-queries.js +483 -193
  20. package/core/codegen/hooks-ast.d.ts +75 -0
  21. package/core/codegen/hooks-ast.js +522 -0
  22. package/core/codegen/index.d.ts +16 -18
  23. package/core/codegen/index.js +42 -88
  24. package/core/codegen/invalidation.d.ts +1 -7
  25. package/core/codegen/invalidation.js +50 -16
  26. package/core/codegen/mutation-keys.d.ts +1 -10
  27. package/core/codegen/mutation-keys.js +22 -8
  28. package/core/codegen/mutations.d.ts +0 -13
  29. package/core/codegen/mutations.js +301 -366
  30. package/core/codegen/orm/barrel.d.ts +0 -5
  31. package/core/codegen/orm/barrel.js +5 -0
  32. package/core/codegen/orm/client-generator.d.ts +0 -5
  33. package/core/codegen/orm/client-generator.js +7 -2
  34. package/core/codegen/orm/client.js +3 -1
  35. package/core/codegen/orm/custom-ops-generator.d.ts +0 -6
  36. package/core/codegen/orm/custom-ops-generator.js +104 -51
  37. package/core/codegen/orm/index.d.ts +4 -4
  38. package/core/codegen/orm/index.js +28 -15
  39. package/core/codegen/orm/input-types-generator.d.ts +1 -13
  40. package/core/codegen/orm/input-types-generator.js +85 -23
  41. package/core/codegen/orm/model-generator.d.ts +0 -5
  42. package/core/codegen/orm/model-generator.js +309 -131
  43. package/core/codegen/orm/select-types.d.ts +19 -14
  44. package/core/codegen/queries.d.ts +0 -8
  45. package/core/codegen/queries.js +360 -559
  46. package/core/codegen/query-keys.d.ts +1 -1
  47. package/core/codegen/query-keys.js +37 -23
  48. package/core/codegen/scalars.js +3 -1
  49. package/core/codegen/schema-types-generator.d.ts +1 -1
  50. package/core/codegen/schema-types-generator.js +17 -2
  51. package/core/codegen/select-helpers.d.ts +19 -0
  52. package/core/codegen/select-helpers.js +40 -0
  53. package/core/codegen/selection.d.ts +4 -0
  54. package/core/codegen/selection.js +65 -0
  55. package/core/codegen/shared/index.d.ts +2 -15
  56. package/core/codegen/shared/index.js +17 -4
  57. package/core/codegen/templates/hooks-client.ts +49 -0
  58. package/core/codegen/templates/hooks-selection.ts +58 -0
  59. package/core/codegen/templates/orm-client.ts +8 -6
  60. package/core/codegen/templates/query-builder.ts +250 -46
  61. package/core/codegen/templates/select-types.ts +31 -14
  62. package/core/codegen/type-resolver.d.ts +1 -5
  63. package/core/codegen/type-resolver.js +0 -22
  64. package/core/codegen/types.d.ts +0 -3
  65. package/core/codegen/types.js +71 -14
  66. package/core/codegen/utils.d.ts +1 -4
  67. package/core/codegen/utils.js +4 -1
  68. package/core/config/index.d.ts +1 -1
  69. package/core/config/resolver.js +1 -3
  70. package/core/generate.js +38 -50
  71. package/core/index.d.ts +3 -3
  72. package/core/index.js +3 -4
  73. package/core/introspect/index.d.ts +6 -6
  74. package/core/introspect/index.js +5 -8
  75. package/core/introspect/infer-tables.d.ts +0 -14
  76. package/core/introspect/infer-tables.js +15 -1
  77. package/core/introspect/source/database.js +1 -1
  78. package/core/introspect/source/endpoint.d.ts +0 -6
  79. package/core/introspect/source/endpoint.js +7 -1
  80. package/core/introspect/source/index.d.ts +4 -4
  81. package/core/introspect/source/index.js +5 -9
  82. package/core/introspect/source/pgpm-module.js +3 -3
  83. package/core/introspect/transform-schema.d.ts +2 -2
  84. package/core/introspect/transform-schema.js +2 -2
  85. package/core/output/index.d.ts +1 -1
  86. package/core/output/index.js +2 -2
  87. package/core/output/writer.d.ts +3 -0
  88. package/core/output/writer.js +20 -1
  89. package/core/pipeline/index.d.ts +2 -2
  90. package/core/query-builder.d.ts +2 -2
  91. package/core/query-builder.js +1 -1
  92. package/core/watch/index.d.ts +4 -4
  93. package/core/watch/index.js +9 -9
  94. package/core/watch/orchestrator.js +5 -3
  95. package/esm/cli/index.js +37 -44
  96. package/esm/cli/shared.d.ts +15 -19
  97. package/esm/cli/shared.js +94 -23
  98. package/esm/client/error.js +31 -9
  99. package/esm/client/execute.js +2 -2
  100. package/esm/client/index.d.ts +3 -3
  101. package/esm/client/index.js +3 -3
  102. package/esm/core/ast.d.ts +1 -1
  103. package/esm/core/ast.js +1 -1
  104. package/esm/core/codegen/babel-ast.d.ts +1 -1
  105. package/esm/core/codegen/babel-ast.js +2 -2
  106. package/esm/core/codegen/barrel.d.ts +0 -6
  107. package/esm/core/codegen/barrel.js +23 -20
  108. package/esm/core/codegen/client.d.ts +2 -12
  109. package/esm/core/codegen/client.js +7 -21
  110. package/esm/core/codegen/custom-mutations.d.ts +0 -14
  111. package/esm/core/codegen/custom-mutations.js +141 -90
  112. package/esm/core/codegen/custom-queries.d.ts +0 -14
  113. package/esm/core/codegen/custom-queries.js +486 -196
  114. package/esm/core/codegen/hooks-ast.d.ts +75 -0
  115. package/esm/core/codegen/hooks-ast.js +424 -0
  116. package/esm/core/codegen/index.d.ts +16 -18
  117. package/esm/core/codegen/index.js +26 -71
  118. package/esm/core/codegen/invalidation.d.ts +1 -7
  119. package/esm/core/codegen/invalidation.js +51 -17
  120. package/esm/core/codegen/mutation-keys.d.ts +1 -10
  121. package/esm/core/codegen/mutation-keys.js +23 -9
  122. package/esm/core/codegen/mutations.d.ts +0 -13
  123. package/esm/core/codegen/mutations.js +302 -367
  124. package/esm/core/codegen/orm/barrel.d.ts +0 -5
  125. package/esm/core/codegen/orm/barrel.js +6 -1
  126. package/esm/core/codegen/orm/client-generator.d.ts +0 -5
  127. package/esm/core/codegen/orm/client-generator.js +7 -2
  128. package/esm/core/codegen/orm/client.js +3 -1
  129. package/esm/core/codegen/orm/custom-ops-generator.d.ts +0 -6
  130. package/esm/core/codegen/orm/custom-ops-generator.js +103 -50
  131. package/esm/core/codegen/orm/index.d.ts +4 -4
  132. package/esm/core/codegen/orm/index.js +25 -12
  133. package/esm/core/codegen/orm/input-types-generator.d.ts +1 -13
  134. package/esm/core/codegen/orm/input-types-generator.js +85 -23
  135. package/esm/core/codegen/orm/model-generator.d.ts +0 -5
  136. package/esm/core/codegen/orm/model-generator.js +310 -132
  137. package/esm/core/codegen/orm/select-types.d.ts +19 -14
  138. package/esm/core/codegen/queries.d.ts +0 -8
  139. package/esm/core/codegen/queries.js +362 -561
  140. package/esm/core/codegen/query-keys.d.ts +1 -1
  141. package/esm/core/codegen/query-keys.js +38 -24
  142. package/esm/core/codegen/scalars.js +3 -1
  143. package/esm/core/codegen/schema-types-generator.d.ts +1 -1
  144. package/esm/core/codegen/schema-types-generator.js +17 -2
  145. package/esm/core/codegen/select-helpers.d.ts +19 -0
  146. package/esm/core/codegen/select-helpers.js +35 -0
  147. package/esm/core/codegen/selection.d.ts +4 -0
  148. package/esm/core/codegen/selection.js +29 -0
  149. package/esm/core/codegen/shared/index.d.ts +2 -15
  150. package/esm/core/codegen/shared/index.js +16 -3
  151. package/esm/core/codegen/type-resolver.d.ts +1 -5
  152. package/esm/core/codegen/type-resolver.js +1 -22
  153. package/esm/core/codegen/types.d.ts +0 -3
  154. package/esm/core/codegen/types.js +72 -15
  155. package/esm/core/codegen/utils.d.ts +1 -4
  156. package/esm/core/codegen/utils.js +4 -1
  157. package/esm/core/config/index.d.ts +1 -1
  158. package/esm/core/config/resolver.js +2 -4
  159. package/esm/core/generate.js +38 -50
  160. package/esm/core/index.d.ts +3 -3
  161. package/esm/core/index.js +2 -3
  162. package/esm/core/introspect/index.d.ts +6 -6
  163. package/esm/core/introspect/index.js +3 -6
  164. package/esm/core/introspect/infer-tables.d.ts +0 -14
  165. package/esm/core/introspect/infer-tables.js +16 -2
  166. package/esm/core/introspect/source/database.js +2 -2
  167. package/esm/core/introspect/source/endpoint.d.ts +0 -6
  168. package/esm/core/introspect/source/endpoint.js +7 -1
  169. package/esm/core/introspect/source/index.d.ts +4 -4
  170. package/esm/core/introspect/source/index.js +6 -10
  171. package/esm/core/introspect/source/pgpm-module.js +3 -3
  172. package/esm/core/introspect/transform-schema.d.ts +2 -2
  173. package/esm/core/introspect/transform-schema.js +2 -2
  174. package/esm/core/output/index.d.ts +1 -1
  175. package/esm/core/output/index.js +1 -1
  176. package/esm/core/output/writer.d.ts +3 -0
  177. package/esm/core/output/writer.js +20 -1
  178. package/esm/core/pipeline/index.d.ts +2 -2
  179. package/esm/core/pipeline/index.js +2 -2
  180. package/esm/core/query-builder.d.ts +2 -2
  181. package/esm/core/query-builder.js +2 -2
  182. package/esm/core/watch/index.d.ts +4 -4
  183. package/esm/core/watch/index.js +3 -3
  184. package/esm/core/watch/orchestrator.js +5 -3
  185. package/esm/generators/index.d.ts +3 -3
  186. package/esm/generators/index.js +3 -3
  187. package/esm/generators/mutations.d.ts +1 -1
  188. package/esm/generators/select.d.ts +1 -1
  189. package/esm/index.d.ts +3 -3
  190. package/esm/index.js +1 -4
  191. package/esm/types/config.d.ts +0 -10
  192. package/esm/types/config.js +0 -2
  193. package/esm/types/index.d.ts +6 -6
  194. package/esm/types/index.js +1 -1
  195. package/generators/index.d.ts +3 -3
  196. package/generators/index.js +8 -8
  197. package/generators/mutations.d.ts +1 -1
  198. package/generators/select.d.ts +1 -1
  199. package/index.d.ts +3 -3
  200. package/index.js +11 -6
  201. package/package.json +10 -10
  202. package/types/config.d.ts +0 -10
  203. package/types/config.js +0 -2
  204. package/types/index.d.ts +6 -6
  205. package/types/index.js +2 -2
  206. package/core/codegen/gql-ast.d.ts +0 -41
  207. package/core/codegen/gql-ast.js +0 -353
  208. package/core/codegen/schema-gql-ast.d.ts +0 -51
  209. package/core/codegen/schema-gql-ast.js +0 -385
  210. package/core/codegen/templates/client.browser.ts +0 -271
  211. package/core/codegen/templates/client.node.ts +0 -337
  212. package/esm/core/codegen/gql-ast.d.ts +0 -41
  213. package/esm/core/codegen/gql-ast.js +0 -312
  214. package/esm/core/codegen/schema-gql-ast.d.ts +0 -51
  215. package/esm/core/codegen/schema-gql-ast.js +0 -343
@@ -8,15 +8,16 @@
8
8
  * Any changes here will affect all generated ORM clients.
9
9
  */
10
10
 
11
- import * as t from 'gql-ast';
12
11
  import { parseType, print } from '@0no-co/graphql.web';
12
+ import * as t from 'gql-ast';
13
13
  import type {
14
14
  ArgumentNode,
15
+ EnumValueNode,
15
16
  FieldNode,
16
17
  VariableDefinitionNode,
17
- EnumValueNode,
18
18
  } from 'graphql';
19
- import { OrmClient, QueryResult, GraphQLRequestError } from './client';
19
+
20
+ import { GraphQLRequestError, OrmClient, QueryResult } from './client';
20
21
 
21
22
  export interface QueryBuilderConfig {
22
23
  client: OrmClient;
@@ -41,7 +42,7 @@ export class QueryBuilder<TResult> {
41
42
  async execute(): Promise<QueryResult<TResult>> {
42
43
  return this.config.client.execute<TResult>(
43
44
  this.config.document,
44
- this.config.variables
45
+ this.config.variables,
45
46
  );
46
47
  }
47
48
 
@@ -72,7 +73,7 @@ export class QueryBuilder<TResult> {
72
73
  * Execute and unwrap, calling onError callback on failure
73
74
  */
74
75
  async unwrapOrElse<D>(
75
- onError: (errors: import('./client').GraphQLError[]) => D
76
+ onError: (errors: import('./client').GraphQLError[]) => D,
76
77
  ): Promise<TResult | D> {
77
78
  const result = await this.execute();
78
79
  if (!result.ok) {
@@ -95,13 +96,18 @@ export class QueryBuilder<TResult> {
95
96
  // ============================================================================
96
97
 
97
98
  export function buildSelections(
98
- select: Record<string, unknown> | undefined
99
+ select: Record<string, unknown> | undefined,
100
+ connectionFieldsMap?: Record<string, Record<string, string>>,
101
+ entityType?: string,
99
102
  ): FieldNode[] {
100
103
  if (!select) {
101
104
  return [];
102
105
  }
103
106
 
104
107
  const fields: FieldNode[] = [];
108
+ const entityConnections = entityType
109
+ ? connectionFieldsMap?.[entityType]
110
+ : undefined;
105
111
 
106
112
  for (const [key, value] of Object.entries(select)) {
107
113
  if (value === false || value === undefined) {
@@ -123,15 +129,24 @@ export function buildSelections(
123
129
  };
124
130
 
125
131
  if (nested.select) {
126
- const nestedSelections = buildSelections(nested.select);
132
+ const relatedEntityType = entityConnections?.[key];
133
+ const nestedSelections = buildSelections(
134
+ nested.select,
135
+ connectionFieldsMap,
136
+ relatedEntityType,
137
+ );
127
138
  const isConnection =
128
139
  nested.connection === true ||
129
140
  nested.first !== undefined ||
130
- nested.filter !== undefined;
141
+ nested.filter !== undefined ||
142
+ relatedEntityType !== undefined;
131
143
  const args = buildArgs([
132
144
  buildOptionalArg('first', nested.first),
133
145
  nested.filter
134
- ? t.argument({ name: 'filter', value: buildValueAst(nested.filter) })
146
+ ? t.argument({
147
+ name: 'filter',
148
+ value: buildValueAst(nested.filter),
149
+ })
135
150
  : null,
136
151
  buildEnumListArg('orderBy', nested.orderBy),
137
152
  ]);
@@ -144,7 +159,7 @@ export function buildSelections(
144
159
  selectionSet: t.selectionSet({
145
160
  selections: buildConnectionSelections(nestedSelections),
146
161
  }),
147
- })
162
+ }),
148
163
  );
149
164
  } else {
150
165
  fields.push(
@@ -152,7 +167,7 @@ export function buildSelections(
152
167
  name: key,
153
168
  args,
154
169
  selectionSet: t.selectionSet({ selections: nestedSelections }),
155
- })
170
+ }),
156
171
  );
157
172
  }
158
173
  }
@@ -180,10 +195,15 @@ export function buildFindManyDocument<TSelect, TWhere>(
180
195
  offset?: number;
181
196
  },
182
197
  filterTypeName: string,
183
- orderByTypeName: string
198
+ orderByTypeName: string,
199
+ connectionFieldsMap?: Record<string, Record<string, string>>,
184
200
  ): { document: string; variables: Record<string, unknown> } {
185
201
  const selections = select
186
- ? buildSelections(select as Record<string, unknown>)
202
+ ? buildSelections(
203
+ select as Record<string, unknown>,
204
+ connectionFieldsMap,
205
+ operationName,
206
+ )
187
207
  : [t.field({ name: 'id' })];
188
208
 
189
209
  const variableDefinitions: VariableDefinitionNode[] = [];
@@ -191,10 +211,15 @@ export function buildFindManyDocument<TSelect, TWhere>(
191
211
  const variables: Record<string, unknown> = {};
192
212
 
193
213
  addVariable(
194
- { varName: 'where', argName: 'filter', typeName: filterTypeName, value: args.where },
214
+ {
215
+ varName: 'where',
216
+ argName: 'filter',
217
+ typeName: filterTypeName,
218
+ value: args.where,
219
+ },
195
220
  variableDefinitions,
196
221
  queryArgs,
197
- variables
222
+ variables,
198
223
  );
199
224
  addVariable(
200
225
  {
@@ -204,37 +229,37 @@ export function buildFindManyDocument<TSelect, TWhere>(
204
229
  },
205
230
  variableDefinitions,
206
231
  queryArgs,
207
- variables
232
+ variables,
208
233
  );
209
234
  addVariable(
210
235
  { varName: 'first', typeName: 'Int', value: args.first },
211
236
  variableDefinitions,
212
237
  queryArgs,
213
- variables
238
+ variables,
214
239
  );
215
240
  addVariable(
216
241
  { varName: 'last', typeName: 'Int', value: args.last },
217
242
  variableDefinitions,
218
243
  queryArgs,
219
- variables
244
+ variables,
220
245
  );
221
246
  addVariable(
222
247
  { varName: 'after', typeName: 'Cursor', value: args.after },
223
248
  variableDefinitions,
224
249
  queryArgs,
225
- variables
250
+ variables,
226
251
  );
227
252
  addVariable(
228
253
  { varName: 'before', typeName: 'Cursor', value: args.before },
229
254
  variableDefinitions,
230
255
  queryArgs,
231
- variables
256
+ variables,
232
257
  );
233
258
  addVariable(
234
259
  { varName: 'offset', typeName: 'Int', value: args.offset },
235
260
  variableDefinitions,
236
261
  queryArgs,
237
- variables
262
+ variables,
238
263
  );
239
264
 
240
265
  const document = t.document({
@@ -242,7 +267,9 @@ export function buildFindManyDocument<TSelect, TWhere>(
242
267
  t.operationDefinition({
243
268
  operation: 'query',
244
269
  name: operationName + 'Query',
245
- variableDefinitions: variableDefinitions.length ? variableDefinitions : undefined,
270
+ variableDefinitions: variableDefinitions.length
271
+ ? variableDefinitions
272
+ : undefined,
246
273
  selectionSet: t.selectionSet({
247
274
  selections: [
248
275
  t.field({
@@ -266,10 +293,15 @@ export function buildFindFirstDocument<TSelect, TWhere>(
266
293
  queryField: string,
267
294
  select: TSelect,
268
295
  args: { where?: TWhere },
269
- filterTypeName: string
296
+ filterTypeName: string,
297
+ connectionFieldsMap?: Record<string, Record<string, string>>,
270
298
  ): { document: string; variables: Record<string, unknown> } {
271
299
  const selections = select
272
- ? buildSelections(select as Record<string, unknown>)
300
+ ? buildSelections(
301
+ select as Record<string, unknown>,
302
+ connectionFieldsMap,
303
+ operationName,
304
+ )
273
305
  : [t.field({ name: 'id' })];
274
306
 
275
307
  const variableDefinitions: VariableDefinitionNode[] = [];
@@ -281,13 +313,18 @@ export function buildFindFirstDocument<TSelect, TWhere>(
281
313
  { varName: 'first', typeName: 'Int', value: 1 },
282
314
  variableDefinitions,
283
315
  queryArgs,
284
- variables
316
+ variables,
285
317
  );
286
318
  addVariable(
287
- { varName: 'where', argName: 'filter', typeName: filterTypeName, value: args.where },
319
+ {
320
+ varName: 'where',
321
+ argName: 'filter',
322
+ typeName: filterTypeName,
323
+ value: args.where,
324
+ },
288
325
  variableDefinitions,
289
326
  queryArgs,
290
- variables
327
+ variables,
291
328
  );
292
329
 
293
330
  const document = t.document({
@@ -325,10 +362,15 @@ export function buildCreateDocument<TSelect, TData>(
325
362
  entityField: string,
326
363
  select: TSelect,
327
364
  data: TData,
328
- inputTypeName: string
365
+ inputTypeName: string,
366
+ connectionFieldsMap?: Record<string, Record<string, string>>,
329
367
  ): { document: string; variables: Record<string, unknown> } {
330
368
  const selections = select
331
- ? buildSelections(select as Record<string, unknown>)
369
+ ? buildSelections(
370
+ select as Record<string, unknown>,
371
+ connectionFieldsMap,
372
+ operationName,
373
+ )
332
374
  : [t.field({ name: 'id' })];
333
375
 
334
376
  return {
@@ -351,17 +393,26 @@ export function buildCreateDocument<TSelect, TData>(
351
393
  };
352
394
  }
353
395
 
354
- export function buildUpdateDocument<TSelect, TWhere extends { id: string }, TData>(
396
+ export function buildUpdateDocument<
397
+ TSelect,
398
+ TWhere extends { id: string },
399
+ TData,
400
+ >(
355
401
  operationName: string,
356
402
  mutationField: string,
357
403
  entityField: string,
358
404
  select: TSelect,
359
405
  where: TWhere,
360
406
  data: TData,
361
- inputTypeName: string
407
+ inputTypeName: string,
408
+ connectionFieldsMap?: Record<string, Record<string, string>>,
362
409
  ): { document: string; variables: Record<string, unknown> } {
363
410
  const selections = select
364
- ? buildSelections(select as Record<string, unknown>)
411
+ ? buildSelections(
412
+ select as Record<string, unknown>,
413
+ connectionFieldsMap,
414
+ operationName,
415
+ )
365
416
  : [t.field({ name: 'id' })];
366
417
 
367
418
  return {
@@ -385,13 +436,122 @@ export function buildUpdateDocument<TSelect, TWhere extends { id: string }, TDat
385
436
  };
386
437
  }
387
438
 
388
- export function buildDeleteDocument<TWhere extends { id: string }>(
439
+ export function buildUpdateByPkDocument<TSelect, TData>(
440
+ operationName: string,
441
+ mutationField: string,
442
+ entityField: string,
443
+ select: TSelect,
444
+ id: string | number,
445
+ data: TData,
446
+ inputTypeName: string,
447
+ idFieldName: string,
448
+ connectionFieldsMap?: Record<string, Record<string, string>>,
449
+ ): { document: string; variables: Record<string, unknown> } {
450
+ const selections = select
451
+ ? buildSelections(
452
+ select as Record<string, unknown>,
453
+ connectionFieldsMap,
454
+ operationName,
455
+ )
456
+ : [t.field({ name: 'id' })];
457
+
458
+ return {
459
+ document: buildInputMutationDocument({
460
+ operationName,
461
+ mutationField,
462
+ inputTypeName,
463
+ resultSelections: [
464
+ t.field({
465
+ name: entityField,
466
+ selectionSet: t.selectionSet({ selections }),
467
+ }),
468
+ ],
469
+ }),
470
+ variables: {
471
+ input: {
472
+ [idFieldName]: id,
473
+ patch: data,
474
+ },
475
+ },
476
+ };
477
+ }
478
+
479
+ export function buildFindOneDocument<TSelect>(
480
+ operationName: string,
481
+ queryField: string,
482
+ id: string | number,
483
+ select: TSelect,
484
+ idArgName: string,
485
+ idTypeName: string,
486
+ connectionFieldsMap?: Record<string, Record<string, string>>,
487
+ ): { document: string; variables: Record<string, unknown> } {
488
+ const selections = select
489
+ ? buildSelections(
490
+ select as Record<string, unknown>,
491
+ connectionFieldsMap,
492
+ operationName,
493
+ )
494
+ : [t.field({ name: 'id' })];
495
+
496
+ const variableDefinitions: VariableDefinitionNode[] = [
497
+ t.variableDefinition({
498
+ variable: t.variable({ name: idArgName }),
499
+ type: parseType(idTypeName),
500
+ }),
501
+ ];
502
+
503
+ const queryArgs: ArgumentNode[] = [
504
+ t.argument({
505
+ name: idArgName,
506
+ value: t.variable({ name: idArgName }),
507
+ }),
508
+ ];
509
+
510
+ const document = t.document({
511
+ definitions: [
512
+ t.operationDefinition({
513
+ operation: 'query',
514
+ name: operationName + 'Query',
515
+ variableDefinitions,
516
+ selectionSet: t.selectionSet({
517
+ selections: [
518
+ t.field({
519
+ name: queryField,
520
+ args: queryArgs,
521
+ selectionSet: t.selectionSet({ selections }),
522
+ }),
523
+ ],
524
+ }),
525
+ }),
526
+ ],
527
+ });
528
+
529
+ return {
530
+ document: print(document),
531
+ variables: { [idArgName]: id },
532
+ };
533
+ }
534
+
535
+ export function buildDeleteDocument<
536
+ TWhere extends { id: string },
537
+ TSelect = undefined,
538
+ >(
389
539
  operationName: string,
390
540
  mutationField: string,
391
541
  entityField: string,
392
542
  where: TWhere,
393
- inputTypeName: string
543
+ inputTypeName: string,
544
+ select?: TSelect,
545
+ connectionFieldsMap?: Record<string, Record<string, string>>,
394
546
  ): { document: string; variables: Record<string, unknown> } {
547
+ const entitySelections = select
548
+ ? buildSelections(
549
+ select as Record<string, unknown>,
550
+ connectionFieldsMap,
551
+ operationName,
552
+ )
553
+ : [t.field({ name: 'id' })];
554
+
395
555
  return {
396
556
  document: buildInputMutationDocument({
397
557
  operationName,
@@ -401,7 +561,7 @@ export function buildDeleteDocument<TWhere extends { id: string }>(
401
561
  t.field({
402
562
  name: entityField,
403
563
  selectionSet: t.selectionSet({
404
- selections: [t.field({ name: 'id' })],
564
+ selections: entitySelections,
405
565
  }),
406
566
  }),
407
567
  ],
@@ -414,13 +574,53 @@ export function buildDeleteDocument<TWhere extends { id: string }>(
414
574
  };
415
575
  }
416
576
 
577
+ export function buildDeleteByPkDocument<TSelect = undefined>(
578
+ operationName: string,
579
+ mutationField: string,
580
+ entityField: string,
581
+ id: string | number,
582
+ inputTypeName: string,
583
+ idFieldName: string,
584
+ select?: TSelect,
585
+ connectionFieldsMap?: Record<string, Record<string, string>>,
586
+ ): { document: string; variables: Record<string, unknown> } {
587
+ const entitySelections = select
588
+ ? buildSelections(
589
+ select as Record<string, unknown>,
590
+ connectionFieldsMap,
591
+ operationName,
592
+ )
593
+ : [t.field({ name: 'id' })];
594
+
595
+ return {
596
+ document: buildInputMutationDocument({
597
+ operationName,
598
+ mutationField,
599
+ inputTypeName,
600
+ resultSelections: [
601
+ t.field({
602
+ name: entityField,
603
+ selectionSet: t.selectionSet({ selections: entitySelections }),
604
+ }),
605
+ ],
606
+ }),
607
+ variables: {
608
+ input: {
609
+ [idFieldName]: id,
610
+ },
611
+ },
612
+ };
613
+ }
614
+
417
615
  export function buildCustomDocument<TSelect, TArgs>(
418
616
  operationType: 'query' | 'mutation',
419
617
  operationName: string,
420
618
  fieldName: string,
421
619
  select: TSelect,
422
620
  args: TArgs,
423
- variableDefinitions: Array<{ name: string; type: string }>
621
+ variableDefinitions: Array<{ name: string; type: string }>,
622
+ connectionFieldsMap?: Record<string, Record<string, string>>,
623
+ entityType?: string,
424
624
  ): { document: string; variables: Record<string, unknown> } {
425
625
  let actualSelect = select;
426
626
  let isConnection = false;
@@ -434,20 +634,24 @@ export function buildCustomDocument<TSelect, TArgs>(
434
634
  }
435
635
 
436
636
  const selections = actualSelect
437
- ? buildSelections(actualSelect as Record<string, unknown>)
637
+ ? buildSelections(
638
+ actualSelect as Record<string, unknown>,
639
+ connectionFieldsMap,
640
+ entityType,
641
+ )
438
642
  : [];
439
643
 
440
644
  const variableDefs = variableDefinitions.map((definition) =>
441
645
  t.variableDefinition({
442
646
  variable: t.variable({ name: definition.name }),
443
647
  type: parseType(definition.type),
444
- })
648
+ }),
445
649
  );
446
650
  const fieldArgs = variableDefinitions.map((definition) =>
447
651
  t.argument({
448
652
  name: definition.name,
449
653
  value: t.variable({ name: definition.name }),
450
- })
654
+ }),
451
655
  );
452
656
 
453
657
  const fieldSelections = isConnection
@@ -491,7 +695,7 @@ function buildArgs(args: Array<ArgumentNode | null>): ArgumentNode[] {
491
695
 
492
696
  function buildOptionalArg(
493
697
  name: string,
494
- value: number | string | undefined
698
+ value: number | string | undefined,
495
699
  ): ArgumentNode | null {
496
700
  if (value === undefined) {
497
701
  return null;
@@ -505,7 +709,7 @@ function buildOptionalArg(
505
709
 
506
710
  function buildEnumListArg(
507
711
  name: string,
508
- values: string[] | undefined
712
+ values: string[] | undefined,
509
713
  ): ArgumentNode | null {
510
714
  if (!values || values.length === 0) {
511
715
  return null;
@@ -600,7 +804,7 @@ function addVariable(
600
804
  spec: VariableSpec,
601
805
  definitions: VariableDefinitionNode[],
602
806
  args: ArgumentNode[],
603
- variables: Record<string, unknown>
807
+ variables: Record<string, unknown>,
604
808
  ): void {
605
809
  if (spec.value === undefined) return;
606
810
 
@@ -608,19 +812,19 @@ function addVariable(
608
812
  t.variableDefinition({
609
813
  variable: t.variable({ name: spec.varName }),
610
814
  type: parseType(spec.typeName),
611
- })
815
+ }),
612
816
  );
613
817
  args.push(
614
818
  t.argument({
615
819
  name: spec.argName ?? spec.varName,
616
820
  value: t.variable({ name: spec.varName }),
617
- })
821
+ }),
618
822
  );
619
823
  variables[spec.varName] = spec.value;
620
824
  }
621
825
 
622
826
  function buildValueAst(
623
- value: unknown
827
+ value: unknown,
624
828
  ):
625
829
  | ReturnType<typeof t.stringValue>
626
830
  | ReturnType<typeof t.intValue>
@@ -661,7 +865,7 @@ function buildValueAst(
661
865
  t.objectField({
662
866
  name: key,
663
867
  value: buildValueAst(val),
664
- })
868
+ }),
665
869
  ),
666
870
  });
667
871
  }
@@ -48,23 +48,26 @@ export interface UpdateArgs<TSelect, TWhere, TData> {
48
48
  select?: TSelect;
49
49
  }
50
50
 
51
- export interface DeleteArgs<TWhere> {
51
+ export type FindOneArgs<
52
+ TSelect,
53
+ TIdName extends string = 'id',
54
+ TId = string,
55
+ > = {
56
+ select?: TSelect;
57
+ } & Record<TIdName, TId>;
58
+
59
+ export interface DeleteArgs<TWhere, TSelect = undefined> {
52
60
  where: TWhere;
61
+ select?: TSelect;
53
62
  }
54
63
 
55
64
  /**
56
65
  * Recursively validates select objects, rejecting unknown keys.
57
66
  *
58
- * This type ensures that users can only select fields that actually exist
59
- * in the GraphQL schema. It returns `never` if any excess keys are found
60
- * at any nesting level, causing a TypeScript compile error.
61
- *
62
- * Why this is needed:
63
- * TypeScript's excess property checking has a quirk where it only catches
64
- * invalid fields when they are the ONLY fields. When mixed with valid fields
65
- * (e.g., `{ id: true, invalidField: true }`), the structural typing allows
66
- * the excess property through. This type explicitly checks for and rejects
67
- * such cases.
67
+ * NOTE: This type is intentionally NOT used in generated parameter positions
68
+ * (conditional types block IDE autocompletion). Parameters use `S` directly
69
+ * with `S extends XxxSelect` constraints, which provides full
70
+ * autocompletion via TypeScript's contextual typing.
68
71
  *
69
72
  * @example
70
73
  * // This will cause a type error because 'invalid' doesn't exist:
@@ -81,15 +84,29 @@ export type DeepExact<T, Shape> = T extends Shape
81
84
  ? {
82
85
  [K in keyof T]: K extends keyof Shape
83
86
  ? T[K] extends { select: infer NS }
84
- ? Shape[K] extends { select?: infer ShapeNS }
85
- ? { select: DeepExact<NS, NonNullable<ShapeNS>> }
86
- : T[K]
87
+ ? Extract<Shape[K], { select?: unknown }> extends {
88
+ select?: infer ShapeNS;
89
+ }
90
+ ? DeepExact<
91
+ Omit<T[K], 'select'> & {
92
+ select: DeepExact<NS, NonNullable<ShapeNS>>;
93
+ },
94
+ Extract<Shape[K], { select?: unknown }>
95
+ >
96
+ : never
87
97
  : T[K]
88
98
  : never;
89
99
  }
90
100
  : never
91
101
  : never;
92
102
 
103
+ /**
104
+ * Enforces exact select shape while keeping contextual typing on `S extends XxxSelect`.
105
+ * Use this as an intersection in overloads:
106
+ * `{ select: S } & StrictSelect<S, XxxSelect>`.
107
+ */
108
+ export type StrictSelect<S, Shape> = S extends DeepExact<S, Shape> ? {} : never;
109
+
93
110
  /**
94
111
  * Infer result type from select configuration
95
112
  */
@@ -4,7 +4,7 @@
4
4
  * Utilities for converting CleanTypeRef and other GraphQL types
5
5
  * into TypeScript type strings and interface definitions.
6
6
  */
7
- import type { CleanTypeRef, CleanObjectField } from '../../types/schema';
7
+ import type { CleanTypeRef } from '../../types/schema';
8
8
  /**
9
9
  * Interface for tracking referenced types during code generation
10
10
  */
@@ -73,10 +73,6 @@ export declare function getBaseTypeKind(typeRef: CleanTypeRef): CleanTypeRef['ki
73
73
  * Check if a field should be skipped in selections
74
74
  */
75
75
  export declare function shouldSkipField(fieldName: string, skipQueryField: boolean): boolean;
76
- /**
77
- * Filter fields to only include selectable scalar and object fields
78
- */
79
- export declare function getSelectableFields(fields: CleanObjectField[] | undefined, skipQueryField: boolean, maxDepth?: number, currentDepth?: number): CleanObjectField[];
80
76
  /**
81
77
  * Convert operation name to PascalCase for type names
82
78
  */
@@ -9,7 +9,6 @@ exports.isTypeList = isTypeList;
9
9
  exports.getTypeBaseName = getTypeBaseName;
10
10
  exports.getBaseTypeKind = getBaseTypeKind;
11
11
  exports.shouldSkipField = shouldSkipField;
12
- exports.getSelectableFields = getSelectableFields;
13
12
  exports.operationNameToPascal = operationNameToPascal;
14
13
  exports.getOperationVariablesTypeName = getOperationVariablesTypeName;
15
14
  exports.getOperationResultTypeName = getOperationResultTypeName;
@@ -194,27 +193,6 @@ function shouldSkipField(fieldName, skipQueryField) {
194
193
  return true;
195
194
  return false;
196
195
  }
197
- /**
198
- * Filter fields to only include selectable scalar and object fields
199
- */
200
- function getSelectableFields(fields, skipQueryField, maxDepth = 2, currentDepth = 0) {
201
- if (!fields || currentDepth >= maxDepth)
202
- return [];
203
- return fields.filter((field) => {
204
- // Skip internal fields
205
- if (shouldSkipField(field.name, skipQueryField))
206
- return false;
207
- // Get base type kind
208
- const baseKind = getBaseTypeKind(field.type);
209
- // Include scalars and enums
210
- if (baseKind === 'SCALAR' || baseKind === 'ENUM')
211
- return true;
212
- // Include objects up to max depth
213
- if (baseKind === 'OBJECT' && currentDepth < maxDepth - 1)
214
- return true;
215
- return false;
216
- });
217
- }
218
196
  // ============================================================================
219
197
  // Type Name Utilities
220
198
  // ============================================================================
@@ -1,6 +1,3 @@
1
- /**
2
- * Types generator - generates types.ts with entity interfaces using Babel AST
3
- */
4
1
  import type { CleanTable } from '../../types/schema';
5
2
  /**
6
3
  * Options for generating types.ts