prisma-generator-express 1.45.0 → 1.46.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.
Files changed (70) hide show
  1. package/README.md +155 -30
  2. package/dist/client/encodeQueryParams.js +4 -0
  3. package/dist/client/encodeQueryParams.js.map +1 -1
  4. package/dist/copy/misc.d.ts +4 -2
  5. package/dist/copy/misc.js +35 -24
  6. package/dist/copy/misc.js.map +1 -1
  7. package/dist/generators/generateFastifyHandler.js +2 -4
  8. package/dist/generators/generateFastifyHandler.js.map +1 -1
  9. package/dist/generators/generateHonoHandler.js +2 -4
  10. package/dist/generators/generateHonoHandler.js.map +1 -1
  11. package/dist/generators/generateImportPrismaStatement.d.ts +0 -1
  12. package/dist/generators/generateImportPrismaStatement.js +2 -20
  13. package/dist/generators/generateImportPrismaStatement.js.map +1 -1
  14. package/dist/generators/generateOperationCore.js +1 -1
  15. package/dist/generators/generateQueryBuilderHelper.js +9 -0
  16. package/dist/generators/generateQueryBuilderHelper.js.map +1 -1
  17. package/dist/generators/generateRelationMeta.js +0 -10
  18. package/dist/generators/generateRelationMeta.js.map +1 -1
  19. package/dist/generators/generateRouteConfigType.js +33 -12
  20. package/dist/generators/generateRouteConfigType.js.map +1 -1
  21. package/dist/generators/generateRouter.d.ts +0 -1
  22. package/dist/generators/generateRouter.js +75 -70
  23. package/dist/generators/generateRouter.js.map +1 -1
  24. package/dist/generators/generateRouterFastify.js +83 -89
  25. package/dist/generators/generateRouterFastify.js.map +1 -1
  26. package/dist/generators/generateRouterHono.js +257 -237
  27. package/dist/generators/generateRouterHono.js.map +1 -1
  28. package/dist/generators/generateUnifiedDocs.d.ts +2 -2
  29. package/dist/generators/generateUnifiedDocs.js +90 -252
  30. package/dist/generators/generateUnifiedDocs.js.map +1 -1
  31. package/dist/generators/generateUnifiedHandler.js +2 -4
  32. package/dist/generators/generateUnifiedHandler.js.map +1 -1
  33. package/dist/index.js +16 -8
  34. package/dist/index.js.map +1 -1
  35. package/dist/utils/copyFiles.js +3 -2
  36. package/dist/utils/copyFiles.js.map +1 -1
  37. package/dist/utils/strings.d.ts +0 -1
  38. package/dist/utils/strings.js +0 -9
  39. package/dist/utils/strings.js.map +1 -1
  40. package/package.json +1 -1
  41. package/src/client/encodeQueryParams.ts +7 -15
  42. package/src/copy/autoIncludePlanner.ts +4 -17
  43. package/src/copy/autoIncludeRuntime.ts +11 -19
  44. package/src/copy/buildModelOpenApi.ts +11 -14
  45. package/src/copy/docsRenderer.ts +8 -14
  46. package/src/copy/misc.ts +28 -23
  47. package/src/copy/operationRuntime.ts +61 -43
  48. package/src/copy/parseQueryParams.ts +5 -14
  49. package/src/copy/routeConfig.express.ts +24 -18
  50. package/src/copy/routeConfig.fastify.ts +1 -1
  51. package/src/copy/routeConfig.hono.ts +34 -6
  52. package/src/copy/routeConfig.ts +2 -2
  53. package/src/generators/generateFastifyHandler.ts +2 -5
  54. package/src/generators/generateHonoHandler.ts +2 -5
  55. package/src/generators/generateImportPrismaStatement.ts +3 -35
  56. package/src/generators/generateOperationCore.ts +1 -1
  57. package/src/generators/generateQueryBuilderHelper.ts +9 -0
  58. package/src/generators/generateRelationMeta.ts +0 -10
  59. package/src/generators/generateRouteConfigType.ts +34 -10
  60. package/src/generators/generateRouter.ts +75 -71
  61. package/src/generators/generateRouterFastify.ts +83 -89
  62. package/src/generators/generateRouterHono.ts +257 -237
  63. package/src/generators/generateUnifiedDocs.ts +89 -267
  64. package/src/generators/generateUnifiedHandler.ts +2 -4
  65. package/src/index.ts +45 -14
  66. package/src/utils/copyFiles.ts +2 -2
  67. package/src/utils/strings.ts +0 -8
  68. package/src/copy/createOutputValidatorMiddleware.ts +0 -47
  69. package/src/copy/createValidatorMiddleware.ts +0 -62
  70. package/src/copy/transformZod.ts +0 -139
@@ -1,5 +1,4 @@
1
1
  import { DMMF } from '@prisma/generator-helper'
2
- import { toCamelCase } from '../utils/strings'
3
2
  import { generateRouteConfigType } from './generateRouteConfigType'
4
3
  import { ImportStyle } from '../utils/resolveImportStyle'
5
4
  import { importExt } from '../utils/importExt'
@@ -12,16 +11,14 @@ export function generateRouterFunction({
12
11
  }: {
13
12
  model: DMMF.Model
14
13
  enums: DMMF.DatamodelEnum[]
15
- relativeClientPath?: string
16
14
  guardShapesImport: string | null
17
15
  importStyle: ImportStyle
18
16
  }): string {
19
17
  const ext = importExt(importStyle)
20
18
  const modelName = model.name
21
- const prefix = toCamelCase(modelName)
22
19
  const modelNameLower = modelName.toLowerCase()
23
20
  const delegateKey = modelName.charAt(0).toLowerCase() + modelName.slice(1)
24
- const routerFunctionName = `${prefix}Router`
21
+ const routerFunctionName = `${modelName}Router`
25
22
 
26
23
  const fieldsMeta = model.fields.map((f) => ({
27
24
  name: f.name,
@@ -50,29 +47,29 @@ export function generateRouterFunction({
50
47
  import type { Request, Response, NextFunction, RequestHandler } from 'express'
51
48
  import { startQueryBuilder } from '../queryBuilder${ext}'
52
49
  import {
53
- ${prefix}FindUnique,
54
- ${prefix}FindUniqueOrThrow,
55
- ${prefix}FindFirst,
56
- ${prefix}FindFirstOrThrow,
57
- ${prefix}FindMany,
58
- ${prefix}FindManyPaginated,
59
- ${prefix}Create,
60
- ${prefix}CreateMany,
61
- ${prefix}CreateManyAndReturn,
62
- ${prefix}Update,
63
- ${prefix}UpdateMany,
64
- ${prefix}UpdateManyAndReturn,
65
- ${prefix}Upsert,
66
- ${prefix}Delete,
67
- ${prefix}DeleteMany,
68
- ${prefix}Aggregate,
69
- ${prefix}Count,
70
- ${prefix}GroupBy,
50
+ ${modelName}FindUnique,
51
+ ${modelName}FindUniqueOrThrow,
52
+ ${modelName}FindFirst,
53
+ ${modelName}FindFirstOrThrow,
54
+ ${modelName}FindMany,
55
+ ${modelName}FindManyPaginated,
56
+ ${modelName}Create,
57
+ ${modelName}CreateMany,
58
+ ${modelName}CreateManyAndReturn,
59
+ ${modelName}Update,
60
+ ${modelName}UpdateMany,
61
+ ${modelName}UpdateManyAndReturn,
62
+ ${modelName}Upsert,
63
+ ${modelName}Delete,
64
+ ${modelName}DeleteMany,
65
+ ${modelName}Aggregate,
66
+ ${modelName}Count,
67
+ ${modelName}GroupBy,
71
68
  } from './${modelName}Handlers${ext}'
72
69
  import * as core from './${modelName}Core${ext}'
73
70
  import type { RouteConfig, QueryBuilderConfig } from '../routeConfig.target${ext}'
74
71
  import { parseQueryParams } from '../parseQueryParams${ext}'
75
- import { sanitizeKeys } from '../misc${ext}'
72
+ import { sanitizeKeys, normalizePrefix, getEnv } from '../misc${ext}'
76
73
  import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
77
74
  import type { OperationContext } from '../operationRuntime${ext}'
78
75
  import {
@@ -89,7 +86,7 @@ import { relationModels } from '../relationModels${ext}'
89
86
  import { runAutoIncludeProgressive } from '../autoIncludeRuntime${ext}'
90
87
 
91
88
  ${generateRouteConfigType(modelName, 'RequestHandler', guardShapesImport, importStyle, 'express')}
92
- const _env = typeof process !== 'undefined' && process.env ? process.env : {} as Record<string, string | undefined>
89
+ const _env = getEnv()
93
90
 
94
91
  const MODEL_FIELDS = ${JSON.stringify(fieldsMeta, null, 2)} as const
95
92
  const MODEL_ENUMS = ${JSON.stringify(enumsMeta, null, 2)} as const
@@ -116,19 +113,10 @@ type LocalsBag = {
116
113
  data?: unknown
117
114
  }
118
115
 
119
- const defaultOpConfig: OperationConfigLike = {
120
- before: [],
121
- after: [],
122
- }
123
-
124
- function normalizePrefix(p: string): string {
125
- if (!p) return ''
126
- let result = p
127
- if (!result.startsWith('/')) result = '/' + result
128
- while (result.length > 1 && result.endsWith('/')) result = result.slice(0, -1)
129
- if (result === '/') return ''
130
- return result
131
- }
116
+ const defaultOpConfig: OperationConfigLike = Object.freeze({
117
+ before: Object.freeze([]) as unknown as RequestHandler[],
118
+ after: Object.freeze([]) as unknown as RequestHandler[],
119
+ })
132
120
 
133
121
  function isQueryBuilderEnabled(config: { queryBuilder?: QueryBuilderConfig | false }): boolean {
134
122
  if (config.queryBuilder === false) return false
@@ -147,9 +135,8 @@ function readLocals(res: Response): LocalsBag {
147
135
  return res.locals as LocalsBag
148
136
  }
149
137
 
150
- export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteConfig<TCtx> = {}) {
138
+ export function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(config: ${modelName}RouteConfig<TCtx, TPrisma> = {}) {
151
139
  const router = express.Router()
152
- router.use(express.json())
153
140
 
154
141
  const customPrefix = normalizePrefix(config.customUrlPrefix || '')
155
142
  const modelPrefix = config.addModelPrefix !== false ? '/${modelNameLower}' : ''
@@ -160,6 +147,25 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
160
147
 
161
148
  const postReadsEnabled = !config.disablePostReads
162
149
 
150
+ const openApiJsonSpec = openApiDisabled
151
+ ? null
152
+ : buildModelOpenApi(
153
+ '${modelName}',
154
+ MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
155
+ MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
156
+ config as unknown as Parameters<typeof buildModelOpenApi>[3],
157
+ { format: 'json' },
158
+ )
159
+ const openApiYamlSpec = openApiDisabled
160
+ ? null
161
+ : buildModelOpenApi(
162
+ '${modelName}',
163
+ MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
164
+ MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
165
+ config as unknown as Parameters<typeof buildModelOpenApi>[3],
166
+ { format: 'yaml' },
167
+ )
168
+
163
169
  const qbEnabled = isQueryBuilderEnabled(config)
164
170
  if (qbEnabled) {
165
171
  const qbConfig = getQueryBuilderConfig(config)
@@ -219,7 +225,7 @@ export function ${routerFunctionName}<TCtx = unknown>(config: ${modelName}RouteC
219
225
  }
220
226
  }
221
227
 
222
- const maybeProgressiveSSE = (
228
+ const maybeProgressiveSSE = (
223
229
  opConfig: OperationConfigLike,
224
230
  coreFn: (ctx: OperationContext) => Promise<unknown>,
225
231
  baseOp: string,
@@ -342,12 +348,10 @@ const maybeProgressiveSSE = (
342
348
  const openapiJsonPath = basePath ? \`\${basePath}/openapi.json\` : '/openapi.json'
343
349
  const openapiYamlPath = basePath ? \`\${basePath}/openapi.yaml\` : '/openapi.yaml'
344
350
  router.get(openapiJsonPath, (_req, res) => {
345
- 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' })
346
- res.json(spec)
351
+ res.json(openApiJsonSpec)
347
352
  })
348
353
  router.get(openapiYamlPath, (_req, res) => {
349
- 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' })
350
- res.type('application/yaml').send(spec as string)
354
+ res.type('application/yaml').send(openApiYamlSpec as string)
351
355
  })
352
356
  }
353
357
 
@@ -355,66 +359,66 @@ const maybeProgressiveSSE = (
355
359
  const opConfig: OperationConfigLike = (config.findFirst as OperationConfigLike | undefined) ?? defaultOpConfig
356
360
  const { before = [], after = [] } = opConfig
357
361
  const path = basePath ? \`\${basePath}/first\` : '/first'
358
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findFirst, 'findFirst'), ${prefix}FindFirst as RequestHandler, ...after, respond)
359
- if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindFirst as RequestHandler, ...after, respond)
362
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findFirst, 'findFirst'), ${modelName}FindFirst as RequestHandler, ...after, respond)
363
+ if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${modelName}FindFirst as RequestHandler, ...after, respond)
360
364
  }
361
365
  if (config.enableAll || config.findFirstOrThrow) {
362
366
  const opConfig: OperationConfigLike = (config.findFirstOrThrow as OperationConfigLike | undefined) ?? defaultOpConfig
363
367
  const { before = [], after = [] } = opConfig
364
368
  const path = basePath ? \`\${basePath}/first/strict\` : '/first/strict'
365
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findFirstOrThrow, 'findFirstOrThrow'), ${prefix}FindFirstOrThrow as RequestHandler, ...after, respond)
366
- if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindFirstOrThrow as RequestHandler, ...after, respond)
369
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findFirstOrThrow, 'findFirstOrThrow'), ${modelName}FindFirstOrThrow as RequestHandler, ...after, respond)
370
+ if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${modelName}FindFirstOrThrow as RequestHandler, ...after, respond)
367
371
  }
368
372
  if (config.enableAll || config.findManyPaginated) {
369
373
  const opConfig: OperationConfigLike = (config.findManyPaginated as OperationConfigLike | undefined) ?? defaultOpConfig
370
374
  const { before = [], after = [] } = opConfig
371
375
  const path = basePath ? \`\${basePath}/paginated\` : '/paginated'
372
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findManyPaginated, 'findManyPaginated'), ${prefix}FindManyPaginated as RequestHandler, ...after, respond)
373
- if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindManyPaginated as RequestHandler, ...after, respond)
376
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findManyPaginated, 'findManyPaginated'), ${modelName}FindManyPaginated as RequestHandler, ...after, respond)
377
+ if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${modelName}FindManyPaginated as RequestHandler, ...after, respond)
374
378
  }
375
379
  if (config.enableAll || config.aggregate) {
376
380
  const opConfig: OperationConfigLike = (config.aggregate as OperationConfigLike | undefined) ?? defaultOpConfig
377
381
  const { before = [], after = [] } = opConfig
378
382
  const path = basePath ? \`\${basePath}/aggregate\` : '/aggregate'
379
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.aggregate, 'aggregate'), ${prefix}Aggregate as RequestHandler, ...after, respond)
380
- if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}Aggregate as RequestHandler, ...after, respond)
383
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.aggregate, 'aggregate'), ${modelName}Aggregate as RequestHandler, ...after, respond)
384
+ if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${modelName}Aggregate as RequestHandler, ...after, respond)
381
385
  }
382
386
  if (config.enableAll || config.count) {
383
387
  const opConfig: OperationConfigLike = (config.count as OperationConfigLike | undefined) ?? defaultOpConfig
384
388
  const { before = [], after = [] } = opConfig
385
389
  const path = basePath ? \`\${basePath}/count\` : '/count'
386
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.count, 'count'), ${prefix}Count as RequestHandler, ...after, respond)
387
- if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}Count as RequestHandler, ...after, respond)
390
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.count, 'count'), ${modelName}Count as RequestHandler, ...after, respond)
391
+ if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${modelName}Count as RequestHandler, ...after, respond)
388
392
  }
389
393
  if (config.enableAll || config.groupBy) {
390
394
  const opConfig: OperationConfigLike = (config.groupBy as OperationConfigLike | undefined) ?? defaultOpConfig
391
395
  const { before = [], after = [] } = opConfig
392
396
  const path = basePath ? \`\${basePath}/groupby\` : '/groupby'
393
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.groupBy, 'groupBy'), ${prefix}GroupBy as RequestHandler, ...after, respond)
394
- if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}GroupBy as RequestHandler, ...after, respond)
397
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.groupBy, 'groupBy'), ${modelName}GroupBy as RequestHandler, ...after, respond)
398
+ if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${modelName}GroupBy as RequestHandler, ...after, respond)
395
399
  }
396
400
  if (config.enableAll || config.findUniqueOrThrow) {
397
401
  const opConfig: OperationConfigLike = (config.findUniqueOrThrow as OperationConfigLike | undefined) ?? defaultOpConfig
398
402
  const { before = [], after = [] } = opConfig
399
403
  const path = basePath ? \`\${basePath}/unique/strict\` : '/unique/strict'
400
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findUniqueOrThrow, 'findUniqueOrThrow'), ${prefix}FindUniqueOrThrow as RequestHandler, ...after, respond)
401
- if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindUniqueOrThrow as RequestHandler, ...after, respond)
404
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findUniqueOrThrow, 'findUniqueOrThrow'), ${modelName}FindUniqueOrThrow as RequestHandler, ...after, respond)
405
+ if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${modelName}FindUniqueOrThrow as RequestHandler, ...after, respond)
402
406
  }
403
407
  if (config.enableAll || config.findUnique) {
404
408
  const opConfig: OperationConfigLike = (config.findUnique as OperationConfigLike | undefined) ?? defaultOpConfig
405
409
  const { before = [], after = [] } = opConfig
406
410
  const path = basePath ? \`\${basePath}/unique\` : '/unique'
407
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findUnique, 'findUnique'), ${prefix}FindUnique as RequestHandler, ...after, respond)
408
- if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindUnique as RequestHandler, ...after, respond)
411
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findUnique, 'findUnique'), ${modelName}FindUnique as RequestHandler, ...after, respond)
412
+ if (postReadsEnabled) router.post(path, parseBodyAsQuery, setShape(opConfig), ...before, ${modelName}FindUnique as RequestHandler, ...after, respond)
409
413
  }
410
414
  if (config.enableAll || config.findMany) {
411
415
  const opConfig: OperationConfigLike = (config.findMany as OperationConfigLike | undefined) ?? defaultOpConfig
412
416
  const { before = [], after = [] } = opConfig
413
417
  const path = basePath || '/'
414
- router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findMany, 'findMany'), ${prefix}FindMany as RequestHandler, ...after, respond)
418
+ router.get(path, parseQuery, setShape(opConfig), ...before, maybeProgressiveSSE(opConfig, core.findMany, 'findMany'), ${modelName}FindMany as RequestHandler, ...after, respond)
415
419
  if (postReadsEnabled) {
416
420
  const postPath = basePath ? \`\${basePath}/read\` : '/read'
417
- router.post(postPath, parseBodyAsQuery, setShape(opConfig), ...before, ${prefix}FindMany as RequestHandler, ...after, respond)
421
+ router.post(postPath, parseBodyAsQuery, setShape(opConfig), ...before, ${modelName}FindMany as RequestHandler, ...after, respond)
418
422
  }
419
423
  }
420
424
 
@@ -422,55 +426,55 @@ const maybeProgressiveSSE = (
422
426
  const opConfig: OperationConfigLike = (config.createManyAndReturn as OperationConfigLike | undefined) ?? defaultOpConfig
423
427
  const { before = [], after = [] } = opConfig
424
428
  const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
425
- router.post(path, setShape(opConfig), ...before, ${prefix}CreateManyAndReturn as RequestHandler, ...after, respondCreated)
429
+ router.post(path, setShape(opConfig), ...before, ${modelName}CreateManyAndReturn as RequestHandler, ...after, respondCreated)
426
430
  }
427
431
  if (config.enableAll || config.createMany) {
428
432
  const opConfig: OperationConfigLike = (config.createMany as OperationConfigLike | undefined) ?? defaultOpConfig
429
433
  const { before = [], after = [] } = opConfig
430
434
  const path = basePath ? \`\${basePath}/many\` : '/many'
431
- router.post(path, setShape(opConfig), ...before, ${prefix}CreateMany as RequestHandler, ...after, respondCreated)
435
+ router.post(path, setShape(opConfig), ...before, ${modelName}CreateMany as RequestHandler, ...after, respondCreated)
432
436
  }
433
437
  if (config.enableAll || config.create) {
434
438
  const opConfig: OperationConfigLike = (config.create as OperationConfigLike | undefined) ?? defaultOpConfig
435
439
  const { before = [], after = [] } = opConfig
436
440
  const path = basePath || '/'
437
- router.post(path, setShape(opConfig), ...before, ${prefix}Create as RequestHandler, ...after, respondCreated)
441
+ router.post(path, setShape(opConfig), ...before, ${modelName}Create as RequestHandler, ...after, respondCreated)
438
442
  }
439
443
  if (config.enableAll || config.updateManyAndReturn) {
440
444
  const opConfig: OperationConfigLike = (config.updateManyAndReturn as OperationConfigLike | undefined) ?? defaultOpConfig
441
445
  const { before = [], after = [] } = opConfig
442
446
  const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
443
- router.put(path, setShape(opConfig), ...before, ${prefix}UpdateManyAndReturn as RequestHandler, ...after, respond)
447
+ router.put(path, setShape(opConfig), ...before, ${modelName}UpdateManyAndReturn as RequestHandler, ...after, respond)
444
448
  }
445
449
  if (config.enableAll || config.updateMany) {
446
450
  const opConfig: OperationConfigLike = (config.updateMany as OperationConfigLike | undefined) ?? defaultOpConfig
447
451
  const { before = [], after = [] } = opConfig
448
452
  const path = basePath ? \`\${basePath}/many\` : '/many'
449
- router.put(path, setShape(opConfig), ...before, ${prefix}UpdateMany as RequestHandler, ...after, respond)
453
+ router.put(path, setShape(opConfig), ...before, ${modelName}UpdateMany as RequestHandler, ...after, respond)
450
454
  }
451
455
  if (config.enableAll || config.update) {
452
456
  const opConfig: OperationConfigLike = (config.update as OperationConfigLike | undefined) ?? defaultOpConfig
453
457
  const { before = [], after = [] } = opConfig
454
458
  const path = basePath || '/'
455
- router.put(path, setShape(opConfig), ...before, ${prefix}Update as RequestHandler, ...after, respond)
459
+ router.put(path, setShape(opConfig), ...before, ${modelName}Update as RequestHandler, ...after, respond)
456
460
  }
457
461
  if (config.enableAll || config.upsert) {
458
462
  const opConfig: OperationConfigLike = (config.upsert as OperationConfigLike | undefined) ?? defaultOpConfig
459
463
  const { before = [], after = [] } = opConfig
460
464
  const path = basePath || '/'
461
- router.patch(path, setShape(opConfig), ...before, ${prefix}Upsert as RequestHandler, ...after, respond)
465
+ router.patch(path, setShape(opConfig), ...before, ${modelName}Upsert as RequestHandler, ...after, respond)
462
466
  }
463
467
  if (config.enableAll || config.deleteMany) {
464
468
  const opConfig: OperationConfigLike = (config.deleteMany as OperationConfigLike | undefined) ?? defaultOpConfig
465
469
  const { before = [], after = [] } = opConfig
466
470
  const path = basePath ? \`\${basePath}/many\` : '/many'
467
- router.delete(path, setShape(opConfig), ...before, ${prefix}DeleteMany as RequestHandler, ...after, respond)
471
+ router.delete(path, setShape(opConfig), ...before, ${modelName}DeleteMany as RequestHandler, ...after, respond)
468
472
  }
469
473
  if (config.enableAll || config.delete) {
470
474
  const opConfig: OperationConfigLike = (config.delete as OperationConfigLike | undefined) ?? defaultOpConfig
471
475
  const { before = [], after = [] } = opConfig
472
476
  const path = basePath || '/'
473
- router.delete(path, setShape(opConfig), ...before, ${prefix}Delete as RequestHandler, ...after, respond)
477
+ router.delete(path, setShape(opConfig), ...before, ${modelName}Delete as RequestHandler, ...after, respond)
474
478
  }
475
479
 
476
480
  router.use((err: unknown, _req: Request, res: Response, next: NextFunction) => {
@@ -1,5 +1,4 @@
1
1
  import { DMMF } from '@prisma/generator-helper'
2
- import { toCamelCase } from '../utils/strings'
3
2
  import { generateRouteConfigType } from './generateRouteConfigType'
4
3
  import { ImportStyle } from '../utils/resolveImportStyle'
5
4
  import { importExt } from '../utils/importExt'
@@ -17,9 +16,8 @@ export function generateFastifyRouterFunction({
17
16
  }): string {
18
17
  const ext = importExt(importStyle)
19
18
  const modelName = model.name
20
- const prefix = toCamelCase(modelName)
21
19
  const modelNameLower = modelName.toLowerCase()
22
- const routerFunctionName = `${prefix}Router`
20
+ const routerFunctionName = `${modelName}Router`
23
21
 
24
22
  const fieldsMeta = model.fields.map((f) => ({
25
23
  name: f.name,
@@ -47,33 +45,33 @@ export function generateFastifyRouterFunction({
47
45
  return `import type { FastifyInstance, FastifyRequest, FastifyReply, FastifyError } from 'fastify'
48
46
  import { startQueryBuilder } from '../queryBuilder${ext}'
49
47
  import {
50
- ${prefix}FindUnique,
51
- ${prefix}FindUniqueOrThrow,
52
- ${prefix}FindFirst,
53
- ${prefix}FindFirstOrThrow,
54
- ${prefix}FindMany,
55
- ${prefix}FindManyPaginated,
56
- ${prefix}Create,
57
- ${prefix}CreateMany,
58
- ${prefix}CreateManyAndReturn,
59
- ${prefix}Update,
60
- ${prefix}UpdateMany,
61
- ${prefix}UpdateManyAndReturn,
62
- ${prefix}Upsert,
63
- ${prefix}Delete,
64
- ${prefix}DeleteMany,
65
- ${prefix}Aggregate,
66
- ${prefix}Count,
67
- ${prefix}GroupBy,
48
+ ${modelName}FindUnique,
49
+ ${modelName}FindUniqueOrThrow,
50
+ ${modelName}FindFirst,
51
+ ${modelName}FindFirstOrThrow,
52
+ ${modelName}FindMany,
53
+ ${modelName}FindManyPaginated,
54
+ ${modelName}Create,
55
+ ${modelName}CreateMany,
56
+ ${modelName}CreateManyAndReturn,
57
+ ${modelName}Update,
58
+ ${modelName}UpdateMany,
59
+ ${modelName}UpdateManyAndReturn,
60
+ ${modelName}Upsert,
61
+ ${modelName}Delete,
62
+ ${modelName}DeleteMany,
63
+ ${modelName}Aggregate,
64
+ ${modelName}Count,
65
+ ${modelName}GroupBy,
68
66
  } from './${modelName}Handlers${ext}'
69
67
  import type { RouteConfig, FastifyHookHandler } from '../routeConfig.target${ext}'
70
68
  import { parseQueryParams } from '../parseQueryParams${ext}'
71
- import { sanitizeKeys } from '../misc${ext}'
69
+ import { sanitizeKeys, normalizePrefix, getEnv } from '../misc${ext}'
72
70
  import { buildModelOpenApi } from '../buildModelOpenApi${ext}'
73
71
  import { mapError, transformResult, HttpError, type OperationContext } from '../operationRuntime${ext}'
74
72
 
75
73
  ${generateRouteConfigType(modelName, 'FastifyHookHandler', guardShapesImport, importStyle, 'fastify')}
76
- const _env = typeof process !== 'undefined' && process.env ? process.env : {} as Record<string, string | undefined>
74
+ const _env = getEnv()
77
75
 
78
76
  const MODEL_FIELDS = ${JSON.stringify(fieldsMeta, null, 2)} as const
79
77
 
@@ -97,19 +95,10 @@ type FastifyExtended = FastifyRequest & {
97
95
  resultStatus?: number
98
96
  }
99
97
 
100
- const defaultOpConfig: OperationConfigLike = {
101
- before: [],
102
- after: [],
103
- }
104
-
105
- function normalizePrefix(p: string): string {
106
- if (!p) return ''
107
- let result = p
108
- if (!result.startsWith('/')) result = '/' + result
109
- while (result.length > 1 && result.endsWith('/')) result = result.slice(0, -1)
110
- if (result === '/') return ''
111
- return result
112
- }
98
+ const defaultOpConfig: OperationConfigLike = Object.freeze({
99
+ before: Object.freeze([]) as unknown as FastifyHookHandler[],
100
+ after: Object.freeze([]) as unknown as FastifyHookHandler[],
101
+ })
113
102
 
114
103
  function isQueryBuilderEnabled(config: RouteConfig): boolean {
115
104
  if (config.queryBuilder === false) return false
@@ -149,16 +138,16 @@ function makeShapeHook(
149
138
  if (paginationConfig) {
150
139
  fx.routeConfig = { pagination: paginationConfig }
151
140
  }
141
+ const headerName = (config.guard?.variantHeader || 'x-api-variant').toLowerCase()
142
+ const headerValue = request.headers[headerName]
143
+ const caller = config.guard?.resolveVariant?.(request)
144
+ ?? (Array.isArray(headerValue) ? headerValue[0] : headerValue)
145
+ ?? undefined
146
+ if (caller) {
147
+ fx.guardCaller = caller
148
+ }
152
149
  if (opConfig.shape) {
153
150
  fx.guardShape = opConfig.shape
154
- const headerName = config.guard?.variantHeader || 'x-api-variant'
155
- const headerValue = request.headers[headerName]
156
- const caller = config.guard?.resolveVariant?.(request)
157
- ?? (Array.isArray(headerValue) ? headerValue[0] : headerValue)
158
- ?? undefined
159
- if (caller) {
160
- fx.guardCaller = caller
161
- }
162
151
  }
163
152
  }
164
153
  }
@@ -191,9 +180,9 @@ function sendError(reply: FastifyReply, error: unknown): void {
191
180
  reply.code(httpError.status).send({ message: httpError.message })
192
181
  }
193
182
 
194
- export async function ${routerFunctionName}<TCtx = unknown>(
183
+ export async function ${routerFunctionName}<TCtx = unknown, TPrisma = any>(
195
184
  fastify: FastifyInstance,
196
- config: ${modelName}RouteConfig<TCtx> = {},
185
+ config: ${modelName}RouteConfig<TCtx, TPrisma> = {},
197
186
  ) {
198
187
  const customPrefix = normalizePrefix(config.customUrlPrefix || '')
199
188
  const modelPrefix = config.addModelPrefix !== false ? '/${modelNameLower}' : ''
@@ -207,6 +196,25 @@ export async function ${routerFunctionName}<TCtx = unknown>(
207
196
 
208
197
  const postReadsEnabled = !config.disablePostReads
209
198
 
199
+ const openApiJsonSpec = openApiDisabled
200
+ ? null
201
+ : buildModelOpenApi(
202
+ '${modelName}',
203
+ MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
204
+ MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
205
+ config,
206
+ { format: 'json' },
207
+ )
208
+ const openApiYamlSpec = openApiDisabled
209
+ ? null
210
+ : buildModelOpenApi(
211
+ '${modelName}',
212
+ MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
213
+ MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
214
+ config,
215
+ { format: 'yaml' },
216
+ )
217
+
210
218
  const qbEnabled = isQueryBuilderEnabled(config)
211
219
 
212
220
  if (qbEnabled) {
@@ -234,25 +242,11 @@ export async function ${routerFunctionName}<TCtx = unknown>(
234
242
  const openapiYamlPath = basePath ? \`\${basePath}/openapi.yaml\` : '/openapi.yaml'
235
243
 
236
244
  fastify.get(openapiJsonPath, async (_request, reply) => {
237
- const spec = buildModelOpenApi(
238
- '${modelName}',
239
- MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
240
- MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
241
- config,
242
- { format: 'json' },
243
- )
244
- return reply.send(spec)
245
+ return reply.send(openApiJsonSpec)
245
246
  })
246
247
 
247
248
  fastify.get(openapiYamlPath, async (_request, reply) => {
248
- const spec = buildModelOpenApi(
249
- '${modelName}',
250
- MODEL_FIELDS as unknown as Parameters<typeof buildModelOpenApi>[1],
251
- MODEL_ENUMS as unknown as Parameters<typeof buildModelOpenApi>[2],
252
- config,
253
- { format: 'yaml' },
254
- )
255
- return reply.type('application/yaml').send(spec as string)
249
+ return reply.type('application/yaml').send(openApiYamlSpec as string)
256
250
  })
257
251
  }
258
252
 
@@ -293,121 +287,121 @@ export async function ${routerFunctionName}<TCtx = unknown>(
293
287
  if (config.enableAll || config.findFirst) {
294
288
  const opConfig: OperationConfigLike = (config.findFirst as OperationConfigLike | undefined) ?? defaultOpConfig
295
289
  const path = basePath ? \`\${basePath}/first\` : '/first'
296
- fastify.get(path, handleGet(opConfig, ${prefix}FindFirst, parseQueryHook))
297
- if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${prefix}FindFirst, parseBodyAsQueryHook))
290
+ fastify.get(path, handleGet(opConfig, ${modelName}FindFirst, parseQueryHook))
291
+ if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${modelName}FindFirst, parseBodyAsQueryHook))
298
292
  }
299
293
 
300
294
  if (config.enableAll || config.findFirstOrThrow) {
301
295
  const opConfig: OperationConfigLike = (config.findFirstOrThrow as OperationConfigLike | undefined) ?? defaultOpConfig
302
296
  const path = basePath ? \`\${basePath}/first/strict\` : '/first/strict'
303
- fastify.get(path, handleGet(opConfig, ${prefix}FindFirstOrThrow, parseQueryHook))
304
- if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${prefix}FindFirstOrThrow, parseBodyAsQueryHook))
297
+ fastify.get(path, handleGet(opConfig, ${modelName}FindFirstOrThrow, parseQueryHook))
298
+ if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${modelName}FindFirstOrThrow, parseBodyAsQueryHook))
305
299
  }
306
300
 
307
301
  if (config.enableAll || config.findManyPaginated) {
308
302
  const opConfig: OperationConfigLike = (config.findManyPaginated as OperationConfigLike | undefined) ?? defaultOpConfig
309
303
  const path = basePath ? \`\${basePath}/paginated\` : '/paginated'
310
- fastify.get(path, handleGet(opConfig, ${prefix}FindManyPaginated, parseQueryHook))
311
- if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${prefix}FindManyPaginated, parseBodyAsQueryHook))
304
+ fastify.get(path, handleGet(opConfig, ${modelName}FindManyPaginated, parseQueryHook))
305
+ if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${modelName}FindManyPaginated, parseBodyAsQueryHook))
312
306
  }
313
307
 
314
308
  if (config.enableAll || config.aggregate) {
315
309
  const opConfig: OperationConfigLike = (config.aggregate as OperationConfigLike | undefined) ?? defaultOpConfig
316
310
  const path = basePath ? \`\${basePath}/aggregate\` : '/aggregate'
317
- fastify.get(path, handleGet(opConfig, ${prefix}Aggregate, parseQueryHook))
318
- if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${prefix}Aggregate, parseBodyAsQueryHook))
311
+ fastify.get(path, handleGet(opConfig, ${modelName}Aggregate, parseQueryHook))
312
+ if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${modelName}Aggregate, parseBodyAsQueryHook))
319
313
  }
320
314
 
321
315
  if (config.enableAll || config.count) {
322
316
  const opConfig: OperationConfigLike = (config.count as OperationConfigLike | undefined) ?? defaultOpConfig
323
317
  const path = basePath ? \`\${basePath}/count\` : '/count'
324
- fastify.get(path, handleGet(opConfig, ${prefix}Count, parseQueryHook))
325
- if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${prefix}Count, parseBodyAsQueryHook))
318
+ fastify.get(path, handleGet(opConfig, ${modelName}Count, parseQueryHook))
319
+ if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${modelName}Count, parseBodyAsQueryHook))
326
320
  }
327
321
 
328
322
  if (config.enableAll || config.groupBy) {
329
323
  const opConfig: OperationConfigLike = (config.groupBy as OperationConfigLike | undefined) ?? defaultOpConfig
330
324
  const path = basePath ? \`\${basePath}/groupby\` : '/groupby'
331
- fastify.get(path, handleGet(opConfig, ${prefix}GroupBy, parseQueryHook))
332
- if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${prefix}GroupBy, parseBodyAsQueryHook))
325
+ fastify.get(path, handleGet(opConfig, ${modelName}GroupBy, parseQueryHook))
326
+ if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${modelName}GroupBy, parseBodyAsQueryHook))
333
327
  }
334
328
 
335
329
  if (config.enableAll || config.findUniqueOrThrow) {
336
330
  const opConfig: OperationConfigLike = (config.findUniqueOrThrow as OperationConfigLike | undefined) ?? defaultOpConfig
337
331
  const path = basePath ? \`\${basePath}/unique/strict\` : '/unique/strict'
338
- fastify.get(path, handleGet(opConfig, ${prefix}FindUniqueOrThrow, parseQueryHook))
339
- if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${prefix}FindUniqueOrThrow, parseBodyAsQueryHook))
332
+ fastify.get(path, handleGet(opConfig, ${modelName}FindUniqueOrThrow, parseQueryHook))
333
+ if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${modelName}FindUniqueOrThrow, parseBodyAsQueryHook))
340
334
  }
341
335
 
342
336
  if (config.enableAll || config.findUnique) {
343
337
  const opConfig: OperationConfigLike = (config.findUnique as OperationConfigLike | undefined) ?? defaultOpConfig
344
338
  const path = basePath ? \`\${basePath}/unique\` : '/unique'
345
- fastify.get(path, handleGet(opConfig, ${prefix}FindUnique, parseQueryHook))
346
- if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${prefix}FindUnique, parseBodyAsQueryHook))
339
+ fastify.get(path, handleGet(opConfig, ${modelName}FindUnique, parseQueryHook))
340
+ if (postReadsEnabled) fastify.post(path, handleGet(opConfig, ${modelName}FindUnique, parseBodyAsQueryHook))
347
341
  }
348
342
 
349
343
  if (config.enableAll || config.findMany) {
350
344
  const opConfig: OperationConfigLike = (config.findMany as OperationConfigLike | undefined) ?? defaultOpConfig
351
345
  const path = basePath || '/'
352
- fastify.get(path, handleGet(opConfig, ${prefix}FindMany, parseQueryHook))
346
+ fastify.get(path, handleGet(opConfig, ${modelName}FindMany, parseQueryHook))
353
347
  if (postReadsEnabled) {
354
348
  const postPath = basePath ? \`\${basePath}/read\` : '/read'
355
- fastify.post(postPath, handleGet(opConfig, ${prefix}FindMany, parseBodyAsQueryHook))
349
+ fastify.post(postPath, handleGet(opConfig, ${modelName}FindMany, parseBodyAsQueryHook))
356
350
  }
357
351
  }
358
352
 
359
353
  if (config.enableAll || config.createManyAndReturn) {
360
354
  const opConfig: OperationConfigLike = (config.createManyAndReturn as OperationConfigLike | undefined) ?? defaultOpConfig
361
355
  const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
362
- fastify.post(path, handleWrite(opConfig, ${prefix}CreateManyAndReturn))
356
+ fastify.post(path, handleWrite(opConfig, ${modelName}CreateManyAndReturn))
363
357
  }
364
358
 
365
359
  if (config.enableAll || config.createMany) {
366
360
  const opConfig: OperationConfigLike = (config.createMany as OperationConfigLike | undefined) ?? defaultOpConfig
367
361
  const path = basePath ? \`\${basePath}/many\` : '/many'
368
- fastify.post(path, handleWrite(opConfig, ${prefix}CreateMany))
362
+ fastify.post(path, handleWrite(opConfig, ${modelName}CreateMany))
369
363
  }
370
364
 
371
365
  if (config.enableAll || config.create) {
372
366
  const opConfig: OperationConfigLike = (config.create as OperationConfigLike | undefined) ?? defaultOpConfig
373
367
  const path = basePath || '/'
374
- fastify.post(path, handleWrite(opConfig, ${prefix}Create))
368
+ fastify.post(path, handleWrite(opConfig, ${modelName}Create))
375
369
  }
376
370
 
377
371
  if (config.enableAll || config.updateManyAndReturn) {
378
372
  const opConfig: OperationConfigLike = (config.updateManyAndReturn as OperationConfigLike | undefined) ?? defaultOpConfig
379
373
  const path = basePath ? \`\${basePath}/many/return\` : '/many/return'
380
- fastify.put(path, handleWrite(opConfig, ${prefix}UpdateManyAndReturn))
374
+ fastify.put(path, handleWrite(opConfig, ${modelName}UpdateManyAndReturn))
381
375
  }
382
376
 
383
377
  if (config.enableAll || config.updateMany) {
384
378
  const opConfig: OperationConfigLike = (config.updateMany as OperationConfigLike | undefined) ?? defaultOpConfig
385
379
  const path = basePath ? \`\${basePath}/many\` : '/many'
386
- fastify.put(path, handleWrite(opConfig, ${prefix}UpdateMany))
380
+ fastify.put(path, handleWrite(opConfig, ${modelName}UpdateMany))
387
381
  }
388
382
 
389
383
  if (config.enableAll || config.update) {
390
384
  const opConfig: OperationConfigLike = (config.update as OperationConfigLike | undefined) ?? defaultOpConfig
391
385
  const path = basePath || '/'
392
- fastify.put(path, handleWrite(opConfig, ${prefix}Update))
386
+ fastify.put(path, handleWrite(opConfig, ${modelName}Update))
393
387
  }
394
388
 
395
389
  if (config.enableAll || config.upsert) {
396
390
  const opConfig: OperationConfigLike = (config.upsert as OperationConfigLike | undefined) ?? defaultOpConfig
397
391
  const path = basePath || '/'
398
- fastify.patch(path, handleWrite(opConfig, ${prefix}Upsert))
392
+ fastify.patch(path, handleWrite(opConfig, ${modelName}Upsert))
399
393
  }
400
394
 
401
395
  if (config.enableAll || config.deleteMany) {
402
396
  const opConfig: OperationConfigLike = (config.deleteMany as OperationConfigLike | undefined) ?? defaultOpConfig
403
397
  const path = basePath ? \`\${basePath}/many\` : '/many'
404
- fastify.delete(path, handleWrite(opConfig, ${prefix}DeleteMany))
398
+ fastify.delete(path, handleWrite(opConfig, ${modelName}DeleteMany))
405
399
  }
406
400
 
407
401
  if (config.enableAll || config.delete) {
408
402
  const opConfig: OperationConfigLike = (config.delete as OperationConfigLike | undefined) ?? defaultOpConfig
409
403
  const path = basePath || '/'
410
- fastify.delete(path, handleWrite(opConfig, ${prefix}Delete))
404
+ fastify.delete(path, handleWrite(opConfig, ${modelName}Delete))
411
405
  }
412
406
  }
413
407
  `