@constructive-io/graphql-codegen 3.2.0 → 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 (216) hide show
  1. package/README.md +25 -30
  2. package/cli/index.js +36 -41
  3. package/cli/shared.d.ts +15 -17
  4. package/cli/shared.js +113 -21
  5. package/client/error.js +31 -9
  6. package/client/execute.js +2 -2
  7. package/client/index.d.ts +3 -3
  8. package/client/index.js +6 -6
  9. package/core/ast.d.ts +1 -1
  10. package/core/ast.js +1 -1
  11. package/core/codegen/babel-ast.d.ts +1 -1
  12. package/core/codegen/babel-ast.js +2 -2
  13. package/core/codegen/barrel.d.ts +0 -6
  14. package/core/codegen/barrel.js +22 -19
  15. package/core/codegen/client.d.ts +2 -12
  16. package/core/codegen/client.js +7 -21
  17. package/core/codegen/custom-mutations.d.ts +0 -14
  18. package/core/codegen/custom-mutations.js +139 -88
  19. package/core/codegen/custom-queries.d.ts +0 -14
  20. package/core/codegen/custom-queries.js +483 -193
  21. package/core/codegen/hooks-ast.d.ts +75 -0
  22. package/core/codegen/hooks-ast.js +522 -0
  23. package/core/codegen/index.d.ts +16 -18
  24. package/core/codegen/index.js +42 -88
  25. package/core/codegen/invalidation.d.ts +1 -7
  26. package/core/codegen/invalidation.js +50 -16
  27. package/core/codegen/mutation-keys.d.ts +1 -10
  28. package/core/codegen/mutation-keys.js +22 -8
  29. package/core/codegen/mutations.d.ts +0 -13
  30. package/core/codegen/mutations.js +301 -366
  31. package/core/codegen/orm/barrel.d.ts +0 -5
  32. package/core/codegen/orm/barrel.js +5 -0
  33. package/core/codegen/orm/client-generator.d.ts +0 -5
  34. package/core/codegen/orm/client-generator.js +7 -2
  35. package/core/codegen/orm/client.js +3 -1
  36. package/core/codegen/orm/custom-ops-generator.d.ts +0 -6
  37. package/core/codegen/orm/custom-ops-generator.js +104 -51
  38. package/core/codegen/orm/index.d.ts +4 -4
  39. package/core/codegen/orm/index.js +28 -15
  40. package/core/codegen/orm/input-types-generator.d.ts +1 -13
  41. package/core/codegen/orm/input-types-generator.js +85 -23
  42. package/core/codegen/orm/model-generator.d.ts +0 -5
  43. package/core/codegen/orm/model-generator.js +309 -131
  44. package/core/codegen/orm/select-types.d.ts +19 -14
  45. package/core/codegen/queries.d.ts +0 -8
  46. package/core/codegen/queries.js +360 -559
  47. package/core/codegen/query-keys.d.ts +1 -1
  48. package/core/codegen/query-keys.js +37 -23
  49. package/core/codegen/scalars.js +3 -1
  50. package/core/codegen/schema-types-generator.d.ts +1 -1
  51. package/core/codegen/schema-types-generator.js +17 -2
  52. package/core/codegen/select-helpers.d.ts +19 -0
  53. package/core/codegen/select-helpers.js +40 -0
  54. package/core/codegen/selection.d.ts +4 -0
  55. package/core/codegen/selection.js +65 -0
  56. package/core/codegen/shared/index.d.ts +2 -15
  57. package/core/codegen/shared/index.js +17 -4
  58. package/core/codegen/templates/hooks-client.ts +49 -0
  59. package/core/codegen/templates/hooks-selection.ts +58 -0
  60. package/core/codegen/templates/orm-client.ts +8 -6
  61. package/core/codegen/templates/query-builder.ts +250 -46
  62. package/core/codegen/templates/select-types.ts +31 -14
  63. package/core/codegen/type-resolver.d.ts +1 -5
  64. package/core/codegen/type-resolver.js +0 -22
  65. package/core/codegen/types.d.ts +0 -3
  66. package/core/codegen/types.js +71 -14
  67. package/core/codegen/utils.d.ts +1 -4
  68. package/core/codegen/utils.js +4 -1
  69. package/core/config/index.d.ts +1 -1
  70. package/core/config/resolver.js +1 -3
  71. package/core/generate.js +38 -50
  72. package/core/index.d.ts +3 -3
  73. package/core/index.js +3 -4
  74. package/core/introspect/index.d.ts +6 -6
  75. package/core/introspect/index.js +5 -8
  76. package/core/introspect/infer-tables.d.ts +0 -14
  77. package/core/introspect/infer-tables.js +15 -1
  78. package/core/introspect/source/database.js +1 -1
  79. package/core/introspect/source/endpoint.d.ts +0 -6
  80. package/core/introspect/source/endpoint.js +7 -1
  81. package/core/introspect/source/index.d.ts +4 -4
  82. package/core/introspect/source/index.js +5 -9
  83. package/core/introspect/source/pgpm-module.js +3 -3
  84. package/core/introspect/transform-schema.d.ts +2 -2
  85. package/core/introspect/transform-schema.js +2 -2
  86. package/core/output/index.d.ts +1 -1
  87. package/core/output/index.js +2 -2
  88. package/core/output/writer.d.ts +3 -0
  89. package/core/output/writer.js +20 -1
  90. package/core/pipeline/index.d.ts +2 -2
  91. package/core/query-builder.d.ts +2 -2
  92. package/core/query-builder.js +1 -1
  93. package/core/watch/index.d.ts +4 -4
  94. package/core/watch/index.js +9 -9
  95. package/core/watch/orchestrator.js +5 -3
  96. package/esm/cli/index.js +37 -42
  97. package/esm/cli/shared.d.ts +15 -17
  98. package/esm/cli/shared.js +103 -20
  99. package/esm/client/error.js +31 -9
  100. package/esm/client/execute.js +2 -2
  101. package/esm/client/index.d.ts +3 -3
  102. package/esm/client/index.js +3 -3
  103. package/esm/core/ast.d.ts +1 -1
  104. package/esm/core/ast.js +1 -1
  105. package/esm/core/codegen/babel-ast.d.ts +1 -1
  106. package/esm/core/codegen/babel-ast.js +2 -2
  107. package/esm/core/codegen/barrel.d.ts +0 -6
  108. package/esm/core/codegen/barrel.js +23 -20
  109. package/esm/core/codegen/client.d.ts +2 -12
  110. package/esm/core/codegen/client.js +7 -21
  111. package/esm/core/codegen/custom-mutations.d.ts +0 -14
  112. package/esm/core/codegen/custom-mutations.js +141 -90
  113. package/esm/core/codegen/custom-queries.d.ts +0 -14
  114. package/esm/core/codegen/custom-queries.js +486 -196
  115. package/esm/core/codegen/hooks-ast.d.ts +75 -0
  116. package/esm/core/codegen/hooks-ast.js +424 -0
  117. package/esm/core/codegen/index.d.ts +16 -18
  118. package/esm/core/codegen/index.js +26 -71
  119. package/esm/core/codegen/invalidation.d.ts +1 -7
  120. package/esm/core/codegen/invalidation.js +51 -17
  121. package/esm/core/codegen/mutation-keys.d.ts +1 -10
  122. package/esm/core/codegen/mutation-keys.js +23 -9
  123. package/esm/core/codegen/mutations.d.ts +0 -13
  124. package/esm/core/codegen/mutations.js +302 -367
  125. package/esm/core/codegen/orm/barrel.d.ts +0 -5
  126. package/esm/core/codegen/orm/barrel.js +6 -1
  127. package/esm/core/codegen/orm/client-generator.d.ts +0 -5
  128. package/esm/core/codegen/orm/client-generator.js +7 -2
  129. package/esm/core/codegen/orm/client.js +3 -1
  130. package/esm/core/codegen/orm/custom-ops-generator.d.ts +0 -6
  131. package/esm/core/codegen/orm/custom-ops-generator.js +103 -50
  132. package/esm/core/codegen/orm/index.d.ts +4 -4
  133. package/esm/core/codegen/orm/index.js +25 -12
  134. package/esm/core/codegen/orm/input-types-generator.d.ts +1 -13
  135. package/esm/core/codegen/orm/input-types-generator.js +85 -23
  136. package/esm/core/codegen/orm/model-generator.d.ts +0 -5
  137. package/esm/core/codegen/orm/model-generator.js +310 -132
  138. package/esm/core/codegen/orm/select-types.d.ts +19 -14
  139. package/esm/core/codegen/queries.d.ts +0 -8
  140. package/esm/core/codegen/queries.js +362 -561
  141. package/esm/core/codegen/query-keys.d.ts +1 -1
  142. package/esm/core/codegen/query-keys.js +38 -24
  143. package/esm/core/codegen/scalars.js +3 -1
  144. package/esm/core/codegen/schema-types-generator.d.ts +1 -1
  145. package/esm/core/codegen/schema-types-generator.js +17 -2
  146. package/esm/core/codegen/select-helpers.d.ts +19 -0
  147. package/esm/core/codegen/select-helpers.js +35 -0
  148. package/esm/core/codegen/selection.d.ts +4 -0
  149. package/esm/core/codegen/selection.js +29 -0
  150. package/esm/core/codegen/shared/index.d.ts +2 -15
  151. package/esm/core/codegen/shared/index.js +16 -3
  152. package/esm/core/codegen/type-resolver.d.ts +1 -5
  153. package/esm/core/codegen/type-resolver.js +1 -22
  154. package/esm/core/codegen/types.d.ts +0 -3
  155. package/esm/core/codegen/types.js +72 -15
  156. package/esm/core/codegen/utils.d.ts +1 -4
  157. package/esm/core/codegen/utils.js +4 -1
  158. package/esm/core/config/index.d.ts +1 -1
  159. package/esm/core/config/resolver.js +2 -4
  160. package/esm/core/generate.js +38 -50
  161. package/esm/core/index.d.ts +3 -3
  162. package/esm/core/index.js +2 -3
  163. package/esm/core/introspect/index.d.ts +6 -6
  164. package/esm/core/introspect/index.js +3 -6
  165. package/esm/core/introspect/infer-tables.d.ts +0 -14
  166. package/esm/core/introspect/infer-tables.js +16 -2
  167. package/esm/core/introspect/source/database.js +2 -2
  168. package/esm/core/introspect/source/endpoint.d.ts +0 -6
  169. package/esm/core/introspect/source/endpoint.js +7 -1
  170. package/esm/core/introspect/source/index.d.ts +4 -4
  171. package/esm/core/introspect/source/index.js +6 -10
  172. package/esm/core/introspect/source/pgpm-module.js +3 -3
  173. package/esm/core/introspect/transform-schema.d.ts +2 -2
  174. package/esm/core/introspect/transform-schema.js +2 -2
  175. package/esm/core/output/index.d.ts +1 -1
  176. package/esm/core/output/index.js +1 -1
  177. package/esm/core/output/writer.d.ts +3 -0
  178. package/esm/core/output/writer.js +20 -1
  179. package/esm/core/pipeline/index.d.ts +2 -2
  180. package/esm/core/pipeline/index.js +2 -2
  181. package/esm/core/query-builder.d.ts +2 -2
  182. package/esm/core/query-builder.js +2 -2
  183. package/esm/core/watch/index.d.ts +4 -4
  184. package/esm/core/watch/index.js +3 -3
  185. package/esm/core/watch/orchestrator.js +5 -3
  186. package/esm/generators/index.d.ts +3 -3
  187. package/esm/generators/index.js +3 -3
  188. package/esm/generators/mutations.d.ts +1 -1
  189. package/esm/generators/select.d.ts +1 -1
  190. package/esm/index.d.ts +3 -3
  191. package/esm/index.js +1 -4
  192. package/esm/types/config.d.ts +0 -10
  193. package/esm/types/config.js +0 -2
  194. package/esm/types/index.d.ts +6 -6
  195. package/esm/types/index.js +1 -1
  196. package/generators/index.d.ts +3 -3
  197. package/generators/index.js +8 -8
  198. package/generators/mutations.d.ts +1 -1
  199. package/generators/select.d.ts +1 -1
  200. package/index.d.ts +3 -3
  201. package/index.js +11 -5
  202. package/package.json +11 -11
  203. package/types/config.d.ts +0 -10
  204. package/types/config.js +0 -2
  205. package/types/index.d.ts +6 -6
  206. package/types/index.js +2 -2
  207. package/core/codegen/gql-ast.d.ts +0 -41
  208. package/core/codegen/gql-ast.js +0 -353
  209. package/core/codegen/schema-gql-ast.d.ts +0 -51
  210. package/core/codegen/schema-gql-ast.js +0 -385
  211. package/core/codegen/templates/client.browser.ts +0 -271
  212. package/core/codegen/templates/client.node.ts +0 -337
  213. package/esm/core/codegen/gql-ast.d.ts +0 -41
  214. package/esm/core/codegen/gql-ast.js +0 -312
  215. package/esm/core/codegen/schema-gql-ast.d.ts +0 -51
  216. package/esm/core/codegen/schema-gql-ast.js +0 -343
@@ -37,444 +37,379 @@ exports.generateCreateMutationHook = generateCreateMutationHook;
37
37
  exports.generateUpdateMutationHook = generateUpdateMutationHook;
38
38
  exports.generateDeleteMutationHook = generateDeleteMutationHook;
39
39
  exports.generateAllMutationHooks = generateAllMutationHooks;
40
+ /**
41
+ * Mutation hook generators - delegates to ORM model methods (Babel AST-based)
42
+ *
43
+ * Output structure:
44
+ * mutations/
45
+ * useCreateCarMutation.ts -> ORM create
46
+ * useUpdateCarMutation.ts -> ORM update
47
+ * useDeleteCarMutation.ts -> ORM delete
48
+ */
40
49
  const t = __importStar(require("@babel/types"));
41
- const babel_ast_1 = require("./babel-ast");
42
- const gql_ast_1 = require("./gql-ast");
50
+ const hooks_ast_1 = require("./hooks-ast");
43
51
  const utils_1 = require("./utils");
44
- function isAutoGeneratedField(fieldName, pkFieldNames) {
45
- const name = fieldName.toLowerCase();
46
- if (pkFieldNames.has(fieldName))
47
- return true;
48
- const timestampPatterns = [
49
- 'createdat', 'created_at', 'createddate', 'created_date',
50
- 'updatedat', 'updated_at', 'updateddate', 'updated_date',
51
- 'deletedat', 'deleted_at',
52
- ];
53
- return timestampPatterns.includes(name);
52
+ function buildMutationResultType(mutationName, singularName, relationTypeName, selectType) {
53
+ return (0, hooks_ast_1.typeLiteralWithProps)([
54
+ {
55
+ name: mutationName,
56
+ type: (0, hooks_ast_1.typeLiteralWithProps)([
57
+ {
58
+ name: singularName,
59
+ type: (0, hooks_ast_1.inferSelectResultType)(relationTypeName, selectType),
60
+ },
61
+ ]),
62
+ },
63
+ ]);
64
+ }
65
+ function buildFieldsSelectionType(s, selectTypeName) {
66
+ return t.tsParenthesizedType(t.tsIntersectionType([
67
+ t.tsTypeLiteral([
68
+ t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(s)),
69
+ ]),
70
+ (0, hooks_ast_1.typeRef)('StrictSelect', [s, (0, hooks_ast_1.typeRef)(selectTypeName)]),
71
+ ]));
54
72
  }
55
73
  function generateCreateMutationHook(table, options = {}) {
56
- const { reactQueryEnabled = true, enumsFromSchemaTypes = [], useCentralizedKeys = true, hasRelationships = false, tableTypeNames = new Set(), } = options;
57
- if (!reactQueryEnabled) {
74
+ const { reactQueryEnabled = true, useCentralizedKeys = true } = options;
75
+ if (!reactQueryEnabled)
58
76
  return null;
59
- }
60
- const enumSet = new Set(enumsFromSchemaTypes);
61
77
  const { typeName, singularName } = (0, utils_1.getTableNames)(table);
62
78
  const hookName = (0, utils_1.getCreateMutationHookName)(table);
79
+ const mutationName = (0, utils_1.getCreateMutationName)(table);
63
80
  const keysName = `${(0, utils_1.lcFirst)(typeName)}Keys`;
64
81
  const mutationKeysName = `${(0, utils_1.lcFirst)(typeName)}MutationKeys`;
65
- const scopeTypeName = `${typeName}Scope`;
66
- const mutationName = (0, utils_1.getCreateMutationName)(table);
67
- const scalarFields = (0, utils_1.getScalarFields)(table);
68
- const pkFieldNames = new Set((0, utils_1.getPrimaryKeyInfo)(table).map((pk) => pk.name));
69
- const usedEnums = new Set();
70
- const usedTableTypes = new Set();
71
- for (const field of scalarFields) {
72
- const cleanType = field.type.gqlType.replace(/!/g, '');
73
- if (enumSet.has(cleanType)) {
74
- usedEnums.add(cleanType);
75
- }
76
- else if (tableTypeNames.has(cleanType) && cleanType !== typeName) {
77
- // Track table types used in scalar fields (excluding the main type which is already imported)
78
- usedTableTypes.add(cleanType);
79
- }
80
- }
81
- const mutationAST = (0, gql_ast_1.buildCreateMutationAST)({ table });
82
- const mutationDocument = (0, gql_ast_1.printGraphQL)(mutationAST);
82
+ const selectTypeName = `${typeName}Select`;
83
+ const relationTypeName = `${typeName}WithRelations`;
84
+ const createInputTypeName = `Create${typeName}Input`;
83
85
  const statements = [];
84
- const reactQueryImport = t.importDeclaration([
85
- t.importSpecifier(t.identifier('useMutation'), t.identifier('useMutation')),
86
- t.importSpecifier(t.identifier('useQueryClient'), t.identifier('useQueryClient')),
87
- ], t.stringLiteral('@tanstack/react-query'));
88
- statements.push(reactQueryImport);
89
- const reactQueryTypeImport = t.importDeclaration([t.importSpecifier(t.identifier('UseMutationOptions'), t.identifier('UseMutationOptions'))], t.stringLiteral('@tanstack/react-query'));
90
- reactQueryTypeImport.importKind = 'type';
91
- statements.push(reactQueryTypeImport);
92
- const clientImport = t.importDeclaration([t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], t.stringLiteral('../client'));
93
- statements.push(clientImport);
94
- // Import the main type and any other table types used in scalar fields
95
- const allTypesToImport = [typeName, ...Array.from(usedTableTypes)].sort();
96
- const typesImport = t.importDeclaration(allTypesToImport.map((t_) => t.importSpecifier(t.identifier(t_), t.identifier(t_))), t.stringLiteral('../types'));
97
- typesImport.importKind = 'type';
98
- statements.push(typesImport);
99
- if (usedEnums.size > 0) {
100
- const enumImport = t.importDeclaration(Array.from(usedEnums).sort().map((e) => t.importSpecifier(t.identifier(e), t.identifier(e))), t.stringLiteral('../schema-types'));
101
- enumImport.importKind = 'type';
102
- statements.push(enumImport);
103
- }
104
- if (useCentralizedKeys) {
105
- const queryKeyImport = t.importDeclaration([t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], t.stringLiteral('../query-keys'));
106
- statements.push(queryKeyImport);
107
- if (hasRelationships) {
108
- const scopeTypeImport = t.importDeclaration([t.importSpecifier(t.identifier(scopeTypeName), t.identifier(scopeTypeName))], t.stringLiteral('../query-keys'));
109
- scopeTypeImport.importKind = 'type';
110
- statements.push(scopeTypeImport);
111
- }
112
- const mutationKeyImport = t.importDeclaration([t.importSpecifier(t.identifier(mutationKeysName), t.identifier(mutationKeysName))], t.stringLiteral('../mutation-keys'));
113
- statements.push(mutationKeyImport);
114
- }
115
- const reExportDecl = t.exportNamedDeclaration(null, [t.exportSpecifier(t.identifier(typeName), t.identifier(typeName))], t.stringLiteral('../types'));
116
- reExportDecl.exportKind = 'type';
117
- statements.push(reExportDecl);
118
- const mutationDocConst = t.variableDeclaration('const', [
119
- t.variableDeclarator(t.identifier(`${mutationName}MutationDocument`), t.templateLiteral([t.templateElement({ raw: '\n' + mutationDocument, cooked: '\n' + mutationDocument }, true)], [])),
120
- ]);
121
- statements.push(t.exportNamedDeclaration(mutationDocConst));
122
- const inputFields = scalarFields
123
- .filter((f) => !isAutoGeneratedField(f.name, pkFieldNames))
124
- .map((f) => {
125
- const prop = t.tsPropertySignature(t.identifier(f.name), t.tsTypeAnnotation(t.tsUnionType([
126
- t.tsTypeReference(t.identifier((0, utils_1.fieldTypeToTs)(f.type))),
127
- t.tsNullKeyword(),
128
- ])));
129
- prop.optional = true;
130
- return prop;
131
- });
132
- const createInputInterface = t.tsInterfaceDeclaration(t.identifier(`${typeName}CreateInput`), null, null, t.tsInterfaceBody(inputFields));
133
- (0, babel_ast_1.addJSDocComment)(createInputInterface, [`Input type for creating a ${typeName}`]);
134
- statements.push(createInputInterface);
135
- const variablesInterfaceBody = t.tsInterfaceBody([
136
- t.tsPropertySignature(t.identifier('input'), t.tsTypeAnnotation(t.tsTypeLiteral([
137
- t.tsPropertySignature(t.identifier((0, utils_1.lcFirst)(typeName)), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${typeName}CreateInput`)))),
138
- ]))),
139
- ]);
140
- const variablesInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationVariables`), null, null, variablesInterfaceBody);
141
- statements.push(t.exportNamedDeclaration(variablesInterface));
142
- const resultInterfaceBody = t.tsInterfaceBody([
143
- t.tsPropertySignature(t.identifier(mutationName), t.tsTypeAnnotation(t.tsTypeLiteral([
144
- t.tsPropertySignature(t.identifier(singularName), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(typeName)))),
145
- ]))),
146
- ]);
147
- const resultInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationResult`), null, null, resultInterfaceBody);
148
- statements.push(t.exportNamedDeclaration(resultInterface));
149
- const hookBodyStatements = [];
150
- hookBodyStatements.push(t.variableDeclaration('const', [
151
- t.variableDeclarator(t.identifier('queryClient'), t.callExpression(t.identifier('useQueryClient'), [])),
86
+ // Imports
87
+ statements.push((0, hooks_ast_1.createImportDeclaration)('@tanstack/react-query', [
88
+ 'useMutation',
89
+ 'useQueryClient',
152
90
  ]));
153
- const mutationOptions = [];
91
+ statements.push((0, hooks_ast_1.createImportDeclaration)('@tanstack/react-query', ['UseMutationOptions', 'UseMutationResult'], true));
92
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../client', ['getClient']));
93
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../selection', ['buildSelectionArgs']));
94
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../selection', ['SelectionConfig'], true));
154
95
  if (useCentralizedKeys) {
155
- mutationOptions.push(t.objectProperty(t.identifier('mutationKey'), t.callExpression(t.memberExpression(t.identifier(mutationKeysName), t.identifier('create')), [])));
96
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../query-keys', [keysName]));
97
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../mutation-keys', [mutationKeysName]));
156
98
  }
157
- mutationOptions.push(t.objectProperty(t.identifier('mutationFn'), t.arrowFunctionExpression([(0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationVariables`)))], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${mutationName}MutationDocument`), t.identifier('variables')], [
158
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationResult`)),
159
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationVariables`)),
160
- ]))));
161
- const invalidateQueryKey = useCentralizedKeys
162
- ? t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('lists')), [])
163
- : t.arrayExpression([t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('list')]);
164
- mutationOptions.push(t.objectProperty(t.identifier('onSuccess'), t.arrowFunctionExpression([], t.blockStatement([
165
- t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), [t.objectExpression([t.objectProperty(t.identifier('queryKey'), invalidateQueryKey)])])),
166
- ]))));
167
- mutationOptions.push(t.spreadElement(t.identifier('options')));
168
- hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)])));
169
- const optionsTypeStr = `Omit<UseMutationOptions<${(0, utils_1.ucFirst)(mutationName)}MutationResult, Error, ${(0, utils_1.ucFirst)(mutationName)}MutationVariables>, 'mutationFn'>`;
170
- const optionsParam = t.identifier('options');
171
- optionsParam.optional = true;
172
- optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr)));
173
- const hookFunc = t.functionDeclaration(t.identifier(hookName), [optionsParam], t.blockStatement(hookBodyStatements));
174
- const hookExport = t.exportNamedDeclaration(hookFunc);
175
- (0, babel_ast_1.addJSDocComment)(hookExport, [
99
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/input-types', [selectTypeName, relationTypeName, createInputTypeName], true));
100
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true));
101
+ // Re-exports
102
+ statements.push((0, hooks_ast_1.createTypeReExport)([selectTypeName, relationTypeName, createInputTypeName], '../../orm/input-types'));
103
+ // Variable type: CreateTypeName['singularName']
104
+ const createVarType = t.tsIndexedAccessType((0, hooks_ast_1.typeRef)(createInputTypeName), t.tsLiteralType(t.stringLiteral(singularName)));
105
+ const resultType = (sel) => buildMutationResultType(mutationName, singularName, relationTypeName, sel);
106
+ // Overload 1: with fields
107
+ const o1ParamType = t.tsIntersectionType([
108
+ t.tsTypeLiteral([
109
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(buildFieldsSelectionType((0, hooks_ast_1.sRef)(), selectTypeName))),
110
+ ]),
111
+ (0, hooks_ast_1.useMutationOptionsType)(resultType((0, hooks_ast_1.sRef)()), createVarType),
112
+ ]);
113
+ const o1 = (0, hooks_ast_1.exportDeclareFunction)(hookName, (0, hooks_ast_1.createSTypeParam)(selectTypeName), [(0, hooks_ast_1.createFunctionParam)('params', o1ParamType)], (0, hooks_ast_1.useMutationResultType)(resultType((0, hooks_ast_1.sRef)()), createVarType));
114
+ (0, hooks_ast_1.addJSDocComment)(o1, [
176
115
  `Mutation hook for creating a ${typeName}`,
177
116
  '',
178
117
  '@example',
179
118
  '```tsx',
180
- `const { mutate, isPending } = ${hookName}();`,
181
- '',
182
- 'mutate({',
183
- ' input: {',
184
- ` ${(0, utils_1.lcFirst)(typeName)}: {`,
185
- ' // ... fields',
186
- ' },',
187
- ' },',
119
+ `const { mutate, isPending } = ${hookName}({`,
120
+ ' selection: { fields: { id: true, name: true } },',
188
121
  '});',
122
+ '',
123
+ "mutate({ name: 'New item' });",
189
124
  '```',
190
125
  ]);
191
- statements.push(hookExport);
192
- const code = (0, babel_ast_1.generateCode)(statements);
193
- const content = (0, utils_1.getGeneratedFileHeader)(`Create mutation hook for ${typeName}`) + '\n\n' + code;
126
+ statements.push(o1);
127
+ // Implementation
128
+ const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.selectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName))));
129
+ const implParamType = t.tsIntersectionType([
130
+ t.tsTypeLiteral([implSelProp]),
131
+ (0, hooks_ast_1.omitType)((0, hooks_ast_1.typeRef)('UseMutationOptions', [
132
+ t.tsAnyKeyword(),
133
+ (0, hooks_ast_1.typeRef)('Error'),
134
+ createVarType,
135
+ ]), ['mutationFn']),
136
+ ]);
137
+ const body = [];
138
+ body.push((0, hooks_ast_1.buildSelectionArgsCall)(selectTypeName));
139
+ body.push((0, hooks_ast_1.destructureParamsWithSelection)('mutationOptions'));
140
+ body.push((0, hooks_ast_1.voidStatement)('_selection'));
141
+ body.push((0, hooks_ast_1.constDecl)('queryClient', (0, hooks_ast_1.callExpr)('useQueryClient', [])));
142
+ const mutationKeyExpr = useCentralizedKeys
143
+ ? (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier(mutationKeysName), t.identifier('create')), [])
144
+ : undefined;
145
+ // mutationFn: (data: CreateInput['singular']) => getClient().singular.create({ data, select: ... }).unwrap()
146
+ const dataParam = (0, hooks_ast_1.createFunctionParam)('data', createVarType);
147
+ const mutationFnExpr = t.arrowFunctionExpression([dataParam], (0, hooks_ast_1.getClientCallUnwrap)(singularName, 'create', t.objectExpression([
148
+ (0, hooks_ast_1.shorthandProp)('data'),
149
+ (0, hooks_ast_1.objectProp)('select', t.memberExpression(t.identifier('args'), t.identifier('select'))),
150
+ ])));
151
+ // onSuccess: invalidate lists
152
+ const listKeyExpr = useCentralizedKeys
153
+ ? (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier(keysName), t.identifier('lists')), [])
154
+ : t.arrayExpression([
155
+ t.stringLiteral(typeName.toLowerCase()),
156
+ t.stringLiteral('list'),
157
+ ]);
158
+ const onSuccessFn = t.arrowFunctionExpression([], t.blockStatement([
159
+ t.expressionStatement((0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), [t.objectExpression([(0, hooks_ast_1.objectProp)('queryKey', listKeyExpr)])])),
160
+ ]));
161
+ body.push((0, hooks_ast_1.returnUseMutation)(mutationFnExpr, [
162
+ (0, hooks_ast_1.objectProp)('onSuccess', onSuccessFn),
163
+ (0, hooks_ast_1.spreadObj)(t.identifier('mutationOptions')),
164
+ ], mutationKeyExpr));
165
+ statements.push((0, hooks_ast_1.exportFunction)(hookName, null, [(0, hooks_ast_1.createFunctionParam)('params', implParamType)], body));
194
166
  return {
195
167
  fileName: (0, utils_1.getCreateMutationFileName)(table),
196
- content,
168
+ content: (0, hooks_ast_1.generateHookFileCode)(`Create mutation hook for ${typeName}`, statements),
197
169
  };
198
170
  }
199
171
  function generateUpdateMutationHook(table, options = {}) {
200
- const { reactQueryEnabled = true, enumsFromSchemaTypes = [], useCentralizedKeys = true, hasRelationships = false, tableTypeNames = new Set(), } = options;
201
- if (!reactQueryEnabled) {
172
+ const { reactQueryEnabled = true, useCentralizedKeys = true } = options;
173
+ if (!reactQueryEnabled)
202
174
  return null;
203
- }
204
- if (table.query?.update === null) {
175
+ if (table.query?.update === null)
176
+ return null;
177
+ if (!(0, utils_1.hasValidPrimaryKey)(table))
205
178
  return null;
206
- }
207
- const enumSet = new Set(enumsFromSchemaTypes);
208
179
  const { typeName, singularName } = (0, utils_1.getTableNames)(table);
209
180
  const hookName = (0, utils_1.getUpdateMutationHookName)(table);
210
181
  const mutationName = (0, utils_1.getUpdateMutationName)(table);
211
- const scalarFields = (0, utils_1.getScalarFields)(table);
212
182
  const keysName = `${(0, utils_1.lcFirst)(typeName)}Keys`;
213
183
  const mutationKeysName = `${(0, utils_1.lcFirst)(typeName)}MutationKeys`;
214
- const scopeTypeName = `${typeName}Scope`;
184
+ const selectTypeName = `${typeName}Select`;
185
+ const relationTypeName = `${typeName}WithRelations`;
186
+ const patchTypeName = `${typeName}Patch`;
215
187
  const pkFields = (0, utils_1.getPrimaryKeyInfo)(table);
216
188
  const pkField = pkFields[0];
217
- const pkFieldNames = new Set(pkFields.map((pk) => pk.name));
218
- const usedEnums = new Set();
219
- const usedTableTypes = new Set();
220
- for (const field of scalarFields) {
221
- const cleanType = field.type.gqlType.replace(/!/g, '');
222
- if (enumSet.has(cleanType)) {
223
- usedEnums.add(cleanType);
224
- }
225
- else if (tableTypeNames.has(cleanType) && cleanType !== typeName) {
226
- usedTableTypes.add(cleanType);
227
- }
228
- }
229
- const mutationAST = (0, gql_ast_1.buildUpdateMutationAST)({ table });
230
- const mutationDocument = (0, gql_ast_1.printGraphQL)(mutationAST);
189
+ const pkTsType = pkField.tsType === 'string' ? t.tsStringKeyword() : t.tsNumberKeyword();
231
190
  const statements = [];
232
- const reactQueryImport = t.importDeclaration([
233
- t.importSpecifier(t.identifier('useMutation'), t.identifier('useMutation')),
234
- t.importSpecifier(t.identifier('useQueryClient'), t.identifier('useQueryClient')),
235
- ], t.stringLiteral('@tanstack/react-query'));
236
- statements.push(reactQueryImport);
237
- const reactQueryTypeImport = t.importDeclaration([t.importSpecifier(t.identifier('UseMutationOptions'), t.identifier('UseMutationOptions'))], t.stringLiteral('@tanstack/react-query'));
238
- reactQueryTypeImport.importKind = 'type';
239
- statements.push(reactQueryTypeImport);
240
- const clientImport = t.importDeclaration([t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], t.stringLiteral('../client'));
241
- statements.push(clientImport);
242
- // Import the main type and any other table types used in scalar fields
243
- const allTypesToImportUpdate = [typeName, ...Array.from(usedTableTypes)].sort();
244
- const typesImport = t.importDeclaration(allTypesToImportUpdate.map((t_) => t.importSpecifier(t.identifier(t_), t.identifier(t_))), t.stringLiteral('../types'));
245
- typesImport.importKind = 'type';
246
- statements.push(typesImport);
247
- if (usedEnums.size > 0) {
248
- const enumImport = t.importDeclaration(Array.from(usedEnums).sort().map((e) => t.importSpecifier(t.identifier(e), t.identifier(e))), t.stringLiteral('../schema-types'));
249
- enumImport.importKind = 'type';
250
- statements.push(enumImport);
251
- }
191
+ // Imports
192
+ statements.push((0, hooks_ast_1.createImportDeclaration)('@tanstack/react-query', [
193
+ 'useMutation',
194
+ 'useQueryClient',
195
+ ]));
196
+ statements.push((0, hooks_ast_1.createImportDeclaration)('@tanstack/react-query', ['UseMutationOptions', 'UseMutationResult'], true));
197
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../client', ['getClient']));
198
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../selection', ['buildSelectionArgs']));
199
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../selection', ['SelectionConfig'], true));
252
200
  if (useCentralizedKeys) {
253
- const queryKeyImport = t.importDeclaration([t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], t.stringLiteral('../query-keys'));
254
- statements.push(queryKeyImport);
255
- if (hasRelationships) {
256
- const scopeTypeImport = t.importDeclaration([t.importSpecifier(t.identifier(scopeTypeName), t.identifier(scopeTypeName))], t.stringLiteral('../query-keys'));
257
- scopeTypeImport.importKind = 'type';
258
- statements.push(scopeTypeImport);
259
- }
260
- const mutationKeyImport = t.importDeclaration([t.importSpecifier(t.identifier(mutationKeysName), t.identifier(mutationKeysName))], t.stringLiteral('../mutation-keys'));
261
- statements.push(mutationKeyImport);
201
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../query-keys', [keysName]));
202
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../mutation-keys', [mutationKeysName]));
262
203
  }
263
- const reExportDecl = t.exportNamedDeclaration(null, [t.exportSpecifier(t.identifier(typeName), t.identifier(typeName))], t.stringLiteral('../types'));
264
- reExportDecl.exportKind = 'type';
265
- statements.push(reExportDecl);
266
- const mutationDocConst = t.variableDeclaration('const', [
267
- t.variableDeclarator(t.identifier(`${mutationName}MutationDocument`), t.templateLiteral([t.templateElement({ raw: '\n' + mutationDocument, cooked: '\n' + mutationDocument }, true)], [])),
204
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/input-types', [selectTypeName, relationTypeName, patchTypeName], true));
205
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true));
206
+ // Re-exports
207
+ statements.push((0, hooks_ast_1.createTypeReExport)([selectTypeName, relationTypeName, patchTypeName], '../../orm/input-types'));
208
+ // Variable type: { pkField: type; patch: PatchType }
209
+ const updateVarType = t.tsTypeLiteral([
210
+ t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTsType)),
211
+ t.tsPropertySignature(t.identifier('patch'), t.tsTypeAnnotation((0, hooks_ast_1.typeRef)(patchTypeName))),
268
212
  ]);
269
- statements.push(t.exportNamedDeclaration(mutationDocConst));
270
- const patchFields = scalarFields
271
- .filter((f) => !pkFieldNames.has(f.name))
272
- .map((f) => {
273
- const prop = t.tsPropertySignature(t.identifier(f.name), t.tsTypeAnnotation(t.tsUnionType([
274
- t.tsTypeReference(t.identifier((0, utils_1.fieldTypeToTs)(f.type))),
275
- t.tsNullKeyword(),
276
- ])));
277
- prop.optional = true;
278
- return prop;
279
- });
280
- const patchInterface = t.tsInterfaceDeclaration(t.identifier(`${typeName}Patch`), null, null, t.tsInterfaceBody(patchFields));
281
- (0, babel_ast_1.addJSDocComment)(patchInterface, [`Patch type for updating a ${typeName} - all fields optional`]);
282
- statements.push(patchInterface);
283
- const pkTypeAnnotation = pkField.tsType === 'string'
284
- ? t.tsStringKeyword()
285
- : pkField.tsType === 'number'
286
- ? t.tsNumberKeyword()
287
- : t.tsTypeReference(t.identifier(pkField.tsType));
288
- const variablesInterfaceBody = t.tsInterfaceBody([
289
- t.tsPropertySignature(t.identifier('input'), t.tsTypeAnnotation(t.tsTypeLiteral([
290
- t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTypeAnnotation)),
291
- t.tsPropertySignature(t.identifier('patch'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${typeName}Patch`)))),
292
- ]))),
213
+ const resultType = (sel) => buildMutationResultType(mutationName, singularName, relationTypeName, sel);
214
+ // Overload 1: with fields
215
+ const o1ParamType = t.tsIntersectionType([
216
+ t.tsTypeLiteral([
217
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(buildFieldsSelectionType((0, hooks_ast_1.sRef)(), selectTypeName))),
218
+ ]),
219
+ (0, hooks_ast_1.useMutationOptionsType)(resultType((0, hooks_ast_1.sRef)()), updateVarType),
293
220
  ]);
294
- const variablesInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationVariables`), null, null, variablesInterfaceBody);
295
- statements.push(t.exportNamedDeclaration(variablesInterface));
296
- const resultInterfaceBody = t.tsInterfaceBody([
297
- t.tsPropertySignature(t.identifier(mutationName), t.tsTypeAnnotation(t.tsTypeLiteral([
298
- t.tsPropertySignature(t.identifier(singularName), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(typeName)))),
299
- ]))),
300
- ]);
301
- const resultInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationResult`), null, null, resultInterfaceBody);
302
- statements.push(t.exportNamedDeclaration(resultInterface));
303
- const hookBodyStatements = [];
304
- hookBodyStatements.push(t.variableDeclaration('const', [
305
- t.variableDeclarator(t.identifier('queryClient'), t.callExpression(t.identifier('useQueryClient'), [])),
306
- ]));
307
- const mutationOptions = [];
308
- if (useCentralizedKeys) {
309
- mutationOptions.push(t.objectProperty(t.identifier('mutationKey'), t.memberExpression(t.identifier(mutationKeysName), t.identifier('all'))));
310
- }
311
- mutationOptions.push(t.objectProperty(t.identifier('mutationFn'), t.arrowFunctionExpression([(0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationVariables`)))], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${mutationName}MutationDocument`), t.identifier('variables')], [
312
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationResult`)),
313
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationVariables`)),
314
- ]))));
315
- const detailQueryKey = useCentralizedKeys
316
- ? t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [t.memberExpression(t.memberExpression(t.identifier('variables'), t.identifier('input')), t.identifier(pkField.name))])
317
- : t.arrayExpression([
318
- t.stringLiteral(typeName.toLowerCase()),
319
- t.stringLiteral('detail'),
320
- t.memberExpression(t.memberExpression(t.identifier('variables'), t.identifier('input')), t.identifier(pkField.name)),
321
- ]);
322
- const listQueryKey = useCentralizedKeys
323
- ? t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('lists')), [])
324
- : t.arrayExpression([t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('list')]);
325
- mutationOptions.push(t.objectProperty(t.identifier('onSuccess'), t.arrowFunctionExpression([t.identifier('_'), t.identifier('variables')], t.blockStatement([
326
- t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), [t.objectExpression([t.objectProperty(t.identifier('queryKey'), detailQueryKey)])])),
327
- t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), [t.objectExpression([t.objectProperty(t.identifier('queryKey'), listQueryKey)])])),
328
- ]))));
329
- mutationOptions.push(t.spreadElement(t.identifier('options')));
330
- hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)])));
331
- const optionsTypeStr = `Omit<UseMutationOptions<${(0, utils_1.ucFirst)(mutationName)}MutationResult, Error, ${(0, utils_1.ucFirst)(mutationName)}MutationVariables>, 'mutationFn'>`;
332
- const optionsParam = t.identifier('options');
333
- optionsParam.optional = true;
334
- optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr)));
335
- const hookFunc = t.functionDeclaration(t.identifier(hookName), [optionsParam], t.blockStatement(hookBodyStatements));
336
- const hookExport = t.exportNamedDeclaration(hookFunc);
337
- (0, babel_ast_1.addJSDocComment)(hookExport, [
221
+ const o1 = (0, hooks_ast_1.exportDeclareFunction)(hookName, (0, hooks_ast_1.createSTypeParam)(selectTypeName), [(0, hooks_ast_1.createFunctionParam)('params', o1ParamType)], (0, hooks_ast_1.useMutationResultType)(resultType((0, hooks_ast_1.sRef)()), updateVarType));
222
+ (0, hooks_ast_1.addJSDocComment)(o1, [
338
223
  `Mutation hook for updating a ${typeName}`,
339
224
  '',
340
225
  '@example',
341
226
  '```tsx',
342
- `const { mutate, isPending } = ${hookName}();`,
343
- '',
344
- 'mutate({',
345
- ' input: {',
346
- ` ${pkField.name}: ${pkField.tsType === 'string' ? "'value-here'" : '123'},`,
347
- ' patch: {',
348
- ' // ... fields to update',
349
- ' },',
350
- ' },',
227
+ `const { mutate, isPending } = ${hookName}({`,
228
+ ' selection: { fields: { id: true, name: true } },',
351
229
  '});',
230
+ '',
231
+ `mutate({ ${pkField.name}: 'value-here', patch: { name: 'Updated' } });`,
352
232
  '```',
353
233
  ]);
354
- statements.push(hookExport);
355
- const code = (0, babel_ast_1.generateCode)(statements);
356
- const content = (0, utils_1.getGeneratedFileHeader)(`Update mutation hook for ${typeName}`) + '\n\n' + code;
234
+ statements.push(o1);
235
+ // Implementation
236
+ const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.selectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName))));
237
+ const implParamType = t.tsIntersectionType([
238
+ t.tsTypeLiteral([implSelProp]),
239
+ (0, hooks_ast_1.omitType)((0, hooks_ast_1.typeRef)('UseMutationOptions', [
240
+ t.tsAnyKeyword(),
241
+ (0, hooks_ast_1.typeRef)('Error'),
242
+ updateVarType,
243
+ ]), ['mutationFn']),
244
+ ]);
245
+ const body = [];
246
+ body.push((0, hooks_ast_1.buildSelectionArgsCall)(selectTypeName));
247
+ body.push((0, hooks_ast_1.destructureParamsWithSelection)('mutationOptions'));
248
+ body.push((0, hooks_ast_1.voidStatement)('_selection'));
249
+ body.push((0, hooks_ast_1.constDecl)('queryClient', (0, hooks_ast_1.callExpr)('useQueryClient', [])));
250
+ const mutationKeyExpr = useCentralizedKeys
251
+ ? t.memberExpression(t.identifier(mutationKeysName), t.identifier('all'))
252
+ : undefined;
253
+ // mutationFn: ({ pkField, patch }: { pkField: type; patch: PatchType }) =>
254
+ // getClient().singular.update({ where: { pkField }, data: patch, select: ... }).unwrap()
255
+ const destructParam = t.objectPattern([
256
+ (0, hooks_ast_1.shorthandProp)(pkField.name),
257
+ (0, hooks_ast_1.shorthandProp)('patch'),
258
+ ]);
259
+ destructParam.typeAnnotation = t.tsTypeAnnotation(updateVarType);
260
+ const mutationFnExpr = t.arrowFunctionExpression([destructParam], (0, hooks_ast_1.getClientCallUnwrap)(singularName, 'update', t.objectExpression([
261
+ (0, hooks_ast_1.objectProp)('where', t.objectExpression([(0, hooks_ast_1.shorthandProp)(pkField.name)])),
262
+ (0, hooks_ast_1.objectProp)('data', t.identifier('patch')),
263
+ (0, hooks_ast_1.objectProp)('select', t.memberExpression(t.identifier('args'), t.identifier('select'))),
264
+ ])));
265
+ // onSuccess: invalidate detail and lists
266
+ const detailKeyExpr = useCentralizedKeys
267
+ ? (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [
268
+ t.memberExpression(t.identifier('variables'), t.identifier(pkField.name)),
269
+ ])
270
+ : t.arrayExpression([
271
+ t.stringLiteral(typeName.toLowerCase()),
272
+ t.stringLiteral('detail'),
273
+ t.memberExpression(t.identifier('variables'), t.identifier(pkField.name)),
274
+ ]);
275
+ const listKeyExpr = useCentralizedKeys
276
+ ? (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier(keysName), t.identifier('lists')), [])
277
+ : t.arrayExpression([
278
+ t.stringLiteral(typeName.toLowerCase()),
279
+ t.stringLiteral('list'),
280
+ ]);
281
+ const onSuccessParam = t.identifier('_');
282
+ const variablesParam = t.identifier('variables');
283
+ const onSuccessFn = t.arrowFunctionExpression([onSuccessParam, variablesParam], t.blockStatement([
284
+ t.expressionStatement((0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), [t.objectExpression([(0, hooks_ast_1.objectProp)('queryKey', detailKeyExpr)])])),
285
+ t.expressionStatement((0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), [t.objectExpression([(0, hooks_ast_1.objectProp)('queryKey', listKeyExpr)])])),
286
+ ]));
287
+ body.push((0, hooks_ast_1.returnUseMutation)(mutationFnExpr, [
288
+ (0, hooks_ast_1.objectProp)('onSuccess', onSuccessFn),
289
+ (0, hooks_ast_1.spreadObj)(t.identifier('mutationOptions')),
290
+ ], mutationKeyExpr));
291
+ statements.push((0, hooks_ast_1.exportFunction)(hookName, null, [(0, hooks_ast_1.createFunctionParam)('params', implParamType)], body));
357
292
  return {
358
293
  fileName: (0, utils_1.getUpdateMutationFileName)(table),
359
- content,
294
+ content: (0, hooks_ast_1.generateHookFileCode)(`Update mutation hook for ${typeName}`, statements),
360
295
  };
361
296
  }
362
297
  function generateDeleteMutationHook(table, options = {}) {
363
- const { reactQueryEnabled = true, useCentralizedKeys = true, hasRelationships = false, } = options;
364
- if (!reactQueryEnabled) {
298
+ const { reactQueryEnabled = true, useCentralizedKeys = true } = options;
299
+ if (!reactQueryEnabled)
365
300
  return null;
366
- }
367
- if (table.query?.delete === null) {
301
+ if (table.query?.delete === null)
368
302
  return null;
369
- }
370
- const { typeName } = (0, utils_1.getTableNames)(table);
303
+ if (!(0, utils_1.hasValidPrimaryKey)(table))
304
+ return null;
305
+ const { typeName, singularName } = (0, utils_1.getTableNames)(table);
371
306
  const hookName = (0, utils_1.getDeleteMutationHookName)(table);
372
307
  const mutationName = (0, utils_1.getDeleteMutationName)(table);
373
308
  const keysName = `${(0, utils_1.lcFirst)(typeName)}Keys`;
374
309
  const mutationKeysName = `${(0, utils_1.lcFirst)(typeName)}MutationKeys`;
375
- const scopeTypeName = `${typeName}Scope`;
310
+ const selectTypeName = `${typeName}Select`;
311
+ const relationTypeName = `${typeName}WithRelations`;
376
312
  const pkFields = (0, utils_1.getPrimaryKeyInfo)(table);
377
313
  const pkField = pkFields[0];
378
- const mutationAST = (0, gql_ast_1.buildDeleteMutationAST)({ table });
379
- const mutationDocument = (0, gql_ast_1.printGraphQL)(mutationAST);
314
+ const pkTsType = pkField.tsType === 'string' ? t.tsStringKeyword() : t.tsNumberKeyword();
380
315
  const statements = [];
381
- const reactQueryImport = t.importDeclaration([
382
- t.importSpecifier(t.identifier('useMutation'), t.identifier('useMutation')),
383
- t.importSpecifier(t.identifier('useQueryClient'), t.identifier('useQueryClient')),
384
- ], t.stringLiteral('@tanstack/react-query'));
385
- statements.push(reactQueryImport);
386
- const reactQueryTypeImport = t.importDeclaration([t.importSpecifier(t.identifier('UseMutationOptions'), t.identifier('UseMutationOptions'))], t.stringLiteral('@tanstack/react-query'));
387
- reactQueryTypeImport.importKind = 'type';
388
- statements.push(reactQueryTypeImport);
389
- const clientImport = t.importDeclaration([t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], t.stringLiteral('../client'));
390
- statements.push(clientImport);
316
+ // Imports
317
+ statements.push((0, hooks_ast_1.createImportDeclaration)('@tanstack/react-query', [
318
+ 'useMutation',
319
+ 'useQueryClient',
320
+ ]));
321
+ statements.push((0, hooks_ast_1.createImportDeclaration)('@tanstack/react-query', ['UseMutationOptions', 'UseMutationResult'], true));
322
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../client', ['getClient']));
323
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../selection', ['buildSelectionArgs']));
324
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../selection', ['SelectionConfig'], true));
391
325
  if (useCentralizedKeys) {
392
- const queryKeyImport = t.importDeclaration([t.importSpecifier(t.identifier(keysName), t.identifier(keysName))], t.stringLiteral('../query-keys'));
393
- statements.push(queryKeyImport);
394
- if (hasRelationships) {
395
- const scopeTypeImport = t.importDeclaration([t.importSpecifier(t.identifier(scopeTypeName), t.identifier(scopeTypeName))], t.stringLiteral('../query-keys'));
396
- scopeTypeImport.importKind = 'type';
397
- statements.push(scopeTypeImport);
398
- }
399
- const mutationKeyImport = t.importDeclaration([t.importSpecifier(t.identifier(mutationKeysName), t.identifier(mutationKeysName))], t.stringLiteral('../mutation-keys'));
400
- statements.push(mutationKeyImport);
326
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../query-keys', [keysName]));
327
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../mutation-keys', [mutationKeysName]));
401
328
  }
402
- const mutationDocConst = t.variableDeclaration('const', [
403
- t.variableDeclarator(t.identifier(`${mutationName}MutationDocument`), t.templateLiteral([t.templateElement({ raw: '\n' + mutationDocument, cooked: '\n' + mutationDocument }, true)], [])),
329
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/input-types', [selectTypeName, relationTypeName], true));
330
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true));
331
+ // Re-exports
332
+ statements.push((0, hooks_ast_1.createTypeReExport)([selectTypeName, relationTypeName], '../../orm/input-types'));
333
+ // Variable type: { pkField: type }
334
+ const deleteVarType = t.tsTypeLiteral([
335
+ t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTsType)),
404
336
  ]);
405
- statements.push(t.exportNamedDeclaration(mutationDocConst));
406
- const pkTypeAnnotation = pkField.tsType === 'string'
407
- ? t.tsStringKeyword()
408
- : pkField.tsType === 'number'
409
- ? t.tsNumberKeyword()
410
- : t.tsTypeReference(t.identifier(pkField.tsType));
411
- const variablesInterfaceBody = t.tsInterfaceBody([
412
- t.tsPropertySignature(t.identifier('input'), t.tsTypeAnnotation(t.tsTypeLiteral([
413
- t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTypeAnnotation)),
414
- ]))),
337
+ const resultType = (sel) => buildMutationResultType(mutationName, singularName, relationTypeName, sel);
338
+ // Overload 1: with fields
339
+ const o1ParamType = t.tsIntersectionType([
340
+ t.tsTypeLiteral([
341
+ t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(buildFieldsSelectionType((0, hooks_ast_1.sRef)(), selectTypeName))),
342
+ ]),
343
+ (0, hooks_ast_1.useMutationOptionsType)(resultType((0, hooks_ast_1.sRef)()), deleteVarType),
415
344
  ]);
416
- const variablesInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationVariables`), null, null, variablesInterfaceBody);
417
- statements.push(t.exportNamedDeclaration(variablesInterface));
418
- const clientMutationIdProp = t.tsPropertySignature(t.identifier('clientMutationId'), t.tsTypeAnnotation(t.tsUnionType([t.tsStringKeyword(), t.tsNullKeyword()])));
419
- const resultInterfaceBody = t.tsInterfaceBody([
420
- t.tsPropertySignature(t.identifier(mutationName), t.tsTypeAnnotation(t.tsTypeLiteral([clientMutationIdProp]))),
421
- ]);
422
- const resultInterface = t.tsInterfaceDeclaration(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationResult`), null, null, resultInterfaceBody);
423
- statements.push(t.exportNamedDeclaration(resultInterface));
424
- const hookBodyStatements = [];
425
- hookBodyStatements.push(t.variableDeclaration('const', [
426
- t.variableDeclarator(t.identifier('queryClient'), t.callExpression(t.identifier('useQueryClient'), [])),
427
- ]));
428
- const mutationOptions = [];
429
- if (useCentralizedKeys) {
430
- mutationOptions.push(t.objectProperty(t.identifier('mutationKey'), t.memberExpression(t.identifier(mutationKeysName), t.identifier('all'))));
431
- }
432
- mutationOptions.push(t.objectProperty(t.identifier('mutationFn'), t.arrowFunctionExpression([(0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationVariables`)))], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(`${mutationName}MutationDocument`), t.identifier('variables')], [
433
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationResult`)),
434
- t.tsTypeReference(t.identifier(`${(0, utils_1.ucFirst)(mutationName)}MutationVariables`)),
435
- ]))));
436
- const detailQueryKey = useCentralizedKeys
437
- ? t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [t.memberExpression(t.memberExpression(t.identifier('variables'), t.identifier('input')), t.identifier(pkField.name))])
438
- : t.arrayExpression([
439
- t.stringLiteral(typeName.toLowerCase()),
440
- t.stringLiteral('detail'),
441
- t.memberExpression(t.memberExpression(t.identifier('variables'), t.identifier('input')), t.identifier(pkField.name)),
442
- ]);
443
- const listQueryKey = useCentralizedKeys
444
- ? t.callExpression(t.memberExpression(t.identifier(keysName), t.identifier('lists')), [])
445
- : t.arrayExpression([t.stringLiteral(typeName.toLowerCase()), t.stringLiteral('list')]);
446
- mutationOptions.push(t.objectProperty(t.identifier('onSuccess'), t.arrowFunctionExpression([t.identifier('_'), t.identifier('variables')], t.blockStatement([
447
- t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('removeQueries')), [t.objectExpression([t.objectProperty(t.identifier('queryKey'), detailQueryKey)])])),
448
- t.expressionStatement(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), [t.objectExpression([t.objectProperty(t.identifier('queryKey'), listQueryKey)])])),
449
- ]))));
450
- mutationOptions.push(t.spreadElement(t.identifier('options')));
451
- hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useMutation'), [t.objectExpression(mutationOptions)])));
452
- const optionsTypeStr = `Omit<UseMutationOptions<${(0, utils_1.ucFirst)(mutationName)}MutationResult, Error, ${(0, utils_1.ucFirst)(mutationName)}MutationVariables>, 'mutationFn'>`;
453
- const optionsParam = t.identifier('options');
454
- optionsParam.optional = true;
455
- optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr)));
456
- const hookFunc = t.functionDeclaration(t.identifier(hookName), [optionsParam], t.blockStatement(hookBodyStatements));
457
- const hookExport = t.exportNamedDeclaration(hookFunc);
458
- (0, babel_ast_1.addJSDocComment)(hookExport, [
459
- `Mutation hook for deleting a ${typeName}`,
345
+ const o1 = (0, hooks_ast_1.exportDeclareFunction)(hookName, (0, hooks_ast_1.createSTypeParam)(selectTypeName), [(0, hooks_ast_1.createFunctionParam)('params', o1ParamType)], (0, hooks_ast_1.useMutationResultType)(resultType((0, hooks_ast_1.sRef)()), deleteVarType));
346
+ (0, hooks_ast_1.addJSDocComment)(o1, [
347
+ `Mutation hook for deleting a ${typeName} with typed selection`,
460
348
  '',
461
349
  '@example',
462
350
  '```tsx',
463
- `const { mutate, isPending } = ${hookName}();`,
464
- '',
465
- 'mutate({',
466
- ' input: {',
467
- ` ${pkField.name}: ${pkField.tsType === 'string' ? "'value-to-delete'" : '123'},`,
468
- ' },',
351
+ `const { mutate, isPending } = ${hookName}({`,
352
+ ' selection: { fields: { id: true } },',
469
353
  '});',
354
+ '',
355
+ `mutate({ ${pkField.name}: ${pkField.tsType === 'string' ? "'value-to-delete'" : '123'} });`,
470
356
  '```',
471
357
  ]);
472
- statements.push(hookExport);
473
- const code = (0, babel_ast_1.generateCode)(statements);
474
- const content = (0, utils_1.getGeneratedFileHeader)(`Delete mutation hook for ${typeName}`) + '\n\n' + code;
358
+ statements.push(o1);
359
+ // Implementation
360
+ const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.selectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName))));
361
+ const implParamType = t.tsIntersectionType([
362
+ t.tsTypeLiteral([implSelProp]),
363
+ (0, hooks_ast_1.omitType)((0, hooks_ast_1.typeRef)('UseMutationOptions', [
364
+ t.tsAnyKeyword(),
365
+ (0, hooks_ast_1.typeRef)('Error'),
366
+ deleteVarType,
367
+ ]), ['mutationFn']),
368
+ ]);
369
+ const body = [];
370
+ body.push((0, hooks_ast_1.buildSelectionArgsCall)(selectTypeName));
371
+ body.push((0, hooks_ast_1.destructureParamsWithSelection)('mutationOptions'));
372
+ body.push((0, hooks_ast_1.voidStatement)('_selection'));
373
+ body.push((0, hooks_ast_1.constDecl)('queryClient', (0, hooks_ast_1.callExpr)('useQueryClient', [])));
374
+ const mutationKeyExpr = useCentralizedKeys
375
+ ? t.memberExpression(t.identifier(mutationKeysName), t.identifier('all'))
376
+ : undefined;
377
+ // mutationFn: ({ pkField }: { pkField: type }) =>
378
+ // getClient().singular.delete({ where: { pkField }, select: ... }).unwrap()
379
+ const destructParam = t.objectPattern([(0, hooks_ast_1.shorthandProp)(pkField.name)]);
380
+ destructParam.typeAnnotation = t.tsTypeAnnotation(deleteVarType);
381
+ const mutationFnExpr = t.arrowFunctionExpression([destructParam], (0, hooks_ast_1.getClientCallUnwrap)(singularName, 'delete', t.objectExpression([
382
+ (0, hooks_ast_1.objectProp)('where', t.objectExpression([(0, hooks_ast_1.shorthandProp)(pkField.name)])),
383
+ (0, hooks_ast_1.objectProp)('select', t.memberExpression(t.identifier('args'), t.identifier('select'))),
384
+ ])));
385
+ // onSuccess: remove detail, invalidate lists
386
+ const detailKeyExpr = useCentralizedKeys
387
+ ? (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier(keysName), t.identifier('detail')), [
388
+ t.memberExpression(t.identifier('variables'), t.identifier(pkField.name)),
389
+ ])
390
+ : t.arrayExpression([
391
+ t.stringLiteral(typeName.toLowerCase()),
392
+ t.stringLiteral('detail'),
393
+ t.memberExpression(t.identifier('variables'), t.identifier(pkField.name)),
394
+ ]);
395
+ const listKeyExpr = useCentralizedKeys
396
+ ? (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier(keysName), t.identifier('lists')), [])
397
+ : t.arrayExpression([
398
+ t.stringLiteral(typeName.toLowerCase()),
399
+ t.stringLiteral('list'),
400
+ ]);
401
+ const onSuccessFn = t.arrowFunctionExpression([t.identifier('_'), t.identifier('variables')], t.blockStatement([
402
+ t.expressionStatement((0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier('queryClient'), t.identifier('removeQueries')), [t.objectExpression([(0, hooks_ast_1.objectProp)('queryKey', detailKeyExpr)])])),
403
+ t.expressionStatement((0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier('queryClient'), t.identifier('invalidateQueries')), [t.objectExpression([(0, hooks_ast_1.objectProp)('queryKey', listKeyExpr)])])),
404
+ ]));
405
+ body.push((0, hooks_ast_1.returnUseMutation)(mutationFnExpr, [
406
+ (0, hooks_ast_1.objectProp)('onSuccess', onSuccessFn),
407
+ (0, hooks_ast_1.spreadObj)(t.identifier('mutationOptions')),
408
+ ], mutationKeyExpr));
409
+ statements.push((0, hooks_ast_1.exportFunction)(hookName, null, [(0, hooks_ast_1.createFunctionParam)('params', implParamType)], body));
475
410
  return {
476
411
  fileName: (0, utils_1.getDeleteMutationFileName)(table),
477
- content,
412
+ content: (0, hooks_ast_1.generateHookFileCode)(`Delete mutation hook for ${typeName}`, statements),
478
413
  };
479
414
  }
480
415
  function generateAllMutationHooks(tables, options = {}) {