prisma-generator-express 1.59.0 → 1.60.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/dist/client/encodeQueryParams.js +19 -23
- package/dist/client/encodeQueryParams.js.map +1 -1
- package/dist/copy/operationDefinitions.d.ts +37 -0
- package/dist/copy/operationDefinitions.js +412 -0
- package/dist/copy/operationDefinitions.js.map +1 -0
- package/dist/generators/generateFastifyHandler.js +10 -41
- package/dist/generators/generateFastifyHandler.js.map +1 -1
- package/dist/generators/generateHonoHandler.js +10 -41
- package/dist/generators/generateHonoHandler.js.map +1 -1
- package/dist/generators/generateModelMetadata.d.ts +8 -0
- package/dist/generators/generateModelMetadata.js +77 -0
- package/dist/generators/generateModelMetadata.js.map +1 -0
- package/dist/generators/generateOperationCore.js +20 -30
- package/dist/generators/generateOperationCore.js.map +1 -1
- package/dist/generators/generateQueryBuilderHelper.js +1 -1
- package/dist/generators/generateQueryBuilderHelper.js.map +1 -1
- package/dist/generators/generateRouteConfigType.js +11 -57
- package/dist/generators/generateRouteConfigType.js.map +1 -1
- package/dist/generators/generateRouter.js +64 -177
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.js +59 -169
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.js +52 -152
- package/dist/generators/generateRouterHono.js.map +1 -1
- package/dist/generators/generateUnifiedHandler.js +7 -30
- package/dist/generators/generateUnifiedHandler.js.map +1 -1
- package/dist/generators/generateUnifiedScalarUI.js +9 -74
- package/dist/generators/generateUnifiedScalarUI.js.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/utils/copyFiles.js +7 -0
- package/dist/utils/copyFiles.js.map +1 -1
- package/dist/utils/writeFileSafely.js +5 -12
- package/dist/utils/writeFileSafely.js.map +1 -1
- package/package.json +12 -2
- package/src/client/encodeQueryParams.ts +23 -36
- package/src/copy/autoIncludePlanner.ts +14 -23
- package/src/copy/autoIncludeRuntime.ts +117 -228
- package/src/copy/buildModelOpenApi.ts +248 -628
- package/src/copy/concurrency.ts +20 -0
- package/src/copy/docsRenderer.ts +63 -333
- package/src/copy/errorMapper.ts +126 -0
- package/src/copy/guardHelpers.ts +56 -0
- package/src/copy/materializedCount.ts +68 -0
- package/src/copy/materializedRouter.ts +33 -29
- package/src/copy/operationDefinitions.ts +359 -35
- package/src/copy/operationRuntime.ts +11 -605
- package/src/copy/pagination.ts +151 -0
- package/src/copy/scalarTypes.ts +2 -0
- package/src/copy/sse.ts +296 -0
- package/src/generators/generateFastifyHandler.ts +13 -47
- package/src/generators/generateHonoHandler.ts +13 -47
- package/src/generators/generateModelMetadata.ts +92 -0
- package/src/generators/generateOperationCore.ts +19 -32
- package/src/generators/generateQueryBuilderHelper.ts +1 -1
- package/src/generators/generateRouteConfigType.ts +9 -60
- package/src/generators/generateRouter.ts +88 -180
- package/src/generators/generateRouterFastify.ts +65 -172
- package/src/generators/generateRouterHono.ts +58 -155
- package/src/generators/generateUnifiedHandler.ts +8 -33
- package/src/generators/generateUnifiedScalarUI.ts +9 -91
- package/src/index.ts +13 -1
- package/src/utils/copyFiles.ts +7 -0
- package/src/utils/writeFileSafely.ts +5 -11
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { stringify as yamlStringify } from 'yaml'
|
|
1
2
|
import type { RouteConfig, WriteStrategy } from './routeConfig'
|
|
2
|
-
import {
|
|
3
|
+
import { OPERATION_BY_NAME, isOperationEnabled } from './operationDefinitions'
|
|
3
4
|
import { normalizePrefix, removeTrailingSlash } from './misc'
|
|
5
|
+
import { NUMERIC_SCALAR_TYPES, STRING_NUMERIC_TYPES } from './scalarTypes'
|
|
4
6
|
|
|
5
7
|
type SchemaObject = {
|
|
6
8
|
type?: string | string[]
|
|
@@ -13,6 +15,7 @@ type SchemaObject = {
|
|
|
13
15
|
oneOf?: (SchemaObject | RefObject)[]
|
|
14
16
|
allOf?: (SchemaObject | RefObject)[]
|
|
15
17
|
nullable?: boolean
|
|
18
|
+
maxItems?: number
|
|
16
19
|
}
|
|
17
20
|
|
|
18
21
|
type RefObject = { $ref: string; description?: string }
|
|
@@ -54,21 +57,44 @@ type BuildOptions = {
|
|
|
54
57
|
writeStrategy?: WriteStrategy
|
|
55
58
|
}
|
|
56
59
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
const
|
|
60
|
+
const WHERE_PROP: SchemaObject = { type: 'object', description: 'Filter conditions' }
|
|
61
|
+
const TAKE_PROP: SchemaObject = { type: 'integer', description: 'Limit results' }
|
|
62
|
+
const SKIP_PROP: SchemaObject = { type: 'integer', description: 'Skip results' }
|
|
63
|
+
const CURSOR_PROP: SchemaObject = { type: 'object', description: 'Cursor for pagination' }
|
|
64
|
+
const ORDERBY_PROP: SchemaObject = { description: 'Sort order (object or array of objects)' }
|
|
65
|
+
const SELECT_PROP: SchemaObject = { type: 'object', description: 'Select fields' }
|
|
66
|
+
const INCLUDE_PROP: SchemaObject = { type: 'object', description: 'Include relations' }
|
|
67
|
+
const OMIT_PROP: SchemaObject = { type: 'object', description: 'Omit fields from response' }
|
|
68
|
+
const DISTINCT_PROP: SchemaObject = { description: 'Distinct fields (string or array of strings)' }
|
|
69
|
+
const AGG_COUNT: SchemaObject = { description: 'Count aggregate (true or field selection object)' }
|
|
70
|
+
const AGG_AVG: SchemaObject = { type: 'object', description: 'Average aggregate (field selection object)' }
|
|
71
|
+
const AGG_SUM: SchemaObject = { type: 'object', description: 'Sum aggregate (field selection object)' }
|
|
72
|
+
const AGG_MIN: SchemaObject = { type: 'object', description: 'Min aggregate (field selection object)' }
|
|
73
|
+
const AGG_MAX: SchemaObject = { type: 'object', description: 'Max aggregate (field selection object)' }
|
|
74
|
+
|
|
75
|
+
const PROJECTION_PROPS: Record<string, SchemaObject> = {
|
|
76
|
+
select: SELECT_PROP,
|
|
77
|
+
include: INCLUDE_PROP,
|
|
78
|
+
omit: OMIT_PROP,
|
|
79
|
+
}
|
|
60
80
|
|
|
61
|
-
const
|
|
81
|
+
const AGGREGATE_PROPS: Record<string, SchemaObject> = {
|
|
82
|
+
_count: AGG_COUNT,
|
|
83
|
+
_avg: AGG_AVG,
|
|
84
|
+
_sum: AGG_SUM,
|
|
85
|
+
_min: AGG_MIN,
|
|
86
|
+
_max: AGG_MAX,
|
|
87
|
+
}
|
|
62
88
|
|
|
63
89
|
function opEnabled(config: RouteConfig, name: string): boolean {
|
|
64
|
-
const
|
|
65
|
-
return
|
|
90
|
+
const meta = OPERATION_BY_NAME[name]
|
|
91
|
+
return meta ? isOperationEnabled(config as Record<string, any>, meta) : false
|
|
66
92
|
}
|
|
67
93
|
|
|
68
94
|
function opPath(basePath: string, name: string): string {
|
|
69
|
-
const
|
|
70
|
-
if (!
|
|
71
|
-
return `${basePath}${
|
|
95
|
+
const meta = OPERATION_BY_NAME[name]
|
|
96
|
+
if (!meta.pathSuffix) return basePath || '/'
|
|
97
|
+
return `${basePath}${meta.pathSuffix}`
|
|
72
98
|
}
|
|
73
99
|
|
|
74
100
|
function postReadPath(basePath: string, name: string): string {
|
|
@@ -97,7 +123,7 @@ const COMMON_ERRORS: Record<number, string> = {
|
|
|
97
123
|
503: 'Service unavailable — database connection pool timeout',
|
|
98
124
|
}
|
|
99
125
|
|
|
100
|
-
function addErrorResponses(operation: any, codes: number[]): void {
|
|
126
|
+
function addErrorResponses(operation: any, codes: readonly number[]): void {
|
|
101
127
|
for (const code of codes) {
|
|
102
128
|
operation.responses[String(code)] = errorResponse(
|
|
103
129
|
COMMON_ERRORS[code] || 'Error',
|
|
@@ -116,6 +142,10 @@ function queryParam(
|
|
|
116
142
|
return param
|
|
117
143
|
}
|
|
118
144
|
|
|
145
|
+
const oneOrMany = (schema: SchemaObject | RefObject): SchemaObject => ({
|
|
146
|
+
oneOf: [schema, { type: 'array', items: schema }],
|
|
147
|
+
})
|
|
148
|
+
|
|
119
149
|
function scalarUpdateOperations(
|
|
120
150
|
baseSchema: SchemaObject | RefObject,
|
|
121
151
|
fieldType: string,
|
|
@@ -156,15 +186,13 @@ function findManyBodySchema(): SchemaObject {
|
|
|
156
186
|
return {
|
|
157
187
|
type: 'object',
|
|
158
188
|
properties: {
|
|
159
|
-
where:
|
|
160
|
-
orderBy:
|
|
161
|
-
take:
|
|
162
|
-
skip:
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
cursor: { type: 'object', description: 'Cursor for pagination' },
|
|
167
|
-
distinct: { description: 'Distinct fields (string or array of strings)' },
|
|
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,
|
|
168
196
|
},
|
|
169
197
|
}
|
|
170
198
|
}
|
|
@@ -174,9 +202,7 @@ function findUniqueBodySchema(): SchemaObject {
|
|
|
174
202
|
type: 'object',
|
|
175
203
|
properties: {
|
|
176
204
|
where: { type: 'object', description: 'Unique selector' },
|
|
177
|
-
|
|
178
|
-
include: { type: 'object', description: 'Include relations' },
|
|
179
|
-
omit: { type: 'object', description: 'Omit fields from response' },
|
|
205
|
+
...PROJECTION_PROPS,
|
|
180
206
|
},
|
|
181
207
|
required: ['where'],
|
|
182
208
|
}
|
|
@@ -186,11 +212,11 @@ function countBodySchema(): SchemaObject {
|
|
|
186
212
|
return {
|
|
187
213
|
type: 'object',
|
|
188
214
|
properties: {
|
|
189
|
-
where:
|
|
215
|
+
where: WHERE_PROP,
|
|
190
216
|
orderBy: { description: 'Sort order' },
|
|
191
|
-
take:
|
|
192
|
-
skip:
|
|
193
|
-
cursor:
|
|
217
|
+
take: TAKE_PROP,
|
|
218
|
+
skip: SKIP_PROP,
|
|
219
|
+
cursor: CURSOR_PROP,
|
|
194
220
|
select: {
|
|
195
221
|
description:
|
|
196
222
|
'Count specific fields. When provided, returns per-field counts as an object instead of a single integer.',
|
|
@@ -203,30 +229,12 @@ function aggregateBodySchema(): SchemaObject {
|
|
|
203
229
|
return {
|
|
204
230
|
type: 'object',
|
|
205
231
|
properties: {
|
|
206
|
-
where:
|
|
232
|
+
where: WHERE_PROP,
|
|
207
233
|
orderBy: { description: 'Sort order' },
|
|
208
|
-
cursor:
|
|
209
|
-
take:
|
|
210
|
-
skip:
|
|
211
|
-
|
|
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
|
-
},
|
|
234
|
+
cursor: CURSOR_PROP,
|
|
235
|
+
take: TAKE_PROP,
|
|
236
|
+
skip: SKIP_PROP,
|
|
237
|
+
...AGGREGATE_PROPS,
|
|
230
238
|
},
|
|
231
239
|
}
|
|
232
240
|
}
|
|
@@ -240,57 +248,34 @@ function groupByBodySchema(): SchemaObject {
|
|
|
240
248
|
items: { type: 'string' },
|
|
241
249
|
description: 'Fields to group by',
|
|
242
250
|
},
|
|
243
|
-
where:
|
|
251
|
+
where: WHERE_PROP,
|
|
244
252
|
orderBy: { description: 'Sort order. Required when using skip or take.' },
|
|
245
253
|
having: {
|
|
246
254
|
type: 'object',
|
|
247
255
|
description: 'Having conditions (filter object)',
|
|
248
256
|
},
|
|
249
|
-
take:
|
|
250
|
-
skip:
|
|
251
|
-
|
|
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
|
-
},
|
|
257
|
+
take: TAKE_PROP,
|
|
258
|
+
skip: SKIP_PROP,
|
|
259
|
+
...AGGREGATE_PROPS,
|
|
270
260
|
},
|
|
271
261
|
required: ['by'],
|
|
272
262
|
}
|
|
273
263
|
}
|
|
274
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
|
+
|
|
275
277
|
function getPostReadBodySchema(opName: string): SchemaObject {
|
|
276
|
-
|
|
277
|
-
case 'findMany':
|
|
278
|
-
case 'findFirst':
|
|
279
|
-
case 'findFirstOrThrow':
|
|
280
|
-
case 'findManyPaginated':
|
|
281
|
-
return findManyBodySchema()
|
|
282
|
-
case 'findUnique':
|
|
283
|
-
case 'findUniqueOrThrow':
|
|
284
|
-
return findUniqueBodySchema()
|
|
285
|
-
case 'count':
|
|
286
|
-
return countBodySchema()
|
|
287
|
-
case 'aggregate':
|
|
288
|
-
return aggregateBodySchema()
|
|
289
|
-
case 'groupBy':
|
|
290
|
-
return groupByBodySchema()
|
|
291
|
-
default:
|
|
292
|
-
return findManyBodySchema()
|
|
293
|
-
}
|
|
278
|
+
return (POST_READ_BODY_SCHEMAS[opName] ?? findManyBodySchema)()
|
|
294
279
|
}
|
|
295
280
|
|
|
296
281
|
function applyWriteStrategy(
|
|
@@ -335,36 +320,30 @@ function applyWriteStrategy(
|
|
|
335
320
|
}
|
|
336
321
|
const reqSchema = op.requestBody?.content?.['application/json']?.schema
|
|
337
322
|
if (reqSchema && reqSchema.properties) {
|
|
338
|
-
reqSchema.properties
|
|
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
|
-
}
|
|
323
|
+
Object.assign(reqSchema.properties, PROJECTION_PROPS)
|
|
350
324
|
}
|
|
351
325
|
}
|
|
352
326
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
}
|
|
327
|
+
const forceReturnOps: Array<{
|
|
328
|
+
method: 'post' | 'put'
|
|
329
|
+
successCode: '200' | '201'
|
|
330
|
+
verb: string
|
|
331
|
+
targetOp: string
|
|
332
|
+
}> = [
|
|
333
|
+
{ method: 'post', successCode: '201', verb: 'Create', targetOp: 'createManyAndReturn' },
|
|
334
|
+
{ method: 'put', successCode: '200', verb: 'Update', targetOp: 'updateManyAndReturn' },
|
|
335
|
+
]
|
|
361
336
|
|
|
362
|
-
|
|
337
|
+
for (const entry of forceReturnOps) {
|
|
338
|
+
const target = node[entry.method]
|
|
339
|
+
if (!target) continue
|
|
363
340
|
injectProjectionAndArrayResponse(
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
'
|
|
367
|
-
'writeStrategy="forceReturn": this endpoint silently invokes
|
|
341
|
+
target,
|
|
342
|
+
entry.successCode,
|
|
343
|
+
entry.verb + ' many ' + modelName + ' (forceReturn)',
|
|
344
|
+
'writeStrategy="forceReturn": this endpoint silently invokes ' + entry.targetOp +
|
|
345
|
+
' and returns the ' + (entry.verb === 'Create' ? 'created' : 'updated') +
|
|
346
|
+
' records instead of { count }.',
|
|
368
347
|
)
|
|
369
348
|
}
|
|
370
349
|
}
|
|
@@ -430,13 +409,11 @@ export function buildModelOpenApi(
|
|
|
430
409
|
}
|
|
431
410
|
|
|
432
411
|
generateOperationSchemas(spec, modelName, modelFields)
|
|
433
|
-
|
|
434
412
|
generatePaths(spec, modelName, basePath, config, modelFields)
|
|
435
|
-
|
|
436
413
|
applyWriteStrategy(spec, modelName, basePath, options.writeStrategy)
|
|
437
414
|
|
|
438
415
|
if (options.format === 'yaml') {
|
|
439
|
-
return
|
|
416
|
+
return yamlStringify(spec)
|
|
440
417
|
}
|
|
441
418
|
return spec
|
|
442
419
|
}
|
|
@@ -446,12 +423,9 @@ function generateOperationSchemas(
|
|
|
446
423
|
modelName: string,
|
|
447
424
|
fields: ModelField[],
|
|
448
425
|
) {
|
|
449
|
-
const relatedModels = new Set
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
relatedModels.add(field.type)
|
|
453
|
-
}
|
|
454
|
-
})
|
|
426
|
+
const relatedModels = new Set(
|
|
427
|
+
fields.filter((f) => f.kind === 'object').map((f) => f.type),
|
|
428
|
+
)
|
|
455
429
|
|
|
456
430
|
relatedModels.forEach((relatedModel) => {
|
|
457
431
|
if (!spec.components.schemas[`${relatedModel}Response`]) {
|
|
@@ -613,11 +587,6 @@ function generateOperationSchemas(
|
|
|
613
587
|
(f) => f.kind === 'scalar' && NUMERIC_SCALAR_TYPES.has(f.type),
|
|
614
588
|
)
|
|
615
589
|
|
|
616
|
-
const numericFieldSelection: Record<string, SchemaObject> = {}
|
|
617
|
-
for (const f of numericFields) {
|
|
618
|
-
numericFieldSelection[f.name] = { type: 'boolean' }
|
|
619
|
-
}
|
|
620
|
-
|
|
621
590
|
const avgResultProps: Record<string, SchemaObject> = {}
|
|
622
591
|
const numericResultProps: Record<string, SchemaObject> = {}
|
|
623
592
|
for (const f of numericFields) {
|
|
@@ -632,15 +601,6 @@ function generateOperationSchemas(
|
|
|
632
601
|
: { oneOf: [{ type: 'number' }, { type: 'null' }] }
|
|
633
602
|
}
|
|
634
603
|
|
|
635
|
-
const allFieldSelection: Record<string, SchemaObject> = {
|
|
636
|
-
_all: { type: 'boolean' },
|
|
637
|
-
}
|
|
638
|
-
for (const f of fields) {
|
|
639
|
-
if (f.kind === 'scalar' || f.kind === 'enum') {
|
|
640
|
-
allFieldSelection[f.name] = { type: 'boolean' }
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
|
|
644
604
|
const countResultProps: Record<string, SchemaObject> = {
|
|
645
605
|
_all: { type: 'integer' },
|
|
646
606
|
}
|
|
@@ -798,7 +758,7 @@ function addPostReadOperation(
|
|
|
798
758
|
opName: string,
|
|
799
759
|
summary: string,
|
|
800
760
|
responseSchema: any,
|
|
801
|
-
errorCodes: number[],
|
|
761
|
+
errorCodes: readonly number[],
|
|
802
762
|
description?: string,
|
|
803
763
|
) {
|
|
804
764
|
const op: any = {
|
|
@@ -836,40 +796,21 @@ function generatePaths(
|
|
|
836
796
|
) {
|
|
837
797
|
const postReads = !config.disablePostReads
|
|
838
798
|
|
|
839
|
-
const createInputRef = {
|
|
840
|
-
|
|
841
|
-
}
|
|
842
|
-
const
|
|
843
|
-
$ref: `#/components/schemas/${modelName}UpdateInput`,
|
|
844
|
-
}
|
|
845
|
-
const createManyInputRef = {
|
|
846
|
-
$ref: `#/components/schemas/${modelName}CreateManyInput`,
|
|
847
|
-
}
|
|
848
|
-
const updateManyMutationRef = {
|
|
849
|
-
$ref: `#/components/schemas/${modelName}UpdateManyMutationInput`,
|
|
850
|
-
}
|
|
799
|
+
const createInputRef = { $ref: `#/components/schemas/${modelName}CreateInput` }
|
|
800
|
+
const updateInputRef = { $ref: `#/components/schemas/${modelName}UpdateInput` }
|
|
801
|
+
const createManyInputRef = { $ref: `#/components/schemas/${modelName}CreateManyInput` }
|
|
802
|
+
const updateManyMutationRef = { $ref: `#/components/schemas/${modelName}UpdateManyMutationInput` }
|
|
851
803
|
const responseRef = { $ref: `#/components/schemas/${modelName}Response` }
|
|
852
|
-
const nullableResponseSchema = {
|
|
853
|
-
|
|
854
|
-
}
|
|
855
|
-
const batchCountRef = {
|
|
856
|
-
$ref: `#/components/schemas/${modelName}BatchCountResponse`,
|
|
857
|
-
}
|
|
804
|
+
const nullableResponseSchema = { oneOf: [responseRef, { type: 'null' as const }] }
|
|
805
|
+
const batchCountRef = { $ref: `#/components/schemas/${modelName}BatchCountResponse` }
|
|
858
806
|
const listRef = { $ref: `#/components/schemas/${modelName}ListResponse` }
|
|
859
|
-
const aggregateRef = {
|
|
860
|
-
|
|
861
|
-
}
|
|
862
|
-
const
|
|
863
|
-
$ref: `#/components/schemas/${modelName}GroupByItem`,
|
|
864
|
-
}
|
|
865
|
-
const updateEachItemRef = {
|
|
866
|
-
$ref: `#/components/schemas/${modelName}UpdateEachItemInput`,
|
|
867
|
-
}
|
|
868
|
-
const updateEachResponseRef = {
|
|
869
|
-
$ref: `#/components/schemas/${modelName}UpdateEachResponse`,
|
|
870
|
-
}
|
|
807
|
+
const aggregateRef = { $ref: `#/components/schemas/${modelName}AggregateResponse` }
|
|
808
|
+
const groupByItemRef = { $ref: `#/components/schemas/${modelName}GroupByItem` }
|
|
809
|
+
const updateEachItemRef = { $ref: `#/components/schemas/${modelName}UpdateEachItemInput` }
|
|
810
|
+
const updateEachResponseRef = { $ref: `#/components/schemas/${modelName}UpdateEachResponse` }
|
|
871
811
|
|
|
872
812
|
if (opEnabled(config, 'findMany')) {
|
|
813
|
+
const meta = OPERATION_BY_NAME['findMany']
|
|
873
814
|
const op: any = {
|
|
874
815
|
tags: [modelName],
|
|
875
816
|
summary: `List ${modelName}`,
|
|
@@ -886,7 +827,7 @@ function generatePaths(
|
|
|
886
827
|
},
|
|
887
828
|
},
|
|
888
829
|
}
|
|
889
|
-
addErrorResponses(op,
|
|
830
|
+
addErrorResponses(op, meta.errors)
|
|
890
831
|
addPath(spec, opPath(basePath, 'findMany'), 'get', op)
|
|
891
832
|
|
|
892
833
|
if (postReads) {
|
|
@@ -897,12 +838,13 @@ function generatePaths(
|
|
|
897
838
|
'findMany',
|
|
898
839
|
`List ${modelName}`,
|
|
899
840
|
{ type: 'array', items: responseRef },
|
|
900
|
-
|
|
841
|
+
meta.errors,
|
|
901
842
|
)
|
|
902
843
|
}
|
|
903
844
|
}
|
|
904
845
|
|
|
905
846
|
if (opEnabled(config, 'findUnique')) {
|
|
847
|
+
const meta = OPERATION_BY_NAME['findUnique']
|
|
906
848
|
const op: any = {
|
|
907
849
|
tags: [modelName],
|
|
908
850
|
summary: `Get ${modelName} by unique constraint`,
|
|
@@ -917,7 +859,7 @@ function generatePaths(
|
|
|
917
859
|
},
|
|
918
860
|
},
|
|
919
861
|
}
|
|
920
|
-
addErrorResponses(op,
|
|
862
|
+
addErrorResponses(op, meta.errors)
|
|
921
863
|
addPath(spec, opPath(basePath, 'findUnique'), 'get', op)
|
|
922
864
|
|
|
923
865
|
if (postReads) {
|
|
@@ -928,13 +870,14 @@ function generatePaths(
|
|
|
928
870
|
'findUnique',
|
|
929
871
|
`Get ${modelName} by unique constraint`,
|
|
930
872
|
nullableResponseSchema,
|
|
931
|
-
|
|
873
|
+
meta.errors,
|
|
932
874
|
'Returns null with status 200 when no record matches the unique constraint.',
|
|
933
875
|
)
|
|
934
876
|
}
|
|
935
877
|
}
|
|
936
878
|
|
|
937
879
|
if (opEnabled(config, 'findUniqueOrThrow')) {
|
|
880
|
+
const meta = OPERATION_BY_NAME['findUniqueOrThrow']
|
|
938
881
|
const op: any = {
|
|
939
882
|
tags: [modelName],
|
|
940
883
|
summary: `Get ${modelName} by unique constraint (throws if not found)`,
|
|
@@ -947,7 +890,7 @@ function generatePaths(
|
|
|
947
890
|
},
|
|
948
891
|
},
|
|
949
892
|
}
|
|
950
|
-
addErrorResponses(op,
|
|
893
|
+
addErrorResponses(op, meta.errors)
|
|
951
894
|
addPath(spec, opPath(basePath, 'findUniqueOrThrow'), 'get', op)
|
|
952
895
|
|
|
953
896
|
if (postReads) {
|
|
@@ -958,12 +901,13 @@ function generatePaths(
|
|
|
958
901
|
'findUniqueOrThrow',
|
|
959
902
|
`Get ${modelName} by unique constraint (throws if not found)`,
|
|
960
903
|
responseRef,
|
|
961
|
-
|
|
904
|
+
meta.errors,
|
|
962
905
|
)
|
|
963
906
|
}
|
|
964
907
|
}
|
|
965
908
|
|
|
966
909
|
if (opEnabled(config, 'findFirst')) {
|
|
910
|
+
const meta = OPERATION_BY_NAME['findFirst']
|
|
967
911
|
const op: any = {
|
|
968
912
|
tags: [modelName],
|
|
969
913
|
summary: `Get first ${modelName}`,
|
|
@@ -977,7 +921,7 @@ function generatePaths(
|
|
|
977
921
|
},
|
|
978
922
|
},
|
|
979
923
|
}
|
|
980
|
-
addErrorResponses(op,
|
|
924
|
+
addErrorResponses(op, meta.errors)
|
|
981
925
|
addPath(spec, opPath(basePath, 'findFirst'), 'get', op)
|
|
982
926
|
|
|
983
927
|
if (postReads) {
|
|
@@ -988,13 +932,14 @@ function generatePaths(
|
|
|
988
932
|
'findFirst',
|
|
989
933
|
`Get first ${modelName}`,
|
|
990
934
|
nullableResponseSchema,
|
|
991
|
-
|
|
935
|
+
meta.errors,
|
|
992
936
|
'Returns null with status 200 when no record matches.',
|
|
993
937
|
)
|
|
994
938
|
}
|
|
995
939
|
}
|
|
996
940
|
|
|
997
941
|
if (opEnabled(config, 'findFirstOrThrow')) {
|
|
942
|
+
const meta = OPERATION_BY_NAME['findFirstOrThrow']
|
|
998
943
|
const op: any = {
|
|
999
944
|
tags: [modelName],
|
|
1000
945
|
summary: `Get first ${modelName} (throws if not found)`,
|
|
@@ -1007,7 +952,7 @@ function generatePaths(
|
|
|
1007
952
|
},
|
|
1008
953
|
},
|
|
1009
954
|
}
|
|
1010
|
-
addErrorResponses(op,
|
|
955
|
+
addErrorResponses(op, meta.errors)
|
|
1011
956
|
addPath(spec, opPath(basePath, 'findFirstOrThrow'), 'get', op)
|
|
1012
957
|
|
|
1013
958
|
if (postReads) {
|
|
@@ -1018,12 +963,13 @@ function generatePaths(
|
|
|
1018
963
|
'findFirstOrThrow',
|
|
1019
964
|
`Get first ${modelName} (throws if not found)`,
|
|
1020
965
|
responseRef,
|
|
1021
|
-
|
|
966
|
+
meta.errors,
|
|
1022
967
|
)
|
|
1023
968
|
}
|
|
1024
969
|
}
|
|
1025
970
|
|
|
1026
971
|
if (opEnabled(config, 'findManyPaginated')) {
|
|
972
|
+
const meta = OPERATION_BY_NAME['findManyPaginated']
|
|
1027
973
|
const op: any = {
|
|
1028
974
|
tags: [modelName],
|
|
1029
975
|
summary: `List ${modelName} with pagination`,
|
|
@@ -1038,7 +984,7 @@ function generatePaths(
|
|
|
1038
984
|
},
|
|
1039
985
|
},
|
|
1040
986
|
}
|
|
1041
|
-
addErrorResponses(op,
|
|
987
|
+
addErrorResponses(op, meta.errors)
|
|
1042
988
|
addPath(spec, opPath(basePath, 'findManyPaginated'), 'get', op)
|
|
1043
989
|
|
|
1044
990
|
if (postReads) {
|
|
@@ -1049,13 +995,14 @@ function generatePaths(
|
|
|
1049
995
|
'findManyPaginated',
|
|
1050
996
|
`List ${modelName} with pagination`,
|
|
1051
997
|
listRef,
|
|
1052
|
-
|
|
998
|
+
meta.errors,
|
|
1053
999
|
'Returns paginated results with total count.',
|
|
1054
1000
|
)
|
|
1055
1001
|
}
|
|
1056
1002
|
}
|
|
1057
1003
|
|
|
1058
1004
|
if (opEnabled(config, 'create')) {
|
|
1005
|
+
const meta = OPERATION_BY_NAME['create']
|
|
1059
1006
|
const op: any = {
|
|
1060
1007
|
tags: [modelName],
|
|
1061
1008
|
summary: `Create ${modelName}`,
|
|
@@ -1068,18 +1015,7 @@ function generatePaths(
|
|
|
1068
1015
|
type: 'object',
|
|
1069
1016
|
properties: {
|
|
1070
1017
|
data: createInputRef,
|
|
1071
|
-
|
|
1072
|
-
type: 'object',
|
|
1073
|
-
description: 'Select fields to return',
|
|
1074
|
-
},
|
|
1075
|
-
include: {
|
|
1076
|
-
type: 'object',
|
|
1077
|
-
description: 'Include relations to return',
|
|
1078
|
-
},
|
|
1079
|
-
omit: {
|
|
1080
|
-
type: 'object',
|
|
1081
|
-
description: 'Omit fields from response',
|
|
1082
|
-
},
|
|
1018
|
+
...PROJECTION_PROPS,
|
|
1083
1019
|
},
|
|
1084
1020
|
required: ['data'],
|
|
1085
1021
|
},
|
|
@@ -1093,11 +1029,12 @@ function generatePaths(
|
|
|
1093
1029
|
},
|
|
1094
1030
|
},
|
|
1095
1031
|
}
|
|
1096
|
-
addErrorResponses(op,
|
|
1032
|
+
addErrorResponses(op, meta.errors)
|
|
1097
1033
|
addPath(spec, opPath(basePath, 'create'), 'post', op)
|
|
1098
1034
|
}
|
|
1099
1035
|
|
|
1100
1036
|
if (opEnabled(config, 'createMany')) {
|
|
1037
|
+
const meta = OPERATION_BY_NAME['createMany']
|
|
1101
1038
|
const op: any = {
|
|
1102
1039
|
tags: [modelName],
|
|
1103
1040
|
summary: `Create many ${modelName}`,
|
|
@@ -1128,11 +1065,12 @@ function generatePaths(
|
|
|
1128
1065
|
},
|
|
1129
1066
|
},
|
|
1130
1067
|
}
|
|
1131
|
-
addErrorResponses(op,
|
|
1068
|
+
addErrorResponses(op, meta.errors)
|
|
1132
1069
|
addPath(spec, opPath(basePath, 'createMany'), 'post', op)
|
|
1133
1070
|
}
|
|
1134
1071
|
|
|
1135
1072
|
if (opEnabled(config, 'createManyAndReturn')) {
|
|
1073
|
+
const meta = OPERATION_BY_NAME['createManyAndReturn']
|
|
1136
1074
|
const op: any = {
|
|
1137
1075
|
tags: [modelName],
|
|
1138
1076
|
summary: `Create many ${modelName} and return records`,
|
|
@@ -1150,18 +1088,7 @@ function generatePaths(
|
|
|
1150
1088
|
description:
|
|
1151
1089
|
'Skip records that would cause unique constraint violations. Not supported on all database providers.',
|
|
1152
1090
|
},
|
|
1153
|
-
|
|
1154
|
-
type: 'object',
|
|
1155
|
-
description: 'Select fields to return',
|
|
1156
|
-
},
|
|
1157
|
-
include: {
|
|
1158
|
-
type: 'object',
|
|
1159
|
-
description: 'Include relations to return',
|
|
1160
|
-
},
|
|
1161
|
-
omit: {
|
|
1162
|
-
type: 'object',
|
|
1163
|
-
description: 'Omit fields from response',
|
|
1164
|
-
},
|
|
1091
|
+
...PROJECTION_PROPS,
|
|
1165
1092
|
},
|
|
1166
1093
|
required: ['data'],
|
|
1167
1094
|
},
|
|
@@ -1179,11 +1106,12 @@ function generatePaths(
|
|
|
1179
1106
|
},
|
|
1180
1107
|
},
|
|
1181
1108
|
}
|
|
1182
|
-
addErrorResponses(op,
|
|
1109
|
+
addErrorResponses(op, meta.errors)
|
|
1183
1110
|
addPath(spec, opPath(basePath, 'createManyAndReturn'), 'post', op)
|
|
1184
1111
|
}
|
|
1185
1112
|
|
|
1186
1113
|
if (opEnabled(config, 'update')) {
|
|
1114
|
+
const meta = OPERATION_BY_NAME['update']
|
|
1187
1115
|
const op: any = {
|
|
1188
1116
|
tags: [modelName],
|
|
1189
1117
|
summary: `Update ${modelName}`,
|
|
@@ -1197,18 +1125,7 @@ function generatePaths(
|
|
|
1197
1125
|
properties: {
|
|
1198
1126
|
where: { type: 'object' },
|
|
1199
1127
|
data: updateInputRef,
|
|
1200
|
-
|
|
1201
|
-
type: 'object',
|
|
1202
|
-
description: 'Select fields to return',
|
|
1203
|
-
},
|
|
1204
|
-
include: {
|
|
1205
|
-
type: 'object',
|
|
1206
|
-
description: 'Include relations to return',
|
|
1207
|
-
},
|
|
1208
|
-
omit: {
|
|
1209
|
-
type: 'object',
|
|
1210
|
-
description: 'Omit fields from response',
|
|
1211
|
-
},
|
|
1128
|
+
...PROJECTION_PROPS,
|
|
1212
1129
|
},
|
|
1213
1130
|
required: ['where', 'data'],
|
|
1214
1131
|
},
|
|
@@ -1222,11 +1139,12 @@ function generatePaths(
|
|
|
1222
1139
|
},
|
|
1223
1140
|
},
|
|
1224
1141
|
}
|
|
1225
|
-
addErrorResponses(op,
|
|
1142
|
+
addErrorResponses(op, meta.errors)
|
|
1226
1143
|
addPath(spec, opPath(basePath, 'update'), 'put', op)
|
|
1227
1144
|
}
|
|
1228
1145
|
|
|
1229
1146
|
if (opEnabled(config, 'updateMany')) {
|
|
1147
|
+
const meta = OPERATION_BY_NAME['updateMany']
|
|
1230
1148
|
const op: any = {
|
|
1231
1149
|
tags: [modelName],
|
|
1232
1150
|
summary: `Update many ${modelName}`,
|
|
@@ -1253,11 +1171,12 @@ function generatePaths(
|
|
|
1253
1171
|
},
|
|
1254
1172
|
},
|
|
1255
1173
|
}
|
|
1256
|
-
addErrorResponses(op,
|
|
1174
|
+
addErrorResponses(op, meta.errors)
|
|
1257
1175
|
addPath(spec, opPath(basePath, 'updateMany'), 'put', op)
|
|
1258
1176
|
}
|
|
1259
1177
|
|
|
1260
1178
|
if (opEnabled(config, 'updateManyAndReturn')) {
|
|
1179
|
+
const meta = OPERATION_BY_NAME['updateManyAndReturn']
|
|
1261
1180
|
const op: any = {
|
|
1262
1181
|
tags: [modelName],
|
|
1263
1182
|
summary: `Update many ${modelName} and return records`,
|
|
@@ -1271,18 +1190,7 @@ function generatePaths(
|
|
|
1271
1190
|
properties: {
|
|
1272
1191
|
where: { type: 'object' },
|
|
1273
1192
|
data: updateManyMutationRef,
|
|
1274
|
-
|
|
1275
|
-
type: 'object',
|
|
1276
|
-
description: 'Select fields to return',
|
|
1277
|
-
},
|
|
1278
|
-
include: {
|
|
1279
|
-
type: 'object',
|
|
1280
|
-
description: 'Include relations to return',
|
|
1281
|
-
},
|
|
1282
|
-
omit: {
|
|
1283
|
-
type: 'object',
|
|
1284
|
-
description: 'Omit fields from response',
|
|
1285
|
-
},
|
|
1193
|
+
...PROJECTION_PROPS,
|
|
1286
1194
|
},
|
|
1287
1195
|
required: ['where', 'data'],
|
|
1288
1196
|
},
|
|
@@ -1300,11 +1208,12 @@ function generatePaths(
|
|
|
1300
1208
|
},
|
|
1301
1209
|
},
|
|
1302
1210
|
}
|
|
1303
|
-
addErrorResponses(op,
|
|
1211
|
+
addErrorResponses(op, meta.errors)
|
|
1304
1212
|
addPath(spec, opPath(basePath, 'updateManyAndReturn'), 'put', op)
|
|
1305
1213
|
}
|
|
1306
1214
|
|
|
1307
1215
|
if (opEnabled(config, 'upsert')) {
|
|
1216
|
+
const meta = OPERATION_BY_NAME['upsert']
|
|
1308
1217
|
const op: any = {
|
|
1309
1218
|
tags: [modelName],
|
|
1310
1219
|
summary: `Upsert ${modelName}`,
|
|
@@ -1319,18 +1228,7 @@ function generatePaths(
|
|
|
1319
1228
|
where: { type: 'object' },
|
|
1320
1229
|
create: createInputRef,
|
|
1321
1230
|
update: updateInputRef,
|
|
1322
|
-
|
|
1323
|
-
type: 'object',
|
|
1324
|
-
description: 'Select fields to return',
|
|
1325
|
-
},
|
|
1326
|
-
include: {
|
|
1327
|
-
type: 'object',
|
|
1328
|
-
description: 'Include relations to return',
|
|
1329
|
-
},
|
|
1330
|
-
omit: {
|
|
1331
|
-
type: 'object',
|
|
1332
|
-
description: 'Omit fields from response',
|
|
1333
|
-
},
|
|
1231
|
+
...PROJECTION_PROPS,
|
|
1334
1232
|
},
|
|
1335
1233
|
required: ['where', 'create', 'update'],
|
|
1336
1234
|
},
|
|
@@ -1344,11 +1242,12 @@ function generatePaths(
|
|
|
1344
1242
|
},
|
|
1345
1243
|
},
|
|
1346
1244
|
}
|
|
1347
|
-
addErrorResponses(op,
|
|
1245
|
+
addErrorResponses(op, meta.errors)
|
|
1348
1246
|
addPath(spec, opPath(basePath, 'upsert'), 'patch', op)
|
|
1349
1247
|
}
|
|
1350
1248
|
|
|
1351
1249
|
if (opEnabled(config, 'delete')) {
|
|
1250
|
+
const meta = OPERATION_BY_NAME['delete']
|
|
1352
1251
|
const op: any = {
|
|
1353
1252
|
tags: [modelName],
|
|
1354
1253
|
summary: `Delete ${modelName}`,
|
|
@@ -1361,18 +1260,7 @@ function generatePaths(
|
|
|
1361
1260
|
type: 'object',
|
|
1362
1261
|
properties: {
|
|
1363
1262
|
where: { type: 'object' },
|
|
1364
|
-
|
|
1365
|
-
type: 'object',
|
|
1366
|
-
description: 'Select fields to return',
|
|
1367
|
-
},
|
|
1368
|
-
include: {
|
|
1369
|
-
type: 'object',
|
|
1370
|
-
description: 'Include relations to return',
|
|
1371
|
-
},
|
|
1372
|
-
omit: {
|
|
1373
|
-
type: 'object',
|
|
1374
|
-
description: 'Omit fields from response',
|
|
1375
|
-
},
|
|
1263
|
+
...PROJECTION_PROPS,
|
|
1376
1264
|
},
|
|
1377
1265
|
required: ['where'],
|
|
1378
1266
|
},
|
|
@@ -1386,11 +1274,12 @@ function generatePaths(
|
|
|
1386
1274
|
},
|
|
1387
1275
|
},
|
|
1388
1276
|
}
|
|
1389
|
-
addErrorResponses(op,
|
|
1277
|
+
addErrorResponses(op, meta.errors)
|
|
1390
1278
|
addPath(spec, opPath(basePath, 'delete'), 'delete', op)
|
|
1391
1279
|
}
|
|
1392
1280
|
|
|
1393
1281
|
if (opEnabled(config, 'deleteMany')) {
|
|
1282
|
+
const meta = OPERATION_BY_NAME['deleteMany']
|
|
1394
1283
|
const op: any = {
|
|
1395
1284
|
tags: [modelName],
|
|
1396
1285
|
summary: `Delete many ${modelName}`,
|
|
@@ -1414,11 +1303,12 @@ function generatePaths(
|
|
|
1414
1303
|
},
|
|
1415
1304
|
},
|
|
1416
1305
|
}
|
|
1417
|
-
addErrorResponses(op,
|
|
1306
|
+
addErrorResponses(op, meta.errors)
|
|
1418
1307
|
addPath(spec, opPath(basePath, 'deleteMany'), 'delete', op)
|
|
1419
1308
|
}
|
|
1420
1309
|
|
|
1421
1310
|
if (opEnabled(config, 'count')) {
|
|
1311
|
+
const meta = OPERATION_BY_NAME['count']
|
|
1422
1312
|
const op: any = {
|
|
1423
1313
|
tags: [modelName],
|
|
1424
1314
|
summary: `Count ${modelName}`,
|
|
@@ -1437,8 +1327,7 @@ function generatePaths(
|
|
|
1437
1327
|
},
|
|
1438
1328
|
{
|
|
1439
1329
|
type: 'object',
|
|
1440
|
-
description:
|
|
1441
|
-
'Per-field count object when select is provided',
|
|
1330
|
+
description: 'Per-field count object when select is provided',
|
|
1442
1331
|
},
|
|
1443
1332
|
],
|
|
1444
1333
|
},
|
|
@@ -1447,7 +1336,7 @@ function generatePaths(
|
|
|
1447
1336
|
},
|
|
1448
1337
|
},
|
|
1449
1338
|
}
|
|
1450
|
-
addErrorResponses(op,
|
|
1339
|
+
addErrorResponses(op, meta.errors)
|
|
1451
1340
|
addPath(spec, opPath(basePath, 'count'), 'get', op)
|
|
1452
1341
|
|
|
1453
1342
|
if (postReads) {
|
|
@@ -1469,12 +1358,13 @@ function generatePaths(
|
|
|
1469
1358
|
},
|
|
1470
1359
|
],
|
|
1471
1360
|
},
|
|
1472
|
-
|
|
1361
|
+
meta.errors,
|
|
1473
1362
|
)
|
|
1474
1363
|
}
|
|
1475
1364
|
}
|
|
1476
1365
|
|
|
1477
1366
|
if (opEnabled(config, 'aggregate')) {
|
|
1367
|
+
const meta = OPERATION_BY_NAME['aggregate']
|
|
1478
1368
|
const op: any = {
|
|
1479
1369
|
tags: [modelName],
|
|
1480
1370
|
summary: `Aggregate ${modelName}`,
|
|
@@ -1487,7 +1377,7 @@ function generatePaths(
|
|
|
1487
1377
|
},
|
|
1488
1378
|
},
|
|
1489
1379
|
}
|
|
1490
|
-
addErrorResponses(op,
|
|
1380
|
+
addErrorResponses(op, meta.errors)
|
|
1491
1381
|
addPath(spec, opPath(basePath, 'aggregate'), 'get', op)
|
|
1492
1382
|
|
|
1493
1383
|
if (postReads) {
|
|
@@ -1498,12 +1388,13 @@ function generatePaths(
|
|
|
1498
1388
|
'aggregate',
|
|
1499
1389
|
`Aggregate ${modelName}`,
|
|
1500
1390
|
aggregateRef,
|
|
1501
|
-
|
|
1391
|
+
meta.errors,
|
|
1502
1392
|
)
|
|
1503
1393
|
}
|
|
1504
1394
|
}
|
|
1505
1395
|
|
|
1506
1396
|
if (opEnabled(config, 'groupBy')) {
|
|
1397
|
+
const meta = OPERATION_BY_NAME['groupBy']
|
|
1507
1398
|
const op: any = {
|
|
1508
1399
|
tags: [modelName],
|
|
1509
1400
|
summary: `Group ${modelName}`,
|
|
@@ -1522,7 +1413,7 @@ function generatePaths(
|
|
|
1522
1413
|
},
|
|
1523
1414
|
},
|
|
1524
1415
|
}
|
|
1525
|
-
addErrorResponses(op,
|
|
1416
|
+
addErrorResponses(op, meta.errors)
|
|
1526
1417
|
addPath(spec, opPath(basePath, 'groupBy'), 'get', op)
|
|
1527
1418
|
|
|
1528
1419
|
if (postReads) {
|
|
@@ -1533,13 +1424,14 @@ function generatePaths(
|
|
|
1533
1424
|
'groupBy',
|
|
1534
1425
|
`Group ${modelName}`,
|
|
1535
1426
|
{ type: 'array', items: groupByItemRef },
|
|
1536
|
-
|
|
1427
|
+
meta.errors,
|
|
1537
1428
|
'Groups records by the specified fields and returns aggregates.',
|
|
1538
1429
|
)
|
|
1539
1430
|
}
|
|
1540
1431
|
}
|
|
1541
1432
|
|
|
1542
1433
|
if (opEnabled(config, 'updateEach')) {
|
|
1434
|
+
const meta = OPERATION_BY_NAME['updateEach']
|
|
1543
1435
|
const op: any = {
|
|
1544
1436
|
tags: [modelName],
|
|
1545
1437
|
summary: `Update each ${modelName} (batch)`,
|
|
@@ -1578,7 +1470,7 @@ function generatePaths(
|
|
|
1578
1470
|
},
|
|
1579
1471
|
},
|
|
1580
1472
|
}
|
|
1581
|
-
addErrorResponses(op,
|
|
1473
|
+
addErrorResponses(op, meta.errors)
|
|
1582
1474
|
addPath(spec, opPath(basePath, 'updateEach'), 'post', op)
|
|
1583
1475
|
}
|
|
1584
1476
|
}
|
|
@@ -1688,225 +1580,95 @@ function mapFieldToSchema(field: ModelField): SchemaObject | RefObject {
|
|
|
1688
1580
|
return schema
|
|
1689
1581
|
}
|
|
1690
1582
|
|
|
1691
|
-
function
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1583
|
+
function nestedListRelationOps(fieldType: string): SchemaObject {
|
|
1584
|
+
const createInput: SchemaObject = { type: 'object', description: `${fieldType} create input` }
|
|
1585
|
+
const uniqueId: SchemaObject = { type: 'object', description: 'Unique identifier' }
|
|
1586
|
+
const uniqueConnect: SchemaObject = { type: 'object', description: 'Unique identifier to connect' }
|
|
1587
|
+
const uniqueDisconnect: SchemaObject = { type: 'object', description: 'Unique identifier to disconnect' }
|
|
1588
|
+
const uniqueDelete: SchemaObject = { type: 'object', description: 'Unique identifier to delete' }
|
|
1589
|
+
const whereFilter: SchemaObject = { type: 'object', description: 'Where filter' }
|
|
1590
|
+
const whereCreatePair: SchemaObject = {
|
|
1591
|
+
type: 'object',
|
|
1592
|
+
description: '{ where, create } pair',
|
|
1593
|
+
properties: { where: { type: 'object' }, create: { type: 'object' } },
|
|
1594
|
+
}
|
|
1595
|
+
const whereDataPair: SchemaObject = {
|
|
1596
|
+
type: 'object',
|
|
1597
|
+
description: '{ where, data } pair',
|
|
1598
|
+
properties: { where: { type: 'object' }, data: { type: 'object' } },
|
|
1599
|
+
}
|
|
1600
|
+
const whereCreateUpdateTriple: SchemaObject = {
|
|
1601
|
+
type: 'object',
|
|
1602
|
+
description: '{ where, create, update } triple',
|
|
1603
|
+
properties: {
|
|
1604
|
+
where: { type: 'object' },
|
|
1605
|
+
create: { type: 'object' },
|
|
1606
|
+
update: { type: 'object' },
|
|
1607
|
+
},
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
return {
|
|
1611
|
+
type: 'object',
|
|
1612
|
+
description: `Nested ${fieldType} write operations for list relation`,
|
|
1613
|
+
properties: {
|
|
1614
|
+
create: oneOrMany(createInput),
|
|
1615
|
+
connect: oneOrMany(uniqueConnect),
|
|
1616
|
+
connectOrCreate: oneOrMany(whereCreatePair),
|
|
1617
|
+
createMany: {
|
|
1698
1618
|
type: 'object',
|
|
1699
|
-
description: `Nested ${field.type} write operations for list relation`,
|
|
1700
1619
|
properties: {
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
{ type: 'object', description: `${field.type} create input` },
|
|
1704
|
-
{
|
|
1705
|
-
type: 'array',
|
|
1706
|
-
items: {
|
|
1707
|
-
type: 'object',
|
|
1708
|
-
description: `${field.type} create input`,
|
|
1709
|
-
},
|
|
1710
|
-
},
|
|
1711
|
-
],
|
|
1712
|
-
},
|
|
1713
|
-
connect: {
|
|
1714
|
-
oneOf: [
|
|
1715
|
-
{ type: 'object', description: 'Unique identifier to connect' },
|
|
1716
|
-
{
|
|
1717
|
-
type: 'array',
|
|
1718
|
-
items: {
|
|
1719
|
-
type: 'object',
|
|
1720
|
-
description: 'Unique identifier to connect',
|
|
1721
|
-
},
|
|
1722
|
-
},
|
|
1723
|
-
],
|
|
1724
|
-
},
|
|
1725
|
-
connectOrCreate: {
|
|
1726
|
-
oneOf: [
|
|
1727
|
-
{
|
|
1728
|
-
type: 'object',
|
|
1729
|
-
description: '{ where, create } pair',
|
|
1730
|
-
properties: {
|
|
1731
|
-
where: { type: 'object' },
|
|
1732
|
-
create: { type: 'object' },
|
|
1733
|
-
},
|
|
1734
|
-
},
|
|
1735
|
-
{
|
|
1736
|
-
type: 'array',
|
|
1737
|
-
items: {
|
|
1738
|
-
type: 'object',
|
|
1739
|
-
properties: {
|
|
1740
|
-
where: { type: 'object' },
|
|
1741
|
-
create: { type: 'object' },
|
|
1742
|
-
},
|
|
1743
|
-
},
|
|
1744
|
-
},
|
|
1745
|
-
],
|
|
1746
|
-
},
|
|
1747
|
-
createMany: {
|
|
1748
|
-
type: 'object',
|
|
1749
|
-
properties: {
|
|
1750
|
-
data: {
|
|
1751
|
-
type: 'array',
|
|
1752
|
-
items: {
|
|
1753
|
-
type: 'object',
|
|
1754
|
-
description: `${field.type} create input`,
|
|
1755
|
-
},
|
|
1756
|
-
},
|
|
1757
|
-
skipDuplicates: { type: 'boolean' },
|
|
1758
|
-
},
|
|
1759
|
-
},
|
|
1760
|
-
set: {
|
|
1761
|
-
type: 'array',
|
|
1762
|
-
items: { type: 'object', description: 'Unique identifier' },
|
|
1763
|
-
description: 'Replace all connected records',
|
|
1764
|
-
},
|
|
1765
|
-
disconnect: {
|
|
1766
|
-
oneOf: [
|
|
1767
|
-
{
|
|
1768
|
-
type: 'object',
|
|
1769
|
-
description: 'Unique identifier to disconnect',
|
|
1770
|
-
},
|
|
1771
|
-
{
|
|
1772
|
-
type: 'array',
|
|
1773
|
-
items: {
|
|
1774
|
-
type: 'object',
|
|
1775
|
-
description: 'Unique identifier to disconnect',
|
|
1776
|
-
},
|
|
1777
|
-
},
|
|
1778
|
-
],
|
|
1779
|
-
},
|
|
1780
|
-
delete: {
|
|
1781
|
-
oneOf: [
|
|
1782
|
-
{ type: 'object', description: 'Unique identifier to delete' },
|
|
1783
|
-
{
|
|
1784
|
-
type: 'array',
|
|
1785
|
-
items: {
|
|
1786
|
-
type: 'object',
|
|
1787
|
-
description: 'Unique identifier to delete',
|
|
1788
|
-
},
|
|
1789
|
-
},
|
|
1790
|
-
],
|
|
1791
|
-
},
|
|
1792
|
-
update: {
|
|
1793
|
-
oneOf: [
|
|
1794
|
-
{
|
|
1795
|
-
type: 'object',
|
|
1796
|
-
description: '{ where, data } pair',
|
|
1797
|
-
properties: {
|
|
1798
|
-
where: { type: 'object' },
|
|
1799
|
-
data: { type: 'object' },
|
|
1800
|
-
},
|
|
1801
|
-
},
|
|
1802
|
-
{
|
|
1803
|
-
type: 'array',
|
|
1804
|
-
items: {
|
|
1805
|
-
type: 'object',
|
|
1806
|
-
properties: {
|
|
1807
|
-
where: { type: 'object' },
|
|
1808
|
-
data: { type: 'object' },
|
|
1809
|
-
},
|
|
1810
|
-
},
|
|
1811
|
-
},
|
|
1812
|
-
],
|
|
1813
|
-
},
|
|
1814
|
-
updateMany: {
|
|
1815
|
-
oneOf: [
|
|
1816
|
-
{
|
|
1817
|
-
type: 'object',
|
|
1818
|
-
description: '{ where, data } pair',
|
|
1819
|
-
properties: {
|
|
1820
|
-
where: { type: 'object' },
|
|
1821
|
-
data: { type: 'object' },
|
|
1822
|
-
},
|
|
1823
|
-
},
|
|
1824
|
-
{
|
|
1825
|
-
type: 'array',
|
|
1826
|
-
items: {
|
|
1827
|
-
type: 'object',
|
|
1828
|
-
properties: {
|
|
1829
|
-
where: { type: 'object' },
|
|
1830
|
-
data: { type: 'object' },
|
|
1831
|
-
},
|
|
1832
|
-
},
|
|
1833
|
-
},
|
|
1834
|
-
],
|
|
1835
|
-
},
|
|
1836
|
-
deleteMany: {
|
|
1837
|
-
oneOf: [
|
|
1838
|
-
{ type: 'object', description: 'Where filter' },
|
|
1839
|
-
{
|
|
1840
|
-
type: 'array',
|
|
1841
|
-
items: { type: 'object', description: 'Where filter' },
|
|
1842
|
-
},
|
|
1843
|
-
],
|
|
1844
|
-
},
|
|
1845
|
-
upsert: {
|
|
1846
|
-
oneOf: [
|
|
1847
|
-
{
|
|
1848
|
-
type: 'object',
|
|
1849
|
-
description: '{ where, create, update } triple',
|
|
1850
|
-
properties: {
|
|
1851
|
-
where: { type: 'object' },
|
|
1852
|
-
create: { type: 'object' },
|
|
1853
|
-
update: { type: 'object' },
|
|
1854
|
-
},
|
|
1855
|
-
},
|
|
1856
|
-
{
|
|
1857
|
-
type: 'array',
|
|
1858
|
-
items: {
|
|
1859
|
-
type: 'object',
|
|
1860
|
-
description: '{ where, create, update } triple',
|
|
1861
|
-
properties: {
|
|
1862
|
-
where: { type: 'object' },
|
|
1863
|
-
create: { type: 'object' },
|
|
1864
|
-
update: { type: 'object' },
|
|
1865
|
-
},
|
|
1866
|
-
},
|
|
1867
|
-
},
|
|
1868
|
-
],
|
|
1869
|
-
},
|
|
1870
|
-
},
|
|
1871
|
-
}
|
|
1872
|
-
}
|
|
1873
|
-
return {
|
|
1874
|
-
type: 'object',
|
|
1875
|
-
description: `Nested ${field.type} write operations for single relation`,
|
|
1876
|
-
properties: {
|
|
1877
|
-
create: { type: 'object', description: `${field.type} create input` },
|
|
1878
|
-
connect: {
|
|
1879
|
-
type: 'object',
|
|
1880
|
-
description: 'Unique identifier to connect',
|
|
1881
|
-
},
|
|
1882
|
-
connectOrCreate: {
|
|
1883
|
-
type: 'object',
|
|
1884
|
-
description: '{ where, create } pair',
|
|
1885
|
-
properties: { where: { type: 'object' }, create: { type: 'object' } },
|
|
1886
|
-
},
|
|
1887
|
-
disconnect: {
|
|
1888
|
-
type: 'boolean',
|
|
1889
|
-
description: 'Disconnect the related record',
|
|
1620
|
+
data: { type: 'array', items: createInput },
|
|
1621
|
+
skipDuplicates: { type: 'boolean' },
|
|
1890
1622
|
},
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1623
|
+
},
|
|
1624
|
+
set: {
|
|
1625
|
+
type: 'array',
|
|
1626
|
+
items: uniqueId,
|
|
1627
|
+
description: 'Replace all connected records',
|
|
1628
|
+
},
|
|
1629
|
+
disconnect: oneOrMany(uniqueDisconnect),
|
|
1630
|
+
delete: oneOrMany(uniqueDelete),
|
|
1631
|
+
update: oneOrMany(whereDataPair),
|
|
1632
|
+
updateMany: oneOrMany(whereDataPair),
|
|
1633
|
+
deleteMany: oneOrMany(whereFilter),
|
|
1634
|
+
upsert: oneOrMany(whereCreateUpdateTriple),
|
|
1635
|
+
},
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
function nestedSingleRelationOps(fieldType: string): SchemaObject {
|
|
1640
|
+
return {
|
|
1641
|
+
type: 'object',
|
|
1642
|
+
description: `Nested ${fieldType} write operations for single relation`,
|
|
1643
|
+
properties: {
|
|
1644
|
+
create: { type: 'object', description: `${fieldType} create input` },
|
|
1645
|
+
connect: { type: 'object', description: 'Unique identifier to connect' },
|
|
1646
|
+
connectOrCreate: {
|
|
1647
|
+
type: 'object',
|
|
1648
|
+
description: '{ where, create } pair',
|
|
1649
|
+
properties: { where: { type: 'object' }, create: { type: 'object' } },
|
|
1650
|
+
},
|
|
1651
|
+
disconnect: { type: 'boolean', description: 'Disconnect the related record' },
|
|
1652
|
+
delete: { type: 'boolean', description: 'Delete the related record' },
|
|
1653
|
+
update: { type: 'object', description: `${fieldType} update input` },
|
|
1654
|
+
upsert: {
|
|
1655
|
+
type: 'object',
|
|
1656
|
+
description: '{ create, update } pair — create if not exists, update if exists',
|
|
1657
|
+
properties: {
|
|
1658
|
+
create: { type: 'object', description: `${fieldType} create input` },
|
|
1659
|
+
update: { type: 'object', description: `${fieldType} update input` },
|
|
1907
1660
|
},
|
|
1908
1661
|
},
|
|
1909
|
-
}
|
|
1662
|
+
},
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
function mapFieldToWriteSchema(
|
|
1667
|
+
field: ModelField,
|
|
1668
|
+
mode: 'create' | 'update',
|
|
1669
|
+
): SchemaObject | RefObject {
|
|
1670
|
+
if (field.kind === 'object') {
|
|
1671
|
+
return field.isList ? nestedListRelationOps(field.type) : nestedSingleRelationOps(field.type)
|
|
1910
1672
|
}
|
|
1911
1673
|
|
|
1912
1674
|
let baseSchema: SchemaObject | RefObject
|
|
@@ -1971,146 +1733,4 @@ function mapScalarType(type: string): SchemaObject {
|
|
|
1971
1733
|
},
|
|
1972
1734
|
}
|
|
1973
1735
|
return typeMap[type] || { type: 'string' }
|
|
1974
|
-
}
|
|
1975
|
-
|
|
1976
|
-
function yamlEscapeValue(value: unknown, indent: number = 0): string {
|
|
1977
|
-
if (value === null) return 'null'
|
|
1978
|
-
if (value === undefined) return 'null'
|
|
1979
|
-
if (typeof value === 'boolean') return value ? 'true' : 'false'
|
|
1980
|
-
if (typeof value === 'number') return String(value)
|
|
1981
|
-
|
|
1982
|
-
const str = String(value)
|
|
1983
|
-
if (str === '') return "''"
|
|
1984
|
-
|
|
1985
|
-
const needsQuote =
|
|
1986
|
-
str === '~' ||
|
|
1987
|
-
str === '.inf' ||
|
|
1988
|
-
str === '-.inf' ||
|
|
1989
|
-
str === '.nan' ||
|
|
1990
|
-
str === '-' ||
|
|
1991
|
-
str === '?' ||
|
|
1992
|
-
str.startsWith('- ') ||
|
|
1993
|
-
str.startsWith('? ') ||
|
|
1994
|
-
/^[!&*|>@`]/.test(str) ||
|
|
1995
|
-
str.includes(':') ||
|
|
1996
|
-
str.includes('#') ||
|
|
1997
|
-
str.includes('{') ||
|
|
1998
|
-
str.includes('}') ||
|
|
1999
|
-
str.includes('[') ||
|
|
2000
|
-
str.includes(']') ||
|
|
2001
|
-
str.includes(',') ||
|
|
2002
|
-
str.includes('&') ||
|
|
2003
|
-
str.includes('*') ||
|
|
2004
|
-
str.includes('!') ||
|
|
2005
|
-
str.includes('|') ||
|
|
2006
|
-
str.includes('>') ||
|
|
2007
|
-
str.includes("'") ||
|
|
2008
|
-
str.includes('"') ||
|
|
2009
|
-
str.includes('%') ||
|
|
2010
|
-
str.includes('@') ||
|
|
2011
|
-
str.includes('`') ||
|
|
2012
|
-
str.startsWith(' ') ||
|
|
2013
|
-
str.endsWith(' ') ||
|
|
2014
|
-
str === 'true' ||
|
|
2015
|
-
str === 'false' ||
|
|
2016
|
-
str === 'null' ||
|
|
2017
|
-
str === 'yes' ||
|
|
2018
|
-
str === 'no' ||
|
|
2019
|
-
str === 'on' ||
|
|
2020
|
-
str === 'off' ||
|
|
2021
|
-
(!isNaN(Number(str)) && str !== '')
|
|
2022
|
-
|
|
2023
|
-
if (str.includes('\n')) {
|
|
2024
|
-
const blockIndent = ' '.repeat(indent + 1)
|
|
2025
|
-
return (
|
|
2026
|
-
'|\n' +
|
|
2027
|
-
str
|
|
2028
|
-
.split('\n')
|
|
2029
|
-
.map((l) => blockIndent + l)
|
|
2030
|
-
.join('\n')
|
|
2031
|
-
)
|
|
2032
|
-
}
|
|
2033
|
-
|
|
2034
|
-
if (needsQuote) {
|
|
2035
|
-
return '"' + str.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"'
|
|
2036
|
-
}
|
|
2037
|
-
|
|
2038
|
-
return str
|
|
2039
|
-
}
|
|
2040
|
-
|
|
2041
|
-
function yamlEscapeKey(key: string): string {
|
|
2042
|
-
if (key === '') return "''"
|
|
2043
|
-
|
|
2044
|
-
const needsQuote =
|
|
2045
|
-
key === '~' ||
|
|
2046
|
-
key === '.inf' ||
|
|
2047
|
-
key === '-.inf' ||
|
|
2048
|
-
key === '.nan' ||
|
|
2049
|
-
key === '-' ||
|
|
2050
|
-
key === '?' ||
|
|
2051
|
-
key.startsWith('- ') ||
|
|
2052
|
-
key.startsWith('? ') ||
|
|
2053
|
-
/^[!&*|>@`]/.test(key) ||
|
|
2054
|
-
key.includes(':') ||
|
|
2055
|
-
key.includes('#') ||
|
|
2056
|
-
key.includes('{') ||
|
|
2057
|
-
key.includes('}') ||
|
|
2058
|
-
key.includes('[') ||
|
|
2059
|
-
key.includes(']') ||
|
|
2060
|
-
key.includes(',') ||
|
|
2061
|
-
key.includes('&') ||
|
|
2062
|
-
key.includes('*') ||
|
|
2063
|
-
key.includes('!') ||
|
|
2064
|
-
key.includes('|') ||
|
|
2065
|
-
key.includes('>') ||
|
|
2066
|
-
key.includes("'") ||
|
|
2067
|
-
key.includes('"') ||
|
|
2068
|
-
key.includes('%') ||
|
|
2069
|
-
key.includes('@') ||
|
|
2070
|
-
key.includes('`') ||
|
|
2071
|
-
key.includes(' ') ||
|
|
2072
|
-
key === 'true' ||
|
|
2073
|
-
key === 'false' ||
|
|
2074
|
-
key === 'null' ||
|
|
2075
|
-
key === 'yes' ||
|
|
2076
|
-
key === 'no' ||
|
|
2077
|
-
key === 'on' ||
|
|
2078
|
-
key === 'off' ||
|
|
2079
|
-
(!isNaN(Number(key)) && key !== '')
|
|
2080
|
-
|
|
2081
|
-
if (needsQuote) {
|
|
2082
|
-
return '"' + key.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + '"'
|
|
2083
|
-
}
|
|
2084
|
-
|
|
2085
|
-
return key
|
|
2086
|
-
}
|
|
2087
|
-
|
|
2088
|
-
function toYaml(obj: any, indent = 0): string {
|
|
2089
|
-
const spaces = ' '.repeat(indent)
|
|
2090
|
-
let yaml = ''
|
|
2091
|
-
|
|
2092
|
-
if (Array.isArray(obj)) {
|
|
2093
|
-
if (obj.length === 0) return `${spaces}[]\n`
|
|
2094
|
-
for (const item of obj) {
|
|
2095
|
-
if (typeof item === 'object' && item !== null) {
|
|
2096
|
-
const inner = toYaml(item, indent + 1).trimStart()
|
|
2097
|
-
yaml += `${spaces}- ${inner}`
|
|
2098
|
-
} else {
|
|
2099
|
-
yaml += `${spaces}- ${yamlEscapeValue(item, indent)}\n`
|
|
2100
|
-
}
|
|
2101
|
-
}
|
|
2102
|
-
} else if (typeof obj === 'object' && obj !== null) {
|
|
2103
|
-
if (Object.keys(obj).length === 0) return `${spaces}{}\n`
|
|
2104
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
2105
|
-
if (value === undefined) continue
|
|
2106
|
-
const safeKey = yamlEscapeKey(key)
|
|
2107
|
-
if (typeof value === 'object' && value !== null) {
|
|
2108
|
-
yaml += `${spaces}${safeKey}:\n${toYaml(value, indent + 1)}`
|
|
2109
|
-
} else {
|
|
2110
|
-
yaml += `${spaces}${safeKey}: ${yamlEscapeValue(value, indent)}\n`
|
|
2111
|
-
}
|
|
2112
|
-
}
|
|
2113
|
-
}
|
|
2114
|
-
|
|
2115
|
-
return yaml
|
|
2116
|
-
}
|
|
1736
|
+
}
|