prisma-generator-express 1.66.0 → 1.67.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 (102) hide show
  1. package/README.md +37 -3476
  2. package/dist/client/encodeQueryParams.js +3 -1
  3. package/dist/client/encodeQueryParams.js.map +1 -1
  4. package/dist/copy/misc.d.ts +1 -0
  5. package/dist/copy/misc.js +14 -0
  6. package/dist/copy/misc.js.map +1 -1
  7. package/dist/copy/operationDefinitions.js +69 -6
  8. package/dist/copy/operationDefinitions.js.map +1 -1
  9. package/dist/generators/generateFastifyHandler.d.ts +2 -2
  10. package/dist/generators/generateFastifyHandler.js +15 -5
  11. package/dist/generators/generateFastifyHandler.js.map +1 -1
  12. package/dist/generators/generateHonoHandler.d.ts +2 -2
  13. package/dist/generators/generateHonoHandler.js +12 -5
  14. package/dist/generators/generateHonoHandler.js.map +1 -1
  15. package/dist/generators/generateImportPrismaStatement.d.ts +1 -0
  16. package/dist/generators/generateImportPrismaStatement.js +6 -0
  17. package/dist/generators/generateImportPrismaStatement.js.map +1 -1
  18. package/dist/generators/generateModelMetadata.js +20 -10
  19. package/dist/generators/generateModelMetadata.js.map +1 -1
  20. package/dist/generators/generateOperationCore.d.ts +3 -3
  21. package/dist/generators/generateOperationCore.js +51 -16
  22. package/dist/generators/generateOperationCore.js.map +1 -1
  23. package/dist/generators/generateRelationMeta.js +2 -2
  24. package/dist/generators/generateRelationMeta.js.map +1 -1
  25. package/dist/generators/generateRouteConfigType.d.ts +2 -2
  26. package/dist/generators/generateRouteConfigType.js +29 -11
  27. package/dist/generators/generateRouteConfigType.js.map +1 -1
  28. package/dist/generators/generateRouter.d.ts +7 -4
  29. package/dist/generators/generateRouter.js +107 -14
  30. package/dist/generators/generateRouter.js.map +1 -1
  31. package/dist/generators/generateRouterFastify.d.ts +7 -4
  32. package/dist/generators/generateRouterFastify.js +56 -28
  33. package/dist/generators/generateRouterFastify.js.map +1 -1
  34. package/dist/generators/generateRouterHono.d.ts +7 -4
  35. package/dist/generators/generateRouterHono.js +36 -23
  36. package/dist/generators/generateRouterHono.js.map +1 -1
  37. package/dist/generators/generateUnifiedDocs.d.ts +1 -1
  38. package/dist/generators/generateUnifiedDocs.js +15 -8
  39. package/dist/generators/generateUnifiedDocs.js.map +1 -1
  40. package/dist/generators/generateUnifiedHandler.d.ts +2 -2
  41. package/dist/generators/generateUnifiedHandler.js +11 -3
  42. package/dist/generators/generateUnifiedHandler.js.map +1 -1
  43. package/dist/guardOptions.js +12 -7
  44. package/dist/guardOptions.js.map +1 -1
  45. package/dist/index.d.ts +1 -1
  46. package/dist/index.js +22 -1
  47. package/dist/index.js.map +1 -1
  48. package/dist/utils/copyFiles.js +22 -6
  49. package/dist/utils/copyFiles.js.map +1 -1
  50. package/dist/utils/importExt.d.ts +1 -1
  51. package/dist/utils/pathCasing.d.ts +4 -0
  52. package/dist/utils/pathCasing.js +40 -0
  53. package/dist/utils/pathCasing.js.map +1 -0
  54. package/dist/utils/resolveImportStyle.js +13 -5
  55. package/dist/utils/resolveImportStyle.js.map +1 -1
  56. package/dist/utils/writeFileSafely.js.map +1 -1
  57. package/package.json +5 -3
  58. package/src/bin.ts +1 -1
  59. package/src/client/encodeQueryParams.ts +39 -35
  60. package/src/constants.ts +1 -1
  61. package/src/copy/autoIncludePlanner.ts +93 -27
  62. package/src/copy/autoIncludePlannerGuarded.ts +171 -48
  63. package/src/copy/autoIncludeRuntimeGuarded.ts +25 -7
  64. package/src/copy/buildModelOpenApi.ts +153 -50
  65. package/src/copy/concurrency.ts +10 -8
  66. package/src/copy/errorMapper.ts +68 -19
  67. package/src/copy/guardHelpers.ts +30 -9
  68. package/src/copy/materializedCount.ts +17 -5
  69. package/src/copy/misc.ts +88 -68
  70. package/src/copy/ndjson.ts +72 -0
  71. package/src/copy/operationDefinitions.ts +99 -21
  72. package/src/copy/operationRuntime.ts +100 -12
  73. package/src/copy/pagination.ts +25 -11
  74. package/src/copy/parseQueryParams.ts +47 -48
  75. package/src/copy/projectionDefaults.ts +6 -4
  76. package/src/copy/routeConfig.express.ts +16 -4
  77. package/src/copy/routeConfig.fastify.ts +16 -2
  78. package/src/copy/routeConfig.hono.ts +12 -9
  79. package/src/copy/routeConfig.ts +174 -39
  80. package/src/copy/scalarTypes.ts +7 -2
  81. package/src/copy/sse.ts +72 -19
  82. package/src/generators/generateFastifyHandler.ts +24 -13
  83. package/src/generators/generateHonoHandler.ts +21 -13
  84. package/src/generators/generateImportPrismaStatement.ts +93 -81
  85. package/src/generators/generateModelMetadata.ts +24 -12
  86. package/src/generators/generateOperationCore.ts +81 -33
  87. package/src/generators/generateRelationMeta.ts +23 -11
  88. package/src/generators/generateRouteConfigType.ts +39 -13
  89. package/src/generators/generateRouter.ts +114 -17
  90. package/src/generators/generateRouterFastify.ts +67 -31
  91. package/src/generators/generateRouterHono.ts +60 -30
  92. package/src/generators/generateUnifiedDocs.ts +29 -8
  93. package/src/generators/generateUnifiedHandler.ts +16 -8
  94. package/src/generators/generateUnifiedScalarUI.ts +1 -1
  95. package/src/guardOptions.ts +105 -92
  96. package/src/index.ts +46 -4
  97. package/src/utils/copyFiles.ts +199 -168
  98. package/src/utils/importExt.ts +2 -2
  99. package/src/utils/pathCasing.ts +42 -0
  100. package/src/utils/resolveImportStyle.ts +37 -15
  101. package/src/utils/strings.ts +2 -2
  102. package/src/utils/writeFileSafely.ts +6 -2
@@ -1,5 +1,5 @@
1
- import { DMMF } from '@prisma/generator-helper'
2
- import { ImportStyle } from '../utils/resolveImportStyle'
1
+ import type { DMMF } from '@prisma/generator-helper'
2
+ import type { ImportStyle } from '../utils/resolveImportStyle'
3
3
  import { importExt } from '../utils/importExt'
4
4
  import { OPERATION_METADATA } from '../copy/operationDefinitions'
5
5
 
@@ -12,12 +12,14 @@ export function generateFastifyHandler(options: {
12
12
 
13
13
  const readOps = OPERATION_METADATA.filter((m) => m.kind === 'read')
14
14
  const writeOps = OPERATION_METADATA.filter(
15
- (m) => (m.kind === 'write' || m.kind === 'batch') && m.name !== 'updateEach',
15
+ (m) =>
16
+ (m.kind === 'write' || m.kind === 'batch') && m.name !== 'updateEach',
16
17
  )
17
18
 
18
- const readHandlers = readOps.map((meta) => {
19
- const exportName = `${modelName}${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`
20
- return `
19
+ const readHandlers = readOps
20
+ .map((meta) => {
21
+ const exportName = `${modelName}${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`
22
+ return `
21
23
  export async function ${exportName}(
22
24
  request: FastifyRequest,
23
25
  _reply: FastifyReply,
@@ -25,11 +27,13 @@ export async function ${exportName}(
25
27
  const data = await core.${meta.coreName}(buildContext(request))
26
28
  ;(request as FastifyExtended).resultData = data
27
29
  }`
28
- }).join('\n')
30
+ })
31
+ .join('\n')
29
32
 
30
- const writeHandlers = writeOps.map((meta) => {
31
- const exportName = `${modelName}${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`
32
- return `
33
+ const writeHandlers = writeOps
34
+ .map((meta) => {
35
+ const exportName = `${modelName}${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`
36
+ return `
33
37
  export async function ${exportName}(
34
38
  request: FastifyRequest,
35
39
  _reply: FastifyReply,
@@ -39,7 +43,8 @@ export async function ${exportName}(
39
43
  ext.resultData = data
40
44
  ext.resultStatus = ${meta.successStatus}
41
45
  }`
42
- }).join('\n')
46
+ })
47
+ .join('\n')
43
48
 
44
49
  const updateEachExportName = `${modelName}UpdateEach`
45
50
  const updateEachHandler = `
@@ -54,7 +59,7 @@ export async function ${updateEachExportName}(
54
59
 
55
60
  return `import type { FastifyRequest, FastifyReply } from 'fastify'
56
61
  import * as core from './${modelName}Core${ext}'
57
- import type { OperationContext, FindManyPaginatedMode } from '../operationRuntime${ext}'
62
+ import type { RuntimeOperationOverride, OperationContext, FindManyPaginatedMode } from '../operationRuntime${ext}'
58
63
 
59
64
  type FastifyExtended = FastifyRequest & {
60
65
  prisma?: unknown
@@ -64,6 +69,9 @@ type FastifyExtended = FastifyRequest & {
64
69
  routeConfig?: { pagination?: OperationContext['paginationConfig'] }
65
70
  guardShape?: Record<string, unknown>
66
71
  guardCaller?: string
72
+ guardVariantKey?: string
73
+ operationOverride?: RuntimeOperationOverride
74
+ resolveOperationContext?: () => unknown | Promise<unknown>
67
75
  findManyPaginatedMode?: FindManyPaginatedMode
68
76
  resultData?: unknown
69
77
  resultStatus?: number
@@ -72,6 +80,8 @@ type FastifyExtended = FastifyRequest & {
72
80
  function buildContext(request: FastifyRequest): OperationContext {
73
81
  const req = request as FastifyExtended
74
82
  return {
83
+ operationOverride: req.operationOverride,
84
+ resolveOperationContext: req.resolveOperationContext,
75
85
  prisma: req.prisma,
76
86
  postgres: req.postgres,
77
87
  sqlite: req.sqlite,
@@ -79,6 +89,7 @@ function buildContext(request: FastifyRequest): OperationContext {
79
89
  body: request.body,
80
90
  guardShape: req.guardShape,
81
91
  guardCaller: req.guardCaller,
92
+ guardVariantKey: req.guardVariantKey,
82
93
  paginationConfig: req.routeConfig?.pagination,
83
94
  findManyPaginatedMode: req.findManyPaginatedMode,
84
95
  }
@@ -87,4 +98,4 @@ ${readHandlers}
87
98
  ${writeHandlers}
88
99
  ${updateEachHandler}
89
100
  `
90
- }
101
+ }
@@ -1,5 +1,5 @@
1
- import { DMMF } from '@prisma/generator-helper'
2
- import { ImportStyle } from '../utils/resolveImportStyle'
1
+ import type { DMMF } from '@prisma/generator-helper'
2
+ import type { ImportStyle } from '../utils/resolveImportStyle'
3
3
  import { importExt } from '../utils/importExt'
4
4
  import { OPERATION_METADATA } from '../copy/operationDefinitions'
5
5
 
@@ -12,27 +12,32 @@ export function generateHonoHandler(options: {
12
12
 
13
13
  const readOps = OPERATION_METADATA.filter((m) => m.kind === 'read')
14
14
  const writeOps = OPERATION_METADATA.filter(
15
- (m) => (m.kind === 'write' || m.kind === 'batch') && m.name !== 'updateEach',
15
+ (m) =>
16
+ (m.kind === 'write' || m.kind === 'batch') && m.name !== 'updateEach',
16
17
  )
17
18
 
18
- const readHandlers = readOps.map((meta) => {
19
- const exportName = `${modelName}${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`
20
- return `
19
+ const readHandlers = readOps
20
+ .map((meta) => {
21
+ const exportName = `${modelName}${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`
22
+ return `
21
23
  export async function ${exportName}(c: HandlerContext): Promise<void> {
22
24
  const data = await core.${meta.coreName}(buildContext(c))
23
25
  c.set('resultData', data)
24
26
  }`
25
- }).join('\n')
27
+ })
28
+ .join('\n')
26
29
 
27
- const writeHandlers = writeOps.map((meta) => {
28
- const exportName = `${modelName}${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`
29
- return `
30
+ const writeHandlers = writeOps
31
+ .map((meta) => {
32
+ const exportName = `${modelName}${meta.name.charAt(0).toUpperCase() + meta.name.slice(1)}`
33
+ return `
30
34
  export async function ${exportName}(c: HandlerContext): Promise<void> {
31
35
  const data = await core.${meta.coreName}(buildContext(c))
32
36
  c.set('resultData', data)
33
37
  c.set('resultStatus', ${meta.successStatus})
34
38
  }`
35
- }).join('\n')
39
+ })
40
+ .join('\n')
36
41
 
37
42
  const updateEachExportName = `${modelName}UpdateEach`
38
43
  const updateEachHandler = `
@@ -44,13 +49,15 @@ export async function ${updateEachExportName}(c: HandlerContext): Promise<void>
44
49
 
45
50
  return `import type { Context } from 'hono'
46
51
  import * as core from './${modelName}Core${ext}'
47
- import type { OperationContext } from '../operationRuntime${ext}'
52
+ import type { RuntimeOperationOverride, OperationContext } from '../operationRuntime${ext}'
48
53
  import type { HonoInternalVariables } from '../routeConfig.target${ext}'
49
54
 
50
55
  type HandlerContext = Context<{ Variables: HonoInternalVariables }>
51
56
 
52
57
  function buildContext(c: HandlerContext): OperationContext {
53
58
  return {
59
+ operationOverride: c.get('operationOverride'),
60
+ resolveOperationContext: c.get('resolveOperationContext'),
54
61
  prisma: c.get('prisma'),
55
62
  postgres: c.get('postgres'),
56
63
  sqlite: c.get('sqlite'),
@@ -58,6 +65,7 @@ function buildContext(c: HandlerContext): OperationContext {
58
65
  body: c.get('body'),
59
66
  guardShape: c.get('guardShape'),
60
67
  guardCaller: c.get('guardCaller'),
68
+ guardVariantKey: c.get('guardVariantKey'),
61
69
  paginationConfig: c.get('routeConfig')?.pagination,
62
70
  }
63
71
  }
@@ -65,4 +73,4 @@ ${readHandlers}
65
73
  ${writeHandlers}
66
74
  ${updateEachHandler}
67
75
  `
68
- }
76
+ }
@@ -1,81 +1,93 @@
1
- import { GeneratorOptions } from '@prisma/generator-helper'
2
- import * as fs from 'fs'
3
- import path from 'path'
4
-
5
- function findClientGenerator(options: GeneratorOptions) {
6
- const byName = options.otherGenerators.find((gen) => gen.name === 'client')
7
- if (byName) return byName
8
-
9
- const byProvider = options.otherGenerators.find(
10
- (gen) =>
11
- gen.provider.value === 'prisma-client-js' ||
12
- gen.provider.value === '@prisma/client' ||
13
- gen.provider.value === 'prisma-client',
14
- )
15
- return byProvider || null
16
- }
17
-
18
- function getRelativeImportPath(fromDir: string, clientOutputPath: string): string {
19
- let relativeImportPath = path.relative(fromDir, clientOutputPath)
20
- relativeImportPath = relativeImportPath.split(path.sep).join(path.posix.sep)
21
- if (!relativeImportPath.startsWith('.')) {
22
- relativeImportPath = './' + relativeImportPath
23
- }
24
- return relativeImportPath
25
- }
26
-
27
- export function getRelativeClientPath(
28
- generatorOptions: GeneratorOptions,
29
- modelName: string,
30
- ): string {
31
- const clientGenerator = findClientGenerator(generatorOptions)
32
-
33
- if (!clientGenerator || !clientGenerator.output?.value) {
34
- throw new Error(
35
- 'Prisma client generator not found. Ensure a generator block exists with name "client" or provider one of: prisma-client-js, @prisma/client, prisma-client.',
36
- )
37
- }
38
-
39
- const outputValue = generatorOptions.generator.output?.value
40
- if (!outputValue) {
41
- throw new Error('Generator output path not defined.')
42
- }
43
-
44
- const routerDirPath = path.join(outputValue, modelName)
45
-
46
- return getRelativeImportPath(routerDirPath, clientGenerator.output.value)
47
- }
48
-
49
- function findGuardGenerator(options: GeneratorOptions) {
50
- const byProvider = options.otherGenerators.find(
51
- (gen) =>
52
- !!gen.provider?.value && gen.provider.value.includes('prisma-guard'),
53
- )
54
- if (byProvider) return byProvider
55
-
56
- const byConfig = options.otherGenerators.find(
57
- (gen) =>
58
- !!gen.config &&
59
- ('typedGuardShapes' in gen.config ||
60
- 'onInvalidZod' in gen.config ||
61
- 'findUniqueMode' in gen.config),
62
- )
63
- return byConfig || null
64
- }
65
-
66
- export function getGuardShapesImport(
67
- options: GeneratorOptions,
68
- modelName: string,
69
- ): string | null {
70
- const guard = findGuardGenerator(options)
71
- if (!guard || !guard.output?.value) return null
72
-
73
- if (guard.config?.typedGuardShapes === 'false') return null
74
-
75
- const outputValue = options.generator.output?.value
76
- if (!outputValue) return null
77
-
78
- const fromDir = path.join(outputValue, modelName)
79
- const shapesPath = path.join(guard.output.value, 'shapes')
80
- return getRelativeImportPath(fromDir, shapesPath)
81
- }
1
+ import { GeneratorOptions } from '@prisma/generator-helper'
2
+ import * as fs from 'fs'
3
+ import path from 'path'
4
+
5
+ function findClientGenerator(options: GeneratorOptions) {
6
+ const byName = options.otherGenerators.find((gen) => gen.name === 'client')
7
+ if (byName) return byName
8
+
9
+ const byProvider = options.otherGenerators.find(
10
+ (gen) =>
11
+ gen.provider.value === 'prisma-client-js' ||
12
+ gen.provider.value === '@prisma/client' ||
13
+ gen.provider.value === 'prisma-client',
14
+ )
15
+ return byProvider || null
16
+ }
17
+
18
+ function getRelativeImportPath(
19
+ fromDir: string,
20
+ clientOutputPath: string,
21
+ ): string {
22
+ let relativeImportPath = path.relative(fromDir, clientOutputPath)
23
+ relativeImportPath = relativeImportPath.split(path.sep).join(path.posix.sep)
24
+ if (!relativeImportPath.startsWith('.')) {
25
+ relativeImportPath = './' + relativeImportPath
26
+ }
27
+ return relativeImportPath
28
+ }
29
+
30
+ export function getRelativeClientPath(
31
+ generatorOptions: GeneratorOptions,
32
+ modelName: string,
33
+ ): string {
34
+ const clientGenerator = findClientGenerator(generatorOptions)
35
+
36
+ if (!clientGenerator || !clientGenerator.output?.value) {
37
+ throw new Error(
38
+ 'Prisma client generator not found. Ensure a generator block exists with name "client" or provider one of: prisma-client-js, @prisma/client, prisma-client.',
39
+ )
40
+ }
41
+
42
+ const outputValue = generatorOptions.generator.output?.value
43
+ if (!outputValue) {
44
+ throw new Error('Generator output path not defined.')
45
+ }
46
+
47
+ const routerDirPath = path.join(outputValue, modelName)
48
+
49
+ return getRelativeImportPath(routerDirPath, clientGenerator.output.value)
50
+ }
51
+
52
+ function findGuardGenerator(options: GeneratorOptions) {
53
+ const byProvider = options.otherGenerators.find(
54
+ (gen) =>
55
+ !!gen.provider?.value && gen.provider.value.includes('prisma-guard'),
56
+ )
57
+ if (byProvider) return byProvider
58
+
59
+ const byConfig = options.otherGenerators.find(
60
+ (gen) =>
61
+ !!gen.config &&
62
+ ('typedGuardShapes' in gen.config ||
63
+ 'onInvalidZod' in gen.config ||
64
+ 'findUniqueMode' in gen.config),
65
+ )
66
+ return byConfig || null
67
+ }
68
+
69
+ export function getGuardShapesImport(
70
+ options: GeneratorOptions,
71
+ modelName: string,
72
+ ): string | null {
73
+ const guard = findGuardGenerator(options)
74
+ if (!guard || !guard.output?.value) return null
75
+
76
+ if (guard.config?.typedGuardShapes === 'false') return null
77
+
78
+ const outputValue = options.generator.output?.value
79
+ if (!outputValue) return null
80
+
81
+ const fromDir = path.join(outputValue, modelName)
82
+ const shapesPath = path.join(guard.output.value, 'shapes')
83
+ return getRelativeImportPath(fromDir, shapesPath)
84
+ }
85
+
86
+ export function getRelativeClientTypeImport(
87
+ options: GeneratorOptions,
88
+ modelName: string,
89
+ ): string {
90
+ const client = findClientGenerator(options)
91
+ const entry = client?.provider.value === 'prisma-client' ? 'client' : 'index'
92
+ return getRelativeClientPath(options, modelName) + '/' + entry
93
+ }
@@ -4,16 +4,26 @@ import { importExt } from '../utils/importExt'
4
4
 
5
5
  function exampleValueForType(fieldType: string): unknown {
6
6
  switch (fieldType) {
7
- case 'String': return 'example'
8
- case 'Int': return 1
9
- case 'BigInt': return '1'
10
- case 'Float': return 1.0
11
- case 'Decimal': return '1.0'
12
- case 'Boolean': return true
13
- case 'DateTime': return '2025-01-01T00:00:00.000Z'
14
- case 'Json': return {}
15
- case 'Bytes': return 'base64data'
16
- default: return 'example'
7
+ case 'String':
8
+ return 'example'
9
+ case 'Int':
10
+ return 1
11
+ case 'BigInt':
12
+ return '1'
13
+ case 'Float':
14
+ return 1.0
15
+ case 'Decimal':
16
+ return '1.0'
17
+ case 'Boolean':
18
+ return true
19
+ case 'DateTime':
20
+ return '2025-01-01T00:00:00.000Z'
21
+ case 'Json':
22
+ return {}
23
+ case 'Bytes':
24
+ return 'base64data'
25
+ default:
26
+ return 'example'
17
27
  }
18
28
  }
19
29
 
@@ -23,7 +33,9 @@ export interface GenerateModelMetadataOptions {
23
33
  importStyle: ImportStyle
24
34
  }
25
35
 
26
- export function generateModelMetadata(options: GenerateModelMetadataOptions): string {
36
+ export function generateModelMetadata(
37
+ options: GenerateModelMetadataOptions,
38
+ ): string {
27
39
  const ext = importExt(options.importStyle)
28
40
  const { model, enums } = options
29
41
  const modelName = model.name
@@ -89,4 +101,4 @@ export const COMPOUND_UNIQUES: { name: string; fields: string[] }[] = ${JSON.str
89
101
 
90
102
  export const EXAMPLE_VALUES: Record<string, unknown> = ${JSON.stringify(exampleValues, null, 2)}
91
103
  `
92
- }
104
+ }
@@ -1,7 +1,8 @@
1
- import { DMMF } from '@prisma/generator-helper'
2
- import { ImportStyle } from '../utils/resolveImportStyle'
1
+ import { OPERATION_METADATA } from '../copy/operationDefinitions'
2
+ import type { DMMF } from '@prisma/generator-helper'
3
+ import type { ImportStyle } from '../utils/resolveImportStyle'
3
4
  import { importExt } from '../utils/importExt'
4
- import { WriteStrategy, FindManyPaginatedMode } from '../constants'
5
+ import type { WriteStrategy, FindManyPaginatedMode } from '../constants'
5
6
 
6
7
  export interface ModelCoreOptions {
7
8
  model: DMMF.Model
@@ -17,7 +18,10 @@ function decideWriteOp(
17
18
  defaultMethod: string,
18
19
  strategy: WriteStrategy,
19
20
  ): WriteOpDecision {
20
- if (strategy === 'throwOnNonReturning' && (name === 'createMany' || name === 'updateMany')) {
21
+ if (
22
+ strategy === 'throwOnNonReturning' &&
23
+ (name === 'createMany' || name === 'updateMany')
24
+ ) {
21
25
  return { throw: true, method: defaultMethod }
22
26
  }
23
27
  if (strategy === 'forceReturn') {
@@ -27,7 +31,10 @@ function decideWriteOp(
27
31
  return { method: defaultMethod }
28
32
  }
29
33
 
30
- function renderPaginatedBody(modelNameLower: string, mode: FindManyPaginatedMode): string {
34
+ function renderPaginatedBody(
35
+ modelNameLower: string,
36
+ mode: FindManyPaginatedMode,
37
+ ): string {
31
38
  if (mode === 'transaction') {
32
39
  return `
33
40
  const txClient = extended as { $transaction?: <T>(fn: (tx: unknown) => Promise<T>) => Promise<T> }
@@ -69,16 +76,25 @@ export function generateModelCore(options: ModelCoreOptions): string {
69
76
  const modelName = options.model.name
70
77
  const modelNameLower = modelName.charAt(0).toLowerCase() + modelName.slice(1)
71
78
  const writeStrategy = options.writeStrategy
72
- const paginatedBody = renderPaginatedBody(modelNameLower, options.findManyPaginatedMode)
79
+ const paginatedBody = renderPaginatedBody(
80
+ modelNameLower,
81
+ options.findManyPaginatedMode,
82
+ )
73
83
 
74
84
  const standardReadOps = [
75
- 'findFirst', 'findUnique', 'findUniqueOrThrow', 'findFirstOrThrow',
76
- 'count', 'aggregate', 'groupBy',
85
+ 'findFirst',
86
+ 'findUnique',
87
+ 'findUniqueOrThrow',
88
+ 'findFirstOrThrow',
89
+ 'count',
90
+ 'aggregate',
91
+ 'groupBy',
77
92
  ]
78
93
 
79
94
  const standardReadHandlers = standardReadOps
80
- .map((op) => `
81
- export async function ${op}(ctx: OperationContext): Promise<unknown> {
95
+ .map(
96
+ (op) => `
97
+ async function default_${op}(ctx: OperationContext): Promise<unknown> {
82
98
  const query = ctx.parsedQuery || {}
83
99
  const extended = await getExtendedClient(ctx)
84
100
  const delegate = getDelegate(extended, '${modelNameLower}')
@@ -87,38 +103,56 @@ export async function ${op}(ctx: OperationContext): Promise<unknown> {
87
103
  return delegate.guard(ctx.guardShape, ctx.guardCaller).${op}(query)
88
104
  }
89
105
  return delegate.${op}(query)
90
- }`)
106
+ }`,
107
+ )
91
108
  .join('\n')
92
109
 
93
110
  const writeOps = [
94
111
  { name: 'create', method: 'create', requiredFields: ['data'] },
95
112
  { name: 'createMany', method: 'createMany', requiredFields: ['data'] },
96
- { name: 'createManyAndReturn', method: 'createManyAndReturn', requiredFields: ['data'] },
113
+ {
114
+ name: 'createManyAndReturn',
115
+ method: 'createManyAndReturn',
116
+ requiredFields: ['data'],
117
+ },
97
118
  { name: 'update', method: 'update', requiredFields: ['where', 'data'] },
98
- { name: 'updateMany', method: 'updateMany', requiredFields: ['where', 'data'] },
99
- { name: 'updateManyAndReturn', method: 'updateManyAndReturn', requiredFields: ['where', 'data'] },
119
+ {
120
+ name: 'updateMany',
121
+ method: 'updateMany',
122
+ requiredFields: ['where', 'data'],
123
+ },
124
+ {
125
+ name: 'updateManyAndReturn',
126
+ method: 'updateManyAndReturn',
127
+ requiredFields: ['where', 'data'],
128
+ },
100
129
  { name: 'deleteUnique', method: 'delete', requiredFields: ['where'] },
101
130
  { name: 'deleteMany', method: 'deleteMany', requiredFields: ['where'] },
102
- { name: 'upsert', method: 'upsert', requiredFields: ['where', 'create', 'update'] },
131
+ {
132
+ name: 'upsert',
133
+ method: 'upsert',
134
+ requiredFields: ['where', 'create', 'update'],
135
+ },
103
136
  ]
104
137
 
105
- const writeHandlers = writeOps.map((op) => {
106
- const decision = decideWriteOp(op.name, op.method, writeStrategy)
138
+ const writeHandlers = writeOps
139
+ .map((op) => {
140
+ const decision = decideWriteOp(op.name, op.method, writeStrategy)
107
141
 
108
- if (decision.throw) {
109
- return `
110
- export async function ${op.name}(_ctx: OperationContext): Promise<unknown> {
142
+ if (decision.throw) {
143
+ return `
144
+ async function default_${op.name}(_ctx: OperationContext): Promise<unknown> {
111
145
  throw new HttpError(501, '${op.name} is disabled by writeStrategy="${writeStrategy}"')
112
146
  }`
113
- }
147
+ }
114
148
 
115
- const method = decision.method
116
- const validationLines = op.requiredFields
117
- .map((field) => ` requireBodyField(body, '${field}')`)
118
- .join('\n')
149
+ const method = decision.method
150
+ const validationLines = op.requiredFields
151
+ .map((field) => ` requireBodyField(body, '${field}')`)
152
+ .join('\n')
119
153
 
120
- return `
121
- export async function ${op.name}(ctx: OperationContext): Promise<unknown> {
154
+ return `
155
+ async function default_${op.name}(ctx: OperationContext): Promise<unknown> {
122
156
  const body = validateBody(ctx.body)
123
157
  ${validationLines}
124
158
  const extended = await getExtendedClient(ctx)
@@ -129,11 +163,24 @@ ${validationLines}
129
163
  }
130
164
  return delegate.${method}(body)
131
165
  }`
132
- }).join('\n')
166
+ })
167
+ .join('\n')
168
+
169
+ const wrappers = OPERATION_METADATA.filter((op) => op.name !== 'updateEach')
170
+ .map(
171
+ (op) => `
172
+ export async function ${op.coreName}(ctx: OperationContext): Promise<${op.name === 'findManyPaginated' ? '{ data: unknown[]; total: number; hasMore: boolean }' : 'unknown'}> {
173
+ const input = ${op.kind === 'read' ? 'ctx.parsedQuery || {}' : 'validateBody(ctx.body)'}
174
+ ${op.requiredBodyFields.map((field) => ` requireBodyField(input, '${field}')`).join('\n')}
175
+ return executeOperationOverride(ctx, '${modelNameLower}', '${op.name}', input, () => default_${op.coreName}(ctx))
176
+ }`,
177
+ )
178
+ .join('\n')
133
179
 
134
180
  return `import {
135
- OperationContext,
136
- PrismaClientLike,
181
+ type OperationContext,
182
+ executeOperationOverride,
183
+ type PrismaClientLike,
137
184
  getExtendedClient,
138
185
  getDelegate,
139
186
  validateBody,
@@ -144,7 +191,7 @@ import { applyPaginationLimits, countForPagination } from '../pagination${ext}'
144
191
  import { assertGuard } from '../guardHelpers${ext}'
145
192
  import { mapLimited } from '../concurrency${ext}'
146
193
 
147
- export async function findMany(ctx: OperationContext): Promise<unknown> {
194
+ async function default_findMany(ctx: OperationContext): Promise<unknown> {
148
195
  const rawQuery = ctx.parsedQuery || {}
149
196
  const query = applyPaginationLimits(rawQuery, ctx.paginationConfig, !!ctx.guardShape)
150
197
  const extended = await getExtendedClient(ctx)
@@ -155,10 +202,11 @@ export async function findMany(ctx: OperationContext): Promise<unknown> {
155
202
  }
156
203
  return delegate.findMany(query)
157
204
  }
205
+ ${wrappers}
158
206
  ${standardReadHandlers}
159
207
  ${writeHandlers}
160
208
 
161
- export async function findManyPaginated(
209
+ async function default_findManyPaginated(
162
210
  ctx: OperationContext,
163
211
  ): Promise<{ data: unknown[]; total: number; hasMore: boolean }> {
164
212
  const rawQuery = ctx.parsedQuery || {}
@@ -252,4 +300,4 @@ export async function updateEach(
252
300
  return results
253
301
  }
254
302
  `
255
- }
303
+ }
@@ -32,13 +32,15 @@ function findOppositeField(
32
32
  const target = models.find((m) => m.name === targetModelName)
33
33
  if (!target) return null
34
34
  const isSelfRelation = targetModelName === selfModelName
35
- return target.fields.find(
36
- (f) =>
37
- f.kind === 'object' &&
38
- f.relationName === relationName &&
39
- f.type === selfModelName &&
40
- !(isSelfRelation && f.name === selfFieldName),
41
- ) || null
35
+ return (
36
+ target.fields.find(
37
+ (f) =>
38
+ f.kind === 'object' &&
39
+ f.relationName === relationName &&
40
+ f.type === selfModelName &&
41
+ !(isSelfRelation && f.name === selfFieldName),
42
+ ) || null
43
+ )
42
44
  }
43
45
 
44
46
  function computeRelation(
@@ -61,7 +63,13 @@ function computeRelation(
61
63
  }
62
64
  }
63
65
 
64
- const opposite = findOppositeField(models, field.type, field.relationName, selfModelName, field.name)
66
+ const opposite = findOppositeField(
67
+ models,
68
+ field.type,
69
+ field.relationName,
70
+ selfModelName,
71
+ field.name,
72
+ )
65
73
  if (opposite) {
66
74
  const oppFrom = (opposite.relationFromFields ?? []) as string[]
67
75
  const oppTo = (opposite.relationToFields ?? []) as string[]
@@ -118,7 +126,9 @@ export interface GenerateRelationMetaOptions {
118
126
  importStyle: ImportStyle
119
127
  }
120
128
 
121
- export function generateRelationMeta(options: GenerateRelationMetaOptions): string {
129
+ export function generateRelationMeta(
130
+ options: GenerateRelationMetaOptions,
131
+ ): string {
122
132
  const ext = importExt(options.importStyle)
123
133
  const meta = buildModelMeta(options.model, options.allModels)
124
134
  return `import type { ModelRelationMap } from '../autoIncludePlanner${ext}'
@@ -132,7 +142,9 @@ export interface GenerateRelationModelsIndexOptions {
132
142
  importStyle: ImportStyle
133
143
  }
134
144
 
135
- export function generateRelationModelsIndex(options: GenerateRelationModelsIndexOptions): string {
145
+ export function generateRelationModelsIndex(
146
+ options: GenerateRelationModelsIndexOptions,
147
+ ): string {
136
148
  const ext = importExt(options.importStyle)
137
149
  const imports = options.modelNames
138
150
  .map((n) => `import { ${n}Relations } from './${n}/${n}Relations${ext}'`)
@@ -147,4 +159,4 @@ export const relationModels: Record<string, ModelRelationMap> = {
147
159
  ${entries}
148
160
  }
149
161
  `
150
- }
162
+ }