@constructive-io/graphql-codegen 2.23.3 → 2.24.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.
- package/README.md +147 -2
- package/cli/codegen/babel-ast.d.ts +53 -0
- package/cli/codegen/babel-ast.js +160 -0
- package/cli/codegen/barrel.d.ts +7 -2
- package/cli/codegen/barrel.js +193 -102
- package/cli/codegen/client.js +61 -0
- package/cli/codegen/custom-mutations.d.ts +2 -12
- package/cli/codegen/custom-mutations.js +116 -124
- package/cli/codegen/custom-queries.d.ts +2 -10
- package/cli/codegen/custom-queries.js +236 -335
- package/cli/codegen/gql-ast.js +22 -1
- package/cli/codegen/index.d.ts +3 -0
- package/cli/codegen/index.js +73 -3
- package/cli/codegen/invalidation.d.ts +20 -0
- package/cli/codegen/invalidation.js +327 -0
- package/cli/codegen/mutation-keys.d.ts +24 -0
- package/cli/codegen/mutation-keys.js +247 -0
- package/cli/codegen/mutations.d.ts +5 -19
- package/cli/codegen/mutations.js +385 -383
- package/cli/codegen/orm/barrel.d.ts +1 -1
- package/cli/codegen/orm/barrel.js +42 -10
- package/cli/codegen/orm/client-generator.d.ts +1 -19
- package/cli/codegen/orm/client-generator.js +108 -77
- package/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
- package/cli/codegen/orm/custom-ops-generator.js +192 -235
- package/cli/codegen/orm/input-types-generator.d.ts +13 -1
- package/cli/codegen/orm/input-types-generator.js +425 -147
- package/cli/codegen/orm/model-generator.d.ts +1 -19
- package/cli/codegen/orm/model-generator.js +229 -234
- package/cli/codegen/queries.d.ts +4 -12
- package/cli/codegen/queries.js +660 -390
- package/cli/codegen/query-keys.d.ts +15 -0
- package/cli/codegen/query-keys.js +477 -0
- package/cli/codegen/scalars.js +1 -0
- package/cli/codegen/schema-types-generator.d.ts +15 -10
- package/cli/codegen/schema-types-generator.js +87 -175
- package/cli/codegen/type-resolver.d.ts +1 -30
- package/cli/codegen/type-resolver.js +0 -53
- package/cli/codegen/types.d.ts +1 -1
- package/cli/codegen/types.js +76 -21
- package/cli/codegen/utils.d.ts +6 -0
- package/cli/codegen/utils.js +19 -0
- package/esm/cli/codegen/babel-ast.d.ts +53 -0
- package/esm/cli/codegen/babel-ast.js +111 -0
- package/esm/cli/codegen/barrel.d.ts +7 -2
- package/esm/cli/codegen/barrel.js +161 -103
- package/esm/cli/codegen/client.js +61 -0
- package/esm/cli/codegen/custom-mutations.d.ts +2 -12
- package/esm/cli/codegen/custom-mutations.js +83 -124
- package/esm/cli/codegen/custom-queries.d.ts +2 -10
- package/esm/cli/codegen/custom-queries.js +204 -336
- package/esm/cli/codegen/gql-ast.js +23 -2
- package/esm/cli/codegen/index.d.ts +3 -0
- package/esm/cli/codegen/index.js +69 -2
- package/esm/cli/codegen/invalidation.d.ts +20 -0
- package/esm/cli/codegen/invalidation.js +291 -0
- package/esm/cli/codegen/mutation-keys.d.ts +24 -0
- package/esm/cli/codegen/mutation-keys.js +211 -0
- package/esm/cli/codegen/mutations.d.ts +5 -19
- package/esm/cli/codegen/mutations.js +353 -384
- package/esm/cli/codegen/orm/barrel.d.ts +1 -1
- package/esm/cli/codegen/orm/barrel.js +10 -11
- package/esm/cli/codegen/orm/client-generator.d.ts +1 -19
- package/esm/cli/codegen/orm/client-generator.js +76 -78
- package/esm/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
- package/esm/cli/codegen/orm/custom-ops-generator.js +160 -236
- package/esm/cli/codegen/orm/input-types-generator.d.ts +13 -1
- package/esm/cli/codegen/orm/input-types-generator.js +393 -148
- package/esm/cli/codegen/orm/model-generator.d.ts +1 -19
- package/esm/cli/codegen/orm/model-generator.js +197 -235
- package/esm/cli/codegen/queries.d.ts +4 -12
- package/esm/cli/codegen/queries.js +628 -391
- package/esm/cli/codegen/query-keys.d.ts +15 -0
- package/esm/cli/codegen/query-keys.js +441 -0
- package/esm/cli/codegen/scalars.js +1 -0
- package/esm/cli/codegen/schema-types-generator.d.ts +15 -10
- package/esm/cli/codegen/schema-types-generator.js +54 -175
- package/esm/cli/codegen/type-resolver.d.ts +1 -30
- package/esm/cli/codegen/type-resolver.js +0 -49
- package/esm/cli/codegen/types.d.ts +1 -1
- package/esm/cli/codegen/types.js +44 -22
- package/esm/cli/codegen/utils.d.ts +6 -0
- package/esm/cli/codegen/utils.js +18 -0
- package/esm/types/config.d.ts +75 -0
- package/esm/types/config.js +18 -0
- package/package.json +6 -4
- package/types/config.d.ts +75 -0
- package/types/config.js +19 -1
- package/cli/codegen/ts-ast.d.ts +0 -124
- package/cli/codegen/ts-ast.js +0 -280
- package/esm/cli/codegen/ts-ast.d.ts +0 -124
- package/esm/cli/codegen/ts-ast.js +0 -260
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import * as t from '@babel/types';
|
|
2
|
+
import { generateCode } from '../babel-ast';
|
|
3
|
+
import { ucFirst, getGeneratedFileHeader } from '../utils';
|
|
3
4
|
import { typeRefToTsType, isTypeRequired, getTypeBaseName, } from '../type-resolver';
|
|
4
5
|
import { SCALAR_NAMES } from '../scalars';
|
|
5
6
|
/**
|
|
@@ -61,274 +62,197 @@ function getSelectTypeName(returnType) {
|
|
|
61
62
|
}
|
|
62
63
|
return null;
|
|
63
64
|
}
|
|
65
|
+
function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false) {
|
|
66
|
+
const specifiers = namedImports.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
|
|
67
|
+
const decl = t.importDeclaration(specifiers, t.stringLiteral(moduleSpecifier));
|
|
68
|
+
decl.importKind = typeOnly ? 'type' : 'value';
|
|
69
|
+
return decl;
|
|
70
|
+
}
|
|
71
|
+
function createVariablesInterface(op) {
|
|
72
|
+
if (op.args.length === 0)
|
|
73
|
+
return null;
|
|
74
|
+
const varTypeName = `${ucFirst(op.name)}Variables`;
|
|
75
|
+
const props = op.args.map((arg) => {
|
|
76
|
+
const optional = !isTypeRequired(arg.type);
|
|
77
|
+
const prop = t.tsPropertySignature(t.identifier(arg.name), t.tsTypeAnnotation(parseTypeAnnotation(typeRefToTsType(arg.type))));
|
|
78
|
+
prop.optional = optional;
|
|
79
|
+
return prop;
|
|
80
|
+
});
|
|
81
|
+
const interfaceDecl = t.tsInterfaceDeclaration(t.identifier(varTypeName), null, null, t.tsInterfaceBody(props));
|
|
82
|
+
return t.exportNamedDeclaration(interfaceDecl);
|
|
83
|
+
}
|
|
84
|
+
function parseTypeAnnotation(typeStr) {
|
|
85
|
+
if (typeStr === 'string')
|
|
86
|
+
return t.tsStringKeyword();
|
|
87
|
+
if (typeStr === 'number')
|
|
88
|
+
return t.tsNumberKeyword();
|
|
89
|
+
if (typeStr === 'boolean')
|
|
90
|
+
return t.tsBooleanKeyword();
|
|
91
|
+
if (typeStr === 'null')
|
|
92
|
+
return t.tsNullKeyword();
|
|
93
|
+
if (typeStr === 'undefined')
|
|
94
|
+
return t.tsUndefinedKeyword();
|
|
95
|
+
if (typeStr === 'unknown')
|
|
96
|
+
return t.tsUnknownKeyword();
|
|
97
|
+
if (typeStr.includes(' | ')) {
|
|
98
|
+
const parts = typeStr.split(' | ').map((p) => parseTypeAnnotation(p.trim()));
|
|
99
|
+
return t.tsUnionType(parts);
|
|
100
|
+
}
|
|
101
|
+
if (typeStr.endsWith('[]')) {
|
|
102
|
+
return t.tsArrayType(parseTypeAnnotation(typeStr.slice(0, -2)));
|
|
103
|
+
}
|
|
104
|
+
return t.tsTypeReference(t.identifier(typeStr));
|
|
105
|
+
}
|
|
106
|
+
function buildOperationMethod(op, operationType) {
|
|
107
|
+
const hasArgs = op.args.length > 0;
|
|
108
|
+
const varTypeName = `${ucFirst(op.name)}Variables`;
|
|
109
|
+
const varDefs = op.args.map((arg) => ({
|
|
110
|
+
name: arg.name,
|
|
111
|
+
type: formatGraphQLType(arg.type),
|
|
112
|
+
}));
|
|
113
|
+
const selectTypeName = getSelectTypeName(op.returnType);
|
|
114
|
+
const payloadTypeName = getTypeBaseName(op.returnType);
|
|
115
|
+
// Build the arrow function parameters
|
|
116
|
+
const params = [];
|
|
117
|
+
if (hasArgs) {
|
|
118
|
+
const argsParam = t.identifier('args');
|
|
119
|
+
argsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(varTypeName)));
|
|
120
|
+
params.push(argsParam);
|
|
121
|
+
}
|
|
122
|
+
const optionsParam = t.identifier('options');
|
|
123
|
+
optionsParam.optional = true;
|
|
124
|
+
if (selectTypeName) {
|
|
125
|
+
optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeLiteral([
|
|
126
|
+
(() => {
|
|
127
|
+
const prop = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('S'))));
|
|
128
|
+
prop.optional = true;
|
|
129
|
+
return prop;
|
|
130
|
+
})(),
|
|
131
|
+
]));
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeLiteral([
|
|
135
|
+
(() => {
|
|
136
|
+
const prop = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([t.tsStringKeyword(), t.tsUnknownKeyword()]))));
|
|
137
|
+
prop.optional = true;
|
|
138
|
+
return prop;
|
|
139
|
+
})(),
|
|
140
|
+
]));
|
|
141
|
+
}
|
|
142
|
+
params.push(optionsParam);
|
|
143
|
+
// Build the QueryBuilder call
|
|
144
|
+
const queryBuilderArgs = t.objectExpression([
|
|
145
|
+
t.objectProperty(t.identifier('client'), t.identifier('client'), false, true),
|
|
146
|
+
t.objectProperty(t.identifier('operation'), t.stringLiteral(operationType)),
|
|
147
|
+
t.objectProperty(t.identifier('operationName'), t.stringLiteral(ucFirst(op.name))),
|
|
148
|
+
t.objectProperty(t.identifier('fieldName'), t.stringLiteral(op.name)),
|
|
149
|
+
t.spreadElement(t.callExpression(t.identifier('buildCustomDocument'), [
|
|
150
|
+
t.stringLiteral(operationType),
|
|
151
|
+
t.stringLiteral(ucFirst(op.name)),
|
|
152
|
+
t.stringLiteral(op.name),
|
|
153
|
+
t.optionalMemberExpression(t.identifier('options'), t.identifier('select'), false, true),
|
|
154
|
+
hasArgs ? t.identifier('args') : t.identifier('undefined'),
|
|
155
|
+
t.arrayExpression(varDefs.map((v) => t.objectExpression([
|
|
156
|
+
t.objectProperty(t.identifier('name'), t.stringLiteral(v.name)),
|
|
157
|
+
t.objectProperty(t.identifier('type'), t.stringLiteral(v.type)),
|
|
158
|
+
]))),
|
|
159
|
+
])),
|
|
160
|
+
]);
|
|
161
|
+
const newExpr = t.newExpression(t.identifier('QueryBuilder'), [queryBuilderArgs]);
|
|
162
|
+
// Add type parameter if we have a select type
|
|
163
|
+
if (selectTypeName && payloadTypeName) {
|
|
164
|
+
newExpr.typeParameters = t.tsTypeParameterInstantiation([
|
|
165
|
+
t.tsTypeLiteral([
|
|
166
|
+
t.tsPropertySignature(t.identifier(op.name), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
|
|
167
|
+
t.tsTypeReference(t.identifier(payloadTypeName)),
|
|
168
|
+
t.tsTypeReference(t.identifier('S')),
|
|
169
|
+
])))),
|
|
170
|
+
]),
|
|
171
|
+
]);
|
|
172
|
+
}
|
|
173
|
+
const arrowFunc = t.arrowFunctionExpression(params, newExpr);
|
|
174
|
+
// Add type parameters to arrow function if we have a select type
|
|
175
|
+
if (selectTypeName) {
|
|
176
|
+
const typeParam = t.tsTypeParameter(t.tsTypeReference(t.identifier(selectTypeName)), null, 'S');
|
|
177
|
+
typeParam.const = true;
|
|
178
|
+
arrowFunc.typeParameters = t.tsTypeParameterDeclaration([typeParam]);
|
|
179
|
+
}
|
|
180
|
+
return t.objectProperty(t.identifier(op.name), arrowFunc);
|
|
181
|
+
}
|
|
64
182
|
/**
|
|
65
183
|
* Generate the query/index.ts file for custom query operations
|
|
66
184
|
*/
|
|
67
185
|
export function generateCustomQueryOpsFile(operations) {
|
|
68
|
-
const
|
|
69
|
-
const sourceFile = createSourceFile(project, 'index.ts');
|
|
186
|
+
const statements = [];
|
|
70
187
|
// Collect all input type names and payload type names
|
|
71
188
|
const inputTypeNames = collectInputTypeNamesFromOps(operations);
|
|
72
189
|
const payloadTypeNames = collectPayloadTypeNamesFromOps(operations);
|
|
73
|
-
// Generate Select type names for payloads
|
|
74
190
|
const selectTypeNames = payloadTypeNames.map((p) => `${p}Select`);
|
|
75
|
-
|
|
76
|
-
const allTypeImports = [
|
|
77
|
-
...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames]),
|
|
78
|
-
];
|
|
79
|
-
// Add file header
|
|
80
|
-
sourceFile.insertText(0, createFileHeader('Custom query operations') + '\n\n');
|
|
191
|
+
const allTypeImports = [...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames])];
|
|
81
192
|
// Add imports
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
namedImports: ['OrmClient'],
|
|
86
|
-
}),
|
|
87
|
-
createImport({
|
|
88
|
-
moduleSpecifier: '../query-builder',
|
|
89
|
-
namedImports: ['QueryBuilder', 'buildCustomDocument'],
|
|
90
|
-
}),
|
|
91
|
-
createImport({
|
|
92
|
-
moduleSpecifier: '../select-types',
|
|
93
|
-
typeOnlyNamedImports: ['InferSelectResult'],
|
|
94
|
-
}),
|
|
95
|
-
]);
|
|
96
|
-
// Import types from input-types if we have any
|
|
193
|
+
statements.push(createImportDeclaration('../client', ['OrmClient']));
|
|
194
|
+
statements.push(createImportDeclaration('../query-builder', ['QueryBuilder', 'buildCustomDocument']));
|
|
195
|
+
statements.push(createImportDeclaration('../select-types', ['InferSelectResult'], true));
|
|
97
196
|
if (allTypeImports.length > 0) {
|
|
98
|
-
|
|
99
|
-
createImport({
|
|
100
|
-
moduleSpecifier: '../input-types',
|
|
101
|
-
typeOnlyNamedImports: allTypeImports,
|
|
102
|
-
}),
|
|
103
|
-
]);
|
|
197
|
+
statements.push(createImportDeclaration('../input-types', allTypeImports, true));
|
|
104
198
|
}
|
|
105
|
-
// Generate variable
|
|
106
|
-
sourceFile.addStatements('\n// ============================================================================');
|
|
107
|
-
sourceFile.addStatements('// Variable Types');
|
|
108
|
-
sourceFile.addStatements('// ============================================================================\n');
|
|
199
|
+
// Generate variable interfaces
|
|
109
200
|
for (const op of operations) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
const optional = !isTypeRequired(arg.type);
|
|
114
|
-
return `${arg.name}${optional ? '?' : ''}: ${typeRefToTsType(arg.type)};`;
|
|
115
|
-
});
|
|
116
|
-
sourceFile.addStatements(`export interface ${varTypeName} {\n ${props.join('\n ')}\n}\n`);
|
|
117
|
-
}
|
|
201
|
+
const varInterface = createVariablesInterface(op);
|
|
202
|
+
if (varInterface)
|
|
203
|
+
statements.push(varInterface);
|
|
118
204
|
}
|
|
119
205
|
// Generate factory function
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
type: formatGraphQLType(arg.type),
|
|
130
|
-
}));
|
|
131
|
-
const varDefsJson = JSON.stringify(varDefs);
|
|
132
|
-
// Get Select type for return type
|
|
133
|
-
const selectTypeName = getSelectTypeName(op.returnType);
|
|
134
|
-
const payloadTypeName = getTypeBaseName(op.returnType);
|
|
135
|
-
// Use typed select if available, otherwise fall back to Record<string, unknown>
|
|
136
|
-
const selectType = selectTypeName ?? 'Record<string, unknown>';
|
|
137
|
-
const returnTypePart = selectTypeName && payloadTypeName
|
|
138
|
-
? `{ ${op.name}: InferSelectResult<${payloadTypeName}, S> }`
|
|
139
|
-
: 'unknown';
|
|
140
|
-
if (hasArgs) {
|
|
141
|
-
if (selectTypeName) {
|
|
142
|
-
return `${op.name}: <const S extends ${selectType}>(args: ${varTypeName}, options?: { select?: S }) =>
|
|
143
|
-
new QueryBuilder<${returnTypePart}>({
|
|
144
|
-
client,
|
|
145
|
-
operation: 'query',
|
|
146
|
-
operationName: '${ucFirst(op.name)}',
|
|
147
|
-
fieldName: '${op.name}',
|
|
148
|
-
...buildCustomDocument('query', '${ucFirst(op.name)}', '${op.name}', options?.select, args, ${varDefsJson}),
|
|
149
|
-
})`;
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
return `${op.name}: (args: ${varTypeName}, options?: { select?: Record<string, unknown> }) =>
|
|
153
|
-
new QueryBuilder({
|
|
154
|
-
client,
|
|
155
|
-
operation: 'query',
|
|
156
|
-
operationName: '${ucFirst(op.name)}',
|
|
157
|
-
fieldName: '${op.name}',
|
|
158
|
-
...buildCustomDocument('query', '${ucFirst(op.name)}', '${op.name}', options?.select, args, ${varDefsJson}),
|
|
159
|
-
})`;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
// No args - still provide typed select
|
|
164
|
-
if (selectTypeName) {
|
|
165
|
-
return `${op.name}: <const S extends ${selectType}>(options?: { select?: S }) =>
|
|
166
|
-
new QueryBuilder<${returnTypePart}>({
|
|
167
|
-
client,
|
|
168
|
-
operation: 'query',
|
|
169
|
-
operationName: '${ucFirst(op.name)}',
|
|
170
|
-
fieldName: '${op.name}',
|
|
171
|
-
...buildCustomDocument('query', '${ucFirst(op.name)}', '${op.name}', options?.select, undefined, []),
|
|
172
|
-
})`;
|
|
173
|
-
}
|
|
174
|
-
else {
|
|
175
|
-
return `${op.name}: (options?: { select?: Record<string, unknown> }) =>
|
|
176
|
-
new QueryBuilder({
|
|
177
|
-
client,
|
|
178
|
-
operation: 'query',
|
|
179
|
-
operationName: '${ucFirst(op.name)}',
|
|
180
|
-
fieldName: '${op.name}',
|
|
181
|
-
...buildCustomDocument('query', '${ucFirst(op.name)}', '${op.name}', options?.select, undefined, []),
|
|
182
|
-
})`;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
sourceFile.addFunction({
|
|
187
|
-
name: 'createQueryOperations',
|
|
188
|
-
isExported: true,
|
|
189
|
-
parameters: [{ name: 'client', type: 'OrmClient' }],
|
|
190
|
-
statements: `return {
|
|
191
|
-
${operationMethods.join(',\n ')},
|
|
192
|
-
};`,
|
|
193
|
-
});
|
|
206
|
+
const operationProperties = operations.map((op) => buildOperationMethod(op, 'query'));
|
|
207
|
+
const returnObj = t.objectExpression(operationProperties);
|
|
208
|
+
const returnStmt = t.returnStatement(returnObj);
|
|
209
|
+
const clientParam = t.identifier('client');
|
|
210
|
+
clientParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('OrmClient')));
|
|
211
|
+
const factoryFunc = t.functionDeclaration(t.identifier('createQueryOperations'), [clientParam], t.blockStatement([returnStmt]));
|
|
212
|
+
statements.push(t.exportNamedDeclaration(factoryFunc));
|
|
213
|
+
const header = getGeneratedFileHeader('Custom query operations');
|
|
214
|
+
const code = generateCode(statements);
|
|
194
215
|
return {
|
|
195
216
|
fileName: 'query/index.ts',
|
|
196
|
-
content:
|
|
217
|
+
content: header + '\n' + code,
|
|
197
218
|
};
|
|
198
219
|
}
|
|
199
220
|
/**
|
|
200
221
|
* Generate the mutation/index.ts file for custom mutation operations
|
|
201
222
|
*/
|
|
202
223
|
export function generateCustomMutationOpsFile(operations) {
|
|
203
|
-
const
|
|
204
|
-
const sourceFile = createSourceFile(project, 'index.ts');
|
|
224
|
+
const statements = [];
|
|
205
225
|
// Collect all input type names and payload type names
|
|
206
226
|
const inputTypeNames = collectInputTypeNamesFromOps(operations);
|
|
207
227
|
const payloadTypeNames = collectPayloadTypeNamesFromOps(operations);
|
|
208
|
-
// Generate Select type names for payloads
|
|
209
228
|
const selectTypeNames = payloadTypeNames.map((p) => `${p}Select`);
|
|
210
|
-
|
|
211
|
-
const allTypeImports = [
|
|
212
|
-
...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames]),
|
|
213
|
-
];
|
|
214
|
-
// Add file header
|
|
215
|
-
sourceFile.insertText(0, createFileHeader('Custom mutation operations') + '\n\n');
|
|
229
|
+
const allTypeImports = [...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames])];
|
|
216
230
|
// Add imports
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
namedImports: ['OrmClient'],
|
|
221
|
-
}),
|
|
222
|
-
createImport({
|
|
223
|
-
moduleSpecifier: '../query-builder',
|
|
224
|
-
namedImports: ['QueryBuilder', 'buildCustomDocument'],
|
|
225
|
-
}),
|
|
226
|
-
createImport({
|
|
227
|
-
moduleSpecifier: '../select-types',
|
|
228
|
-
typeOnlyNamedImports: ['InferSelectResult'],
|
|
229
|
-
}),
|
|
230
|
-
]);
|
|
231
|
-
// Import types from input-types if we have any
|
|
231
|
+
statements.push(createImportDeclaration('../client', ['OrmClient']));
|
|
232
|
+
statements.push(createImportDeclaration('../query-builder', ['QueryBuilder', 'buildCustomDocument']));
|
|
233
|
+
statements.push(createImportDeclaration('../select-types', ['InferSelectResult'], true));
|
|
232
234
|
if (allTypeImports.length > 0) {
|
|
233
|
-
|
|
234
|
-
createImport({
|
|
235
|
-
moduleSpecifier: '../input-types',
|
|
236
|
-
typeOnlyNamedImports: allTypeImports,
|
|
237
|
-
}),
|
|
238
|
-
]);
|
|
235
|
+
statements.push(createImportDeclaration('../input-types', allTypeImports, true));
|
|
239
236
|
}
|
|
240
|
-
// Generate variable
|
|
241
|
-
sourceFile.addStatements('\n// ============================================================================');
|
|
242
|
-
sourceFile.addStatements('// Variable Types');
|
|
243
|
-
sourceFile.addStatements('// ============================================================================\n');
|
|
237
|
+
// Generate variable interfaces
|
|
244
238
|
for (const op of operations) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
const optional = !isTypeRequired(arg.type);
|
|
249
|
-
return `${arg.name}${optional ? '?' : ''}: ${typeRefToTsType(arg.type)};`;
|
|
250
|
-
});
|
|
251
|
-
sourceFile.addStatements(`export interface ${varTypeName} {\n ${props.join('\n ')}\n}\n`);
|
|
252
|
-
}
|
|
239
|
+
const varInterface = createVariablesInterface(op);
|
|
240
|
+
if (varInterface)
|
|
241
|
+
statements.push(varInterface);
|
|
253
242
|
}
|
|
254
243
|
// Generate factory function
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
type: formatGraphQLType(arg.type),
|
|
265
|
-
}));
|
|
266
|
-
const varDefsJson = JSON.stringify(varDefs);
|
|
267
|
-
// Get Select type for return type
|
|
268
|
-
const selectTypeName = getSelectTypeName(op.returnType);
|
|
269
|
-
const payloadTypeName = getTypeBaseName(op.returnType);
|
|
270
|
-
// Use typed select if available, otherwise fall back to Record<string, unknown>
|
|
271
|
-
const selectType = selectTypeName ?? 'Record<string, unknown>';
|
|
272
|
-
const returnTypePart = selectTypeName && payloadTypeName
|
|
273
|
-
? `{ ${op.name}: InferSelectResult<${payloadTypeName}, S> }`
|
|
274
|
-
: 'unknown';
|
|
275
|
-
if (hasArgs) {
|
|
276
|
-
if (selectTypeName) {
|
|
277
|
-
return `${op.name}: <const S extends ${selectType}>(args: ${varTypeName}, options?: { select?: S }) =>
|
|
278
|
-
new QueryBuilder<${returnTypePart}>({
|
|
279
|
-
client,
|
|
280
|
-
operation: 'mutation',
|
|
281
|
-
operationName: '${ucFirst(op.name)}',
|
|
282
|
-
fieldName: '${op.name}',
|
|
283
|
-
...buildCustomDocument('mutation', '${ucFirst(op.name)}', '${op.name}', options?.select, args, ${varDefsJson}),
|
|
284
|
-
})`;
|
|
285
|
-
}
|
|
286
|
-
else {
|
|
287
|
-
return `${op.name}: (args: ${varTypeName}, options?: { select?: Record<string, unknown> }) =>
|
|
288
|
-
new QueryBuilder({
|
|
289
|
-
client,
|
|
290
|
-
operation: 'mutation',
|
|
291
|
-
operationName: '${ucFirst(op.name)}',
|
|
292
|
-
fieldName: '${op.name}',
|
|
293
|
-
...buildCustomDocument('mutation', '${ucFirst(op.name)}', '${op.name}', options?.select, args, ${varDefsJson}),
|
|
294
|
-
})`;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
else {
|
|
298
|
-
// No args - still provide typed select
|
|
299
|
-
if (selectTypeName) {
|
|
300
|
-
return `${op.name}: <const S extends ${selectType}>(options?: { select?: S }) =>
|
|
301
|
-
new QueryBuilder<${returnTypePart}>({
|
|
302
|
-
client,
|
|
303
|
-
operation: 'mutation',
|
|
304
|
-
operationName: '${ucFirst(op.name)}',
|
|
305
|
-
fieldName: '${op.name}',
|
|
306
|
-
...buildCustomDocument('mutation', '${ucFirst(op.name)}', '${op.name}', options?.select, undefined, []),
|
|
307
|
-
})`;
|
|
308
|
-
}
|
|
309
|
-
else {
|
|
310
|
-
return `${op.name}: (options?: { select?: Record<string, unknown> }) =>
|
|
311
|
-
new QueryBuilder({
|
|
312
|
-
client,
|
|
313
|
-
operation: 'mutation',
|
|
314
|
-
operationName: '${ucFirst(op.name)}',
|
|
315
|
-
fieldName: '${op.name}',
|
|
316
|
-
...buildCustomDocument('mutation', '${ucFirst(op.name)}', '${op.name}', options?.select, undefined, []),
|
|
317
|
-
})`;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
sourceFile.addFunction({
|
|
322
|
-
name: 'createMutationOperations',
|
|
323
|
-
isExported: true,
|
|
324
|
-
parameters: [{ name: 'client', type: 'OrmClient' }],
|
|
325
|
-
statements: `return {
|
|
326
|
-
${operationMethods.join(',\n ')},
|
|
327
|
-
};`,
|
|
328
|
-
});
|
|
244
|
+
const operationProperties = operations.map((op) => buildOperationMethod(op, 'mutation'));
|
|
245
|
+
const returnObj = t.objectExpression(operationProperties);
|
|
246
|
+
const returnStmt = t.returnStatement(returnObj);
|
|
247
|
+
const clientParam = t.identifier('client');
|
|
248
|
+
clientParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('OrmClient')));
|
|
249
|
+
const factoryFunc = t.functionDeclaration(t.identifier('createMutationOperations'), [clientParam], t.blockStatement([returnStmt]));
|
|
250
|
+
statements.push(t.exportNamedDeclaration(factoryFunc));
|
|
251
|
+
const header = getGeneratedFileHeader('Custom mutation operations');
|
|
252
|
+
const code = generateCode(statements);
|
|
329
253
|
return {
|
|
330
254
|
fileName: 'mutation/index.ts',
|
|
331
|
-
content:
|
|
255
|
+
content: header + '\n' + code,
|
|
332
256
|
};
|
|
333
257
|
}
|
|
334
258
|
/**
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Input types generator for ORM client (Babel AST-based)
|
|
3
|
+
*
|
|
4
|
+
* Generates TypeScript interfaces for:
|
|
5
|
+
* 1. Scalar filter types (StringFilter, IntFilter, UUIDFilter, etc.)
|
|
6
|
+
* 2. Entity interfaces (User, Order, etc.)
|
|
7
|
+
* 3. Table filter types (UserFilter, OrderFilter, etc.)
|
|
8
|
+
* 4. OrderBy enums (UsersOrderBy, OrdersOrderBy, etc.)
|
|
9
|
+
* 5. Input types (LoginInput, CreateUserInput, etc.)
|
|
10
|
+
*
|
|
11
|
+
* Uses Babel AST for robust code generation.
|
|
12
|
+
*/
|
|
1
13
|
import type { TypeRegistry, CleanArgument, CleanTable } from '../../../types/schema';
|
|
2
14
|
export interface GeneratedInputTypesFile {
|
|
3
15
|
fileName: string;
|
|
@@ -16,6 +28,6 @@ export declare function collectPayloadTypeNames(operations: Array<{
|
|
|
16
28
|
returnType: CleanArgument['type'];
|
|
17
29
|
}>): Set<string>;
|
|
18
30
|
/**
|
|
19
|
-
* Generate comprehensive input-types.ts file using
|
|
31
|
+
* Generate comprehensive input-types.ts file using Babel AST
|
|
20
32
|
*/
|
|
21
33
|
export declare function generateInputTypesFile(typeRegistry: TypeRegistry, usedInputTypes: Set<string>, tables?: CleanTable[], usedPayloadTypes?: Set<string>): GeneratedInputTypesFile;
|