@constructive-io/graphql-codegen 3.2.1 → 3.3.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 (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
@@ -1,6 +1,12 @@
1
+ /**
2
+ * Model class generator for ORM client (Babel AST-based)
3
+ *
4
+ * Generates per-table model classes with findMany, findFirst, create, update, delete methods.
5
+ * Each method uses function overloads for IDE autocompletion of select objects.
6
+ */
1
7
  import * as t from '@babel/types';
2
8
  import { generateCode } from '../babel-ast';
3
- import { getTableNames, getOrderByTypeName, getFilterTypeName, lcFirst, getGeneratedFileHeader, } from '../utils';
9
+ import { getFilterTypeName, getGeneratedFileHeader, getOrderByTypeName, getPrimaryKeyInfo, getTableNames, hasValidPrimaryKey, lcFirst, } from '../utils';
4
10
  function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false) {
5
11
  const specifiers = namedImports.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
6
12
  const decl = t.importDeclaration(specifiers, t.stringLiteral(moduleSpecifier));
@@ -32,11 +38,36 @@ function createClassMethod(name, typeParameters, params, returnType, body) {
32
38
  method.returnType = returnType;
33
39
  return method;
34
40
  }
35
- function createConstTypeParam(constraintTypeName) {
36
- const param = t.tsTypeParameter(t.tsTypeReference(t.identifier(constraintTypeName)), null, 'S');
37
- param.const = true;
41
+ function createDeclareMethod(name, typeParameters, params, returnType) {
42
+ const method = t.tsDeclareMethod(null, t.identifier(name), typeParameters, params, returnType);
43
+ return method;
44
+ }
45
+ function createTypeParam(constraintTypeName, defaultType) {
46
+ const param = t.tsTypeParameter(t.tsTypeReference(t.identifier(constraintTypeName)), defaultType ?? null, 'S');
38
47
  return t.tsTypeParameterDeclaration([param]);
39
48
  }
49
+ function tsTypeFromPrimitive(typeName) {
50
+ if (typeName === 'string')
51
+ return t.tsStringKeyword();
52
+ if (typeName === 'number')
53
+ return t.tsNumberKeyword();
54
+ if (typeName === 'boolean')
55
+ return t.tsBooleanKeyword();
56
+ return t.tsTypeReference(t.identifier(typeName));
57
+ }
58
+ /** Build a required `select: S` property for overload signatures */
59
+ function requiredSelectProp() {
60
+ const prop = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('S'))));
61
+ prop.optional = false;
62
+ return prop;
63
+ }
64
+ /** Build `StrictSelect<S, XxxSelect>` type reference for overload intersections */
65
+ function strictSelectGuard(selectTypeName) {
66
+ return t.tsTypeReference(t.identifier('StrictSelect'), t.tsTypeParameterInstantiation([
67
+ t.tsTypeReference(t.identifier('S')),
68
+ t.tsTypeReference(t.identifier(selectTypeName)),
69
+ ]));
70
+ }
40
71
  export function generateModelFile(table, _useSharedTypes) {
41
72
  const { typeName, singularName, pluralName } = getTableNames(table);
42
73
  const modelName = `${typeName}Model`;
@@ -51,6 +82,8 @@ export function generateModelFile(table, _useSharedTypes) {
51
82
  const updateInputTypeName = `Update${typeName}Input`;
52
83
  const deleteInputTypeName = `Delete${typeName}Input`;
53
84
  const patchTypeName = `${typeName}Patch`;
85
+ const pkFields = getPrimaryKeyInfo(table);
86
+ const pkField = pkFields[0];
54
87
  const pluralQueryName = table.query?.all ?? pluralName;
55
88
  const createMutationName = table.query?.create ?? `create${typeName}`;
56
89
  const updateMutationName = table.query?.update;
@@ -58,17 +91,35 @@ export function generateModelFile(table, _useSharedTypes) {
58
91
  const statements = [];
59
92
  statements.push(createImportDeclaration('../client', ['OrmClient']));
60
93
  statements.push(createImportDeclaration('../query-builder', [
61
- 'QueryBuilder', 'buildFindManyDocument', 'buildFindFirstDocument',
62
- 'buildCreateDocument', 'buildUpdateDocument', 'buildDeleteDocument',
94
+ 'QueryBuilder',
95
+ 'buildFindManyDocument',
96
+ 'buildFindFirstDocument',
97
+ 'buildFindOneDocument',
98
+ 'buildCreateDocument',
99
+ 'buildUpdateByPkDocument',
100
+ 'buildDeleteByPkDocument',
63
101
  ]));
64
102
  statements.push(createImportDeclaration('../select-types', [
65
- 'ConnectionResult', 'FindManyArgs', 'FindFirstArgs', 'CreateArgs',
66
- 'UpdateArgs', 'DeleteArgs', 'InferSelectResult', 'DeepExact',
103
+ 'ConnectionResult',
104
+ 'FindManyArgs',
105
+ 'FindFirstArgs',
106
+ 'CreateArgs',
107
+ 'UpdateArgs',
108
+ 'DeleteArgs',
109
+ 'InferSelectResult',
110
+ 'StrictSelect',
67
111
  ], true));
68
112
  statements.push(createImportDeclaration('../input-types', [
69
- typeName, relationTypeName, selectTypeName, whereTypeName, orderByTypeName,
70
- createInputTypeName, updateInputTypeName, patchTypeName,
113
+ typeName,
114
+ relationTypeName,
115
+ selectTypeName,
116
+ whereTypeName,
117
+ orderByTypeName,
118
+ createInputTypeName,
119
+ updateInputTypeName,
120
+ patchTypeName,
71
121
  ], true));
122
+ statements.push(createImportDeclaration('../input-types', ['connectionFieldsMap']));
72
123
  const classBody = [];
73
124
  // Constructor
74
125
  const constructorParam = t.identifier('client');
@@ -76,162 +127,289 @@ export function generateModelFile(table, _useSharedTypes) {
76
127
  const paramProp = t.tsParameterProperty(constructorParam);
77
128
  paramProp.accessibility = 'private';
78
129
  classBody.push(t.classMethod('constructor', t.identifier('constructor'), [paramProp], t.blockStatement([])));
79
- // findMany method
80
- // Use DeepExact<S, SelectType> to enforce strict field validation
81
- const findManyParam = t.identifier('args');
82
- findManyParam.optional = true;
83
- findManyParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('FindManyArgs'), t.tsTypeParameterInstantiation([
84
- t.tsTypeReference(t.identifier('DeepExact'), t.tsTypeParameterInstantiation([
85
- t.tsTypeReference(t.identifier('S')),
86
- t.tsTypeReference(t.identifier(selectTypeName)),
87
- ])),
88
- t.tsTypeReference(t.identifier(whereTypeName)),
89
- t.tsTypeReference(t.identifier(orderByTypeName)),
90
- ])));
91
- const findManyReturnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
92
- t.tsTypeLiteral([
93
- t.tsPropertySignature(t.identifier(pluralQueryName), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ConnectionResult'), t.tsTypeParameterInstantiation([
94
- t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
95
- t.tsTypeReference(t.identifier(relationTypeName)),
96
- t.tsTypeReference(t.identifier('S')),
97
- ])),
98
- ])))),
99
- ]),
100
- ])));
101
- const findManyArgs = [
102
- t.stringLiteral(typeName),
103
- t.stringLiteral(pluralQueryName),
104
- t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true),
105
- t.objectExpression([
106
- t.objectProperty(t.identifier('where'), t.optionalMemberExpression(t.identifier('args'), t.identifier('where'), false, true)),
107
- t.objectProperty(t.identifier('orderBy'), t.tsAsExpression(t.optionalMemberExpression(t.identifier('args'), t.identifier('orderBy'), false, true), t.tsUnionType([t.tsArrayType(t.tsStringKeyword()), t.tsUndefinedKeyword()]))),
108
- t.objectProperty(t.identifier('first'), t.optionalMemberExpression(t.identifier('args'), t.identifier('first'), false, true)),
109
- t.objectProperty(t.identifier('last'), t.optionalMemberExpression(t.identifier('args'), t.identifier('last'), false, true)),
110
- t.objectProperty(t.identifier('after'), t.optionalMemberExpression(t.identifier('args'), t.identifier('after'), false, true)),
111
- t.objectProperty(t.identifier('before'), t.optionalMemberExpression(t.identifier('args'), t.identifier('before'), false, true)),
112
- t.objectProperty(t.identifier('offset'), t.optionalMemberExpression(t.identifier('args'), t.identifier('offset'), false, true)),
113
- ]),
114
- t.stringLiteral(whereTypeName),
115
- t.stringLiteral(orderByTypeName),
116
- ];
117
- classBody.push(createClassMethod('findMany', createConstTypeParam(selectTypeName), [findManyParam], findManyReturnType, buildMethodBody('buildFindManyDocument', findManyArgs, 'query', typeName, pluralQueryName)));
118
- // findFirst method
119
- const findFirstParam = t.identifier('args');
120
- findFirstParam.optional = true;
121
- findFirstParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('FindFirstArgs'), t.tsTypeParameterInstantiation([
122
- t.tsTypeReference(t.identifier('DeepExact'), t.tsTypeParameterInstantiation([
123
- t.tsTypeReference(t.identifier('S')),
124
- t.tsTypeReference(t.identifier(selectTypeName)),
125
- ])),
126
- t.tsTypeReference(t.identifier(whereTypeName)),
127
- ])));
128
- const findFirstReturnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
129
- t.tsTypeLiteral([
130
- t.tsPropertySignature(t.identifier(pluralQueryName), t.tsTypeAnnotation(t.tsTypeLiteral([
131
- t.tsPropertySignature(t.identifier('nodes'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
132
- t.tsTypeReference(t.identifier(relationTypeName)),
133
- t.tsTypeReference(t.identifier('S')),
134
- ]))))),
135
- ]))),
136
- ]),
137
- ])));
138
- const findFirstArgs = [
139
- t.stringLiteral(typeName),
140
- t.stringLiteral(pluralQueryName),
141
- t.optionalMemberExpression(t.identifier('args'), t.identifier('select'), false, true),
142
- t.objectExpression([
143
- t.objectProperty(t.identifier('where'), t.optionalMemberExpression(t.identifier('args'), t.identifier('where'), false, true)),
144
- ]),
145
- t.stringLiteral(whereTypeName),
146
- ];
147
- classBody.push(createClassMethod('findFirst', createConstTypeParam(selectTypeName), [findFirstParam], findFirstReturnType, buildMethodBody('buildFindFirstDocument', findFirstArgs, 'query', typeName, pluralQueryName)));
148
- // create method
149
- const createParam = t.identifier('args');
150
- createParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('CreateArgs'), t.tsTypeParameterInstantiation([
151
- t.tsTypeReference(t.identifier('DeepExact'), t.tsTypeParameterInstantiation([
152
- t.tsTypeReference(t.identifier('S')),
153
- t.tsTypeReference(t.identifier(selectTypeName)),
154
- ])),
155
- t.tsIndexedAccessType(t.tsTypeReference(t.identifier(createInputTypeName)), t.tsLiteralType(t.stringLiteral(singularName))),
156
- ])));
157
- const createReturnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
158
- t.tsTypeLiteral([
159
- t.tsPropertySignature(t.identifier(createMutationName), t.tsTypeAnnotation(t.tsTypeLiteral([
160
- t.tsPropertySignature(t.identifier(entityLower), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
161
- t.tsTypeReference(t.identifier(relationTypeName)),
162
- t.tsTypeReference(t.identifier('S')),
130
+ // Reusable type reference factories
131
+ const sRef = () => t.tsTypeReference(t.identifier('S'));
132
+ const selectRef = () => t.tsTypeReference(t.identifier(selectTypeName));
133
+ const pkTsType = () => tsTypeFromPrimitive(pkField.tsType);
134
+ // ── findMany ───────────────────────────────────────────────────────────
135
+ {
136
+ const argsType = (sel) => t.tsTypeReference(t.identifier('FindManyArgs'), t.tsTypeParameterInstantiation([
137
+ sel,
138
+ t.tsTypeReference(t.identifier(whereTypeName)),
139
+ t.tsTypeReference(t.identifier(orderByTypeName)),
140
+ ]));
141
+ const retType = (sel) => t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
142
+ t.tsTypeLiteral([
143
+ t.tsPropertySignature(t.identifier(pluralQueryName), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('ConnectionResult'), t.tsTypeParameterInstantiation([
144
+ t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
145
+ t.tsTypeReference(t.identifier(relationTypeName)),
146
+ sel,
147
+ ])),
163
148
  ])))),
164
- ]))),
165
- ]),
166
- ])));
167
- const createArgs = [
168
- t.stringLiteral(typeName),
169
- t.stringLiteral(createMutationName),
170
- t.stringLiteral(entityLower),
171
- t.memberExpression(t.identifier('args'), t.identifier('select')),
172
- t.memberExpression(t.identifier('args'), t.identifier('data')),
173
- t.stringLiteral(createInputTypeName),
174
- ];
175
- classBody.push(createClassMethod('create', createConstTypeParam(selectTypeName), [createParam], createReturnType, buildMethodBody('buildCreateDocument', createArgs, 'mutation', typeName, createMutationName)));
176
- // update method (if available)
149
+ ]),
150
+ ])));
151
+ // Overload 1: with select (autocompletion)
152
+ const o1Param = t.identifier('args');
153
+ o1Param.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
154
+ argsType(sRef()),
155
+ t.tsTypeLiteral([requiredSelectProp()]),
156
+ strictSelectGuard(selectTypeName),
157
+ ]));
158
+ classBody.push(createDeclareMethod('findMany', createTypeParam(selectTypeName), [o1Param], retType(sRef())));
159
+ // Implementation
160
+ const implParam = t.identifier('args');
161
+ implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef()));
162
+ const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
163
+ const bodyArgs = [
164
+ t.stringLiteral(typeName),
165
+ t.stringLiteral(pluralQueryName),
166
+ selectExpr,
167
+ t.objectExpression([
168
+ t.objectProperty(t.identifier('where'), t.optionalMemberExpression(t.identifier('args'), t.identifier('where'), false, true)),
169
+ t.objectProperty(t.identifier('orderBy'), t.tsAsExpression(t.optionalMemberExpression(t.identifier('args'), t.identifier('orderBy'), false, true), t.tsUnionType([
170
+ t.tsArrayType(t.tsStringKeyword()),
171
+ t.tsUndefinedKeyword(),
172
+ ]))),
173
+ t.objectProperty(t.identifier('first'), t.optionalMemberExpression(t.identifier('args'), t.identifier('first'), false, true)),
174
+ t.objectProperty(t.identifier('last'), t.optionalMemberExpression(t.identifier('args'), t.identifier('last'), false, true)),
175
+ t.objectProperty(t.identifier('after'), t.optionalMemberExpression(t.identifier('args'), t.identifier('after'), false, true)),
176
+ t.objectProperty(t.identifier('before'), t.optionalMemberExpression(t.identifier('args'), t.identifier('before'), false, true)),
177
+ t.objectProperty(t.identifier('offset'), t.optionalMemberExpression(t.identifier('args'), t.identifier('offset'), false, true)),
178
+ ]),
179
+ t.stringLiteral(whereTypeName),
180
+ t.stringLiteral(orderByTypeName),
181
+ t.identifier('connectionFieldsMap'),
182
+ ];
183
+ classBody.push(createClassMethod('findMany', null, [implParam], null, buildMethodBody('buildFindManyDocument', bodyArgs, 'query', typeName, pluralQueryName)));
184
+ }
185
+ // ── findFirst ──────────────────────────────────────────────────────────
186
+ {
187
+ const argsType = (sel) => t.tsTypeReference(t.identifier('FindFirstArgs'), t.tsTypeParameterInstantiation([
188
+ sel,
189
+ t.tsTypeReference(t.identifier(whereTypeName)),
190
+ ]));
191
+ const retType = (sel) => t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
192
+ t.tsTypeLiteral([
193
+ t.tsPropertySignature(t.identifier(pluralQueryName), t.tsTypeAnnotation(t.tsTypeLiteral([
194
+ t.tsPropertySignature(t.identifier('nodes'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
195
+ t.tsTypeReference(t.identifier(relationTypeName)),
196
+ sel,
197
+ ]))))),
198
+ ]))),
199
+ ]),
200
+ ])));
201
+ // Overload 1: with select (autocompletion)
202
+ const o1Param = t.identifier('args');
203
+ o1Param.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
204
+ argsType(sRef()),
205
+ t.tsTypeLiteral([requiredSelectProp()]),
206
+ strictSelectGuard(selectTypeName),
207
+ ]));
208
+ classBody.push(createDeclareMethod('findFirst', createTypeParam(selectTypeName), [o1Param], retType(sRef())));
209
+ // Implementation
210
+ const implParam = t.identifier('args');
211
+ implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef()));
212
+ const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
213
+ const bodyArgs = [
214
+ t.stringLiteral(typeName),
215
+ t.stringLiteral(pluralQueryName),
216
+ selectExpr,
217
+ t.objectExpression([
218
+ t.objectProperty(t.identifier('where'), t.optionalMemberExpression(t.identifier('args'), t.identifier('where'), false, true)),
219
+ ]),
220
+ t.stringLiteral(whereTypeName),
221
+ t.identifier('connectionFieldsMap'),
222
+ ];
223
+ classBody.push(createClassMethod('findFirst', null, [implParam], null, buildMethodBody('buildFindFirstDocument', bodyArgs, 'query', typeName, pluralQueryName)));
224
+ }
225
+ // ── findOne ────────────────────────────────────────────────────────────
226
+ const singleQueryName = table.query?.one;
227
+ if (singleQueryName && hasValidPrimaryKey(table)) {
228
+ const pkGqlType = pkField.gqlType.replace(/!/g, '') + '!';
229
+ const retType = (sel) => t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
230
+ t.tsTypeLiteral([
231
+ t.tsPropertySignature(t.identifier(singleQueryName), t.tsTypeAnnotation(t.tsUnionType([
232
+ t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
233
+ t.tsTypeReference(t.identifier(relationTypeName)),
234
+ sel,
235
+ ])),
236
+ t.tsNullKeyword(),
237
+ ]))),
238
+ ]),
239
+ ])));
240
+ const pkProp = () => {
241
+ const prop = t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTsType()));
242
+ prop.optional = false;
243
+ return prop;
244
+ };
245
+ // Overload 1: with select (autocompletion)
246
+ const o1Param = t.identifier('args');
247
+ o1Param.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
248
+ t.tsTypeLiteral([pkProp(), requiredSelectProp()]),
249
+ strictSelectGuard(selectTypeName),
250
+ ]));
251
+ classBody.push(createDeclareMethod('findOne', createTypeParam(selectTypeName), [o1Param], retType(sRef())));
252
+ // Implementation
253
+ const implParam = t.identifier('args');
254
+ implParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeLiteral([
255
+ pkProp(),
256
+ (() => {
257
+ const prop = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(selectTypeName))));
258
+ return prop;
259
+ })(),
260
+ ]));
261
+ const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
262
+ const bodyArgs = [
263
+ t.stringLiteral(typeName),
264
+ t.stringLiteral(singleQueryName),
265
+ t.memberExpression(t.identifier('args'), t.identifier(pkField.name)),
266
+ selectExpr,
267
+ t.stringLiteral(pkField.name),
268
+ t.stringLiteral(pkGqlType),
269
+ t.identifier('connectionFieldsMap'),
270
+ ];
271
+ classBody.push(createClassMethod('findOne', null, [implParam], null, buildMethodBody('buildFindOneDocument', bodyArgs, 'query', typeName, singleQueryName)));
272
+ }
273
+ // ── create ─────────────────────────────────────────────────────────────
274
+ {
275
+ const dataType = () => t.tsIndexedAccessType(t.tsTypeReference(t.identifier(createInputTypeName)), t.tsLiteralType(t.stringLiteral(singularName)));
276
+ const argsType = (sel) => t.tsTypeReference(t.identifier('CreateArgs'), t.tsTypeParameterInstantiation([sel, dataType()]));
277
+ const retType = (sel) => t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
278
+ t.tsTypeLiteral([
279
+ t.tsPropertySignature(t.identifier(createMutationName), t.tsTypeAnnotation(t.tsTypeLiteral([
280
+ t.tsPropertySignature(t.identifier(entityLower), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
281
+ t.tsTypeReference(t.identifier(relationTypeName)),
282
+ sel,
283
+ ])))),
284
+ ]))),
285
+ ]),
286
+ ])));
287
+ // Overload 1: with select (autocompletion)
288
+ const o1Param = t.identifier('args');
289
+ o1Param.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
290
+ argsType(sRef()),
291
+ t.tsTypeLiteral([requiredSelectProp()]),
292
+ strictSelectGuard(selectTypeName),
293
+ ]));
294
+ classBody.push(createDeclareMethod('create', createTypeParam(selectTypeName), [o1Param], retType(sRef())));
295
+ // Implementation
296
+ const implParam = t.identifier('args');
297
+ implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef()));
298
+ const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
299
+ const bodyArgs = [
300
+ t.stringLiteral(typeName),
301
+ t.stringLiteral(createMutationName),
302
+ t.stringLiteral(entityLower),
303
+ selectExpr,
304
+ t.memberExpression(t.identifier('args'), t.identifier('data')),
305
+ t.stringLiteral(createInputTypeName),
306
+ t.identifier('connectionFieldsMap'),
307
+ ];
308
+ classBody.push(createClassMethod('create', null, [implParam], null, buildMethodBody('buildCreateDocument', bodyArgs, 'mutation', typeName, createMutationName)));
309
+ }
310
+ // ── update ─────────────────────────────────────────────────────────────
177
311
  if (updateMutationName) {
178
- const updateParam = t.identifier('args');
179
- updateParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('UpdateArgs'), t.tsTypeParameterInstantiation([
180
- t.tsTypeReference(t.identifier('DeepExact'), t.tsTypeParameterInstantiation([
181
- t.tsTypeReference(t.identifier('S')),
182
- t.tsTypeReference(t.identifier(selectTypeName)),
183
- ])),
184
- t.tsTypeLiteral([t.tsPropertySignature(t.identifier('id'), t.tsTypeAnnotation(t.tsStringKeyword()))]),
312
+ const whereLiteral = () => t.tsTypeLiteral([
313
+ (() => {
314
+ const prop = t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTsType()));
315
+ prop.optional = false;
316
+ return prop;
317
+ })(),
318
+ ]);
319
+ const argsType = (sel) => t.tsTypeReference(t.identifier('UpdateArgs'), t.tsTypeParameterInstantiation([
320
+ sel,
321
+ whereLiteral(),
185
322
  t.tsTypeReference(t.identifier(patchTypeName)),
186
- ])));
187
- const updateReturnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
323
+ ]));
324
+ const retType = (sel) => t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
188
325
  t.tsTypeLiteral([
189
326
  t.tsPropertySignature(t.identifier(updateMutationName), t.tsTypeAnnotation(t.tsTypeLiteral([
190
327
  t.tsPropertySignature(t.identifier(entityLower), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
191
328
  t.tsTypeReference(t.identifier(relationTypeName)),
192
- t.tsTypeReference(t.identifier('S')),
329
+ sel,
193
330
  ])))),
194
331
  ]))),
195
332
  ]),
196
333
  ])));
197
- const updateArgs = [
334
+ // Overload 1: with select (autocompletion)
335
+ const o1Param = t.identifier('args');
336
+ o1Param.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
337
+ argsType(sRef()),
338
+ t.tsTypeLiteral([requiredSelectProp()]),
339
+ strictSelectGuard(selectTypeName),
340
+ ]));
341
+ classBody.push(createDeclareMethod('update', createTypeParam(selectTypeName), [o1Param], retType(sRef())));
342
+ // Implementation
343
+ const implParam = t.identifier('args');
344
+ implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef()));
345
+ const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
346
+ const bodyArgs = [
198
347
  t.stringLiteral(typeName),
199
348
  t.stringLiteral(updateMutationName),
200
349
  t.stringLiteral(entityLower),
201
- t.memberExpression(t.identifier('args'), t.identifier('select')),
202
- t.memberExpression(t.identifier('args'), t.identifier('where')),
350
+ selectExpr,
351
+ t.memberExpression(t.memberExpression(t.identifier('args'), t.identifier('where')), t.identifier(pkField.name)),
203
352
  t.memberExpression(t.identifier('args'), t.identifier('data')),
204
353
  t.stringLiteral(updateInputTypeName),
354
+ t.stringLiteral(pkField.name),
355
+ t.identifier('connectionFieldsMap'),
205
356
  ];
206
- classBody.push(createClassMethod('update', createConstTypeParam(selectTypeName), [updateParam], updateReturnType, buildMethodBody('buildUpdateDocument', updateArgs, 'mutation', typeName, updateMutationName)));
357
+ classBody.push(createClassMethod('update', null, [implParam], null, buildMethodBody('buildUpdateByPkDocument', bodyArgs, 'mutation', typeName, updateMutationName)));
207
358
  }
208
- // delete method (if available)
359
+ // ── delete ─────────────────────────────────────────────────────────────
209
360
  if (deleteMutationName) {
210
- const deleteParam = t.identifier('args');
211
- deleteParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('DeleteArgs'), t.tsTypeParameterInstantiation([
212
- t.tsTypeLiteral([t.tsPropertySignature(t.identifier('id'), t.tsTypeAnnotation(t.tsStringKeyword()))]),
213
- ])));
214
- const deleteReturnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
361
+ const whereLiteral = () => t.tsTypeLiteral([
362
+ (() => {
363
+ const prop = t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTsType()));
364
+ prop.optional = false;
365
+ return prop;
366
+ })(),
367
+ ]);
368
+ const argsType = (sel) => t.tsTypeReference(t.identifier('DeleteArgs'), t.tsTypeParameterInstantiation([whereLiteral(), sel]));
369
+ const retType = (sel) => t.tsTypeAnnotation(t.tsTypeReference(t.identifier('QueryBuilder'), t.tsTypeParameterInstantiation([
215
370
  t.tsTypeLiteral([
216
371
  t.tsPropertySignature(t.identifier(deleteMutationName), t.tsTypeAnnotation(t.tsTypeLiteral([
217
- t.tsPropertySignature(t.identifier(entityLower), t.tsTypeAnnotation(t.tsTypeLiteral([t.tsPropertySignature(t.identifier('id'), t.tsTypeAnnotation(t.tsStringKeyword()))]))),
372
+ t.tsPropertySignature(t.identifier(entityLower), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
373
+ t.tsTypeReference(t.identifier(relationTypeName)),
374
+ sel,
375
+ ])))),
218
376
  ]))),
219
377
  ]),
220
378
  ])));
221
- const deleteArgs = [
379
+ // Overload 1: with select (autocompletion)
380
+ const o1Param = t.identifier('args');
381
+ o1Param.typeAnnotation = t.tsTypeAnnotation(t.tsIntersectionType([
382
+ argsType(sRef()),
383
+ t.tsTypeLiteral([requiredSelectProp()]),
384
+ strictSelectGuard(selectTypeName),
385
+ ]));
386
+ classBody.push(createDeclareMethod('delete', createTypeParam(selectTypeName), [o1Param], retType(sRef())));
387
+ // Implementation
388
+ const implParam = t.identifier('args');
389
+ implParam.typeAnnotation = t.tsTypeAnnotation(argsType(selectRef()));
390
+ const selectExpr = t.memberExpression(t.identifier('args'), t.identifier('select'));
391
+ const bodyArgs = [
222
392
  t.stringLiteral(typeName),
223
393
  t.stringLiteral(deleteMutationName),
224
394
  t.stringLiteral(entityLower),
225
- t.memberExpression(t.identifier('args'), t.identifier('where')),
395
+ t.memberExpression(t.memberExpression(t.identifier('args'), t.identifier('where')), t.identifier(pkField.name)),
226
396
  t.stringLiteral(deleteInputTypeName),
397
+ t.stringLiteral(pkField.name),
398
+ selectExpr,
399
+ t.identifier('connectionFieldsMap'),
227
400
  ];
228
- classBody.push(createClassMethod('delete', null, [deleteParam], deleteReturnType, buildMethodBody('buildDeleteDocument', deleteArgs, 'mutation', typeName, deleteMutationName)));
401
+ classBody.push(createClassMethod('delete', null, [implParam], null, buildMethodBody('buildDeleteByPkDocument', bodyArgs, 'mutation', typeName, deleteMutationName)));
229
402
  }
230
403
  const classDecl = t.classDeclaration(t.identifier(modelName), null, t.classBody(classBody));
231
404
  statements.push(t.exportNamedDeclaration(classDecl));
232
405
  const header = getGeneratedFileHeader(`${typeName} model for ORM client`);
233
406
  const code = generateCode(statements);
234
- return { fileName, content: header + '\n' + code, modelName, tableName: table.name };
407
+ return {
408
+ fileName,
409
+ content: header + '\n' + code,
410
+ modelName,
411
+ tableName: table.name,
412
+ };
235
413
  }
236
414
  export function generateAllModelFiles(tables, useSharedTypes) {
237
415
  return tables.map((table) => generateModelFile(table, useSharedTypes));
@@ -47,16 +47,10 @@ export interface NestedSelectConfig {
47
47
  /**
48
48
  * Recursively validates select objects, rejecting unknown keys.
49
49
  *
50
- * This type ensures that users can only select fields that actually exist
51
- * in the GraphQL schema. It returns `never` if any excess keys are found
52
- * at any nesting level, causing a TypeScript compile error.
53
- *
54
- * Why this is needed:
55
- * TypeScript's excess property checking has a quirk where it only catches
56
- * invalid fields when they are the ONLY fields. When mixed with valid fields
57
- * (e.g., `{ id: true, invalidField: true }`), the structural typing allows
58
- * the excess property through. This type explicitly checks for and rejects
59
- * such cases.
50
+ * NOTE: This type is intentionally NOT used in generated parameter positions
51
+ * (conditional types block IDE autocompletion). Parameters use `S` directly
52
+ * with `S extends XxxSelect` constraints, which provides full
53
+ * autocompletion via TypeScript's contextual typing.
60
54
  *
61
55
  * @example
62
56
  * // This will cause a type error because 'invalid' doesn't exist:
@@ -71,12 +65,22 @@ export interface NestedSelectConfig {
71
65
  export type DeepExact<T, Shape> = T extends Shape ? Exclude<keyof T, keyof Shape> extends never ? {
72
66
  [K in keyof T]: K extends keyof Shape ? T[K] extends {
73
67
  select: infer NS;
74
- } ? Shape[K] extends {
68
+ } ? Extract<Shape[K], {
69
+ select?: unknown;
70
+ }> extends {
75
71
  select?: infer ShapeNS;
76
- } ? {
72
+ } ? DeepExact<Omit<T[K], 'select'> & {
77
73
  select: DeepExact<NS, NonNullable<ShapeNS>>;
78
- } : T[K] : T[K] : never;
74
+ }, Extract<Shape[K], {
75
+ select?: unknown;
76
+ }>> : never : T[K] : never;
79
77
  } : never : never;
78
+ /**
79
+ * Enforces exact select shape while keeping contextual typing on `S extends XxxSelect`.
80
+ * Use this as an intersection in overloads:
81
+ * `{ select: S } & StrictSelect<S, XxxSelect>`.
82
+ */
83
+ export type StrictSelect<S, Shape> = S extends DeepExact<S, Shape> ? {} : never;
80
84
  /**
81
85
  * Infers the result type from a select configuration
82
86
  *
@@ -172,8 +176,9 @@ export interface UpdateArgs<TSelect, TWhere, TData> {
172
176
  /**
173
177
  * Arguments for delete operations
174
178
  */
175
- export interface DeleteArgs<TWhere> {
179
+ export interface DeleteArgs<TWhere, TSelect = undefined> {
176
180
  where: TWhere;
181
+ select?: TSelect;
177
182
  }
178
183
  /**
179
184
  * Helper type to get the final result type from a query
@@ -1,11 +1,3 @@
1
- /**
2
- * Query hook generators using Babel AST-based code generation
3
- *
4
- * Output structure:
5
- * queries/
6
- * useCarsQuery.ts - List query hook
7
- * useCarQuery.ts - Single item query hook
8
- */
9
1
  import type { CleanTable } from '../../types/schema';
10
2
  export interface GeneratedQueryFile {
11
3
  fileName: string;