@k0lyan/nestjs-prisma-graphql-generator 0.2.0 → 0.2.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/dist/generator/generate-grouped-fast.d.ts +9 -0
- package/dist/generator/generate-grouped-fast.d.ts.map +1 -0
- package/dist/generator/generate-grouped-fast.js +689 -0
- package/dist/generator/generate-grouped-fast.js.map +1 -0
- package/dist/generator/generate.js +3 -3
- package/dist/generator/generate.js.map +1 -1
- package/package.json +1 -1
- package/dist/generator/generate-grouped.d.ts +0 -20
- package/dist/generator/generate-grouped.d.ts.map +0 -1
- package/dist/generator/generate-grouped.js +0 -862
- package/dist/generator/generate-grouped.js.map +0 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DMMFDocument } from './dmmf/document';
|
|
2
|
+
import type { GeneratedFile } from './dmmf/types';
|
|
3
|
+
import type { GeneratorConfig } from '../cli/options-parser';
|
|
4
|
+
/**
|
|
5
|
+
* Generate code with files grouped by model using direct string generation
|
|
6
|
+
* (faster than ts-morph AST manipulation)
|
|
7
|
+
*/
|
|
8
|
+
export declare function generateCodeGrouped(dmmf: DMMFDocument, config: GeneratorConfig): Promise<GeneratedFile[]>;
|
|
9
|
+
//# sourceMappingURL=generate-grouped-fast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-grouped-fast.d.ts","sourceRoot":"","sources":["../../src/generator/generate-grouped-fast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAgC,MAAM,cAAc,CAAC;AAChF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAmB7D;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,aAAa,EAAE,CAAC,CAwB1B"}
|
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.generateCodeGrouped = generateCodeGrouped;
|
|
7
|
+
const types_1 = require("./dmmf/types");
|
|
8
|
+
const transformer_1 = require("./dmmf/transformer");
|
|
9
|
+
const pluralize_1 = __importDefault(require("pluralize"));
|
|
10
|
+
/**
|
|
11
|
+
* Generate code with files grouped by model using direct string generation
|
|
12
|
+
* (faster than ts-morph AST manipulation)
|
|
13
|
+
*/
|
|
14
|
+
async function generateCodeGrouped(dmmf, config) {
|
|
15
|
+
const files = [];
|
|
16
|
+
// Pre-compute input type names set for all models
|
|
17
|
+
const inputTypeNames = new Set(dmmf.inputTypes.keys());
|
|
18
|
+
// Generate shared enums
|
|
19
|
+
files.push(...generateEnumsGrouped(dmmf));
|
|
20
|
+
// Generate common types
|
|
21
|
+
files.push(...generateCommonTypesGrouped());
|
|
22
|
+
// Generate helpers
|
|
23
|
+
files.push(generateHelpersGrouped());
|
|
24
|
+
// Generate per-model files
|
|
25
|
+
for (const model of dmmf.models) {
|
|
26
|
+
files.push(...generateModelGrouped(model, dmmf, config, inputTypeNames));
|
|
27
|
+
}
|
|
28
|
+
// Generate root index
|
|
29
|
+
files.push(generateRootIndexGrouped(dmmf, inputTypeNames));
|
|
30
|
+
return files;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Generate all files for a single model
|
|
34
|
+
*/
|
|
35
|
+
function generateModelGrouped(model, dmmf, config, inputTypeNames) {
|
|
36
|
+
const files = [];
|
|
37
|
+
const modelDir = model.name;
|
|
38
|
+
const available = {
|
|
39
|
+
hasWhereInput: inputTypeNames.has(`${model.name}WhereInput`),
|
|
40
|
+
hasWhereUniqueInput: inputTypeNames.has(`${model.name}WhereUniqueInput`),
|
|
41
|
+
hasOrderByInput: inputTypeNames.has(`${model.name}OrderByWithRelationInput`),
|
|
42
|
+
hasCreateInput: inputTypeNames.has(`${model.name}CreateInput`),
|
|
43
|
+
hasCreateManyInput: inputTypeNames.has(`${model.name}CreateManyInput`),
|
|
44
|
+
hasUpdateInput: inputTypeNames.has(`${model.name}UpdateInput`),
|
|
45
|
+
hasUpdateManyInput: inputTypeNames.has(`${model.name}UpdateManyMutationInput`),
|
|
46
|
+
hasScalarWhereWithAggregates: inputTypeNames.has(`${model.name}ScalarWhereWithAggregatesInput`),
|
|
47
|
+
};
|
|
48
|
+
// Skip models with no query capability
|
|
49
|
+
if (!available.hasWhereInput && !available.hasWhereUniqueInput) {
|
|
50
|
+
return files;
|
|
51
|
+
}
|
|
52
|
+
// Generate model.ts
|
|
53
|
+
files.push({
|
|
54
|
+
path: `${modelDir}/model.ts`,
|
|
55
|
+
content: generateModelObjectType(model, dmmf, config),
|
|
56
|
+
});
|
|
57
|
+
// Generate inputs.ts
|
|
58
|
+
const modelInputTypes = getInputTypesForModel(model.name, dmmf);
|
|
59
|
+
if (modelInputTypes.length > 0) {
|
|
60
|
+
files.push({
|
|
61
|
+
path: `${modelDir}/inputs.ts`,
|
|
62
|
+
content: generateModelInputs(model, modelInputTypes, dmmf),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
// Generate args.ts
|
|
66
|
+
files.push({
|
|
67
|
+
path: `${modelDir}/args.ts`,
|
|
68
|
+
content: generateModelArgs(model, available),
|
|
69
|
+
});
|
|
70
|
+
// Generate resolver.ts
|
|
71
|
+
if (config.generateResolvers) {
|
|
72
|
+
files.push({
|
|
73
|
+
path: `${modelDir}/resolver.ts`,
|
|
74
|
+
content: generateModelResolver(model, available),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
// Generate index.ts
|
|
78
|
+
files.push({
|
|
79
|
+
path: `${modelDir}/index.ts`,
|
|
80
|
+
content: generateModelIndex(config, modelInputTypes.length > 0),
|
|
81
|
+
});
|
|
82
|
+
return files;
|
|
83
|
+
}
|
|
84
|
+
function getInputTypesForModel(modelName, dmmf) {
|
|
85
|
+
const result = [];
|
|
86
|
+
for (const [name, inputType] of dmmf.inputTypes) {
|
|
87
|
+
if (name.startsWith(modelName)) {
|
|
88
|
+
result.push(inputType);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return result;
|
|
92
|
+
}
|
|
93
|
+
// ============ Model ObjectType ============
|
|
94
|
+
function generateModelObjectType(model, dmmf, config) {
|
|
95
|
+
const lines = [];
|
|
96
|
+
const hasJson = model.fields.some(f => f.type === 'Json');
|
|
97
|
+
const hasBigInt = model.fields.some(f => f.type === 'BigInt');
|
|
98
|
+
const relationFields = model.fields.filter(f => (0, transformer_1.isRelationField)(f));
|
|
99
|
+
const relatedModels = [...new Set(relationFields.map(f => f.type))].filter(m => m !== model.name);
|
|
100
|
+
const enumFields = model.fields.filter(f => (0, transformer_1.isEnumField)(f));
|
|
101
|
+
const enumTypes = [...new Set(enumFields.map(f => f.type))];
|
|
102
|
+
// Imports
|
|
103
|
+
lines.push(`import { ObjectType, Field, ID, Int, Float } from '@nestjs/graphql';`);
|
|
104
|
+
if (hasJson)
|
|
105
|
+
lines.push(`import { GraphQLJSON } from 'graphql-type-json';`);
|
|
106
|
+
if (hasBigInt)
|
|
107
|
+
lines.push(`import { GraphQLBigInt } from 'graphql-scalars';`);
|
|
108
|
+
if (relatedModels.length > 0) {
|
|
109
|
+
lines.push(`// eslint-disable-next-line @typescript-eslint/no-unused-vars`);
|
|
110
|
+
lines.push(`import type { ${relatedModels.join(', ')} } from '../index';`);
|
|
111
|
+
}
|
|
112
|
+
if (enumTypes.length > 0) {
|
|
113
|
+
lines.push(`import { ${enumTypes.join(', ')} } from '../enums';`);
|
|
114
|
+
}
|
|
115
|
+
lines.push('');
|
|
116
|
+
// Class
|
|
117
|
+
const className = `${config.typePrefix ?? ''}${model.name}${config.typeSuffix ?? ''}`;
|
|
118
|
+
const descOption = model.documentation ? `, { description: '${escapeStr(model.documentation)}' }` : '';
|
|
119
|
+
lines.push(`@ObjectType()${descOption}`);
|
|
120
|
+
lines.push(`export class ${className} {`);
|
|
121
|
+
for (const field of model.fields) {
|
|
122
|
+
lines.push(generateModelField(field, dmmf));
|
|
123
|
+
}
|
|
124
|
+
lines.push('}');
|
|
125
|
+
return lines.join('\n');
|
|
126
|
+
}
|
|
127
|
+
function generateModelField(field, _dmmf) {
|
|
128
|
+
const { graphqlType, tsType } = getFieldTypes(field);
|
|
129
|
+
const isRelation = (0, transformer_1.isRelationField)(field);
|
|
130
|
+
const lines = [];
|
|
131
|
+
let typeArg;
|
|
132
|
+
if (isRelation) {
|
|
133
|
+
typeArg = field.isList
|
|
134
|
+
? `() => [require('../${field.type}/model').${field.type}]`
|
|
135
|
+
: `() => require('../${field.type}/model').${field.type}`;
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
typeArg = field.isList ? `() => [${graphqlType}]` : `() => ${graphqlType}`;
|
|
139
|
+
}
|
|
140
|
+
const options = [];
|
|
141
|
+
if (!field.isRequired && !field.isList)
|
|
142
|
+
options.push('nullable: true');
|
|
143
|
+
if (field.documentation)
|
|
144
|
+
options.push(`description: '${escapeStr(field.documentation)}'`);
|
|
145
|
+
const optionsStr = options.length > 0 ? `, { ${options.join(', ')} }` : '';
|
|
146
|
+
lines.push(` @Field(${typeArg}${optionsStr})`);
|
|
147
|
+
let propertyType = tsType;
|
|
148
|
+
if (field.isList)
|
|
149
|
+
propertyType = `${tsType}[]`;
|
|
150
|
+
if (!field.isRequired)
|
|
151
|
+
propertyType = `${propertyType} | null`;
|
|
152
|
+
const modifier = field.isRequired || field.isList ? '!' : '?';
|
|
153
|
+
lines.push(` ${field.name}${modifier}: ${propertyType};`);
|
|
154
|
+
lines.push('');
|
|
155
|
+
return lines.join('\n');
|
|
156
|
+
}
|
|
157
|
+
function getFieldTypes(field) {
|
|
158
|
+
if (field.isId)
|
|
159
|
+
return { graphqlType: 'ID', tsType: 'string' };
|
|
160
|
+
if ((0, transformer_1.isScalarField)(field)) {
|
|
161
|
+
if (field.type === 'Json')
|
|
162
|
+
return { graphqlType: 'GraphQLJSON', tsType: 'any' };
|
|
163
|
+
return {
|
|
164
|
+
graphqlType: types_1.PRISMA_TO_GRAPHQL_SCALAR[field.type] ?? 'String',
|
|
165
|
+
tsType: types_1.PRISMA_TO_TS_TYPE[field.type] ?? 'string',
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
if ((0, transformer_1.isEnumField)(field))
|
|
169
|
+
return { graphqlType: field.type, tsType: field.type };
|
|
170
|
+
if ((0, transformer_1.isRelationField)(field))
|
|
171
|
+
return { graphqlType: field.type, tsType: field.type };
|
|
172
|
+
return { graphqlType: 'String', tsType: 'string' };
|
|
173
|
+
}
|
|
174
|
+
// ============ Inputs ============
|
|
175
|
+
function generateModelInputs(model, inputTypes, dmmf) {
|
|
176
|
+
const lines = [];
|
|
177
|
+
const hasJson = inputTypes.some(it => it.fields.some(f => f.type === 'Json'));
|
|
178
|
+
const hasBigInt = inputTypes.some(it => it.fields.some(f => f.type === 'BigInt'));
|
|
179
|
+
// Collect enums
|
|
180
|
+
const enumTypes = new Set();
|
|
181
|
+
for (const it of inputTypes) {
|
|
182
|
+
for (const f of it.fields) {
|
|
183
|
+
if (dmmf.isEnum(f.type))
|
|
184
|
+
enumTypes.add(f.type);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
// Imports
|
|
188
|
+
lines.push(`import { InputType, Field, Int, Float } from '@nestjs/graphql';`);
|
|
189
|
+
if (hasJson)
|
|
190
|
+
lines.push(`import { GraphQLJSON } from 'graphql-type-json';`);
|
|
191
|
+
if (hasBigInt)
|
|
192
|
+
lines.push(`import { GraphQLBigInt } from 'graphql-scalars';`);
|
|
193
|
+
if (enumTypes.size > 0)
|
|
194
|
+
lines.push(`import { ${[...enumTypes].join(', ')} } from '../enums';`);
|
|
195
|
+
lines.push('');
|
|
196
|
+
for (const inputType of inputTypes) {
|
|
197
|
+
lines.push(generateInputClass(inputType, dmmf, model.name));
|
|
198
|
+
lines.push('');
|
|
199
|
+
}
|
|
200
|
+
return lines.join('\n');
|
|
201
|
+
}
|
|
202
|
+
function generateInputClass(inputType, dmmf, modelName) {
|
|
203
|
+
const lines = [];
|
|
204
|
+
lines.push(`@InputType()`);
|
|
205
|
+
lines.push(`export class ${inputType.name} {`);
|
|
206
|
+
for (const field of inputType.fields) {
|
|
207
|
+
lines.push(generateInputField(field, dmmf, inputType.name, modelName));
|
|
208
|
+
}
|
|
209
|
+
lines.push('}');
|
|
210
|
+
return lines.join('\n');
|
|
211
|
+
}
|
|
212
|
+
function generateInputField(field, dmmf, currentTypeName, modelName) {
|
|
213
|
+
const { graphqlType, tsType, isInputObjectType } = getInputFieldTypes(field, dmmf);
|
|
214
|
+
const lines = [];
|
|
215
|
+
let typeArg;
|
|
216
|
+
if (isInputObjectType && graphqlType !== currentTypeName) {
|
|
217
|
+
if (graphqlType.startsWith(modelName)) {
|
|
218
|
+
typeArg = field.isList ? `() => [${graphqlType}]` : `() => ${graphqlType}`;
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
const otherModel = graphqlType.replace(/(?:Where|Create|Update|OrderBy|Scalar).*Input$/, '');
|
|
222
|
+
typeArg = field.isList
|
|
223
|
+
? `() => [require('../${otherModel}/inputs').${graphqlType}]`
|
|
224
|
+
: `() => require('../${otherModel}/inputs').${graphqlType}`;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
typeArg = field.isList ? `() => [${graphqlType}]` : `() => ${graphqlType}`;
|
|
229
|
+
}
|
|
230
|
+
const optionsStr = !field.isRequired ? ', { nullable: true }' : '';
|
|
231
|
+
lines.push(` @Field(${typeArg}${optionsStr})`);
|
|
232
|
+
let propertyType = tsType;
|
|
233
|
+
if (field.isList)
|
|
234
|
+
propertyType = `${tsType}[]`;
|
|
235
|
+
if (!field.isRequired)
|
|
236
|
+
propertyType = `${propertyType} | undefined`;
|
|
237
|
+
const modifier = field.isRequired ? '!' : '?';
|
|
238
|
+
lines.push(` ${field.name}${modifier}: ${propertyType};`);
|
|
239
|
+
lines.push('');
|
|
240
|
+
return lines.join('\n');
|
|
241
|
+
}
|
|
242
|
+
function getInputFieldTypes(field, dmmf) {
|
|
243
|
+
if (types_1.PRISMA_TO_GRAPHQL_SCALAR[field.type]) {
|
|
244
|
+
if (field.type === 'Json')
|
|
245
|
+
return { graphqlType: 'GraphQLJSON', tsType: 'any', isInputObjectType: false };
|
|
246
|
+
return {
|
|
247
|
+
graphqlType: types_1.PRISMA_TO_GRAPHQL_SCALAR[field.type] ?? 'String',
|
|
248
|
+
tsType: types_1.PRISMA_TO_TS_TYPE[field.type] ?? 'string',
|
|
249
|
+
isInputObjectType: false,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
if (dmmf.isEnum(field.type))
|
|
253
|
+
return { graphqlType: field.type, tsType: field.type, isInputObjectType: false };
|
|
254
|
+
return { graphqlType: field.type, tsType: 'any', isInputObjectType: true };
|
|
255
|
+
}
|
|
256
|
+
// ============ Args ============
|
|
257
|
+
function generateModelArgs(model, available) {
|
|
258
|
+
const lines = [];
|
|
259
|
+
const m = model.name;
|
|
260
|
+
// Imports
|
|
261
|
+
lines.push(`import { ArgsType, Field, Int } from '@nestjs/graphql';`);
|
|
262
|
+
const inputImports = [];
|
|
263
|
+
if (available.hasWhereInput)
|
|
264
|
+
inputImports.push(`${m}WhereInput`);
|
|
265
|
+
if (available.hasWhereUniqueInput)
|
|
266
|
+
inputImports.push(`${m}WhereUniqueInput`);
|
|
267
|
+
if (available.hasOrderByInput)
|
|
268
|
+
inputImports.push(`${m}OrderByWithRelationInput`);
|
|
269
|
+
if (available.hasCreateInput)
|
|
270
|
+
inputImports.push(`${m}CreateInput`);
|
|
271
|
+
if (available.hasCreateManyInput)
|
|
272
|
+
inputImports.push(`${m}CreateManyInput`);
|
|
273
|
+
if (available.hasUpdateInput)
|
|
274
|
+
inputImports.push(`${m}UpdateInput`);
|
|
275
|
+
if (available.hasUpdateManyInput)
|
|
276
|
+
inputImports.push(`${m}UpdateManyMutationInput`);
|
|
277
|
+
if (available.hasScalarWhereWithAggregates)
|
|
278
|
+
inputImports.push(`${m}ScalarWhereWithAggregatesInput`);
|
|
279
|
+
if (inputImports.length > 0) {
|
|
280
|
+
lines.push(`import { ${inputImports.join(', ')} } from './inputs';`);
|
|
281
|
+
}
|
|
282
|
+
lines.push(`import { ${m}ScalarFieldEnum } from '../enums';`);
|
|
283
|
+
lines.push('');
|
|
284
|
+
// Generate args classes
|
|
285
|
+
if (available.hasWhereInput) {
|
|
286
|
+
lines.push(generateFindManyArgs(m, available));
|
|
287
|
+
lines.push(generateFindFirstArgs(m, available));
|
|
288
|
+
lines.push(generateDeleteManyArgs(m));
|
|
289
|
+
lines.push(generateAggregateArgs(m, available));
|
|
290
|
+
lines.push(generateGroupByArgs(m, available));
|
|
291
|
+
}
|
|
292
|
+
if (available.hasWhereUniqueInput) {
|
|
293
|
+
lines.push(generateFindUniqueArgs(m));
|
|
294
|
+
lines.push(generateDeleteArgs(m));
|
|
295
|
+
}
|
|
296
|
+
if (available.hasCreateInput)
|
|
297
|
+
lines.push(generateCreateArgs(m));
|
|
298
|
+
if (available.hasCreateManyInput)
|
|
299
|
+
lines.push(generateCreateManyArgs(m));
|
|
300
|
+
if (available.hasUpdateInput && available.hasWhereUniqueInput)
|
|
301
|
+
lines.push(generateUpdateArgs(m));
|
|
302
|
+
if (available.hasUpdateManyInput && available.hasWhereInput)
|
|
303
|
+
lines.push(generateUpdateManyArgs(m));
|
|
304
|
+
if (available.hasCreateInput && available.hasUpdateInput && available.hasWhereUniqueInput) {
|
|
305
|
+
lines.push(generateUpsertArgs(m));
|
|
306
|
+
}
|
|
307
|
+
return lines.join('\n');
|
|
308
|
+
}
|
|
309
|
+
function generateFindManyArgs(m, a) {
|
|
310
|
+
return `@ArgsType()
|
|
311
|
+
export class FindMany${m}Args {
|
|
312
|
+
@Field(() => ${m}WhereInput, { nullable: true })
|
|
313
|
+
where?: ${m}WhereInput;
|
|
314
|
+
${a.hasOrderByInput ? `
|
|
315
|
+
@Field(() => [${m}OrderByWithRelationInput], { nullable: true })
|
|
316
|
+
orderBy?: ${m}OrderByWithRelationInput[];
|
|
317
|
+
` : ''}${a.hasWhereUniqueInput ? `
|
|
318
|
+
@Field(() => ${m}WhereUniqueInput, { nullable: true })
|
|
319
|
+
cursor?: ${m}WhereUniqueInput;
|
|
320
|
+
` : ''}
|
|
321
|
+
@Field(() => Int, { nullable: true })
|
|
322
|
+
take?: number;
|
|
323
|
+
|
|
324
|
+
@Field(() => Int, { nullable: true })
|
|
325
|
+
skip?: number;
|
|
326
|
+
|
|
327
|
+
@Field(() => [${m}ScalarFieldEnum], { nullable: true })
|
|
328
|
+
distinct?: ${m}ScalarFieldEnum[];
|
|
329
|
+
}
|
|
330
|
+
`;
|
|
331
|
+
}
|
|
332
|
+
function generateFindFirstArgs(m, a) {
|
|
333
|
+
return `@ArgsType()
|
|
334
|
+
export class FindFirst${m}Args {
|
|
335
|
+
@Field(() => ${m}WhereInput, { nullable: true })
|
|
336
|
+
where?: ${m}WhereInput;
|
|
337
|
+
${a.hasOrderByInput ? `
|
|
338
|
+
@Field(() => [${m}OrderByWithRelationInput], { nullable: true })
|
|
339
|
+
orderBy?: ${m}OrderByWithRelationInput[];
|
|
340
|
+
` : ''}${a.hasWhereUniqueInput ? `
|
|
341
|
+
@Field(() => ${m}WhereUniqueInput, { nullable: true })
|
|
342
|
+
cursor?: ${m}WhereUniqueInput;
|
|
343
|
+
` : ''}
|
|
344
|
+
@Field(() => Int, { nullable: true })
|
|
345
|
+
take?: number;
|
|
346
|
+
|
|
347
|
+
@Field(() => Int, { nullable: true })
|
|
348
|
+
skip?: number;
|
|
349
|
+
|
|
350
|
+
@Field(() => [${m}ScalarFieldEnum], { nullable: true })
|
|
351
|
+
distinct?: ${m}ScalarFieldEnum[];
|
|
352
|
+
}
|
|
353
|
+
`;
|
|
354
|
+
}
|
|
355
|
+
function generateFindUniqueArgs(m) {
|
|
356
|
+
return `@ArgsType()
|
|
357
|
+
export class FindUnique${m}Args {
|
|
358
|
+
@Field(() => ${m}WhereUniqueInput)
|
|
359
|
+
where!: ${m}WhereUniqueInput;
|
|
360
|
+
}
|
|
361
|
+
`;
|
|
362
|
+
}
|
|
363
|
+
function generateCreateArgs(m) {
|
|
364
|
+
return `@ArgsType()
|
|
365
|
+
export class Create${m}Args {
|
|
366
|
+
@Field(() => ${m}CreateInput)
|
|
367
|
+
data!: ${m}CreateInput;
|
|
368
|
+
}
|
|
369
|
+
`;
|
|
370
|
+
}
|
|
371
|
+
function generateCreateManyArgs(m) {
|
|
372
|
+
return `@ArgsType()
|
|
373
|
+
export class CreateMany${m}Args {
|
|
374
|
+
@Field(() => [${m}CreateManyInput])
|
|
375
|
+
data!: ${m}CreateManyInput[];
|
|
376
|
+
}
|
|
377
|
+
`;
|
|
378
|
+
}
|
|
379
|
+
function generateUpdateArgs(m) {
|
|
380
|
+
return `@ArgsType()
|
|
381
|
+
export class Update${m}Args {
|
|
382
|
+
@Field(() => ${m}UpdateInput)
|
|
383
|
+
data!: ${m}UpdateInput;
|
|
384
|
+
|
|
385
|
+
@Field(() => ${m}WhereUniqueInput)
|
|
386
|
+
where!: ${m}WhereUniqueInput;
|
|
387
|
+
}
|
|
388
|
+
`;
|
|
389
|
+
}
|
|
390
|
+
function generateUpdateManyArgs(m) {
|
|
391
|
+
return `@ArgsType()
|
|
392
|
+
export class UpdateMany${m}Args {
|
|
393
|
+
@Field(() => ${m}UpdateManyMutationInput)
|
|
394
|
+
data!: ${m}UpdateManyMutationInput;
|
|
395
|
+
|
|
396
|
+
@Field(() => ${m}WhereInput, { nullable: true })
|
|
397
|
+
where?: ${m}WhereInput;
|
|
398
|
+
}
|
|
399
|
+
`;
|
|
400
|
+
}
|
|
401
|
+
function generateUpsertArgs(m) {
|
|
402
|
+
return `@ArgsType()
|
|
403
|
+
export class Upsert${m}Args {
|
|
404
|
+
@Field(() => ${m}WhereUniqueInput)
|
|
405
|
+
where!: ${m}WhereUniqueInput;
|
|
406
|
+
|
|
407
|
+
@Field(() => ${m}CreateInput)
|
|
408
|
+
create!: ${m}CreateInput;
|
|
409
|
+
|
|
410
|
+
@Field(() => ${m}UpdateInput)
|
|
411
|
+
update!: ${m}UpdateInput;
|
|
412
|
+
}
|
|
413
|
+
`;
|
|
414
|
+
}
|
|
415
|
+
function generateDeleteArgs(m) {
|
|
416
|
+
return `@ArgsType()
|
|
417
|
+
export class Delete${m}Args {
|
|
418
|
+
@Field(() => ${m}WhereUniqueInput)
|
|
419
|
+
where!: ${m}WhereUniqueInput;
|
|
420
|
+
}
|
|
421
|
+
`;
|
|
422
|
+
}
|
|
423
|
+
function generateDeleteManyArgs(m) {
|
|
424
|
+
return `@ArgsType()
|
|
425
|
+
export class DeleteMany${m}Args {
|
|
426
|
+
@Field(() => ${m}WhereInput, { nullable: true })
|
|
427
|
+
where?: ${m}WhereInput;
|
|
428
|
+
}
|
|
429
|
+
`;
|
|
430
|
+
}
|
|
431
|
+
function generateAggregateArgs(m, a) {
|
|
432
|
+
return `@ArgsType()
|
|
433
|
+
export class Aggregate${m}Args {
|
|
434
|
+
@Field(() => ${m}WhereInput, { nullable: true })
|
|
435
|
+
where?: ${m}WhereInput;
|
|
436
|
+
${a.hasOrderByInput ? `
|
|
437
|
+
@Field(() => [${m}OrderByWithRelationInput], { nullable: true })
|
|
438
|
+
orderBy?: ${m}OrderByWithRelationInput[];
|
|
439
|
+
` : ''}${a.hasWhereUniqueInput ? `
|
|
440
|
+
@Field(() => ${m}WhereUniqueInput, { nullable: true })
|
|
441
|
+
cursor?: ${m}WhereUniqueInput;
|
|
442
|
+
` : ''}
|
|
443
|
+
@Field(() => Int, { nullable: true })
|
|
444
|
+
take?: number;
|
|
445
|
+
|
|
446
|
+
@Field(() => Int, { nullable: true })
|
|
447
|
+
skip?: number;
|
|
448
|
+
}
|
|
449
|
+
`;
|
|
450
|
+
}
|
|
451
|
+
function generateGroupByArgs(m, a) {
|
|
452
|
+
return `@ArgsType()
|
|
453
|
+
export class GroupBy${m}Args {
|
|
454
|
+
@Field(() => ${m}WhereInput, { nullable: true })
|
|
455
|
+
where?: ${m}WhereInput;
|
|
456
|
+
${a.hasOrderByInput ? `
|
|
457
|
+
@Field(() => [${m}OrderByWithRelationInput], { nullable: true })
|
|
458
|
+
orderBy?: ${m}OrderByWithRelationInput[];
|
|
459
|
+
` : ''}
|
|
460
|
+
@Field(() => [${m}ScalarFieldEnum])
|
|
461
|
+
by!: ${m}ScalarFieldEnum[];
|
|
462
|
+
${a.hasScalarWhereWithAggregates ? `
|
|
463
|
+
@Field(() => ${m}ScalarWhereWithAggregatesInput, { nullable: true })
|
|
464
|
+
having?: ${m}ScalarWhereWithAggregatesInput;
|
|
465
|
+
` : ''}
|
|
466
|
+
@Field(() => Int, { nullable: true })
|
|
467
|
+
take?: number;
|
|
468
|
+
|
|
469
|
+
@Field(() => Int, { nullable: true })
|
|
470
|
+
skip?: number;
|
|
471
|
+
}
|
|
472
|
+
`;
|
|
473
|
+
}
|
|
474
|
+
// ============ Resolver ============
|
|
475
|
+
function generateModelResolver(model, ops) {
|
|
476
|
+
const m = model.name;
|
|
477
|
+
const lowerName = (0, transformer_1.camelCase)(m);
|
|
478
|
+
const pluralName = (0, pluralize_1.default)(lowerName);
|
|
479
|
+
const isAlreadyPlural = pluralName === lowerName;
|
|
480
|
+
const findManyMethod = isAlreadyPlural ? `findMany${m}` : pluralName;
|
|
481
|
+
const findUniqueMethod = isAlreadyPlural ? `findUnique${m}` : lowerName;
|
|
482
|
+
const lines = [];
|
|
483
|
+
// Imports
|
|
484
|
+
const nestjsImports = ['Resolver', 'Query', 'Args', 'Info', 'Int'];
|
|
485
|
+
if (ops.hasCreateInput || ops.hasUpdateInput)
|
|
486
|
+
nestjsImports.push('Mutation');
|
|
487
|
+
lines.push(`import { ${nestjsImports.join(', ')} } from '@nestjs/graphql';`);
|
|
488
|
+
lines.push(`import { GraphQLResolveInfo } from 'graphql';`);
|
|
489
|
+
lines.push(`import { ${m} } from './model';`);
|
|
490
|
+
lines.push(`import { AffectedRows } from '../common/AffectedRows';`);
|
|
491
|
+
lines.push(`import { transformInfoIntoPrismaArgs, getPrismaFromContext } from '../helpers';`);
|
|
492
|
+
const argsImports = [];
|
|
493
|
+
if (ops.hasWhereInput)
|
|
494
|
+
argsImports.push(`FindMany${m}Args`, `FindFirst${m}Args`, `DeleteMany${m}Args`);
|
|
495
|
+
if (ops.hasWhereUniqueInput)
|
|
496
|
+
argsImports.push(`FindUnique${m}Args`, `Delete${m}Args`);
|
|
497
|
+
if (ops.hasCreateInput)
|
|
498
|
+
argsImports.push(`Create${m}Args`);
|
|
499
|
+
if (ops.hasCreateManyInput)
|
|
500
|
+
argsImports.push(`CreateMany${m}Args`);
|
|
501
|
+
if (ops.hasUpdateInput && ops.hasWhereUniqueInput)
|
|
502
|
+
argsImports.push(`Update${m}Args`);
|
|
503
|
+
if (ops.hasUpdateManyInput && ops.hasWhereInput)
|
|
504
|
+
argsImports.push(`UpdateMany${m}Args`);
|
|
505
|
+
if (ops.hasCreateInput && ops.hasUpdateInput && ops.hasWhereUniqueInput)
|
|
506
|
+
argsImports.push(`Upsert${m}Args`);
|
|
507
|
+
if (argsImports.length > 0) {
|
|
508
|
+
lines.push(`import { ${argsImports.join(', ')} } from './args';`);
|
|
509
|
+
}
|
|
510
|
+
lines.push('');
|
|
511
|
+
lines.push(`@Resolver(() => ${m})`);
|
|
512
|
+
lines.push(`export class ${m}Resolver {`);
|
|
513
|
+
// Queries
|
|
514
|
+
if (ops.hasWhereInput) {
|
|
515
|
+
lines.push(resolverMethod('Query', findManyMethod, `FindMany${m}Args`, `[${m}]`, `Promise<${m}[]>`, lowerName, 'findMany'));
|
|
516
|
+
lines.push(resolverMethod('Query', `findFirst${m}`, `FindFirst${m}Args`, m, `Promise<${m} | null>`, lowerName, 'findFirst', true));
|
|
517
|
+
}
|
|
518
|
+
if (ops.hasWhereUniqueInput) {
|
|
519
|
+
lines.push(resolverMethod('Query', findUniqueMethod, `FindUnique${m}Args`, m, `Promise<${m} | null>`, lowerName, 'findUnique', true));
|
|
520
|
+
}
|
|
521
|
+
// Mutations
|
|
522
|
+
if (ops.hasCreateInput) {
|
|
523
|
+
lines.push(resolverMethod('Mutation', `createOne${m}`, `Create${m}Args`, m, `Promise<${m}>`, lowerName, 'create'));
|
|
524
|
+
}
|
|
525
|
+
if (ops.hasCreateManyInput) {
|
|
526
|
+
lines.push(resolverMethod('Mutation', `createMany${m}`, `CreateMany${m}Args`, 'AffectedRows', 'Promise<AffectedRows>', lowerName, 'createMany'));
|
|
527
|
+
}
|
|
528
|
+
if (ops.hasUpdateInput && ops.hasWhereUniqueInput) {
|
|
529
|
+
lines.push(resolverMethod('Mutation', `updateOne${m}`, `Update${m}Args`, m, `Promise<${m} | null>`, lowerName, 'update', true));
|
|
530
|
+
}
|
|
531
|
+
if (ops.hasUpdateManyInput && ops.hasWhereInput) {
|
|
532
|
+
lines.push(resolverMethod('Mutation', `updateMany${m}`, `UpdateMany${m}Args`, 'AffectedRows', 'Promise<AffectedRows>', lowerName, 'updateMany'));
|
|
533
|
+
}
|
|
534
|
+
if (ops.hasCreateInput && ops.hasUpdateInput && ops.hasWhereUniqueInput) {
|
|
535
|
+
lines.push(resolverMethod('Mutation', `upsertOne${m}`, `Upsert${m}Args`, m, `Promise<${m}>`, lowerName, 'upsert'));
|
|
536
|
+
}
|
|
537
|
+
if (ops.hasWhereUniqueInput) {
|
|
538
|
+
lines.push(resolverMethod('Mutation', `deleteOne${m}`, `Delete${m}Args`, m, `Promise<${m} | null>`, lowerName, 'delete', true));
|
|
539
|
+
}
|
|
540
|
+
if (ops.hasWhereInput) {
|
|
541
|
+
lines.push(resolverMethod('Mutation', `deleteMany${m}`, `DeleteMany${m}Args`, 'AffectedRows', 'Promise<AffectedRows>', lowerName, 'deleteMany'));
|
|
542
|
+
}
|
|
543
|
+
lines.push('}');
|
|
544
|
+
return lines.join('\n');
|
|
545
|
+
}
|
|
546
|
+
function resolverMethod(type, methodName, argsType, graphqlReturn, tsReturn, prismaModel, prismaMethod, nullable = false) {
|
|
547
|
+
const nullableOpt = nullable ? ', { nullable: true }' : '';
|
|
548
|
+
return `
|
|
549
|
+
@${type}(() => ${graphqlReturn}${nullableOpt})
|
|
550
|
+
async ${methodName}(@Args() args: ${argsType}, @Info() info: GraphQLResolveInfo): ${tsReturn} {
|
|
551
|
+
const select = transformInfoIntoPrismaArgs(info);
|
|
552
|
+
const prisma = getPrismaFromContext(info);
|
|
553
|
+
return prisma.${prismaModel}.${prismaMethod}({ ...args, ...select });
|
|
554
|
+
}
|
|
555
|
+
`;
|
|
556
|
+
}
|
|
557
|
+
// ============ Model Index ============
|
|
558
|
+
function generateModelIndex(config, hasInputs) {
|
|
559
|
+
const lines = [];
|
|
560
|
+
lines.push(`export * from './model';`);
|
|
561
|
+
if (hasInputs)
|
|
562
|
+
lines.push(`export * from './inputs';`);
|
|
563
|
+
lines.push(`export * from './args';`);
|
|
564
|
+
if (config.generateResolvers)
|
|
565
|
+
lines.push(`export * from './resolver';`);
|
|
566
|
+
return lines.join('\n');
|
|
567
|
+
}
|
|
568
|
+
// ============ Enums ============
|
|
569
|
+
function generateEnumsGrouped(dmmf) {
|
|
570
|
+
const files = [];
|
|
571
|
+
for (const enumDef of dmmf.enums) {
|
|
572
|
+
const values = enumDef.values.map(v => ` ${v.name} = '${v.name}',`).join('\n');
|
|
573
|
+
const desc = enumDef.documentation ? `'${escapeStr(enumDef.documentation)}'` : 'undefined';
|
|
574
|
+
files.push({
|
|
575
|
+
path: `enums/${enumDef.name}.ts`,
|
|
576
|
+
content: `import { registerEnumType } from '@nestjs/graphql';
|
|
577
|
+
|
|
578
|
+
export enum ${enumDef.name} {
|
|
579
|
+
${values}
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
registerEnumType(${enumDef.name}, {
|
|
583
|
+
name: '${enumDef.name}',
|
|
584
|
+
description: ${desc},
|
|
585
|
+
});
|
|
586
|
+
`,
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
// Index file
|
|
590
|
+
const exports = dmmf.enums.map(e => `export * from './${e.name}';`).join('\n');
|
|
591
|
+
files.push({ path: 'enums/index.ts', content: exports + '\n' });
|
|
592
|
+
return files;
|
|
593
|
+
}
|
|
594
|
+
// ============ Common Types ============
|
|
595
|
+
function generateCommonTypesGrouped() {
|
|
596
|
+
return [
|
|
597
|
+
{
|
|
598
|
+
path: 'common/AffectedRows.ts',
|
|
599
|
+
content: `import { ObjectType, Field, Int } from '@nestjs/graphql';
|
|
600
|
+
|
|
601
|
+
@ObjectType()
|
|
602
|
+
export class AffectedRows {
|
|
603
|
+
@Field(() => Int)
|
|
604
|
+
count!: number;
|
|
605
|
+
}
|
|
606
|
+
`,
|
|
607
|
+
},
|
|
608
|
+
{
|
|
609
|
+
path: 'common/index.ts',
|
|
610
|
+
content: `export * from './AffectedRows';\n`,
|
|
611
|
+
},
|
|
612
|
+
];
|
|
613
|
+
}
|
|
614
|
+
// ============ Helpers ============
|
|
615
|
+
function generateHelpersGrouped() {
|
|
616
|
+
return {
|
|
617
|
+
path: 'helpers.ts',
|
|
618
|
+
content: `import { parseResolveInfo, ResolveTree, FieldsByTypeName } from 'graphql-parse-resolve-info';
|
|
619
|
+
import type { GraphQLResolveInfo } from 'graphql';
|
|
620
|
+
|
|
621
|
+
export function transformInfoIntoPrismaArgs(info: GraphQLResolveInfo): { select?: Record<string, any>; include?: Record<string, any> } {
|
|
622
|
+
const parsedInfo = parseResolveInfo(info) as ResolveTree | null;
|
|
623
|
+
if (!parsedInfo) return {};
|
|
624
|
+
|
|
625
|
+
const select = buildPrismaSelect(parsedInfo.fieldsByTypeName);
|
|
626
|
+
return Object.keys(select).length > 0 ? { select } : {};
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function buildPrismaSelect(fieldsByTypeName: FieldsByTypeName): Record<string, any> {
|
|
630
|
+
const result: Record<string, any> = {};
|
|
631
|
+
|
|
632
|
+
for (const typeName in fieldsByTypeName) {
|
|
633
|
+
const fields = fieldsByTypeName[typeName];
|
|
634
|
+
for (const fieldName in fields) {
|
|
635
|
+
if (fieldName.startsWith('__') || fieldName.startsWith('_count') || fieldName.startsWith('_avg') || fieldName.startsWith('_sum') || fieldName.startsWith('_min') || fieldName.startsWith('_max')) continue;
|
|
636
|
+
|
|
637
|
+
const field = fields[fieldName];
|
|
638
|
+
const nestedFields = field.fieldsByTypeName;
|
|
639
|
+
|
|
640
|
+
if (Object.keys(nestedFields).length > 0) {
|
|
641
|
+
const nestedSelect = buildPrismaSelect(nestedFields);
|
|
642
|
+
result[fieldName] = Object.keys(nestedSelect).length > 0 ? { select: nestedSelect } : true;
|
|
643
|
+
} else {
|
|
644
|
+
result[fieldName] = true;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
return result;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
export function getPrismaFromContext(info: GraphQLResolveInfo): any {
|
|
653
|
+
const context = (info.rootValue as any)?.context ?? info.rootValue;
|
|
654
|
+
const prisma = context?.prisma ?? context?.db;
|
|
655
|
+
if (!prisma) throw new Error('Prisma client not found in context. Please provide prisma in your GraphQL context.');
|
|
656
|
+
return prisma;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
export function mergePrismaSelects(...selects: Array<{ select?: Record<string, any>; include?: Record<string, any> }>): { select?: Record<string, any>; include?: Record<string, any> } {
|
|
660
|
+
const result: { select?: Record<string, any>; include?: Record<string, any> } = {};
|
|
661
|
+
for (const s of selects) {
|
|
662
|
+
if (s.select) result.select = { ...(result.select ?? {}), ...s.select };
|
|
663
|
+
if (s.include) result.include = { ...(result.include ?? {}), ...s.include };
|
|
664
|
+
}
|
|
665
|
+
return result;
|
|
666
|
+
}
|
|
667
|
+
`,
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
// ============ Root Index ============
|
|
671
|
+
function generateRootIndexGrouped(dmmf, inputTypeNames) {
|
|
672
|
+
const lines = [];
|
|
673
|
+
lines.push(`export * from './enums';`);
|
|
674
|
+
lines.push(`export * from './common';`);
|
|
675
|
+
lines.push(`export * from './helpers';`);
|
|
676
|
+
for (const model of dmmf.models) {
|
|
677
|
+
const hasWhereInput = inputTypeNames.has(`${model.name}WhereInput`);
|
|
678
|
+
const hasWhereUniqueInput = inputTypeNames.has(`${model.name}WhereUniqueInput`);
|
|
679
|
+
if (hasWhereInput || hasWhereUniqueInput) {
|
|
680
|
+
lines.push(`export * from './${model.name}';`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
return { path: 'index.ts', content: lines.join('\n') + '\n' };
|
|
684
|
+
}
|
|
685
|
+
// ============ Utilities ============
|
|
686
|
+
function escapeStr(text) {
|
|
687
|
+
return text.replace(/'/g, "\\'").replace(/\n/g, '\\n');
|
|
688
|
+
}
|
|
689
|
+
//# sourceMappingURL=generate-grouped-fast.js.map
|