@constructive-io/graphql-codegen 3.3.2 → 4.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +0 -4
  2. package/cli/index.js +5 -4
  3. package/cli/shared.js +9 -2
  4. package/core/ast.js +6 -5
  5. package/core/codegen/custom-mutations.js +22 -22
  6. package/core/codegen/custom-queries.js +24 -17
  7. package/core/codegen/hooks-ast.d.ts +1 -1
  8. package/core/codegen/hooks-ast.js +22 -5
  9. package/core/codegen/index.d.ts +1 -1
  10. package/core/codegen/mutations.js +16 -12
  11. package/core/codegen/orm/custom-ops-generator.js +37 -3
  12. package/core/codegen/orm/input-types-generator.js +161 -89
  13. package/core/codegen/orm/model-generator.js +72 -73
  14. package/core/codegen/orm/select-types.d.ts +27 -17
  15. package/core/codegen/queries.js +37 -25
  16. package/core/codegen/schema-types-generator.js +21 -0
  17. package/core/codegen/templates/hooks-selection.ts +12 -0
  18. package/core/codegen/templates/query-builder.ts +103 -59
  19. package/core/codegen/templates/select-types.ts +59 -33
  20. package/core/codegen/types.js +26 -0
  21. package/core/codegen/utils.d.ts +1 -1
  22. package/core/codegen/utils.js +1 -1
  23. package/core/custom-ast.js +9 -8
  24. package/core/database/index.js +2 -3
  25. package/core/index.d.ts +2 -0
  26. package/core/index.js +2 -0
  27. package/core/introspect/infer-tables.js +144 -58
  28. package/core/introspect/transform-schema.d.ts +1 -1
  29. package/core/introspect/transform-schema.js +3 -1
  30. package/esm/cli/index.js +5 -4
  31. package/esm/cli/shared.js +9 -2
  32. package/esm/core/ast.js +6 -5
  33. package/esm/core/codegen/custom-mutations.js +23 -23
  34. package/esm/core/codegen/custom-queries.js +25 -18
  35. package/esm/core/codegen/hooks-ast.d.ts +1 -1
  36. package/esm/core/codegen/hooks-ast.js +22 -5
  37. package/esm/core/codegen/index.d.ts +1 -1
  38. package/esm/core/codegen/mutations.js +16 -12
  39. package/esm/core/codegen/orm/custom-ops-generator.js +38 -4
  40. package/esm/core/codegen/orm/input-types-generator.js +163 -91
  41. package/esm/core/codegen/orm/model-generator.js +73 -74
  42. package/esm/core/codegen/orm/select-types.d.ts +27 -17
  43. package/esm/core/codegen/queries.js +37 -25
  44. package/esm/core/codegen/schema-types-generator.js +21 -0
  45. package/esm/core/codegen/types.js +26 -0
  46. package/esm/core/codegen/utils.d.ts +1 -1
  47. package/esm/core/codegen/utils.js +1 -1
  48. package/esm/core/custom-ast.js +9 -8
  49. package/esm/core/database/index.js +2 -3
  50. package/esm/core/index.d.ts +2 -0
  51. package/esm/core/index.js +2 -0
  52. package/esm/core/introspect/infer-tables.js +144 -58
  53. package/esm/core/introspect/transform-schema.d.ts +1 -1
  54. package/esm/core/introspect/transform-schema.js +3 -1
  55. package/esm/generators/field-selector.js +1 -0
  56. package/esm/generators/index.d.ts +3 -0
  57. package/esm/generators/index.js +3 -0
  58. package/esm/generators/mutations.js +4 -4
  59. package/esm/generators/select.js +4 -4
  60. package/esm/index.d.ts +1 -1
  61. package/esm/index.js +1 -1
  62. package/esm/types/schema.d.ts +5 -3
  63. package/generators/field-selector.js +1 -0
  64. package/generators/index.d.ts +3 -0
  65. package/generators/index.js +3 -0
  66. package/generators/mutations.js +3 -3
  67. package/generators/select.js +3 -3
  68. package/index.d.ts +1 -1
  69. package/index.js +1 -1
  70. package/package.json +10 -10
  71. package/types/schema.d.ts +5 -3
package/README.md CHANGED
@@ -183,8 +183,6 @@ interface GraphQLSDKConfigTarget {
183
183
  // Generator flags
184
184
  reactQuery?: boolean; // Generate React Query hooks (output: {output}/hooks)
185
185
  orm?: boolean; // Generate ORM client (output: {output}/orm)
186
- browserCompatible?: boolean; // Generate browser-compatible code (default: true)
187
- // Set to false for Node.js with localhost DNS fix
188
186
 
189
187
  // Table filtering (for CRUD operations from _meta)
190
188
  tables?: {
@@ -685,8 +683,6 @@ Generator Options:
685
683
  -o, --output <dir> Output directory
686
684
  -t, --target <name> Target name (for multi-target configs)
687
685
  -a, --authorization <token> Authorization header value
688
- --browser-compatible Generate browser-compatible code (default: true)
689
- Set to false for Node.js with localhost DNS fix
690
686
  --skip-custom-operations Only generate table CRUD operations
691
687
  --dry-run Preview without writing files
692
688
  -v, --verbose Show detailed output
package/cli/index.js CHANGED
@@ -80,10 +80,11 @@ const commands = async (argv, prompter, _options) => {
80
80
  let hasError = false;
81
81
  for (const name of names) {
82
82
  console.log(`\n[${name}]`);
83
- const result = await (0, generate_1.generate)({
84
- ...targets[name],
85
- ...cliOptions,
86
- });
83
+ const targetConfig = { ...targets[name], ...cliOptions };
84
+ if (targets[name].db && targetConfig.db) {
85
+ targetConfig.db = { ...targets[name].db, ...targetConfig.db };
86
+ }
87
+ const result = await (0, generate_1.generate)(targetConfig);
87
88
  (0, shared_1.printResult)(result);
88
89
  if (!result.success)
89
90
  hasError = true;
package/cli/shared.js CHANGED
@@ -162,7 +162,10 @@ function flattenDbFields(config) {
162
162
  function buildDbConfig(options) {
163
163
  const { schemas, apiNames, ...rest } = options;
164
164
  if (schemas || apiNames) {
165
- return { ...rest, db: { schemas, apiNames } };
165
+ return {
166
+ ...rest,
167
+ db: filterDefined({ schemas, apiNames }),
168
+ };
166
169
  }
167
170
  return rest;
168
171
  }
@@ -202,5 +205,9 @@ function buildGenerateOptions(answers, fileConfig = {}) {
202
205
  const camelized = (0, exports.camelizeArgv)(answers);
203
206
  const normalized = normalizeCodegenListOptions(camelized);
204
207
  const withDb = buildDbConfig(normalized);
205
- return { ...fileConfig, ...withDb };
208
+ const merged = { ...fileConfig, ...withDb };
209
+ if (fileConfig.db && merged.db) {
210
+ merged.db = { ...fileConfig.db, ...merged.db };
211
+ }
212
+ return merged;
206
213
  }
package/core/ast.js CHANGED
@@ -36,6 +36,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.deleteOne = exports.patchOne = exports.createOne = exports.getOne = exports.getMany = exports.getCount = exports.getAll = void 0;
37
37
  exports.getSelections = getSelections;
38
38
  const t = __importStar(require("gql-ast"));
39
+ const graphql_1 = require("graphql");
39
40
  const inflekt_1 = require("inflekt");
40
41
  const custom_ast_1 = require("./custom-ast");
41
42
  const NON_MUTABLE_PROPS = ['createdAt', 'createdBy', 'updatedAt', 'updatedBy'];
@@ -76,7 +77,7 @@ const createGqlMutation = ({ operationName, mutationName, selectArgs, selections
76
77
  return t.document({
77
78
  definitions: [
78
79
  t.operationDefinition({
79
- operation: 'mutation',
80
+ operation: graphql_1.OperationTypeNode.MUTATION,
80
81
  name: mutationName,
81
82
  variableDefinitions,
82
83
  selectionSet: t.selectionSet({ selections: opSel }),
@@ -105,7 +106,7 @@ const getAll = ({ queryName, operationName, selection, }) => {
105
106
  const ast = t.document({
106
107
  definitions: [
107
108
  t.operationDefinition({
108
- operation: 'query',
109
+ operation: graphql_1.OperationTypeNode.QUERY,
109
110
  name: queryName,
110
111
  selectionSet: t.selectionSet({ selections: opSel }),
111
112
  }),
@@ -149,7 +150,7 @@ const getCount = ({ queryName, operationName, query, }) => {
149
150
  const ast = t.document({
150
151
  definitions: [
151
152
  t.operationDefinition({
152
- operation: 'query',
153
+ operation: graphql_1.OperationTypeNode.QUERY,
153
154
  name: queryName,
154
155
  variableDefinitions,
155
156
  selectionSet: t.selectionSet({ selections: opSel }),
@@ -249,7 +250,7 @@ const getMany = ({ builder, queryName, operationName, query, selection, }) => {
249
250
  const ast = t.document({
250
251
  definitions: [
251
252
  t.operationDefinition({
252
- operation: 'query',
253
+ operation: graphql_1.OperationTypeNode.QUERY,
253
254
  name: queryName,
254
255
  variableDefinitions,
255
256
  selectionSet: t.selectionSet({
@@ -306,7 +307,7 @@ const getOne = ({ queryName, operationName, query, selection, }) => {
306
307
  const ast = t.document({
307
308
  definitions: [
308
309
  t.operationDefinition({
309
- operation: 'query',
310
+ operation: graphql_1.OperationTypeNode.QUERY,
310
311
  name: queryName,
311
312
  variableDefinitions,
312
313
  selectionSet: t.selectionSet({ selections: opSel }),
@@ -112,7 +112,7 @@ function generateCustomMutationHookInternal(options) {
112
112
  statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/input-types', inputTypeImports, true));
113
113
  }
114
114
  if (hasSelect) {
115
- statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true));
115
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['InferSelectResult', 'HookStrictSelect', 'StrictSelect'], true));
116
116
  }
117
117
  // Re-exports
118
118
  if (hasArgs) {
@@ -127,39 +127,38 @@ function generateCustomMutationHookInternal(options) {
127
127
  ? (0, hooks_ast_1.typeRef)(varTypeName)
128
128
  : t.tsVoidKeyword();
129
129
  const selectedResultType = (sel) => (0, hooks_ast_1.customSelectResultTypeLiteral)(operation.name, operation.returnType, payloadTypeName, sel);
130
- // Overload 1: with selection.fields
131
- const o1ParamType = t.tsIntersectionType([
130
+ const paramsType = t.tsIntersectionType([
132
131
  t.tsTypeLiteral([
133
132
  t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(t.tsParenthesizedType(t.tsIntersectionType([
134
133
  t.tsTypeLiteral([
135
- t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation((0, hooks_ast_1.sRef)())),
134
+ t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(t.tsIntersectionType([(0, hooks_ast_1.sRef)(), (0, hooks_ast_1.typeRef)(selectTypeName)]))),
135
+ ]),
136
+ (0, hooks_ast_1.typeRef)('HookStrictSelect', [
137
+ (0, hooks_ast_1.typeRef)('NoInfer', [(0, hooks_ast_1.sRef)()]),
138
+ (0, hooks_ast_1.typeRef)(selectTypeName),
136
139
  ]),
137
- (0, hooks_ast_1.typeRef)('StrictSelect', [(0, hooks_ast_1.sRef)(), (0, hooks_ast_1.typeRef)(selectTypeName)]),
138
140
  ])))),
139
141
  ]),
140
142
  (0, hooks_ast_1.useMutationOptionsType)(selectedResultType((0, hooks_ast_1.sRef)()), mutationVarType),
141
143
  ]);
142
- statements.push((0, hooks_ast_1.exportDeclareFunction)(hookName, (0, hooks_ast_1.createSTypeParam)(selectTypeName), [(0, hooks_ast_1.createFunctionParam)('params', o1ParamType)], (0, hooks_ast_1.useMutationResultType)(selectedResultType((0, hooks_ast_1.sRef)()), mutationVarType)));
143
- // Implementation
144
- const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation((0, hooks_ast_1.selectionConfigType)((0, hooks_ast_1.typeRef)(selectTypeName))));
145
- const implParamType = t.tsIntersectionType([
146
- t.tsTypeLiteral([implSelProp]),
147
- (0, hooks_ast_1.omitType)((0, hooks_ast_1.typeRef)('UseMutationOptions', [
148
- t.tsAnyKeyword(),
149
- (0, hooks_ast_1.typeRef)('Error'),
150
- mutationVarType,
151
- ]), ['mutationFn']),
152
- ]);
153
144
  const body = [];
154
- body.push((0, hooks_ast_1.buildSelectionArgsCall)(selectTypeName));
145
+ body.push((0, hooks_ast_1.buildSelectionArgsCall)((0, hooks_ast_1.sRef)()));
155
146
  body.push((0, hooks_ast_1.destructureParamsWithSelection)('mutationOptions'));
156
147
  body.push((0, hooks_ast_1.voidStatement)('_selection'));
157
148
  const mutationKeyExpr = useCentralizedKeys
158
149
  ? (0, hooks_ast_1.callExpr)(t.memberExpression(t.identifier('customMutationKeys'), t.identifier(operation.name)), [])
159
150
  : undefined;
160
- const selectArgExpr = t.objectExpression([
151
+ // Cast to ORM's StrictSelect (not HookStrictSelect) since the ORM
152
+ // method signature requires { select: S } & StrictSelect<S, XxxSelect>.
153
+ // Strictness is already enforced at the hook parameter level.
154
+ const selectArgExpr = t.tsAsExpression(t.objectExpression([
161
155
  (0, hooks_ast_1.objectProp)('select', t.memberExpression(t.identifier('args'), t.identifier('select'))),
162
- ]);
156
+ ]), t.tsIntersectionType([
157
+ t.tsTypeLiteral([
158
+ t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation((0, hooks_ast_1.sRef)())),
159
+ ]),
160
+ (0, hooks_ast_1.typeRef)('StrictSelect', [(0, hooks_ast_1.sRef)(), (0, hooks_ast_1.typeRef)(selectTypeName)]),
161
+ ]));
163
162
  let mutationFnExpr;
164
163
  if (hasArgs) {
165
164
  const variablesParam = (0, hooks_ast_1.createFunctionParam)('variables', (0, hooks_ast_1.typeRef)(varTypeName));
@@ -169,13 +168,14 @@ function generateCustomMutationHookInternal(options) {
169
168
  mutationFnExpr = t.arrowFunctionExpression([], (0, hooks_ast_1.getClientCustomCallUnwrap)('mutation', operation.name, [], selectArgExpr));
170
169
  }
171
170
  body.push((0, hooks_ast_1.returnUseMutation)(mutationFnExpr, [(0, hooks_ast_1.spreadObj)(t.identifier('mutationOptions'))], mutationKeyExpr));
172
- statements.push((0, hooks_ast_1.exportFunction)(hookName, null, [(0, hooks_ast_1.createFunctionParam)('params', implParamType)], body));
171
+ statements.push((0, hooks_ast_1.exportFunction)(hookName, (0, hooks_ast_1.createSTypeParam)(selectTypeName), [(0, hooks_ast_1.createFunctionParam)('params', paramsType)], body, (0, hooks_ast_1.useMutationResultType)(selectedResultType((0, hooks_ast_1.sRef)()), mutationVarType)));
173
172
  }
174
173
  else {
175
174
  // Without select: simple hook (scalar return type)
176
- const resultTypeStr = (0, type_resolver_1.typeRefToTsType)(operation.returnType, tracker);
175
+ (0, type_resolver_1.typeRefToTsType)(operation.returnType, tracker);
176
+ const resultTsType = (0, hooks_ast_1.typeRefToTsTypeAST)(operation.returnType);
177
177
  const resultTypeLiteral = t.tsTypeLiteral([
178
- t.tsPropertySignature(t.identifier(operation.name), t.tsTypeAnnotation((0, hooks_ast_1.typeRef)(resultTypeStr))),
178
+ t.tsPropertySignature(t.identifier(operation.name), t.tsTypeAnnotation(resultTsType)),
179
179
  ]);
180
180
  const mutationVarType = hasArgs
181
181
  ? (0, hooks_ast_1.typeRef)(varTypeName)
@@ -65,10 +65,11 @@ function generateCustomQueryHook(options) {
65
65
  const tracker = (0, type_resolver_1.createTypeTracker)({ tableTypeNames });
66
66
  const hasArgs = operation.args.length > 0;
67
67
  const hasRequiredArgs = operation.args.some((arg) => (0, type_resolver_1.isTypeRequired)(arg.type));
68
- const resultType = (0, type_resolver_1.typeRefToTsType)(operation.returnType, tracker);
68
+ (0, type_resolver_1.typeRefToTsType)(operation.returnType, tracker);
69
69
  for (const arg of operation.args) {
70
70
  (0, type_resolver_1.typeRefToTsType)(arg.type, tracker);
71
71
  }
72
+ const resultTsType = (0, hooks_ast_1.typeRefToTsTypeAST)(operation.returnType);
72
73
  const selectTypeName = (0, select_helpers_1.getSelectTypeName)(operation.returnType);
73
74
  const payloadTypeName = (0, type_resolver_1.getTypeBaseName)(operation.returnType);
74
75
  const hasSelect = !!selectTypeName && !!payloadTypeName;
@@ -106,7 +107,7 @@ function generateCustomQueryHook(options) {
106
107
  statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/input-types', inputTypeImports, true));
107
108
  }
108
109
  if (hasSelect) {
109
- statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true));
110
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['InferSelectResult', 'HookStrictSelect'], true));
110
111
  }
111
112
  // Re-exports
112
113
  if (hasArgs) {
@@ -158,9 +159,12 @@ function generateCustomQueryHook(options) {
158
159
  // Helper to build the fields+StrictSelect intersection type
159
160
  const fieldsSelectionType = (s) => t.tsParenthesizedType(t.tsIntersectionType([
160
161
  t.tsTypeLiteral([
161
- t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(s)),
162
+ t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(t.tsIntersectionType([s, (0, hooks_ast_1.typeRef)(selectTypeName)]))),
163
+ ]),
164
+ (0, hooks_ast_1.typeRef)('HookStrictSelect', [
165
+ (0, hooks_ast_1.typeRef)('NoInfer', [s]),
166
+ (0, hooks_ast_1.typeRef)(selectTypeName),
162
167
  ]),
163
- (0, hooks_ast_1.typeRef)('StrictSelect', [s, (0, hooks_ast_1.typeRef)(selectTypeName)]),
164
168
  ]));
165
169
  const selectedResultType = (sel) => (0, hooks_ast_1.customSelectResultTypeLiteral)(operation.name, operation.returnType, payloadTypeName, sel);
166
170
  // Hook
@@ -178,10 +182,11 @@ function generateCustomQueryHook(options) {
178
182
  // Overload 1: with selection.fields
179
183
  const o1Props = [];
180
184
  if (hasArgs) {
181
- const varType = hasRequiredArgs
182
- ? (0, hooks_ast_1.typeRef)(varTypeName)
183
- : t.tsUnionType([(0, hooks_ast_1.typeRef)(varTypeName), t.tsUndefinedKeyword()]);
184
- o1Props.push(t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(varType)));
185
+ const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation((0, hooks_ast_1.typeRef)(varTypeName)));
186
+ if (!hasRequiredArgs) {
187
+ varProp.optional = true;
188
+ }
189
+ o1Props.push(varProp);
185
190
  }
186
191
  o1Props.push(t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(fieldsSelectionType((0, hooks_ast_1.sRef)()))));
187
192
  const o1ParamType = t.tsIntersectionType([
@@ -267,7 +272,7 @@ function generateCustomQueryHook(options) {
267
272
  else {
268
273
  // Without select: simple hook (scalar return type)
269
274
  const resultTypeLiteral = t.tsTypeLiteral([
270
- t.tsPropertySignature(t.identifier(operation.name), t.tsTypeAnnotation((0, hooks_ast_1.typeRef)(resultType))),
275
+ t.tsPropertySignature(t.identifier(operation.name), t.tsTypeAnnotation(resultTsType)),
271
276
  ]);
272
277
  const optType = (0, hooks_ast_1.omitType)((0, hooks_ast_1.typeRef)('UseQueryOptions', [
273
278
  resultTypeLiteral,
@@ -346,10 +351,11 @@ function generateCustomQueryHook(options) {
346
351
  // Overload 1: with fields
347
352
  const f1Props = [];
348
353
  if (hasArgs) {
349
- const varType = hasRequiredArgs
350
- ? (0, hooks_ast_1.typeRef)(varTypeName)
351
- : t.tsUnionType([(0, hooks_ast_1.typeRef)(varTypeName), t.tsUndefinedKeyword()]);
352
- f1Props.push(t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(varType)));
354
+ const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation((0, hooks_ast_1.typeRef)(varTypeName)));
355
+ if (!hasRequiredArgs) {
356
+ varProp.optional = true;
357
+ }
358
+ f1Props.push(varProp);
353
359
  }
354
360
  f1Props.push(t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(fieldsSelectionType((0, hooks_ast_1.sRef)()))));
355
361
  const f1Decl = (0, hooks_ast_1.exportAsyncDeclareFunction)(fetchFnName, (0, hooks_ast_1.createSTypeParam)(selectTypeName), [(0, hooks_ast_1.createFunctionParam)('params', t.tsTypeLiteral(f1Props))], (0, hooks_ast_1.typeRef)('Promise', [selectedResultType((0, hooks_ast_1.sRef)())]));
@@ -452,10 +458,11 @@ function generateCustomQueryHook(options) {
452
458
  // Overload 1: with fields
453
459
  const p1Props = [];
454
460
  if (hasArgs) {
455
- const varType = hasRequiredArgs
456
- ? (0, hooks_ast_1.typeRef)(varTypeName)
457
- : t.tsUnionType([(0, hooks_ast_1.typeRef)(varTypeName), t.tsUndefinedKeyword()]);
458
- p1Props.push(t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(varType)));
461
+ const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation((0, hooks_ast_1.typeRef)(varTypeName)));
462
+ if (!hasRequiredArgs) {
463
+ varProp.optional = true;
464
+ }
465
+ p1Props.push(varProp);
459
466
  }
460
467
  p1Props.push(t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(fieldsSelectionType((0, hooks_ast_1.sRef)()))));
461
468
  const p1Decl = (0, hooks_ast_1.exportAsyncDeclareFunction)(prefetchFnName, (0, hooks_ast_1.createSTypeParam)(selectTypeName), [
@@ -70,6 +70,6 @@ export declare function generateHookFileCode(headerDescription: string, statemen
70
70
  export declare function scopeTypeLiteral(scopeTypeName: string): t.TSTypeLiteral;
71
71
  export declare function wrapInferSelectResultType(typeRefNode: CleanArgument['type'], payloadTypeName: string, selectType: t.TSType): t.TSType;
72
72
  export declare function typeRefToTsTypeAST(typeRefNode: CleanArgument['type']): t.TSType;
73
- export declare function buildSelectionArgsCall(selectTypeName: string): t.VariableDeclaration;
73
+ export declare function buildSelectionArgsCall(selectType: string | t.TSType): t.VariableDeclaration;
74
74
  export declare function buildListSelectionArgsCall(selectTypeName: string, filterTypeName: string, orderByTypeName: string): t.VariableDeclaration;
75
75
  export declare function customSelectResultTypeLiteral(opName: string, returnType: CleanArgument['type'], payloadTypeName: string, selectType: t.TSType): t.TSTypeLiteral;
@@ -194,7 +194,10 @@ function selectionConfigType(selectType) {
194
194
  return typeRef('SelectionConfig', [selectType]);
195
195
  }
196
196
  function strictSelectType(selectType, shapeTypeName) {
197
- return typeRef('StrictSelect', [selectType, typeRef(shapeTypeName)]);
197
+ return typeRef('HookStrictSelect', [
198
+ typeRef('NoInfer', [selectType]),
199
+ typeRef(shapeTypeName),
200
+ ]);
198
201
  }
199
202
  function withFieldsSelectionType(selectType, selectTypeName) {
200
203
  return t.tsIntersectionType([
@@ -463,8 +466,15 @@ function scopeTypeLiteral(scopeTypeName) {
463
466
  // Type conversion helpers (GraphQL -> AST)
464
467
  // ============================================================================
465
468
  function wrapInferSelectResultType(typeRefNode, payloadTypeName, selectType) {
469
+ const nonNullable = wrapInferSelectResultTypeNonNullable(typeRefNode, payloadTypeName, selectType);
470
+ if (typeRefNode.kind === 'NON_NULL') {
471
+ return nonNullable;
472
+ }
473
+ return t.tsUnionType([nonNullable, t.tsNullKeyword()]);
474
+ }
475
+ function wrapInferSelectResultTypeNonNullable(typeRefNode, payloadTypeName, selectType) {
466
476
  if (typeRefNode.kind === 'NON_NULL' && typeRefNode.ofType) {
467
- return wrapInferSelectResultType(typeRefNode.ofType, payloadTypeName, selectType);
477
+ return wrapInferSelectResultTypeNonNullable(typeRefNode.ofType, payloadTypeName, selectType);
468
478
  }
469
479
  if (typeRefNode.kind === 'LIST' && typeRefNode.ofType) {
470
480
  return t.tsArrayType(wrapInferSelectResultType(typeRefNode.ofType, payloadTypeName, selectType));
@@ -472,8 +482,15 @@ function wrapInferSelectResultType(typeRefNode, payloadTypeName, selectType) {
472
482
  return inferSelectResultType(payloadTypeName, selectType);
473
483
  }
474
484
  function typeRefToTsTypeAST(typeRefNode) {
485
+ const nonNullable = typeRefToTsTypeASTNonNullable(typeRefNode);
486
+ if (typeRefNode.kind === 'NON_NULL') {
487
+ return nonNullable;
488
+ }
489
+ return t.tsUnionType([nonNullable, t.tsNullKeyword()]);
490
+ }
491
+ function typeRefToTsTypeASTNonNullable(typeRefNode) {
475
492
  if (typeRefNode.kind === 'NON_NULL' && typeRefNode.ofType) {
476
- return typeRefToTsTypeAST(typeRefNode.ofType);
493
+ return typeRefToTsTypeASTNonNullable(typeRefNode.ofType);
477
494
  }
478
495
  if (typeRefNode.kind === 'LIST' && typeRefNode.ofType) {
479
496
  return t.tsArrayType(typeRefToTsTypeAST(typeRefNode.ofType));
@@ -490,13 +507,13 @@ function typeRefToTsTypeAST(typeRefNode) {
490
507
  }
491
508
  return typeRef(typeRefNode.name ?? 'unknown');
492
509
  }
493
- function buildSelectionArgsCall(selectTypeName) {
510
+ function buildSelectionArgsCall(selectType) {
494
511
  const call = t.callExpression(t.identifier('buildSelectionArgs'), [
495
512
  t.memberExpression(t.identifier('params'), t.identifier('selection')),
496
513
  ]);
497
514
  // @ts-ignore - Babel types support typeParameters on CallExpression for TS
498
515
  call.typeParameters = t.tsTypeParameterInstantiation([
499
- typeRef(selectTypeName),
516
+ typeof selectType === 'string' ? typeRef(selectType) : selectType,
500
517
  ]);
501
518
  return constDecl('args', call);
502
519
  }
@@ -42,7 +42,7 @@ export interface GenerateResult {
42
42
  };
43
43
  }
44
44
  export interface GenerateOptions {
45
- /** Tables from _meta introspection */
45
+ /** Tables from GraphQL introspection */
46
46
  tables: CleanTable[];
47
47
  /** Custom operations from __schema introspection */
48
48
  customOperations?: {
@@ -65,9 +65,12 @@ function buildMutationResultType(mutationName, singularName, relationTypeName, s
65
65
  function buildFieldsSelectionType(s, selectTypeName) {
66
66
  return t.tsParenthesizedType(t.tsIntersectionType([
67
67
  t.tsTypeLiteral([
68
- t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(s)),
68
+ t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(t.tsIntersectionType([s, (0, hooks_ast_1.typeRef)(selectTypeName)]))),
69
+ ]),
70
+ (0, hooks_ast_1.typeRef)('HookStrictSelect', [
71
+ (0, hooks_ast_1.typeRef)('NoInfer', [s]),
72
+ (0, hooks_ast_1.typeRef)(selectTypeName),
69
73
  ]),
70
- (0, hooks_ast_1.typeRef)('StrictSelect', [s, (0, hooks_ast_1.typeRef)(selectTypeName)]),
71
74
  ]));
72
75
  }
73
76
  function generateCreateMutationHook(table, options = {}) {
@@ -97,7 +100,7 @@ function generateCreateMutationHook(table, options = {}) {
97
100
  statements.push((0, hooks_ast_1.createImportDeclaration)('../mutation-keys', [mutationKeysName]));
98
101
  }
99
102
  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));
103
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['InferSelectResult', 'HookStrictSelect'], true));
101
104
  // Re-exports
102
105
  statements.push((0, hooks_ast_1.createTypeReExport)([selectTypeName, relationTypeName, createInputTypeName], '../../orm/input-types'));
103
106
  // Variable type: CreateTypeName['singularName']
@@ -186,6 +189,7 @@ function generateUpdateMutationHook(table, options = {}) {
186
189
  const patchTypeName = `${typeName}Patch`;
187
190
  const pkFields = (0, utils_1.getPrimaryKeyInfo)(table);
188
191
  const pkField = pkFields[0];
192
+ const patchFieldName = table.query?.patchFieldName ?? (0, utils_1.lcFirst)(typeName) + 'Patch';
189
193
  const pkTsType = pkField.tsType === 'string' ? t.tsStringKeyword() : t.tsNumberKeyword();
190
194
  const statements = [];
191
195
  // Imports
@@ -202,13 +206,13 @@ function generateUpdateMutationHook(table, options = {}) {
202
206
  statements.push((0, hooks_ast_1.createImportDeclaration)('../mutation-keys', [mutationKeysName]));
203
207
  }
204
208
  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));
209
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['InferSelectResult', 'HookStrictSelect'], true));
206
210
  // Re-exports
207
211
  statements.push((0, hooks_ast_1.createTypeReExport)([selectTypeName, relationTypeName, patchTypeName], '../../orm/input-types'));
208
- // Variable type: { pkField: type; patch: PatchType }
212
+ // Variable type: { pkField: type; patchFieldName: PatchType }
209
213
  const updateVarType = t.tsTypeLiteral([
210
214
  t.tsPropertySignature(t.identifier(pkField.name), t.tsTypeAnnotation(pkTsType)),
211
- t.tsPropertySignature(t.identifier('patch'), t.tsTypeAnnotation((0, hooks_ast_1.typeRef)(patchTypeName))),
215
+ t.tsPropertySignature(t.identifier(patchFieldName), t.tsTypeAnnotation((0, hooks_ast_1.typeRef)(patchTypeName))),
212
216
  ]);
213
217
  const resultType = (sel) => buildMutationResultType(mutationName, singularName, relationTypeName, sel);
214
218
  // Overload 1: with fields
@@ -228,7 +232,7 @@ function generateUpdateMutationHook(table, options = {}) {
228
232
  ' selection: { fields: { id: true, name: true } },',
229
233
  '});',
230
234
  '',
231
- `mutate({ ${pkField.name}: 'value-here', patch: { name: 'Updated' } });`,
235
+ `mutate({ ${pkField.name}: 'value-here', ${patchFieldName}: { name: 'Updated' } });`,
232
236
  '```',
233
237
  ]);
234
238
  statements.push(o1);
@@ -250,16 +254,16 @@ function generateUpdateMutationHook(table, options = {}) {
250
254
  const mutationKeyExpr = useCentralizedKeys
251
255
  ? t.memberExpression(t.identifier(mutationKeysName), t.identifier('all'))
252
256
  : undefined;
253
- // mutationFn: ({ pkField, patch }: { pkField: type; patch: PatchType }) =>
254
- // getClient().singular.update({ where: { pkField }, data: patch, select: ... }).unwrap()
257
+ // mutationFn: ({ pkField, patchFieldName }: VarType) =>
258
+ // getClient().singular.update({ where: { pkField }, data: patchFieldName, select: ... }).unwrap()
255
259
  const destructParam = t.objectPattern([
256
260
  (0, hooks_ast_1.shorthandProp)(pkField.name),
257
- (0, hooks_ast_1.shorthandProp)('patch'),
261
+ (0, hooks_ast_1.shorthandProp)(patchFieldName),
258
262
  ]);
259
263
  destructParam.typeAnnotation = t.tsTypeAnnotation(updateVarType);
260
264
  const mutationFnExpr = t.arrowFunctionExpression([destructParam], (0, hooks_ast_1.getClientCallUnwrap)(singularName, 'update', t.objectExpression([
261
265
  (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')),
266
+ (0, hooks_ast_1.objectProp)('data', t.identifier(patchFieldName)),
263
267
  (0, hooks_ast_1.objectProp)('select', t.memberExpression(t.identifier('args'), t.identifier('select'))),
264
268
  ])));
265
269
  // onSuccess: invalidate detail and lists
@@ -327,7 +331,7 @@ function generateDeleteMutationHook(table, options = {}) {
327
331
  statements.push((0, hooks_ast_1.createImportDeclaration)('../mutation-keys', [mutationKeysName]));
328
332
  }
329
333
  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));
334
+ statements.push((0, hooks_ast_1.createImportDeclaration)('../../orm/select-types', ['InferSelectResult', 'HookStrictSelect'], true));
331
335
  // Re-exports
332
336
  statements.push((0, hooks_ast_1.createTypeReExport)([selectTypeName, relationTypeName], '../../orm/input-types'));
333
337
  // Variable type: { pkField: type }
@@ -142,8 +142,15 @@ function parseTypeAnnotation(typeStr) {
142
142
  return t.tsTypeReference(t.identifier(typeStr));
143
143
  }
144
144
  function buildSelectedResultTsType(typeRef, payloadTypeName) {
145
+ const nonNullable = buildSelectedResultTsTypeNonNullable(typeRef, payloadTypeName);
146
+ if (typeRef.kind === 'NON_NULL') {
147
+ return nonNullable;
148
+ }
149
+ return t.tsUnionType([nonNullable, t.tsNullKeyword()]);
150
+ }
151
+ function buildSelectedResultTsTypeNonNullable(typeRef, payloadTypeName) {
145
152
  if (typeRef.kind === 'NON_NULL' && typeRef.ofType) {
146
- return buildSelectedResultTsType(typeRef.ofType, payloadTypeName);
153
+ return buildSelectedResultTsTypeNonNullable(typeRef.ofType, payloadTypeName);
147
154
  }
148
155
  if (typeRef.kind === 'LIST' && typeRef.ofType) {
149
156
  return t.tsArrayType(buildSelectedResultTsType(typeRef.ofType, payloadTypeName));
@@ -153,6 +160,34 @@ function buildSelectedResultTsType(typeRef, payloadTypeName) {
153
160
  t.tsTypeReference(t.identifier('S')),
154
161
  ]));
155
162
  }
163
+ function scalarTsTypeToAst(typeName) {
164
+ if (typeName === 'string')
165
+ return t.tsStringKeyword();
166
+ if (typeName === 'number')
167
+ return t.tsNumberKeyword();
168
+ if (typeName === 'boolean')
169
+ return t.tsBooleanKeyword();
170
+ return t.tsUnknownKeyword();
171
+ }
172
+ function buildRawResultTsType(typeRef) {
173
+ const nonNullable = buildRawResultTsTypeNonNullable(typeRef);
174
+ if (typeRef.kind === 'NON_NULL') {
175
+ return nonNullable;
176
+ }
177
+ return t.tsUnionType([nonNullable, t.tsNullKeyword()]);
178
+ }
179
+ function buildRawResultTsTypeNonNullable(typeRef) {
180
+ if (typeRef.kind === 'NON_NULL' && typeRef.ofType) {
181
+ return buildRawResultTsTypeNonNullable(typeRef.ofType);
182
+ }
183
+ if (typeRef.kind === 'LIST' && typeRef.ofType) {
184
+ return t.tsArrayType(buildRawResultTsType(typeRef.ofType));
185
+ }
186
+ if (typeRef.kind === 'SCALAR') {
187
+ return scalarTsTypeToAst((0, type_resolver_1.scalarToTsType)(typeRef.name ?? 'unknown'));
188
+ }
189
+ return t.tsTypeReference(t.identifier(typeRef.name ?? 'unknown'));
190
+ }
156
191
  function buildOperationMethod(op, operationType) {
157
192
  const hasArgs = op.args.length > 0;
158
193
  const varTypeName = `${(0, utils_1.ucFirst)(op.name)}Variables`;
@@ -235,10 +270,9 @@ function buildOperationMethod(op, operationType) {
235
270
  }
236
271
  else {
237
272
  // Scalar/Connection type: use raw TS type directly
238
- const rawTsType = (0, type_resolver_1.typeRefToTsType)(op.returnType);
239
273
  newExpr.typeParameters = t.tsTypeParameterInstantiation([
240
274
  t.tsTypeLiteral([
241
- t.tsPropertySignature(t.identifier(op.name), t.tsTypeAnnotation(parseTypeAnnotation(rawTsType))),
275
+ t.tsPropertySignature(t.identifier(op.name), t.tsTypeAnnotation(buildRawResultTsType(op.returnType))),
242
276
  ]),
243
277
  ]);
244
278
  }