prisma-generator-express 1.66.0 → 1.68.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 +188 -3432
- package/dist/client/encodeQueryParams.js +3 -1
- package/dist/client/encodeQueryParams.js.map +1 -1
- package/dist/copy/misc.d.ts +1 -0
- package/dist/copy/misc.js +14 -0
- package/dist/copy/misc.js.map +1 -1
- package/dist/copy/operationDefinitions.d.ts +4 -1
- package/dist/copy/operationDefinitions.js +133 -9
- package/dist/copy/operationDefinitions.js.map +1 -1
- package/dist/generators/generateFastifyHandler.d.ts +2 -2
- package/dist/generators/generateFastifyHandler.js +68 -12
- package/dist/generators/generateFastifyHandler.js.map +1 -1
- package/dist/generators/generateHonoHandler.d.ts +2 -2
- package/dist/generators/generateHonoHandler.js +53 -6
- package/dist/generators/generateHonoHandler.js.map +1 -1
- package/dist/generators/generateHonoOpenApi.d.ts +13 -0
- package/dist/generators/generateHonoOpenApi.js +70 -0
- package/dist/generators/generateHonoOpenApi.js.map +1 -0
- package/dist/generators/generateImportPrismaStatement.d.ts +1 -0
- package/dist/generators/generateImportPrismaStatement.js +6 -0
- package/dist/generators/generateImportPrismaStatement.js.map +1 -1
- package/dist/generators/generateMcpApp.d.ts +10 -0
- package/dist/generators/generateMcpApp.js +113 -0
- package/dist/generators/generateMcpApp.js.map +1 -0
- package/dist/generators/generateModelMcp.d.ts +9 -0
- package/dist/generators/generateModelMcp.js +145 -0
- package/dist/generators/generateModelMcp.js.map +1 -0
- package/dist/generators/generateModelMetadata.js +29 -15
- package/dist/generators/generateModelMetadata.js.map +1 -1
- package/dist/generators/generateOperationCore.d.ts +3 -3
- package/dist/generators/generateOperationCore.js +51 -16
- package/dist/generators/generateOperationCore.js.map +1 -1
- package/dist/generators/generateRelationMeta.js +2 -2
- package/dist/generators/generateRelationMeta.js.map +1 -1
- package/dist/generators/generateRouteConfigType.d.ts +2 -2
- package/dist/generators/generateRouteConfigType.js +29 -11
- package/dist/generators/generateRouteConfigType.js.map +1 -1
- package/dist/generators/generateRouter.d.ts +7 -4
- package/dist/generators/generateRouter.js +164 -65
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.d.ts +7 -4
- package/dist/generators/generateRouterFastify.js +106 -86
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.d.ts +7 -4
- package/dist/generators/generateRouterHono.js +59 -414
- package/dist/generators/generateRouterHono.js.map +1 -1
- package/dist/generators/generateRouterPartsHono.d.ts +14 -0
- package/dist/generators/generateRouterPartsHono.js +180 -0
- package/dist/generators/generateRouterPartsHono.js.map +1 -0
- package/dist/generators/generateUnifiedDocs.d.ts +1 -1
- package/dist/generators/generateUnifiedDocs.js +15 -8
- package/dist/generators/generateUnifiedDocs.js.map +1 -1
- package/dist/generators/generateUnifiedHandler.d.ts +2 -2
- package/dist/generators/generateUnifiedHandler.js +42 -18
- package/dist/generators/generateUnifiedHandler.js.map +1 -1
- package/dist/guardOptions.js +12 -7
- package/dist/guardOptions.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +123 -4
- package/dist/index.js.map +1 -1
- package/dist/utils/copyFiles.d.ts +1 -1
- package/dist/utils/copyFiles.js +42 -7
- package/dist/utils/copyFiles.js.map +1 -1
- package/dist/utils/importExt.d.ts +1 -1
- package/dist/utils/mcpGate.d.ts +10 -0
- package/dist/utils/mcpGate.js +118 -0
- package/dist/utils/mcpGate.js.map +1 -0
- package/dist/utils/pathCasing.d.ts +4 -0
- package/dist/utils/pathCasing.js +40 -0
- package/dist/utils/pathCasing.js.map +1 -0
- package/dist/utils/resolveImportStyle.js +13 -5
- package/dist/utils/resolveImportStyle.js.map +1 -1
- package/dist/utils/writeFileSafely.js +6 -0
- package/dist/utils/writeFileSafely.js.map +1 -1
- package/package.json +22 -5
- package/src/bin.ts +1 -1
- package/src/client/encodeQueryParams.ts +39 -35
- package/src/constants.ts +1 -1
- package/src/copy/autoIncludePlanner.ts +93 -27
- package/src/copy/autoIncludePlannerGuarded.ts +171 -48
- package/src/copy/autoIncludeRuntimeGuarded.ts +25 -7
- package/src/copy/buildModelOpenApi.ts +229 -176
- package/src/copy/concurrency.ts +10 -8
- package/src/copy/docsRenderer.ts +14 -15
- package/src/copy/errorMapper.ts +68 -19
- package/src/copy/guardHelpers.ts +30 -9
- package/src/copy/materializedCount.ts +17 -5
- package/src/copy/mcpRuntime.ts +1017 -0
- package/src/copy/misc.ts +88 -68
- package/src/copy/ndjson.ts +72 -0
- package/src/copy/operationDefinitions.ts +177 -25
- package/src/copy/operationPipeline.ts +267 -0
- package/src/copy/operationRuntime.ts +124 -26
- package/src/copy/operationSchemas.ts +2773 -0
- package/src/copy/pagination.ts +35 -13
- package/src/copy/parseQueryParams.ts +47 -48
- package/src/copy/projectionDefaults.ts +6 -4
- package/src/copy/routeConfig.express.ts +16 -4
- package/src/copy/routeConfig.fastify.ts +16 -2
- package/src/copy/routeConfig.hono.ts +46 -14
- package/src/copy/routeConfig.ts +175 -40
- package/src/copy/routerParts.ts +524 -0
- package/src/copy/scalarTypes.ts +7 -2
- package/src/copy/sse.ts +72 -19
- package/src/generators/generateFastifyHandler.ts +77 -20
- package/src/generators/generateHonoHandler.ts +62 -14
- package/src/generators/generateHonoOpenApi.ts +93 -0
- package/src/generators/generateImportPrismaStatement.ts +93 -81
- package/src/generators/generateMcpApp.ts +133 -0
- package/src/generators/generateModelMcp.ts +208 -0
- package/src/generators/generateModelMetadata.ts +40 -22
- package/src/generators/generateOperationCore.ts +81 -33
- package/src/generators/generateRelationMeta.ts +23 -11
- package/src/generators/generateRouteConfigType.ts +39 -13
- package/src/generators/generateRouter.ts +171 -68
- package/src/generators/generateRouterFastify.ts +117 -89
- package/src/generators/generateRouterHono.ts +84 -464
- package/src/generators/generateRouterPartsHono.ts +220 -0
- package/src/generators/generateUnifiedDocs.ts +29 -8
- package/src/generators/generateUnifiedHandler.ts +47 -24
- package/src/generators/generateUnifiedScalarUI.ts +1 -1
- package/src/guardOptions.ts +105 -92
- package/src/index.ts +161 -6
- package/src/utils/copyFiles.ts +235 -168
- package/src/utils/importExt.ts +2 -2
- package/src/utils/mcpGate.ts +157 -0
- package/src/utils/pathCasing.ts +42 -0
- package/src/utils/resolveImportStyle.ts +37 -15
- package/src/utils/strings.ts +2 -2
- package/src/utils/writeFileSafely.ts +12 -2
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { stringify as yamlStringify } from 'yaml'
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
RouteConfig,
|
|
4
|
+
WriteStrategy,
|
|
5
|
+
OpenApiSecuritySchemeConfig,
|
|
6
|
+
} from './routeConfig'
|
|
3
7
|
import { OPERATION_BY_NAME, isOperationEnabled } from './operationDefinitions'
|
|
4
8
|
import { normalizePrefix, removeTrailingSlash } from './misc'
|
|
5
9
|
import { NUMERIC_SCALAR_TYPES, STRING_NUMERIC_TYPES } from './scalarTypes'
|
|
@@ -20,14 +24,51 @@ type SchemaObject = {
|
|
|
20
24
|
|
|
21
25
|
type RefObject = { $ref: string; description?: string }
|
|
22
26
|
|
|
27
|
+
type ContentObject = {
|
|
28
|
+
'application/json'?: { schema: SchemaObject | RefObject }
|
|
29
|
+
'application/yaml'?: { schema: SchemaObject | RefObject }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type ResponseObject = {
|
|
33
|
+
description: string
|
|
34
|
+
content?: ContentObject
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type RequestBodyObject = {
|
|
38
|
+
required?: boolean
|
|
39
|
+
content: ContentObject
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
type ParameterSchema = Record<string, string | string[]>
|
|
43
|
+
|
|
44
|
+
type ParameterObject = {
|
|
45
|
+
name: string
|
|
46
|
+
in: 'query' | 'header'
|
|
47
|
+
schema?: ParameterSchema
|
|
48
|
+
description?: string
|
|
49
|
+
required?: boolean
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type OperationObject = {
|
|
53
|
+
tags?: string[]
|
|
54
|
+
summary?: string
|
|
55
|
+
operationId?: string
|
|
56
|
+
description?: string
|
|
57
|
+
parameters?: ParameterObject[]
|
|
58
|
+
requestBody?: RequestBodyObject
|
|
59
|
+
responses: Record<string, ResponseObject>
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type PathItem = Record<string, OperationObject>
|
|
63
|
+
|
|
23
64
|
type OpenApiSpec = {
|
|
24
65
|
openapi: string
|
|
25
66
|
info: { title: string; description: string; version: string }
|
|
26
67
|
servers?: Array<{ url: string; description?: string }>
|
|
27
|
-
paths: Record<string,
|
|
68
|
+
paths: Record<string, PathItem>
|
|
28
69
|
components: {
|
|
29
70
|
schemas: Record<string, SchemaObject>
|
|
30
|
-
securitySchemes?: Record<string,
|
|
71
|
+
securitySchemes?: Record<string, OpenApiSecuritySchemeConfig>
|
|
31
72
|
}
|
|
32
73
|
security?: Array<Record<string, string[]>>
|
|
33
74
|
}
|
|
@@ -55,22 +96,59 @@ type BuildOptions = {
|
|
|
55
96
|
description?: string
|
|
56
97
|
version?: string
|
|
57
98
|
writeStrategy?: WriteStrategy
|
|
99
|
+
pathSegment?: string
|
|
58
100
|
}
|
|
59
101
|
|
|
60
|
-
const WHERE_PROP: SchemaObject = {
|
|
61
|
-
|
|
102
|
+
const WHERE_PROP: SchemaObject = {
|
|
103
|
+
type: 'object',
|
|
104
|
+
description: 'Filter conditions',
|
|
105
|
+
}
|
|
106
|
+
const TAKE_PROP: SchemaObject = {
|
|
107
|
+
type: 'integer',
|
|
108
|
+
description: 'Limit results',
|
|
109
|
+
}
|
|
62
110
|
const SKIP_PROP: SchemaObject = { type: 'integer', description: 'Skip results' }
|
|
63
|
-
const CURSOR_PROP: SchemaObject = {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
111
|
+
const CURSOR_PROP: SchemaObject = {
|
|
112
|
+
type: 'object',
|
|
113
|
+
description: 'Cursor for pagination',
|
|
114
|
+
}
|
|
115
|
+
const ORDERBY_PROP: SchemaObject = {
|
|
116
|
+
description: 'Sort order (object or array of objects)',
|
|
117
|
+
}
|
|
118
|
+
const SELECT_PROP: SchemaObject = {
|
|
119
|
+
type: 'object',
|
|
120
|
+
description: 'Select fields',
|
|
121
|
+
}
|
|
122
|
+
const INCLUDE_PROP: SchemaObject = {
|
|
123
|
+
type: 'object',
|
|
124
|
+
description: 'Include relations',
|
|
125
|
+
}
|
|
126
|
+
const OMIT_PROP: SchemaObject = {
|
|
127
|
+
type: 'object',
|
|
128
|
+
description: 'Omit fields from response',
|
|
129
|
+
}
|
|
130
|
+
const DISTINCT_PROP: SchemaObject = {
|
|
131
|
+
description: 'Distinct fields (string or array of strings)',
|
|
132
|
+
}
|
|
133
|
+
const AGG_COUNT: SchemaObject = {
|
|
134
|
+
description: 'Count aggregate (true or field selection object)',
|
|
135
|
+
}
|
|
136
|
+
const AGG_AVG: SchemaObject = {
|
|
137
|
+
type: 'object',
|
|
138
|
+
description: 'Average aggregate (field selection object)',
|
|
139
|
+
}
|
|
140
|
+
const AGG_SUM: SchemaObject = {
|
|
141
|
+
type: 'object',
|
|
142
|
+
description: 'Sum aggregate (field selection object)',
|
|
143
|
+
}
|
|
144
|
+
const AGG_MIN: SchemaObject = {
|
|
145
|
+
type: 'object',
|
|
146
|
+
description: 'Min aggregate (field selection object)',
|
|
147
|
+
}
|
|
148
|
+
const AGG_MAX: SchemaObject = {
|
|
149
|
+
type: 'object',
|
|
150
|
+
description: 'Max aggregate (field selection object)',
|
|
151
|
+
}
|
|
74
152
|
|
|
75
153
|
const PROJECTION_PROPS: Record<string, SchemaObject> = {
|
|
76
154
|
select: SELECT_PROP,
|
|
@@ -88,7 +166,7 @@ const AGGREGATE_PROPS: Record<string, SchemaObject> = {
|
|
|
88
166
|
|
|
89
167
|
function opEnabled(config: RouteConfig, name: string): boolean {
|
|
90
168
|
const meta = OPERATION_BY_NAME[name]
|
|
91
|
-
return meta ? isOperationEnabled(config
|
|
169
|
+
return meta ? isOperationEnabled(config, meta) : false
|
|
92
170
|
}
|
|
93
171
|
|
|
94
172
|
function opPath(basePath: string, name: string): string {
|
|
@@ -123,7 +201,10 @@ const COMMON_ERRORS: Record<number, string> = {
|
|
|
123
201
|
503: 'Service unavailable — database connection pool timeout',
|
|
124
202
|
}
|
|
125
203
|
|
|
126
|
-
function addErrorResponses(
|
|
204
|
+
function addErrorResponses(
|
|
205
|
+
operation: OperationObject,
|
|
206
|
+
codes: readonly number[],
|
|
207
|
+
): void {
|
|
127
208
|
for (const code of codes) {
|
|
128
209
|
operation.responses[String(code)] = errorResponse(
|
|
129
210
|
COMMON_ERRORS[code] || 'Error',
|
|
@@ -137,7 +218,7 @@ function queryParam(
|
|
|
137
218
|
schema: Record<string, string> = { type: 'string' },
|
|
138
219
|
required?: boolean,
|
|
139
220
|
) {
|
|
140
|
-
const param:
|
|
221
|
+
const param: ParameterObject = { name, in: 'query', schema, description }
|
|
141
222
|
if (required) param.required = true
|
|
142
223
|
return param
|
|
143
224
|
}
|
|
@@ -182,101 +263,7 @@ function listScalarUpdateOperations(
|
|
|
182
263
|
}
|
|
183
264
|
}
|
|
184
265
|
|
|
185
|
-
|
|
186
|
-
return {
|
|
187
|
-
type: 'object',
|
|
188
|
-
properties: {
|
|
189
|
-
where: WHERE_PROP,
|
|
190
|
-
orderBy: ORDERBY_PROP,
|
|
191
|
-
take: TAKE_PROP,
|
|
192
|
-
skip: SKIP_PROP,
|
|
193
|
-
...PROJECTION_PROPS,
|
|
194
|
-
cursor: CURSOR_PROP,
|
|
195
|
-
distinct: DISTINCT_PROP,
|
|
196
|
-
},
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
function findUniqueBodySchema(): SchemaObject {
|
|
201
|
-
return {
|
|
202
|
-
type: 'object',
|
|
203
|
-
properties: {
|
|
204
|
-
where: { type: 'object', description: 'Unique selector' },
|
|
205
|
-
...PROJECTION_PROPS,
|
|
206
|
-
},
|
|
207
|
-
required: ['where'],
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
function countBodySchema(): SchemaObject {
|
|
212
|
-
return {
|
|
213
|
-
type: 'object',
|
|
214
|
-
properties: {
|
|
215
|
-
where: WHERE_PROP,
|
|
216
|
-
orderBy: { description: 'Sort order' },
|
|
217
|
-
take: TAKE_PROP,
|
|
218
|
-
skip: SKIP_PROP,
|
|
219
|
-
cursor: CURSOR_PROP,
|
|
220
|
-
select: {
|
|
221
|
-
description:
|
|
222
|
-
'Count specific fields. When provided, returns per-field counts as an object instead of a single integer.',
|
|
223
|
-
},
|
|
224
|
-
},
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function aggregateBodySchema(): SchemaObject {
|
|
229
|
-
return {
|
|
230
|
-
type: 'object',
|
|
231
|
-
properties: {
|
|
232
|
-
where: WHERE_PROP,
|
|
233
|
-
orderBy: { description: 'Sort order' },
|
|
234
|
-
cursor: CURSOR_PROP,
|
|
235
|
-
take: TAKE_PROP,
|
|
236
|
-
skip: SKIP_PROP,
|
|
237
|
-
...AGGREGATE_PROPS,
|
|
238
|
-
},
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
function groupByBodySchema(): SchemaObject {
|
|
243
|
-
return {
|
|
244
|
-
type: 'object',
|
|
245
|
-
properties: {
|
|
246
|
-
by: {
|
|
247
|
-
type: 'array',
|
|
248
|
-
items: { type: 'string' },
|
|
249
|
-
description: 'Fields to group by',
|
|
250
|
-
},
|
|
251
|
-
where: WHERE_PROP,
|
|
252
|
-
orderBy: { description: 'Sort order. Required when using skip or take.' },
|
|
253
|
-
having: {
|
|
254
|
-
type: 'object',
|
|
255
|
-
description: 'Having conditions (filter object)',
|
|
256
|
-
},
|
|
257
|
-
take: TAKE_PROP,
|
|
258
|
-
skip: SKIP_PROP,
|
|
259
|
-
...AGGREGATE_PROPS,
|
|
260
|
-
},
|
|
261
|
-
required: ['by'],
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
const POST_READ_BODY_SCHEMAS: Record<string, () => SchemaObject> = {
|
|
266
|
-
findMany: findManyBodySchema,
|
|
267
|
-
findFirst: findManyBodySchema,
|
|
268
|
-
findFirstOrThrow: findManyBodySchema,
|
|
269
|
-
findManyPaginated: findManyBodySchema,
|
|
270
|
-
findUnique: findUniqueBodySchema,
|
|
271
|
-
findUniqueOrThrow: findUniqueBodySchema,
|
|
272
|
-
count: countBodySchema,
|
|
273
|
-
aggregate: aggregateBodySchema,
|
|
274
|
-
groupBy: groupByBodySchema,
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
function getPostReadBodySchema(opName: string): SchemaObject {
|
|
278
|
-
return (POST_READ_BODY_SCHEMAS[opName] ?? findManyBodySchema)()
|
|
279
|
-
}
|
|
266
|
+
import { getPostReadBodySchema } from './operationSchemas'
|
|
280
267
|
|
|
281
268
|
function applyWriteStrategy(
|
|
282
269
|
spec: OpenApiSpec,
|
|
@@ -304,14 +291,14 @@ function applyWriteStrategy(
|
|
|
304
291
|
}
|
|
305
292
|
|
|
306
293
|
const injectProjectionAndArrayResponse = (
|
|
307
|
-
op:
|
|
294
|
+
op: OperationObject,
|
|
308
295
|
successCode: '200' | '201',
|
|
309
296
|
summary: string,
|
|
310
297
|
description: string,
|
|
311
298
|
): void => {
|
|
312
299
|
op.summary = summary
|
|
313
300
|
op.description = description
|
|
314
|
-
const r = op.responses
|
|
301
|
+
const r = op.responses[successCode]
|
|
315
302
|
if (r?.content?.['application/json']) {
|
|
316
303
|
r.content['application/json'].schema = {
|
|
317
304
|
type: 'array',
|
|
@@ -319,7 +306,7 @@ function applyWriteStrategy(
|
|
|
319
306
|
}
|
|
320
307
|
}
|
|
321
308
|
const reqSchema = op.requestBody?.content?.['application/json']?.schema
|
|
322
|
-
if (reqSchema && reqSchema.properties) {
|
|
309
|
+
if (reqSchema && !('$ref' in reqSchema) && reqSchema.properties) {
|
|
323
310
|
Object.assign(reqSchema.properties, PROJECTION_PROPS)
|
|
324
311
|
}
|
|
325
312
|
}
|
|
@@ -330,8 +317,18 @@ function applyWriteStrategy(
|
|
|
330
317
|
verb: string
|
|
331
318
|
targetOp: string
|
|
332
319
|
}> = [
|
|
333
|
-
{
|
|
334
|
-
|
|
320
|
+
{
|
|
321
|
+
method: 'post',
|
|
322
|
+
successCode: '201',
|
|
323
|
+
verb: 'Create',
|
|
324
|
+
targetOp: 'createManyAndReturn',
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
method: 'put',
|
|
328
|
+
successCode: '200',
|
|
329
|
+
verb: 'Update',
|
|
330
|
+
targetOp: 'updateManyAndReturn',
|
|
331
|
+
},
|
|
335
332
|
]
|
|
336
333
|
|
|
337
334
|
for (const entry of forceReturnOps) {
|
|
@@ -341,9 +338,11 @@ function applyWriteStrategy(
|
|
|
341
338
|
target,
|
|
342
339
|
entry.successCode,
|
|
343
340
|
entry.verb + ' many ' + modelName + ' (forceReturn)',
|
|
344
|
-
'writeStrategy="forceReturn": this endpoint silently invokes ' +
|
|
345
|
-
|
|
346
|
-
|
|
341
|
+
'writeStrategy="forceReturn": this endpoint silently invokes ' +
|
|
342
|
+
entry.targetOp +
|
|
343
|
+
' and returns the ' +
|
|
344
|
+
(entry.verb === 'Create' ? 'created' : 'updated') +
|
|
345
|
+
' records instead of { count }.',
|
|
347
346
|
)
|
|
348
347
|
}
|
|
349
348
|
}
|
|
@@ -382,7 +381,9 @@ export function buildModelOpenApi(
|
|
|
382
381
|
const basePath =
|
|
383
382
|
normalizePrefix(prefixSource) +
|
|
384
383
|
removeTrailingSlash(
|
|
385
|
-
config.addModelPrefix !== false
|
|
384
|
+
config.addModelPrefix !== false
|
|
385
|
+
? `/${options.pathSegment ?? modelName.toLowerCase()}`
|
|
386
|
+
: '',
|
|
386
387
|
)
|
|
387
388
|
|
|
388
389
|
const referencedEnumTypes = new Set(
|
|
@@ -757,11 +758,11 @@ function addPostReadOperation(
|
|
|
757
758
|
modelName: string,
|
|
758
759
|
opName: string,
|
|
759
760
|
summary: string,
|
|
760
|
-
responseSchema:
|
|
761
|
+
responseSchema: SchemaObject | RefObject,
|
|
761
762
|
errorCodes: readonly number[],
|
|
762
763
|
description?: string,
|
|
763
764
|
) {
|
|
764
|
-
const op:
|
|
765
|
+
const op: OperationObject = {
|
|
765
766
|
tags: [modelName],
|
|
766
767
|
summary: summary + ' (POST)',
|
|
767
768
|
operationId: `${modelName}${opName.charAt(0).toUpperCase() + opName.slice(1)}Post`,
|
|
@@ -794,24 +795,51 @@ function generatePaths(
|
|
|
794
795
|
config: RouteConfig,
|
|
795
796
|
fields: ModelField[],
|
|
796
797
|
) {
|
|
797
|
-
const
|
|
798
|
+
const postReadsFor = (op: string): boolean => {
|
|
799
|
+
const raw: unknown = (config as Record<string, unknown>)[op]
|
|
800
|
+
const opValue =
|
|
801
|
+
raw && typeof raw === 'object'
|
|
802
|
+
? (raw as { disablePostReads?: boolean }).disablePostReads
|
|
803
|
+
: undefined
|
|
804
|
+
return !(opValue ?? config.disablePostReads ?? false)
|
|
805
|
+
}
|
|
798
806
|
|
|
799
|
-
const createInputRef = {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
const
|
|
807
|
+
const createInputRef = {
|
|
808
|
+
$ref: `#/components/schemas/${modelName}CreateInput`,
|
|
809
|
+
}
|
|
810
|
+
const updateInputRef = {
|
|
811
|
+
$ref: `#/components/schemas/${modelName}UpdateInput`,
|
|
812
|
+
}
|
|
813
|
+
const createManyInputRef = {
|
|
814
|
+
$ref: `#/components/schemas/${modelName}CreateManyInput`,
|
|
815
|
+
}
|
|
816
|
+
const updateManyMutationRef = {
|
|
817
|
+
$ref: `#/components/schemas/${modelName}UpdateManyMutationInput`,
|
|
818
|
+
}
|
|
803
819
|
const responseRef = { $ref: `#/components/schemas/${modelName}Response` }
|
|
804
|
-
const nullableResponseSchema = {
|
|
805
|
-
|
|
820
|
+
const nullableResponseSchema = {
|
|
821
|
+
oneOf: [responseRef, { type: 'null' as const }],
|
|
822
|
+
}
|
|
823
|
+
const batchCountRef = {
|
|
824
|
+
$ref: `#/components/schemas/${modelName}BatchCountResponse`,
|
|
825
|
+
}
|
|
806
826
|
const listRef = { $ref: `#/components/schemas/${modelName}ListResponse` }
|
|
807
|
-
const aggregateRef = {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
const
|
|
827
|
+
const aggregateRef = {
|
|
828
|
+
$ref: `#/components/schemas/${modelName}AggregateResponse`,
|
|
829
|
+
}
|
|
830
|
+
const groupByItemRef = {
|
|
831
|
+
$ref: `#/components/schemas/${modelName}GroupByItem`,
|
|
832
|
+
}
|
|
833
|
+
const updateEachItemRef = {
|
|
834
|
+
$ref: `#/components/schemas/${modelName}UpdateEachItemInput`,
|
|
835
|
+
}
|
|
836
|
+
const updateEachResponseRef = {
|
|
837
|
+
$ref: `#/components/schemas/${modelName}UpdateEachResponse`,
|
|
838
|
+
}
|
|
811
839
|
|
|
812
840
|
if (opEnabled(config, 'findMany')) {
|
|
813
841
|
const meta = OPERATION_BY_NAME['findMany']
|
|
814
|
-
const op:
|
|
842
|
+
const op: OperationObject = {
|
|
815
843
|
tags: [modelName],
|
|
816
844
|
summary: `List ${modelName}`,
|
|
817
845
|
operationId: `${modelName}FindMany`,
|
|
@@ -830,7 +858,7 @@ function generatePaths(
|
|
|
830
858
|
addErrorResponses(op, meta.errors)
|
|
831
859
|
addPath(spec, opPath(basePath, 'findMany'), 'get', op)
|
|
832
860
|
|
|
833
|
-
if (
|
|
861
|
+
if (postReadsFor('findMany')) {
|
|
834
862
|
addPostReadOperation(
|
|
835
863
|
spec,
|
|
836
864
|
postReadPath(basePath, 'findMany'),
|
|
@@ -845,7 +873,7 @@ function generatePaths(
|
|
|
845
873
|
|
|
846
874
|
if (opEnabled(config, 'findUnique')) {
|
|
847
875
|
const meta = OPERATION_BY_NAME['findUnique']
|
|
848
|
-
const op:
|
|
876
|
+
const op: OperationObject = {
|
|
849
877
|
tags: [modelName],
|
|
850
878
|
summary: `Get ${modelName} by unique constraint`,
|
|
851
879
|
operationId: `${modelName}FindUnique`,
|
|
@@ -862,7 +890,7 @@ function generatePaths(
|
|
|
862
890
|
addErrorResponses(op, meta.errors)
|
|
863
891
|
addPath(spec, opPath(basePath, 'findUnique'), 'get', op)
|
|
864
892
|
|
|
865
|
-
if (
|
|
893
|
+
if (postReadsFor('findUnique')) {
|
|
866
894
|
addPostReadOperation(
|
|
867
895
|
spec,
|
|
868
896
|
postReadPath(basePath, 'findUnique'),
|
|
@@ -878,7 +906,7 @@ function generatePaths(
|
|
|
878
906
|
|
|
879
907
|
if (opEnabled(config, 'findUniqueOrThrow')) {
|
|
880
908
|
const meta = OPERATION_BY_NAME['findUniqueOrThrow']
|
|
881
|
-
const op:
|
|
909
|
+
const op: OperationObject = {
|
|
882
910
|
tags: [modelName],
|
|
883
911
|
summary: `Get ${modelName} by unique constraint (throws if not found)`,
|
|
884
912
|
operationId: `${modelName}FindUniqueOrThrow`,
|
|
@@ -893,7 +921,7 @@ function generatePaths(
|
|
|
893
921
|
addErrorResponses(op, meta.errors)
|
|
894
922
|
addPath(spec, opPath(basePath, 'findUniqueOrThrow'), 'get', op)
|
|
895
923
|
|
|
896
|
-
if (
|
|
924
|
+
if (postReadsFor('findUniqueOrThrow')) {
|
|
897
925
|
addPostReadOperation(
|
|
898
926
|
spec,
|
|
899
927
|
postReadPath(basePath, 'findUniqueOrThrow'),
|
|
@@ -908,7 +936,7 @@ function generatePaths(
|
|
|
908
936
|
|
|
909
937
|
if (opEnabled(config, 'findFirst')) {
|
|
910
938
|
const meta = OPERATION_BY_NAME['findFirst']
|
|
911
|
-
const op:
|
|
939
|
+
const op: OperationObject = {
|
|
912
940
|
tags: [modelName],
|
|
913
941
|
summary: `Get first ${modelName}`,
|
|
914
942
|
operationId: `${modelName}FindFirst`,
|
|
@@ -924,7 +952,7 @@ function generatePaths(
|
|
|
924
952
|
addErrorResponses(op, meta.errors)
|
|
925
953
|
addPath(spec, opPath(basePath, 'findFirst'), 'get', op)
|
|
926
954
|
|
|
927
|
-
if (
|
|
955
|
+
if (postReadsFor('findFirst')) {
|
|
928
956
|
addPostReadOperation(
|
|
929
957
|
spec,
|
|
930
958
|
postReadPath(basePath, 'findFirst'),
|
|
@@ -940,7 +968,7 @@ function generatePaths(
|
|
|
940
968
|
|
|
941
969
|
if (opEnabled(config, 'findFirstOrThrow')) {
|
|
942
970
|
const meta = OPERATION_BY_NAME['findFirstOrThrow']
|
|
943
|
-
const op:
|
|
971
|
+
const op: OperationObject = {
|
|
944
972
|
tags: [modelName],
|
|
945
973
|
summary: `Get first ${modelName} (throws if not found)`,
|
|
946
974
|
operationId: `${modelName}FindFirstOrThrow`,
|
|
@@ -955,7 +983,7 @@ function generatePaths(
|
|
|
955
983
|
addErrorResponses(op, meta.errors)
|
|
956
984
|
addPath(spec, opPath(basePath, 'findFirstOrThrow'), 'get', op)
|
|
957
985
|
|
|
958
|
-
if (
|
|
986
|
+
if (postReadsFor('findFirstOrThrow')) {
|
|
959
987
|
addPostReadOperation(
|
|
960
988
|
spec,
|
|
961
989
|
postReadPath(basePath, 'findFirstOrThrow'),
|
|
@@ -970,7 +998,7 @@ function generatePaths(
|
|
|
970
998
|
|
|
971
999
|
if (opEnabled(config, 'findManyPaginated')) {
|
|
972
1000
|
const meta = OPERATION_BY_NAME['findManyPaginated']
|
|
973
|
-
const op:
|
|
1001
|
+
const op: OperationObject = {
|
|
974
1002
|
tags: [modelName],
|
|
975
1003
|
summary: `List ${modelName} with pagination`,
|
|
976
1004
|
operationId: `${modelName}FindManyPaginated`,
|
|
@@ -987,7 +1015,7 @@ function generatePaths(
|
|
|
987
1015
|
addErrorResponses(op, meta.errors)
|
|
988
1016
|
addPath(spec, opPath(basePath, 'findManyPaginated'), 'get', op)
|
|
989
1017
|
|
|
990
|
-
if (
|
|
1018
|
+
if (postReadsFor('findManyPaginated')) {
|
|
991
1019
|
addPostReadOperation(
|
|
992
1020
|
spec,
|
|
993
1021
|
postReadPath(basePath, 'findManyPaginated'),
|
|
@@ -1003,7 +1031,7 @@ function generatePaths(
|
|
|
1003
1031
|
|
|
1004
1032
|
if (opEnabled(config, 'create')) {
|
|
1005
1033
|
const meta = OPERATION_BY_NAME['create']
|
|
1006
|
-
const op:
|
|
1034
|
+
const op: OperationObject = {
|
|
1007
1035
|
tags: [modelName],
|
|
1008
1036
|
summary: `Create ${modelName}`,
|
|
1009
1037
|
operationId: `${modelName}Create`,
|
|
@@ -1035,7 +1063,7 @@ function generatePaths(
|
|
|
1035
1063
|
|
|
1036
1064
|
if (opEnabled(config, 'createMany')) {
|
|
1037
1065
|
const meta = OPERATION_BY_NAME['createMany']
|
|
1038
|
-
const op:
|
|
1066
|
+
const op: OperationObject = {
|
|
1039
1067
|
tags: [modelName],
|
|
1040
1068
|
summary: `Create many ${modelName}`,
|
|
1041
1069
|
operationId: `${modelName}CreateMany`,
|
|
@@ -1071,7 +1099,7 @@ function generatePaths(
|
|
|
1071
1099
|
|
|
1072
1100
|
if (opEnabled(config, 'createManyAndReturn')) {
|
|
1073
1101
|
const meta = OPERATION_BY_NAME['createManyAndReturn']
|
|
1074
|
-
const op:
|
|
1102
|
+
const op: OperationObject = {
|
|
1075
1103
|
tags: [modelName],
|
|
1076
1104
|
summary: `Create many ${modelName} and return records`,
|
|
1077
1105
|
operationId: `${modelName}CreateManyAndReturn`,
|
|
@@ -1112,7 +1140,7 @@ function generatePaths(
|
|
|
1112
1140
|
|
|
1113
1141
|
if (opEnabled(config, 'update')) {
|
|
1114
1142
|
const meta = OPERATION_BY_NAME['update']
|
|
1115
|
-
const op:
|
|
1143
|
+
const op: OperationObject = {
|
|
1116
1144
|
tags: [modelName],
|
|
1117
1145
|
summary: `Update ${modelName}`,
|
|
1118
1146
|
operationId: `${modelName}Update`,
|
|
@@ -1145,7 +1173,7 @@ function generatePaths(
|
|
|
1145
1173
|
|
|
1146
1174
|
if (opEnabled(config, 'updateMany')) {
|
|
1147
1175
|
const meta = OPERATION_BY_NAME['updateMany']
|
|
1148
|
-
const op:
|
|
1176
|
+
const op: OperationObject = {
|
|
1149
1177
|
tags: [modelName],
|
|
1150
1178
|
summary: `Update many ${modelName}`,
|
|
1151
1179
|
operationId: `${modelName}UpdateMany`,
|
|
@@ -1177,7 +1205,7 @@ function generatePaths(
|
|
|
1177
1205
|
|
|
1178
1206
|
if (opEnabled(config, 'updateManyAndReturn')) {
|
|
1179
1207
|
const meta = OPERATION_BY_NAME['updateManyAndReturn']
|
|
1180
|
-
const op:
|
|
1208
|
+
const op: OperationObject = {
|
|
1181
1209
|
tags: [modelName],
|
|
1182
1210
|
summary: `Update many ${modelName} and return records`,
|
|
1183
1211
|
operationId: `${modelName}UpdateManyAndReturn`,
|
|
@@ -1214,7 +1242,7 @@ function generatePaths(
|
|
|
1214
1242
|
|
|
1215
1243
|
if (opEnabled(config, 'upsert')) {
|
|
1216
1244
|
const meta = OPERATION_BY_NAME['upsert']
|
|
1217
|
-
const op:
|
|
1245
|
+
const op: OperationObject = {
|
|
1218
1246
|
tags: [modelName],
|
|
1219
1247
|
summary: `Upsert ${modelName}`,
|
|
1220
1248
|
operationId: `${modelName}Upsert`,
|
|
@@ -1248,7 +1276,7 @@ function generatePaths(
|
|
|
1248
1276
|
|
|
1249
1277
|
if (opEnabled(config, 'delete')) {
|
|
1250
1278
|
const meta = OPERATION_BY_NAME['delete']
|
|
1251
|
-
const op:
|
|
1279
|
+
const op: OperationObject = {
|
|
1252
1280
|
tags: [modelName],
|
|
1253
1281
|
summary: `Delete ${modelName}`,
|
|
1254
1282
|
operationId: `${modelName}Delete`,
|
|
@@ -1280,7 +1308,7 @@ function generatePaths(
|
|
|
1280
1308
|
|
|
1281
1309
|
if (opEnabled(config, 'deleteMany')) {
|
|
1282
1310
|
const meta = OPERATION_BY_NAME['deleteMany']
|
|
1283
|
-
const op:
|
|
1311
|
+
const op: OperationObject = {
|
|
1284
1312
|
tags: [modelName],
|
|
1285
1313
|
summary: `Delete many ${modelName}`,
|
|
1286
1314
|
operationId: `${modelName}DeleteMany`,
|
|
@@ -1309,7 +1337,7 @@ function generatePaths(
|
|
|
1309
1337
|
|
|
1310
1338
|
if (opEnabled(config, 'count')) {
|
|
1311
1339
|
const meta = OPERATION_BY_NAME['count']
|
|
1312
|
-
const op:
|
|
1340
|
+
const op: OperationObject = {
|
|
1313
1341
|
tags: [modelName],
|
|
1314
1342
|
summary: `Count ${modelName}`,
|
|
1315
1343
|
operationId: `${modelName}Count`,
|
|
@@ -1327,7 +1355,8 @@ function generatePaths(
|
|
|
1327
1355
|
},
|
|
1328
1356
|
{
|
|
1329
1357
|
type: 'object',
|
|
1330
|
-
description:
|
|
1358
|
+
description:
|
|
1359
|
+
'Per-field count object when select is provided',
|
|
1331
1360
|
},
|
|
1332
1361
|
],
|
|
1333
1362
|
},
|
|
@@ -1339,7 +1368,7 @@ function generatePaths(
|
|
|
1339
1368
|
addErrorResponses(op, meta.errors)
|
|
1340
1369
|
addPath(spec, opPath(basePath, 'count'), 'get', op)
|
|
1341
1370
|
|
|
1342
|
-
if (
|
|
1371
|
+
if (postReadsFor('count')) {
|
|
1343
1372
|
addPostReadOperation(
|
|
1344
1373
|
spec,
|
|
1345
1374
|
postReadPath(basePath, 'count'),
|
|
@@ -1365,7 +1394,7 @@ function generatePaths(
|
|
|
1365
1394
|
|
|
1366
1395
|
if (opEnabled(config, 'aggregate')) {
|
|
1367
1396
|
const meta = OPERATION_BY_NAME['aggregate']
|
|
1368
|
-
const op:
|
|
1397
|
+
const op: OperationObject = {
|
|
1369
1398
|
tags: [modelName],
|
|
1370
1399
|
summary: `Aggregate ${modelName}`,
|
|
1371
1400
|
operationId: `${modelName}Aggregate`,
|
|
@@ -1380,7 +1409,7 @@ function generatePaths(
|
|
|
1380
1409
|
addErrorResponses(op, meta.errors)
|
|
1381
1410
|
addPath(spec, opPath(basePath, 'aggregate'), 'get', op)
|
|
1382
1411
|
|
|
1383
|
-
if (
|
|
1412
|
+
if (postReadsFor('aggregate')) {
|
|
1384
1413
|
addPostReadOperation(
|
|
1385
1414
|
spec,
|
|
1386
1415
|
postReadPath(basePath, 'aggregate'),
|
|
@@ -1395,7 +1424,7 @@ function generatePaths(
|
|
|
1395
1424
|
|
|
1396
1425
|
if (opEnabled(config, 'groupBy')) {
|
|
1397
1426
|
const meta = OPERATION_BY_NAME['groupBy']
|
|
1398
|
-
const op:
|
|
1427
|
+
const op: OperationObject = {
|
|
1399
1428
|
tags: [modelName],
|
|
1400
1429
|
summary: `Group ${modelName}`,
|
|
1401
1430
|
operationId: `${modelName}GroupBy`,
|
|
@@ -1416,7 +1445,7 @@ function generatePaths(
|
|
|
1416
1445
|
addErrorResponses(op, meta.errors)
|
|
1417
1446
|
addPath(spec, opPath(basePath, 'groupBy'), 'get', op)
|
|
1418
1447
|
|
|
1419
|
-
if (
|
|
1448
|
+
if (postReadsFor('groupBy')) {
|
|
1420
1449
|
addPostReadOperation(
|
|
1421
1450
|
spec,
|
|
1422
1451
|
postReadPath(basePath, 'groupBy'),
|
|
@@ -1432,7 +1461,7 @@ function generatePaths(
|
|
|
1432
1461
|
|
|
1433
1462
|
if (opEnabled(config, 'updateEach')) {
|
|
1434
1463
|
const meta = OPERATION_BY_NAME['updateEach']
|
|
1435
|
-
const op:
|
|
1464
|
+
const op: OperationObject = {
|
|
1436
1465
|
tags: [modelName],
|
|
1437
1466
|
summary: `Update each ${modelName} (batch)`,
|
|
1438
1467
|
operationId: `${modelName}UpdateEach`,
|
|
@@ -1479,7 +1508,7 @@ function addPath(
|
|
|
1479
1508
|
spec: OpenApiSpec,
|
|
1480
1509
|
path: string,
|
|
1481
1510
|
method: string,
|
|
1482
|
-
operation:
|
|
1511
|
+
operation: OperationObject,
|
|
1483
1512
|
) {
|
|
1484
1513
|
if (!spec.paths[path]) {
|
|
1485
1514
|
spec.paths[path] = {}
|
|
@@ -1581,12 +1610,30 @@ function mapFieldToSchema(field: ModelField): SchemaObject | RefObject {
|
|
|
1581
1610
|
}
|
|
1582
1611
|
|
|
1583
1612
|
function nestedListRelationOps(fieldType: string): SchemaObject {
|
|
1584
|
-
const createInput: SchemaObject = {
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
const
|
|
1589
|
-
|
|
1613
|
+
const createInput: SchemaObject = {
|
|
1614
|
+
type: 'object',
|
|
1615
|
+
description: `${fieldType} create input`,
|
|
1616
|
+
}
|
|
1617
|
+
const uniqueId: SchemaObject = {
|
|
1618
|
+
type: 'object',
|
|
1619
|
+
description: 'Unique identifier',
|
|
1620
|
+
}
|
|
1621
|
+
const uniqueConnect: SchemaObject = {
|
|
1622
|
+
type: 'object',
|
|
1623
|
+
description: 'Unique identifier to connect',
|
|
1624
|
+
}
|
|
1625
|
+
const uniqueDisconnect: SchemaObject = {
|
|
1626
|
+
type: 'object',
|
|
1627
|
+
description: 'Unique identifier to disconnect',
|
|
1628
|
+
}
|
|
1629
|
+
const uniqueDelete: SchemaObject = {
|
|
1630
|
+
type: 'object',
|
|
1631
|
+
description: 'Unique identifier to delete',
|
|
1632
|
+
}
|
|
1633
|
+
const whereFilter: SchemaObject = {
|
|
1634
|
+
type: 'object',
|
|
1635
|
+
description: 'Where filter',
|
|
1636
|
+
}
|
|
1590
1637
|
const whereCreatePair: SchemaObject = {
|
|
1591
1638
|
type: 'object',
|
|
1592
1639
|
description: '{ where, create } pair',
|
|
@@ -1648,12 +1695,16 @@ function nestedSingleRelationOps(fieldType: string): SchemaObject {
|
|
|
1648
1695
|
description: '{ where, create } pair',
|
|
1649
1696
|
properties: { where: { type: 'object' }, create: { type: 'object' } },
|
|
1650
1697
|
},
|
|
1651
|
-
disconnect: {
|
|
1698
|
+
disconnect: {
|
|
1699
|
+
type: 'boolean',
|
|
1700
|
+
description: 'Disconnect the related record',
|
|
1701
|
+
},
|
|
1652
1702
|
delete: { type: 'boolean', description: 'Delete the related record' },
|
|
1653
1703
|
update: { type: 'object', description: `${fieldType} update input` },
|
|
1654
1704
|
upsert: {
|
|
1655
1705
|
type: 'object',
|
|
1656
|
-
description:
|
|
1706
|
+
description:
|
|
1707
|
+
'{ create, update } pair — create if not exists, update if exists',
|
|
1657
1708
|
properties: {
|
|
1658
1709
|
create: { type: 'object', description: `${fieldType} create input` },
|
|
1659
1710
|
update: { type: 'object', description: `${fieldType} update input` },
|
|
@@ -1668,7 +1719,9 @@ function mapFieldToWriteSchema(
|
|
|
1668
1719
|
mode: 'create' | 'update',
|
|
1669
1720
|
): SchemaObject | RefObject {
|
|
1670
1721
|
if (field.kind === 'object') {
|
|
1671
|
-
return field.isList
|
|
1722
|
+
return field.isList
|
|
1723
|
+
? nestedListRelationOps(field.type)
|
|
1724
|
+
: nestedSingleRelationOps(field.type)
|
|
1672
1725
|
}
|
|
1673
1726
|
|
|
1674
1727
|
let baseSchema: SchemaObject | RefObject
|
|
@@ -1733,4 +1786,4 @@ function mapScalarType(type: string): SchemaObject {
|
|
|
1733
1786
|
},
|
|
1734
1787
|
}
|
|
1735
1788
|
return typeMap[type] || { type: 'string' }
|
|
1736
|
-
}
|
|
1789
|
+
}
|