prisma-generator-express 1.40.0 → 1.41.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 (48) hide show
  1. package/README.md +444 -12
  2. package/dist/generators/generateOperationCore.d.ts +3 -1
  3. package/dist/generators/generateOperationCore.js +266 -160
  4. package/dist/generators/generateOperationCore.js.map +1 -1
  5. package/dist/generators/generateRouteConfigType.d.ts +3 -1
  6. package/dist/generators/generateRouteConfigType.js +36 -31
  7. package/dist/generators/generateRouteConfigType.js.map +1 -1
  8. package/dist/generators/generateRouter.d.ts +4 -2
  9. package/dist/generators/generateRouter.js +130 -119
  10. package/dist/generators/generateRouter.js.map +1 -1
  11. package/dist/generators/generateRouterFastify.d.ts +3 -1
  12. package/dist/generators/generateRouterFastify.js +12 -10
  13. package/dist/generators/generateRouterFastify.js.map +1 -1
  14. package/dist/generators/generateRouterHono.d.ts +3 -1
  15. package/dist/generators/generateRouterHono.js +12 -9
  16. package/dist/generators/generateRouterHono.js.map +1 -1
  17. package/dist/generators/generateUnifiedDocs.d.ts +2 -1
  18. package/dist/generators/generateUnifiedDocs.js +6 -4
  19. package/dist/generators/generateUnifiedDocs.js.map +1 -1
  20. package/dist/index.js +16 -21
  21. package/dist/index.js.map +1 -1
  22. package/dist/utils/copyFiles.d.ts +2 -1
  23. package/dist/utils/copyFiles.js +39 -34
  24. package/dist/utils/copyFiles.js.map +1 -1
  25. package/dist/utils/importExt.d.ts +2 -0
  26. package/dist/utils/importExt.js +11 -0
  27. package/dist/utils/importExt.js.map +1 -0
  28. package/dist/utils/resolveImportStyle.d.ts +3 -0
  29. package/dist/utils/resolveImportStyle.js +211 -0
  30. package/dist/utils/resolveImportStyle.js.map +1 -0
  31. package/dist/utils/writeFileSafely.js +6 -9
  32. package/dist/utils/writeFileSafely.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/copy/routeConfig.express.ts +39 -5
  35. package/src/copy/routeConfig.fastify.ts +8 -4
  36. package/src/copy/routeConfig.hono.ts +7 -3
  37. package/src/copy/routeConfig.ts +42 -2
  38. package/src/generators/generateOperationCore.ts +273 -169
  39. package/src/generators/generateRouteConfigType.ts +42 -35
  40. package/src/generators/generateRouter.ts +134 -121
  41. package/src/generators/generateRouterFastify.ts +14 -9
  42. package/src/generators/generateRouterHono.ts +14 -8
  43. package/src/generators/generateUnifiedDocs.ts +8 -3
  44. package/src/index.ts +25 -47
  45. package/src/utils/copyFiles.ts +45 -45
  46. package/src/utils/importExt.ts +7 -0
  47. package/src/utils/resolveImportStyle.ts +187 -0
  48. package/src/utils/writeFileSafely.ts +6 -22
@@ -1,7 +1,25 @@
1
1
  import { DMMF } from '@prisma/generator-helper'
2
-
3
- export function generateOperationRuntime(): string {
4
- return `import { sanitizeKeys } from './misc'
2
+ import { ImportStyle } from '../utils/resolveImportStyle'
3
+ import { importExt } from '../utils/importExt'
4
+
5
+ export function generateOperationRuntime(importStyle: ImportStyle): string {
6
+ const ext = importExt(importStyle)
7
+ return `import { sanitizeKeys } from './misc${ext}'
8
+ import type {
9
+ ProgressivePatch,
10
+ ProgressiveStopResult,
11
+ ProgressiveStageResult,
12
+ ProgressiveStageContext,
13
+ ProgressiveStage,
14
+ } from './routeConfig${ext}'
15
+
16
+ export type {
17
+ ProgressivePatch,
18
+ ProgressiveStopResult,
19
+ ProgressiveStageResult,
20
+ ProgressiveStageContext,
21
+ ProgressiveStage,
22
+ }
5
23
 
6
24
  export interface PaginationConfig {
7
25
  defaultLimit?: number
@@ -67,88 +85,41 @@ const PRISMA_ERROR_MAP: Record<string, { status: number; message: string }> = {
67
85
 
68
86
  export function mapError(error: unknown): HttpError {
69
87
  if (error instanceof HttpError) return error
70
-
71
- if (
72
- error &&
73
- typeof error === 'object' &&
74
- 'name' in error &&
75
- error.name === 'ShapeError'
76
- ) {
88
+ if (error && typeof error === 'object' && 'name' in error && (error as any).name === 'ShapeError') {
77
89
  return new HttpError(400, (error as any).message)
78
90
  }
79
-
80
- if (
81
- error &&
82
- typeof error === 'object' &&
83
- 'name' in error &&
84
- error.name === 'CallerError'
85
- ) {
91
+ if (error && typeof error === 'object' && 'name' in error && (error as any).name === 'CallerError') {
86
92
  return new HttpError(400, (error as any).message)
87
93
  }
88
-
89
- if (
90
- error &&
91
- typeof error === 'object' &&
92
- 'name' in error &&
93
- error.name === 'PolicyError'
94
- ) {
94
+ if (error && typeof error === 'object' && 'name' in error && (error as any).name === 'PolicyError') {
95
95
  return new HttpError(403, (error as any).message)
96
96
  }
97
-
98
- if (
99
- error &&
100
- typeof error === 'object' &&
101
- 'issues' in error &&
102
- 'name' in error &&
103
- (error as any).name === 'ZodError'
104
- ) {
97
+ if (error && typeof error === 'object' && 'issues' in error && 'name' in error && (error as any).name === 'ZodError') {
105
98
  const issues = (error as any).issues
106
- const message = Array.isArray(issues)
107
- ? issues.map((i: any) => i.message).join('; ')
108
- : (error as any).message
99
+ const message = Array.isArray(issues) ? issues.map((i: any) => i.message).join('; ') : (error as any).message
109
100
  return new HttpError(400, message)
110
101
  }
111
-
112
102
  if (error && typeof error === 'object' && 'code' in error) {
113
103
  const code = (error as any).code as string
114
104
  const mapped = PRISMA_ERROR_MAP[code]
115
105
  if (mapped) {
116
106
  const detail = (error as any).message
117
- const message = detail
118
- ? mapped.message + ': ' + detail
119
- : mapped.message
120
- return new HttpError(mapped.status, message)
107
+ return new HttpError(mapped.status, detail ? mapped.message + ': ' + detail : mapped.message)
121
108
  }
122
109
  if (typeof code === 'string' && code.startsWith('P')) {
123
110
  const msg = (error as any).message || 'Database operation failed'
124
- console.warn(
125
- '[prisma-generator-express] Unmapped Prisma error code:',
126
- code,
127
- msg,
128
- )
111
+ console.warn('[prisma-generator-express] Unmapped Prisma error code:', code, msg)
129
112
  return new HttpError(500, msg)
130
113
  }
131
114
  }
132
-
133
115
  if (error && typeof error === 'object' && 'name' in error) {
134
116
  const name = (error as any).name
135
- if (name === 'PrismaClientValidationError') {
136
- return new HttpError(400, (error as any).message || 'Invalid query parameters')
137
- }
138
- if (name === 'PrismaClientKnownRequestError') {
139
- return new HttpError(400, (error as any).message || 'Database request error')
140
- }
141
- if (name === 'PrismaClientInitializationError') {
142
- return new HttpError(503, (error as any).message || 'Database connection failed')
143
- }
144
- if (name === 'PrismaClientRustPanicError') {
145
- return new HttpError(500, (error as any).message || 'Internal database engine error')
146
- }
147
- if (name === 'PrismaClientUnknownRequestError') {
148
- return new HttpError(500, (error as any).message || 'Unknown database error')
149
- }
117
+ if (name === 'PrismaClientValidationError') return new HttpError(400, (error as any).message || 'Invalid query parameters')
118
+ if (name === 'PrismaClientKnownRequestError') return new HttpError(400, (error as any).message || 'Database request error')
119
+ if (name === 'PrismaClientInitializationError') return new HttpError(503, (error as any).message || 'Database connection failed')
120
+ if (name === 'PrismaClientRustPanicError') return new HttpError(500, (error as any).message || 'Internal database engine error')
121
+ if (name === 'PrismaClientUnknownRequestError') return new HttpError(500, (error as any).message || 'Unknown database error')
150
122
  }
151
-
152
123
  const msg = error instanceof Error ? error.message : String(error)
153
124
  console.error('[prisma-generator-express] Unhandled error:', error)
154
125
  return new HttpError(500, msg || 'Internal server error')
@@ -176,14 +147,10 @@ export async function getExtendedClient(ctx: OperationContext): Promise<any> {
176
147
  if (!base) {
177
148
  throw new HttpError(500, 'PrismaClient not found on request. Set req.prisma in middleware.')
178
149
  }
179
-
180
150
  await _prismasqlReady
181
-
182
151
  if (!_speedExtension) return base
183
-
184
152
  const connector = ctx.postgres || ctx.sqlite
185
153
  if (!connector) return base
186
-
187
154
  if (typeof connector === 'object' && connector !== null) {
188
155
  const innerMap = _extendedClients.get(connector)
189
156
  if (innerMap) {
@@ -191,14 +158,12 @@ export async function getExtendedClient(ctx: OperationContext): Promise<any> {
191
158
  if (cached) return cached
192
159
  }
193
160
  }
194
-
195
161
  try {
196
162
  const extended = base.$extends(_speedExtension({
197
163
  postgres: ctx.postgres,
198
164
  sqlite: ctx.sqlite,
199
165
  debug: process.env.DEBUG === 'true',
200
166
  }))
201
-
202
167
  if (typeof connector === 'object' && connector !== null) {
203
168
  let innerMap = _extendedClients.get(connector)
204
169
  if (!innerMap) {
@@ -207,7 +172,6 @@ export async function getExtendedClient(ctx: OperationContext): Promise<any> {
207
172
  }
208
173
  innerMap.set(base, extended)
209
174
  }
210
-
211
175
  return extended
212
176
  } catch (error) {
213
177
  console.warn('[speedExtension] Failed to initialize, using base client:', error)
@@ -228,25 +192,18 @@ export function requireBodyField(body: Record<string, any>, field: string): void
228
192
  }
229
193
  }
230
194
 
231
- export function applyPaginationLimits(
232
- query: Record<string, any>,
233
- config?: PaginationConfig,
234
- ): Record<string, any> {
195
+ export function applyPaginationLimits(query: Record<string, any>, config?: PaginationConfig): Record<string, any> {
235
196
  if (!config) return query
236
-
237
197
  const result = { ...query }
238
-
239
198
  if (result.take === undefined && config.defaultLimit !== undefined) {
240
199
  result.take = config.defaultLimit
241
200
  }
242
-
243
201
  if (config.maxLimit !== undefined && result.take !== undefined) {
244
202
  const takeNum = Number(result.take)
245
203
  if (Math.abs(takeNum) > config.maxLimit) {
246
204
  result.take = takeNum < 0 ? -config.maxLimit : config.maxLimit
247
205
  }
248
206
  }
249
-
250
207
  return result
251
208
  }
252
209
 
@@ -258,10 +215,7 @@ export function normalizeDistinct(value: unknown): string[] {
258
215
 
259
216
  export function assertGuard(delegate: any): void {
260
217
  if (typeof delegate.guard !== 'function') {
261
- throw new HttpError(
262
- 500,
263
- 'Guard shapes require prisma-guard extension on PrismaClient. Install: npm install prisma-guard, then extend your client with guardExtension().',
264
- )
218
+ throw new HttpError(500, 'Guard shapes require prisma-guard extension on PrismaClient.')
265
219
  }
266
220
  }
267
221
 
@@ -281,14 +235,9 @@ export function buildCountShape(shape: Record<string, any>): Record<string, any>
281
235
  if (typeof shape === 'function') {
282
236
  return (...args: any[]) => keepWhereOnly((shape as Function)(...args))
283
237
  }
284
-
285
238
  const keys = Object.keys(shape)
286
239
  const isSingleShape = keys.length === 0 || keys.every((k) => GUARD_SHAPE_CONFIG_KEYS.has(k))
287
-
288
- if (isSingleShape) {
289
- return keepWhereOnly(shape)
290
- }
291
-
240
+ if (isSingleShape) return keepWhereOnly(shape)
292
241
  const result: Record<string, any> = {}
293
242
  for (const [key, variant] of Object.entries(shape)) {
294
243
  if (typeof variant === 'function') {
@@ -312,7 +261,6 @@ export async function countForPagination(
312
261
  const distinctFields = normalizeDistinct(query.distinct)
313
262
  const hasDistinct = distinctFields.length > 0
314
263
  const effectiveLimit = distinctCountLimit ?? DISTINCT_COUNT_LIMIT
315
-
316
264
  const countShape = shape ? buildCountShape(shape) : undefined
317
265
 
318
266
  if (hasDistinct) {
@@ -323,30 +271,22 @@ export async function countForPagination(
323
271
  select: { [selectField]: true },
324
272
  take: effectiveLimit + 1,
325
273
  }
326
-
327
274
  const results = shape
328
275
  ? await delegate.guard(shape, caller).findMany(distinctArgs)
329
276
  : await delegate.findMany(distinctArgs)
330
-
331
277
  if (results.length > effectiveLimit) {
332
- console.warn(
333
- '[prisma-generator-express] Distinct count exceeds ' +
334
- effectiveLimit +
335
- ', falling back to approximate total',
336
- )
278
+ console.warn('[prisma-generator-express] Distinct count exceeds ' + effectiveLimit + ', falling back to approximate total')
337
279
  const countArgs: Record<string, any> = {}
338
280
  if (query.where) countArgs.where = query.where
339
281
  return countShape
340
282
  ? await delegate.guard(countShape, caller).count(countArgs)
341
283
  : await delegate.count(countArgs)
342
284
  }
343
-
344
285
  return results.length
345
286
  }
346
287
 
347
288
  const countArgs: Record<string, any> = {}
348
289
  if (query.where) countArgs.where = query.where
349
-
350
290
  return countShape
351
291
  ? await delegate.guard(countShape, caller).count(countArgs)
352
292
  : await delegate.count(countArgs)
@@ -355,12 +295,8 @@ export async function countForPagination(
355
295
  export function transformResult(value: unknown): unknown {
356
296
  if (value === null || value === undefined) return value
357
297
  if (typeof value === 'bigint') return value.toString()
358
- if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
359
- return value.toString('base64')
360
- }
361
- if (value instanceof Uint8Array) {
362
- return Buffer.from(value).toString('base64')
363
- }
298
+ if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) return value.toString('base64')
299
+ if (value instanceof Uint8Array) return Buffer.from(value).toString('base64')
364
300
  if (value instanceof Date) return value
365
301
  if (Array.isArray(value)) return value.map(transformResult)
366
302
  if (typeof value === 'object') {
@@ -374,31 +310,238 @@ export function transformResult(value: unknown): unknown {
374
310
  }
375
311
  return value
376
312
  }
313
+
314
+ export function acceptsEventStream(accept: string | undefined): boolean {
315
+ if (!accept) return false
316
+ return accept.toLowerCase().includes('text/event-stream')
317
+ }
318
+
319
+ const UNSAFE_PATH_SEGMENTS = new Set(['__proto__', 'constructor', 'prototype'])
320
+
321
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
322
+ if (value === null || typeof value !== 'object') return false
323
+ if (Array.isArray(value)) return false
324
+ const proto = Object.getPrototypeOf(value)
325
+ return proto === Object.prototype || proto === null
326
+ }
327
+
328
+ export function setByPath(target: Record<string, unknown>, path: string, value: unknown): boolean {
329
+ const parts = path.split('.')
330
+ if (parts.length === 0) return false
331
+ for (const p of parts) {
332
+ if (p === '' || UNSAFE_PATH_SEGMENTS.has(p)) return false
333
+ }
334
+ let cursor: Record<string, unknown> = target
335
+ for (let i = 0; i < parts.length - 1; i++) {
336
+ const part = parts[i]
337
+ const next = cursor[part]
338
+ if (!isPlainObject(next)) {
339
+ if (process.env.NODE_ENV !== 'production') {
340
+ console.warn(
341
+ '[progressive] Dropping patch for "' + path +
342
+ '": cannot traverse non-plain-object at segment "' + part + '"',
343
+ )
344
+ }
345
+ return false
346
+ }
347
+ cursor = next
348
+ }
349
+ cursor[parts[parts.length - 1]] = value
350
+ return true
351
+ }
352
+
353
+ function removeReqCloseListener(req: any, listener: () => void): void {
354
+ if (typeof req.off === 'function') {
355
+ req.off('close', listener)
356
+ } else if (typeof req.removeListener === 'function') {
357
+ req.removeListener('close', listener)
358
+ }
359
+ }
360
+
361
+ export function initSSE(res: any): void {
362
+ res.statusCode = 200
363
+ res.setHeader('Content-Type', 'text/event-stream')
364
+ res.setHeader('Cache-Control', 'no-cache, no-transform')
365
+ res.setHeader('Connection', 'keep-alive')
366
+ res.setHeader('X-Accel-Buffering', 'no')
367
+ if (typeof res.flushHeaders === 'function') res.flushHeaders()
368
+ }
369
+
370
+ export function flushSSE(res: any): void {
371
+ if (typeof res.flush === 'function') {
372
+ try { res.flush() } catch {}
373
+ }
374
+ }
375
+
376
+ export function sendSSE(res: any, payload: unknown): boolean {
377
+ if (res.writableEnded || res.destroyed) return false
378
+ try {
379
+ res.write('data: ' + JSON.stringify(transformResult(payload)) + '\\n\\n')
380
+ flushSSE(res)
381
+ return true
382
+ } catch (err) {
383
+ console.error('[progressive] failed to send SSE event:', err)
384
+ return false
385
+ }
386
+ }
387
+
388
+ export function sendSSEProgress(res: any, stage: string, completed: number, total: number): boolean {
389
+ return sendSSE(res, { type: 'progress', stage, completed, total })
390
+ }
391
+
392
+ export function sendSSEField(res: any, key: string, value: unknown): boolean {
393
+ return sendSSE(res, { type: 'field', key, value })
394
+ }
395
+
396
+ export function sendSSEResult(res: any, data: unknown): boolean {
397
+ return sendSSE(res, { type: 'result', data })
398
+ }
399
+
400
+ export function sendSSEError(res: any, message: string): boolean {
401
+ if (res.writableEnded || res.destroyed) return false
402
+ try {
403
+ res.write('data: ' + JSON.stringify({ type: 'error', message }) + '\\n\\n')
404
+ flushSSE(res)
405
+ return true
406
+ } catch (err) {
407
+ console.error('[progressive] failed to send SSE error event:', err)
408
+ return false
409
+ }
410
+ }
411
+
412
+ export function startSSEKeepalive(res: any, intervalMs: number = 15000): any {
413
+ const handle = setInterval(() => {
414
+ if (res.writableEnded || res.destroyed) return
415
+ try {
416
+ res.write(': keepalive\\n\\n')
417
+ flushSSE(res)
418
+ } catch {}
419
+ }, intervalMs)
420
+ if (typeof (handle as any).unref === 'function') (handle as any).unref()
421
+ return handle
422
+ }
423
+
424
+ export function endSSE(res: any, keepaliveHandle: any): void {
425
+ if (keepaliveHandle) {
426
+ try { clearInterval(keepaliveHandle) } catch {}
427
+ }
428
+ if (!res.writableEnded && !res.destroyed) {
429
+ try { res.end() } catch {}
430
+ }
431
+ }
432
+
433
+ export interface RunSingleResultSSEOptions {
434
+ req: any
435
+ res: any
436
+ coreQueryFn: () => Promise<unknown>
437
+ }
438
+
439
+ export async function runSingleResultSSE(options: RunSingleResultSSEOptions): Promise<void> {
440
+ const { req, res, coreQueryFn } = options
441
+ let keepalive: any = null
442
+ try {
443
+ initSSE(res)
444
+ keepalive = startSSEKeepalive(res)
445
+ if (req.destroyed) return
446
+ const data = await coreQueryFn()
447
+ if (res.writableEnded || res.destroyed) return
448
+ sendSSEResult(res, data)
449
+ } catch (err) {
450
+ console.error('[progressive] single-result error:', err)
451
+ if (!res.writableEnded && !res.destroyed) {
452
+ sendSSEError(res, 'Internal server error')
453
+ }
454
+ } finally {
455
+ endSSE(res, keepalive)
456
+ }
457
+ }
458
+
459
+ function isStopResult(value: unknown): value is ProgressiveStopResult<unknown> {
460
+ return typeof value === 'object' && value !== null && (value as any).stop === true
461
+ }
462
+
463
+ export interface RunProgressiveOptions {
464
+ req: any
465
+ res: any
466
+ ctx: unknown
467
+ prisma: any
468
+ variant: string
469
+ stages: string[]
470
+ stageRegistry: Record<string, ProgressiveStage<any, any>>
471
+ }
472
+
473
+ export async function runProgressiveEndpoint(options: RunProgressiveOptions): Promise<void> {
474
+ const { req, res, ctx, prisma, variant, stages, stageRegistry } = options
475
+ let keepalive: any = null
476
+ const controller = new AbortController()
477
+ const onClose = () => controller.abort()
478
+ if (typeof req.on === 'function') req.on('close', onClose)
479
+
480
+ const accumulated: Record<string, unknown> = {}
481
+ const signal = controller.signal
482
+
483
+ try {
484
+ initSSE(res)
485
+ keepalive = startSSEKeepalive(res)
486
+ sendSSEProgress(res, 'start', 0, stages.length)
487
+
488
+ for (let i = 0; i < stages.length; i++) {
489
+ if (res.writableEnded || res.destroyed || signal.aborted) return
490
+ const stageName = stages[i]
491
+ const stage = stageRegistry[stageName]
492
+ if (!stage) throw new Error('Missing progressive stage: ' + stageName)
493
+
494
+ const result = await stage({ ctx, req, res, prisma, variant, accumulated, signal })
495
+ if (res.writableEnded || res.destroyed) return
496
+
497
+ if (isStopResult(result)) {
498
+ sendSSEResult(res, result.data)
499
+ return
500
+ }
501
+
502
+ const patches = Array.isArray(result) ? result : result ? [result] : []
503
+ for (const patch of patches) {
504
+ if (!patch || typeof patch !== 'object') continue
505
+ if (typeof (patch as any).key !== 'string') continue
506
+ if (!('value' in patch)) continue
507
+ const p = patch as ProgressivePatch
508
+ const applied = setByPath(accumulated, p.key, p.value)
509
+ if (applied) sendSSEField(res, p.key, p.value)
510
+ }
511
+ sendSSEProgress(res, stageName, i + 1, stages.length)
512
+ }
513
+ if (res.writableEnded || res.destroyed) return
514
+ sendSSEResult(res, accumulated)
515
+ } catch (err) {
516
+ console.error('[progressive] stage error:', err)
517
+ if (!res.writableEnded && !res.destroyed) {
518
+ sendSSEError(res, 'Could not load progressive response')
519
+ }
520
+ } finally {
521
+ removeReqCloseListener(req, onClose)
522
+ endSSE(res, keepalive)
523
+ }
524
+ }
377
525
  `
378
526
  }
379
527
 
380
528
  export interface ModelCoreOptions {
381
529
  model: DMMF.Model
530
+ importStyle: ImportStyle
382
531
  }
383
532
 
384
533
  export function generateModelCore(options: ModelCoreOptions): string {
534
+ const ext = importExt(options.importStyle)
385
535
  const modelName = options.model.name
386
- const modelNameLower =
387
- modelName.charAt(0).toLowerCase() + modelName.slice(1)
536
+ const modelNameLower = modelName.charAt(0).toLowerCase() + modelName.slice(1)
388
537
 
389
538
  const standardReadOps = [
390
- 'findFirst',
391
- 'findUnique',
392
- 'findUniqueOrThrow',
393
- 'findFirstOrThrow',
394
- 'count',
395
- 'aggregate',
396
- 'groupBy',
539
+ 'findFirst', 'findUnique', 'findUniqueOrThrow', 'findFirstOrThrow',
540
+ 'count', 'aggregate', 'groupBy',
397
541
  ]
398
542
 
399
543
  const standardReadHandlers = standardReadOps
400
- .map(
401
- (op) => `
544
+ .map((op) => `
402
545
  export async function ${op}(ctx: OperationContext): Promise<unknown> {
403
546
  const query = ctx.parsedQuery || {}
404
547
  const extended = await getExtendedClient(ctx)
@@ -407,53 +550,24 @@ export async function ${op}(ctx: OperationContext): Promise<unknown> {
407
550
  return (extended as any).${modelNameLower}.guard(ctx.guardShape, ctx.guardCaller).${op}(query)
408
551
  }
409
552
  return (extended as any).${modelNameLower}.${op}(query)
410
- }`,
411
- )
553
+ }`)
412
554
  .join('\n')
413
555
 
414
556
  const writeOps = [
415
557
  { name: 'create', method: 'create', requiredFields: ['data'] },
416
558
  { name: 'createMany', method: 'createMany', requiredFields: ['data'] },
417
- {
418
- name: 'createManyAndReturn',
419
- method: 'createManyAndReturn',
420
- requiredFields: ['data'],
421
- },
422
- {
423
- name: 'update',
424
- method: 'update',
425
- requiredFields: ['where', 'data'],
426
- },
427
- {
428
- name: 'updateMany',
429
- method: 'updateMany',
430
- requiredFields: ['where', 'data'],
431
- },
432
- {
433
- name: 'updateManyAndReturn',
434
- method: 'updateManyAndReturn',
435
- requiredFields: ['where', 'data'],
436
- },
559
+ { name: 'createManyAndReturn', method: 'createManyAndReturn', requiredFields: ['data'] },
560
+ { name: 'update', method: 'update', requiredFields: ['where', 'data'] },
561
+ { name: 'updateMany', method: 'updateMany', requiredFields: ['where', 'data'] },
562
+ { name: 'updateManyAndReturn', method: 'updateManyAndReturn', requiredFields: ['where', 'data'] },
437
563
  { name: 'deleteUnique', method: 'delete', requiredFields: ['where'] },
438
- {
439
- name: 'deleteMany',
440
- method: 'deleteMany',
441
- requiredFields: ['where'],
442
- },
443
- {
444
- name: 'upsert',
445
- method: 'upsert',
446
- requiredFields: ['where', 'create', 'update'],
447
- },
564
+ { name: 'deleteMany', method: 'deleteMany', requiredFields: ['where'] },
565
+ { name: 'upsert', method: 'upsert', requiredFields: ['where', 'create', 'update'] },
448
566
  ]
449
567
 
450
- const writeHandlers = writeOps
451
- .map((op) => {
452
- const validationLines = op.requiredFields
453
- .map((field) => ` requireBodyField(body, '${field}')`)
454
- .join('\n')
455
-
456
- return `
568
+ const writeHandlers = writeOps.map((op) => {
569
+ const validationLines = op.requiredFields.map((field) => ` requireBodyField(body, '${field}')`).join('\n')
570
+ return `
457
571
  export async function ${op.name}(ctx: OperationContext): Promise<unknown> {
458
572
  const body = validateBody(ctx.body)
459
573
  ${validationLines}
@@ -464,8 +578,7 @@ ${validationLines}
464
578
  }
465
579
  return (extended as any).${modelNameLower}.${op.method}(body)
466
580
  }`
467
- })
468
- .join('\n')
581
+ }).join('\n')
469
582
 
470
583
  return `import {
471
584
  OperationContext,
@@ -475,7 +588,7 @@ ${validationLines}
475
588
  applyPaginationLimits,
476
589
  assertGuard,
477
590
  countForPagination,
478
- } from '../operationRuntime'
591
+ } from '../operationRuntime${ext}'
479
592
 
480
593
  export async function findMany(ctx: OperationContext): Promise<unknown> {
481
594
  const rawQuery = ctx.parsedQuery || {}
@@ -501,18 +614,14 @@ export async function findManyPaginated(
501
614
  const distinctCountLimit = ctx.paginationConfig?.distinctCountLimit
502
615
  const delegate = (extended as any).${modelNameLower}
503
616
 
504
- if (shape) {
505
- assertGuard(delegate)
506
- }
617
+ if (shape) assertGuard(delegate)
507
618
 
508
619
  let items: any[]
509
620
  let total: number
510
621
 
511
622
  if (shape || typeof extended.$transaction !== 'function') {
512
623
  const [data, count] = await Promise.all([
513
- shape
514
- ? delegate.guard(shape, caller).findMany(query)
515
- : delegate.findMany(query),
624
+ shape ? delegate.guard(shape, caller).findMany(query) : delegate.findMany(query),
516
625
  countForPagination(delegate, query, shape, caller, distinctCountLimit),
517
626
  ])
518
627
  items = data
@@ -527,13 +636,8 @@ export async function findManyPaginated(
527
636
  items = txResult.d
528
637
  total = txResult.t
529
638
  } catch (txError: any) {
530
- if (
531
- txError?.message?.includes?.('interactive transactions') ||
532
- txError?.code === 'P2028'
533
- ) {
534
- console.warn(
535
- '[prisma-generator-express] Interactive transactions not available, pagination queries are non-atomic',
536
- )
639
+ if (txError?.message?.includes?.('interactive transactions') || txError?.code === 'P2028') {
640
+ console.warn('[prisma-generator-express] Interactive transactions not available, pagination queries are non-atomic')
537
641
  items = await delegate.findMany(query)
538
642
  total = await countForPagination(delegate, query, undefined, undefined, distinctCountLimit)
539
643
  } else {