prisma-generator-express 1.53.0 → 1.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -12
- package/dist/constants.d.ts +1 -0
- package/dist/generators/generateOperationCore.d.ts +2 -0
- package/dist/generators/generateOperationCore.js +30 -3
- package/dist/generators/generateOperationCore.js.map +1 -1
- package/dist/generators/generateRouter.d.ts +3 -1
- package/dist/generators/generateRouter.js +6 -4
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.d.ts +3 -1
- package/dist/generators/generateRouterFastify.js +6 -4
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.d.ts +3 -1
- package/dist/generators/generateRouterHono.js +6 -3
- package/dist/generators/generateRouterHono.js.map +1 -1
- package/dist/generators/generateUnifiedScalarUI.d.ts +2 -1
- package/dist/generators/generateUnifiedScalarUI.js +13 -10
- package/dist/generators/generateUnifiedScalarUI.js.map +1 -1
- package/dist/index.js +23 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/constants.ts +3 -1
- package/src/copy/autoIncludeRuntime.ts +52 -24
- package/src/copy/buildModelOpenApi.ts +144 -23
- package/src/copy/docsRenderer.ts +121 -95
- package/src/copy/operationRuntime.ts +9 -0
- package/src/copy/routeConfig.express.ts +2 -0
- package/src/copy/routeConfig.fastify.ts +2 -0
- package/src/copy/routeConfig.hono.ts +2 -0
- package/src/copy/routeConfig.ts +2 -0
- package/src/generators/generateOperationCore.ts +43 -3
- package/src/generators/generateRouter.ts +8 -3
- package/src/generators/generateRouterFastify.ts +8 -3
- package/src/generators/generateRouterHono.ts +8 -2
- package/src/generators/generateUnifiedScalarUI.ts +15 -11
- package/src/index.ts +27 -7
|
@@ -49,7 +49,7 @@ function generateExpressDocsExport(modelName) {
|
|
|
49
49
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
50
50
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
51
51
|
config,
|
|
52
|
-
{ format: 'yaml' }
|
|
52
|
+
{ format: 'yaml', writeStrategy: WRITE_STRATEGY }
|
|
53
53
|
)
|
|
54
54
|
return res.type('application/yaml').send(yaml as string)
|
|
55
55
|
}
|
|
@@ -59,7 +59,7 @@ function generateExpressDocsExport(modelName) {
|
|
|
59
59
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
60
60
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
61
61
|
config,
|
|
62
|
-
{ format: 'json' }
|
|
62
|
+
{ format: 'json', writeStrategy: WRITE_STRATEGY }
|
|
63
63
|
)
|
|
64
64
|
|
|
65
65
|
if (ui === 'json') return res.json(spec)
|
|
@@ -70,7 +70,7 @@ function generateExpressDocsExport(modelName) {
|
|
|
70
70
|
return res.type('html').send(renderScalar('${modelName}', spec, pageTitle, config.scalarCdnUrl))
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
const html = renderDocs('${modelName}', config, MODEL_CONTEXT)
|
|
73
|
+
const html = renderDocs('${modelName}', config, MODEL_CONTEXT, WRITE_STRATEGY)
|
|
74
74
|
return res.type('html').send(html)
|
|
75
75
|
}
|
|
76
76
|
}`;
|
|
@@ -99,7 +99,7 @@ function generateFastifyDocsExport(modelName) {
|
|
|
99
99
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
100
100
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
101
101
|
config,
|
|
102
|
-
{ format: 'yaml' }
|
|
102
|
+
{ format: 'yaml', writeStrategy: WRITE_STRATEGY }
|
|
103
103
|
)
|
|
104
104
|
reply.type('application/yaml').send(yaml as string); return
|
|
105
105
|
}
|
|
@@ -109,7 +109,7 @@ function generateFastifyDocsExport(modelName) {
|
|
|
109
109
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
110
110
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
111
111
|
config,
|
|
112
|
-
{ format: 'json' }
|
|
112
|
+
{ format: 'json', writeStrategy: WRITE_STRATEGY }
|
|
113
113
|
)
|
|
114
114
|
|
|
115
115
|
if (ui === 'json') { reply.send(spec); return }
|
|
@@ -120,7 +120,7 @@ function generateFastifyDocsExport(modelName) {
|
|
|
120
120
|
reply.type('text/html').send(renderScalar('${modelName}', spec, pageTitle, config.scalarCdnUrl)); return
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
const html = renderDocs('${modelName}', config, MODEL_CONTEXT)
|
|
123
|
+
const html = renderDocs('${modelName}', config, MODEL_CONTEXT, WRITE_STRATEGY)
|
|
124
124
|
reply.type('text/html').send(html)
|
|
125
125
|
}
|
|
126
126
|
}`;
|
|
@@ -148,7 +148,7 @@ function generateHonoDocsExport(modelName) {
|
|
|
148
148
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
149
149
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
150
150
|
config,
|
|
151
|
-
{ format: 'yaml' }
|
|
151
|
+
{ format: 'yaml', writeStrategy: WRITE_STRATEGY }
|
|
152
152
|
) as string
|
|
153
153
|
return c.body(yaml, 200, { 'Content-Type': 'application/yaml' })
|
|
154
154
|
}
|
|
@@ -158,7 +158,7 @@ function generateHonoDocsExport(modelName) {
|
|
|
158
158
|
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
159
159
|
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
160
160
|
config,
|
|
161
|
-
{ format: 'json' }
|
|
161
|
+
{ format: 'json', writeStrategy: WRITE_STRATEGY }
|
|
162
162
|
)
|
|
163
163
|
|
|
164
164
|
if (ui === 'json') return c.json(spec as Record<string, unknown>)
|
|
@@ -169,13 +169,13 @@ function generateHonoDocsExport(modelName) {
|
|
|
169
169
|
return c.html(renderScalar('${modelName}', spec, pageTitle, config.scalarCdnUrl))
|
|
170
170
|
}
|
|
171
171
|
|
|
172
|
-
const html = renderDocs('${modelName}', config, MODEL_CONTEXT)
|
|
172
|
+
const html = renderDocs('${modelName}', config, MODEL_CONTEXT, WRITE_STRATEGY)
|
|
173
173
|
return c.html(html)
|
|
174
174
|
}
|
|
175
175
|
}`;
|
|
176
176
|
}
|
|
177
177
|
function generateScalarUIHandler(options) {
|
|
178
|
-
const { model, enums } = options;
|
|
178
|
+
const { model, enums, writeStrategy } = options;
|
|
179
179
|
const target = options.target || 'express';
|
|
180
180
|
const ext = (0, importExt_1.importExt)(options.importStyle);
|
|
181
181
|
const modelName = model.name;
|
|
@@ -229,6 +229,7 @@ function generateScalarUIHandler(options) {
|
|
|
229
229
|
: generateExpressDocsExport(modelName);
|
|
230
230
|
return `${frameworkImport}
|
|
231
231
|
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
232
|
+
import type { WriteStrategy } from '../routeConfig${ext}'
|
|
232
233
|
import {
|
|
233
234
|
renderDocs,
|
|
234
235
|
renderScalar,
|
|
@@ -242,6 +243,8 @@ import {
|
|
|
242
243
|
type DocsModelContext,
|
|
243
244
|
} from '../docsRenderer${ext}'
|
|
244
245
|
|
|
246
|
+
const WRITE_STRATEGY: WriteStrategy = '${writeStrategy}'
|
|
247
|
+
|
|
245
248
|
export const MODEL_FIELDS: FieldMeta[] = ${JSON.stringify(fieldsMeta, null, 2)}
|
|
246
249
|
|
|
247
250
|
export const MODEL_ENUMS: EnumMeta[] = ${JSON.stringify(enumsMeta, null, 2)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateUnifiedScalarUI.js","sourceRoot":"","sources":["../../src/generators/generateUnifiedScalarUI.ts"],"names":[],"mappings":";;AAqLA,
|
|
1
|
+
{"version":3,"file":"generateUnifiedScalarUI.js","sourceRoot":"","sources":["../../src/generators/generateUnifiedScalarUI.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -28,6 +28,21 @@ function getTarget(options) {
|
|
|
28
28
|
return raw;
|
|
29
29
|
throw new Error(`Invalid target "${raw}". Expected "express", "fastify", or "hono".`);
|
|
30
30
|
}
|
|
31
|
+
function getWriteStrategy(options) {
|
|
32
|
+
const raw = String(options.generator.config.writeStrategy ?? 'regular');
|
|
33
|
+
const lower = raw.toLowerCase();
|
|
34
|
+
if (lower === 'regular')
|
|
35
|
+
return 'regular';
|
|
36
|
+
if (lower === 'throwonnonreturning')
|
|
37
|
+
return 'throwOnNonReturning';
|
|
38
|
+
if (lower === 'throwonregular') {
|
|
39
|
+
console.warn('[prisma-generator-express] writeStrategy="throwOnRegular" is deprecated. Use "throwOnNonReturning" instead.');
|
|
40
|
+
return 'throwOnNonReturning';
|
|
41
|
+
}
|
|
42
|
+
if (lower === 'forcereturn')
|
|
43
|
+
return 'forceReturn';
|
|
44
|
+
throw new Error(`Invalid writeStrategy "${raw}". Expected "regular", "throwOnNonReturning", or "forceReturn".`);
|
|
45
|
+
}
|
|
31
46
|
function validateClientGeneratorPresent(options) {
|
|
32
47
|
(0, generateImportPrismaStatement_1.getRelativeClientPath)(options, options.dmmf.datamodel.models[0]?.name ?? 'Model');
|
|
33
48
|
}
|
|
@@ -41,6 +56,7 @@ function validateClientGeneratorPresent(options) {
|
|
|
41
56
|
},
|
|
42
57
|
async onGenerate(options) {
|
|
43
58
|
const target = getTarget(options);
|
|
59
|
+
const writeStrategy = getWriteStrategy(options);
|
|
44
60
|
const hasExplicitOutput = !!options.generator.output?.fromEnvVar ||
|
|
45
61
|
options.generator.config.output !== undefined;
|
|
46
62
|
if (!hasExplicitOutput) {
|
|
@@ -53,6 +69,7 @@ function validateClientGeneratorPresent(options) {
|
|
|
53
69
|
console.log(` Target: ${target}`);
|
|
54
70
|
console.log(` Output: ${options.generator.output?.value}`);
|
|
55
71
|
console.log(` Import style: ${importStyle}`);
|
|
72
|
+
console.log(` Write strategy: ${writeStrategy}`);
|
|
56
73
|
if (options.dmmf.datamodel.models.length > 0) {
|
|
57
74
|
validateClientGeneratorPresent(options);
|
|
58
75
|
}
|
|
@@ -65,15 +82,14 @@ function validateClientGeneratorPresent(options) {
|
|
|
65
82
|
: generateUnifiedHandler_1.generateUnifiedHandler;
|
|
66
83
|
const allModels = options.dmmf.datamodel.models;
|
|
67
84
|
for (const model of options.dmmf.datamodel.models) {
|
|
68
|
-
if (model.documentation &&
|
|
69
|
-
GENERATOR_OFF_RE.test(model.documentation)) {
|
|
85
|
+
if (model.documentation && GENERATOR_OFF_RE.test(model.documentation)) {
|
|
70
86
|
console.log(` Skipping: ${model.name} (generator off)`);
|
|
71
87
|
continue;
|
|
72
88
|
}
|
|
73
89
|
modelNames.push(model.name);
|
|
74
90
|
const guardShapesImport = (0, generateImportPrismaStatement_1.getGuardShapesImport)(options, model.name);
|
|
75
91
|
await (0, writeFileSafely_1.writeFileSafely)({
|
|
76
|
-
content: (0, generateOperationCore_1.generateModelCore)({ model: model, importStyle }),
|
|
92
|
+
content: (0, generateOperationCore_1.generateModelCore)({ model: model, importStyle, writeStrategy }),
|
|
77
93
|
options,
|
|
78
94
|
model: model,
|
|
79
95
|
operation: 'Core',
|
|
@@ -90,6 +106,7 @@ function validateClientGeneratorPresent(options) {
|
|
|
90
106
|
enums: options.dmmf.datamodel.enums,
|
|
91
107
|
guardShapesImport,
|
|
92
108
|
importStyle,
|
|
109
|
+
writeStrategy,
|
|
93
110
|
})
|
|
94
111
|
: target === 'hono'
|
|
95
112
|
? (0, generateRouterHono_1.generateHonoRouterFunction)({
|
|
@@ -97,12 +114,14 @@ function validateClientGeneratorPresent(options) {
|
|
|
97
114
|
enums: options.dmmf.datamodel.enums,
|
|
98
115
|
guardShapesImport,
|
|
99
116
|
importStyle,
|
|
117
|
+
writeStrategy,
|
|
100
118
|
})
|
|
101
119
|
: (0, generateRouter_1.generateRouterFunction)({
|
|
102
120
|
model: model,
|
|
103
121
|
enums: options.dmmf.datamodel.enums,
|
|
104
122
|
guardShapesImport,
|
|
105
123
|
importStyle,
|
|
124
|
+
writeStrategy,
|
|
106
125
|
});
|
|
107
126
|
await (0, writeFileSafely_1.writeFileSafely)({
|
|
108
127
|
content: routerContent,
|
|
@@ -116,6 +135,7 @@ function validateClientGeneratorPresent(options) {
|
|
|
116
135
|
enums: options.dmmf.datamodel.enums,
|
|
117
136
|
target,
|
|
118
137
|
importStyle,
|
|
138
|
+
writeStrategy,
|
|
119
139
|
}),
|
|
120
140
|
options,
|
|
121
141
|
model: model,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;AAAA,+DAIiC;AACjC,gDAAuB;AACvB,gFAA4E;AAC5E,gFAA4E;AAC5E,0EAAsE;AACtE,gEAAoE;AACpE,8EAAkF;AAClF,wEAA4E;AAC5E,kFAA8E;AAC9E,0EAAsE;AACtE,wFAAoF;AACpF,8EAAsE;AACtE,4EAG0C;AAC1C,8FAGmD;AACnD,6DAAyD;AACzD,iDAA6C;AAC7C,mEAA4E;AAC5E,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prisma-generator-express",
|
|
3
3
|
"description": "Prisma generator for Express, Fastify, and Hono CRUD APIs with OpenAPI documentation",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.55.0",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "MIT",
|
package/src/constants.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
sendSSEProgress,
|
|
10
10
|
sendSSERootArray,
|
|
11
11
|
sendSSERelationBatch,
|
|
12
|
+
sendSSENestedRelationBatch,
|
|
12
13
|
sendSSEPageMeta,
|
|
13
14
|
runSingleResultSSE,
|
|
14
15
|
emitTerminalSSEError,
|
|
@@ -62,6 +63,10 @@ type RowPair = {
|
|
|
62
63
|
public: Record<string, unknown>
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
type ParentEntry = RowPair & {
|
|
67
|
+
locator: Array<number | string>
|
|
68
|
+
}
|
|
69
|
+
|
|
65
70
|
function readPath(source: Record<string, unknown>, path: string): unknown {
|
|
66
71
|
if (path === '') return source
|
|
67
72
|
const parts = path.split('.')
|
|
@@ -235,35 +240,49 @@ function singleUnsupportedReason(plan: AutoIncludePlan): string | null {
|
|
|
235
240
|
return null
|
|
236
241
|
}
|
|
237
242
|
|
|
238
|
-
function
|
|
243
|
+
function collectParentEntries(
|
|
239
244
|
rootPairs: RowPair[],
|
|
240
245
|
parentPath: string,
|
|
241
|
-
):
|
|
242
|
-
|
|
243
|
-
|
|
246
|
+
): ParentEntry[] {
|
|
247
|
+
const initial: ParentEntry[] = rootPairs.map((p, i) => ({
|
|
248
|
+
internal: p.internal,
|
|
249
|
+
public: p.public,
|
|
250
|
+
locator: [i],
|
|
251
|
+
}))
|
|
252
|
+
if (parentPath === '') return initial
|
|
253
|
+
|
|
254
|
+
let entries = initial
|
|
244
255
|
for (const segment of parentPath.split('.')) {
|
|
245
|
-
const next:
|
|
246
|
-
for (const
|
|
247
|
-
const internalValue =
|
|
248
|
-
const publicValue =
|
|
256
|
+
const next: ParentEntry[] = []
|
|
257
|
+
for (const entry of entries) {
|
|
258
|
+
const internalValue = entry.internal[segment]
|
|
259
|
+
const publicValue = entry.public[segment]
|
|
249
260
|
if (Array.isArray(internalValue) && Array.isArray(publicValue)) {
|
|
250
261
|
const length = Math.min(internalValue.length, publicValue.length)
|
|
251
262
|
for (let i = 0; i < length; i++) {
|
|
252
263
|
const internalItem = internalValue[i]
|
|
253
264
|
const publicItem = publicValue[i]
|
|
254
265
|
if (isPlainObject(internalItem) && isPlainObject(publicItem)) {
|
|
255
|
-
next.push({
|
|
266
|
+
next.push({
|
|
267
|
+
internal: internalItem,
|
|
268
|
+
public: publicItem,
|
|
269
|
+
locator: [...entry.locator, segment, i],
|
|
270
|
+
})
|
|
256
271
|
}
|
|
257
272
|
}
|
|
258
273
|
continue
|
|
259
274
|
}
|
|
260
275
|
if (isPlainObject(internalValue) && isPlainObject(publicValue)) {
|
|
261
|
-
next.push({
|
|
276
|
+
next.push({
|
|
277
|
+
internal: internalValue,
|
|
278
|
+
public: publicValue,
|
|
279
|
+
locator: [...entry.locator, segment],
|
|
280
|
+
})
|
|
262
281
|
}
|
|
263
282
|
}
|
|
264
|
-
|
|
283
|
+
entries = next
|
|
265
284
|
}
|
|
266
|
-
return
|
|
285
|
+
return entries
|
|
267
286
|
}
|
|
268
287
|
|
|
269
288
|
async function runOneStageSingle(options: {
|
|
@@ -522,12 +541,12 @@ async function runOneStageMany(options: {
|
|
|
522
541
|
extended: unknown
|
|
523
542
|
models: Record<string, ModelRelationMap>
|
|
524
543
|
stage: AutoIncludeStage
|
|
525
|
-
|
|
544
|
+
parentEntries: ParentEntry[]
|
|
526
545
|
internalFieldPaths: string[]
|
|
527
546
|
res: Response
|
|
528
547
|
isAborted: () => boolean
|
|
529
548
|
}): Promise<void> {
|
|
530
|
-
const { extended, models, stage,
|
|
549
|
+
const { extended, models, stage, parentEntries, internalFieldPaths, res, isAborted } = options
|
|
531
550
|
|
|
532
551
|
if (isAborted()) return
|
|
533
552
|
|
|
@@ -540,14 +559,16 @@ async function runOneStageMany(options: {
|
|
|
540
559
|
throw new Error('Target model not in relation metadata: ' + rel.type)
|
|
541
560
|
}
|
|
542
561
|
|
|
543
|
-
if (
|
|
562
|
+
if (parentEntries.length === 0) {
|
|
544
563
|
if (stage.depth === 1) {
|
|
545
564
|
sendSSERelationBatch(res, stage.relationPath, [])
|
|
565
|
+
} else {
|
|
566
|
+
sendSSENestedRelationBatch(res, stage.relationPath, stage.depth, [])
|
|
546
567
|
}
|
|
547
568
|
return
|
|
548
569
|
}
|
|
549
570
|
|
|
550
|
-
const internalParents =
|
|
571
|
+
const internalParents = parentEntries.map((p) => p.internal)
|
|
551
572
|
const distinctValues = collectDistinctParentValues(internalParents, parentKey)
|
|
552
573
|
const delegate: PrismaDelegate = getDelegate(extended, targetModel.delegateKey)
|
|
553
574
|
|
|
@@ -571,11 +592,11 @@ async function runOneStageMany(options: {
|
|
|
571
592
|
: internalFieldPaths
|
|
572
593
|
|
|
573
594
|
const grouped = groupRelatedRows(children, childKey)
|
|
574
|
-
const publicValues: unknown[] = new Array(
|
|
595
|
+
const publicValues: unknown[] = new Array(parentEntries.length)
|
|
575
596
|
|
|
576
|
-
for (let i = 0; i <
|
|
577
|
-
const
|
|
578
|
-
const fkVal =
|
|
597
|
+
for (let i = 0; i < parentEntries.length; i++) {
|
|
598
|
+
const entry = parentEntries[i]
|
|
599
|
+
const fkVal = entry.internal[parentKey]
|
|
579
600
|
let internalVal: unknown
|
|
580
601
|
|
|
581
602
|
if (fkVal === undefined || fkVal === null) {
|
|
@@ -591,8 +612,8 @@ async function runOneStageMany(options: {
|
|
|
591
612
|
|
|
592
613
|
const publicVal = buildPublicForStage(internalVal, effectivePaths, stage.relationPath)
|
|
593
614
|
|
|
594
|
-
|
|
595
|
-
|
|
615
|
+
entry.internal[stage.relationName] = internalVal
|
|
616
|
+
entry.public[stage.relationName] = publicVal
|
|
596
617
|
publicValues[i] = publicVal
|
|
597
618
|
}
|
|
598
619
|
|
|
@@ -600,7 +621,14 @@ async function runOneStageMany(options: {
|
|
|
600
621
|
|
|
601
622
|
if (stage.depth === 1) {
|
|
602
623
|
sendSSERelationBatch(res, stage.relationPath, publicValues)
|
|
624
|
+
return
|
|
603
625
|
}
|
|
626
|
+
|
|
627
|
+
const attachments = parentEntries.map((entry, i) => ({
|
|
628
|
+
locator: entry.locator,
|
|
629
|
+
value: publicValues[i],
|
|
630
|
+
}))
|
|
631
|
+
sendSSENestedRelationBatch(res, stage.relationPath, stage.depth, attachments)
|
|
604
632
|
}
|
|
605
633
|
|
|
606
634
|
function buildRootPairs(
|
|
@@ -652,13 +680,13 @@ async function processFindManyStages(args: {
|
|
|
652
680
|
|
|
653
681
|
await runConcurrent(group, STAGE_CONCURRENCY, async (stage) => {
|
|
654
682
|
if (isAborted()) return
|
|
655
|
-
const
|
|
683
|
+
const parentEntries = collectParentEntries(rootPairs, stage.parentPath)
|
|
656
684
|
try {
|
|
657
685
|
await runOneStageMany({
|
|
658
686
|
extended,
|
|
659
687
|
models,
|
|
660
688
|
stage,
|
|
661
|
-
|
|
689
|
+
parentEntries,
|
|
662
690
|
internalFieldPaths: plan.internalFieldPaths,
|
|
663
691
|
res,
|
|
664
692
|
isAborted,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { RouteConfig } from './routeConfig'
|
|
1
|
+
import type { RouteConfig, WriteStrategy } from './routeConfig'
|
|
2
2
|
import { OPERATION_DEFS, isOperationEnabled } from './operationDefinitions'
|
|
3
3
|
import { normalizePrefix, removeTrailingSlash } from './misc'
|
|
4
4
|
|
|
@@ -51,6 +51,7 @@ type BuildOptions = {
|
|
|
51
51
|
title?: string
|
|
52
52
|
description?: string
|
|
53
53
|
version?: string
|
|
54
|
+
writeStrategy?: WriteStrategy
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
const OP_MAP = new Map(OPERATION_DEFS.map((d) => [d.name, d]))
|
|
@@ -130,10 +131,7 @@ function scalarUpdateOperations(
|
|
|
130
131
|
}
|
|
131
132
|
|
|
132
133
|
return {
|
|
133
|
-
oneOf: [
|
|
134
|
-
baseSchema,
|
|
135
|
-
{ type: 'object', properties: ops },
|
|
136
|
-
],
|
|
134
|
+
oneOf: [baseSchema, { type: 'object', properties: ops }],
|
|
137
135
|
}
|
|
138
136
|
}
|
|
139
137
|
|
|
@@ -193,7 +191,10 @@ function countBodySchema(): SchemaObject {
|
|
|
193
191
|
take: { type: 'integer', description: 'Limit results' },
|
|
194
192
|
skip: { type: 'integer', description: 'Skip results' },
|
|
195
193
|
cursor: { type: 'object', description: 'Cursor for pagination' },
|
|
196
|
-
select: {
|
|
194
|
+
select: {
|
|
195
|
+
description:
|
|
196
|
+
'Count specific fields. When provided, returns per-field counts as an object instead of a single integer.',
|
|
197
|
+
},
|
|
197
198
|
},
|
|
198
199
|
}
|
|
199
200
|
}
|
|
@@ -207,11 +208,25 @@ function aggregateBodySchema(): SchemaObject {
|
|
|
207
208
|
cursor: { type: 'object', description: 'Cursor for pagination' },
|
|
208
209
|
take: { type: 'integer', description: 'Limit results' },
|
|
209
210
|
skip: { type: 'integer', description: 'Skip results' },
|
|
210
|
-
_count: {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
211
|
+
_count: {
|
|
212
|
+
description: 'Count aggregate (true or field selection object)',
|
|
213
|
+
},
|
|
214
|
+
_avg: {
|
|
215
|
+
type: 'object',
|
|
216
|
+
description: 'Average aggregate (field selection object)',
|
|
217
|
+
},
|
|
218
|
+
_sum: {
|
|
219
|
+
type: 'object',
|
|
220
|
+
description: 'Sum aggregate (field selection object)',
|
|
221
|
+
},
|
|
222
|
+
_min: {
|
|
223
|
+
type: 'object',
|
|
224
|
+
description: 'Min aggregate (field selection object)',
|
|
225
|
+
},
|
|
226
|
+
_max: {
|
|
227
|
+
type: 'object',
|
|
228
|
+
description: 'Max aggregate (field selection object)',
|
|
229
|
+
},
|
|
215
230
|
},
|
|
216
231
|
}
|
|
217
232
|
}
|
|
@@ -220,17 +235,38 @@ function groupByBodySchema(): SchemaObject {
|
|
|
220
235
|
return {
|
|
221
236
|
type: 'object',
|
|
222
237
|
properties: {
|
|
223
|
-
by: {
|
|
238
|
+
by: {
|
|
239
|
+
type: 'array',
|
|
240
|
+
items: { type: 'string' },
|
|
241
|
+
description: 'Fields to group by',
|
|
242
|
+
},
|
|
224
243
|
where: { type: 'object', description: 'Filter conditions' },
|
|
225
244
|
orderBy: { description: 'Sort order. Required when using skip or take.' },
|
|
226
|
-
having: {
|
|
245
|
+
having: {
|
|
246
|
+
type: 'object',
|
|
247
|
+
description: 'Having conditions (filter object)',
|
|
248
|
+
},
|
|
227
249
|
take: { type: 'integer', description: 'Limit results' },
|
|
228
250
|
skip: { type: 'integer', description: 'Skip results' },
|
|
229
|
-
_count: {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
251
|
+
_count: {
|
|
252
|
+
description: 'Count aggregate (true or field selection object)',
|
|
253
|
+
},
|
|
254
|
+
_avg: {
|
|
255
|
+
type: 'object',
|
|
256
|
+
description: 'Average aggregate (field selection object)',
|
|
257
|
+
},
|
|
258
|
+
_sum: {
|
|
259
|
+
type: 'object',
|
|
260
|
+
description: 'Sum aggregate (field selection object)',
|
|
261
|
+
},
|
|
262
|
+
_min: {
|
|
263
|
+
type: 'object',
|
|
264
|
+
description: 'Min aggregate (field selection object)',
|
|
265
|
+
},
|
|
266
|
+
_max: {
|
|
267
|
+
type: 'object',
|
|
268
|
+
description: 'Max aggregate (field selection object)',
|
|
269
|
+
},
|
|
234
270
|
},
|
|
235
271
|
required: ['by'],
|
|
236
272
|
}
|
|
@@ -257,6 +293,82 @@ function getPostReadBodySchema(opName: string): SchemaObject {
|
|
|
257
293
|
}
|
|
258
294
|
}
|
|
259
295
|
|
|
296
|
+
function applyWriteStrategy(
|
|
297
|
+
spec: OpenApiSpec,
|
|
298
|
+
modelName: string,
|
|
299
|
+
basePath: string,
|
|
300
|
+
writeStrategy: WriteStrategy | undefined,
|
|
301
|
+
): void {
|
|
302
|
+
if (!writeStrategy || writeStrategy === 'regular') return
|
|
303
|
+
|
|
304
|
+
const manyPath = basePath + '/many'
|
|
305
|
+
const node = spec.paths[manyPath]
|
|
306
|
+
if (!node) return
|
|
307
|
+
|
|
308
|
+
if (writeStrategy === 'throwOnNonReturning') {
|
|
309
|
+
delete node.post
|
|
310
|
+
delete node.put
|
|
311
|
+
if (Object.keys(node).length === 0) {
|
|
312
|
+
delete spec.paths[manyPath]
|
|
313
|
+
}
|
|
314
|
+
return
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const responseRef: RefObject = {
|
|
318
|
+
$ref: '#/components/schemas/' + modelName + 'Response',
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const injectProjectionAndArrayResponse = (
|
|
322
|
+
op: any,
|
|
323
|
+
successCode: '200' | '201',
|
|
324
|
+
summary: string,
|
|
325
|
+
description: string,
|
|
326
|
+
): void => {
|
|
327
|
+
op.summary = summary
|
|
328
|
+
op.description = description
|
|
329
|
+
const r = op.responses?.[successCode]
|
|
330
|
+
if (r?.content?.['application/json']) {
|
|
331
|
+
r.content['application/json'].schema = {
|
|
332
|
+
type: 'array',
|
|
333
|
+
items: responseRef,
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const reqSchema = op.requestBody?.content?.['application/json']?.schema
|
|
337
|
+
if (reqSchema && reqSchema.properties) {
|
|
338
|
+
reqSchema.properties.select = {
|
|
339
|
+
type: 'object',
|
|
340
|
+
description: 'Select fields to return',
|
|
341
|
+
}
|
|
342
|
+
reqSchema.properties.include = {
|
|
343
|
+
type: 'object',
|
|
344
|
+
description: 'Include relations to return',
|
|
345
|
+
}
|
|
346
|
+
reqSchema.properties.omit = {
|
|
347
|
+
type: 'object',
|
|
348
|
+
description: 'Omit fields from response',
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (node.post) {
|
|
354
|
+
injectProjectionAndArrayResponse(
|
|
355
|
+
node.post,
|
|
356
|
+
'201',
|
|
357
|
+
'Create many ' + modelName + ' (forceReturn)',
|
|
358
|
+
'writeStrategy="forceReturn": this endpoint silently invokes createManyAndReturn and returns the created records instead of { count }.',
|
|
359
|
+
)
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (node.put) {
|
|
363
|
+
injectProjectionAndArrayResponse(
|
|
364
|
+
node.put,
|
|
365
|
+
'200',
|
|
366
|
+
'Update many ' + modelName + ' (forceReturn)',
|
|
367
|
+
'writeStrategy="forceReturn": this endpoint silently invokes updateManyAndReturn and returns the updated records instead of { count }.',
|
|
368
|
+
)
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
260
372
|
export function buildModelOpenApi(
|
|
261
373
|
modelName: string,
|
|
262
374
|
modelFields: ModelField[],
|
|
@@ -321,6 +433,8 @@ export function buildModelOpenApi(
|
|
|
321
433
|
|
|
322
434
|
generatePaths(spec, modelName, basePath, config, modelFields)
|
|
323
435
|
|
|
436
|
+
applyWriteStrategy(spec, modelName, basePath, options.writeStrategy)
|
|
437
|
+
|
|
324
438
|
if (options.format === 'yaml') {
|
|
325
439
|
return toYaml(spec)
|
|
326
440
|
}
|
|
@@ -644,7 +758,8 @@ function addPostReadOperation(
|
|
|
644
758
|
tags: [modelName],
|
|
645
759
|
summary: summary + ' (POST)',
|
|
646
760
|
operationId: `${modelName}${opName.charAt(0).toUpperCase() + opName.slice(1)}Post`,
|
|
647
|
-
description:
|
|
761
|
+
description:
|
|
762
|
+
(description ? description + ' ' : '') +
|
|
648
763
|
'POST alternative for requests with complex query parameters that may exceed URL length limits. Accepts the same arguments as the GET endpoint but as a JSON request body instead of query parameters.',
|
|
649
764
|
requestBody: {
|
|
650
765
|
required: true,
|
|
@@ -1291,8 +1406,14 @@ function generatePaths(
|
|
|
1291
1406
|
`Count ${modelName}`,
|
|
1292
1407
|
{
|
|
1293
1408
|
oneOf: [
|
|
1294
|
-
{
|
|
1295
|
-
|
|
1409
|
+
{
|
|
1410
|
+
type: 'integer',
|
|
1411
|
+
description: 'Total count when select is not provided',
|
|
1412
|
+
},
|
|
1413
|
+
{
|
|
1414
|
+
type: 'object',
|
|
1415
|
+
description: 'Per-field count object when select is provided',
|
|
1416
|
+
},
|
|
1296
1417
|
],
|
|
1297
1418
|
},
|
|
1298
1419
|
[400, 403, 500, 501, 503],
|
|
@@ -1730,7 +1851,7 @@ function mapFieldToWriteSchema(
|
|
|
1730
1851
|
description: field.documentation,
|
|
1731
1852
|
}
|
|
1732
1853
|
} else if (!('$ref' in schema)) {
|
|
1733
|
-
(schema as SchemaObject).description = field.documentation
|
|
1854
|
+
;(schema as SchemaObject).description = field.documentation
|
|
1734
1855
|
}
|
|
1735
1856
|
}
|
|
1736
1857
|
|
|
@@ -1896,4 +2017,4 @@ function toYaml(obj: any, indent = 0): string {
|
|
|
1896
2017
|
}
|
|
1897
2018
|
|
|
1898
2019
|
return yaml
|
|
1899
|
-
}
|
|
2020
|
+
}
|