prisma-generator-express 1.65.2 → 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 (106) hide show
  1. package/README.md +51 -3480
  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/generateQueryBuilderHelper.d.ts +1 -1
  24. package/dist/generators/generateQueryBuilderHelper.js +2 -4
  25. package/dist/generators/generateQueryBuilderHelper.js.map +1 -1
  26. package/dist/generators/generateRelationMeta.js +2 -2
  27. package/dist/generators/generateRelationMeta.js.map +1 -1
  28. package/dist/generators/generateRouteConfigType.d.ts +2 -2
  29. package/dist/generators/generateRouteConfigType.js +29 -11
  30. package/dist/generators/generateRouteConfigType.js.map +1 -1
  31. package/dist/generators/generateRouter.d.ts +7 -4
  32. package/dist/generators/generateRouter.js +107 -14
  33. package/dist/generators/generateRouter.js.map +1 -1
  34. package/dist/generators/generateRouterFastify.d.ts +7 -4
  35. package/dist/generators/generateRouterFastify.js +56 -28
  36. package/dist/generators/generateRouterFastify.js.map +1 -1
  37. package/dist/generators/generateRouterHono.d.ts +7 -4
  38. package/dist/generators/generateRouterHono.js +84 -53
  39. package/dist/generators/generateRouterHono.js.map +1 -1
  40. package/dist/generators/generateUnifiedDocs.d.ts +1 -1
  41. package/dist/generators/generateUnifiedDocs.js +15 -8
  42. package/dist/generators/generateUnifiedDocs.js.map +1 -1
  43. package/dist/generators/generateUnifiedHandler.d.ts +2 -2
  44. package/dist/generators/generateUnifiedHandler.js +11 -3
  45. package/dist/generators/generateUnifiedHandler.js.map +1 -1
  46. package/dist/guardOptions.js +12 -7
  47. package/dist/guardOptions.js.map +1 -1
  48. package/dist/index.d.ts +1 -1
  49. package/dist/index.js +22 -1
  50. package/dist/index.js.map +1 -1
  51. package/dist/utils/copyFiles.js +22 -6
  52. package/dist/utils/copyFiles.js.map +1 -1
  53. package/dist/utils/importExt.d.ts +1 -1
  54. package/dist/utils/pathCasing.d.ts +4 -0
  55. package/dist/utils/pathCasing.js +40 -0
  56. package/dist/utils/pathCasing.js.map +1 -0
  57. package/dist/utils/resolveImportStyle.js +13 -5
  58. package/dist/utils/resolveImportStyle.js.map +1 -1
  59. package/dist/utils/writeFileSafely.js.map +1 -1
  60. package/package.json +16 -3
  61. package/src/bin.ts +1 -1
  62. package/src/client/encodeQueryParams.ts +39 -35
  63. package/src/constants.ts +1 -1
  64. package/src/copy/autoIncludePlanner.ts +93 -27
  65. package/src/copy/autoIncludePlannerGuarded.ts +171 -48
  66. package/src/copy/autoIncludeRuntimeGuarded.ts +25 -7
  67. package/src/copy/buildModelOpenApi.ts +153 -50
  68. package/src/copy/concurrency.ts +10 -8
  69. package/src/copy/errorMapper.ts +68 -19
  70. package/src/copy/guardHelpers.ts +30 -9
  71. package/src/copy/materializedCount.ts +17 -5
  72. package/src/copy/misc.ts +88 -68
  73. package/src/copy/ndjson.ts +72 -0
  74. package/src/copy/operationDefinitions.ts +99 -21
  75. package/src/copy/operationRuntime.ts +100 -12
  76. package/src/copy/pagination.ts +25 -11
  77. package/src/copy/parseQueryParams.ts +47 -48
  78. package/src/copy/projectionDefaults.ts +6 -4
  79. package/src/copy/routeConfig.express.ts +16 -4
  80. package/src/copy/routeConfig.fastify.ts +16 -2
  81. package/src/copy/routeConfig.hono.ts +19 -9
  82. package/src/copy/routeConfig.ts +174 -39
  83. package/src/copy/scalarTypes.ts +7 -2
  84. package/src/copy/sse.ts +72 -19
  85. package/src/generators/generateFastifyHandler.ts +24 -13
  86. package/src/generators/generateHonoHandler.ts +21 -13
  87. package/src/generators/generateImportPrismaStatement.ts +93 -81
  88. package/src/generators/generateModelMetadata.ts +24 -12
  89. package/src/generators/generateOperationCore.ts +81 -33
  90. package/src/generators/generateQueryBuilderHelper.ts +20 -4
  91. package/src/generators/generateRelationMeta.ts +23 -11
  92. package/src/generators/generateRouteConfigType.ts +39 -13
  93. package/src/generators/generateRouter.ts +114 -17
  94. package/src/generators/generateRouterFastify.ts +67 -31
  95. package/src/generators/generateRouterHono.ts +108 -60
  96. package/src/generators/generateUnifiedDocs.ts +29 -8
  97. package/src/generators/generateUnifiedHandler.ts +16 -8
  98. package/src/generators/generateUnifiedScalarUI.ts +1 -1
  99. package/src/guardOptions.ts +105 -92
  100. package/src/index.ts +46 -4
  101. package/src/utils/copyFiles.ts +199 -168
  102. package/src/utils/importExt.ts +2 -2
  103. package/src/utils/pathCasing.ts +42 -0
  104. package/src/utils/resolveImportStyle.ts +37 -15
  105. package/src/utils/strings.ts +2 -2
  106. 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
+ }
@@ -1,11 +1,27 @@
1
1
  import { GeneratorOptions } from '@prisma/generator-helper'
2
2
 
3
+ /**
4
+ * THE EMITTED DEFAULT IS THE CONSUMER'S OWN SCHEMA, NEVER THE GENERATOR'S.
5
+ *
6
+ * This baked `options.schemaPath` — an ABSOLUTE path on the machine that ran
7
+ * `prisma generate` — into the generated helper as its runtime default. For a
8
+ * consumer that generates and runs in the same checkout that is invisible; for
9
+ * anyone else it is a path that does not exist, and for a generated artifact
10
+ * built in a staging directory it is worse than that: the directory is renamed
11
+ * away at adoption, so the shipped fallback can never resolve on ANY machine,
12
+ * including the one that produced it.
13
+ *
14
+ * `resolve(process.cwd(), 'prisma/schema.prisma')` — Prisma's own convention,
15
+ * relative to wherever the consumer's process runs — was already written here as
16
+ * the no-schemaPath branch. It is now the only default.
17
+ *
18
+ * THE EXPLICIT OVERRIDE IS UNTOUCHED: `startQueryBuilder({ schemaPath })` still
19
+ * wins, which is how a consumer with a different layout says so.
20
+ */
3
21
  export function generateQueryBuilderHelper(
4
- options: Pick<GeneratorOptions, 'schemaPath'>,
22
+ _options?: Partial<Pick<GeneratorOptions, 'schemaPath'>>,
5
23
  ): string {
6
- const schemaPath = options.schemaPath
7
- ? JSON.stringify(options.schemaPath)
8
- : "resolve(process.cwd(), 'prisma/schema.prisma')"
24
+ const schemaPath = "resolve(process.cwd(), 'prisma/schema.prisma')"
9
25
 
10
26
  return `import { spawn } from 'child_process'
11
27
  import { resolve, join, dirname } from 'path'