prisma-generator-express 1.41.0 → 1.42.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/generators/generateRouteConfigType.js +3 -3
- package/dist/generators/generateRouteConfigType.js.map +1 -1
- package/dist/generators/generateRouter.js +96 -53
- package/dist/generators/generateRouter.js.map +1 -1
- package/package.json +1 -1
- package/src/generators/generateRouteConfigType.ts +3 -3
- package/src/generators/generateRouter.ts +96 -53
|
@@ -41,7 +41,7 @@ function generateRouteConfigType(modelName, hookHandlerType, guardShapesImport,
|
|
|
41
41
|
const m = modelName;
|
|
42
42
|
const supportsProgressive = target === 'express';
|
|
43
43
|
if (!guardShapesImport) {
|
|
44
|
-
return `export type ${m}RouteConfig<TCtx = unknown> = RouteConfig<Record<string,
|
|
44
|
+
return `export type ${m}RouteConfig<TCtx = unknown> = RouteConfig<Record<string, unknown>, TCtx>\n`;
|
|
45
45
|
}
|
|
46
46
|
const shapeOps = Object.values(ROUTER_OP_TO_SHAPE_OP).filter((v, i, a) => a.indexOf(v) === i);
|
|
47
47
|
const opShapeImports = shapeOps.map((op) => `${m}${capitalize(op)}ShapeInput`).join(',\n ');
|
|
@@ -65,9 +65,9 @@ function generateRouteConfigType(modelName, hookHandlerType, guardShapesImport,
|
|
|
65
65
|
? `import type { ProgressiveVariantConfig, ProgressiveStage } from '../routeConfig.target${ext}'\n\n`
|
|
66
66
|
: '';
|
|
67
67
|
return (progressiveTypeImport +
|
|
68
|
-
`import type {\n ${opShapeImports}\n} from '${guardShapesImport}'\n\n` +
|
|
68
|
+
`import type {\n ${opShapeImports}\n} from '${guardShapesImport}${ext}'\n\n` +
|
|
69
69
|
`export type ${m}RouteConfig<TCtx = unknown> = Omit<\n` +
|
|
70
|
-
` RouteConfig<Record<string,
|
|
70
|
+
` RouteConfig<Record<string, unknown>, TCtx>,\n` +
|
|
71
71
|
` | ${omitKeys}\n` +
|
|
72
72
|
` | 'resolveContext'\n` +
|
|
73
73
|
`> & {\n` +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateRouteConfigType.js","sourceRoot":"","sources":["../../src/generators/generateRouteConfigType.ts"],"names":[],"mappings":";;AA4CA,0DAmDC;AA9FD,kDAA8C;AAG9C,MAAM,iBAAiB,GAAG;IACxB,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,kBAAkB;IAClE,UAAU,EAAE,mBAAmB,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS;IAChE,QAAQ,EAAE,YAAY,EAAE,qBAAqB;IAC7C,QAAQ,EAAE,YAAY,EAAE,qBAAqB;IAC7C,QAAQ,EAAE,QAAQ,EAAE,YAAY;CACxB,CAAA;AAIV,MAAM,eAAe,GAAiC,IAAI,GAAG,CAAkB;IAC7E,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,kBAAkB;IAClE,UAAU,EAAE,mBAAmB,EAAE,OAAO,EAAE,WAAW,EAAE,SAAS;CACjE,CAAC,CAAA;AAEF,MAAM,qBAAqB,GAAoC;IAC7D,UAAU,EAAE,YAAY;IACxB,iBAAiB,EAAE,mBAAmB;IACtC,SAAS,EAAE,WAAW;IACtB,gBAAgB,EAAE,kBAAkB;IACpC,QAAQ,EAAE,UAAU;IACpB,iBAAiB,EAAE,mBAAmB;IACtC,KAAK,EAAE,OAAO;IACd,SAAS,EAAE,WAAW;IACtB,OAAO,EAAE,SAAS;IAClB,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,YAAY;IACxB,mBAAmB,EAAE,qBAAqB;IAC1C,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,YAAY;IACxB,mBAAmB,EAAE,qBAAqB;IAC1C,MAAM,EAAE,QAAQ;IAChB,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,YAAY;CACzB,CAAA;AAED,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAC/C,CAAC;AAED,SAAgB,uBAAuB,CACrC,SAAiB,EACjB,eAAuB,EACvB,iBAAgC,EAChC,WAAwB,EACxB,MAAc;IAEd,MAAM,GAAG,GAAG,IAAA,qBAAS,EAAC,WAAW,CAAC,CAAA;IAClC,MAAM,CAAC,GAAG,SAAS,CAAA;IACnB,MAAM,mBAAmB,GAAG,MAAM,KAAK,SAAS,CAAA;IAEhD,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,OAAO,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"generateRouteConfigType.js","sourceRoot":"","sources":["../../src/generators/generateRouteConfigType.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,6 +30,7 @@ function generateRouterFunction({ model, enums, guardShapesImport, importStyle,
|
|
|
30
30
|
}));
|
|
31
31
|
return `import express from 'express'
|
|
32
32
|
import type { Request, Response, NextFunction, RequestHandler } from 'express'
|
|
33
|
+
import { startQueryBuilder } from '../queryBuilder${ext}'
|
|
33
34
|
import {
|
|
34
35
|
${prefix}FindUnique,
|
|
35
36
|
${prefix}FindUniqueOrThrow,
|
|
@@ -51,7 +52,7 @@ import {
|
|
|
51
52
|
${prefix}GroupBy,
|
|
52
53
|
} from './${modelName}Handlers${ext}'
|
|
53
54
|
import * as core from './${modelName}Core${ext}'
|
|
54
|
-
import type { RouteConfig } from '../routeConfig.target${ext}'
|
|
55
|
+
import type { RouteConfig, ProgressiveVariantConfig, ProgressiveStage } from '../routeConfig.target${ext}'
|
|
55
56
|
import { parseQueryParams } from '../parseQueryParams${ext}'
|
|
56
57
|
import { sanitizeKeys } from '../misc${ext}'
|
|
57
58
|
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
@@ -69,9 +70,31 @@ const _env = typeof process !== 'undefined' && process.env ? process.env : {} as
|
|
|
69
70
|
const MODEL_FIELDS = ${JSON.stringify(fieldsMeta, null, 2)} as const
|
|
70
71
|
const MODEL_ENUMS = ${JSON.stringify(enumsMeta, null, 2)} as const
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
before
|
|
74
|
-
after
|
|
73
|
+
type OperationConfigLike = {
|
|
74
|
+
before?: RequestHandler[]
|
|
75
|
+
after?: RequestHandler[]
|
|
76
|
+
shape?: Record<string, unknown>
|
|
77
|
+
progressive?: Record<string, ProgressiveVariantConfig>
|
|
78
|
+
progressiveStages?: Record<string, ProgressiveStage<unknown>>
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
type ExtendedRequest = Request & {
|
|
82
|
+
prisma?: unknown
|
|
83
|
+
postgres?: unknown
|
|
84
|
+
sqlite?: unknown
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type LocalsBag = {
|
|
88
|
+
parsedQuery?: Record<string, unknown>
|
|
89
|
+
routeConfig?: ${modelName}RouteConfig
|
|
90
|
+
guardShape?: Record<string, unknown>
|
|
91
|
+
guardCaller?: string
|
|
92
|
+
data?: unknown
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const defaultOpConfig: OperationConfigLike = {
|
|
96
|
+
before: [],
|
|
97
|
+
after: [],
|
|
75
98
|
}
|
|
76
99
|
|
|
77
100
|
function normalizePrefix(p: string): string {
|
|
@@ -96,6 +119,10 @@ function getQueryBuilderConfig(config: RouteConfig) {
|
|
|
96
119
|
return {}
|
|
97
120
|
}
|
|
98
121
|
|
|
122
|
+
function readLocals(res: Response): LocalsBag {
|
|
123
|
+
return res.locals as LocalsBag
|
|
124
|
+
}
|
|
125
|
+
|
|
99
126
|
export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteConfig<TCtx> = {}) {
|
|
100
127
|
const router = express.Router()
|
|
101
128
|
router.use(express.json())
|
|
@@ -113,25 +140,34 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
113
140
|
if (qbEnabled) {
|
|
114
141
|
const qbConfig = getQueryBuilderConfig(config)
|
|
115
142
|
if (qbConfig) {
|
|
116
|
-
try {
|
|
143
|
+
try {
|
|
144
|
+
startQueryBuilder(qbConfig)
|
|
145
|
+
} catch (err) {
|
|
146
|
+
if (_env.NODE_ENV !== 'production') console.warn('[query-builder]', err)
|
|
147
|
+
}
|
|
117
148
|
}
|
|
118
149
|
}
|
|
119
150
|
|
|
120
|
-
const buildContext = (req: Request, res: Response): OperationContext =>
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
151
|
+
const buildContext = (req: Request, res: Response): OperationContext => {
|
|
152
|
+
const extReq = req as ExtendedRequest
|
|
153
|
+
const locals = readLocals(res)
|
|
154
|
+
return {
|
|
155
|
+
prisma: extReq.prisma,
|
|
156
|
+
postgres: extReq.postgres,
|
|
157
|
+
sqlite: extReq.sqlite,
|
|
158
|
+
parsedQuery: locals.parsedQuery,
|
|
159
|
+
body: req.body,
|
|
160
|
+
guardShape: locals.guardShape,
|
|
161
|
+
guardCaller: locals.guardCaller,
|
|
162
|
+
paginationConfig: locals.routeConfig?.pagination,
|
|
163
|
+
}
|
|
164
|
+
}
|
|
130
165
|
|
|
131
166
|
const parseQuery: RequestHandler = (req, res, next) => {
|
|
132
167
|
const rawQuery = req.query
|
|
133
168
|
if (rawQuery && Object.keys(rawQuery).length > 0) {
|
|
134
|
-
|
|
169
|
+
const parsed = parseQueryParams(rawQuery as Record<string, unknown>) as Record<string, unknown>
|
|
170
|
+
readLocals(res).parsedQuery = parsed
|
|
135
171
|
}
|
|
136
172
|
next()
|
|
137
173
|
}
|
|
@@ -140,29 +176,34 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
140
176
|
if (!req.body || typeof req.body !== 'object' || Array.isArray(req.body)) {
|
|
141
177
|
return next({ status: 400, message: 'Request body must be a JSON object' })
|
|
142
178
|
}
|
|
143
|
-
res.
|
|
179
|
+
readLocals(res).parsedQuery = sanitizeKeys(req.body as Record<string, unknown>)
|
|
144
180
|
next()
|
|
145
181
|
}
|
|
146
182
|
|
|
147
|
-
const setShape = (opConfig:
|
|
183
|
+
const setShape = (opConfig: OperationConfigLike): RequestHandler => {
|
|
148
184
|
return (req, res, next) => {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
if (
|
|
185
|
+
const locals = readLocals(res)
|
|
186
|
+
locals.routeConfig = config
|
|
187
|
+
const headerName = config.guard?.variantHeader || 'x-api-variant'
|
|
188
|
+
const headerValue = req.get(headerName)
|
|
189
|
+
const caller = config.guard?.resolveVariant?.(req) ?? headerValue ?? undefined
|
|
190
|
+
if (caller) locals.guardCaller = caller
|
|
191
|
+
if (opConfig.shape) locals.guardShape = opConfig.shape
|
|
155
192
|
next()
|
|
156
193
|
}
|
|
157
194
|
}
|
|
158
195
|
|
|
159
|
-
const maybeProgressiveSSE = (
|
|
196
|
+
const maybeProgressiveSSE = (
|
|
197
|
+
opConfig: OperationConfigLike,
|
|
198
|
+
coreFn: (ctx: OperationContext) => Promise<unknown>,
|
|
199
|
+
): RequestHandler => {
|
|
160
200
|
return async (req, res, next) => {
|
|
161
201
|
if (res.headersSent || res.writableEnded) return next()
|
|
162
202
|
if (req.method !== 'GET') return next()
|
|
163
203
|
if (!acceptsEventStream(req.headers.accept)) return next()
|
|
164
204
|
|
|
165
|
-
const
|
|
205
|
+
const locals = readLocals(res)
|
|
206
|
+
const variant = locals.guardCaller
|
|
166
207
|
const progressiveConfig = variant ? opConfig.progressive?.[variant] : undefined
|
|
167
208
|
|
|
168
209
|
try {
|
|
@@ -181,7 +222,7 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
181
222
|
|
|
182
223
|
const stageRegistry = opConfig.progressiveStages ?? {}
|
|
183
224
|
const missingStage = progressiveConfig.stages.find(
|
|
184
|
-
(name
|
|
225
|
+
(name) => typeof stageRegistry[name] !== 'function',
|
|
185
226
|
)
|
|
186
227
|
if (missingStage) {
|
|
187
228
|
return next({ status: 500, message: 'Missing progressive stage: ' + missingStage })
|
|
@@ -196,12 +237,13 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
196
237
|
req,
|
|
197
238
|
res,
|
|
198
239
|
ctx,
|
|
199
|
-
prisma: (req as
|
|
240
|
+
prisma: (req as ExtendedRequest).prisma,
|
|
200
241
|
variant: variant as string,
|
|
201
242
|
stages: progressiveConfig.stages,
|
|
202
243
|
stageRegistry,
|
|
203
244
|
})
|
|
204
245
|
} catch (err) {
|
|
246
|
+
console.error('[progressive] dispatch error:', err)
|
|
205
247
|
if (!res.headersSent) {
|
|
206
248
|
return next({ status: 500, message: 'Internal server error' })
|
|
207
249
|
}
|
|
@@ -210,13 +252,13 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
210
252
|
}
|
|
211
253
|
|
|
212
254
|
const respond: RequestHandler = (_req, res) => {
|
|
213
|
-
const data = res.
|
|
255
|
+
const data = readLocals(res).data
|
|
214
256
|
if (data === undefined) return res.status(500).json({ message: 'No data set by handler' })
|
|
215
257
|
return res.json(transformResult(data))
|
|
216
258
|
}
|
|
217
259
|
|
|
218
260
|
const respondCreated: RequestHandler = (_req, res) => {
|
|
219
|
-
const data = res.
|
|
261
|
+
const data = readLocals(res).data
|
|
220
262
|
if (data === undefined) return res.status(500).json({ message: 'No data set by handler' })
|
|
221
263
|
return res.status(201).json(transformResult(data))
|
|
222
264
|
}
|
|
@@ -225,73 +267,73 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
225
267
|
const openapiJsonPath = basePath ? \`\${basePath}/openapi.json\` : '/openapi.json'
|
|
226
268
|
const openapiYamlPath = basePath ? \`\${basePath}/openapi.yaml\` : '/openapi.yaml'
|
|
227
269
|
router.get(openapiJsonPath, (_req, res) => {
|
|
228
|
-
const spec = buildModelOpenApi('${modelName}', MODEL_FIELDS as
|
|
270
|
+
const spec = buildModelOpenApi('${modelName}', MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1], MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2], config, { format: 'json' })
|
|
229
271
|
res.json(spec)
|
|
230
272
|
})
|
|
231
273
|
router.get(openapiYamlPath, (_req, res) => {
|
|
232
|
-
const spec = buildModelOpenApi('${modelName}', MODEL_FIELDS as
|
|
274
|
+
const spec = buildModelOpenApi('${modelName}', MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1], MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2], config, { format: 'yaml' })
|
|
233
275
|
res.type('application/yaml').send(spec as string)
|
|
234
276
|
})
|
|
235
277
|
}
|
|
236
278
|
|
|
237
279
|
if (config.enableAll || config.findFirst) {
|
|
238
|
-
const opConfig:
|
|
280
|
+
const opConfig: OperationConfigLike = (config.findFirst as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
239
281
|
const { before = [], after = [] } = opConfig
|
|
240
282
|
const path = basePath ? \`\${basePath}/first\` : '/first'
|
|
241
283
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findFirst), ${prefix}FindFirst as RequestHandler, ...after, respond)
|
|
242
284
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindFirst as RequestHandler, ...after, respond)
|
|
243
285
|
}
|
|
244
286
|
if (config.enableAll || config.findFirstOrThrow) {
|
|
245
|
-
const opConfig:
|
|
287
|
+
const opConfig: OperationConfigLike = (config.findFirstOrThrow as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
246
288
|
const { before = [], after = [] } = opConfig
|
|
247
289
|
const path = basePath ? \`\${basePath}/first/strict\` : '/first/strict'
|
|
248
290
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findFirstOrThrow), ${prefix}FindFirstOrThrow as RequestHandler, ...after, respond)
|
|
249
291
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindFirstOrThrow as RequestHandler, ...after, respond)
|
|
250
292
|
}
|
|
251
293
|
if (config.enableAll || config.findManyPaginated) {
|
|
252
|
-
const opConfig:
|
|
294
|
+
const opConfig: OperationConfigLike = (config.findManyPaginated as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
253
295
|
const { before = [], after = [] } = opConfig
|
|
254
296
|
const path = basePath ? \`\${basePath}/paginated\` : '/paginated'
|
|
255
297
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findManyPaginated), ${prefix}FindManyPaginated as RequestHandler, ...after, respond)
|
|
256
298
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindManyPaginated as RequestHandler, ...after, respond)
|
|
257
299
|
}
|
|
258
300
|
if (config.enableAll || config.aggregate) {
|
|
259
|
-
const opConfig:
|
|
301
|
+
const opConfig: OperationConfigLike = (config.aggregate as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
260
302
|
const { before = [], after = [] } = opConfig
|
|
261
303
|
const path = basePath ? \`\${basePath}/aggregate\` : '/aggregate'
|
|
262
304
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.aggregate), ${prefix}Aggregate as RequestHandler, ...after, respond)
|
|
263
305
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}Aggregate as RequestHandler, ...after, respond)
|
|
264
306
|
}
|
|
265
307
|
if (config.enableAll || config.count) {
|
|
266
|
-
const opConfig:
|
|
308
|
+
const opConfig: OperationConfigLike = (config.count as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
267
309
|
const { before = [], after = [] } = opConfig
|
|
268
310
|
const path = basePath ? \`\${basePath}/count\` : '/count'
|
|
269
311
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.count), ${prefix}Count as RequestHandler, ...after, respond)
|
|
270
312
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}Count as RequestHandler, ...after, respond)
|
|
271
313
|
}
|
|
272
314
|
if (config.enableAll || config.groupBy) {
|
|
273
|
-
const opConfig:
|
|
315
|
+
const opConfig: OperationConfigLike = (config.groupBy as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
274
316
|
const { before = [], after = [] } = opConfig
|
|
275
317
|
const path = basePath ? \`\${basePath}/groupby\` : '/groupby'
|
|
276
318
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.groupBy), ${prefix}GroupBy as RequestHandler, ...after, respond)
|
|
277
319
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}GroupBy as RequestHandler, ...after, respond)
|
|
278
320
|
}
|
|
279
321
|
if (config.enableAll || config.findUniqueOrThrow) {
|
|
280
|
-
const opConfig:
|
|
322
|
+
const opConfig: OperationConfigLike = (config.findUniqueOrThrow as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
281
323
|
const { before = [], after = [] } = opConfig
|
|
282
324
|
const path = basePath ? \`\${basePath}/unique/strict\` : '/unique/strict'
|
|
283
325
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findUniqueOrThrow), ${prefix}FindUniqueOrThrow as RequestHandler, ...after, respond)
|
|
284
326
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindUniqueOrThrow as RequestHandler, ...after, respond)
|
|
285
327
|
}
|
|
286
328
|
if (config.enableAll || config.findUnique) {
|
|
287
|
-
const opConfig:
|
|
329
|
+
const opConfig: OperationConfigLike = (config.findUnique as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
288
330
|
const { before = [], after = [] } = opConfig
|
|
289
331
|
const path = basePath ? \`\${basePath}/unique\` : '/unique'
|
|
290
332
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findUnique), ${prefix}FindUnique as RequestHandler, ...after, respond)
|
|
291
333
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindUnique as RequestHandler, ...after, respond)
|
|
292
334
|
}
|
|
293
335
|
if (config.enableAll || config.findMany) {
|
|
294
|
-
const opConfig:
|
|
336
|
+
const opConfig: OperationConfigLike = (config.findMany as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
295
337
|
const { before = [], after = [] } = opConfig
|
|
296
338
|
const path = basePath || '/'
|
|
297
339
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findMany), ${prefix}FindMany as RequestHandler, ...after, respond)
|
|
@@ -302,63 +344,64 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
302
344
|
}
|
|
303
345
|
|
|
304
346
|
if (config.enableAll || config.createManyAndReturn) {
|
|
305
|
-
const opConfig:
|
|
347
|
+
const opConfig: OperationConfigLike = (config.createManyAndReturn as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
306
348
|
const { before = [], after = [] } = opConfig
|
|
307
349
|
const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
|
|
308
350
|
router.post(path, setShape(opConfig), ...before, ${prefix}CreateManyAndReturn as RequestHandler, ...after, respondCreated)
|
|
309
351
|
}
|
|
310
352
|
if (config.enableAll || config.createMany) {
|
|
311
|
-
const opConfig:
|
|
353
|
+
const opConfig: OperationConfigLike = (config.createMany as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
312
354
|
const { before = [], after = [] } = opConfig
|
|
313
355
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
314
356
|
router.post(path, setShape(opConfig), ...before, ${prefix}CreateMany as RequestHandler, ...after, respondCreated)
|
|
315
357
|
}
|
|
316
358
|
if (config.enableAll || config.create) {
|
|
317
|
-
const opConfig:
|
|
359
|
+
const opConfig: OperationConfigLike = (config.create as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
318
360
|
const { before = [], after = [] } = opConfig
|
|
319
361
|
const path = basePath || '/'
|
|
320
362
|
router.post(path, setShape(opConfig), ...before, ${prefix}Create as RequestHandler, ...after, respondCreated)
|
|
321
363
|
}
|
|
322
364
|
if (config.enableAll || config.updateManyAndReturn) {
|
|
323
|
-
const opConfig:
|
|
365
|
+
const opConfig: OperationConfigLike = (config.updateManyAndReturn as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
324
366
|
const { before = [], after = [] } = opConfig
|
|
325
367
|
const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
|
|
326
368
|
router.put(path, setShape(opConfig), ...before, ${prefix}UpdateManyAndReturn as RequestHandler, ...after, respond)
|
|
327
369
|
}
|
|
328
370
|
if (config.enableAll || config.updateMany) {
|
|
329
|
-
const opConfig:
|
|
371
|
+
const opConfig: OperationConfigLike = (config.updateMany as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
330
372
|
const { before = [], after = [] } = opConfig
|
|
331
373
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
332
374
|
router.put(path, setShape(opConfig), ...before, ${prefix}UpdateMany as RequestHandler, ...after, respond)
|
|
333
375
|
}
|
|
334
376
|
if (config.enableAll || config.update) {
|
|
335
|
-
const opConfig:
|
|
377
|
+
const opConfig: OperationConfigLike = (config.update as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
336
378
|
const { before = [], after = [] } = opConfig
|
|
337
379
|
const path = basePath || '/'
|
|
338
380
|
router.put(path, setShape(opConfig), ...before, ${prefix}Update as RequestHandler, ...after, respond)
|
|
339
381
|
}
|
|
340
382
|
if (config.enableAll || config.upsert) {
|
|
341
|
-
const opConfig:
|
|
383
|
+
const opConfig: OperationConfigLike = (config.upsert as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
342
384
|
const { before = [], after = [] } = opConfig
|
|
343
385
|
const path = basePath || '/'
|
|
344
386
|
router.patch(path, setShape(opConfig), ...before, ${prefix}Upsert as RequestHandler, ...after, respond)
|
|
345
387
|
}
|
|
346
388
|
if (config.enableAll || config.deleteMany) {
|
|
347
|
-
const opConfig:
|
|
389
|
+
const opConfig: OperationConfigLike = (config.deleteMany as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
348
390
|
const { before = [], after = [] } = opConfig
|
|
349
391
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
350
392
|
router.delete(path, setShape(opConfig), ...before, ${prefix}DeleteMany as RequestHandler, ...after, respond)
|
|
351
393
|
}
|
|
352
394
|
if (config.enableAll || config.delete) {
|
|
353
|
-
const opConfig:
|
|
395
|
+
const opConfig: OperationConfigLike = (config.delete as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
354
396
|
const { before = [], after = [] } = opConfig
|
|
355
397
|
const path = basePath || '/'
|
|
356
398
|
router.delete(path, setShape(opConfig), ...before, ${prefix}Delete as RequestHandler, ...after, respond)
|
|
357
399
|
}
|
|
358
400
|
|
|
359
|
-
router.use((err:
|
|
360
|
-
const
|
|
361
|
-
const
|
|
401
|
+
router.use((err: unknown, _req: Request, res: Response, next: NextFunction) => {
|
|
402
|
+
const e = err as { status?: number; message?: string }
|
|
403
|
+
const status = typeof e.status === 'number' ? e.status : 500
|
|
404
|
+
const message = e.message || 'Internal server error'
|
|
362
405
|
if (!res.headersSent) return res.status(status).json({ message })
|
|
363
406
|
next(err)
|
|
364
407
|
})
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateRouter.js","sourceRoot":"","sources":["../../src/generators/generateRouter.ts"],"names":[],"mappings":";;AAMA,
|
|
1
|
+
{"version":3,"file":"generateRouter.js","sourceRoot":"","sources":["../../src/generators/generateRouter.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.42.0",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"license": "MIT",
|
|
@@ -54,7 +54,7 @@ export function generateRouteConfigType(
|
|
|
54
54
|
const supportsProgressive = target === 'express'
|
|
55
55
|
|
|
56
56
|
if (!guardShapesImport) {
|
|
57
|
-
return `export type ${m}RouteConfig<TCtx = unknown> = RouteConfig<Record<string,
|
|
57
|
+
return `export type ${m}RouteConfig<TCtx = unknown> = RouteConfig<Record<string, unknown>, TCtx>\n`
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
const shapeOps = Object.values(ROUTER_OP_TO_SHAPE_OP).filter((v, i, a) => a.indexOf(v) === i)
|
|
@@ -84,9 +84,9 @@ export function generateRouteConfigType(
|
|
|
84
84
|
|
|
85
85
|
return (
|
|
86
86
|
progressiveTypeImport +
|
|
87
|
-
`import type {\n ${opShapeImports}\n} from '${guardShapesImport}'\n\n` +
|
|
87
|
+
`import type {\n ${opShapeImports}\n} from '${guardShapesImport}${ext}'\n\n` +
|
|
88
88
|
`export type ${m}RouteConfig<TCtx = unknown> = Omit<\n` +
|
|
89
|
-
` RouteConfig<Record<string,
|
|
89
|
+
` RouteConfig<Record<string, unknown>, TCtx>,\n` +
|
|
90
90
|
` | ${omitKeys}\n` +
|
|
91
91
|
` | 'resolveContext'\n` +
|
|
92
92
|
`> & {\n` +
|
|
@@ -47,6 +47,7 @@ export function generateRouterFunction({
|
|
|
47
47
|
|
|
48
48
|
return `import express from 'express'
|
|
49
49
|
import type { Request, Response, NextFunction, RequestHandler } from 'express'
|
|
50
|
+
import { startQueryBuilder } from '../queryBuilder${ext}'
|
|
50
51
|
import {
|
|
51
52
|
${prefix}FindUnique,
|
|
52
53
|
${prefix}FindUniqueOrThrow,
|
|
@@ -68,7 +69,7 @@ import {
|
|
|
68
69
|
${prefix}GroupBy,
|
|
69
70
|
} from './${modelName}Handlers${ext}'
|
|
70
71
|
import * as core from './${modelName}Core${ext}'
|
|
71
|
-
import type { RouteConfig } from '../routeConfig.target${ext}'
|
|
72
|
+
import type { RouteConfig, ProgressiveVariantConfig, ProgressiveStage } from '../routeConfig.target${ext}'
|
|
72
73
|
import { parseQueryParams } from '../parseQueryParams${ext}'
|
|
73
74
|
import { sanitizeKeys } from '../misc${ext}'
|
|
74
75
|
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
@@ -86,9 +87,31 @@ const _env = typeof process !== 'undefined' && process.env ? process.env : {} as
|
|
|
86
87
|
const MODEL_FIELDS = ${JSON.stringify(fieldsMeta, null, 2)} as const
|
|
87
88
|
const MODEL_ENUMS = ${JSON.stringify(enumsMeta, null, 2)} as const
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
before
|
|
91
|
-
after
|
|
90
|
+
type OperationConfigLike = {
|
|
91
|
+
before?: RequestHandler[]
|
|
92
|
+
after?: RequestHandler[]
|
|
93
|
+
shape?: Record<string, unknown>
|
|
94
|
+
progressive?: Record<string, ProgressiveVariantConfig>
|
|
95
|
+
progressiveStages?: Record<string, ProgressiveStage<unknown>>
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
type ExtendedRequest = Request & {
|
|
99
|
+
prisma?: unknown
|
|
100
|
+
postgres?: unknown
|
|
101
|
+
sqlite?: unknown
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
type LocalsBag = {
|
|
105
|
+
parsedQuery?: Record<string, unknown>
|
|
106
|
+
routeConfig?: ${modelName}RouteConfig
|
|
107
|
+
guardShape?: Record<string, unknown>
|
|
108
|
+
guardCaller?: string
|
|
109
|
+
data?: unknown
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const defaultOpConfig: OperationConfigLike = {
|
|
113
|
+
before: [],
|
|
114
|
+
after: [],
|
|
92
115
|
}
|
|
93
116
|
|
|
94
117
|
function normalizePrefix(p: string): string {
|
|
@@ -113,6 +136,10 @@ function getQueryBuilderConfig(config: RouteConfig) {
|
|
|
113
136
|
return {}
|
|
114
137
|
}
|
|
115
138
|
|
|
139
|
+
function readLocals(res: Response): LocalsBag {
|
|
140
|
+
return res.locals as LocalsBag
|
|
141
|
+
}
|
|
142
|
+
|
|
116
143
|
export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteConfig<TCtx> = {}) {
|
|
117
144
|
const router = express.Router()
|
|
118
145
|
router.use(express.json())
|
|
@@ -130,25 +157,34 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
130
157
|
if (qbEnabled) {
|
|
131
158
|
const qbConfig = getQueryBuilderConfig(config)
|
|
132
159
|
if (qbConfig) {
|
|
133
|
-
try {
|
|
160
|
+
try {
|
|
161
|
+
startQueryBuilder(qbConfig)
|
|
162
|
+
} catch (err) {
|
|
163
|
+
if (_env.NODE_ENV !== 'production') console.warn('[query-builder]', err)
|
|
164
|
+
}
|
|
134
165
|
}
|
|
135
166
|
}
|
|
136
167
|
|
|
137
|
-
const buildContext = (req: Request, res: Response): OperationContext =>
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
168
|
+
const buildContext = (req: Request, res: Response): OperationContext => {
|
|
169
|
+
const extReq = req as ExtendedRequest
|
|
170
|
+
const locals = readLocals(res)
|
|
171
|
+
return {
|
|
172
|
+
prisma: extReq.prisma,
|
|
173
|
+
postgres: extReq.postgres,
|
|
174
|
+
sqlite: extReq.sqlite,
|
|
175
|
+
parsedQuery: locals.parsedQuery,
|
|
176
|
+
body: req.body,
|
|
177
|
+
guardShape: locals.guardShape,
|
|
178
|
+
guardCaller: locals.guardCaller,
|
|
179
|
+
paginationConfig: locals.routeConfig?.pagination,
|
|
180
|
+
}
|
|
181
|
+
}
|
|
147
182
|
|
|
148
183
|
const parseQuery: RequestHandler = (req, res, next) => {
|
|
149
184
|
const rawQuery = req.query
|
|
150
185
|
if (rawQuery && Object.keys(rawQuery).length > 0) {
|
|
151
|
-
|
|
186
|
+
const parsed = parseQueryParams(rawQuery as Record<string, unknown>) as Record<string, unknown>
|
|
187
|
+
readLocals(res).parsedQuery = parsed
|
|
152
188
|
}
|
|
153
189
|
next()
|
|
154
190
|
}
|
|
@@ -157,29 +193,34 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
157
193
|
if (!req.body || typeof req.body !== 'object' || Array.isArray(req.body)) {
|
|
158
194
|
return next({ status: 400, message: 'Request body must be a JSON object' })
|
|
159
195
|
}
|
|
160
|
-
res.
|
|
196
|
+
readLocals(res).parsedQuery = sanitizeKeys(req.body as Record<string, unknown>)
|
|
161
197
|
next()
|
|
162
198
|
}
|
|
163
199
|
|
|
164
|
-
const setShape = (opConfig:
|
|
200
|
+
const setShape = (opConfig: OperationConfigLike): RequestHandler => {
|
|
165
201
|
return (req, res, next) => {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
if (
|
|
202
|
+
const locals = readLocals(res)
|
|
203
|
+
locals.routeConfig = config
|
|
204
|
+
const headerName = config.guard?.variantHeader || 'x-api-variant'
|
|
205
|
+
const headerValue = req.get(headerName)
|
|
206
|
+
const caller = config.guard?.resolveVariant?.(req) ?? headerValue ?? undefined
|
|
207
|
+
if (caller) locals.guardCaller = caller
|
|
208
|
+
if (opConfig.shape) locals.guardShape = opConfig.shape
|
|
172
209
|
next()
|
|
173
210
|
}
|
|
174
211
|
}
|
|
175
212
|
|
|
176
|
-
const maybeProgressiveSSE = (
|
|
213
|
+
const maybeProgressiveSSE = (
|
|
214
|
+
opConfig: OperationConfigLike,
|
|
215
|
+
coreFn: (ctx: OperationContext) => Promise<unknown>,
|
|
216
|
+
): RequestHandler => {
|
|
177
217
|
return async (req, res, next) => {
|
|
178
218
|
if (res.headersSent || res.writableEnded) return next()
|
|
179
219
|
if (req.method !== 'GET') return next()
|
|
180
220
|
if (!acceptsEventStream(req.headers.accept)) return next()
|
|
181
221
|
|
|
182
|
-
const
|
|
222
|
+
const locals = readLocals(res)
|
|
223
|
+
const variant = locals.guardCaller
|
|
183
224
|
const progressiveConfig = variant ? opConfig.progressive?.[variant] : undefined
|
|
184
225
|
|
|
185
226
|
try {
|
|
@@ -198,7 +239,7 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
198
239
|
|
|
199
240
|
const stageRegistry = opConfig.progressiveStages ?? {}
|
|
200
241
|
const missingStage = progressiveConfig.stages.find(
|
|
201
|
-
(name
|
|
242
|
+
(name) => typeof stageRegistry[name] !== 'function',
|
|
202
243
|
)
|
|
203
244
|
if (missingStage) {
|
|
204
245
|
return next({ status: 500, message: 'Missing progressive stage: ' + missingStage })
|
|
@@ -213,12 +254,13 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
213
254
|
req,
|
|
214
255
|
res,
|
|
215
256
|
ctx,
|
|
216
|
-
prisma: (req as
|
|
257
|
+
prisma: (req as ExtendedRequest).prisma,
|
|
217
258
|
variant: variant as string,
|
|
218
259
|
stages: progressiveConfig.stages,
|
|
219
260
|
stageRegistry,
|
|
220
261
|
})
|
|
221
262
|
} catch (err) {
|
|
263
|
+
console.error('[progressive] dispatch error:', err)
|
|
222
264
|
if (!res.headersSent) {
|
|
223
265
|
return next({ status: 500, message: 'Internal server error' })
|
|
224
266
|
}
|
|
@@ -227,13 +269,13 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
227
269
|
}
|
|
228
270
|
|
|
229
271
|
const respond: RequestHandler = (_req, res) => {
|
|
230
|
-
const data = res.
|
|
272
|
+
const data = readLocals(res).data
|
|
231
273
|
if (data === undefined) return res.status(500).json({ message: 'No data set by handler' })
|
|
232
274
|
return res.json(transformResult(data))
|
|
233
275
|
}
|
|
234
276
|
|
|
235
277
|
const respondCreated: RequestHandler = (_req, res) => {
|
|
236
|
-
const data = res.
|
|
278
|
+
const data = readLocals(res).data
|
|
237
279
|
if (data === undefined) return res.status(500).json({ message: 'No data set by handler' })
|
|
238
280
|
return res.status(201).json(transformResult(data))
|
|
239
281
|
}
|
|
@@ -242,73 +284,73 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
242
284
|
const openapiJsonPath = basePath ? \`\${basePath}/openapi.json\` : '/openapi.json'
|
|
243
285
|
const openapiYamlPath = basePath ? \`\${basePath}/openapi.yaml\` : '/openapi.yaml'
|
|
244
286
|
router.get(openapiJsonPath, (_req, res) => {
|
|
245
|
-
const spec = buildModelOpenApi('${modelName}', MODEL_FIELDS as
|
|
287
|
+
const spec = buildModelOpenApi('${modelName}', MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1], MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2], config, { format: 'json' })
|
|
246
288
|
res.json(spec)
|
|
247
289
|
})
|
|
248
290
|
router.get(openapiYamlPath, (_req, res) => {
|
|
249
|
-
const spec = buildModelOpenApi('${modelName}', MODEL_FIELDS as
|
|
291
|
+
const spec = buildModelOpenApi('${modelName}', MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1], MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2], config, { format: 'yaml' })
|
|
250
292
|
res.type('application/yaml').send(spec as string)
|
|
251
293
|
})
|
|
252
294
|
}
|
|
253
295
|
|
|
254
296
|
if (config.enableAll || config.findFirst) {
|
|
255
|
-
const opConfig:
|
|
297
|
+
const opConfig: OperationConfigLike = (config.findFirst as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
256
298
|
const { before = [], after = [] } = opConfig
|
|
257
299
|
const path = basePath ? \`\${basePath}/first\` : '/first'
|
|
258
300
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findFirst), ${prefix}FindFirst as RequestHandler, ...after, respond)
|
|
259
301
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindFirst as RequestHandler, ...after, respond)
|
|
260
302
|
}
|
|
261
303
|
if (config.enableAll || config.findFirstOrThrow) {
|
|
262
|
-
const opConfig:
|
|
304
|
+
const opConfig: OperationConfigLike = (config.findFirstOrThrow as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
263
305
|
const { before = [], after = [] } = opConfig
|
|
264
306
|
const path = basePath ? \`\${basePath}/first/strict\` : '/first/strict'
|
|
265
307
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findFirstOrThrow), ${prefix}FindFirstOrThrow as RequestHandler, ...after, respond)
|
|
266
308
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindFirstOrThrow as RequestHandler, ...after, respond)
|
|
267
309
|
}
|
|
268
310
|
if (config.enableAll || config.findManyPaginated) {
|
|
269
|
-
const opConfig:
|
|
311
|
+
const opConfig: OperationConfigLike = (config.findManyPaginated as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
270
312
|
const { before = [], after = [] } = opConfig
|
|
271
313
|
const path = basePath ? \`\${basePath}/paginated\` : '/paginated'
|
|
272
314
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findManyPaginated), ${prefix}FindManyPaginated as RequestHandler, ...after, respond)
|
|
273
315
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindManyPaginated as RequestHandler, ...after, respond)
|
|
274
316
|
}
|
|
275
317
|
if (config.enableAll || config.aggregate) {
|
|
276
|
-
const opConfig:
|
|
318
|
+
const opConfig: OperationConfigLike = (config.aggregate as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
277
319
|
const { before = [], after = [] } = opConfig
|
|
278
320
|
const path = basePath ? \`\${basePath}/aggregate\` : '/aggregate'
|
|
279
321
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.aggregate), ${prefix}Aggregate as RequestHandler, ...after, respond)
|
|
280
322
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}Aggregate as RequestHandler, ...after, respond)
|
|
281
323
|
}
|
|
282
324
|
if (config.enableAll || config.count) {
|
|
283
|
-
const opConfig:
|
|
325
|
+
const opConfig: OperationConfigLike = (config.count as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
284
326
|
const { before = [], after = [] } = opConfig
|
|
285
327
|
const path = basePath ? \`\${basePath}/count\` : '/count'
|
|
286
328
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.count), ${prefix}Count as RequestHandler, ...after, respond)
|
|
287
329
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}Count as RequestHandler, ...after, respond)
|
|
288
330
|
}
|
|
289
331
|
if (config.enableAll || config.groupBy) {
|
|
290
|
-
const opConfig:
|
|
332
|
+
const opConfig: OperationConfigLike = (config.groupBy as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
291
333
|
const { before = [], after = [] } = opConfig
|
|
292
334
|
const path = basePath ? \`\${basePath}/groupby\` : '/groupby'
|
|
293
335
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.groupBy), ${prefix}GroupBy as RequestHandler, ...after, respond)
|
|
294
336
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}GroupBy as RequestHandler, ...after, respond)
|
|
295
337
|
}
|
|
296
338
|
if (config.enableAll || config.findUniqueOrThrow) {
|
|
297
|
-
const opConfig:
|
|
339
|
+
const opConfig: OperationConfigLike = (config.findUniqueOrThrow as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
298
340
|
const { before = [], after = [] } = opConfig
|
|
299
341
|
const path = basePath ? \`\${basePath}/unique/strict\` : '/unique/strict'
|
|
300
342
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findUniqueOrThrow), ${prefix}FindUniqueOrThrow as RequestHandler, ...after, respond)
|
|
301
343
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindUniqueOrThrow as RequestHandler, ...after, respond)
|
|
302
344
|
}
|
|
303
345
|
if (config.enableAll || config.findUnique) {
|
|
304
|
-
const opConfig:
|
|
346
|
+
const opConfig: OperationConfigLike = (config.findUnique as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
305
347
|
const { before = [], after = [] } = opConfig
|
|
306
348
|
const path = basePath ? \`\${basePath}/unique\` : '/unique'
|
|
307
349
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findUnique), ${prefix}FindUnique as RequestHandler, ...after, respond)
|
|
308
350
|
if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindUnique as RequestHandler, ...after, respond)
|
|
309
351
|
}
|
|
310
352
|
if (config.enableAll || config.findMany) {
|
|
311
|
-
const opConfig:
|
|
353
|
+
const opConfig: OperationConfigLike = (config.findMany as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
312
354
|
const { before = [], after = [] } = opConfig
|
|
313
355
|
const path = basePath || '/'
|
|
314
356
|
router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findMany), ${prefix}FindMany as RequestHandler, ...after, respond)
|
|
@@ -319,63 +361,64 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
|
|
|
319
361
|
}
|
|
320
362
|
|
|
321
363
|
if (config.enableAll || config.createManyAndReturn) {
|
|
322
|
-
const opConfig:
|
|
364
|
+
const opConfig: OperationConfigLike = (config.createManyAndReturn as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
323
365
|
const { before = [], after = [] } = opConfig
|
|
324
366
|
const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
|
|
325
367
|
router.post(path, setShape(opConfig), ...before, ${prefix}CreateManyAndReturn as RequestHandler, ...after, respondCreated)
|
|
326
368
|
}
|
|
327
369
|
if (config.enableAll || config.createMany) {
|
|
328
|
-
const opConfig:
|
|
370
|
+
const opConfig: OperationConfigLike = (config.createMany as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
329
371
|
const { before = [], after = [] } = opConfig
|
|
330
372
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
331
373
|
router.post(path, setShape(opConfig), ...before, ${prefix}CreateMany as RequestHandler, ...after, respondCreated)
|
|
332
374
|
}
|
|
333
375
|
if (config.enableAll || config.create) {
|
|
334
|
-
const opConfig:
|
|
376
|
+
const opConfig: OperationConfigLike = (config.create as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
335
377
|
const { before = [], after = [] } = opConfig
|
|
336
378
|
const path = basePath || '/'
|
|
337
379
|
router.post(path, setShape(opConfig), ...before, ${prefix}Create as RequestHandler, ...after, respondCreated)
|
|
338
380
|
}
|
|
339
381
|
if (config.enableAll || config.updateManyAndReturn) {
|
|
340
|
-
const opConfig:
|
|
382
|
+
const opConfig: OperationConfigLike = (config.updateManyAndReturn as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
341
383
|
const { before = [], after = [] } = opConfig
|
|
342
384
|
const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
|
|
343
385
|
router.put(path, setShape(opConfig), ...before, ${prefix}UpdateManyAndReturn as RequestHandler, ...after, respond)
|
|
344
386
|
}
|
|
345
387
|
if (config.enableAll || config.updateMany) {
|
|
346
|
-
const opConfig:
|
|
388
|
+
const opConfig: OperationConfigLike = (config.updateMany as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
347
389
|
const { before = [], after = [] } = opConfig
|
|
348
390
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
349
391
|
router.put(path, setShape(opConfig), ...before, ${prefix}UpdateMany as RequestHandler, ...after, respond)
|
|
350
392
|
}
|
|
351
393
|
if (config.enableAll || config.update) {
|
|
352
|
-
const opConfig:
|
|
394
|
+
const opConfig: OperationConfigLike = (config.update as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
353
395
|
const { before = [], after = [] } = opConfig
|
|
354
396
|
const path = basePath || '/'
|
|
355
397
|
router.put(path, setShape(opConfig), ...before, ${prefix}Update as RequestHandler, ...after, respond)
|
|
356
398
|
}
|
|
357
399
|
if (config.enableAll || config.upsert) {
|
|
358
|
-
const opConfig:
|
|
400
|
+
const opConfig: OperationConfigLike = (config.upsert as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
359
401
|
const { before = [], after = [] } = opConfig
|
|
360
402
|
const path = basePath || '/'
|
|
361
403
|
router.patch(path, setShape(opConfig), ...before, ${prefix}Upsert as RequestHandler, ...after, respond)
|
|
362
404
|
}
|
|
363
405
|
if (config.enableAll || config.deleteMany) {
|
|
364
|
-
const opConfig:
|
|
406
|
+
const opConfig: OperationConfigLike = (config.deleteMany as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
365
407
|
const { before = [], after = [] } = opConfig
|
|
366
408
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
367
409
|
router.delete(path, setShape(opConfig), ...before, ${prefix}DeleteMany as RequestHandler, ...after, respond)
|
|
368
410
|
}
|
|
369
411
|
if (config.enableAll || config.delete) {
|
|
370
|
-
const opConfig:
|
|
412
|
+
const opConfig: OperationConfigLike = (config.delete as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
371
413
|
const { before = [], after = [] } = opConfig
|
|
372
414
|
const path = basePath || '/'
|
|
373
415
|
router.delete(path, setShape(opConfig), ...before, ${prefix}Delete as RequestHandler, ...after, respond)
|
|
374
416
|
}
|
|
375
417
|
|
|
376
|
-
router.use((err:
|
|
377
|
-
const
|
|
378
|
-
const
|
|
418
|
+
router.use((err: unknown, _req: Request, res: Response, next: NextFunction) => {
|
|
419
|
+
const e = err as { status?: number; message?: string }
|
|
420
|
+
const status = typeof e.status === 'number' ? e.status : 500
|
|
421
|
+
const message = e.message || 'Internal server error'
|
|
379
422
|
if (!res.headersSent) return res.status(status).json({ message })
|
|
380
423
|
next(err)
|
|
381
424
|
})
|