prisma-generator-express 1.42.0 → 1.44.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/generateFastifyHandler.d.ts +2 -0
- package/dist/generators/generateFastifyHandler.js +21 -6
- package/dist/generators/generateFastifyHandler.js.map +1 -1
- package/dist/generators/generateHonoHandler.d.ts +2 -0
- package/dist/generators/generateHonoHandler.js +8 -6
- package/dist/generators/generateHonoHandler.js.map +1 -1
- package/dist/generators/generateOperationCore.d.ts +0 -1
- package/dist/generators/generateOperationCore.js +34 -546
- package/dist/generators/generateOperationCore.js.map +1 -1
- package/dist/generators/generateRelationMeta.d.ts +13 -0
- package/dist/generators/generateRelationMeta.js +110 -0
- package/dist/generators/generateRelationMeta.js.map +1 -0
- package/dist/generators/generateRouteConfigType.js +13 -5
- package/dist/generators/generateRouteConfigType.js.map +1 -1
- package/dist/generators/generateRouter.js +83 -19
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.js +127 -384
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.js +48 -36
- package/dist/generators/generateRouterHono.js.map +1 -1
- package/dist/generators/generateUnifiedHandler.d.ts +2 -0
- package/dist/generators/generateUnifiedHandler.js +28 -10
- package/dist/generators/generateUnifiedHandler.js.map +1 -1
- package/dist/generators/generateUnifiedScalarUI.d.ts +2 -0
- package/dist/generators/generateUnifiedScalarUI.js +19 -16
- package/dist/generators/generateUnifiedScalarUI.js.map +1 -1
- package/dist/index.js +21 -5
- package/dist/index.js.map +1 -1
- package/dist/utils/copyFiles.js +12 -0
- package/dist/utils/copyFiles.js.map +1 -1
- package/dist/utils/writeFileSafely.js +2 -2
- package/dist/utils/writeFileSafely.js.map +1 -1
- package/package.json +1 -1
- package/src/copy/autoIncludePlanner.ts +354 -0
- package/src/copy/autoIncludeRuntime.ts +362 -0
- package/src/copy/operationRuntime.ts +614 -0
- package/src/copy/routeConfig.express.ts +5 -3
- package/src/copy/routeConfig.fastify.ts +2 -2
- package/src/copy/routeConfig.hono.ts +3 -3
- package/src/copy/routeConfig.ts +20 -9
- package/src/generators/generateFastifyHandler.ts +23 -6
- package/src/generators/generateHonoHandler.ts +10 -6
- package/src/generators/generateOperationCore.ts +34 -546
- package/src/generators/generateRelationMeta.ts +160 -0
- package/src/generators/generateRouteConfigType.ts +13 -6
- package/src/generators/generateRouter.ts +83 -19
- package/src/generators/generateRouterFastify.ts +127 -384
- package/src/generators/generateRouterHono.ts +48 -36
- package/src/generators/generateUnifiedHandler.ts +30 -10
- package/src/generators/generateUnifiedScalarUI.ts +21 -16
- package/src/index.ts +31 -13
- package/src/utils/copyFiles.ts +13 -0
- package/src/utils/writeFileSafely.ts +2 -2
|
@@ -71,17 +71,17 @@ import type { RouteConfig, HonoHookHandler } from '../routeConfig.target${ext}'
|
|
|
71
71
|
import { parseQueryParams } from '../parseQueryParams${ext}'
|
|
72
72
|
import { sanitizeKeys } from '../misc${ext}'
|
|
73
73
|
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
74
|
-
import { mapError, transformResult, HttpError } from '../operationRuntime${ext}'
|
|
74
|
+
import { mapError, transformResult, HttpError, type OperationContext } from '../operationRuntime${ext}'
|
|
75
75
|
|
|
76
76
|
${generateRouteConfigType(modelName, 'HonoHookHandler', guardShapesImport, importStyle, 'hono')}
|
|
77
77
|
|
|
78
78
|
type HonoVariables = {
|
|
79
|
-
prisma:
|
|
80
|
-
postgres?:
|
|
81
|
-
sqlite?:
|
|
79
|
+
prisma: unknown
|
|
80
|
+
postgres?: unknown
|
|
81
|
+
sqlite?: unknown
|
|
82
82
|
parsedQuery?: Record<string, unknown>
|
|
83
83
|
body?: unknown
|
|
84
|
-
routeConfig?:
|
|
84
|
+
routeConfig?: { pagination?: OperationContext['paginationConfig'] }
|
|
85
85
|
guardShape?: Record<string, unknown>
|
|
86
86
|
guardCaller?: string
|
|
87
87
|
resultData?: unknown
|
|
@@ -96,9 +96,15 @@ const MODEL_FIELDS = ${JSON.stringify(fieldsMeta, null, 2)} as const
|
|
|
96
96
|
|
|
97
97
|
const MODEL_ENUMS = ${JSON.stringify(enumsMeta, null, 2)} as const
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
before
|
|
101
|
-
after
|
|
99
|
+
type OperationConfigLike = {
|
|
100
|
+
before?: HonoHookHandler[]
|
|
101
|
+
after?: HonoHookHandler[]
|
|
102
|
+
shape?: Record<string, unknown>
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const defaultOpConfig: OperationConfigLike = {
|
|
106
|
+
before: [],
|
|
107
|
+
after: [],
|
|
102
108
|
}
|
|
103
109
|
|
|
104
110
|
function normalizePrefix(p: string): string {
|
|
@@ -140,7 +146,7 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
140
146
|
return c.json({ message: err.message }, err.status)
|
|
141
147
|
}
|
|
142
148
|
const httpError = mapError(err)
|
|
143
|
-
return c.json({ message: httpError.message }, httpError.status as
|
|
149
|
+
return c.json({ message: httpError.message }, httpError.status as Parameters<typeof c.json>[1])
|
|
144
150
|
})
|
|
145
151
|
|
|
146
152
|
const parseQueryMw = async (c: Context<HonoEnv>, next: Next): Promise<void> => {
|
|
@@ -169,12 +175,15 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
169
175
|
await next()
|
|
170
176
|
}
|
|
171
177
|
|
|
172
|
-
const setContextMw = (opConfig:
|
|
173
|
-
|
|
178
|
+
const setContextMw = (opConfig: OperationConfigLike) => async (c: Context<HonoEnv>, next: Next): Promise<void> => {
|
|
179
|
+
const paginationConfig = (config as { pagination?: OperationContext['paginationConfig'] }).pagination
|
|
180
|
+
if (paginationConfig) {
|
|
181
|
+
c.set('routeConfig', { pagination: paginationConfig })
|
|
182
|
+
}
|
|
174
183
|
if (opConfig.shape) {
|
|
175
184
|
c.set('guardShape', opConfig.shape)
|
|
176
185
|
const headerName = config.guard?.variantHeader || 'x-api-variant'
|
|
177
|
-
const caller = config.guard?.resolveVariant?.(c as
|
|
186
|
+
const caller = config.guard?.resolveVariant?.(c as Context)
|
|
178
187
|
?? c.req.header(headerName)
|
|
179
188
|
?? undefined
|
|
180
189
|
if (caller) {
|
|
@@ -190,7 +199,10 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
190
199
|
if (data === undefined) {
|
|
191
200
|
return c.json({ message: 'No data set by handler' }, 500)
|
|
192
201
|
}
|
|
193
|
-
return c.json(
|
|
202
|
+
return c.json(
|
|
203
|
+
transformResult(data) as Parameters<typeof c.json>[0],
|
|
204
|
+
status as Parameters<typeof c.json>[1],
|
|
205
|
+
)
|
|
194
206
|
}
|
|
195
207
|
|
|
196
208
|
const wrap = (fn: (c: Context<HonoEnv>) => Promise<void>) =>
|
|
@@ -206,19 +218,19 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
206
218
|
app.get(openapiJsonPath, (c) => {
|
|
207
219
|
const spec = buildModelOpenApi(
|
|
208
220
|
'${modelName}',
|
|
209
|
-
MODEL_FIELDS as
|
|
210
|
-
MODEL_ENUMS as
|
|
221
|
+
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
222
|
+
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
211
223
|
config,
|
|
212
224
|
{ format: 'json' },
|
|
213
225
|
)
|
|
214
|
-
return c.json(spec as
|
|
226
|
+
return c.json(spec as Parameters<typeof c.json>[0])
|
|
215
227
|
})
|
|
216
228
|
|
|
217
229
|
app.get(openapiYamlPath, (c) => {
|
|
218
230
|
const yaml = buildModelOpenApi(
|
|
219
231
|
'${modelName}',
|
|
220
|
-
MODEL_FIELDS as
|
|
221
|
-
MODEL_ENUMS as
|
|
232
|
+
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
233
|
+
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
222
234
|
config,
|
|
223
235
|
{ format: 'yaml' },
|
|
224
236
|
) as string
|
|
@@ -227,7 +239,7 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
227
239
|
}
|
|
228
240
|
|
|
229
241
|
if (config.enableAll || config.findFirst) {
|
|
230
|
-
const opConfig = config.findFirst
|
|
242
|
+
const opConfig: OperationConfigLike = (config.findFirst as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
231
243
|
const { before = [], after = [] } = opConfig
|
|
232
244
|
const path = basePath ? \`\${basePath}/first\` : '/first'
|
|
233
245
|
app.get(path, parseQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}FindFirst), ...after, sendResultMw)
|
|
@@ -237,7 +249,7 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
237
249
|
}
|
|
238
250
|
|
|
239
251
|
if (config.enableAll || config.findFirstOrThrow) {
|
|
240
|
-
const opConfig = config.findFirstOrThrow
|
|
252
|
+
const opConfig: OperationConfigLike = (config.findFirstOrThrow as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
241
253
|
const { before = [], after = [] } = opConfig
|
|
242
254
|
const path = basePath ? \`\${basePath}/first/strict\` : '/first/strict'
|
|
243
255
|
app.get(path, parseQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}FindFirstOrThrow), ...after, sendResultMw)
|
|
@@ -247,7 +259,7 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
247
259
|
}
|
|
248
260
|
|
|
249
261
|
if (config.enableAll || config.findManyPaginated) {
|
|
250
|
-
const opConfig = config.findManyPaginated
|
|
262
|
+
const opConfig: OperationConfigLike = (config.findManyPaginated as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
251
263
|
const { before = [], after = [] } = opConfig
|
|
252
264
|
const path = basePath ? \`\${basePath}/paginated\` : '/paginated'
|
|
253
265
|
app.get(path, parseQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}FindManyPaginated), ...after, sendResultMw)
|
|
@@ -257,7 +269,7 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
257
269
|
}
|
|
258
270
|
|
|
259
271
|
if (config.enableAll || config.aggregate) {
|
|
260
|
-
const opConfig = config.aggregate
|
|
272
|
+
const opConfig: OperationConfigLike = (config.aggregate as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
261
273
|
const { before = [], after = [] } = opConfig
|
|
262
274
|
const path = basePath ? \`\${basePath}/aggregate\` : '/aggregate'
|
|
263
275
|
app.get(path, parseQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}Aggregate), ...after, sendResultMw)
|
|
@@ -267,7 +279,7 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
267
279
|
}
|
|
268
280
|
|
|
269
281
|
if (config.enableAll || config.count) {
|
|
270
|
-
const opConfig = config.count
|
|
282
|
+
const opConfig: OperationConfigLike = (config.count as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
271
283
|
const { before = [], after = [] } = opConfig
|
|
272
284
|
const path = basePath ? \`\${basePath}/count\` : '/count'
|
|
273
285
|
app.get(path, parseQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}Count), ...after, sendResultMw)
|
|
@@ -277,7 +289,7 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
277
289
|
}
|
|
278
290
|
|
|
279
291
|
if (config.enableAll || config.groupBy) {
|
|
280
|
-
const opConfig = config.groupBy
|
|
292
|
+
const opConfig: OperationConfigLike = (config.groupBy as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
281
293
|
const { before = [], after = [] } = opConfig
|
|
282
294
|
const path = basePath ? \`\${basePath}/groupby\` : '/groupby'
|
|
283
295
|
app.get(path, parseQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}GroupBy), ...after, sendResultMw)
|
|
@@ -287,7 +299,7 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
287
299
|
}
|
|
288
300
|
|
|
289
301
|
if (config.enableAll || config.findUniqueOrThrow) {
|
|
290
|
-
const opConfig = config.findUniqueOrThrow
|
|
302
|
+
const opConfig: OperationConfigLike = (config.findUniqueOrThrow as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
291
303
|
const { before = [], after = [] } = opConfig
|
|
292
304
|
const path = basePath ? \`\${basePath}/unique/strict\` : '/unique/strict'
|
|
293
305
|
app.get(path, parseQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}FindUniqueOrThrow), ...after, sendResultMw)
|
|
@@ -297,7 +309,7 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
297
309
|
}
|
|
298
310
|
|
|
299
311
|
if (config.enableAll || config.findUnique) {
|
|
300
|
-
const opConfig = config.findUnique
|
|
312
|
+
const opConfig: OperationConfigLike = (config.findUnique as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
301
313
|
const { before = [], after = [] } = opConfig
|
|
302
314
|
const path = basePath ? \`\${basePath}/unique\` : '/unique'
|
|
303
315
|
app.get(path, parseQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}FindUnique), ...after, sendResultMw)
|
|
@@ -307,7 +319,7 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
307
319
|
}
|
|
308
320
|
|
|
309
321
|
if (config.enableAll || config.findMany) {
|
|
310
|
-
const opConfig = config.findMany
|
|
322
|
+
const opConfig: OperationConfigLike = (config.findMany as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
311
323
|
const { before = [], after = [] } = opConfig
|
|
312
324
|
const path = basePath || '/'
|
|
313
325
|
app.get(path, parseQueryMw, setContextMw(opConfig), ...before, wrap(${prefix}FindMany), ...after, sendResultMw)
|
|
@@ -318,63 +330,63 @@ export function ${routerFunctionName}<TCtx = unknown>(
|
|
|
318
330
|
}
|
|
319
331
|
|
|
320
332
|
if (config.enableAll || config.createManyAndReturn) {
|
|
321
|
-
const opConfig = config.createManyAndReturn
|
|
333
|
+
const opConfig: OperationConfigLike = (config.createManyAndReturn as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
322
334
|
const { before = [], after = [] } = opConfig
|
|
323
335
|
const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
|
|
324
336
|
app.post(path, parseBodyMw, setContextMw(opConfig), ...before, wrap(${prefix}CreateManyAndReturn), ...after, sendResultMw)
|
|
325
337
|
}
|
|
326
338
|
|
|
327
339
|
if (config.enableAll || config.createMany) {
|
|
328
|
-
const opConfig = config.createMany
|
|
340
|
+
const opConfig: OperationConfigLike = (config.createMany as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
329
341
|
const { before = [], after = [] } = opConfig
|
|
330
342
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
331
343
|
app.post(path, parseBodyMw, setContextMw(opConfig), ...before, wrap(${prefix}CreateMany), ...after, sendResultMw)
|
|
332
344
|
}
|
|
333
345
|
|
|
334
346
|
if (config.enableAll || config.create) {
|
|
335
|
-
const opConfig = config.create
|
|
347
|
+
const opConfig: OperationConfigLike = (config.create as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
336
348
|
const { before = [], after = [] } = opConfig
|
|
337
349
|
const path = basePath || '/'
|
|
338
350
|
app.post(path, parseBodyMw, setContextMw(opConfig), ...before, wrap(${prefix}Create), ...after, sendResultMw)
|
|
339
351
|
}
|
|
340
352
|
|
|
341
353
|
if (config.enableAll || config.updateManyAndReturn) {
|
|
342
|
-
const opConfig = config.updateManyAndReturn
|
|
354
|
+
const opConfig: OperationConfigLike = (config.updateManyAndReturn as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
343
355
|
const { before = [], after = [] } = opConfig
|
|
344
356
|
const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
|
|
345
357
|
app.put(path, parseBodyMw, setContextMw(opConfig), ...before, wrap(${prefix}UpdateManyAndReturn), ...after, sendResultMw)
|
|
346
358
|
}
|
|
347
359
|
|
|
348
360
|
if (config.enableAll || config.updateMany) {
|
|
349
|
-
const opConfig = config.updateMany
|
|
361
|
+
const opConfig: OperationConfigLike = (config.updateMany as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
350
362
|
const { before = [], after = [] } = opConfig
|
|
351
363
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
352
364
|
app.put(path, parseBodyMw, setContextMw(opConfig), ...before, wrap(${prefix}UpdateMany), ...after, sendResultMw)
|
|
353
365
|
}
|
|
354
366
|
|
|
355
367
|
if (config.enableAll || config.update) {
|
|
356
|
-
const opConfig = config.update
|
|
368
|
+
const opConfig: OperationConfigLike = (config.update as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
357
369
|
const { before = [], after = [] } = opConfig
|
|
358
370
|
const path = basePath || '/'
|
|
359
371
|
app.put(path, parseBodyMw, setContextMw(opConfig), ...before, wrap(${prefix}Update), ...after, sendResultMw)
|
|
360
372
|
}
|
|
361
373
|
|
|
362
374
|
if (config.enableAll || config.upsert) {
|
|
363
|
-
const opConfig = config.upsert
|
|
375
|
+
const opConfig: OperationConfigLike = (config.upsert as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
364
376
|
const { before = [], after = [] } = opConfig
|
|
365
377
|
const path = basePath || '/'
|
|
366
378
|
app.patch(path, parseBodyMw, setContextMw(opConfig), ...before, wrap(${prefix}Upsert), ...after, sendResultMw)
|
|
367
379
|
}
|
|
368
380
|
|
|
369
381
|
if (config.enableAll || config.deleteMany) {
|
|
370
|
-
const opConfig = config.deleteMany
|
|
382
|
+
const opConfig: OperationConfigLike = (config.deleteMany as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
371
383
|
const { before = [], after = [] } = opConfig
|
|
372
384
|
const path = basePath ? \`\${basePath}/many\` : '/many'
|
|
373
385
|
app.delete(path, parseBodyMw, setContextMw(opConfig), ...before, wrap(${prefix}DeleteMany), ...after, sendResultMw)
|
|
374
386
|
}
|
|
375
387
|
|
|
376
388
|
if (config.enableAll || config.delete) {
|
|
377
|
-
const opConfig = config.delete
|
|
389
|
+
const opConfig: OperationConfigLike = (config.delete as OperationConfigLike | undefined) ?? defaultOpConfig
|
|
378
390
|
const { before = [], after = [] } = opConfig
|
|
379
391
|
const path = basePath || '/'
|
|
380
392
|
app.delete(path, parseBodyMw, setContextMw(opConfig), ...before, wrap(${prefix}Delete), ...after, sendResultMw)
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { DMMF } from '@prisma/generator-helper'
|
|
2
2
|
import { toCamelCase } from '../utils/strings'
|
|
3
|
+
import { ImportStyle } from '../utils/resolveImportStyle'
|
|
4
|
+
import { importExt } from '../utils/importExt'
|
|
3
5
|
|
|
4
6
|
export interface UnifiedHandlerOptions {
|
|
5
7
|
model: DMMF.Model
|
|
8
|
+
importStyle: ImportStyle
|
|
6
9
|
}
|
|
7
10
|
|
|
8
11
|
const CORE_NAME_MAP: Record<string, string> = {
|
|
@@ -35,6 +38,7 @@ const ALL_OPS = [
|
|
|
35
38
|
]
|
|
36
39
|
|
|
37
40
|
export function generateUnifiedHandler(options: UnifiedHandlerOptions): string {
|
|
41
|
+
const ext = importExt(options.importStyle)
|
|
38
42
|
const modelName = options.model.name
|
|
39
43
|
const prefix = toCamelCase(modelName)
|
|
40
44
|
|
|
@@ -48,7 +52,7 @@ export async function ${exportName}(
|
|
|
48
52
|
next: NextFunction,
|
|
49
53
|
) {
|
|
50
54
|
try {
|
|
51
|
-
res.locals.data = await core.${coreFnName(op)}(buildContext(req, res))
|
|
55
|
+
;(res.locals as LocalsBag).data = await core.${coreFnName(op)}(buildContext(req, res))
|
|
52
56
|
next()
|
|
53
57
|
} catch (error: unknown) {
|
|
54
58
|
next(mapError(error))
|
|
@@ -57,19 +61,35 @@ export async function ${exportName}(
|
|
|
57
61
|
}).join('\n')
|
|
58
62
|
|
|
59
63
|
return `import { Request, Response, NextFunction } from 'express'
|
|
60
|
-
import * as core from './${modelName}Core'
|
|
61
|
-
import { OperationContext, mapError } from '../operationRuntime'
|
|
64
|
+
import * as core from './${modelName}Core${ext}'
|
|
65
|
+
import { OperationContext, mapError } from '../operationRuntime${ext}'
|
|
66
|
+
|
|
67
|
+
type ExtendedRequest = Request & {
|
|
68
|
+
prisma?: unknown
|
|
69
|
+
postgres?: unknown
|
|
70
|
+
sqlite?: unknown
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
type LocalsBag = {
|
|
74
|
+
parsedQuery?: Record<string, unknown>
|
|
75
|
+
routeConfig?: { pagination?: unknown }
|
|
76
|
+
guardShape?: Record<string, unknown>
|
|
77
|
+
guardCaller?: string
|
|
78
|
+
data?: unknown
|
|
79
|
+
}
|
|
62
80
|
|
|
63
81
|
function buildContext(req: Request, res: Response): OperationContext {
|
|
82
|
+
const extReq = req as ExtendedRequest
|
|
83
|
+
const locals = res.locals as LocalsBag
|
|
64
84
|
return {
|
|
65
|
-
prisma:
|
|
66
|
-
postgres:
|
|
67
|
-
sqlite:
|
|
68
|
-
parsedQuery:
|
|
85
|
+
prisma: extReq.prisma,
|
|
86
|
+
postgres: extReq.postgres,
|
|
87
|
+
sqlite: extReq.sqlite,
|
|
88
|
+
parsedQuery: locals.parsedQuery,
|
|
69
89
|
body: req.body,
|
|
70
|
-
guardShape:
|
|
71
|
-
guardCaller:
|
|
72
|
-
paginationConfig:
|
|
90
|
+
guardShape: locals.guardShape,
|
|
91
|
+
guardCaller: locals.guardCaller,
|
|
92
|
+
paginationConfig: (locals.routeConfig?.pagination) as OperationContext['paginationConfig'],
|
|
73
93
|
}
|
|
74
94
|
}
|
|
75
95
|
${handlers}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { DMMF } from '@prisma/generator-helper'
|
|
2
2
|
import { Target } from '../constants'
|
|
3
|
+
import { ImportStyle } from '../utils/resolveImportStyle'
|
|
4
|
+
import { importExt } from '../utils/importExt'
|
|
3
5
|
|
|
4
6
|
function exampleValueForType(fieldType: string): unknown {
|
|
5
7
|
switch (fieldType) {
|
|
@@ -46,8 +48,8 @@ function generateExpressDocsExport(modelName: string): string {
|
|
|
46
48
|
if (ui === 'yaml') {
|
|
47
49
|
const yaml = buildModelOpenApi(
|
|
48
50
|
'${modelName}',
|
|
49
|
-
MODEL_FIELDS as
|
|
50
|
-
MODEL_ENUMS as
|
|
51
|
+
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
52
|
+
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
51
53
|
config,
|
|
52
54
|
{ format: 'yaml' }
|
|
53
55
|
)
|
|
@@ -56,8 +58,8 @@ function generateExpressDocsExport(modelName: string): string {
|
|
|
56
58
|
|
|
57
59
|
const spec = buildModelOpenApi(
|
|
58
60
|
'${modelName}',
|
|
59
|
-
MODEL_FIELDS as
|
|
60
|
-
MODEL_ENUMS as
|
|
61
|
+
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
62
|
+
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
61
63
|
config,
|
|
62
64
|
{ format: 'json' }
|
|
63
65
|
)
|
|
@@ -82,7 +84,8 @@ function generateFastifyDocsExport(modelName: string): string {
|
|
|
82
84
|
const disabled = isOpenApiDisabled(config.disableOpenApi)
|
|
83
85
|
if (disabled) { reply.code(404).send('OpenAPI documentation is disabled in production'); return }
|
|
84
86
|
|
|
85
|
-
const
|
|
87
|
+
const queryParams = request.query as { ui?: string } | undefined
|
|
88
|
+
const rawUi = queryParams?.ui || config.docsUi || 'docs'
|
|
86
89
|
const validUis: DocsUI[] = ['docs', 'scalar', 'json', 'yaml', 'playground']
|
|
87
90
|
const ui: DocsUI = validUis.includes(rawUi as DocsUI) ? (rawUi as DocsUI) : 'docs'
|
|
88
91
|
|
|
@@ -96,8 +99,8 @@ function generateFastifyDocsExport(modelName: string): string {
|
|
|
96
99
|
if (ui === 'yaml') {
|
|
97
100
|
const yaml = buildModelOpenApi(
|
|
98
101
|
'${modelName}',
|
|
99
|
-
MODEL_FIELDS as
|
|
100
|
-
MODEL_ENUMS as
|
|
102
|
+
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
103
|
+
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
101
104
|
config,
|
|
102
105
|
{ format: 'yaml' }
|
|
103
106
|
)
|
|
@@ -106,8 +109,8 @@ function generateFastifyDocsExport(modelName: string): string {
|
|
|
106
109
|
|
|
107
110
|
const spec = buildModelOpenApi(
|
|
108
111
|
'${modelName}',
|
|
109
|
-
MODEL_FIELDS as
|
|
110
|
-
MODEL_ENUMS as
|
|
112
|
+
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
113
|
+
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
111
114
|
config,
|
|
112
115
|
{ format: 'json' }
|
|
113
116
|
)
|
|
@@ -146,8 +149,8 @@ function generateHonoDocsExport(modelName: string): string {
|
|
|
146
149
|
if (ui === 'yaml') {
|
|
147
150
|
const yaml = buildModelOpenApi(
|
|
148
151
|
'${modelName}',
|
|
149
|
-
MODEL_FIELDS as
|
|
150
|
-
MODEL_ENUMS as
|
|
152
|
+
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
153
|
+
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
151
154
|
config,
|
|
152
155
|
{ format: 'yaml' }
|
|
153
156
|
) as string
|
|
@@ -156,13 +159,13 @@ function generateHonoDocsExport(modelName: string): string {
|
|
|
156
159
|
|
|
157
160
|
const spec = buildModelOpenApi(
|
|
158
161
|
'${modelName}',
|
|
159
|
-
MODEL_FIELDS as
|
|
160
|
-
MODEL_ENUMS as
|
|
162
|
+
MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
|
|
163
|
+
MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
|
|
161
164
|
config,
|
|
162
165
|
{ format: 'json' }
|
|
163
166
|
)
|
|
164
167
|
|
|
165
|
-
if (ui === 'json') return c.json(spec as
|
|
168
|
+
if (ui === 'json') return c.json(spec as Record<string, unknown>)
|
|
166
169
|
|
|
167
170
|
const pageTitle = config.docsTitle || \`${modelName} API\`
|
|
168
171
|
|
|
@@ -180,9 +183,11 @@ export function generateScalarUIHandler(options: {
|
|
|
180
183
|
model: DMMF.Model
|
|
181
184
|
enums: DMMF.DatamodelEnum[]
|
|
182
185
|
target?: Target
|
|
186
|
+
importStyle: ImportStyle
|
|
183
187
|
}): string {
|
|
184
188
|
const { model, enums } = options
|
|
185
189
|
const target = options.target || 'express'
|
|
190
|
+
const ext = importExt(options.importStyle)
|
|
186
191
|
const modelName = model.name
|
|
187
192
|
|
|
188
193
|
const fieldsMeta = model.fields.map((f: any) => ({
|
|
@@ -254,7 +259,7 @@ export function generateScalarUIHandler(options: {
|
|
|
254
259
|
: generateExpressDocsExport(modelName)
|
|
255
260
|
|
|
256
261
|
return `${frameworkImport}
|
|
257
|
-
import { buildModelOpenApi } from '../buildModelOpenApi'
|
|
262
|
+
import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
|
|
258
263
|
import {
|
|
259
264
|
renderDocs,
|
|
260
265
|
renderScalar,
|
|
@@ -266,7 +271,7 @@ import {
|
|
|
266
271
|
type DocsUI,
|
|
267
272
|
type DocsConfig,
|
|
268
273
|
type DocsModelContext,
|
|
269
|
-
} from '../docsRenderer'
|
|
274
|
+
} from '../docsRenderer${ext}'
|
|
270
275
|
|
|
271
276
|
export const MODEL_FIELDS: FieldMeta[] = ${JSON.stringify(fieldsMeta, null, 2)}
|
|
272
277
|
|
package/src/index.ts
CHANGED
|
@@ -9,11 +9,12 @@ import { generateHonoRouterFunction } from './generators/generateRouterHono'
|
|
|
9
9
|
import { generateScalarUIHandler } from './generators/generateUnifiedScalarUI'
|
|
10
10
|
import { generateUnifiedDocs } from './generators/generateUnifiedDocs'
|
|
11
11
|
import { generateQueryBuilderHelper } from './generators/generateQueryBuilderHelper'
|
|
12
|
-
import {
|
|
12
|
+
import { generateModelCore } from './generators/generateOperationCore'
|
|
13
|
+
import { generateRelationMeta, generateRelationModelsIndex } from './generators/generateRelationMeta'
|
|
13
14
|
import { getRelativeClientPath, getGuardShapesImport } from './generators/generateImportPrismaStatement'
|
|
14
15
|
import { writeFileSafely } from './utils/writeFileSafely'
|
|
15
16
|
import { copyFiles } from './utils/copyFiles'
|
|
16
|
-
import { resolveImportStyle } from './utils/resolveImportStyle'
|
|
17
|
+
import { resolveImportStyle, ImportStyle } from './utils/resolveImportStyle'
|
|
17
18
|
import { GENERATOR_NAME, Target } from './constants'
|
|
18
19
|
|
|
19
20
|
function getTarget(options: GeneratorOptions): Target {
|
|
@@ -51,18 +52,14 @@ generatorHandler({
|
|
|
51
52
|
|
|
52
53
|
await copyFiles(options, target, importStyle)
|
|
53
54
|
|
|
54
|
-
await writeFileSafely({
|
|
55
|
-
content: generateOperationRuntime(importStyle),
|
|
56
|
-
options,
|
|
57
|
-
operation: 'operationRuntime',
|
|
58
|
-
})
|
|
59
|
-
|
|
60
55
|
const modelNames: string[] = []
|
|
61
|
-
const generateHandler =
|
|
56
|
+
const generateHandler: (opts: { model: DMMF.Model; importStyle: ImportStyle }) => string =
|
|
62
57
|
target === 'fastify' ? generateFastifyHandler :
|
|
63
58
|
target === 'hono' ? generateHonoHandler :
|
|
64
59
|
generateUnifiedHandler
|
|
65
60
|
|
|
61
|
+
const allModels = options.dmmf.datamodel.models as DMMF.Model[]
|
|
62
|
+
|
|
66
63
|
for (const model of options.dmmf.datamodel.models) {
|
|
67
64
|
if (model.documentation && model.documentation.includes('generator off')) {
|
|
68
65
|
console.log(` Skipping: ${model.name} (generator off)`)
|
|
@@ -81,7 +78,7 @@ generatorHandler({
|
|
|
81
78
|
})
|
|
82
79
|
|
|
83
80
|
await writeFileSafely({
|
|
84
|
-
content: generateHandler({ model: model as DMMF.Model, importStyle }
|
|
81
|
+
content: generateHandler({ model: model as DMMF.Model, importStyle }),
|
|
85
82
|
options,
|
|
86
83
|
model: model as DMMF.Model,
|
|
87
84
|
operation: 'Handlers',
|
|
@@ -94,14 +91,14 @@ generatorHandler({
|
|
|
94
91
|
enums: options.dmmf.datamodel.enums as DMMF.DatamodelEnum[],
|
|
95
92
|
guardShapesImport,
|
|
96
93
|
importStyle,
|
|
97
|
-
}
|
|
94
|
+
})
|
|
98
95
|
: target === 'hono'
|
|
99
96
|
? generateHonoRouterFunction({
|
|
100
97
|
model: model as DMMF.Model,
|
|
101
98
|
enums: options.dmmf.datamodel.enums as DMMF.DatamodelEnum[],
|
|
102
99
|
guardShapesImport,
|
|
103
100
|
importStyle,
|
|
104
|
-
}
|
|
101
|
+
})
|
|
105
102
|
: generateRouterFunction({
|
|
106
103
|
model: model as DMMF.Model,
|
|
107
104
|
enums: options.dmmf.datamodel.enums as DMMF.DatamodelEnum[],
|
|
@@ -123,11 +120,32 @@ generatorHandler({
|
|
|
123
120
|
enums: options.dmmf.datamodel.enums as DMMF.DatamodelEnum[],
|
|
124
121
|
target,
|
|
125
122
|
importStyle,
|
|
126
|
-
}
|
|
123
|
+
}),
|
|
127
124
|
options,
|
|
128
125
|
model: model as DMMF.Model,
|
|
129
126
|
operation: 'Docs',
|
|
130
127
|
})
|
|
128
|
+
|
|
129
|
+
if (target === 'express') {
|
|
130
|
+
await writeFileSafely({
|
|
131
|
+
content: generateRelationMeta({
|
|
132
|
+
model: model as DMMF.Model,
|
|
133
|
+
allModels,
|
|
134
|
+
importStyle,
|
|
135
|
+
}),
|
|
136
|
+
options,
|
|
137
|
+
model: model as DMMF.Model,
|
|
138
|
+
operation: 'Relations',
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (target === 'express') {
|
|
144
|
+
await writeFileSafely({
|
|
145
|
+
content: generateRelationModelsIndex({ modelNames, importStyle }),
|
|
146
|
+
options,
|
|
147
|
+
operation: 'relationModelsIndex',
|
|
148
|
+
})
|
|
131
149
|
}
|
|
132
150
|
|
|
133
151
|
await writeFileSafely({
|
package/src/utils/copyFiles.ts
CHANGED
|
@@ -12,6 +12,12 @@ const SHARED_FILES = [
|
|
|
12
12
|
'misc.ts',
|
|
13
13
|
'routeConfig.ts',
|
|
14
14
|
'docsRenderer.ts',
|
|
15
|
+
'operationRuntime.ts',
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
const EXPRESS_ONLY_FILES = [
|
|
19
|
+
'autoIncludePlanner.ts',
|
|
20
|
+
'autoIncludeRuntime.ts',
|
|
15
21
|
]
|
|
16
22
|
|
|
17
23
|
interface CopyFileOptions {
|
|
@@ -112,6 +118,13 @@ export async function copyFiles(
|
|
|
112
118
|
if (err) errors.push(err)
|
|
113
119
|
}
|
|
114
120
|
|
|
121
|
+
if (target === 'express') {
|
|
122
|
+
for (const file of EXPRESS_ONLY_FILES) {
|
|
123
|
+
const err = copyFileSync(copyBase, outputPath, file, importStyle, { required: true })
|
|
124
|
+
if (err) errors.push(err)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
115
128
|
const targetConfigFile = 'routeConfig.' + target + '.ts'
|
|
116
129
|
const err = copyFileSync(copyBase, outputPath, targetConfigFile, importStyle, {
|
|
117
130
|
required: true,
|
|
@@ -36,8 +36,8 @@ export async function writeFileSafely({
|
|
|
36
36
|
case 'queryBuilder':
|
|
37
37
|
filePath = path.join(outputPath, 'queryBuilder.ts')
|
|
38
38
|
break
|
|
39
|
-
case '
|
|
40
|
-
filePath = path.join(outputPath, '
|
|
39
|
+
case 'relationModelsIndex':
|
|
40
|
+
filePath = path.join(outputPath, 'relationModels.ts')
|
|
41
41
|
break
|
|
42
42
|
default:
|
|
43
43
|
if (!model) throw new Error('Model required for operation: ' + operation)
|