prisma-generator-express 1.45.1 → 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 (69) hide show
  1. package/dist/client/encodeQueryParams.js +4 -0
  2. package/dist/client/encodeQueryParams.js.map +1 -1
  3. package/dist/copy/misc.d.ts +4 -2
  4. package/dist/copy/misc.js +35 -24
  5. package/dist/copy/misc.js.map +1 -1
  6. package/dist/generators/generateFastifyHandler.js +2 -4
  7. package/dist/generators/generateFastifyHandler.js.map +1 -1
  8. package/dist/generators/generateHonoHandler.js +2 -4
  9. package/dist/generators/generateHonoHandler.js.map +1 -1
  10. package/dist/generators/generateImportPrismaStatement.d.ts +0 -1
  11. package/dist/generators/generateImportPrismaStatement.js +2 -20
  12. package/dist/generators/generateImportPrismaStatement.js.map +1 -1
  13. package/dist/generators/generateOperationCore.js +1 -1
  14. package/dist/generators/generateQueryBuilderHelper.js +9 -0
  15. package/dist/generators/generateQueryBuilderHelper.js.map +1 -1
  16. package/dist/generators/generateRelationMeta.js +0 -10
  17. package/dist/generators/generateRelationMeta.js.map +1 -1
  18. package/dist/generators/generateRouteConfigType.js +33 -12
  19. package/dist/generators/generateRouteConfigType.js.map +1 -1
  20. package/dist/generators/generateRouter.d.ts +0 -1
  21. package/dist/generators/generateRouter.js +75 -70
  22. package/dist/generators/generateRouter.js.map +1 -1
  23. package/dist/generators/generateRouterFastify.js +83 -89
  24. package/dist/generators/generateRouterFastify.js.map +1 -1
  25. package/dist/generators/generateRouterHono.js +257 -237
  26. package/dist/generators/generateRouterHono.js.map +1 -1
  27. package/dist/generators/generateUnifiedDocs.d.ts +2 -2
  28. package/dist/generators/generateUnifiedDocs.js +90 -252
  29. package/dist/generators/generateUnifiedDocs.js.map +1 -1
  30. package/dist/generators/generateUnifiedHandler.js +2 -4
  31. package/dist/generators/generateUnifiedHandler.js.map +1 -1
  32. package/dist/index.js +16 -8
  33. package/dist/index.js.map +1 -1
  34. package/dist/utils/copyFiles.js +3 -2
  35. package/dist/utils/copyFiles.js.map +1 -1
  36. package/dist/utils/strings.d.ts +0 -1
  37. package/dist/utils/strings.js +0 -9
  38. package/dist/utils/strings.js.map +1 -1
  39. package/package.json +1 -1
  40. package/src/client/encodeQueryParams.ts +7 -15
  41. package/src/copy/autoIncludePlanner.ts +4 -17
  42. package/src/copy/autoIncludeRuntime.ts +11 -19
  43. package/src/copy/buildModelOpenApi.ts +11 -14
  44. package/src/copy/docsRenderer.ts +8 -14
  45. package/src/copy/misc.ts +28 -23
  46. package/src/copy/operationRuntime.ts +61 -43
  47. package/src/copy/parseQueryParams.ts +5 -14
  48. package/src/copy/routeConfig.express.ts +24 -18
  49. package/src/copy/routeConfig.fastify.ts +1 -1
  50. package/src/copy/routeConfig.hono.ts +34 -6
  51. package/src/copy/routeConfig.ts +2 -2
  52. package/src/generators/generateFastifyHandler.ts +2 -5
  53. package/src/generators/generateHonoHandler.ts +2 -5
  54. package/src/generators/generateImportPrismaStatement.ts +3 -35
  55. package/src/generators/generateOperationCore.ts +1 -1
  56. package/src/generators/generateQueryBuilderHelper.ts +9 -0
  57. package/src/generators/generateRelationMeta.ts +0 -10
  58. package/src/generators/generateRouteConfigType.ts +34 -10
  59. package/src/generators/generateRouter.ts +75 -71
  60. package/src/generators/generateRouterFastify.ts +83 -89
  61. package/src/generators/generateRouterHono.ts +257 -237
  62. package/src/generators/generateUnifiedDocs.ts +89 -267
  63. package/src/generators/generateUnifiedHandler.ts +2 -4
  64. package/src/index.ts +45 -14
  65. package/src/utils/copyFiles.ts +2 -2
  66. package/src/utils/strings.ts +0 -8
  67. package/src/copy/createOutputValidatorMiddleware.ts +0 -47
  68. package/src/copy/createValidatorMiddleware.ts +0 -62
  69. package/src/copy/transformZod.ts +0 -139
@@ -13,13 +13,41 @@ export type {
13
13
  OpenApiSecuritySchemeConfig,
14
14
  }
15
15
 
16
- export type HonoHookHandler<Env extends { Variables: Record<string, unknown> } = { Variables: Record<string, unknown> }> = (
17
- c: Context<Env>,
16
+ export type HonoEnvBase = {
17
+ Variables: Record<string, unknown>
18
+ Bindings?: Record<string, unknown>
19
+ }
20
+
21
+ export type HonoInternalVariables = {
22
+ prisma?: unknown
23
+ postgres?: unknown
24
+ sqlite?: unknown
25
+ parsedQuery?: Record<string, unknown>
26
+ body?: unknown
27
+ routeConfig?: { pagination?: unknown }
28
+ guardShape?: Record<string, unknown>
29
+ guardCaller?: string
30
+ resultData?: unknown
31
+ resultStatus?: number
32
+ }
33
+
34
+ export type GeneratedHonoEnv<TEnv extends HonoEnvBase = HonoEnvBase> = {
35
+ Variables: HonoInternalVariables & TEnv['Variables']
36
+ Bindings: TEnv['Bindings']
37
+ }
38
+
39
+ export type HonoHookHandler<TEnv extends HonoEnvBase = HonoEnvBase> = (
40
+ c: Context<GeneratedHonoEnv<TEnv>>,
18
41
  next: Next,
19
42
  ) => Promise<Response | void> | Response | void
20
43
 
21
- export type OperationConfig<TShape = Record<string, unknown>> =
22
- BaseOperationConfig<HonoHookHandler, TShape>
44
+ export type OperationConfig<
45
+ TShape = Record<string, unknown>,
46
+ TEnv extends HonoEnvBase = HonoEnvBase,
47
+ > = BaseOperationConfig<HonoHookHandler<TEnv>, TShape>
23
48
 
24
- export type RouteConfig<TShape = Record<string, unknown>, TCtx = unknown> =
25
- BaseRouteConfig<HonoHookHandler, Context, TShape, TCtx>
49
+ export type RouteConfig<
50
+ TShape = Record<string, unknown>,
51
+ TCtx = unknown,
52
+ TEnv extends HonoEnvBase = HonoEnvBase,
53
+ > = BaseRouteConfig<HonoHookHandler<TEnv>, Context<GeneratedHonoEnv<TEnv>>, TShape, TCtx>
@@ -36,7 +36,7 @@ export type ProgressiveStageResult<T = unknown> =
36
36
  | ProgressivePatch[]
37
37
  | ProgressiveStopResult<T>
38
38
 
39
- export type ProgressiveStageContext<TContext = unknown, TPrisma = unknown> = {
39
+ export type ProgressiveStageContext<TContext = unknown, TPrisma = any> = {
40
40
  ctx: TContext
41
41
  req: unknown
42
42
  res: unknown
@@ -46,7 +46,7 @@ export type ProgressiveStageContext<TContext = unknown, TPrisma = unknown> = {
46
46
  signal: AbortSignal
47
47
  }
48
48
 
49
- export type ProgressiveStage<TContext = unknown, TPrisma = unknown, T = unknown> = (
49
+ export type ProgressiveStage<TContext = unknown, TPrisma = any, T = unknown> = (
50
50
  context: ProgressiveStageContext<TContext, TPrisma>,
51
51
  ) => Promise<ProgressiveStageResult<T>>
52
52
 
@@ -1,5 +1,4 @@
1
1
  import { DMMF } from '@prisma/generator-helper'
2
- import { toCamelCase } from '../utils/strings'
3
2
  import { ImportStyle } from '../utils/resolveImportStyle'
4
3
  import { importExt } from '../utils/importExt'
5
4
 
@@ -47,11 +46,9 @@ export function generateFastifyHandler(options: {
47
46
  }): string {
48
47
  const ext = importExt(options.importStyle)
49
48
  const modelName = options.model.name
50
- const prefix = toCamelCase(modelName)
51
49
 
52
50
  const readHandlers = READ_OPS.map((op) => {
53
- const exportName = `${prefix}${op.charAt(0).toUpperCase() + op.slice(1)}`
54
-
51
+ const exportName = `${modelName}${op.charAt(0).toUpperCase() + op.slice(1)}`
55
52
  return `
56
53
  export async function ${exportName}(
57
54
  request: FastifyRequest,
@@ -63,7 +60,7 @@ export async function ${exportName}(
63
60
  }).join('\n')
64
61
 
65
62
  const writeHandlers = WRITE_OPS.map((op) => {
66
- const exportName = `${prefix}${op.charAt(0).toUpperCase() + op.slice(1)}`
63
+ const exportName = `${modelName}${op.charAt(0).toUpperCase() + op.slice(1)}`
67
64
  const statusCode = CREATED_OPS.has(op) ? 201 : 200
68
65
 
69
66
  return `
@@ -1,5 +1,4 @@
1
1
  import { DMMF } from '@prisma/generator-helper'
2
- import { toCamelCase } from '../utils/strings'
3
2
  import { ImportStyle } from '../utils/resolveImportStyle'
4
3
  import { importExt } from '../utils/importExt'
5
4
 
@@ -47,11 +46,9 @@ export function generateHonoHandler(options: {
47
46
  }): string {
48
47
  const ext = importExt(options.importStyle)
49
48
  const modelName = options.model.name
50
- const prefix = toCamelCase(modelName)
51
49
 
52
50
  const readHandlers = READ_OPS.map((op) => {
53
- const exportName = `${prefix}${op.charAt(0).toUpperCase() + op.slice(1)}`
54
-
51
+ const exportName = `${modelName}${op.charAt(0).toUpperCase() + op.slice(1)}`
55
52
  return `
56
53
  export async function ${exportName}(c: Context<HonoEnv>): Promise<void> {
57
54
  const data = await core.${coreFnName(op)}(buildContext(c))
@@ -60,7 +57,7 @@ export async function ${exportName}(c: Context<HonoEnv>): Promise<void> {
60
57
  }).join('\n')
61
58
 
62
59
  const writeHandlers = WRITE_OPS.map((op) => {
63
- const exportName = `${prefix}${op.charAt(0).toUpperCase() + op.slice(1)}`
60
+ const exportName = `${modelName}${op.charAt(0).toUpperCase() + op.slice(1)}`
64
61
  const statusCode = CREATED_OPS.has(op) ? 201 : 200
65
62
 
66
63
  return `
@@ -11,20 +11,10 @@ function findClientGenerator(options: GeneratorOptions) {
11
11
  gen.provider.value === '@prisma/client' ||
12
12
  gen.provider.value === 'prisma-client',
13
13
  )
14
- if (byProvider) return byProvider
15
-
16
- const withOutput = options.otherGenerators.find(
17
- (gen) =>
18
- gen.output?.value?.includes('prisma') ||
19
- gen.output?.value?.includes('client'),
20
- )
21
- return withOutput || null
14
+ return byProvider || null
22
15
  }
23
16
 
24
- function getRelativeImportPath(
25
- fromDir: string,
26
- clientOutputPath: string,
27
- ): string {
17
+ function getRelativeImportPath(fromDir: string, clientOutputPath: string): string {
28
18
  let relativeImportPath = path.relative(fromDir, clientOutputPath)
29
19
  relativeImportPath = relativeImportPath.split(path.sep).join(path.posix.sep)
30
20
  if (!relativeImportPath.startsWith('.')) {
@@ -33,28 +23,6 @@ function getRelativeImportPath(
33
23
  return relativeImportPath
34
24
  }
35
25
 
36
- export function generateImportPrismaStatement(
37
- generatorOptions: GeneratorOptions,
38
- ): string {
39
- const clientGenerator = findClientGenerator(generatorOptions)
40
-
41
- if (!clientGenerator || !clientGenerator.output?.value) {
42
- throw new Error(
43
- 'Prisma client generator not found. Ensure a generator with provider "prisma-client-js" exists in your schema.',
44
- )
45
- }
46
-
47
- const outputValue = generatorOptions.generator.output?.value
48
- if (!outputValue) {
49
- throw new Error('Generator output path not defined.')
50
- }
51
-
52
- const subDir = path.join(outputValue, '_relative')
53
- const outputPath = getRelativeImportPath(subDir, clientGenerator.output.value)
54
-
55
- return `import { Prisma, PrismaClient } from '${outputPath}';\n`
56
- }
57
-
58
26
  export function getRelativeClientPath(
59
27
  generatorOptions: GeneratorOptions,
60
28
  modelName: string,
@@ -63,7 +31,7 @@ export function getRelativeClientPath(
63
31
 
64
32
  if (!clientGenerator || !clientGenerator.output?.value) {
65
33
  throw new Error(
66
- 'Prisma client generator not found. Ensure a generator with provider "prisma-client-js" exists in your schema.',
34
+ 'Prisma client generator not found. Ensure a generator block exists with name "client" or provider one of: prisma-client-js, @prisma/client, prisma-client.',
67
35
  )
68
36
  }
69
37
 
@@ -123,7 +123,7 @@ export async function findManyPaginated(
123
123
  total = txResult.t
124
124
  } catch (txError: unknown) {
125
125
  const txe = txError as { message?: string; code?: string }
126
- if ((typeof txe?.message === 'string' && txe.message.includes('interactive transactions')) || txe?.code === 'P2028') {
126
+ if (txe?.code === 'P2028') {
127
127
  console.warn('[prisma-generator-express] Interactive transactions not available, pagination queries are non-atomic')
128
128
  items = (await delegate.findMany(query)) as unknown[]
129
129
  total = await countForPagination(delegate, query, undefined, undefined, distinctCountLimit)
@@ -86,6 +86,15 @@ function doStart(options: QueryBuilderOptions): Promise<void> {
86
86
  return
87
87
  }
88
88
 
89
+ const schemaByteLength = Buffer.byteLength(schemaContent, 'utf8')
90
+ if (schemaByteLength > 28000) {
91
+ console.warn(
92
+ '[query-builder] Schema size is ' + schemaByteLength + ' bytes. ' +
93
+ 'Environment variable size limits may cause spawn failure on Windows (~32KB). ' +
94
+ 'If the query builder fails to start, this is the likely cause.',
95
+ )
96
+ }
97
+
89
98
  const schemaCwd = dirname(resolve(schemaPath))
90
99
 
91
100
  _process = spawn(process.execPath, [cliPath], {
@@ -18,7 +18,6 @@ type ModelMeta = {
18
18
  name: string
19
19
  delegateKey: string
20
20
  scalarFields: string[]
21
- idFields: string[]
22
21
  relations: Record<string, RelationFieldMeta>
23
22
  }
24
23
 
@@ -95,7 +94,6 @@ function buildModelMeta(
95
94
  models: ReadonlyArray<DMMF.Model>,
96
95
  ): ModelMeta {
97
96
  const scalarFields: string[] = []
98
- const idFields: string[] = []
99
97
  const relations: Record<string, RelationFieldMeta> = {}
100
98
 
101
99
  for (const field of model.fields) {
@@ -103,13 +101,6 @@ function buildModelMeta(
103
101
  relations[field.name] = computeRelation(field, model.name, models)
104
102
  } else if (field.kind === 'scalar' || field.kind === 'enum') {
105
103
  scalarFields.push(field.name)
106
- if (field.isId) idFields.push(field.name)
107
- }
108
- }
109
-
110
- if (model.primaryKey && Array.isArray(model.primaryKey.fields)) {
111
- for (const f of model.primaryKey.fields) {
112
- if (!idFields.includes(f)) idFields.push(f)
113
104
  }
114
105
  }
115
106
 
@@ -117,7 +108,6 @@ function buildModelMeta(
117
108
  name: model.name,
118
109
  delegateKey: model.name.charAt(0).toLowerCase() + model.name.slice(1),
119
110
  scalarFields,
120
- idFields,
121
111
  relations,
122
112
  }
123
113
  }
@@ -1,6 +1,7 @@
1
1
  import { ImportStyle } from '../utils/resolveImportStyle'
2
2
  import { importExt } from '../utils/importExt'
3
3
  import type { Target } from '../constants'
4
+ import { capitalize } from '../utils/strings'
4
5
 
5
6
  const ROUTER_OPERATIONS = [
6
7
  'findUnique', 'findUniqueOrThrow', 'findFirst', 'findFirstOrThrow',
@@ -38,16 +39,35 @@ const ROUTER_OP_TO_SHAPE_OP: Record<RouterOperation, string> = {
38
39
  deleteMany: 'deleteMany',
39
40
  }
40
41
 
41
- function capitalize(s: string): string {
42
- return s.charAt(0).toUpperCase() + s.slice(1)
43
- }
44
42
 
45
43
  function requestTypeFor(target: Target): string {
46
44
  if (target === 'fastify') return `import('fastify').FastifyRequest`
47
- if (target === 'hono') return `import('hono').Context`
45
+ if (target === 'hono') return `import('hono').Context<TEnv>`
48
46
  return `import('express').Request`
49
47
  }
50
48
 
49
+ function configGenericsFor(target: Target): string {
50
+ if (target === 'hono') {
51
+ return `<TCtx = unknown, TPrisma = any, TEnv extends { Variables: Record<string, unknown> } = { Variables: Record<string, unknown> }>`
52
+ }
53
+ return `<TCtx = unknown, TPrisma = any>`
54
+ }
55
+
56
+ function routeConfigBaseFor(target: Target): string {
57
+ if (target === 'hono') {
58
+ return `RouteConfig<Record<string, unknown>, TCtx, TEnv>`
59
+ }
60
+ if (target === 'express') {
61
+ return `RouteConfig<Record<string, unknown>, TCtx, TPrisma>`
62
+ }
63
+ return `RouteConfig<Record<string, unknown>, TCtx>`
64
+ }
65
+
66
+ function hookHandlerTypeRef(target: Target, hookHandlerType: string): string {
67
+ if (target === 'hono') return `${hookHandlerType}<TEnv>`
68
+ return hookHandlerType
69
+ }
70
+
51
71
  export function generateRouteConfigType(
52
72
  modelName: string,
53
73
  hookHandlerType: string,
@@ -58,6 +78,10 @@ export function generateRouteConfigType(
58
78
  const ext = importExt(importStyle)
59
79
  const m = modelName
60
80
  const supportsProgressive = target === 'express'
81
+
82
+ const generics = configGenericsFor(target)
83
+ const baseConfig = routeConfigBaseFor(target)
84
+ const hookRef = hookHandlerTypeRef(target, hookHandlerType)
61
85
  const requestType = requestTypeFor(target)
62
86
 
63
87
  const progressiveTypeImport = supportsProgressive
@@ -65,7 +89,7 @@ export function generateRouteConfigType(
65
89
  : ''
66
90
 
67
91
  if (!guardShapesImport) {
68
- return progressiveTypeImport + `export type ${m}RouteConfig<TCtx = unknown> = RouteConfig<Record<string, unknown>, TCtx>\n`
92
+ return progressiveTypeImport + `export type ${m}RouteConfig${generics} = ${baseConfig}\n`
69
93
  }
70
94
 
71
95
  const shapeOps = Object.values(ROUTER_OP_TO_SHAPE_OP).filter((v, i, a) => a.indexOf(v) === i)
@@ -76,13 +100,13 @@ export function generateRouteConfigType(
76
100
  const c = capitalize(shapeOp)
77
101
  const isRead = READ_OPERATIONS.has(routerOp)
78
102
  const lines = [
79
- ` before?: ${hookHandlerType}[]`,
80
- ` after?: ${hookHandlerType}[]`,
103
+ ` before?: ${hookRef}[]`,
104
+ ` after?: ${hookRef}[]`,
81
105
  ` shape?: ${m}${c}ShapeInput<TCtx>`,
82
106
  ]
83
107
  if (isRead && supportsProgressive) {
84
108
  lines.push(` progressive?: Record<string, ProgressiveVariantConfig>`)
85
- lines.push(` progressiveStages?: Record<string, ProgressiveStage<TCtx>>`)
109
+ lines.push(` progressiveStages?: Record<string, ProgressiveStage<TCtx, TPrisma>>`)
86
110
  }
87
111
  return ` ${routerOp}?: {\n${lines.join('\n')}\n }`
88
112
  }).join('\n')
@@ -92,8 +116,8 @@ export function generateRouteConfigType(
92
116
  return (
93
117
  progressiveTypeImport +
94
118
  `import type {\n ${opShapeImports}\n} from '${guardShapesImport}${ext}'\n\n` +
95
- `export type ${m}RouteConfig<TCtx = unknown> = Omit<\n` +
96
- ` RouteConfig<Record<string, unknown>, TCtx>,\n` +
119
+ `export type ${m}RouteConfig${generics} = Omit<\n` +
120
+ ` ${baseConfig},\n` +
97
121
  ` | ${omitKeys}\n` +
98
122
  ` | 'resolveContext'\n` +
99
123
  `> & {\n` +