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.
- package/README.md +51 -3480
- package/dist/client/encodeQueryParams.js +3 -1
- package/dist/client/encodeQueryParams.js.map +1 -1
- package/dist/copy/misc.d.ts +1 -0
- package/dist/copy/misc.js +14 -0
- package/dist/copy/misc.js.map +1 -1
- package/dist/copy/operationDefinitions.js +69 -6
- package/dist/copy/operationDefinitions.js.map +1 -1
- package/dist/generators/generateFastifyHandler.d.ts +2 -2
- package/dist/generators/generateFastifyHandler.js +15 -5
- package/dist/generators/generateFastifyHandler.js.map +1 -1
- package/dist/generators/generateHonoHandler.d.ts +2 -2
- package/dist/generators/generateHonoHandler.js +12 -5
- package/dist/generators/generateHonoHandler.js.map +1 -1
- package/dist/generators/generateImportPrismaStatement.d.ts +1 -0
- package/dist/generators/generateImportPrismaStatement.js +6 -0
- package/dist/generators/generateImportPrismaStatement.js.map +1 -1
- package/dist/generators/generateModelMetadata.js +20 -10
- package/dist/generators/generateModelMetadata.js.map +1 -1
- package/dist/generators/generateOperationCore.d.ts +3 -3
- package/dist/generators/generateOperationCore.js +51 -16
- package/dist/generators/generateOperationCore.js.map +1 -1
- package/dist/generators/generateQueryBuilderHelper.d.ts +1 -1
- package/dist/generators/generateQueryBuilderHelper.js +2 -4
- package/dist/generators/generateQueryBuilderHelper.js.map +1 -1
- package/dist/generators/generateRelationMeta.js +2 -2
- package/dist/generators/generateRelationMeta.js.map +1 -1
- package/dist/generators/generateRouteConfigType.d.ts +2 -2
- package/dist/generators/generateRouteConfigType.js +29 -11
- package/dist/generators/generateRouteConfigType.js.map +1 -1
- package/dist/generators/generateRouter.d.ts +7 -4
- package/dist/generators/generateRouter.js +107 -14
- package/dist/generators/generateRouter.js.map +1 -1
- package/dist/generators/generateRouterFastify.d.ts +7 -4
- package/dist/generators/generateRouterFastify.js +56 -28
- package/dist/generators/generateRouterFastify.js.map +1 -1
- package/dist/generators/generateRouterHono.d.ts +7 -4
- package/dist/generators/generateRouterHono.js +84 -53
- package/dist/generators/generateRouterHono.js.map +1 -1
- package/dist/generators/generateUnifiedDocs.d.ts +1 -1
- package/dist/generators/generateUnifiedDocs.js +15 -8
- package/dist/generators/generateUnifiedDocs.js.map +1 -1
- package/dist/generators/generateUnifiedHandler.d.ts +2 -2
- package/dist/generators/generateUnifiedHandler.js +11 -3
- package/dist/generators/generateUnifiedHandler.js.map +1 -1
- package/dist/guardOptions.js +12 -7
- package/dist/guardOptions.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +22 -1
- package/dist/index.js.map +1 -1
- package/dist/utils/copyFiles.js +22 -6
- package/dist/utils/copyFiles.js.map +1 -1
- package/dist/utils/importExt.d.ts +1 -1
- package/dist/utils/pathCasing.d.ts +4 -0
- package/dist/utils/pathCasing.js +40 -0
- package/dist/utils/pathCasing.js.map +1 -0
- package/dist/utils/resolveImportStyle.js +13 -5
- package/dist/utils/resolveImportStyle.js.map +1 -1
- package/dist/utils/writeFileSafely.js.map +1 -1
- package/package.json +16 -3
- package/src/bin.ts +1 -1
- package/src/client/encodeQueryParams.ts +39 -35
- package/src/constants.ts +1 -1
- package/src/copy/autoIncludePlanner.ts +93 -27
- package/src/copy/autoIncludePlannerGuarded.ts +171 -48
- package/src/copy/autoIncludeRuntimeGuarded.ts +25 -7
- package/src/copy/buildModelOpenApi.ts +153 -50
- package/src/copy/concurrency.ts +10 -8
- package/src/copy/errorMapper.ts +68 -19
- package/src/copy/guardHelpers.ts +30 -9
- package/src/copy/materializedCount.ts +17 -5
- package/src/copy/misc.ts +88 -68
- package/src/copy/ndjson.ts +72 -0
- package/src/copy/operationDefinitions.ts +99 -21
- package/src/copy/operationRuntime.ts +100 -12
- package/src/copy/pagination.ts +25 -11
- package/src/copy/parseQueryParams.ts +47 -48
- package/src/copy/projectionDefaults.ts +6 -4
- package/src/copy/routeConfig.express.ts +16 -4
- package/src/copy/routeConfig.fastify.ts +16 -2
- package/src/copy/routeConfig.hono.ts +19 -9
- package/src/copy/routeConfig.ts +174 -39
- package/src/copy/scalarTypes.ts +7 -2
- package/src/copy/sse.ts +72 -19
- package/src/generators/generateFastifyHandler.ts +24 -13
- package/src/generators/generateHonoHandler.ts +21 -13
- package/src/generators/generateImportPrismaStatement.ts +93 -81
- package/src/generators/generateModelMetadata.ts +24 -12
- package/src/generators/generateOperationCore.ts +81 -33
- package/src/generators/generateQueryBuilderHelper.ts +20 -4
- package/src/generators/generateRelationMeta.ts +23 -11
- package/src/generators/generateRouteConfigType.ts +39 -13
- package/src/generators/generateRouter.ts +114 -17
- package/src/generators/generateRouterFastify.ts +67 -31
- package/src/generators/generateRouterHono.ts +108 -60
- package/src/generators/generateUnifiedDocs.ts +29 -8
- package/src/generators/generateUnifiedHandler.ts +16 -8
- package/src/generators/generateUnifiedScalarUI.ts +1 -1
- package/src/guardOptions.ts +105 -92
- package/src/index.ts +46 -4
- package/src/utils/copyFiles.ts +199 -168
- package/src/utils/importExt.ts +2 -2
- package/src/utils/pathCasing.ts +42 -0
- package/src/utils/resolveImportStyle.ts +37 -15
- package/src/utils/strings.ts +2 -2
- 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) =>
|
|
15
|
+
(m) =>
|
|
16
|
+
(m.kind === 'write' || m.kind === 'batch') && m.name !== 'updateEach',
|
|
16
17
|
)
|
|
17
18
|
|
|
18
|
-
const readHandlers = readOps
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
30
|
+
})
|
|
31
|
+
.join('\n')
|
|
29
32
|
|
|
30
|
-
const writeHandlers = writeOps
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
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) =>
|
|
15
|
+
(m) =>
|
|
16
|
+
(m.kind === 'write' || m.kind === 'batch') && m.name !== 'updateEach',
|
|
16
17
|
)
|
|
17
18
|
|
|
18
|
-
const readHandlers = readOps
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
27
|
+
})
|
|
28
|
+
.join('\n')
|
|
26
29
|
|
|
27
|
-
const writeHandlers = writeOps
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
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':
|
|
8
|
-
|
|
9
|
-
case '
|
|
10
|
-
|
|
11
|
-
case '
|
|
12
|
-
|
|
13
|
-
case '
|
|
14
|
-
|
|
15
|
-
case '
|
|
16
|
-
|
|
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(
|
|
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 {
|
|
2
|
-
import {
|
|
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 (
|
|
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(
|
|
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(
|
|
79
|
+
const paginatedBody = renderPaginatedBody(
|
|
80
|
+
modelNameLower,
|
|
81
|
+
options.findManyPaginatedMode,
|
|
82
|
+
)
|
|
73
83
|
|
|
74
84
|
const standardReadOps = [
|
|
75
|
-
'findFirst',
|
|
76
|
-
'
|
|
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(
|
|
81
|
-
|
|
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
|
-
{
|
|
113
|
+
{
|
|
114
|
+
name: 'createManyAndReturn',
|
|
115
|
+
method: 'createManyAndReturn',
|
|
116
|
+
requiredFields: ['data'],
|
|
117
|
+
},
|
|
97
118
|
{ name: 'update', method: 'update', requiredFields: ['where', 'data'] },
|
|
98
|
-
{
|
|
99
|
-
|
|
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
|
-
{
|
|
131
|
+
{
|
|
132
|
+
name: 'upsert',
|
|
133
|
+
method: 'upsert',
|
|
134
|
+
requiredFields: ['where', 'create', 'update'],
|
|
135
|
+
},
|
|
103
136
|
]
|
|
104
137
|
|
|
105
|
-
const writeHandlers = writeOps
|
|
106
|
-
|
|
138
|
+
const writeHandlers = writeOps
|
|
139
|
+
.map((op) => {
|
|
140
|
+
const decision = decideWriteOp(op.name, op.method, writeStrategy)
|
|
107
141
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
149
|
+
const method = decision.method
|
|
150
|
+
const validationLines = op.requiredFields
|
|
151
|
+
.map((field) => ` requireBodyField(body, '${field}')`)
|
|
152
|
+
.join('\n')
|
|
119
153
|
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
22
|
+
_options?: Partial<Pick<GeneratorOptions, 'schemaPath'>>,
|
|
5
23
|
): string {
|
|
6
|
-
const 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'
|